Commit Graph

305 Commits

Author SHA1 Message Date
BenTaylorDev 28f6264dd4 chore: release monorepo v1.59.1 2026-05-29 15:19:08 +00:00
Tyler Slaton 360eac2320 chore: bump @copilotkit/license-verifier to ~0.4.2 (#5100)
## What

Bumps `@copilotkit/license-verifier` from an exact `0.4.0` pin to a
`~0.4.2` patch range across:

- `package.json` — root `pnpm.overrides`
- `packages/runtime/package.json` — `dependencies`
- `packages/shared/package.json` — `dependencies`
- `pnpm-lock.yaml` — regenerated, resolves to `0.4.2`

## Why

Aligns the runtime/shared deps with the newly published
`@copilotkit/license-verifier@0.4.2`. Switching from an exact pin to
`~0.4.2` (`>=0.4.2 <0.5.0`) means future `0.4.x` patches are picked up
automatically, while `0.5.0`+ still requires an intentional bump.

## Notes

- `.npmrc` `minimum-release-age` guard was **not** modified; the
lockfile was regenerated with a one-off override since `0.4.2` was
freshly published.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-05-29 07:51:25 -07:00
Benjamin Taylor 832eb435b5 chore: bump @copilotkit/license-verifier to ~0.4.2
Move runtime and shared deps (and the root pnpm override) from an exact
0.4.0 pin to ~0.4.2, so future 0.4.x patches are picked up automatically.
Regenerate pnpm-lock.yaml to resolve 0.4.2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 09:04:07 -05:00
BenTaylorDev 94b1f61cc3 chore: release monorepo v1.59.0 2026-05-27 22:31:30 +00:00
Jordan Ritter d61908dd1e chore(deps): bump @ag-ui/langgraph to 0.0.34
Picks up the forwarded-headers fix from ag-ui PR #1798
(https://github.com/ag-ui-protocol/ag-ui/pull/1798), which injects
agent.headers as config.configurable.copilotkit_forwarded_headers so
the LG dev server's HTTP-to-configurable bridge is no longer required
for X-AIMock-Context propagation. Closes the header-propagation gap
for showcase D5/D6 langgraph-typescript probes.
2026-05-27 12:55:30 -07:00
Jordan Ritter 9d3a3a5559 chore: bump @ag-ui/langgraph to 0.0.33 for D6 header forwarding
Picks up per-request header forwarding (onRequest hook + headerFactory)
and the prepareStream configurable+context partition fix from
ag-ui-protocol/ag-ui#1763. Together with copilotkit==0.1.91 on the
Python side (R3a), this unblocks D6 LGP/LGT header propagation.

The mergeConfigs() change in 0.0.33 also fixes the HTTP 400 from
langgraph-api 0.7+ when both configurable and context are present.

Bumped in two files:
- packages/runtime/package.json: 0.0.31 -> 0.0.33
- packages/sdk-js/package.json: 0.0.31 -> 0.0.33

Added @ag-ui/langgraph to minimumReleaseAgeExclude in .npmrc.
pnpm-lock.yaml regenerated.

Showcase auto-redeploys on merge via showcase_build.yml.
2026-05-26 10:16:27 -07:00
BenTaylorDev ebc09ea5c0 chore: release monorepo v1.58.0 2026-05-26 15:40:57 +00:00
Sam Julien 33f669ba7b fix(packages): canonicalize docs.copilotkit.ai URLs in user-facing messages
Replace docs URLs that currently 301 through the legacy redirect catalog
with their canonical post-cutover destinations so users clicking links
from console warnings, JSDoc, and in-product help land in one hop.

URLs updated:
- /premium#how-do-i-get-access-to-premium-features
  -> /premium/overview#getting-access
- /coagents/quickstart/langgraph -> /langgraph-python/quickstart
- /coagents/shared-state/predictive-state-updates
  -> /langgraph-python/shared-state/predictive-state-updates
- /reference/v1/hooks/useCopilotChatHeadless_c
  -> /reference/v2/hooks/useCopilotChatHeadless_c
- /coagents/troubleshooting/common-issues
  -> /langgraph-python/troubleshooting/common-issues
- /quickstart#get-a-copilot-cloud-public-api-key
  -> /built-in-agent/quickstart#create-a-free-account
- /premium -> /premium/overview

URLs left as-is because they already resolve 200 with no redirect:
/migration-guides/migrate-attachments, /migration/render-message,
/telemetry.

Hook bypassed: pre-commit test failed in @copilotkit/web-inspector due
to missing jsdom dependency in its package.json (unrelated to this
change; no overlap with edited files or URLs). Tests for the four
affected packages (react-core, react-ui, shared, runtime) pass.
2026-05-22 16:37:21 -07:00
Benjamin Taylor b684fae377 review(telemetry): address CR findings on client-side sampling
- Rework shared helper: parseAndWarnTelemetryId returns parsed id AND
  warns, so both v1 and v2 setLicenseToken call it once without
  inlining duplicate code or double-parsing the JWT.
- Fix v1 sampleWeight bug: identified events bypass the sample gate
  and ship at effective rate 1.0, so a single global sampleWeight =
  1/sampleRate would overweight identified-customer counts by
  1/sampleRate (20x at the 0.05 default). Move sample metadata
  (sampleRate / sampleRateAdjustmentFactor / sampleWeight) out of
  globalProperties and compute per-event using effectiveSampleRate.
- Guard setSampleRate against parseFloat("nonsense") = NaN slipping
  past the range check. With the default now 0.05, env-var overrides
  are more common and a typo would otherwise produce silent
  always-drop.
- Add tests: sampleWeight differs for identified vs anonymous,
  malformed JWT stays anonymous, license-token cache is overwritable,
  NaN env override is rejected, v2 default sampleRate = 0.05 is pinned.
2026-05-21 14:45:20 -05:00
Benjamin Taylor ad94ceb254 feat(telemetry): gate anonymous v2 events client-side, bypass for identified
Cache parsed telemetry_id at setLicenseToken time and use it in capture()
to branch on identified vs anonymous. Identified callers (token with
telemetry_id) always send; anonymous callers are sampled at sampleRate.

Default sampleRate changes from 1.0 to 0.05 so the anonymous OSS-runtime
firehose is capped at the client. Identified customers continue to send
at full fidelity.
2026-05-21 14:45:20 -05:00
Benjamin Taylor e03de792c3 review(telemetry): address PR feedback on sink migration
- Mark v1 licenseToken private to match v2 visibility
- Extract shared warnIfLicenseTokenLacksTelemetryId helper to keep v1
  and v2 setLicenseToken bodies in lockstep
- Remove dead v2 scarf-client and its test block (migration leftover)
- Add v1 shared TelemetryClient test coverage: lambda always-send,
  segment sample gating, setLicenseToken warn paths, cloud config,
  telemetryDisabled gate, sample-rate range, env-var matrix
2026-05-21 14:45:20 -05:00
Benjamin Taylor 3be4c6b1e7 feat(telemetry): warn when license token yields no telemetry_id
Operators currently get silent attribution loss if a license token is
configured but parses without a telemetry_id field — useful as a smoke
signal during the issuer rollout, when older licenses lack the field
entirely.

Each TelemetryClient setter (v1 shared, v2 singleton) now calls
parseTelemetryIdFromLicense at configuration time and emits a one-shot
console.warn when the result is null. No per-event spam.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:20 -05:00
Benjamin Taylor ff33123c93 feat(telemetry): source telemetry-id from EIP license JWT
The CopilotCloud customer API key (`ck_<env>_<id>.<secret>`) is unrelated
to telemetry attribution — it flows into Segment/PostHog only. The
attribution signal lives in the EIP / Intelligence license JWT, whose
payload carries `telemetry_id` (alongside license_id, owner.org_id,
features, etc.).

Rewires the lambda-client to base64url-decode the license JWT payload
and emit X-CopilotKit-Telemetry-Id from `telemetry_id`. No signature
verification — that's license-verifier's job, and the Lambda is
claim-only by design.

Plumbing:
- Shared TelemetryClient (v1) and v2 telemetry singleton each get a
  `setLicenseToken` setter; the v1 client drops `apiKey:` from its
  lambdaClient.send call, the v2 client drops the
  cloud.public_api_key extraction from event properties.
- Both runtime constructors call `telemetry.setLicenseToken(...)` once,
  resolving `options.licenseToken ?? process.env.COPILOTKIT_LICENSE_TOKEN`
  to match license-verifier's own env-fallback. Without that, customers
  who set only the env var would get a working licenseChecker but
  anonymous telemetry.

Tests: v2 telemetry test refreshed — old "cloud api key extraction"
assertion replaced with one that confirms cloud.public_api_key rides
in properties (not as licenseToken), and a new test asserts that
setLicenseToken plumbs through to lambdaClient.send.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
Benjamin Taylor ce3697aad8 feat(telemetry): route runtime telemetry through CopilotKit telemetry sink
Adds @copilotkit/shared/telemetry/lambda-client which posts events to a
CopilotKit-controlled telemetry-sink endpoint, replacing the direct Scarf
calls in both v1 (shared) and v2 (runtime) telemetry clients. When the
configured CopilotCloud API key parses as the new ck_<env>_<id>.<secret>
format, the request is HMAC-signed (CK1, sha256 over ts/nonce/body) so
the sink can verify and enrich with the customer email; otherwise it
falls through to an unsigned send (legacy keys, OSS-only installs). v1
keeps its existing Segment path with 5% client sampling; v2 sends 100%
to the sink and lets the sink sample server-side.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:45:19 -05:00
tylerslaton 938803e6f4 chore: release monorepo v1.57.4 2026-05-21 14:25:58 +00:00
Jordan Ritter 9107e00a9a fix(runtime): close header propagation gap for LangGraphAgent
The if (agent.headers) guard in configureAgentForRequest silently
skipped header forwarding when agent.headers was undefined (the
default for LangGraphAgent). This meant x-aimock-context, x-test-id,
and other x-* headers were never forwarded to agent backends.

Also wires install_httpx_hook in the Python SDK middleware so
forwarded headers propagate to outgoing LLM API calls.

Closes the gap documented in PR #4773 spec as out-of-scope.
2026-05-21 01:39:28 -07:00
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