Skip to content

Commit 073c0ed

Browse files
committed
fix: resolve merge conflict with main (pnpm-lock.yaml)
2 parents bd2ccbd + 3ffe9cb commit 073c0ed

238 files changed

Lines changed: 5699 additions & 2918 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/empty-mails-applaud.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@copilotkit/runtime": patch
3+
---
4+
5+
fix: preserve jsonSchema structure in MCP tool parameter extraction

.changeset/five-avocados-visit.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@copilotkit/react-core": patch
3+
---
4+
5+
fix: pass toolCallId to useRenderTool render components

.changeset/little-pears-tell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@copilotkit/react-ui": patch
3+
---
4+
5+
fix: pass urlTransform prop through to ReactMarkdown

.github/workflows/publish-release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ jobs:
7474
git config --global user.email "github-actions[bot]@users.noreply.github.com"
7575
git config --global user.name "github-actions[bot]"
7676
77+
- name: Check for pre-existing tags
78+
run: |
79+
SCOPE="${{ steps.meta.outputs.scope }}"
80+
VERSION="${{ steps.publish.outputs.version }}"
81+
if [ "$SCOPE" == "monorepo" ]; then
82+
TAG="v${VERSION}"
83+
else
84+
TAG="${SCOPE}/v${VERSION}"
85+
fi
86+
if git rev-parse "$TAG" >/dev/null 2>&1; then
87+
echo "ERROR: Tag $TAG already exists" >&2
88+
exit 1
89+
fi
90+
7791
- name: Create and push git tag
7892
run: |
7993
SCOPE="${{ steps.meta.outputs.scope }}"

.github/workflows/showcase_aimock-e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878
- name: Start aimock
7979
run: |
8080
npm install -g @copilotkit/aimock@latest
81-
npx aimock --port 4010 --host 127.0.0.1 --fixtures showcase/aimock/feature-parity.json &
81+
npx aimock --port 4010 --host 127.0.0.1 --fixtures showcase/aimock/feature-parity.json --validate-on-load &
8282
# Wait for aimock to be ready
8383
for i in $(seq 1 20); do
8484
curl -sf http://localhost:4010/ > /dev/null 2>&1 && break

.github/workflows/showcase_deploy.yml

Lines changed: 217 additions & 73 deletions
Large diffs are not rendered by default.

.github/workflows/showcase_docs-sync.yml

Lines changed: 147 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ jobs:
5959
elif [ $EXIT_CODE -eq 3 ]; then
6060
echo "Has review items + clean transforms"
6161
echo "action=push_and_pr" >> "$GITHUB_OUTPUT"
62+
if [ -f review-items.txt ]; then
63+
REVIEW_ITEMS=$(cat review-items.txt)
64+
else
65+
echo "::warning::review-items.txt not found despite exit code 3 — sync script may have a bug"
66+
REVIEW_ITEMS="(review-items.txt not found — check sync script output)"
67+
fi
68+
# Persist review items to a file for downstream jq-based payload building
69+
# (avoids unsafe string interpolation of untrusted filenames into JSON).
70+
printf '%s' "$REVIEW_ITEMS" > review-items-raw.txt
71+
echo "review_items_file=review-items-raw.txt" >> "$GITHUB_OUTPUT"
6272
else
6373
echo "Sync failed with exit code $EXIT_CODE"
6474
exit 1
@@ -91,8 +101,11 @@ jobs:
91101
CHANGED=$(git diff --cached --name-only | wc -l | tr -d ' ')
92102
93103
if [ "$CHANGED" = "0" ]; then
94-
echo "Nothing to commit"
104+
echo "Nothing to commit — no PR will be opened (deliberate)"
95105
echo "files_changed=0" >> "$GITHUB_OUTPUT"
106+
# Explicit signal: no PR opened, and this is the intended outcome
107+
# (not an error path). Downstream alerts key on this.
108+
echo "pr_opened=false" >> "$GITHUB_OUTPUT"
96109
exit 0
97110
fi
98111
@@ -111,44 +124,163 @@ jobs:
111124
echo "Created PR: $PR_URL"
112125
echo "files_changed=${CHANGED}" >> "$GITHUB_OUTPUT"
113126
echo "pr_url=${PR_URL}" >> "$GITHUB_OUTPUT"
127+
# Only set pr_opened=true after the PR URL is captured. Any earlier
128+
# failure (push, gh pr create) will leave this unset so downstream
129+
# alerts fall through to failure() instead of a falsely-benign path.
130+
echo "pr_opened=true" >> "$GITHUB_OUTPUT"
114131
115132
gh pr merge "$PR_URL" --merge
116133
134+
# Build all Slack payloads via jq into tmpfiles. This guarantees any
135+
# review-item filename containing ", \, or control chars is safely
136+
# JSON-escaped (never string-interpolated into a JSON literal).
137+
- name: Build Slack payloads
138+
id: payloads
139+
if: always()
140+
env:
141+
RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
142+
PR_URL: ${{ steps.push.outputs.pr_url }}
143+
FILES_CHANGED: ${{ steps.push.outputs.files_changed }}
144+
REVIEW_ITEMS_FILE: ${{ steps.sync.outputs.review_items_file }}
145+
SYNC_OUTCOME: ${{ steps.sync.outcome }}
146+
BOT_TOKEN_OUTCOME: ${{ steps.bot-token.outcome }}
147+
PUSH_OUTCOME: ${{ steps.push.outcome }}
148+
run: |
149+
set -euo pipefail
150+
mkdir -p slack-payloads
151+
152+
# auto-sync success (PR merged)
153+
jq -n \
154+
--arg pr_url "${PR_URL:-}" \
155+
--arg files "${FILES_CHANGED:-?}" \
156+
--arg run_url "$RUN_URL" \
157+
'{text: (":arrows_counterclockwise: *Docs sync*: auto-merged " + $files + " file(s)\n" + $pr_url + "\n<" + $run_url + "|View run>")}' \
158+
> slack-payloads/auto-sync.json
159+
160+
# merge failed (PR exists but gh pr merge failed)
161+
jq -n \
162+
--arg pr_url "${PR_URL:-}" \
163+
--arg run_url "$RUN_URL" \
164+
'{text: (":warning: *Docs sync*: PR created but auto-merge FAILED — needs manual merge\n" + $pr_url + "\n<" + $run_url + "|View run>")}' \
165+
> slack-payloads/merge-failed.json
166+
167+
# review-needed payloads: read items from file, let jq handle escaping
168+
REVIEW_ITEMS=""
169+
if [ -n "${REVIEW_ITEMS_FILE:-}" ] && [ -f "$REVIEW_ITEMS_FILE" ]; then
170+
REVIEW_ITEMS=$(cat "$REVIEW_ITEMS_FILE")
171+
fi
172+
173+
jq -n \
174+
--arg items "$REVIEW_ITEMS" \
175+
--arg pr_url "${PR_URL:-}" \
176+
--arg run_url "$RUN_URL" \
177+
'{text: (":warning: *Docs sync*: files needing manual review\n```" + $items + "```\nReview: " + $pr_url + "\n<" + $run_url + "|View run>")}' \
178+
> slack-payloads/review-with-pr.json
179+
180+
jq -n \
181+
--arg items "$REVIEW_ITEMS" \
182+
--arg run_url "$RUN_URL" \
183+
'{text: (":warning: *Docs sync*: files needing manual review (no auto-PR opened)\n```" + $items + "```\n<" + $run_url + "|View run>")}' \
184+
> slack-payloads/review-no-pr.json
185+
186+
# failure alert
187+
FAILED_STEP="unknown"
188+
if [ "${SYNC_OUTCOME:-}" = "failure" ]; then
189+
FAILED_STEP="sync-docs script"
190+
elif [ "${BOT_TOKEN_OUTCOME:-}" = "failure" ]; then
191+
FAILED_STEP="bot token generation (check DEVOPS_BOT_PRIVATE_KEY secret)"
192+
elif [ "${PUSH_OUTCOME:-}" = "failure" ]; then
193+
FAILED_STEP="push/PR creation"
194+
fi
195+
jq -n \
196+
--arg failed_step "$FAILED_STEP" \
197+
--arg run_url "$RUN_URL" \
198+
'{text: (":x: *Docs sync*: workflow failed\n*Failed step:* " + $failed_step + " | <" + $run_url + "|View run>")}' \
199+
> slack-payloads/failure.json
200+
117201
- name: Notify Slack (auto-sync)
202+
id: notify-auto-sync
118203
if: always() && steps.push.outcome == 'success' && steps.push.outputs.files_changed != '0'
119204
uses: slackapi/slack-github-action@v2.1.0
120205
with:
121206
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
122207
webhook-type: incoming-webhook
123-
payload: |
124-
{ "text": ":arrows_counterclockwise: *Docs sync*: auto-merged ${{ steps.push.outputs.files_changed || '?' }} file(s)\n${{ steps.push.outputs.pr_url || '' }}\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>" }
208+
payload-file-path: slack-payloads/auto-sync.json
125209

126210
- name: Notify Slack (merge failed)
127-
if: failure() && steps.push.outputs.pr_url != ''
211+
id: notify-merge-failed
212+
if: failure() && steps.push.outputs.pr_opened == 'true'
128213
uses: slackapi/slack-github-action@v2.1.0
129214
with:
130215
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
131216
webhook-type: incoming-webhook
132-
payload: |
133-
{ "text": ":warning: *Docs sync*: PR created but auto-merge FAILED — needs manual merge\n${{ steps.push.outputs.pr_url }}\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>" }
217+
payload-file-path: slack-payloads/merge-failed.json
134218

135219
# Review items = files the sync script flagged but did NOT write to disk
136-
# (local modifications, files deleted on main). No file changes to propose —
137-
# just alert Slack so a human can manually reconcile.
138-
- name: Notify Slack (review needed)
139-
if: always() && steps.sync.outputs.action == 'push_and_pr'
220+
# (local modifications, files deleted on main). A PR was opened for the
221+
# clean-transform portion — link it so reviewers can click through.
222+
# Gated on pr_opened == 'true' so it only fires when we actually have a
223+
# PR URL (not on any error path that leaves pr_url empty).
224+
- name: Notify Slack (review needed, with PR)
225+
id: notify-review-with-pr
226+
if: always() && steps.sync.outputs.action == 'push_and_pr' && steps.push.outputs.pr_opened == 'true'
140227
uses: slackapi/slack-github-action@v2.1.0
141228
with:
142229
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
143230
webhook-type: incoming-webhook
144-
payload: |
145-
{ "text": ":warning: *Docs sync*: files needing manual review — see workflow run for details\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>" }
231+
payload-file-path: slack-payloads/review-with-pr.json
232+
233+
# Review items but the clean-transform portion was empty so no PR was
234+
# opened. Gated on pr_opened == 'false' (deliberate no-PR path) — not
235+
# empty pr_url, which would also match error paths.
236+
- name: Notify Slack (review needed, no PR)
237+
id: notify-review-no-pr
238+
if: always() && steps.sync.outputs.action == 'push_and_pr' && steps.push.outputs.pr_opened == 'false'
239+
uses: slackapi/slack-github-action@v2.1.0
240+
with:
241+
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
242+
webhook-type: incoming-webhook
243+
payload-file-path: slack-payloads/review-no-pr.json
146244

147245
- name: Notify Slack (failure)
148-
if: failure() && steps.push.outputs.pr_url == ''
246+
id: notify-failure
247+
if: failure() && steps.push.outputs.pr_opened != 'true'
149248
uses: slackapi/slack-github-action@v2.1.0
150249
with:
151250
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
152251
webhook-type: incoming-webhook
153-
payload: |
154-
{ "text": ":x: *Docs sync*: workflow failed\n*Failed step:* ${{ steps.sync.outcome == 'failure' && 'sync-docs script' || steps.bot-token.outcome == 'failure' && 'bot token generation (check DEVOPS_BOT_PRIVATE_KEY secret)' || steps.push.outcome == 'failure' && 'push/PR creation' || 'unknown' }} | <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>" }
252+
payload-file-path: slack-payloads/failure.json
253+
254+
# Unconditional fallback: if any notify-* step above failed (webhook 5xx,
255+
# rate limit, malformed payload), fire a plain-text alert so we never
256+
# silently lose a review-needed or failure notification. Uses curl
257+
# directly so it doesn't share failure modes with the slackapi action.
258+
# Payload is inlined (not read from slack-payloads/) so this fallback
259+
# has no dependency on the Build Slack payloads step succeeding — if
260+
# that step broke (jq missing, mkdir failed, etc), every notify-* step
261+
# would fail AND the fallback could not read its file. RUN_URL is
262+
# constructed from GitHub-controlled env vars only (no user input), so
263+
# direct string interpolation into the JSON literal is safe — the
264+
# values cannot contain " or \.
265+
- name: Notify Slack (alert machinery failed)
266+
if: >-
267+
always() && (
268+
steps.notify-auto-sync.outcome == 'failure' ||
269+
steps.notify-merge-failed.outcome == 'failure' ||
270+
steps.notify-review-with-pr.outcome == 'failure' ||
271+
steps.notify-review-no-pr.outcome == 'failure' ||
272+
steps.notify-failure.outcome == 'failure'
273+
)
274+
env:
275+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
276+
run: |
277+
set -eu
278+
if [ -z "${SLACK_WEBHOOK:-}" ]; then
279+
echo "::warning::SLACK_WEBHOOK_OSS_ALERTS not set — cannot post fallback alert"
280+
exit 0
281+
fi
282+
RUN_URL="https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
283+
curl -sS -X POST \
284+
-H "Content-Type: application/json" \
285+
--data "{\"text\": \":rotating_light: *Docs sync*: review/alert machinery failed — check Actions UI ${RUN_URL}\"}" \
286+
"$SLACK_WEBHOOK" || echo "::warning::fallback Slack post also failed"

.github/workflows/showcase_drift-detection.yml

Lines changed: 30 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -74,45 +74,45 @@ jobs:
7474
7575
- name: Build Slack payload
7676
if: failure()
77+
id: slack-payload
78+
env:
79+
DETAILS_RAW: ${{ steps.failures.outputs.details }}
7780
run: |
78-
SUMMARY=$(echo "${{ steps.failures.outputs.details }}" | head -3 | sed 's/\x1b\[[0-9;]*m//g' | cut -c1-200)
81+
# Strip ANSI sequences (SGR, OSC, and G0/G1 charset designators), then truncate
82+
# to 200 bytes and drop any trailing partial UTF-8 bytes so we don't emit mojibake.
83+
SUMMARY=$(printf '%s' "$DETAILS_RAW" | head -3 \
84+
| sed -E 's/\x1b\[[0-9;?]*[A-Za-z]//g; s/\x1b\][^\x07]*\x07//g; s/\x1b[()][A-Za-z0-9]//g' \
85+
| head -c 200 | iconv -f UTF-8 -t UTF-8//IGNORE)
86+
if [ -z "$SUMMARY" ]; then
87+
SUMMARY="(no failure detail captured — see job log)"
88+
fi
7989
URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
80-
jq -n --arg text ":x: *Showcase E2E suite failed*\n<$URL|View run>\n\`\`\`$SUMMARY\`\`\`" \
81-
'{text: $text}' > /tmp/slack-payload.json
90+
JOB_URL="${URL}/job/${{ github.job }}"
91+
92+
SLACK_MSG=$(mktemp)
93+
SLACK_PAYLOAD=$(mktemp)
94+
95+
# Build the message with REAL newlines, then hand it to jq via --rawfile so escaping is handled correctly.
96+
{
97+
printf ':x: *Showcase E2E suite failed*\n'
98+
printf '<%s|View run> · <%s|View job>\n' "$URL" "$JOB_URL"
99+
printf '```\n%s\n```\n' "$SUMMARY"
100+
} > "$SLACK_MSG"
101+
jq -n --rawfile text "$SLACK_MSG" '{text: $text}' > "$SLACK_PAYLOAD"
102+
rm -f "$SLACK_MSG"
103+
echo "payload_path=${SLACK_PAYLOAD}" >> "$GITHUB_OUTPUT"
82104
83105
- name: Post failure to Slack
84106
if: failure()
85107
uses: slackapi/slack-github-action@v2.1.0
86108
with:
87109
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
88110
webhook-type: incoming-webhook
89-
payload-file-path: /tmp/slack-payload.json
111+
payload-file-path: ${{ steps.slack-payload.outputs.payload_path }}
90112
91-
- name: Create issue on failure
92-
if: failure()
93-
uses: actions/github-script@v7
94-
with:
95-
script: |
96-
const title = '[Drift] Showcase E2E suite failing';
97-
const body = `## E2E Drift Detection Alert\n\n**Run**: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}\n**Schedule**: ${context.payload.schedule || 'manual'}\n\nThe centralized E2E smoke suite is failing. Please investigate.`;
98-
99-
const { data: issues } = await github.rest.issues.listForRepo({
100-
owner: context.repo.owner,
101-
repo: context.repo.repo,
102-
labels: 'showcase-drift',
103-
state: 'open',
104-
});
105-
106-
const existing = issues.find(i => i.title === title);
107-
if (!existing) {
108-
await github.rest.issues.create({
109-
owner: context.repo.owner,
110-
repo: context.repo.repo,
111-
title,
112-
body,
113-
labels: ['showcase-drift'],
114-
});
115-
}
113+
- name: Clean up Slack payload tmpfile
114+
if: always() && steps.slack-payload.outputs.payload_path
115+
run: rm -f "${{ steps.slack-payload.outputs.payload_path }}"
116116
117117
version-drift:
118118
name: Version Drift Report
@@ -195,67 +195,14 @@ jobs:
195195
echo -e "$report" >> $GITHUB_OUTPUT
196196
echo "EOF" >> $GITHUB_OUTPUT
197197
198-
- name: Create drift report issue
199-
id: drift_issue
200-
if: steps.python_drift.outputs.report != '' || steps.npm_drift.outputs.report != ''
201-
uses: actions/github-script@v7
202-
with:
203-
script: |
204-
const pythonDrift = `${{ steps.python_drift.outputs.report }}`.trim();
205-
const npmDrift = `${{ steps.npm_drift.outputs.report }}`.trim();
206-
207-
if (!pythonDrift && !npmDrift) return;
208-
209-
const title = `[Drift] Showcase packages have outdated pinned versions`;
210-
const body = `## Weekly Version Drift Report
211-
212-
Showcase packages have pinned versions that differ from the latest releases.
213-
Review each and update if the new version is compatible.
214-
215-
${pythonDrift ? `### Python Packages\n| Package | Dep | Pinned | Latest |\n|---------|-----|--------|--------|\n${pythonDrift}` : ''}
216-
217-
${npmDrift ? `### npm Packages\n| Package | Dep | Pinned | Latest |\n|---------|-----|--------|--------|\n${npmDrift}` : ''}
218-
219-
**Action**: For each outdated dep, check the Dojo example for the correct version.
220-
Update \`requirements.txt\` / \`package.json\`, rebuild, and verify demos still work.
221-
`;
222-
223-
const { data: issues } = await github.rest.issues.listForRepo({
224-
owner: context.repo.owner,
225-
repo: context.repo.repo,
226-
labels: 'showcase-drift,version-drift',
227-
state: 'open',
228-
});
229-
230-
let issueUrl;
231-
if (issues.length === 0) {
232-
const { data: created } = await github.rest.issues.create({
233-
owner: context.repo.owner,
234-
repo: context.repo.repo,
235-
title,
236-
body,
237-
labels: ['showcase-drift', 'version-drift'],
238-
});
239-
issueUrl = created.html_url;
240-
} else {
241-
await github.rest.issues.update({
242-
owner: context.repo.owner,
243-
repo: context.repo.repo,
244-
issue_number: issues[0].number,
245-
body,
246-
});
247-
issueUrl = issues[0].html_url;
248-
}
249-
core.setOutput('issue_url', issueUrl);
250-
251198
- name: Notify Slack (version drift)
252199
if: steps.python_drift.outputs.report != '' || steps.npm_drift.outputs.report != ''
253200
uses: slackapi/slack-github-action@v2.1.0
254201
with:
255202
webhook: ${{ secrets.SLACK_WEBHOOK_OSS_ALERTS }}
256203
webhook-type: incoming-webhook
257204
payload: |
258-
{ "text": ":warning: *Version drift*: dependency updates available | <${{ steps.drift_issue.outputs.issue_url }}|View issue>" }
205+
{ "text": ":warning: *Version drift*: dependency updates available | <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>" }
259206
260207
- name: Notify Slack (version drift failure)
261208
if: failure()

0 commit comments

Comments
 (0)