Commit Graph

289 Commits

Author SHA1 Message Date
Alem Tuzlak 65928b9ca3 Merge remote-tracking branch 'origin/main' into worktree-lucky-popping-wren
# Conflicts:
#	package.json
2026-05-20 10:54:04 +02:00
tylerslaton efae3dfb5b chore: release monorepo v1.57.3 2026-05-19 15:59:44 +00:00
Alem Tuzlak 6d49ecbb7b fix(showcase, runtime): subagents fixtures, voice mic format, fine-grained shared-state gating
Three follow-ups on top of PR #4837 that I had on the same branch but
didn't make it into the squash merge.

1. **packages/runtime: stamp `audio/webm` on empty-type Blobs in the
   transcription handler.** Browser MediaRecorder writes the audio as
   webm/opus, but the Blob's `type` field is often empty by the time it
   hits the server. `isValidAudioType` lets empty / octet-stream through
   for compatibility, but OpenAI Whisper then rejects the upload with
   `502 Invalid file format. Supported formats: ['flac', 'm4a', 'mp3',
   'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm']` because it
   can't pick a decoder. Reconstructing the File with an explicit
   `audio/webm` type (and a `.webm` filename fallback) makes Whisper
   accept the bytes that were already valid. Monorepo-wide — applies to
   every integration using `/api/copilotkit-voice/transcribe`.

2. **showcase/aimock/feature-parity.json: port 12 subagents fixtures
   from d5-all.json** so the three pills (cold-exposure blog, LLM
   tool-calling explanation, reusable-rockets summary) work in
   production. d5-all.json already has the full research → writing →
   critique chain with substantive content; feature-parity only had the
   single LP remote-work pill. Production aimock loads both files but
   any case where feature-parity wins first-match needs the same
   content. Verbatim port — no fabricated text. Net result: no more
   `[sub-agent error] the writing agent...` on the demo's pills.

3. **showcase/aimock both files: scope shared-state-read-write Greet +
   Plan-a-weekend fixtures with a true all-defaults systemMessage
   gate.** The PR #4837 gate (`systemMessage: "tone: casual"`) only
   caught tone changes — name / language / interests changes still hit
   the canned fixture. Replaced with a two-element array gate (aimock
   supports all-present substring matching, verified in
   `/app/dist/router.js`):
     - `preferences:\n- Preferred tone: casual\n` — breaks if name is
       set (Name line inserts between signature and tone) or tone changes.
     - `- Preferred language: English\nTailor every response` — breaks
       if language changes or interests are added (Interests line
       inserts between language and Tailor).
   With `--provider-gemini` already wired in both local docker-compose
   and Railway prod, any state change now proxies to real Gemini and
   returns a personalised reply.

4. **showcase/aimock/feature-parity.json: re-remove bare 'plan' /
   'steps' / 'mars' / 'dashboard' / 'report' substring catch-alls + the
   bare 'alice' / 'Alice' fixtures.** These were removed in commit
   `ddc2e179` on the PR #4837 branch but didn't survive the squash
   merge, so they're back in main and still hijacking hitl-in-app
   downgrade-#12346 ('plan'), shared-state-rw weekend pill ('plan'),
   subagents 'rockets' pills, hitl-in-chat Schedule-1:1 with Alice
   ('alice'). Replace the alice pair with a single scoped
   `Hi, my name is Alice` fixture for the showcase-assistant
   introduction flow.

Local verification:
- `bin/showcase test google-adk --d5` → 38/38 green, 165s.
- Paired curl on shared-state-read-write:
  - Default state → canned fixture ("Hi — I'm your shared-state co-pilot…")
  - `name=alem` → real Gemini ("Hi there! …")
  - `interests=[Cooking, Travel]` weekend pill → real Gemini ("Hey
    there! Since you're into cooking and travel, how about a weekend
    plan that combines both?")

Production deploys this PR will pick up the aimock fixture changes
(prod loads feature-parity.json from GitHub raw at boot — no image
rebuild needed for that file) plus the runtime change once the
packages/runtime build is republished.
2026-05-15 15:57:31 +02:00
tylerslaton 1b14504788 chore: release monorepo v1.57.2 2026-05-13 00:40:27 +00:00
github-actions[bot] fd5e8e7c20 style: auto-fix formatting 2026-05-12 16:33:44 +00:00
Alem Tuzlak cdb5f44fb5 test(reasoning-chain): add regression coverage at runtime, harness, and e2e layers
Three layers of regression guards for the runtime reasoning-role filter and
the chained demo behavior:

1. Runtime unit test — packages/runtime/.../run-message-filtering.test.ts:
   - Verifies `LangGraphAgent.run` strips `role:"reasoning"` from
     `input.messages` before delegating to super.run.
   - Verifies user/assistant/system/tool messages pass through in order.
   - Verifies empty + missing messages arrays are tolerated.
   - Verifies pre-existing forwardedProps.streamSubgraphs default + override
     behavior is preserved.
   - 6/6 tests pass against the runtime package's vitest config.

2. D5 harness probe — showcase/harness/.../d5-tool-rendering-reasoning-chain.ts:
   - Expanded from one chained turn (flights→weather) to all three chained
     pills in a single thread (stocks AAPL→MSFT, dice d20→d6, flights→weather).
   - This is the canonical multi-pill regression at the harness layer:
     without the runtime reasoning-role filter, the second pill would crash
     before the model was called.
   - Each turn asserts the per-turn delta of reasoning-block mounts (idx+1),
     the minimum card count for each tool group, and unique transcript
     substrings that scope to that turn.

3. Playwright e2e spec — showcase/integrations/langgraph-python/tests/e2e/
   tool-rendering-reasoning-chain.spec.ts:
   - Mirrors the pattern of the sibling tool-rendering-default-catchall spec
     (notably its multi-pill regression at lines 162-212).
   - Page-loads test verifies the 3 pills mount and no cards leak from a
     prior session.
   - One test per chained pill (stocks, dice, flights+weather) asserts the
     full chain renders with reasoning-block + correct per-tool cards +
     narration matching the aimock fixture text.
   - Sequential-pills regression test clicks all 3 pills in one thread,
     asserts each chain renders independently AND the reasoning-block count
     increases monotonically across turns.

Agent: extend `get_stock_price` to accept optional `price_usd` and
`change_pct` arguments (mirrors the basic tool-rendering agent's signature
introduced in #4770). The aimock fixtures script the chained AAPL/MSFT
comparison by passing deterministic prices via these args; without the
wider signature, pydantic rejects the tool call and the card never mounts.

The runtime unit test is the strongest guard — it would catch any
regression on the role-filter logic without depending on the full Docker
stack. The harness probe and Playwright spec catch end-to-end regressions
in the canonical CI environment.
2026-05-12 18:29:27 +02:00
Alem Tuzlak e4764324c5 fix(runtime/langgraph): filter reasoning-role messages before AG-UI converter
`@ag-ui/langgraph`'s message converter handles only user/assistant/system/tool
roles and throws `"message role is not supported."` on anything else. Agents
that stream reasoning summaries (OpenAI Responses API + `reasoning={summary:
"detailed"}`) emit AG-UI messages with `role: "reasoning"` that the AG-UI
client replays in the next turn's `input.messages`; the converter then crashes
before the model is ever called and the second pill click in a multi-turn
thread produces an `INCOMPLETE_STREAM` error.

Strip `role: "reasoning"` from `input.messages` inside CopilotKit's
LangGraphAgent.run subclass before delegating to super. This is the narrowest
fix at the runtime/AG-UI boundary — only the inbound message list is filtered,
the outbound event stream still carries reasoning summaries to the client, so
the `<ReasoningBlock>` slot continues to render on the active turn.
2026-05-12 17:21:21 +02:00
Martha Schumann ce35cba85e feat(inspector/telemetry): propagate telemetryDisabled from runtime env var through inspector
- Add telemetryDisabled to RuntimeInfo from COPILOTKIT_TELEMETRY_DISABLED/DO_NOT_TRACK env vars
- Mirror through AgentRegistry and expose via CopilotKitCore getter
- Guard track calls, URL param appending, and console disclosure on core.telemetryDisabled
- Move maybeShowDisclosure() to onRuntimeConnectionStatusChanged (fires after core attaches)
- Update docs to replace localStorage toggle description with env var approach
- Add telemetryDisabled test suite to get-runtime-info tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
Martha Schumann db17476883 fix(inspector): update wire body shape + typed helpers + full test coverage (OSS-96)
- Move `package` from properties string to top-level `{ name }` object per
  Ben's confirmed IngestPayload schema (telemetry-sink-ingest/index.ts:127-134)
- Add typed per-event helpers trackBannerViewed/trackBannerClicked/trackThreadsTabClicked
  to enforce property shapes at call sites and prevent PII leakage under wrong keys
- Add trackBannerClickedOnce guard in index.ts (per-mount Set keyed by
  banner_id + cta) to prevent banner_clicked inflation on repeated clicks
- Fix handleTelemetryOptOutToggle: replace ?? true fallback with
  instanceof HTMLInputElement guard (wrong fallback was a privacy bug)
- Add threadsTabClicked re-selection guard (skip if already on threads tab)
- Replace getTelemetryDistinctIdForUrl() call on mount with ensureTelemetryDistinctId()
- Add inMemoryFallbackId in persistence.ts for funnel coherence when
  localStorage is unavailable (same UUID returned per page load)
- Add _resetTelemetryPersistenceForTesting() for test isolation
- Remove @copilotkit/shared dep from telemetry-disclosure.ts (inline
  env-var check; keeps module self-contained and testable in isolation)
- Add clearMocks: true to web-inspector vitest config (fixes spy call
  history accumulating across tests)
- Expand telemetry.test.ts to 22 tests covering wire body shape, opt-out,
  5 error-resilience paths, typed helpers, distinct ID lifecycle (SSR +
  localStorage-throws + funnel coherence), maybeShowDisclosure, and
  getTelemetryDistinctIdForUrl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 15:43:17 -05:00
Claude 7914275c99 feat(inspector): add anonymous interaction telemetry (OSS-96)
Three V1 funnel events from the inspector — oss.inspector.banner_viewed,
oss.inspector.banner_clicked, oss.inspector.threads_tab_clicked — plus a
privacy panel for opt-out, a first-run console disclosure on inspector
mount and runtime startup, and inspector content added to the canonical
/telemetry docs page on main.

Inspector POSTs directly from the browser to telemetry.copilotkit.ai/ingest
(per ticket: URL is intentionally clearly named for transparency in DevTools).
Inline fetch POST in lib/telemetry.ts — no @copilotkit/shared dep on the
inspector, no dependency on any non-main branch.

Wire body shape (conservative; needs Ben confirmation):
  POST https://telemetry.copilotkit.ai/ingest
  { event, properties: { ...caller, distinct_id, package }, ts }
If the lambda expects a richer envelope, update the single JSON.stringify
in lib/telemetry.ts.

Privacy invariants:
- Opt-out toggle short-circuits before any network call (verified by test).
- Properties are scoped to event metadata only — no message content, agent
  state, prompts, completions, banner markdown. Negative test pins the wire.
- Anonymous distinct ID (UUID v4 in localStorage) set on inspector load and
  propagated onto banner CTA links as ?posthog_distinct_id=<uuid> so the
  destination site can posthog.alias() and close the
  banner_viewed → banner_clicked → signup_attributed funnel. URL param
  suppressed when opted out.
- Console disclosure on first inspector mount and runtime startup. Both
  link to https://docs.copilotkit.ai/telemetry.

Plan gaps addressed:
- CTA name on banner_clicked: cta:'body'|'dismiss' (click location) plus
  optional cta_label read defensively. Sam: confirm dismiss treatment.
- De-anon opt-out folded into the single toggle. Docs say so explicitly.
- banner_viewed dedup: per-instance Set<string> keyed by timestamp.
- EPIC consent / pixel review: out of scope for this PR; flagged at merge.

Deferred for V1.1:
- Wire body shape (Ben).
- Event-type allowlist for oss.inspector.* (Ben — oss-path-to-production).
- posthog_distinct_id URL-param key name (Ben/Tyler/website team).

Refs https://linear.app/copilotkit/issue/OSS-96
2026-05-11 15:43:17 -05:00
tylerslaton 5164ae303f chore: release monorepo v1.57.1 2026-05-07 16:41:22 +00:00
Max Korp 8fe276eaa9 chore(deps): bump @copilotkit/license-verifier to 0.4.0
Updates runtime, shared, and root override pin from 0.2.0 to 0.4.0.
2026-05-07 09:20:37 -07:00
github-actions[bot] 657077b4f2 style: auto-fix formatting 2026-05-07 12:35:14 +00:00
Markus Ecker 12f2c0e734 refactor(runtime): rename cki → cpki and use INTELLIGENCE_USER_ID_HEADER constant
Two CR comments addressed:

- Rename the local destructure of forwardedProps.auth.copilotkitIntelligence
  from 'cki' to 'cpki' so it matches the project-wide abbreviation already
  used in metadata fields (cpki_event_id, cpki_event_seq, etc).

- Replace the inline 'X-Cpki-User-Id' string literal with the existing
  INTELLIGENCE_USER_ID_HEADER constant exported from intelligence-platform/client.
  Applies to the runtime auto-attach in agent/index.ts and to the three
  test sites in intelligence-mcp-helper.test.ts so the user-side and
  runtime-side stay in sync.
2026-05-07 14:31:59 +02:00
Markus Ecker 3e7449dc4c Merge remote-tracking branch 'origin/main' into lukas/cpk-7526-copilotkitruntimev2-configurable-mcp-server-on-builtinagent 2026-05-07 14:28:27 +02:00
Markus Ecker 6ed400c776 refactor(runtime): nest Intelligence MCP credentials under forwardedProps.auth.copilotkitIntelligence
Move the per-request Intelligence MCP bag from
forwardedProps.copilotkitIntelligence to
forwardedProps.auth.copilotkitIntelligence so the Intelligence-side
redaction policy strips it. The 'auth' namespace is the convention for
credentials; persistence sinks (Postgres, Redis, S3) and FE replay
paths in apps/realtime-gateway already strip everything under it.

Updates:
- Emitter (handlers/intelligence/run.ts): merge the bag into a single
  forwardedProps.auth object alongside any upstream auth keys, and
  only emit the auth namespace when there is something to put in it.
- Reader (agent/index.ts): read from forwardedProps.auth.copilotkitIntelligence
  instead of forwardedProps.copilotkitIntelligence.
- Tests (intelligence-mcp-helper.test.ts): three fixtures rewritten
  to the nested shape.
2026-05-07 10:55:02 +02:00
Markus Ecker faa2a556d0 test(runtime): cover Intelligence MCP auto-attach via forwardedProps
Four cases at the agent layer (BuiltInAgent reading forwardedProps):
  * attaches when `copilotkitIntelligence` carries all three strings
    (userId, apiKey, mcpUrl) — outbound headers carry Authorization +
    X-Cpki-User-Id.
  * does NOT attach when the bag is absent (no Intelligence wiring on
    this run).
  * does NOT attach when the bag is partial (e.g. mcpUrl missing).
  * does NOT attach when the user has already configured an MCP server
    pointing at the same URL — explicit user config wins, with the
    user's headers and resolver hitting the wire.
2026-05-06 16:16:14 +02:00
Markus Ecker a46acc3f94 feat(runtime/agent): auto-attach Intelligence MCP server via input.forwardedProps
Runtime side (intelligence/run.ts): when `runtime.intelligence.mcpServer`
is enabled, build a `copilotkitIntelligence` bag carrying the resolved
user-id, project apiKey, and the platform MCP URL, and pass it through
on `RunAgentInput.forwardedProps` to the agent. Skipped when the flag
is off — runs that don't go through this Intelligence path simply
don't see the bag.

Agent side (BuiltInAgent's run code): if `forwardedProps.copilotkitIntelligence`
contains all three string values AND the user's static `config.mcpServers`
doesn't already include the same URL, append a per-request
`MCPClientConfigHTTP`. Its `options.fetch` closes over apiKey + userId
and stamps `Authorization: Bearer <apiKey>` and `X-Cpki-User-Id:
<userId>` on every outbound MCP call. The custom fetch is the MCP
TypeScript SDK's documented extension point for per-request header
injection — no extra wrapper class, no separate framework concept.

The agent class is otherwise untouched: no new fields, no per-request
side channels, no typed reference to `CopilotKitIntelligence`. Other
agents that don't read `forwardedProps.copilotkitIntelligence` ignore
the bag.

Pulls in the AI SDK's stable `createMCPClient` export (rename from
`experimental_createMCPClient`) — the experimental name was deprecated;
`mcp-clients.test.ts`'s mock setup follows.
2026-05-06 16:15:57 +02:00
Markus Ecker 1de2fae369 feat(runtime): CopilotKitIntelligence.mcpServer opt-in flag + ɵ-accessors
Adds `mcpServer?: boolean` to `CopilotKitIntelligenceConfig` (default
`false`). When true, the runtime emits the per-request bag the agent
needs to attach the platform's MCP server.

Internal accessors `ɵisMcpServerEnabled()` and `ɵgetApiKey()` round
out the existing `ɵgetApiUrl()`. Used by the runtime layer in the
forthcoming auto-attach commit; not part of the public surface.
2026-05-06 16:15:21 +02:00
Markus Ecker 44cb538856 feat(runtime/v2): re-export MCPClient and MCPTransport from @ai-sdk/mcp
Convenience re-exports so consumers wiring custom MCP clients (via
`mcpClients`) or custom transports don't need to add `@ai-sdk/mcp`
to their dependencies just to type the values.
2026-05-06 16:15:06 +02:00
tylerslaton 490440a0e4 chore: release monorepo v1.57.0 2026-05-04 17:33:59 +00:00
github-actions[bot] 56524a7282 style: auto-fix formatting 2026-05-01 01:08:19 +00:00
Martha Schumann 0721414fbb Merge remote-tracking branch 'origin/main' into feat/CPK-7193-inspector-threads-clean
# Conflicts:
#	examples/integrations/langgraph-python-threads/apps/app/package.json
#	examples/integrations/langgraph-python-threads/apps/bff/package.json
#	examples/integrations/langgraph-python-threads/package-lock.json
#	pnpm-lock.yaml
2026-04-30 18:01:51 -07:00
Martha Schumann c9e1bd8e34 feat(runtime): wire intelligence /_inspect/threads/:id/{events,state} endpoints
Replaces the 501 stubs in handleGetThreadEvents and handleGetThreadState
with real delegation to CopilotKitIntelligence. Adds two new client
methods (`getThreadEvents`, `getThreadState`) on intelligence-platform/
client.ts that hit the new `/api/_inspect/threads/:id/{events,state}`
routes shipped in Intelligence PR #144 (CPK-7453). Auth flows through
the existing `resolveIntelligenceUser` path; threadId scoping happens
server-side via the API key's org/project resolution.

Wire shapes match the in-memory branch so the inspector consumes both
runtimes identically:
- events: `{ events }` (platform-internal `decodeErrorRowIds` and
  `truncated` flags are stripped at the runtime boundary)
- state: `{ state }` where the platform's discriminated `ThreadStateResult`
  flattens to the snapshot value for `kind: "snapshot"` and to `null` for
  both `no-snapshot` and `snapshot-decode-error`

Replaces the 501 regression-protection tests with real delegation tests
that mock the platform methods, assert call args, and exercise the
no-snapshot / decode-error / throw paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 14:33:02 -07:00
Martha Schumann 2e498341ad test(runtime): pin per-thread routes, GET-only enforcement, and agentId tagging
Three new test areas covering surfaces this PR introduced or relies on:

- fetch-router: matchRoute tests for `/threads/:id/events`,
  `/threads/:id/state`, and `/threads/clear` (with and without URL
  encoding). Critically pins that "/threads/clear" resolves to
  `threads/clear` and does NOT fall through to the more permissive
  `threads/update` arm with threadId="clear" — the explicit guard in
  the router exists for this reason.
- fetch-handler validation: 405 enforcement for POST/PATCH/DELETE on
  the read-only `/threads/:id/events` and `/threads/:id/state`
  endpoints, with `Allow: GET` header. Complementary positive case
  asserts GET is NOT a 405.
- handle-run: end-to-end test that handle-run.ts:40
  (`agent.agentId = agentId`) propagates the registry key onto historic
  runs. Without this stamp, InMemoryAgentRunner falls back to "default"
  and the agentId filter on `GET /threads?agentId=...` breaks for the
  local-dev fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:52:35 -07:00
Martha Schumann 3d6166611e refactor(runtime,inspector): tighten types and align JSDoc with reality
Type quality:
- intelligence/threads.ts handleGetThreadMessages: switch on the Message
  discriminant (role) and read narrowed fields directly. Removes
  `as Record<string, unknown>` laundering and chained `as` casts on
  toolCalls/function/arguments. AssistantMessage's toolCalls always have
  `function: { name, arguments }`, so the prior fallbacks (`tc.name`,
  `tc.args`) were dead branches.
- in-memory.ts getThreadState: import StateSnapshotEvent and use it
  instead of `(event as { snapshot?: unknown }).snapshot`.

Comment / API alignment:
- intelligence/threads.ts handleClearThreads JSDoc no longer claims the
  inspector calls this; the actual caller is the demo button.
- in-memory.ts clearThreads JSDoc updated to match.
- in-memory.ts getThreadEvents JSDoc no longer references a SQLite
  runner that does not exist; just describes the compaction logic.
- web-inspector lint fix: rename unused `changed` parameter to
  `_changed` per oxc no-unused-vars.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:45:07 -07:00
Tyler Slaton 52f8030f82 Merge branch 'main' into release/publish/monorepo/v1.56.5 2026-04-30 12:42:10 -07:00
Martha Schumann 7dcaa15063 test(core,runtime): strengthen error-log assertions and stub identity
- thread-store-registry: makeStore now attaches a __testId via
  intersection so callers can distinguish stubs at a glance during
  debugging instead of relying on identity-by-allocation alone.
- thread-store-registry subscriber-isolation test: assert the
  diagnostic content ("Subscriber onThreadStoreRegistered error") and
  Error argument, not just that some error was logged.
- handle-threads identifyUser-throws test: assert
  "Error identifying intelligence user" with an Error argument, since
  the throw originates inside resolveIntelligenceUser which logs and
  returns 500 before subscribeToThreads is reached.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:13:43 -07:00
Martha Schumann 7d525d62aa test(runtime): align MessagePopulatingTestAgent with TestAgent contract
- Add the missing protected connect() override returning EMPTY so the
  mock matches TestAgent and ThrowingAgent. Without it, a clone() that
  ever exercised connect() would fall through to AbstractAgent.connect()
  and may try to open a real transport in tests.
- clone() now forwards this.agentId directly instead of coercing
  undefined to "". The constructor accepts string | undefined to make
  this type-safe — coercion would silently turn "no agent id" into
  "empty agent id", a different state per AgentConfig.agentId?: string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:13:22 -07:00
Martha Schumann d5e5da6dce test(runtime): tighten thread-handler and in-memory-runner assertions
handleClearThreads is intentionally synchronous, but neither test
asserted the return type. Add `expect(response).not.toBeInstanceOf(Promise)`
on both branches so a regression that starts awaiting I/O updates the
synchronous call sites.

The handleGetThreadEvents/handleGetThreadState 501 tests asserted the
status code but not that intelligence stayed untouched. Stub spies for
both `listThreads` and a hypothetical `getThreadEvents`/`getThreadState`,
then assert neither was called — so a regression that drops the early
return and falls through to platform calls fails this test even after
the response code changes.

The handleSubscribeToThreads 500 test created an `errorSpy` to silence
console output but never asserted on it. Add `expect(errorSpy).toHaveBeenCalled()`
so a regression that quietly drops the diagnostic log is caught.

The InMemoryAgentRunner getThreadEvents test claimed the synthetic
terminal event was present but only asserted on TEXT_MESSAGE_*. Add an
explicit assertion on `RUN_ERROR` with `code: "INCOMPLETE_STREAM"` so
finalizeRunEvents' contract is locked in — a regression that stops
appending the synthetic event would leave the inspector showing an
in-progress thread forever.

Declare `onNewMessage` on `MessagePopulatingTestAgent.runAgent`'s options
type to match the runner's call site and `TestAgent` above. Without it,
a regression that starts depending on `onNewMessage` here would compile
cleanly even though the mock would silently drop the call.
2026-04-30 11:54:14 -07:00
Martha Schumann 7421bf12b1 test(runtime): tighten thread-handler and in-memory-runner tests
handle-threads.test.ts:
- handleGetThreadMessages intelligence-path test now asserts the response
  body verbatim, so a regression that swaps in a stub body is caught.
- 422-no-intelligence test issues a real DELETE request for the delete
  path instead of cloning a POST request.
- handleClearThreads block carries a comment explaining why the handler
  is intentionally synchronous (no I/O on either branch).
- The identifyUser-throws test now silences console.error for the
  duration of the assertion, matching the pattern already used by the
  subscribe-throws test.

in-memory-runner.test.ts:
- ThrowingAgent test asserts RUN_ERROR is the last emitted event and
  that no RUN_FINISHED is emitted, locking in terminal-event semantics.
- getThreadEvents test asserts the full TEXT_MESSAGE triple is present
  in the persisted event log, and the comment now reflects the real
  finalizeRunEvents behaviour (it appends a synthetic terminal event
  when the agent does not emit one, so terminal events ARE persisted).
- getThreadState multi-run test gains a cross-thread isolation
  assertion: a snapshot on a different thread must not bleed into the
  original thread's state.
- Bumped the inter-thread sort delay from 5ms to 20ms to absorb timer
  jitter on slow CI runners.
- Removed four redundant `agent.agentId = "test-agent"` reassignments
  (the constructor already sets it via super({ agentId })).
- Aligned MessagePopulatingTestAgent.runAgent with TestAgent: `onEvent`
  is now required so the runner contract is exercised consistently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 10:14:09 -07:00
Ran Shemtov e8061b707b Merge branch 'main' into release/publish/monorepo/v1.56.5 2026-04-30 17:59:09 +02:00
Tyler Slaton 5fe7ec55ca Merge branch 'main' into tyler/kind-mendeleev-636369 2026-04-29 22:46:51 -07:00
Jordan Ritter b355acd56c fix(runtime): stop converting TanStack stream after RUN_FINISHED
TanStack's chat() engine runs a multi-turn agent loop: after the model
returns tool calls, it tries to execute them via processToolCalls().
Frontend-only tools (like render_pie_chart) are unknown to TanStack, so
executeToolCalls() treats them as errors and buildToolResultChunks()
re-emits TOOL_CALL_END without a preceding TOOL_CALL_START. The ag-ui
verify middleware rejects this duplicate.

Fix: track a runFinished flag in convertTanStackStream and discard all
events after the first RUN_FINISHED, which marks the boundary between
the streaming pass and TanStack's internal tool execution loop.

Also adds built-in-agent to docker-compose.local.yml and local-ports.json.
2026-04-29 22:41:58 -07:00
Tyler Slaton bd68aeda32 fix(deps): bump ag-ui packages to 0.0.53
Picks up ag-ui-protocol/ag-ui#1578 — `import * as jsonpatch from
"fast-json-patch"` produced an empty namespace under Node native ESM
because fast-json-patch@3.x populates exports via Object.assign, which
the CJS→ESM named-export detector cannot see. Result: every STATE_DELTA
and ACTIVITY_DELTA event threw "applyPatch is not a function", and
LangGraph generative UI streams floods the console with the failure on
each patch.

0.0.53 switches to a default import so the emitted bundle works under
both ESM and CJS consumers. Bumped @ag-ui/core and @ag-ui/encoder in
lockstep since they share the release.
2026-04-29 22:41:28 -07:00
Jordan Ritter 497b205d1e fix: auto-format 16 files with pre-existing oxfmt violations
These files accumulated formatting drift across recent PRs. Fixes the
format CI check on main.
2026-04-29 19:12:22 -07:00
Jordan Ritter f2bc4a8dcb fix: default streamSubgraphs to true in LangGraph agent wrapper (#4446)
## Summary

- Explicitly defaults `streamSubgraphs: true` in `LangGraphAgent.run()`
forwardedProps so subagent streaming works with `@ag-ui/langgraph`
0.0.31+, which changed the default from `true` to `undefined`
- Uses nullish coalescing (`??`) so explicit user overrides (including
`false`) are preserved
- Fixes 6 showcase integrations failing E2E probes on the `subagents`
feature

## Why

`@ag-ui/langgraph` 0.0.31 removed the `?? true` fallback on
`streamSubgraphs` in `handleStreamEvents()`. The CopilotKit runtime
never explicitly set this prop, so subgraph event forwarding became
silently disabled. This caused all subagent-dependent demos to stop
working.

A previous v1 fix (commit `21e12afca`) handled this in the now-deleted
`agui-action.ts`, but the logic was lost during the v2 migration.

## Additional context

Investigation identified a second issue: `@ag-ui/langgraph` 0.0.34
includes state snapshot fixes needed for shared-state-read/write
features, but 0.0.34 is not yet published on npm (0.0.31 is latest). The
ag-ui team needs to cut a release. Full analysis: [Notion
write-up](https://app.notion.com/p/3513aa381852812a9ecef5fbf1e71739)

## Test plan

- [x] Runtime tests pass (1412/1412)
- [x] 7-agent CR converged Round 1 (0 findings)
- [ ] Verify showcase E2E probes for subagent features turn green after
merge
2026-04-29 16:57:58 -07:00
Jordan Ritter 1baeb9940a fix: use RegExp routes in Express adapter for Express 4/5 compatibility
Express 4 does not support the {*splat} wildcard syntax introduced in
Express 5. Replace string-based wildcard patterns with RegExp routes
that work across both major versions.
2026-04-29 16:50:19 -07:00
Jordan Ritter c0c97b4bf1 fix: default streamSubgraphs to true in LangGraph agent wrapper
The @ag-ui/langgraph 0.0.31+ changed the default for streamSubgraphs
from true to undefined, breaking subagent streaming. This enriches the
run() input's forwardedProps with streamSubgraphs: true as a default,
while preserving any explicit user override via the nullish coalescing
operator.
2026-04-29 15:59:08 -07:00
Martha Schumann d55d5495c7 Merge remote-tracking branch 'origin/main' into feat/CPK-7193-inspector-threads-clean
# Conflicts:
#	pnpm-lock.yaml
2026-04-29 13:31:32 -07:00
ranst91 5686889567 chore: release monorepo v1.56.5 2026-04-29 11:57:11 +00:00
Ran Shem Tov e504254792 chore: use latest ag-ui-langgraph 2026-04-29 11:30:43 +02:00
Jordan Ritter 8d7e850c22 chore: bump @copilotkit/aimock to latest (v1.16.1)
Needed for turnIndex/sequenceIndex fixture matching in D5 multi-turn
conversations. Updated in both packages/runtime (devDep) and
showcase/scripts (dep).
2026-04-28 22:21:02 -07:00
Jordan Ritter 9c9af7665f fix: update express wildcard routes for Express 4.20+ compat
Express 4.20+ uses path-to-regexp v8 which requires named wildcard
params. Bare * is no longer valid — use {*splat} syntax instead.

Updated production code (express.ts) and test (express-fetch-bridge).
Restores express >=4.20.0 override now that code is compatible.
2026-04-28 10:33:05 -07:00
Jordan Ritter a23bdccb6c fix: use /* instead of * in express route for Express 4.20+ compat
Express 4.20+ uses path-to-regexp v8 which rejects bare * as a route
pattern. Use /* which is the forward-compatible syntax.
2026-04-28 10:33:05 -07:00
Alem Tuzlak b2d14a847e Merge remote-tracking branch 'origin/worktree-mossy-tumbling-unicorn' into worktree-mossy-tumbling-unicorn 2026-04-28 13:55:50 +02:00
Alem Tuzlak 46eeb21924 Merge remote-tracking branch 'origin/main' into worktree-mossy-tumbling-unicorn
# Conflicts:
#	showcase/scripts/__tests__/generate-catalog.test.ts
2026-04-28 13:54:22 +02:00
BenTaylorDev f19afade44 chore: release monorepo v1.56.4 2026-04-27 15:05:59 -05:00
github-actions[bot] 8334dcdde6 style: auto-fix formatting 2026-04-27 16:32:58 +00:00
Alem Tuzlak 18f6c1e2e5 fix(runtime): close open reasoning message in REASONING_END and on REASONING_START reopen 2026-04-27 18:30:01 +02:00