@copilotkit/runtime 1.55.3 → 1.56.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts +6 -19
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts +6 -19
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs.map +1 -1
- package/dist/agent/index.cjs +16 -2
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +12 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +12 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +16 -2
- package/dist/agent/index.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -1
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.d.cts +2 -1
- package/dist/lib/index.d.cts.map +1 -1
- package/dist/lib/index.d.mts +2 -1
- package/dist/lib/index.d.mts.map +1 -1
- package/dist/lib/index.mjs +1 -1
- package/dist/lib/integrations/node-http/index.cjs +4 -1
- package/dist/lib/integrations/node-http/index.cjs.map +1 -1
- package/dist/lib/integrations/node-http/index.d.cts.map +1 -1
- package/dist/lib/integrations/node-http/index.d.mts.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +4 -1
- package/dist/lib/integrations/node-http/index.mjs.map +1 -1
- package/dist/lib/integrations/shared.cjs +1 -1
- package/dist/lib/integrations/shared.d.cts +1 -1
- package/dist/lib/integrations/shared.d.mts +1 -1
- package/dist/lib/integrations/shared.mjs +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +25 -5
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +15 -3
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +15 -3
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +25 -5
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.cjs +21 -4
- package/dist/lib/runtime/mcp-tools-utils.cjs.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.d.cts.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.d.mts.map +1 -1
- package/dist/lib/runtime/mcp-tools-utils.mjs +21 -4
- package/dist/lib/runtime/mcp-tools-utils.mjs.map +1 -1
- package/dist/package.cjs +6 -5
- package/dist/package.mjs +6 -5
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs +11 -3
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts +6 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +6 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs +11 -3
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs.map +1 -1
- package/dist/service-adapters/anthropic/utils.cjs +27 -1
- package/dist/service-adapters/anthropic/utils.cjs.map +1 -1
- package/dist/service-adapters/anthropic/utils.mjs +27 -1
- package/dist/service-adapters/anthropic/utils.mjs.map +1 -1
- package/dist/service-adapters/langchain/utils.cjs +1 -1
- package/dist/service-adapters/langchain/utils.cjs.map +1 -1
- package/dist/service-adapters/langchain/utils.mjs +1 -1
- package/dist/service-adapters/langchain/utils.mjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.cjs +3 -2
- package/dist/service-adapters/openai/openai-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.cts +6 -0
- package/dist/service-adapters/openai/openai-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.mts +6 -0
- package/dist/service-adapters/openai/openai-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.mjs +4 -3
- package/dist/service-adapters/openai/openai-adapter.mjs.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.cjs +8 -9
- package/dist/service-adapters/openai/openai-assistant-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-assistant-adapter.mjs +9 -10
- package/dist/service-adapters/openai/openai-assistant-adapter.mjs.map +1 -1
- package/dist/service-adapters/openai/utils.cjs +53 -0
- package/dist/service-adapters/openai/utils.cjs.map +1 -1
- package/dist/service-adapters/openai/utils.mjs +51 -1
- package/dist/service-adapters/openai/utils.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -0
- package/dist/v2/index.d.cts +3 -3
- package/dist/v2/index.d.mts +3 -3
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/middleware-sse-parser.cjs +5 -2
- package/dist/v2/runtime/core/middleware-sse-parser.cjs.map +1 -1
- package/dist/v2/runtime/core/middleware-sse-parser.mjs +5 -2
- package/dist/v2/runtime/core/middleware-sse-parser.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs +25 -0
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +53 -4
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +53 -4
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs +26 -2
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.cjs +18 -10
- package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -1
- package/dist/v2/runtime/handlers/get-runtime-info.mjs +19 -11
- package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs +1 -1
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs +1 -1
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs +8 -2
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +8 -2
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-stop.cjs +2 -1
- package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-stop.mjs +2 -1
- package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +3 -2
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +3 -2
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +40 -1
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +40 -1
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.cjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/sse/run.mjs +3 -1
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -1
- package/package.json +7 -6
- package/src/agent/__tests__/capabilities.test.ts +81 -0
- package/src/agent/__tests__/provider-id-collision.test.ts +195 -0
- package/src/agent/converters/tanstack.ts +15 -7
- package/src/agent/index.ts +52 -11
- package/src/lib/integrations/node-http/__tests__/request-duck-type.test.ts +66 -0
- package/src/lib/integrations/node-http/index.ts +15 -1
- package/src/lib/runtime/__tests__/mcp-tools-utils.test.ts +30 -1
- package/src/lib/runtime/__tests__/on-after-request.test.ts +122 -0
- package/src/lib/runtime/__tests__/v1-agent-factory.test.ts +109 -0
- package/src/lib/runtime/copilot-runtime.ts +54 -5
- package/src/lib/runtime/mcp-tools-utils.ts +41 -6
- package/src/service-adapters/anthropic/anthropic-adapter.ts +22 -2
- package/src/service-adapters/anthropic/utils.ts +60 -1
- package/src/service-adapters/langchain/utils.ts +1 -1
- package/src/service-adapters/openai/__tests__/openai-v5-compat.test.ts +177 -0
- package/src/service-adapters/openai/openai-adapter.ts +17 -2
- package/src/service-adapters/openai/openai-assistant-adapter.ts +7 -9
- package/src/service-adapters/openai/utils.ts +100 -0
- package/src/v2/runtime/__tests__/agents-factory.test.ts +136 -0
- package/src/v2/runtime/__tests__/debug-sse-response.test.ts +302 -0
- package/src/v2/runtime/__tests__/get-runtime-info.test.ts +134 -1
- package/src/v2/runtime/__tests__/middleware-sse-parser.test.ts +50 -0
- package/src/v2/runtime/core/middleware-sse-parser.ts +12 -2
- package/src/v2/runtime/core/runtime.ts +90 -2
- package/src/v2/runtime/handlers/get-runtime-info.ts +33 -8
- package/src/v2/runtime/handlers/handle-connect.ts +1 -1
- package/src/v2/runtime/handlers/handle-run.ts +16 -2
- package/src/v2/runtime/handlers/handle-stop.ts +2 -1
- package/src/v2/runtime/handlers/intelligence/thread-names.ts +1 -1
- package/src/v2/runtime/handlers/shared/agent-utils.ts +3 -2
- package/src/v2/runtime/handlers/shared/sse-response.ts +69 -0
- package/src/v2/runtime/handlers/sse/run.ts +9 -0
- package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +268 -0
- package/tests/service-adapters/anthropic/utils-token-trimming.test.ts +301 -0
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AgentCapabilities } from "@ag-ui/core";
|
|
2
|
+
import {
|
|
3
|
+
CopilotRuntimeLike,
|
|
4
|
+
isIntelligenceRuntime,
|
|
5
|
+
resolveAgents,
|
|
6
|
+
} from "../core/runtime";
|
|
2
7
|
import {
|
|
3
8
|
AgentDescription,
|
|
4
9
|
RuntimeInfo,
|
|
@@ -26,22 +31,42 @@ interface HandleGetRuntimeInfoParameters {
|
|
|
26
31
|
|
|
27
32
|
export async function handleGetRuntimeInfo({
|
|
28
33
|
runtime,
|
|
34
|
+
request,
|
|
29
35
|
}: HandleGetRuntimeInfoParameters) {
|
|
30
36
|
try {
|
|
31
|
-
const agents = await runtime.agents;
|
|
37
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
38
|
+
|
|
39
|
+
const agentEntries = await Promise.all(
|
|
40
|
+
Object.entries(agents).map(async ([name, agent]) => {
|
|
41
|
+
let capabilities: AgentCapabilities | undefined;
|
|
42
|
+
try {
|
|
43
|
+
capabilities = agent.getCapabilities
|
|
44
|
+
? await agent.getCapabilities()
|
|
45
|
+
: undefined;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
// Per-agent isolation: a single agent failing to report capabilities
|
|
48
|
+
// must not take down the entire /info endpoint.
|
|
49
|
+
console.warn(
|
|
50
|
+
`Failed to fetch capabilities for agent "${name}":`,
|
|
51
|
+
error instanceof Error ? error.message : error,
|
|
52
|
+
);
|
|
53
|
+
capabilities = undefined;
|
|
54
|
+
}
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
(acc, [name, agent]) => {
|
|
35
|
-
acc[name] = {
|
|
56
|
+
const description: AgentDescription = {
|
|
36
57
|
name,
|
|
37
58
|
description: agent.description,
|
|
38
59
|
className: agent.constructor.name,
|
|
60
|
+
...(capabilities ? { capabilities } : {}),
|
|
39
61
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
|
|
63
|
+
return [name, description] as const;
|
|
64
|
+
}),
|
|
43
65
|
);
|
|
44
66
|
|
|
67
|
+
const agentsDict: Record<string, AgentDescription> =
|
|
68
|
+
Object.fromEntries(agentEntries);
|
|
69
|
+
|
|
45
70
|
const runtimeInfo: RuntimeInfo = {
|
|
46
71
|
version: VERSION,
|
|
47
72
|
agents: agentsDict,
|
|
@@ -30,7 +30,7 @@ export async function handleRunAgent({
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
try {
|
|
33
|
-
const agent = await cloneAgentForRequest(runtime, agentId);
|
|
33
|
+
const agent = await cloneAgentForRequest(runtime, agentId, request);
|
|
34
34
|
if (agent instanceof Response) {
|
|
35
35
|
return agent;
|
|
36
36
|
}
|
|
@@ -55,6 +55,13 @@ export async function handleRunAgent({
|
|
|
55
55
|
agent.setState(input.state);
|
|
56
56
|
agent.threadId = input.threadId;
|
|
57
57
|
|
|
58
|
+
if (runtime.debug?.lifecycle && runtime.debugLogger) {
|
|
59
|
+
runtime.debugLogger.debug(
|
|
60
|
+
{ agentName: agentId, threadId: input.threadId },
|
|
61
|
+
"Agent run started",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
if (isIntelligenceRuntime(runtime)) {
|
|
59
66
|
return handleIntelligenceRun({
|
|
60
67
|
runtime,
|
|
@@ -65,7 +72,14 @@ export async function handleRunAgent({
|
|
|
65
72
|
});
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
return handleSseRun({
|
|
75
|
+
return handleSseRun({
|
|
76
|
+
runtime,
|
|
77
|
+
request,
|
|
78
|
+
agent,
|
|
79
|
+
input,
|
|
80
|
+
debug: runtime.debug,
|
|
81
|
+
logger: runtime.debugLogger,
|
|
82
|
+
});
|
|
69
83
|
} catch (error) {
|
|
70
84
|
console.error("Error running agent:", error);
|
|
71
85
|
console.error(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CopilotRuntimeLike } from "../core/runtime";
|
|
2
|
+
import { resolveAgents } from "../core/runtime";
|
|
2
3
|
import { EventType } from "@ag-ui/client";
|
|
3
4
|
|
|
4
5
|
interface StopAgentParameters {
|
|
@@ -15,7 +16,7 @@ export async function handleStopAgent({
|
|
|
15
16
|
threadId,
|
|
16
17
|
}: StopAgentParameters) {
|
|
17
18
|
try {
|
|
18
|
-
const agents = await runtime.agents;
|
|
19
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
19
20
|
|
|
20
21
|
if (!agents[agentId]) {
|
|
21
22
|
return new Response(
|
|
@@ -99,7 +99,7 @@ async function runTitleGenerationAttempt(params: {
|
|
|
99
99
|
prompt: string;
|
|
100
100
|
}): Promise<string | null> {
|
|
101
101
|
const { runtime, request, agentId, threadId, prompt } = params;
|
|
102
|
-
const agent = await cloneAgentForRequest(runtime, agentId);
|
|
102
|
+
const agent = await cloneAgentForRequest(runtime, agentId, request);
|
|
103
103
|
if (isHandlerResponse(agent)) {
|
|
104
104
|
logger.warn(
|
|
105
105
|
{ agentId, threadId },
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@ag-ui/client";
|
|
6
6
|
import { A2UIMiddleware } from "@ag-ui/a2ui-middleware";
|
|
7
7
|
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
|
|
8
|
-
import { CopilotRuntimeLike } from "../../core/runtime";
|
|
8
|
+
import { CopilotRuntimeLike, resolveAgents } from "../../core/runtime";
|
|
9
9
|
import { OpenGenerativeUIMiddleware } from "../../open-generative-ui-middleware";
|
|
10
10
|
import { extractForwardableHeaders } from "../header-utils";
|
|
11
11
|
import { logger } from "@copilotkit/shared";
|
|
@@ -28,8 +28,9 @@ export interface ConnectRequestBody extends RunAgentInput {
|
|
|
28
28
|
export async function cloneAgentForRequest(
|
|
29
29
|
runtime: CopilotRuntimeLike,
|
|
30
30
|
agentId: string,
|
|
31
|
+
request?: Request,
|
|
31
32
|
): Promise<AbstractAgent | Response> {
|
|
32
|
-
const agents = await runtime.agents;
|
|
33
|
+
const agents = await resolveAgents(runtime.agents, request);
|
|
33
34
|
|
|
34
35
|
if (!agents[agentId]) {
|
|
35
36
|
return new Response(
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { BaseEvent } from "@ag-ui/client";
|
|
2
2
|
import { EventEncoder } from "@ag-ui/encoder";
|
|
3
3
|
import { Observable, Subscription } from "rxjs";
|
|
4
|
+
import { ResolvedDebugConfig } from "@copilotkit/shared";
|
|
5
|
+
import {
|
|
6
|
+
createLogger,
|
|
7
|
+
type CopilotRuntimeLogger,
|
|
8
|
+
} from "../../../../lib/logger";
|
|
4
9
|
import { telemetry } from "../../telemetry";
|
|
5
10
|
|
|
6
11
|
interface CreateSseEventResponseParams {
|
|
@@ -8,17 +13,27 @@ interface CreateSseEventResponseParams {
|
|
|
8
13
|
observableFactory: () =>
|
|
9
14
|
| Promise<Observable<BaseEvent>>
|
|
10
15
|
| Observable<BaseEvent>;
|
|
16
|
+
debug?: ResolvedDebugConfig;
|
|
17
|
+
/** Pre-created logger instance to avoid creating a new pino logger per request. */
|
|
18
|
+
logger?: CopilotRuntimeLogger;
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export function createSseEventResponse({
|
|
14
22
|
request,
|
|
15
23
|
observableFactory,
|
|
24
|
+
debug,
|
|
25
|
+
logger,
|
|
16
26
|
}: CreateSseEventResponseParams): Response {
|
|
17
27
|
const stream = new TransformStream();
|
|
18
28
|
const writer = stream.writable.getWriter();
|
|
19
29
|
const encoder = new EventEncoder();
|
|
20
30
|
let streamClosed = false;
|
|
21
31
|
|
|
32
|
+
const debugLogger = debug?.enabled
|
|
33
|
+
? (logger ??
|
|
34
|
+
createLogger({ level: "debug", component: "copilotkit-debug" }))
|
|
35
|
+
: undefined;
|
|
36
|
+
|
|
22
37
|
const closeStream = async () => {
|
|
23
38
|
if (!streamClosed) {
|
|
24
39
|
try {
|
|
@@ -50,10 +65,29 @@ export function createSseEventResponse({
|
|
|
50
65
|
|
|
51
66
|
telemetry.capture("oss.runtime.agent_execution_stream_started", {});
|
|
52
67
|
|
|
68
|
+
if (debug?.lifecycle) {
|
|
69
|
+
debugLogger!.debug("SSE stream opened");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let eventCount = 0;
|
|
73
|
+
let loggedEventCount = 0;
|
|
74
|
+
|
|
53
75
|
subscription = observable.subscribe({
|
|
54
76
|
next: async (event) => {
|
|
55
77
|
if (!request.signal.aborted && !streamClosed) {
|
|
56
78
|
try {
|
|
79
|
+
eventCount++;
|
|
80
|
+
if (debug?.events) {
|
|
81
|
+
loggedEventCount++;
|
|
82
|
+
if (debug.verbose) {
|
|
83
|
+
debugLogger!.debug({ event }, "Event emitted");
|
|
84
|
+
} else {
|
|
85
|
+
debugLogger!.debug(
|
|
86
|
+
{ type: event.type, ...summarizeEvent(event) },
|
|
87
|
+
"Event emitted",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
57
91
|
await writer.write(encoder.encode(event));
|
|
58
92
|
} catch (error) {
|
|
59
93
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -66,11 +100,23 @@ export function createSseEventResponse({
|
|
|
66
100
|
telemetry.capture("oss.runtime.agent_execution_stream_errored", {
|
|
67
101
|
error: error instanceof Error ? error.message : String(error),
|
|
68
102
|
});
|
|
103
|
+
if (debug?.lifecycle) {
|
|
104
|
+
debugLogger!.debug(
|
|
105
|
+
{ error: error instanceof Error ? error.message : String(error) },
|
|
106
|
+
"SSE stream errored",
|
|
107
|
+
);
|
|
108
|
+
}
|
|
69
109
|
logError(error);
|
|
70
110
|
await closeStream();
|
|
71
111
|
},
|
|
72
112
|
complete: async () => {
|
|
73
113
|
telemetry.capture("oss.runtime.agent_execution_stream_ended", {});
|
|
114
|
+
if (debug?.lifecycle) {
|
|
115
|
+
debugLogger!.debug(
|
|
116
|
+
{ eventCount, loggedEventCount },
|
|
117
|
+
"SSE stream completed",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
74
120
|
await closeStream();
|
|
75
121
|
},
|
|
76
122
|
});
|
|
@@ -98,3 +144,26 @@ export function createSseEventResponse({
|
|
|
98
144
|
},
|
|
99
145
|
});
|
|
100
146
|
}
|
|
147
|
+
|
|
148
|
+
function summarizeEvent(event: BaseEvent): Record<string, unknown> {
|
|
149
|
+
const e = event as any;
|
|
150
|
+
const summary: Record<string, unknown> = {};
|
|
151
|
+
|
|
152
|
+
if (e.messageId) summary.messageId = e.messageId;
|
|
153
|
+
if (e.toolCallId) summary.toolCallId = e.toolCallId;
|
|
154
|
+
if (e.toolCallName) summary.toolCallName = e.toolCallName;
|
|
155
|
+
if (e.role) summary.role = e.role;
|
|
156
|
+
if (e.delta != null && typeof e.delta === "string")
|
|
157
|
+
summary.deltaLength = e.delta.length;
|
|
158
|
+
if (e.snapshot && typeof e.snapshot === "object")
|
|
159
|
+
summary.snapshotKeys = Object.keys(e.snapshot);
|
|
160
|
+
if (e.delta && Array.isArray(e.delta))
|
|
161
|
+
summary.operationCount = e.delta.length;
|
|
162
|
+
if (e.threadId) summary.threadId = e.threadId;
|
|
163
|
+
if (e.runId) summary.runId = e.runId;
|
|
164
|
+
if (e.message) summary.message = e.message;
|
|
165
|
+
if (e.code) summary.code = e.code;
|
|
166
|
+
if (e.stepName) summary.stepName = e.stepName;
|
|
167
|
+
|
|
168
|
+
return summary;
|
|
169
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { AbstractAgent, RunAgentInput } from "@ag-ui/client";
|
|
2
|
+
import { ResolvedDebugConfig } from "@copilotkit/shared";
|
|
3
|
+
import { type CopilotRuntimeLogger } from "../../../../lib/logger";
|
|
2
4
|
import { CopilotRuntimeLike } from "../../core/runtime";
|
|
3
5
|
import { createSseEventResponse } from "../shared/sse-response";
|
|
4
6
|
|
|
@@ -7,6 +9,9 @@ interface HandleSseRunParams {
|
|
|
7
9
|
request: Request;
|
|
8
10
|
agent: AbstractAgent;
|
|
9
11
|
input: RunAgentInput;
|
|
12
|
+
debug?: ResolvedDebugConfig;
|
|
13
|
+
/** Pre-created logger instance to avoid creating a new pino logger per request. */
|
|
14
|
+
logger?: CopilotRuntimeLogger;
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
export function handleSseRun({
|
|
@@ -14,9 +19,13 @@ export function handleSseRun({
|
|
|
14
19
|
request,
|
|
15
20
|
agent,
|
|
16
21
|
input,
|
|
22
|
+
debug,
|
|
23
|
+
logger,
|
|
17
24
|
}: HandleSseRunParams): Response {
|
|
18
25
|
return createSseEventResponse({
|
|
19
26
|
request,
|
|
27
|
+
debug,
|
|
28
|
+
logger,
|
|
20
29
|
observableFactory: () =>
|
|
21
30
|
runtime.runner.run({
|
|
22
31
|
threadId: input.threadId,
|
|
@@ -374,4 +374,272 @@ describe("AnthropicAdapter", () => {
|
|
|
374
374
|
});
|
|
375
375
|
});
|
|
376
376
|
});
|
|
377
|
+
|
|
378
|
+
describe("Unknown Tool Use Handling", () => {
|
|
379
|
+
it("should skip unknown tool_use blocks without crashing", async () => {
|
|
380
|
+
const systemMessage = new TextMessage("system", "System message");
|
|
381
|
+
const userMessage = new TextMessage("user", "Do something");
|
|
382
|
+
|
|
383
|
+
// Mock Anthropic to return a stream with an unknown tool_use block
|
|
384
|
+
mockAnthropicCreate.mockResolvedValue({
|
|
385
|
+
[Symbol.asyncIterator]: async function* () {
|
|
386
|
+
yield { type: "message_start", message: { id: "msg-1" } };
|
|
387
|
+
// Unknown tool_use block — tool name not in the actions list
|
|
388
|
+
yield {
|
|
389
|
+
type: "content_block_start",
|
|
390
|
+
content_block: {
|
|
391
|
+
type: "tool_use",
|
|
392
|
+
id: "tool-unknown",
|
|
393
|
+
name: "nonexistent_tool",
|
|
394
|
+
},
|
|
395
|
+
};
|
|
396
|
+
yield {
|
|
397
|
+
type: "content_block_delta",
|
|
398
|
+
delta: { type: "input_json_delta", partial_json: '{"query":' },
|
|
399
|
+
};
|
|
400
|
+
yield {
|
|
401
|
+
type: "content_block_delta",
|
|
402
|
+
delta: { type: "input_json_delta", partial_json: '"test"}' },
|
|
403
|
+
};
|
|
404
|
+
yield { type: "content_block_stop" };
|
|
405
|
+
// Then a normal text block
|
|
406
|
+
yield {
|
|
407
|
+
type: "content_block_start",
|
|
408
|
+
content_block: { type: "text" },
|
|
409
|
+
};
|
|
410
|
+
yield {
|
|
411
|
+
type: "content_block_delta",
|
|
412
|
+
delta: { type: "text_delta", text: "Here is the result." },
|
|
413
|
+
};
|
|
414
|
+
yield { type: "content_block_stop" };
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
const mockStream = {
|
|
419
|
+
sendTextMessageStart: vi.fn(),
|
|
420
|
+
sendTextMessageContent: vi.fn(),
|
|
421
|
+
sendTextMessageEnd: vi.fn(),
|
|
422
|
+
sendActionExecutionStart: vi.fn(),
|
|
423
|
+
sendActionExecutionArgs: vi.fn(),
|
|
424
|
+
sendActionExecutionEnd: vi.fn(),
|
|
425
|
+
complete: vi.fn(),
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
let streamCallbackDone: Promise<void>;
|
|
429
|
+
mockEventSource.stream.mockImplementation((callback: any) => {
|
|
430
|
+
streamCallbackDone = callback(mockStream);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
await adapter.process({
|
|
434
|
+
threadId: "test-thread",
|
|
435
|
+
messages: [systemMessage, userMessage],
|
|
436
|
+
actions: [
|
|
437
|
+
{
|
|
438
|
+
name: "known_tool",
|
|
439
|
+
description: "A known tool",
|
|
440
|
+
parameters: [],
|
|
441
|
+
jsonSchema: '{"type":"object","properties":{}}',
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
eventSource: mockEventSource,
|
|
445
|
+
forwardedParameters: {},
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Wait for async stream processing to complete
|
|
449
|
+
await streamCallbackDone!;
|
|
450
|
+
|
|
451
|
+
// Should NOT have sent action execution events for the unknown tool
|
|
452
|
+
expect(mockStream.sendActionExecutionStart).not.toHaveBeenCalled();
|
|
453
|
+
expect(mockStream.sendActionExecutionArgs).not.toHaveBeenCalled();
|
|
454
|
+
expect(mockStream.sendActionExecutionEnd).not.toHaveBeenCalled();
|
|
455
|
+
|
|
456
|
+
// Should still process the text block normally
|
|
457
|
+
expect(mockStream.sendTextMessageStart).toHaveBeenCalled();
|
|
458
|
+
expect(mockStream.sendTextMessageContent).toHaveBeenCalledWith({
|
|
459
|
+
messageId: "msg-1",
|
|
460
|
+
content: "Here is the result.",
|
|
461
|
+
});
|
|
462
|
+
expect(mockStream.sendTextMessageEnd).toHaveBeenCalled();
|
|
463
|
+
expect(mockStream.complete).toHaveBeenCalled();
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("should trigger fallback when only unknown tool_use blocks are returned", async () => {
|
|
467
|
+
const systemMessage = new TextMessage("system", "System message");
|
|
468
|
+
const userMessage = new TextMessage("user", "Do something");
|
|
469
|
+
|
|
470
|
+
const toolExecution = new ActionExecutionMessage({
|
|
471
|
+
id: "tool-prev",
|
|
472
|
+
name: "someAction",
|
|
473
|
+
arguments: "{}",
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const toolResult = new ResultMessage({
|
|
477
|
+
actionExecutionId: "tool-prev",
|
|
478
|
+
result: "Previous result",
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
// Mock Anthropic to return ONLY an unknown tool_use block
|
|
482
|
+
mockAnthropicCreate.mockResolvedValue({
|
|
483
|
+
[Symbol.asyncIterator]: async function* () {
|
|
484
|
+
yield { type: "message_start", message: { id: "msg-1" } };
|
|
485
|
+
yield {
|
|
486
|
+
type: "content_block_start",
|
|
487
|
+
content_block: {
|
|
488
|
+
type: "tool_use",
|
|
489
|
+
id: "tool-unknown",
|
|
490
|
+
name: "nonexistent_tool",
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
yield {
|
|
494
|
+
type: "content_block_delta",
|
|
495
|
+
delta: { type: "input_json_delta", partial_json: "{}" },
|
|
496
|
+
};
|
|
497
|
+
yield { type: "content_block_stop" };
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
const mockStream = {
|
|
502
|
+
sendTextMessageStart: vi.fn(),
|
|
503
|
+
sendTextMessageContent: vi.fn(),
|
|
504
|
+
sendTextMessageEnd: vi.fn(),
|
|
505
|
+
sendActionExecutionStart: vi.fn(),
|
|
506
|
+
sendActionExecutionArgs: vi.fn(),
|
|
507
|
+
sendActionExecutionEnd: vi.fn(),
|
|
508
|
+
complete: vi.fn(),
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
let streamCallbackDone: Promise<void>;
|
|
512
|
+
mockEventSource.stream.mockImplementation((callback: any) => {
|
|
513
|
+
streamCallbackDone = callback(mockStream);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await adapter.process({
|
|
517
|
+
threadId: "test-thread",
|
|
518
|
+
messages: [systemMessage, userMessage, toolExecution, toolResult],
|
|
519
|
+
actions: [
|
|
520
|
+
{
|
|
521
|
+
name: "known_tool",
|
|
522
|
+
description: "A known tool",
|
|
523
|
+
parameters: [],
|
|
524
|
+
jsonSchema: '{"type":"object","properties":{}}',
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
eventSource: mockEventSource,
|
|
528
|
+
forwardedParameters: {},
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Wait for async stream processing to complete
|
|
532
|
+
await streamCallbackDone!;
|
|
533
|
+
|
|
534
|
+
// Should NOT have sent action execution events
|
|
535
|
+
expect(mockStream.sendActionExecutionStart).not.toHaveBeenCalled();
|
|
536
|
+
|
|
537
|
+
// Should trigger fallback since hasReceivedContent should be false
|
|
538
|
+
expect(mockStream.sendTextMessageStart).toHaveBeenCalled();
|
|
539
|
+
expect(mockStream.sendTextMessageContent).toHaveBeenCalledWith({
|
|
540
|
+
messageId: expect.any(String),
|
|
541
|
+
content: "Previous result",
|
|
542
|
+
});
|
|
543
|
+
expect(mockStream.sendTextMessageEnd).toHaveBeenCalled();
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
describe("AnthropicAdapter max_tokens default", () => {
|
|
549
|
+
let mockAnthropicCreate: any;
|
|
550
|
+
let mockEventSource: any;
|
|
551
|
+
|
|
552
|
+
beforeEach(() => {
|
|
553
|
+
vi.clearAllMocks();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it("should default max_tokens to 4096 when not specified", async () => {
|
|
557
|
+
const mockAnthropic = {
|
|
558
|
+
messages: {
|
|
559
|
+
create: vi.fn(),
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
const adapter = new AnthropicAdapter({ anthropic: mockAnthropic as any });
|
|
564
|
+
mockAnthropicCreate = mockAnthropic.messages.create;
|
|
565
|
+
|
|
566
|
+
mockAnthropicCreate.mockResolvedValue({
|
|
567
|
+
[Symbol.asyncIterator]: async function* () {},
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
mockEventSource = {
|
|
571
|
+
stream: vi.fn((callback) => {
|
|
572
|
+
const mockStream = {
|
|
573
|
+
sendTextMessageStart: vi.fn(),
|
|
574
|
+
sendTextMessageContent: vi.fn(),
|
|
575
|
+
sendTextMessageEnd: vi.fn(),
|
|
576
|
+
sendActionExecutionStart: vi.fn(),
|
|
577
|
+
sendActionExecutionArgs: vi.fn(),
|
|
578
|
+
sendActionExecutionEnd: vi.fn(),
|
|
579
|
+
complete: vi.fn(),
|
|
580
|
+
};
|
|
581
|
+
callback(mockStream);
|
|
582
|
+
return Promise.resolve();
|
|
583
|
+
}),
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const systemMessage = new TextMessage("system", "System message");
|
|
587
|
+
const userMessage = new TextMessage("user", "Hello");
|
|
588
|
+
|
|
589
|
+
await adapter.process({
|
|
590
|
+
threadId: "test-thread",
|
|
591
|
+
messages: [systemMessage, userMessage],
|
|
592
|
+
actions: [],
|
|
593
|
+
eventSource: mockEventSource,
|
|
594
|
+
forwardedParameters: {},
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
const createCallArgs = mockAnthropicCreate.mock.calls[0][0];
|
|
598
|
+
expect(createCallArgs.max_tokens).toBe(4096);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it("should use provided maxTokens when specified", async () => {
|
|
602
|
+
const mockAnthropic = {
|
|
603
|
+
messages: {
|
|
604
|
+
create: vi.fn(),
|
|
605
|
+
},
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const adapter = new AnthropicAdapter({ anthropic: mockAnthropic as any });
|
|
609
|
+
mockAnthropicCreate = mockAnthropic.messages.create;
|
|
610
|
+
|
|
611
|
+
mockAnthropicCreate.mockResolvedValue({
|
|
612
|
+
[Symbol.asyncIterator]: async function* () {},
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
mockEventSource = {
|
|
616
|
+
stream: vi.fn((callback) => {
|
|
617
|
+
const mockStream = {
|
|
618
|
+
sendTextMessageStart: vi.fn(),
|
|
619
|
+
sendTextMessageContent: vi.fn(),
|
|
620
|
+
sendTextMessageEnd: vi.fn(),
|
|
621
|
+
sendActionExecutionStart: vi.fn(),
|
|
622
|
+
sendActionExecutionArgs: vi.fn(),
|
|
623
|
+
sendActionExecutionEnd: vi.fn(),
|
|
624
|
+
complete: vi.fn(),
|
|
625
|
+
};
|
|
626
|
+
callback(mockStream);
|
|
627
|
+
return Promise.resolve();
|
|
628
|
+
}),
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
const systemMessage = new TextMessage("system", "System message");
|
|
632
|
+
const userMessage = new TextMessage("user", "Hello");
|
|
633
|
+
|
|
634
|
+
await adapter.process({
|
|
635
|
+
threadId: "test-thread",
|
|
636
|
+
messages: [systemMessage, userMessage],
|
|
637
|
+
actions: [],
|
|
638
|
+
eventSource: mockEventSource,
|
|
639
|
+
forwardedParameters: { maxTokens: 8192 },
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
const createCallArgs = mockAnthropicCreate.mock.calls[0][0];
|
|
643
|
+
expect(createCallArgs.max_tokens).toBe(8192);
|
|
644
|
+
});
|
|
377
645
|
});
|