Commit Graph

76 Commits

Author SHA1 Message Date
Max Korp 9fa9de3bb1 Merge remote-tracking branch 'origin/main' into feat/intelligence-thread-plumbing 2026-03-13 11:19:25 -07:00
github-actions[bot] ea746d4629 chore(post-release): update version to 1.54.0 2026-03-12 22:32:04 +00:00
Benjamin Taylor 1110616c91 feat(runtime, client): Some cleanup and terms alignment 2026-03-12 13:03:05 -07:00
Benjamin Taylor a1e63ae148 feat(runtime, react, angular): Back up version bumps and small refactor 2026-03-12 13:02:46 -07:00
Mike Ryan de6e4007cb feat(runtime,core): Automatic opt-in to Intelligence when an SDK is provided 2026-03-12 13:02:33 -07:00
Mike Ryan 124ed10e27 refactor(runtime): Implement connect strategies 2026-03-12 13:02:17 -07:00
Benjamin Taylor 02b5ae374d fix(react, runtime): Fix tests and typos not caught by types 2026-03-12 12:59:18 -07:00
Benjamin Taylor 689ccf9399 feat(runtime, react, angular): Back up version bumps and small refactor 2026-03-12 12:59:06 -07:00
Mike Ryan 9ce4013d84 feat(runtime,core): Automatic opt-in to Intelligence when an SDK is provided 2026-03-12 12:59:05 -07:00
Mike Ryan c62521523d refactor(runtime): Implement connect strategies 2026-03-12 12:58:45 -07:00
github-actions[bot] 98890426e5 chore(post-release): update version to 1.54.0-next.9 2026-03-12 19:08:50 +00:00
github-actions[bot] b443706792 chore(post-release): update version to 1.54.0-next.8 2026-03-12 16:52:13 +00:00
github-actions[bot] ecd76256ed chore(post-release): update version to 1.54.0-next.7 2026-03-12 14:26:14 +00:00
github-actions[bot] ed34d9daef chore(post-release): update version to 1.54.0-next.6 2026-03-11 16:22:53 +00:00
github-actions[bot] e9cb7dfe26 chore(post-release): update version to 1.54.0-next.5 2026-03-11 15:20:13 +00:00
github-actions[bot] 190eb07f09 chore(post-release): update version to 1.54.0-next.4 2026-03-11 12:50:08 +00:00
github-actions[bot] 60de47cda2 chore(post-release): update version to 1.54.0-next.3 2026-03-11 11:14:53 +00:00
giulio-leone 921dd1944d fix: address all 7 PR review feedback items for tool args guard
CRITICAL 1: ensureObjectArgs (renamed from safeParseToolArgs) in
run-handler.ts now throws on non-object parsed results so the catch
block fires TOOL_ARGUMENT_PARSE_FAILED structured errors.

CRITICAL 2: partialJSONParse return type reverted from
Record<string,unknown> to unknown — callers handle the type.

IMPORTANT 3: safeParseToolArgs consolidated into shared/utils.ts and
exported. Agent/index.ts imports from @copilotkitnext/shared. V1 keeps
a local copy with a comment noting it mirrors the shared version.

IMPORTANT 4: All non-object fallback sites now emit console.warn with
consistent [CopilotKit] prefix format.

IMPORTANT 5: Removed console.warn from getPartialArguments catch block
(incomplete JSON is expected during streaming). Warning is now only in
the try-block non-object guard.

TEST 6: Added run-handler-ensureObjectArgs.test.ts covering valid
object, string, number, array, null, boolean, and undefined inputs.

TEST 7: Added conversion.test.ts for v1 safeParseToolArgs covering
valid object, string, number, array, malformed JSON, null, boolean,
and empty string inputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 21:13:16 +01:00
Jordan Ritter ed61eefb67 fix: extend non-object tool argument guards to all parse sites
Guard partialJSONParse, both agui-to-gql converters, and
run-handler.ts against LLMs returning non-object JSON (strings,
arrays, numbers, booleans, null) as tool arguments. Adds
safeParseToolArgs helper to run-handler.ts and tests for all sites.
2026-03-09 15:10:00 +01:00
Jordan Ritter 792a0b1241 fix: guard against malformed JSON in tool argument parsing
Rename ensureObjectArgs to safeParseToolArgs in v2/agent and v1/runtime,
folding JSON.parse into the guard so malformed JSON (e.g. "{broken") is
caught instead of throwing an unhandled SyntaxError up the call stack.

Add console.warn on parse failure in all three locations (v2/agent,
v1/runtime, v1/runtime-client-gql) so malformed tool arguments are
visible in logs rather than silently swallowed.

Update the v2/agent unparseable-JSON test to expect {} instead of throw.
2026-03-09 15:09:59 +01:00
g97iulio1609 aa8a8a3d11 fix: guard against non-object tool arguments from LLMs
When LLMs return non-object values (e.g. empty string) as tool call
arguments, the parsed result is stored in conversation history. On
subsequent requests, providers like Anthropic reject the non-dictionary
tool_use input with a 400 error, making the conversation permanently
broken.

Fixed in 4 locations across v1 and v2:
- v1 runtime conversion.ts: validate parsed arguments
- v1 client conversion.ts: validate partial arguments
- v2 core run-handler.ts: validate both specific and wildcard tool args
- v2 agent index.ts: validate tool call input conversion

All locations now ensure parsed args are a plain object, falling back to
{} for non-object values.

Fixes #3300
2026-03-09 15:09:59 +01:00
github-actions[bot] d2cf028903 chore(post-release): update version to 1.53.1-next.2 2026-03-07 08:47:03 +00:00
Jordan Ritter 5884dde045 fix(runtime): clean up stale messagesInProcess when copilotkit:emit-messages suppresses events (#3270)
## Description

Fixes #3208

When using a LangGraph agent with an orchestrator node that routes to
terminal nodes,
the orchestrator typically uses `copilotkit_customize_config(config,
emit_messages=False)`
to suppress its internal LLM output (e.g., routing decisions like
"left_intent") from
being streamed to the frontend.

However, the `dispatchEvent` override in the CopilotKit `LangGraphAgent`
was only
suppressing the events from reaching the `verifyEvents` pipeline — it
was **not**
cleaning up the `messagesInProcess` tracking state. This caused a stale
message record
from the orchestrator to persist and leak into subsequent nodes that
have
`emit_messages=True`, ultimately triggering a `verifyEvents` error:

```
Cannot send 'TEXT_MESSAGE_END' event: No active text message found with ID '...'.
A 'TEXT_MESSAGE_START' event must be sent first.
```


### Root cause (step by step)

1. Orchestrator calls LLM with `emit_messages=False` → metadata has
`copilotkit:emit-messages: false`
2. Orchestrator's LLM streams text → `handleSingleEvent` (in
`@ag-ui/langgraph`) calls
`setMessageInProgress()` unconditionally, then calls `dispatchEvent()`
for `TEXT_MESSAGE_START`
3. CopilotKit's `dispatchEvent` suppresses the event (returns `false`),
but the message
   record is already tracked in `messagesInProcess`
4. When `TEXT_MESSAGE_END` is later suppressed, it also returns `false`
— so
`messagesInProcess` is **never cleared** (the cleanup is gated on `if
(resolved)`)
5. The next node (e.g., `left_node`) starts with `emit_messages=True`.
Its first LLM chunk
(often empty content) sees the **stale** `messagesInProcess` record and
determines
   `isMessageEndEvent = true`
6. It dispatches `TEXT_MESSAGE_END` with the orchestrator's message ID,
but since the
raw event now carries `copilotkit:emit-messages: true`, CopilotKit does
**not** suppress it
7. `verifyEvents` sees a `TEXT_MESSAGE_END` for a message ID that never
had a
   `TEXT_MESSAGE_START` → throws the error

### Fix

When `dispatchEvent` suppresses message events due to
`copilotkit:emit-messages === false`,
it now also nullifies the corresponding
`messagesInProcess[activeRun.id]` entry. This
prevents stale records from leaking across node boundaries.

## Type of Change

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)

## How Has This Been Tested?

Tested manually with a LangGraph agent containing:
- An **orchestrator node** using `copilotkit_customize_config(config,
emit_messages=False)` that classifies user intent and routes via
`Command(goto=...)` to one of two terminal subgraphs
- Two **terminal nodes** (`left_node`, `right_node`) using
`copilotkit_customize_config(config, emit_messages=True)` that call an
LLM and stream the response

Before the fix: every message sent through CopilotSidebar triggered the
`TEXT_MESSAGE_END` error and `INCOMPLETE_STREAM`.
After the fix: messages flow correctly — the orchestrator's internal
output is suppressed and the terminal node's response streams to the
frontend as expected.
2026-03-06 14:46:18 -04:00
Jordan Ritter e27df8947d test(runtime): add tests for dispatchEvent emit-messages/emit-tool-calls filtering
Covers the fix for stale messagesInProcess cleanup, plus general
filtering behavior for both copilotkit:emit-messages and
copilotkit:emit-tool-calls metadata.
2026-03-06 10:46:06 -08:00
github-actions[bot] 6c4aab7d6f chore(post-release): update version to 1.53.1-next.1 2026-03-06 18:32:39 +00:00
github-actions[bot] 1fd878c582 chore(post-release): update version to 1.53.1-next.0 2026-03-06 17:10:16 +00:00
github-actions[bot] 57eb016a10 chore(post-release): update version to 1.53.0 2026-03-05 23:57:25 +00:00
github-actions[bot] 671fd0ae47 chore(post-release): update version to 1.53.0-next.6 2026-03-05 23:41:37 +00:00
Maxim 501e8d70ae fix(runtime): skip afterRequestMiddleware when user didn't configure one
The v1 CopilotRuntime always set afterRequestMiddleware on the v2 runtime,
causing parseSSEResponse to attempt reading the cloned SSE stream body even
when no user hooks existed. This results in "Failed to read SSE response
body in afterRequestMiddleware" warnings. Only register the handler when
the user actually provided afterRequestMiddleware or middleware.onAfterRequest.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:38:06 -05:00
github-actions[bot] 3ba2352ef8 chore(post-release): update version to 1.53.0-next.5 2026-03-05 23:06:01 +00:00
Tyler Slaton f822c051de refactor(runtime): mcp -> mcpApps w/ granular config
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-03-05 17:40:28 -05:00
github-actions[bot] 9f12589107 chore(post-release): update version to 1.52.2-next.4 2026-03-05 21:28:52 +00:00
Tyler Slaton 0e0befe35b fix(runtime): fix issue with undefined serviceAdapters
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-03-05 15:39:21 -05:00
github-actions[bot] 2173e89096 chore(post-release): update version to 1.52.2-next.3 2026-03-05 17:42:38 +00:00
Ran Shem Tov e76e5e7c11 chore: use latest agui 2026-03-05 16:43:33 +01:00
Ran Shem Tov 947978e777 feat: enable mcp and a2ui middleware directly from copilotkit runtime 2026-03-05 16:41:29 +01:00
github-actions[bot] 3ff24c8b05 chore(post-release): update version to 1.52.2-next.2 2026-03-05 10:31:34 +00:00
Maxim 9241c2b611 feat(runtime): upgrade AI SDK to v6 to match v2 agent 2026-03-04 15:02:37 -05:00
Tyler Slaton 7c87c4ac61 chore(runtime): fix linter issues
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-03-04 13:14:01 -05:00
Alem Tuzlak 910945f07a fix(runtime): update OpenAI import to use default export 2026-03-04 13:14:01 -05:00
Tyler Slaton aebb9b5918 fix(runtime): remove openai as a peerdep
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-03-04 13:14:01 -05:00
github-actions[bot] 7abe7f89d1 chore(post-release): update version to 1.52.2-next.1 2026-03-03 23:59:38 +00:00
github-actions[bot] 4b78d74e11 chore(post-release): update version to 1.52.2-next.0 2026-03-03 17:40:27 +00:00
Alem Tuzlak 93edc65f23 fix: update build process and add outputs for snapshot caching 2026-03-02 11:42:22 -05:00
github-actions[bot] aeac645881 chore(post-release): update version to 1.52.1 2026-02-27 20:04:51 +00:00
Markus Ecker 39722ecbe4 Merge branch 'main' into mme/ag-ui-0.0.46 2026-02-27 15:13:22 +01:00
github-actions[bot] d523d6cc68 chore(post-release): update version to 1.52.1-next.1 2026-02-27 14:12:29 +00:00
Markus Ecker 979511a900 chore: upgrade AG-UI to 0.0.46 2026-02-27 14:47:50 +01:00
github-actions[bot] 0cf39911a0 chore(post-release): update version to 1.52.1-next.0 2026-02-27 03:53:52 +00:00
Jordan Ritter 3f1259d060 fix: propagate custom provider config from service adapters to BuiltInAgent (#3283)
Fixes #2903

## The Bug

Azure OpenAI users get `AI_LoadAPIKeyError: OpenAI API key is missing`
despite passing a properly configured `OpenAI` instance to
`OpenAIAdapter`, exactly as shown in the docs.

**Root cause**: `CopilotRuntime.handleServiceAdapter()` discards the
adapter's configured OpenAI instance and constructs a plain string
`"openai/gpt-4o"` to pass to `BuiltInAgent`. The agent's
`resolveModel()` then creates a *brand new* OpenAI provider using only
`OPENAI_API_KEY`, losing all Azure configuration (baseURL, api-key
header, api-version query param).

The V1 adapter's `process()` method — which correctly uses the custom
OpenAI instance — is dead code. It's never called. Only `.provider` and
`.model` strings are extracted.

```
User configures Azure OpenAI instance →
  OpenAIAdapter stores it →
    CopilotRuntime extracts only "openai"/"gpt-4o" strings →
      BuiltInAgent.resolveModel("openai/gpt-4o") →
        createOpenAI({ apiKey: OPENAI_API_KEY }) →
          💥 API key missing / wrong endpoint
```

## Workaround

Until this is merged, users can bypass the broken adapter entirely by
using `BuiltInAgent` directly with the Vercel AI SDK Azure provider:

```typescript
import { createAzure } from "@ai-sdk/azure";
import { CopilotRuntime, copilotRuntimeNodeHttpEndpoint } from "@copilotkit/runtime";
import { BuiltInAgent } from "@copilotkitnext/agent";

const azure = createAzure({
  resourceName: process.env.AZURE_RESOURCE_NAME,
  apiKey: process.env.AZURE_API_KEY,
});

const runtime = new CopilotRuntime({
  agents: {
    default: new BuiltInAgent({
      model: azure("your-deployment-name"),
    }),
  },
});

// Then use copilotRuntimeNodeHttpEndpoint as usual — no serviceAdapter needed
```

This works because `BuiltInAgent` already accepts `LanguageModel`
instances and `resolveModel()` passes them straight through.

## The Fix

Add an optional `getLanguageModel()` method to `CopilotServiceAdapter`.
Adapters that accept custom SDK instances (OpenAI, Anthropic, Groq) now
implement this to produce a pre-configured Vercel AI SDK `LanguageModel`
that carries the full provider configuration. `CopilotRuntime` prefers
this over the string format when creating `BuiltInAgent`.

**Backward compatible**: `getLanguageModel()` is optional on the
interface, so existing custom adapters continue to work unchanged.

| File | Change |
|------|--------|
| `service-adapter.ts` | Add optional `getLanguageModel()` to
`CopilotServiceAdapter` interface |
| `openai-adapter.ts` | Implement `getLanguageModel()` using
`createOpenAI` with the configured instance's `baseURL`/`apiKey` |
| `anthropic-adapter.ts` | Implement `getLanguageModel()` using
`createAnthropic` |
| `groq-adapter.ts` | Implement `getLanguageModel()` using
`createOpenAI` (Groq is OpenAI-compatible) |
| `copilot-runtime.ts` | Prefer `serviceAdapter.getLanguageModel()` over
string model when creating `BuiltInAgent` |
| `package.json` | Add `ai`, `@ai-sdk/openai`, `@ai-sdk/anthropic`
dependencies |

## Test plan

- [x] V2 agent tests pass (101/101)
- [x] V1 runtime build succeeds with no type errors
- [x] V1 runtime tests: same pass/fail as `main` (pre-existing failures
unrelated to this change)
- [ ] Manual: configure Azure OpenAI via `OpenAIAdapter` without
`OPENAI_API_KEY` — should work without `AI_LoadAPIKeyError`
- [ ] Manual: standard OpenAI via `OpenAIAdapter` with `OPENAI_API_KEY`
— should continue working

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-02-26 18:36:11 -04:00