Commit Graph

14241 Commits

Author SHA1 Message Date
Mike Ryan 8a2844b571 docs: enforce angular-only documentation routes 2026-07-27 09:38:01 -07:00
Mike Ryan 9988c23890 docs: render shared concepts for Angular 2026-07-27 09:38:00 -07:00
Mike Ryan cc8689e21f fix(showcase): bundle Angular docs source in image 2026-07-27 09:38:00 -07:00
Mike Ryan a87f1c9a30 docs: close Angular information architecture gaps 2026-07-27 09:38:00 -07:00
Mike Ryan db732d3966 docs: complete Angular threads API journey 2026-07-27 09:38:00 -07:00
Mike Ryan 38333d3625 docs: enforce Angular parity across backend guides 2026-07-27 09:38:00 -07:00
Mike Ryan 92e5c31332 docs: align Angular metadata with rendered variants 2026-07-27 09:37:59 -07:00
Mike Ryan fcf2357c25 docs: add Angular-native content and source-backed snippets 2026-07-27 09:37:59 -07:00
Mike Ryan c569aa595d docs: make Angular share the full information architecture 2026-07-27 09:37:59 -07:00
David McKay 6eefe2b551 docs(react-native): correct polyfill auto-install claim for /components
Independent re-verification against packages/react-native source found the
page overstated polyfill auto-install: only /headless (and the root barrel,
via its /headless re-export) side-effect-imports the polyfill barrel.
src/components/index.ts imports no polyfills, so a consumer importing only
from @copilotkit/react-native/components does not get them auto-installed;
it relies on the provider imported alongside it. Corrects the 'all three
surfaces auto-install' and 'every entry point installs these automatically'
statements accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 09:35:53 -07:00
Tyler Slaton 47ce2720a6 fix(release): make verify:runtime-package pass on channels release PRs (#6186)
Fixes OSS-616

## Problem

`scripts/release/verify-runtime-package.ts` **cannot pass on a channels
release PR**, so the `unit (20.x)` leg is red by construction on exactly
the PRs the gate exists to protect — and gets merged past.

1. `packages/runtime/package.json` declares
`@copilotkit/channels-intelligence: workspace:*`.
2. `pnpm pack` rewrites `workspace:` to the workspace's *current*
version — on a release PR, the freshly-bumped one (e.g. `0.3.0`).
3. The temp consumer then has to resolve
`@copilotkit/channels-intelligence@0.3.0` **from npm**.
4. That version doesn't exist yet. This PR is what publishes it.

Real CI output from #6185:

```
ERR_PNPM_NO_MATCHING_VERSION  No matching version found for
@copilotkit/channels-intelligence@0.3.0 while fetching it from https://registry.npmjs.org/
This error happened while installing the dependencies of @copilotkit/runtime@1.63.2
The latest release of @copilotkit/channels-intelligence is "0.2.1". Published at 7/17/2026
```

Red instances: **#6185** (`channels/v0.3.0`) and **#6025**
(`channels/v0.2.1`, merged red on 2026-07-17). #5989 (`v0.2.0`) passed
only because the hard runtime dependency landed the next day in
`fea464de52`.

## Fix

`verify-channels-umbrella.ts` already solved this — its own comment
describes the problem verbatim. Same approach applied here: pack the
whole first-party `workspace:` closure locally and pin it through pnpm
`overrides` so nothing unpublished is resolved over the network.

The packing helpers (`packPackage`, the transitive `workspace:` walk)
move into `scripts/release/lib/pack-workspace.ts`, shared by both
scripts instead of duplicated. `verify-channels-umbrella` behavior is
unchanged — it just calls the extracted helpers.

**The check is not weakened.** It still asserts the packed runtime
declares `@copilotkit/channels-intelligence` as a real dependency and
that the package loads through both ESM and CJS. A new guard fails
loudly if channels-intelligence ever stops being a `workspace:` dep, so
a silent fallback to registry resolution can't creep back in. Runtime
dependency ranges were not touched.

## Testing

All runs under Node 20 in a clean worktree off `origin/main`.

**1. Reproduced the failure** — applied the exact 9 version bumps from
`release/publish/channels/v0.3.0`, then ran the pre-fix script from
`origin/main`:

```
The latest release of @copilotkit/channels-core is "0.2.1". Published at 7/17/2026
Command failed: pnpm install --ignore-scripts
```

**2. Fixed script, same bumped state** — acceptance criterion 1:

```
$ pnpm run verify:runtime-package
OK: packed runtime installs @copilotkit/channels-intelligence and loads through ESM and CJS.
EXIT=0
```

**3. Still fails when the dependency is removed** — deleted
`@copilotkit/channels-intelligence` from
`packages/runtime/package.json`:

```
packed runtime must install @copilotkit/channels-intelligence as a dependency
EXIT=1
```

**4. Still fails on a genuine ESM load break** — `throw` at the top of
`packages/channels-intelligence/src/index.ts`:

```
Error: simulated ESM load break
Command failed: pnpm exec node --experimental-import-meta-resolve --input-type=module --eval ...
EXIT=1
```

**5. Still fails on a genuine CJS load break** — `throw` at the top of
`packages/runtime/src/v2/index.ts`:

```
Error: simulated CJS load break
Command failed: pnpm exec node --eval require("@copilotkit/runtime");
EXIT=1
```

**6. Umbrella check unaffected by the helper extraction:**

```
$ pnpm run verify:channels-umbrella
OK: local Channels snapshot is exact, compatible, singly resolved, and TSX-consumable.
```

**7. Release script tests** — new
`scripts/release/__tests__/verify-runtime-package.test.ts` models the
release-PR case (bumped local versions absent from the registry) and
asserts no workspace dependency is left registry-resolvable. The vitest
include glob was extended to cover `__tests__/`:

```
Test Files  10 passed (10)
     Tests  137 passed (137)
```

**8.** `oxfmt --check` clean, `oxlint` 0 warnings / 0 errors, `tsc
--strict --noEmit` clean on all four touched scripts.

All mutations from steps 1 and 3–5 were reverted; the final diff touches
`scripts/release/` only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-27 09:32:04 -07:00
Benjamin Taylor 4a9837e176 fix(release): pack runtime workspace deps locally in verify-runtime-package
`verify:runtime-package` could not pass on a channels release PR. `pnpm pack`
rewrites the runtime's `workspace:` ranges to the workspace's current version,
so on a release PR the temp consumer tried to resolve the freshly-bumped
`@copilotkit/channels-intelligence` from npm — the version this very PR is
about to publish. It failed `unit (20.x)` by construction on #6185 and #6025.

Apply the fix `verify-channels-umbrella` already uses: pack the whole
first-party `workspace:` closure locally and pin it through pnpm `overrides`.
The packing helpers move to `lib/pack-workspace.ts` so both scripts share one
implementation instead of duplicating it.

The contract is unchanged: the packed runtime must still declare
channels-intelligence as a real dependency, and it must still load through
both ESM and CJS.
2026-07-27 11:10:32 -05:00
Ben Taylor 8180a9160d chore: release channels v0.3.0 (#6185)
## Release channels v0.3.0

**Scope:** `channels` | **Bump:** `minor`

---

### How this release process works

1. **This PR was created automatically** by the "release / create-pr"
workflow.
   It bumped the `channels` packages to `0.3.0`
   and generated AI-enhanced release notes.

2. **CI runs on this PR** — the full test suite (unit tests, lint, type
checks, build)
   must pass before merging. This is the review gate.

3. **Review the release notes** in `release-notes.md` in this PR.
If a Notion draft was created, you can edit the release notes there
before merging.

4. **When this PR is merged**, the `release / publish` workflow
automatically:
   - Builds all packages
   - Publishes the `channels` packages to npm at version `0.3.0`
   - Creates git tag `channels/v0.3.0`
   - Creates a GitHub Release with the final release notes

### Before merging

- [ ] CI is green (tests, lint, types, build)
- [ ] Version bumps look correct
- [ ] Release notes are accurate (edit in Notion if a draft was created)

---

> **Do not merge until CI is fully green.** The full test suite runs
automatically on this PR.
channels/v0.3.0
2026-07-27 11:09:22 -05:00
BenTaylorDev 0e19eb2d5d chore: release channels v0.3.0 2026-07-27 15:43:19 +00:00
David McKay 858aeb2673 test(react-core): drop untyped transport in proxied-agent mock
The harness's loosely-typed runtimeTransport string isn't assignable to
ProxiedCopilotRuntimeAgentConfig.transport (CopilotRuntimeTransport); leave it
at the "auto" default since these tests assert threadId/runtimeAgentId only.
Fixes the check-types failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 08:36:22 -07:00
Lukas Moschitz 5d3dac1298 fix(showcase): restore langgraph-fastapi gen-ui-open.json fixtures (CI: aimock-fixtures)
CI 'Showcase: Validate' failed: aimock-fixtures.test.ts asserts every d6/*.json
yields >=1 fixture, but gen-ui-open.json had been emptied to a _meta stub (0
fixtures) by an earlier open-gen-ui shadowing fix that consolidated the pills
into gen-ui-tool-based.json.

Restore gen-ui-open.json as a byte-for-byte context-swap of the canonical
langgraph-python file (context -> langgraph-fastapi): 4 fixtures for the '3D
axis' and 'Inline expression evaluator' pills, LGP's clean shape
(hasToolResult:false leg-1, distinct toolCallId terminals). No shadowing loop:
each file's leg-1/terminal pair is anchored by its own distinct toolCallId, so
the done-signal always resolves.

Verified: aimock-fixtures.test.ts 839/839 green locally; D6 gen-ui-open,
gen-ui-open-advanced, gen-ui-custom all green (two real runs each).
2026-07-27 17:28:26 +02:00
Mike Ryan 13ee9f5b99 Revise Angular quickstart link in README (#6127)
Updated the Angular section to include 'Source Code & Quickstart'
instead of 'Source Code - Quickstart coming soon'.

<!--
Thank you for sending the PR! We appreciate you spending the time to
work on these changes.

Help us understand your motivation by explaining why you decided to make
this change.


**Please PLEASE reach out to us first before starting any significant
work on new or existing features.**

By the time you've gotten here, you're looking at creating a pull
request so hopefully we're not too late.

We love community contributions! That said, we want to make sure we're
all on the same page before you start.
Investing a lot of time and effort just to find out it doesn't align
with the upstream project feels awful, and we don't want that to happen.
It also helps to make sure the work you're planning isn't already in
progress.

As described in our contributing guide, please file an issue first:
https://github.com/ag-ui-protocol/ag-ui/issues
Or, reach out to us on Discord: https://discord.com/invite/6dffbvGU3D


You can learn more about contributing to copilotkit here:
https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md

Happy contributing!

-->

## What does this PR do?

(Describe the changes introduced in this PR)

## Related PRs and Issues

- (Direct link to related PR or issue, if relevant)

## Checklist

- [ ] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation
- [ ] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)
2026-07-27 08:21:11 -07:00
github-actions[bot] b4cff204d1 style: auto-fix formatting 2026-07-27 15:10:04 +00:00
Ran Shem Tov 1225bd7999 fix(showcase): sweep PNI-100 relaxed-turnIndex re-emit — frontend-tools-async
Same class as the hitl-in-app fix: turnIndex:0 emit legs get re-served on the
post-tool-result turn under aimock's default (relaxed) turn-index selection,
re-firing the frontend tool instead of narrating.

frontend-tools-async (query_notes): add hasToolResult:false to the 4 emit legs
(3 pills + the 'project planning' catch-all) so they match the emit turn and are
excluded once the tool result returns. The toolCallId narration legs round-trip
fine here (verified on the wire) and are unchanged.

Verified under relaxed aimock: pill -> single result card + narration, no
re-emit, no error (was: double card + 'toLowerCase' error).

subagents.json left as-is: its turnIndex 1/2 legs are intentional server-side
step sequencing, not the client-re-POST pattern.

open-gen-ui / open-gen-ui-advanced NOT touched here: their real fixtures live in
gen-ui-open.json / gen-ui-open-advanced.json (already hasToolResult-gated, no
turnIndex). The stale duplicate generateSandboxedUi entries in
gen-ui-tool-based.json are a separate cleanup, tracked outside this PR.
2026-07-27 18:06:00 +03:00
Lukas Moschitz c9d8a9ac14 fix(showcase): restore missing @region markers on 2 langgraph-fastapi agents
The factory automation extracts curated snippets via @region markers.
readonly_state_agent_context.py and shared_state_read_write.py were byte-aligned
to langgraph-python except their @region markers had been stripped, so the
factory would extract nothing for those two regions. Restore them to match LGP:
- agent-context-setup around create_agent in readonly_state_agent_context.py
- shared-state-setup around create_agent in shared_state_read_write.py
Comment-only; no behavior change. Audit confirms all 49 fastapi region pairs are
now balanced and LGP-consistent (0 orphans/typos/mismatches).
2026-07-27 17:03:08 +02:00
David McKay 27827adee2 fix(react-core): require runtimeAgentId to scope useAgent threadId
Writing a per-hook threadId onto an agent resolved by agentId alone mutates a
shared singleton, so two useAgent calls that share an agentId clobber each
other's thread (review feedback from @mme). Require runtimeAgentId when threadId
is provided: the hook then registers a private proxied agent (agentId ->
runtimeAgentId via CopilotKitCore.registerProxiedAgent) and scopes the threadId
to that instance instead of a shared one. Register/unregister run as one
balanced, StrictMode-safe effect, exposing the proxy via state so the hook
swaps from the provisional stand-in deterministically. Passing threadId without
runtimeAgentId now throws. Updates the React Native demo to the new API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 08:01:21 -07:00
Lukas Moschitz efe51e7deb chore(showcase): remove fe-parity tool
fe-parity.ts was a scratch parity checker for this alignment work; it is no
longer needed in the worktree. Drop it and de-reference it from
langgraph-fastapi/PARITY_NOTES.md (reword the intro, convert the
machine-readable fe-parity-allow allowlist into a plain human-readable
'sanctioned file-level divergences' list). No other references existed. D6
behavior remains the parity judge.
2026-07-27 16:55:23 +02:00
Lukas Moschitz b8f37c0c85 docs(showcase): document declarative-json-render scoped-D6 divergence as sanctioned
The byoc D6 featureType covers both declarative demos; the grid cell is green
(hashbrown route+pill). A scoped declarative-json-render --d6 run reds for two
non-fastapi reasons: (1) the shared d5-byoc probe always sends the hashbrown
pill even on the json-render page (harness limitation — build context lacks
demos[]; tracked as a separate follow-up), and (2) fastapi deliberately keeps
hashbrown (@hashbrownai/react) and json-render (@json-render/react) as separate
library integrations with their own pills/fixtures, vs LGP's unified
render_dashboard contract. Sanctioned; do not collapse fastapi's json-render to
the unified contract (content downgrade) — the real fix is probe-side.
2026-07-27 16:49:05 +02:00
Lukas Moschitz 4aee3c6529 docs(showcase): GOTCHAS #8 — aimock D6 green can mask a demo broken against a real LLM
aimock replays scripted tool calls keyed on userMessage+context regardless of
which graph ran or its tool set, so a demo mis-wired to the sample_agent
fallback passes D6 green while breaking against a real model (OSS-582:
gen-ui-tool-based looped on query_data; shared-state-streaming wrote only to
chat; agentic-chat ran with the wrong tool set). Document that D6-green is
necessary but not sufficient, the real-LLM live click-through procedure, and
the structural tell (route.ts fallthrough loop vs LGP's dedicated wiring).
2026-07-27 16:37:06 +02:00
Lukas Moschitz bf2de51705 fix(showcase): wire langgraph-fastapi demos to dedicated graphs (drop sample_agent fallbacks)
Live QA surfaced demos that behaved wrong on fastapi because they fell back to
the generic sample_agent (or were unregistered) instead of the dedicated graph
LGP uses. aimock D6 masked these (fixtures script the tool calls), so they were
green in the grid but broken against a real model. Audit of fastapi's
agentNames fallthrough vs LGP's neutralAssistantCells found exactly these:

- gen-ui-tool-based: port gen_ui_tool_based graph (tools=[], frontend supplies
  render_bar/pie_chart via useComponent). Was sample_agent, whose query_data
  tool + prompt made the model loop on data queries instead of rendering.
- shared-state-streaming: port shared_state_streaming graph (StateStreaming
  middleware + write_document tool + document state). Was sample_agent, which
  never emits state.document, so it only wrote to chat. Remove from
  not_supported_features (now works, D6 green).
- agentic-chat: port agentic_chat graph (tools=[]). Was sample_agent (7+ tools).
- threadid-frontend-tool-roundtrip: wire to frontend_tools (was unregistered).
- reasoning-custom: align reasoning_agent config to LGP (gpt-5.4 / effort
  medium / summary detailed; were gpt-5-mini / low / auto).

Register the 3 new graphs in langgraph.json; remove the 3 names from the
sample_agent fallthrough loop in route.ts. D6 green x2 for reasoning-display,
gen-ui-custom, shared-state-streaming, agentic-chat; agent-config +
tool-rendering-reasoning-chain re-verified (no regression).
2026-07-27 16:24:50 +02:00
Lukas Moschitz 7bd1ca6e70 docs(showcase): record a2ui-recovery D6 red as a shared north-star defect
Soften the stale 'D6 green'/'under investigation' wording. A live trace
confirmed the a2ui-recovery surface-missing D6 red reproduces identically on
the langgraph-python north star (shared Python ag_ui_langgraph recovery loop;
mastra's TS impl is green), so fastapi is already behaviorally aligned and
there is nothing to fix under integrations/langgraph-fastapi/. Fixing the
shared loop is a separate PR against the north star / the package.
2026-07-27 14:30:21 +02:00
Lukas Moschitz 6af08217b2 fix(showcase): align langgraph-fastapi demo overview + canonical cell wiring to parity
The demo-browser overview (page.tsx, identical to LGP) groups cards by
demo.tags[0] and orders within a group by manifest.features[] index, so the
card arrangement is fully driven by manifest.yaml. fastapi's manifest was an
older curation: a different naming scheme (~26 demos), deprecated feature/demo
ids (agentic-chat-reasoning, reasoning-default-render, byoc-hashbrown,
byoc-json-render, hitl, phantom hitl-in-chat-booking), divergent tags/order,
and a missing shared-state-streaming/shared-state-read card.

Align manifest.yaml demos+features to LGP (names, descriptions, tags, order,
canonical ids), preserving fastapi identity (name/slug/logo/description) and
the sanctioned a2ui-recovery prompt divergence. Overview is now card-for-card
identical to langgraph-python.

Canonicalizing the ids pulled two cells into the D6 tested set that were
mis-wired to the old names; wire them to LGP's shape:
- reasoning-custom/reasoning-default -> reasoning_agent in copilotkit/route.ts
  (were wired under agentic-chat-reasoning/reasoning-default-render).
- rename api routes copilotkit-byoc-{hashbrown,json-render} ->
  copilotkit-declarative-{hashbrown,json-render}; align endpoints + the
  declarative-hashbrown-demo agent id to what the demo pages request.

Full D6 sweep: 37 green / 1 red; reasoning-display and byoc now green (two
real runs each); the lone red is a2ui-recovery (known shared north-star
defect, identical on LGP).
2026-07-27 14:30:21 +02:00
Ran Shem Tov 96116dab1a fix(showcase): hitl-in-app mastra fixtures re-trigger approval loop under relaxed aimock (PNI-100)
The three turn-0 pill fixtures (refund/downgrade/escalate) were keyed on
turnIndex:0. aimock's default (relaxed) turn-index selection re-serves a
turnIndex-only fixture on the post-approval turn, so approving a
useFrontendTool(request_user_approval) call re-emitted the tool call
instead of narrating the outcome — the turn never settled (stuck
text-unstable).

Re-key each emit fixture on hasToolResult:false instead of turnIndex:0.
It matches the emit turn (no tool result yet) and is excluded on the
post-approval turn (hasToolResult:true), where the toolCallId narration
fixture wins. No turnIndex dependency, so it is correct under both strict
and relaxed aimock, and multi-pill-safe.

Not a bridge/runtime bug: @ag-ui/mastra loops back correctly on real
OpenAI and under strict aimock. Fault was fixture selection only.
2026-07-27 14:53:45 +03:00
renovate[bot] 4efb0969c0 chore(deps): update jarvusinnovations/background-action action to v2 (#6181)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[JarvusInnovations/background-action](https://redirect.github.com/JarvusInnovations/background-action)
| action | major | `v1` → `v2` |

# Warnings (1)

Please correct - or verify that you can safely ignore - these warnings
before you merge this PR.

- `JarvusInnovations/background-action`: Could not determine new digest
for update (github-tags package JarvusInnovations/background-action)

---

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/592) for more information.

---

### Release Notes

<details>
<summary>JarvusInnovations/background-action
(JarvusInnovations/background-action)</summary>

###
[`v2.0.0`](https://redirect.github.com/JarvusInnovations/background-action/releases/tag/v2.0.0)

[Compare
Source](https://redirect.github.com/JarvusInnovations/background-action/compare/v2.0.0...v2.0.0)

#### Breaking changes

- **Invalid option values now fail the step.** `tail`, `log-output`,
`log-output-resume` and `log-output-if` used to match on substrings, so
`log-output: no-stderr` quietly *enabled* stderr and a typo like
`sdtout` quietly disabled logging entirely. The same applied to
`wait-for`, where `abc123` silently became a 123ms timeout. These are
now validated exactly. **If a workflow of yours currently passes with a
typo'd value, it will start failing — that value was never doing what it
looked like.**
- **Backgrounded processes are stopped during post-run.** They receive
`SIGTERM`, get `shutdown-grace` (default `10s`) to exit cleanly, and
anything they print on the way down is captured in the logs. Set
`shutdown: false` for the previous behavior.
- **Logs are written under `RUNNER_TEMP`** instead of the workspace, so
an automated commit can no longer sweep them into your repository. Use
the new `stdout-log` / `stderr-log` outputs to find them.
- **Runs on the `node24` runtime.**

#### Fixes

- **`wait` was passed as an argument to your last command**
([#&#8203;210](https://redirect.github.com/JarvusInnovations/background-action/issues/210)).
`core.getInput()` strips trailing whitespace, so the shell builtin
appended to your commands became an argv of whatever ran last — `npm run
preview` became `npm run preview wait`. Affected every multi-line `run:`
whose final command wasn't backgrounded.
- **A failed background process is now reported immediately** rather
than at the readiness timeout. A bare `wait` blocks until *every* job
exits and discards their statuses, so one service dying on startup was
invisible until the timeout this action exists to prevent. Jobs are now
awaited one at a time.
- **Backgrounded processes are no longer left running**
([#&#8203;205](https://redirect.github.com/JarvusInnovations/background-action/issues/205)).
- **Log files no longer land in the workspace**
([#&#8203;199](https://redirect.github.com/JarvusInnovations/background-action/issues/199)),
and their paths are published as outputs
([#&#8203;193](https://redirect.github.com/JarvusInnovations/background-action/issues/193)).
- **`log-output-if: early-exit`** — the spelling `action.yml` had
advertised since the first release — was rejected outright. Both
spellings now work.
- **Post-run no longer prints the environment** when debug logging is
enabled.

#### Improvements

- New inputs: `shutdown`, `shutdown-grace`. New outputs: `stdout-log`,
`stderr-log`.
- Durations accept terse and verbose spellings (`30s`, `30 seconds`,
`1h30m45s`).
- Production dependencies reduced to three, with **no known
advisories**.
- The published bundle is now committed and verified against its sources
on every pull request.
- Tests run on macOS as well as Linux.

See the README for the full upgrade notes.

#### Thanks

This release is almost entirely other people's bug reports. Several sat
open for a long time.

- **[@&#8203;OlegYch](https://redirect.github.com/OlegYch)** reported
[#&#8203;210](https://redirect.github.com/JarvusInnovations/background-action/issues/210),
and pointed at the exact line in `index.js`. That's most of the
diagnosis.
- **[@&#8203;rdicroce](https://redirect.github.com/rdicroce)** reported
[#&#8203;199](https://redirect.github.com/JarvusInnovations/background-action/issues/199)
after log files were accidentally committed to a repository by an
automated release workflow.
- **[@&#8203;piranna](https://redirect.github.com/piranna)** reported
[#&#8203;205](https://redirect.github.com/JarvusInnovations/background-action/issues/205),
correctly noting nothing ever killed the backgrounded processes.
- **[@&#8203;vera](https://redirect.github.com/vera)** reported
[#&#8203;187](https://redirect.github.com/JarvusInnovations/background-action/issues/187),
the post-job `ENOENT` failure. Now covered by a regression test.
-
**[@&#8203;JordanLongstaff](https://redirect.github.com/JordanLongstaff)**
reported
[#&#8203;206](https://redirect.github.com/JarvusInnovations/background-action/issues/206)
(Node 20 deprecation), and
**[@&#8203;marcodicro-dp](https://redirect.github.com/marcodicro-dp)**
for following up on it.
- **[@&#8203;riderx](https://redirect.github.com/riderx)**
([#&#8203;207](https://redirect.github.com/JarvusInnovations/background-action/issues/207)),
**[@&#8203;runlevel5](https://redirect.github.com/runlevel5)**
([#&#8203;208](https://redirect.github.com/JarvusInnovations/background-action/issues/208),
[#&#8203;209](https://redirect.github.com/JarvusInnovations/background-action/issues/209))
and **[@&#8203;Lucas127128](https://redirect.github.com/Lucas127128)**
([#&#8203;211](https://redirect.github.com/JarvusInnovations/background-action/issues/211))
all sent Node 24 upgrades.
[#&#8203;207](https://redirect.github.com/JarvusInnovations/background-action/issues/207)
was the closest to complete, and
[#&#8203;209](https://redirect.github.com/JarvusInnovations/background-action/issues/209)'s
ESM work remains valuable and is still on the table.

Sorry it took a while.

###
[`v2`](https://redirect.github.com/JarvusInnovations/background-action/compare/v1.0.7...v2.0.0)

[Compare
Source](https://redirect.github.com/JarvusInnovations/background-action/compare/v1.0.7...v2.0.0)

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/Los_Angeles)

- Branch creation
  - "before 9am every weekday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/CopilotKit/CopilotKit).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
2026-07-27 10:13:28 +00:00
Lukas Moschitz a19ed403cf fix(showcase): port langgraph-fastapi tool-rendering-reasoning-chain to parity
Two independent fastapi divergences from the green north-star kept this red:

1. Missing chunkSize:9999 on the 8 tool-call fixtures. Under aimock's global
   8-byte chunking the large tool-call args failed to JSON-parse in one piece,
   so the AAPL->MSFT reasoning chain stopped at leg 1 (turns 1 & 2). Byte-align
   to LGP (and the green mastra/langgraph-typescript siblings carry the same
   pattern).

2. Fixture-pool shadowing broke turn 3. aimock pools all d4+d6 fixtures for a
   context and matches by userMessage substring, first-match-wins in load order
   (d4 before d6). fastapi had broad keys LGP doesn't:
   - d4/chat.json: 'weather' -> 'weather in San Francisco', 'flights from SFO
     to JFK' -> 'Find flights from SFO to JFK.' (period-terminated so it stops
     being a substring of turn 3's 'Find flights from SFO to JFK and show me
     the weather there.').
   - tool-rendering-{custom,default}-catchall.json: bare 'Find flights' ->
     'Find flights from SFO to JFK.' (now matches LGP's exact key).

Also byte-align the backend agent to LGP: scriptable get_stock_price signature,
the detailed chaining system prompt, model gpt-5.4, reasoning summary detailed.

D6 tool-rendering-reasoning-chain green (two real ~21s runs). Shared-fixture
regression all green: agentic-chat, tool-rendering, tool-rendering-custom-catchall,
tool-rendering-default-catchall, headless-complete (Tokyo-weather consumer).
2026-07-27 11:01:18 +02:00
renovate[bot] b6e0bc0cd2 chore(deps): update jarvusinnovations/background-action action to v2 2026-07-27 08:29:46 +00:00
Ran Shemtov 3274398f72 fix(showcase/ms-agent-dotnet): resolve OPENAI_API_KEY-first via ApiKeyResolver (#6175)
## What
Ports `ms-agent-harness-dotnet`'s `ApiKeyResolver` into
`ms-agent-dotnet` so its 15 agent factories resolve the OpenAI
credential as `OPENAI_API_KEY` (env) → `config[OPENAI_API_KEY]` →
`GitHubToken`, and the endpoint via `OPENAI_BASE_URL` → default —
instead of hardcoding `configuration["GitHubToken"]` in each agent.

## Why
`ms-agent-dotnet`'s main chat clients authenticated **only** with the
GitHub token. On a fixture-miss fall-through, aimock proxies to real
`api.openai.com`, which rejects a GitHub token (`invalid_api_key`,
surfaced as HTTP 502) — the ms-agent-dotnet staging outage.
`ms-agent-harness-dotnet` already works because it resolves
`OPENAI_API_KEY` first; this brings `ms-agent-dotnet` to parity.

Interim showcase-side mitigation while the aimock cross-provider guard
(**PNI-108** / CopilotKit/aimock#340) is deferred. See also PNI-109
(inject `x-aimock-context`) and PNI-110 (per-request upstream routing).

## Changes
- Copy `agent/ApiKeyResolver.cs` verbatim from the harness column (code
copy, no new dependency)
- Rewire 15 factories + `A2uiSecondaryToolCaller` → `ResolveApiKey` /
`ResolveEndpoint`; drop each file's now-dead `DefaultOpenAiEndpoint`
const (−162/+47)
- Add `tests/ApiKeyResolverTests.cs` — 11 cases (precedence,
env-over-config, whitespace-skip, mock-endpoint fallback, non-mock
fail-fast)

## Verification
- `dotnet build` → **0 errors / 0 warnings**
- `dotnet test` → **76/76** (incl. 11 new resolver tests)
- `dotnet format whitespace --verify-no-changes` → clean
- **Live**: built the client exactly as the agents do, resolved a real
`OPENAI_API_KEY`, called `api.openai.com` → **200** (confirms the 502
path is fixed). Throwaway smoke, not committed.

## ⚠️ Operational follow-up (required to flip staging/prod)
`showcase-ms-agent-dotnet` must have a valid **`OPENAI_API_KEY`** set in
Railway (as `ms-agent-harness-dotnet` already does). This code enables
the behavior; the env var makes it live.

## Not run here
Showcase Docker value-test (`bin/showcase test ms-agent-dotnet:… --d6`)
— needs the container stack; worth running before merge.
2026-07-27 10:28:41 +02:00
Jordan Ritter 15a5a0dd99 test(showcase/ci): keep the imagetools fixtures byte-exact
The auto-format bot reflowed both captured registry payloads. Harmless this
time — oxfmt only rewraps arrays, it does not reorder keys — but the whole
value of these two files is that they are verbatim `imagetools inspect`
output. A formatter in the loop means the next re-capture churns, and the
"this is exactly what the registry emits" claim stops being checkable.

Exempt the fixture directory in .oxfmtrc.json, restore the captured bytes,
and say so in the provenance comment so nobody tidies them by hand.
2026-07-26 22:38:42 -07:00
github-actions[bot] 63e1a641e8 style: auto-fix formatting 2026-07-27 05:23:34 +00:00
Jordan Ritter 15222d8589 test(showcase/ci): make the :latest guard suite assert capability, not shape
The previous suite was 37/37 green against a workflow that could not have
run at all: the guard step had no `packages: write` and no GHCR login, so
every `imagetools create` would have 401'd. Asserting that a step EXISTS
proves nothing about whether it can succeed. Each change below was checked
by reintroducing the defect and confirming the test goes red.

Registry-auth precondition (the miss that let the above ship)
- Both redeploy jobs must declare `packages: write` AND a `docker/login-action`
  step for ghcr.io, ordered BEFORE the guard. Dropping either reds the suite.

The intersection, executed rather than restated
- The old test only checked that the string `images=` appears in the compute
  step; swapping its jq for the full matrix — so a FAILED build moves
  `:latest` — kept it green. The real `changed` shell now RUNS, against the
  real ALL_SERVICES matrix read out of the workflow, and the emitted
  $GITHUB_OUTPUT is asserted: a failed build is in neither set, and the
  `skip_build` slot is in `services` but NOT in `images` (handing it to the
  guard fails "manifest unknown" and blocks the redeploy for the whole fleet).
  Same treatment for the starter lane.

Fixtures joined to real registry output
- `extractRevisionLabel` was pinned to hand-written payloads that were never
  compared with reality. Since `readLatestRevision` maps every failure to
  null, and null ADVANCES, a parser that silently never matches yields a
  permanently-blind guard with a fully green suite. Both fixtures are now
  verbatim `docker buildx imagetools inspect --format '{{json .Image}}'`
  output (buildx v0.35.0), unformatted so key order survives: a platform-keyed
  multi-arch image carrying the label, and our own `:latest`, which turns out
  to be a bare config object with NO labels at all. The label key used in the
  injection test is read from the workflow's own `labels:` input, so parser
  and producer cannot drift apart silently.

Closed vacuities
- The `:latest` ban read one step's `tags` and was vacuously green on an empty
  list. It now covers every tagged step plus hand-rolled `docker push`/`docker
  tag`/`imagetools create`, and fails on an empty `tags`.
- The `cancel-in-progress` ban read only top-level config; a job-level
  `concurrency` on `build` reproduced the exact harm and stayed green. All
  jobs are checked now.
- `already-current` is keyed on the digest, matching the script.
- The unreachable `(null, "ahead")` row is labelled as the defensive
  input-space case it is, and a new test pins that the real flow never calls
  compare() with an unknown revision.

New coverage: classifyProbeFailure (incl. a REAL execFileSync timeout, and
the two precedence traps — gh's rate-limited 403 is throttling, not auth; a
registry's 404-with-denied is auth, not absent), readFlag, escapeAnnotationData
(a forged `\n::error::` stays inert), isDirectInvocation through a symlink,
the `::error` annotation on fleet failure, and the digest-mismatch advance.

Also: GITHUB_SHA / GITHUB_REPOSITORY are no longer shadowed in the workflow.
The runner exports both and the script reads process.env, so the old
assertions pinned a redundancy rather than a capability — removed together,
as the comment there required. Workflow-reading scaffolding duplicated with
redeploy-guard.test.ts is extracted and the YAML parse memoized.
2026-07-26 22:21:48 -07:00
Jordan Ritter e8c1380e8e fix(showcase/ci): harden advance-latest-tag against silent failure and digest drift
Targeted repairs around the decision logic, which is unchanged: the
compare direction, the `["behind"]`-only decline, and the fail-open
invariant are all preserved.

Digest/identity
- `already-current` keyed on the revision LABEL treated a rebuild of the
  same commit (CVE refresh, cache-miss, retry) as a no-op, stranding
  `:latest` on the older digest while digest-pinned prod moved. It now
  compares manifest DIGESTS, via a new `GuardIo.readDigest`, and only
  when the label claims we are already current — so the common path pays
  nothing.
- Retag passes `--prefer-index=false`. buildx carbon-copies a single
  index source (digest preserved) but WRAPS a bare manifest in a new
  index (digest changes) because `--prefer-index` defaults true. Our
  images are indexes only because provenance is enabled elsewhere; this
  pins the property regardless.

Observability — fail-open stays, silence does not
- `readLatestRevision` / `compare` no longer swallow the error. Failures
  are classified (absent / unauthorized / throttled / timeout /
  unavailable / unknown) and everything but a genuinely absent tag emits
  a `::warning` saying the guard has stopped guarding. Throttling is the
  likeliest failure under the concurrency this exists to handle and was
  previously indistinguishable from a clean first build.
- Annotations are properly escaped. Multi-line registry stderr was
  folding the real reason out of the annotation meant to report it;
  encoding newlines also makes an injected `::` inert.
- Subprocess timeout (60s, `ADVANCE_LATEST_TAG_TIMEOUT_MS`). A hung
  registry previously burned the job budget and concluded `cancelled`.
- The fleet result now names which images advanced, were unchanged, or
  declined — not just which failed.

Correctness / hygiene
- `extractRevisionLabel` collects every occurrence and answers only when
  they agree, so a multi-config payload no longer returns whichever label
  key ordering happened to surface last. Dropped the dead cycle guard.
- Flag parser no longer binds a following flag as a value (`--sha --repo
  x` yielded the literal `"--repo"` as the sha); `--flag=value` accepted;
  an empty `--images` is the documented no-op instead of exit 2.
- Entry guard canonicalises both sides, so a symlinked invocation runs
  instead of exiting 0 having done nothing.
- Docs: corrected the never-rethrown claim, the unreachable `identical`
  example, the self-contradicting `npx tsx` rationale, and the
  preconditions (a retag is a registry WRITE and needs `packages: write`
  plus a login, which the redeploy jobs do not currently have).
2026-07-26 22:04:28 -07:00
Jordan Ritter 428c9c301f ci: keep the guard's GITHUB_SHA/GITHUB_REPOSITORY env, asserted by the contract test
Reverts only the cosmetic third item from the previous commit. Dropping the
redundant GITHUB_SHA / GITHUB_REPOSITORY shadowing is functionally correct --
the runner exports both and advance-latest-tag.ts reads them off process.env
-- but showcase/scripts/advance-latest-tag.test.ts asserts those exact keys
are declared on the guard step, so removing them red "Validate Showcase".

RED (run 30238078822, "Validate Showcase" > Run build pipeline tests):

  Failed Tests 2
   FAIL advance-latest-tag.test.ts > showcase_build.yml - redeploy-staging job
        > runs the guard with the image list, sha, repo and a token
   FAIL advance-latest-tag.test.ts > showcase_build.yml - redeploy-staging-starters
        job > runs the guard with the image list, sha, repo and a token
   AssertionError: expected undefined to be '${{ github.sha }}'
     - Expected: "${{ github.sha }}"
     + Received: undefined
     advance-latest-tag.test.ts:424

GREEN (same six contract assertions per job, replicated against the YAML --
the test is pure yaml-parse, no runtime deps):

  redeploy-staging / redeploy-staging-starters
    PASS IMAGES   PASS GITHUB_SHA   PASS GITHUB_REPOSITORY
    PASS GH_TOKEN truthy   PASS guard `if`   PASS guard BEFORE redeploy

The test file is owned by a concurrent agent on this PR, so the assertions
cannot be relaxed here. If the redundancy is worth removing, the env keys and
the assertions must go together in one change.

Everything else from the previous commit is untouched and was already
validated by that CI run -- only these two assertions failed, so the GHCR
login, `packages: write`, the skip_build/images filter, the timeout bump and
the tsx pin all passed.

Lint unchanged: actionlint 10 findings before and after (0 new); zizmor
CI-equivalent reports "No findings" before and after.
2026-07-26 21:53:20 -07:00
Jordan Ritter 3450d7d7cd ci: give the :latest guard GHCR auth and keep skip_build slots out of the retag set
Two Critical defects in the new "Advance :latest" guard, both of which would
have broken staging redeploys on this PR's own merge commit.

1. Registry auth missing. `redeploy-staging` and `redeploy-staging-starters`
   run `docker buildx imagetools create` (an authenticated GHCR WRITE) but
   declared only `permissions: contents: read` with no `docker/login-action`
   step. Every retag would 401, the guard would exit 1, the redeploy step
   would be skipped -- and since the build step no longer pushes `:latest`
   itself, `:latest` would freeze permanently and staging would never
   redeploy again. The same missing auth also 401s `imagetools inspect` on
   these private packages, which the guard treats as "unknown revision" and
   advances anyway: it would have failed OPEN and never actually guarded.

   Fixed by adding `packages: write` plus a GHCR login mirroring the `build`
   job's existing "Login to GHCR" step. Restores both the read and write path.

2. skip_build slots entered the retag list. The `images` CSV projection did
   not exclude `skip_build` slots. `webhooks` is built out-of-band, never
   pushes a `:<sha>` tag, yet reports job.status: success -- so it reached the
   guard, `imagetools create` failed with "manifest unknown", and the whole
   fleet's redeploy was blocked. Fires on `service=all` dispatch and via the
   `workflow_config` path filter.

   Fixed by carrying `skip_build` through the jq projection and filtering it
   out of `images` ONLY. It stays in `services`: bouncing webhooks so Railway
   re-pulls its out-of-band `:latest` is the documented intent (see the
   `webhooks` entry in showcase/scripts/railway-envs.ts).

Also, same file:
 - timeout-minutes 5 -> 20 on both jobs. The guard adds up to 3 serial
   round-trips per slot (~84 at full fleet width). An overrun concludes
   `cancelled`, which is invisible to both `if: failure()` and
   `if: cancelled()` downstream -- the alerting-suppression class this repo
   has been fixing.
 - `npx tsx` -> `npx --yes tsx@4.21.0` (the pnpm-lock-resolved version),
   matching the no-drift convention showcase_validate.yml enforces via
   `pnpm exec tsx`. `pnpm exec` is unavailable here: no workspace install.
 - Dropped the redundant GITHUB_SHA / GITHUB_REPOSITORY shadowing; the runner
   exports both and advance-latest-tag.ts reads them off process.env.

Deliberately NOT added: a `concurrency` group. Its absence is load-bearing --
detect-changes builds a path-filtered per-push matrix, so concurrent runs
build disjoint service sets and cancelling the older run would leave services
never shipped rather than merely stale.

RED/GREEN
---------
Workflow auth cannot be fully proven without merging, so the proof is scoped
to what is actually demonstrable locally. Both probes lift the code under test
VERBATIM out of the workflow at runtime rather than paraphrasing it.

Probe A -- the real jq projection, fed the real ALL_SERVICES array with a
`service=all` / `workflow_config` dispatch (every slot selected, every slot
status:success, which is exactly what the skip_build slot reports):

  RED   images  : ...,ghcr.io/copilotkit/showcase-eval-webhook   (28 entries)
        services: ...,webhooks
        -> webhooks IS in the retag set. imagetools create -> manifest unknown.

  GREEN images  : ends ...,ghcr.io/copilotkit/showcase-pocketbase (27 entries)
        services: ...,webhooks   (unchanged, still 28)
        -> webhooks OUT of images, STILL IN services. Exactly the split wanted.

Probe B -- structural parse of the workflow, over every job that runs
advance-latest-tag.ts:

  RED   redeploy-staging          permissions={'contents':'read'}  login=NO
        redeploy-staging-starters permissions={'contents':'read'}  login=NO
        VERDICT: 2 retag job(s) lacking GHCR auth

  GREEN redeploy-staging          permissions={'contents':'read',
                                               'packages':'write'} login=YES
        redeploy-staging-starters permissions={'contents':'read',
                                               'packages':'write'} login=YES
        VERDICT: 0 retag job(s) lacking GHCR auth

Lint (delta vs the pre-fix file, not raw counts)
------------------------------------------------
actionlint : 10 findings before, 10 after; 0 new, 0 removed (all pre-existing
             depot runner-label + SC2086 noise).
zizmor     : CI-equivalent (--min-severity low, default persona, repo config)
             reports "No findings" both before and after. Auditor persona at
             all severities is also identical before/after (1 concurrency-limits,
             1 template-injection, 3 undocumented-permissions, 6
             anonymous-definition, 9 secrets-outside-env) -- the two new
             `packages: write` entries carry trailing justification comments so
             they add no undocumented-permissions findings.
2026-07-26 21:47:28 -07:00
Mark a3ad8960c9 Merge branch 'main' into mark/ms-agent-dotnet-apikeyresolver 2026-07-26 21:44:10 -07:00
Jordan Ritter cacfaca70d Merge remote-tracking branch 'origin/main' into ci/showcase-latest-tag-race 2026-07-26 21:21:17 -07:00
Ben Taylor e9148b3050 fix(sdk-python): bridge copilotkit context into LangGraph subgraphs (#5373)
## Summary

`CopilotKitMiddleware` loses frontend actions and app context when a
middleware-wrapped agent runs as a LangGraph subgraph. Parent graphs
propagate run context to child nodes, but `state["copilotkit"]` stays
empty there, so the child misses both frontend-tool injection and the
`App Context:` note.

## Root cause

`LangGraphAGUIAgent.langgraph_default_merge_state(...)` materializes
CopilotKit data into state for top-level runs, but child LangGraph nodes
inherit runtime context rather than arbitrary parent state. The missing
piece was earlier in the write path: by the time the base agent calls
`get_stream_kwargs(...)`, it has already replaced the original AG-UI
request with merged graph state, so serializing from that argument drops
the frontend tools and app context on the real subgraph path.

The fix moves ownership to the run entry: `LangGraphAGUIAgent.run(...)`
now captures the frontend tools and app context from the real
`RunAgentInput`, and `get_stream_kwargs(...)` forwards that captured
payload into LangGraph using `context["copilotkit"]` when the graph
supports runtime context, or `config["configurable"]["copilotkit"]` on
older graph shapes. `CopilotKitMiddleware` still uses one shared lookup
order everywhere it reads CopilotKit data: `state["copilotkit"]`, then
`runtime.context["copilotkit"]`, then LangGraph config fallbacks. That
same carrier now drives the app-context-note helper path too.

## Changes

- `sdk-python/copilotkit/langgraph_agui_agent.py`: capture frontend
actions and app context from the original `RunAgentInput` in `run(...)`,
then write the captured payload into the LangGraph runtime carrier that
the current graph shape supports before the subgraph starts.
- `sdk-python/copilotkit/copilotkit_lg_middleware.py`: unify
frontend-tool, app-context, and interception lookups around the same
carrier order, and cover the current-`main` app-context helper path.
- `sdk-python/tests/test_agui_agent.py`: add focused coverage for both
the runtime-context path and the configurable fallback path on graphs
without `context` support.
- `sdk-python/tests/test_copilotkit_lg_middleware.py`: replace the
manually seeded subgraph proof with a real `LangGraphAGUIAgent.run(...)`
regression that reaches the child middleware through the production
path.

## What is NOT changed

- Top-level agents still prefer `state["copilotkit"]`; the runtime
bridge only fills the subgraph gap.
- Header propagation behavior is unchanged.
- No JS LangGraph executor changes are part of this PR.

## Related PRs and Issues

Closes #3886.

## Test plan

- [x] `cd sdk-python && pytest tests/test_agui_agent.py
tests/test_copilotkit_lg_middleware.py -q` - 108/108 pass. Covers the
AGUI run-entry bridge, the configurable fallback for graphs without
`context` support, frontend-tool injection, app-context note injection,
and a real `create_agent` subgraph invocation through
`LangGraphAGUIAgent.run(...)`.
- [x] `ruff check sdk-python/copilotkit/copilotkit_lg_middleware.py
sdk-python/copilotkit/langgraph_agui_agent.py
sdk-python/tests/test_agui_agent.py
sdk-python/tests/test_copilotkit_lg_middleware.py` - pass. Covers Python
lint on every touched file.
- [x] `ruff format --check
sdk-python/copilotkit/copilotkit_lg_middleware.py
sdk-python/copilotkit/langgraph_agui_agent.py
sdk-python/tests/test_agui_agent.py
sdk-python/tests/test_copilotkit_lg_middleware.py` - pass. Covers repo
formatting on every touched file.
- [ ] CI green (`static / quality`, `test / unit` on Node 20/22/24)
2026-07-26 23:19:52 -05:00
Jordan Ritter 3ff7a51606 fix(showcase): pin ag2<1.0.0 to unblock CI after upstream module rename (#6176)
## What's broken

`ag2` **1.0.0 was published to PyPI at 2026-07-27T00:58:37Z**. It
renames the top-level module from `autogen` to `ag2` and ships **no
`autogen/` package at all**.

`showcase/integrations/ag2/requirements.txt` floated on
`ag2[openai,ag-ui]>=0.9.0`, so every *fresh* CI dependency resolution
now pulls 1.0.0 and pytest collection dies on import.

This breaks `Python unit tests (3.10)` and `Python unit tests (3.12)` in
`showcase_validate.yml` **on `main` and on every open PR**. It's
time-based, not commit-based — `main` currently reads green only because
it hasn't re-run since the release landed.

### Release timing evidence

From the PyPI JSON API:

| version | upload_time_iso_8601 |
|---|---|
| 0.14.0 | `2026-06-26T04:48:39.784002Z` |
| 1.0.0  | `2026-07-27T00:58:37.996353Z` |

### Wheel layout proof

Top-level directories in each wheel:

```
=== ag2 0.14.0 ===        === ag2 1.0.0 ===
ag2-0.14.0.dist-info      ag2
autogen                   ag2-1.0.0.dist-info
templates
```

`autogen/` is simply gone in 1.0.0.

## Why pin instead of migrating the imports

**Because 1.0.0 is not a rename — it's an API change.** Diffing the
wheels:

1. `autogen/ag_ui/adapter.py` (the stable, `AgentService`-based
`AGUIStream`) is **deleted**. `ag2/ag_ui/` in 1.0.0 is the *promoted
former `autogen.beta.ag_ui`* — a different implementation with
`events.py`/`stream.py`, matching old `autogen/beta/ag_ui/`, not old
`autogen/ag_ui/`.

2. The constructor lost a parameter:
   ```python
   # 0.14.0 autogen/ag_ui/adapter.py
   def __init__(self, agent, *, event_interceptors=()) -> None:
   # 1.0.0 ag2/ag_ui/stream.py
   def __init__(self, agent: Agent) -> None:
   ```

3. `dispatch()` changed shape — `context=` is **gone**, replaced by
`variables=` plus new
`prompt`/`dependencies`/`config`/`tools`/`middleware`/`observers`/`hitl_hook`
kwargs.

`showcase/integrations/ag2/src/agents/_multimodal_normalize.py:330`
subclasses `AGUIStream` and calls:

```python
async for chunk in super().dispatch(incoming, context=context, accept=accept):
```

So a naive import-path rewrite would trade a loud `ModuleNotFoundError`
at import time for a **silent-until-hit `TypeError` at request time** —
strictly worse while CI is on fire. A genuine 1.0 migration has to port
~20 `autogen` import sites (including
`autogen.agentchat.ContextVariables`, `autogen.tools.tool`,
`autogen.code_utils.content_str`) and re-verify every ag2 demo cell
behaviorally. That's real work, not an unblock.

## Coverage — every `ag2` dependency site

Swept all `requirements*.txt`, `*.lock`, `uv.lock`, `poetry.lock`, and
`pyproject.toml` in the repo:

```
./showcase/integrations/ag2/requirements.txt:1:ag2[openai,ag-ui]>=0.9.0
```

**Exactly one** declaration — no lockfile pins it, no other integration
depends on it, transitively or otherwise. All `autogen` imports live
under `showcase/integrations/ag2/`. This one-line bound closes the whole
surface; nothing else is left floating.

## Red-green proof

Both runs use a clean `python3.12 -m venv` + `pip install -r
requirements.txt`, i.e. a fresh resolution exactly like CI's.

### RED — before the fix (resolves ag2 1.0.0)

```
$ pip show ag2 | head -2
Name: ag2
Version: 1.0.0

$ python -m pytest tests/python/ -q
==================== ERRORS ====================
________ ERROR collecting tests/python/test_multimodal_normalize.py ________
ImportError while importing test module '.../tests/python/test_multimodal_normalize.py'.
Traceback:
tests/python/test_multimodal_normalize.py:77: in <module>
    from agents._multimodal_normalize import (  # noqa: E402
src/agents/_multimodal_normalize.py:75: in <module>
    from autogen.ag_ui import AGUIStream, RunAgentInput
E   ModuleNotFoundError: No module named 'autogen'
=============== short test summary info ===============
ERROR tests/python/test_multimodal_normalize.py
!!!!!! Interrupted: 1 error during collection !!!!!!
1 warning, 1 error in 0.30s
```

### GREEN — after the fix (resolves ag2 0.14.0)

```
$ pip show ag2 | head -2
Name: ag2
Version: 0.14.0

$ python -m pytest tests/python/ -q
......................                                        [100%]
=============== warnings summary ===============
tests/python/test_cvdiag_boundaries.py:34
  StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated

22 passed, 1 warning in 1.52s
```

## Follow-up left undone

Pinning defers the migration; it doesn't cancel it. What remains:

- **Port to ag2 1.x.** Rewrite ~20 `autogen.*` imports to `ag2.*`,
replace the deleted adapter-based `AGUIStream` with the new stream API,
drop/replace `event_interceptors` in `_multimodal_normalize.py`, and
convert `dispatch(context=...)` to `dispatch(variables=...)`. Then
behaviorally re-verify every ag2 demo cell — the beta stream promoted
into `ag2.ag_ui` is a different implementation, so cell-level parity
cannot be assumed from a green unit suite.
- **Renovate** will eventually propose lifting the `<1.0.0` bound. That
PR must not be merged as a routine bump; it's the migration above.
- The inline comment in `requirements.txt` records all of this at the
point of change so the bound isn't lifted casually.

## Second commit: `validate-pins` ratchet hash

The `Validate Showcase` job's `validate-pins (ratchet)` step failed on
the first push. Cause is benign and expected: `ag2` matches
`FRAMEWORK_PATTERNS`, which demands an exact `==` pin, so the dep was
**already** in the drift baseline as a `[FAIL]`. Adding `,<1.0.0`
changes that line's text, which changes the SHA-256 the ratchet takes
over the sorted FAIL set.

Verified the FAIL *set* is otherwise untouched — I reproduced the
committed baseline hash on a pristine `origin/main` tree, then diffed:

```
$ diff <(pristine FAIL lines) <(fixed FAIL lines)
 [FAIL] ag2: ag-ui-protocol is not an exact pin (>=0.1.10)
-[FAIL] ag2: ag2 is not an exact pin (>=0.9.0)
+[FAIL] ag2: ag2 is not an exact pin (>=0.9.0,<1.0.0)
 [FAIL] ag2: openai is not an exact pin (>=1.50.0)
```

Exactly one line differs. `Summary: OK=5 SKIP=0 WARN=3 FAIL=31` both
before and after — **count unchanged at 31**, nothing healed, nothing
regressed. So this is a hash-only baseline update and the "never raise
the count without sign-off" invariant is not engaged.

Pristine run reproduced `b47ca987…` (identical to the committed
baseline), confirming the validator is deterministic and this diff is
the sole delta.

### Why a range bound rather than an exact `==0.14.0`

An exact pin would satisfy `validate-pins` outright and ratchet the
count 31 → 30, but I kept the range deliberately:

- `0.14.0` is the highest final pre-1.0 release and the 0.x line is now
legacy, so the range resolves to exactly `0.14.0` today — proven by the
GREEN run above.
- `1.0.0b0` sorts below `1.0.0` under PEP 440, but pip excludes
pre-releases when a final release satisfies the specifier, so the bound
cannot pull the beta. Empirically confirmed: the GREEN venv resolved
`0.14.0`.
- It leaves room for a future `0.14.x` patch or security release without
another PR.
- It matches the sibling deps in the same file (`ag-ui-protocol>=`,
`openai>=`) and keeps this urgent fix to a pure hash bump rather than a
count ratchet.

Tightening to an exact pin (and ratcheting the count down) is reasonable
follow-up if the team wants to drive `validate-pins` drift toward zero,
but it's a pin-discipline cleanup, not part of this unblock.
2026-07-26 21:16:10 -07:00
Jordan Ritter 4947c4a785 fix(showcase): update validate-pins hash for the ag2 bound
The `<1.0.0` upper bound changes the text of an existing `[FAIL]` line
from `ag2 is not an exact pin (>=0.9.0)` to `(>=0.9.0,<1.0.0)`, which
shifts the ratchet's SHA-256 over the sorted FAIL set.

The FAIL *set* is otherwise identical -- count stays 31, nothing healed
and nothing regressed. Verified by reproducing the committed baseline
hash b47ca987 on a pristine origin/main tree, then diffing the FAIL
lines against the fixed tree; exactly one line differs:

    -[FAIL] ag2: ag2 is not an exact pin (>=0.9.0)
    +[FAIL] ag2: ag2 is not an exact pin (>=0.9.0,<1.0.0)

`ag2` matches FRAMEWORK_PATTERNS, which demands an exact `==` pin, so
the dep was already in the baseline's drift set before this change and
remains in it after. Hash-only update; the count is untouched, so the
"never raise the count without sign-off" invariant is not engaged.
2026-07-26 21:07:32 -07:00
Jordan Ritter 5a09e0e787 fix(showcase): pin ag2<1.0.0 to unblock CI after upstream module rename
ag2 1.0.0 (published 2026-07-27T00:58:37Z) renames its top-level module
from `autogen` to `ag2` and ships no `autogen/` package at all. The ag2
integration floats on `ag2[openai,ag-ui]>=0.9.0`, so every fresh CI
resolution now picks up 1.0.0 and collection fails at:

    src/agents/_multimodal_normalize.py:75
        from autogen.ag_ui import AGUIStream, RunAgentInput
    E   ModuleNotFoundError: No module named 'autogen'

This breaks `Python unit tests (3.10)` and `(3.12)` in showcase_validate
on main and on every open PR. It is time-based rather than commit-based:
main only looks green because it has not re-run since the release.

Pin rather than migrate. 1.0.0 is not a rename -- it deletes the stable
`autogen/ag_ui/adapter.py` and promotes the former `autogen.beta.ag_ui`
stream into its place, dropping `AGUIStream(event_interceptors=...)` and
replacing `dispatch(context=...)` with `dispatch(variables=...)`. Since
`_multimodal_normalize.py` overrides `dispatch` and forwards `context=`,
rewriting the import path alone would swap an import error for a runtime
TypeError. A real migration needs to port ~20 `autogen` import sites and
re-verify every ag2 demo cell, which is not an urgent-unblock change.
2026-07-26 21:03:03 -07:00
Mark a9ce37b75c fix(showcase/ms-agent-dotnet): resolve OPENAI_API_KEY-first via ApiKeyResolver
Port ms-agent-harness-dotnet's ApiKeyResolver into ms-agent-dotnet so the 15
agent factories resolve the OpenAI credential as OPENAI_API_KEY (env) ->
config[OPENAI_API_KEY] -> GitHubToken, and the endpoint via OPENAI_BASE_URL ->
default, instead of hardcoding configuration["GitHubToken"] per agent.

Previously ms-agent-dotnet's main chat clients authenticated only with the
GitHub token. On a fixture-miss fall-through, aimock proxies to real
api.openai.com, which rejects the GitHub token (invalid_api_key, surfaced as
502). ms-agent-harness-dotnet already works because it resolves OPENAI_API_KEY
first; this brings ms-agent-dotnet to parity so its fall-through returns 200.

Interim showcase-side mitigation while the aimock cross-provider guard
(PNI-108, CopilotKit/aimock#340) is deferred.

- Copy agent/ApiKeyResolver.cs verbatim from ms-agent-harness-dotnet (code
  copy, no new dependency)
- Rewire 15 factories + A2uiSecondaryToolCaller to ResolveApiKey/ResolveEndpoint;
  drop the dead per-file DefaultOpenAiEndpoint const
- Add tests/ApiKeyResolverTests.cs (precedence, mock-endpoint fallback,
  non-mock fail-fast)

Verified: dotnet build 0/0, dotnet test 76/76, whitespace format clean, and a
live OpenAI call through the resolver returned 200.
2026-07-27 03:56:33 +00:00
Ben Taylor 063750a19e fix(react-ui): reduce sidebar CSS specificity (#5805)
## Summary
- lowers CopilotSidebar-scoped CSS selector specificity with
`:where(.copilotKitSidebar)`
- keeps the existing sidebar styles and layout behavior unchanged
- adds a regression test to keep sidebar selectors easy for app CSS to
override

## Root cause
Sidebar-specific selectors such as `.copilotKitSidebar
.copilotKitWindow` were more specific than ordinary user overrides like
`.copilotKitWindow`, so user CSS could lose precedence in Chrome.

Fixes #263.

## Validation
- `pnpm -C packages/react-ui test`
- `pnpm exec oxfmt --check
packages/react-ui/src/css/sidebar-specificity.test.ts
packages/react-ui/src/css/window.css
packages/react-ui/src/css/header.css
packages/react-ui/src/css/input.css`
- `pnpm exec oxlint
packages/react-ui/src/css/sidebar-specificity.test.ts`
2026-07-26 22:49:37 -05:00
Jordan Ritter 5afff788dd Merge remote-tracking branch 'origin/main' into ci/showcase-latest-tag-race 2026-07-26 19:20:29 -07:00
Ben Taylor 21cd27ce50 fix(react-core): stop CopilotPopup remounting chat on resize (#6173)
## What does this PR do?

Fixes a bug where resizing a `CopilotPopup` (v2) rescrolls the message
list from top to bottom on every resize, regardless of the user's scroll
position.

**Root cause.** `CopilotPopup` built its `chatView` override component
inside a `useMemo` keyed on `width`/`height`. When those props change —
which happens continuously for consumers driving them from a
drag-to-resize handle that commits new dimensions on `mouseup` —
`useMemo` returns a **new component function**. That function is passed
to `CopilotChat` as the `chatView` slot and rendered via
`React.createElement(newType, …)`. Because React sees a new element
**type** at that position, it unmounts and remounts the entire chat
subtree rather than re-rendering it. The remount resets the scroll
container's `scrollTop` to `0`, after which the default
`initial="smooth"` auto-scroll animates the list from the top back down
to the bottom — the visible "rescroll" on every resize.

**Fix.** Give the override a stable module-scope identity so its type
never changes, and pass the popup shell props (`header`, `toggleButton`,
`width`, `height`, `clickOutsideToClose`, `defaultOpen`) through React
context instead of baking them into the override via `useMemo` deps.
Resizing is now a plain style update on `CopilotPopupView` — no remount
— so scroll position is preserved. `Object.assign` still copies the
`CopilotChatView` static slot members onto the override so callers
reaching them through the namespace continue to work.

**Test.** Adds a regression test (`CopilotPopup.resizeRemount.test.tsx`)
that injects a mount-counting component into the chat subtree and
asserts its mount count stays at `1` across several `width`/`height`
changes. It fails on the pre-fix code (one extra mount per resize —
observed `4` for 3 resizes) and passes with the fix.

Scope is limited to `packages/react-core`:

```
packages/react-core/src/v2/components/chat/CopilotPopup.tsx                               | 124 +++++++++------
packages/react-core/src/v2/components/chat/__tests__/CopilotPopup.resizeRemount.test.tsx  |  98 +++++++++++
2 files changed, 185 insertions(+), 37 deletions(-)
```

Verification: full `@copilotkit/react-core` unit suite green (1443
tests), `check-types` green.

## Related PRs and Issues

- Closes #6172

## Checklist

- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [ ] If the PR changes or adds functionality, I have updated the
relevant documentation — _N/A: internal behavior fix, no public API or
documented behavior change_
- [x] "Allow edits by maintainers" is checked
2026-07-26 18:02:15 -05:00
Rod Boev a76d59ae0b fix(sdk-python): capture subgraph context from run input (#3886) 2026-07-26 16:42:46 -04:00
Ben Taylor 73fe697b15 fix(web-inspector): handle empty tool result content (#5603)
## Summary

Fixes the web inspector crash when historical tool result messages have
empty `content`.

Some stored thread tool-result messages can have `content: ""`. The
inspector previously parsed tool result content with
`JSON.parse(msg.content ?? "{}")`, which still passes the empty string
into `JSON.parse` and throws `Unexpected end of JSON input`.

## Changes

-> Treat empty and whitespace-only tool result content as an empty
result object
-> Keep malformed non-empty result content flowing through the existing
parse-error fallback
-> Add regression coverage for empty and whitespace-only tool result
messages in the thread conversation mapper

## Testing

-> `pnpm exec oxlint packages/web-inspector/src/index.ts
packages/web-inspector/src/__tests__/web-inspector.spec.ts`
-> `pnpm -C packages/web-inspector exec vitest run
src/__tests__/web-inspector.spec.ts --pool=threads --testNamePattern
"maps empty tool result content" --reporter=verbose`

## Notes

-> `pnpm nx show project @copilotkit/web-inspector --json` timed out
locally
-> `pnpm -C packages/web-inspector run check-types` is currently blocked
by existing package-level TypeScript errors around explicit `.js` import
extensions and one unrelated existing error

## Related Issue

Closes #5598
2026-07-26 14:53:45 -05:00