@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
|
@@ -2,9 +2,11 @@ require("reflect-metadata");
|
|
|
2
2
|
const require_sse_response = require('../shared/sse-response.cjs');
|
|
3
3
|
|
|
4
4
|
//#region src/v2/runtime/handlers/sse/run.ts
|
|
5
|
-
function handleSseRun({ runtime, request, agent, input }) {
|
|
5
|
+
function handleSseRun({ runtime, request, agent, input, debug, logger }) {
|
|
6
6
|
return require_sse_response.createSseEventResponse({
|
|
7
7
|
request,
|
|
8
|
+
debug,
|
|
9
|
+
logger,
|
|
8
10
|
observableFactory: () => runtime.runner.run({
|
|
9
11
|
threadId: input.threadId,
|
|
10
12
|
agent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["createSseEventResponse"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["createSseEventResponse"],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { type CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n debug,\n logger,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debug,\n logger,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;AAgBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,OACA,UAC+B;AAC/B,QAAOA,4CAAuB;EAC5B;EACA;EACA;EACA,yBACE,QAAQ,OAAO,IAAI;GACjB,UAAU,MAAM;GAChB;GACA;GACD,CAAC;EACL,CAAC"}
|
|
@@ -2,9 +2,11 @@ import "reflect-metadata";
|
|
|
2
2
|
import { createSseEventResponse } from "../shared/sse-response.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/v2/runtime/handlers/sse/run.ts
|
|
5
|
-
function handleSseRun({ runtime, request, agent, input }) {
|
|
5
|
+
function handleSseRun({ runtime, request, agent, input, debug, logger }) {
|
|
6
6
|
return createSseEventResponse({
|
|
7
7
|
request,
|
|
8
|
+
debug,
|
|
9
|
+
logger,
|
|
8
10
|
observableFactory: () => runtime.runner.run({
|
|
9
11
|
threadId: input.threadId,
|
|
10
12
|
agent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/sse/run.ts"],"sourcesContent":["import { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { ResolvedDebugConfig } from \"@copilotkit/shared\";\nimport { type CopilotRuntimeLogger } from \"../../../../lib/logger\";\nimport { CopilotRuntimeLike } from \"../../core/runtime\";\nimport { createSseEventResponse } from \"../shared/sse-response\";\n\ninterface HandleSseRunParams {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n input: RunAgentInput;\n debug?: ResolvedDebugConfig;\n /** Pre-created logger instance to avoid creating a new pino logger per request. */\n logger?: CopilotRuntimeLogger;\n}\n\nexport function handleSseRun({\n runtime,\n request,\n agent,\n input,\n debug,\n logger,\n}: HandleSseRunParams): Response {\n return createSseEventResponse({\n request,\n debug,\n logger,\n observableFactory: () =>\n runtime.runner.run({\n threadId: input.threadId,\n agent,\n input,\n }),\n });\n}\n"],"mappings":";;;;AAgBA,SAAgB,aAAa,EAC3B,SACA,SACA,OACA,OACA,OACA,UAC+B;AAC/B,QAAO,uBAAuB;EAC5B;EACA;EACA;EACA,yBACE,QAAQ,OAAO,IAAI;GACjB,UAAU,MAAM;GAChB;GACA;GACD,CAAC;EACL,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { TranscribeFileOptions, TranscriptionService } from "./transcription-service/transcription-service.cjs";
|
|
3
3
|
import { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest } from "./runner/agent-runner.cjs";
|
|
4
4
|
import { CopilotKitIntelligence, CopilotKitIntelligenceConfig, CreateThreadRequest, ListThreadsResponse, SubscribeToThreadsRequest, SubscribeToThreadsResponse, ThreadSummary, UpdateThreadRequest } from "./intelligence-platform/client.cjs";
|
|
5
|
-
import { CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotRuntime, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, IdentifyUserCallback, McpAppsConfig, McpAppsServerConfig, OpenGenerativeUIConfig, OpenGenerativeUIOptions, VERSION, isIntelligenceRuntime } from "./core/runtime.cjs";
|
|
5
|
+
import { AgentFactoryContext, AgentsConfig, AgentsFactory, CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotRuntime, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, IdentifyUserCallback, McpAppsConfig, McpAppsServerConfig, OpenGenerativeUIConfig, OpenGenerativeUIOptions, VERSION, isIntelligenceRuntime, resolveAgents } from "./core/runtime.cjs";
|
|
6
6
|
import { CopilotCorsConfig } from "./core/fetch-cors.cjs";
|
|
7
7
|
import { CopilotRuntimeHooks, ErrorHookContext, HandlerHookContext, HookContext, ResponseHookContext, RouteInfo } from "./core/hooks.cjs";
|
|
8
8
|
import { CopilotEndpointCorsConfig, createCopilotEndpoint, createCopilotHonoHandler, toFetchCorsConfig } from "./endpoints/hono.cjs";
|
|
@@ -3,7 +3,7 @@ import { TranscribeFileOptions, TranscriptionService } from "./transcription-ser
|
|
|
3
3
|
import { AgentRunner, AgentRunnerConnectRequest, AgentRunnerIsRunningRequest, AgentRunnerRunRequest, AgentRunnerStopRequest } from "./runner/agent-runner.mjs";
|
|
4
4
|
import { CopilotKitIntelligence, CopilotKitIntelligenceConfig, CreateThreadRequest, ListThreadsResponse, SubscribeToThreadsRequest, SubscribeToThreadsResponse, ThreadSummary, UpdateThreadRequest } from "./intelligence-platform/client.mjs";
|
|
5
5
|
import "./intelligence-platform/index.mjs";
|
|
6
|
-
import { CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotRuntime, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, IdentifyUserCallback, McpAppsConfig, McpAppsServerConfig, OpenGenerativeUIConfig, OpenGenerativeUIOptions, VERSION, isIntelligenceRuntime } from "./core/runtime.mjs";
|
|
6
|
+
import { AgentFactoryContext, AgentsConfig, AgentsFactory, CopilotIntelligenceRuntime, CopilotIntelligenceRuntimeLike, CopilotIntelligenceRuntimeOptions, CopilotRuntime, CopilotRuntimeLike, CopilotRuntimeOptions, CopilotRuntimeUser, CopilotSseRuntime, CopilotSseRuntimeLike, CopilotSseRuntimeOptions, IdentifyUserCallback, McpAppsConfig, McpAppsServerConfig, OpenGenerativeUIConfig, OpenGenerativeUIOptions, VERSION, isIntelligenceRuntime, resolveAgents } from "./core/runtime.mjs";
|
|
7
7
|
import { CopilotCorsConfig } from "./core/fetch-cors.mjs";
|
|
8
8
|
import { CopilotRuntimeHooks, ErrorHookContext, HandlerHookContext, HookContext, ResponseHookContext, RouteInfo } from "./core/hooks.mjs";
|
|
9
9
|
import { CopilotEndpointCorsConfig, createCopilotEndpoint, createCopilotHonoHandler, toFetchCorsConfig } from "./endpoints/hono.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -76,11 +76,11 @@
|
|
|
76
76
|
"access": "public"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@ag-ui/a2ui-middleware": "0.0.
|
|
79
|
+
"@ag-ui/a2ui-middleware": "0.0.5",
|
|
80
80
|
"@ag-ui/client": "0.0.52",
|
|
81
81
|
"@ag-ui/core": "0.0.52",
|
|
82
82
|
"@ag-ui/encoder": "0.0.52",
|
|
83
|
-
"@ag-ui/langgraph": "0.0.
|
|
83
|
+
"@ag-ui/langgraph": "0.0.29",
|
|
84
84
|
"@ag-ui/mcp-apps-middleware": "0.0.3",
|
|
85
85
|
"@ai-sdk/anthropic": "^3.0.49",
|
|
86
86
|
"@ai-sdk/google": "^3.0.33",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"graphql-scalars": "^1.23.0",
|
|
105
105
|
"graphql-yoga": "^5.3.1",
|
|
106
106
|
"hono": "^4.11.4",
|
|
107
|
-
"openai": "^4.85.1",
|
|
107
|
+
"openai": "^4.85.1 || >=5.0.0",
|
|
108
108
|
"partial-json": "^0.1.7",
|
|
109
109
|
"phoenix": "^1.8.4",
|
|
110
110
|
"pino": "^9.2.0",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"uuid": "^10.0.0",
|
|
116
116
|
"ws": "^8.18.0",
|
|
117
117
|
"zod": "^3.23.3",
|
|
118
|
-
"@copilotkit/shared": "1.
|
|
118
|
+
"@copilotkit/shared": "1.56.1"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@copilotkit/aimock": "^1.10.0",
|
|
@@ -148,7 +148,8 @@
|
|
|
148
148
|
"@langchain/langgraph-sdk": ">=0.1.2",
|
|
149
149
|
"@langchain/openai": ">=0.4.2",
|
|
150
150
|
"groq-sdk": ">=0.3.0 <1.0.0",
|
|
151
|
-
"langchain": ">=0.3.3"
|
|
151
|
+
"langchain": ">=0.3.3",
|
|
152
|
+
"openai": "^4.85.1 || >=5.0.0"
|
|
152
153
|
},
|
|
153
154
|
"peerDependenciesMeta": {
|
|
154
155
|
"@anthropic-ai/sdk": {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { BuiltInAgent } from "../index";
|
|
3
|
+
|
|
4
|
+
describe("BuiltInAgent.getCapabilities", () => {
|
|
5
|
+
it("should return default inferred capabilities", async () => {
|
|
6
|
+
const agent = new BuiltInAgent({
|
|
7
|
+
model: "openai/gpt-4o",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const capabilities = await agent.getCapabilities();
|
|
11
|
+
|
|
12
|
+
expect(capabilities).toEqual({
|
|
13
|
+
tools: {
|
|
14
|
+
supported: true,
|
|
15
|
+
clientProvided: true,
|
|
16
|
+
},
|
|
17
|
+
transport: {
|
|
18
|
+
streaming: true,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should merge explicit overrides with inferred defaults", async () => {
|
|
24
|
+
const agent = new BuiltInAgent({
|
|
25
|
+
model: "openai/gpt-4o",
|
|
26
|
+
capabilities: {
|
|
27
|
+
reasoning: {
|
|
28
|
+
supported: true,
|
|
29
|
+
streaming: true,
|
|
30
|
+
},
|
|
31
|
+
identity: {
|
|
32
|
+
name: "my-agent",
|
|
33
|
+
type: "custom",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const capabilities = await agent.getCapabilities();
|
|
39
|
+
|
|
40
|
+
expect(capabilities).toEqual({
|
|
41
|
+
tools: {
|
|
42
|
+
supported: true,
|
|
43
|
+
clientProvided: true,
|
|
44
|
+
},
|
|
45
|
+
transport: {
|
|
46
|
+
streaming: true,
|
|
47
|
+
},
|
|
48
|
+
reasoning: {
|
|
49
|
+
supported: true,
|
|
50
|
+
streaming: true,
|
|
51
|
+
},
|
|
52
|
+
identity: {
|
|
53
|
+
name: "my-agent",
|
|
54
|
+
type: "custom",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should allow overrides to replace entire categories", async () => {
|
|
60
|
+
const agent = new BuiltInAgent({
|
|
61
|
+
model: "openai/gpt-4o",
|
|
62
|
+
capabilities: {
|
|
63
|
+
tools: {
|
|
64
|
+
supported: true,
|
|
65
|
+
clientProvided: true,
|
|
66
|
+
parallelCalls: true,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const capabilities = await agent.getCapabilities();
|
|
72
|
+
|
|
73
|
+
expect(capabilities.tools).toEqual({
|
|
74
|
+
supported: true,
|
|
75
|
+
clientProvided: true,
|
|
76
|
+
parallelCalls: true,
|
|
77
|
+
});
|
|
78
|
+
// transport still inferred
|
|
79
|
+
expect(capabilities.transport).toEqual({ streaming: true });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { BuiltInAgent } from "../index";
|
|
3
|
+
import { EventType, type RunAgentInput } from "@ag-ui/client";
|
|
4
|
+
import { streamText } from "ai";
|
|
5
|
+
import {
|
|
6
|
+
mockStreamTextResponse,
|
|
7
|
+
textDelta,
|
|
8
|
+
finish,
|
|
9
|
+
collectEvents,
|
|
10
|
+
} from "./test-helpers";
|
|
11
|
+
|
|
12
|
+
// Mock the ai module
|
|
13
|
+
vi.mock("ai", () => ({
|
|
14
|
+
streamText: vi.fn(),
|
|
15
|
+
tool: vi.fn((config) => config),
|
|
16
|
+
stepCountIs: vi.fn((count: number) => ({ type: "stepCount", count })),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("@ai-sdk/openai", () => ({
|
|
20
|
+
createOpenAI: vi.fn(() => (modelId: string) => ({
|
|
21
|
+
specificationVersion: "v3",
|
|
22
|
+
modelId,
|
|
23
|
+
provider: "openai",
|
|
24
|
+
})),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock("@ai-sdk/anthropic", () => ({
|
|
28
|
+
createAnthropic: vi.fn(() => (modelId: string) => ({
|
|
29
|
+
specificationVersion: "v3",
|
|
30
|
+
modelId,
|
|
31
|
+
provider: "anthropic",
|
|
32
|
+
})),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock("@ai-sdk/google", () => ({
|
|
36
|
+
createGoogleGenerativeAI: vi.fn(() => (modelId: string) => ({
|
|
37
|
+
specificationVersion: "v3",
|
|
38
|
+
modelId,
|
|
39
|
+
provider: "google",
|
|
40
|
+
})),
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
describe("Provider ID collision (#3410, #3623)", () => {
|
|
44
|
+
const originalEnv = process.env;
|
|
45
|
+
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
vi.clearAllMocks();
|
|
48
|
+
process.env = { ...originalEnv };
|
|
49
|
+
process.env.OPENAI_API_KEY = "test-key";
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
process.env = originalEnv;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should replace text-start providedId "txt-0" with a UUID', async () => {
|
|
57
|
+
const agent = new BuiltInAgent({ model: "openai:gpt-4o-mini" });
|
|
58
|
+
|
|
59
|
+
vi.mocked(streamText).mockReturnValue(
|
|
60
|
+
mockStreamTextResponse([
|
|
61
|
+
{ type: "text-start", id: "txt-0" },
|
|
62
|
+
textDelta("Hello"),
|
|
63
|
+
finish(),
|
|
64
|
+
]) as any,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const input: RunAgentInput = {
|
|
68
|
+
threadId: "thread-1",
|
|
69
|
+
runId: "run-1",
|
|
70
|
+
messages: [{ id: "1", role: "user", content: "Hi" }],
|
|
71
|
+
tools: [],
|
|
72
|
+
context: [],
|
|
73
|
+
state: {},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const events = await collectEvents(agent["run"](input));
|
|
77
|
+
|
|
78
|
+
// Find the TEXT_MESSAGE_CHUNK event and check its messageId
|
|
79
|
+
const textChunks = events.filter(
|
|
80
|
+
(e) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
81
|
+
);
|
|
82
|
+
expect(textChunks.length).toBeGreaterThan(0);
|
|
83
|
+
const messageId = (textChunks[0] as any).messageId;
|
|
84
|
+
|
|
85
|
+
// The messageId should NOT be "txt-0" — it should be a UUID
|
|
86
|
+
expect(messageId).not.toBe("txt-0");
|
|
87
|
+
// UUID v4 pattern
|
|
88
|
+
expect(messageId).toMatch(
|
|
89
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should replace reasoning-start providedId "reasoning-0" with a UUID', async () => {
|
|
94
|
+
const agent = new BuiltInAgent({ model: "openai:gpt-4o-mini" });
|
|
95
|
+
|
|
96
|
+
vi.mocked(streamText).mockReturnValue(
|
|
97
|
+
mockStreamTextResponse([
|
|
98
|
+
{ type: "reasoning-start", id: "reasoning-0" },
|
|
99
|
+
{ type: "reasoning-delta", text: "Thinking..." },
|
|
100
|
+
{ type: "reasoning-end" },
|
|
101
|
+
{ type: "text-start", id: "txt-0" },
|
|
102
|
+
textDelta("Answer"),
|
|
103
|
+
finish(),
|
|
104
|
+
]) as any,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const input: RunAgentInput = {
|
|
108
|
+
threadId: "thread-2",
|
|
109
|
+
runId: "run-2",
|
|
110
|
+
messages: [{ id: "1", role: "user", content: "Hi" }],
|
|
111
|
+
tools: [],
|
|
112
|
+
context: [],
|
|
113
|
+
state: {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const events = await collectEvents(agent["run"](input));
|
|
117
|
+
|
|
118
|
+
// Find REASONING_START event
|
|
119
|
+
const reasoningStarts = events.filter(
|
|
120
|
+
(e) => e.type === EventType.REASONING_START,
|
|
121
|
+
);
|
|
122
|
+
expect(reasoningStarts.length).toBeGreaterThan(0);
|
|
123
|
+
const reasoningId = (reasoningStarts[0] as any).messageId;
|
|
124
|
+
|
|
125
|
+
// Should NOT be "reasoning-0"
|
|
126
|
+
expect(reasoningId).not.toBe("reasoning-0");
|
|
127
|
+
expect(reasoningId).toMatch(
|
|
128
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should replace providedId "msg-0" with a UUID', async () => {
|
|
133
|
+
const agent = new BuiltInAgent({ model: "openai:gpt-4o-mini" });
|
|
134
|
+
|
|
135
|
+
vi.mocked(streamText).mockReturnValue(
|
|
136
|
+
mockStreamTextResponse([
|
|
137
|
+
{ type: "text-start", id: "msg-0" },
|
|
138
|
+
textDelta("Hello"),
|
|
139
|
+
finish(),
|
|
140
|
+
]) as any,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const input: RunAgentInput = {
|
|
144
|
+
threadId: "thread-3",
|
|
145
|
+
runId: "run-3",
|
|
146
|
+
messages: [{ id: "1", role: "user", content: "Hi" }],
|
|
147
|
+
tools: [],
|
|
148
|
+
context: [],
|
|
149
|
+
state: {},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const events = await collectEvents(agent["run"](input));
|
|
153
|
+
|
|
154
|
+
const textChunks = events.filter(
|
|
155
|
+
(e) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
156
|
+
);
|
|
157
|
+
expect(textChunks.length).toBeGreaterThan(0);
|
|
158
|
+
const messageId = (textChunks[0] as any).messageId;
|
|
159
|
+
|
|
160
|
+
expect(messageId).not.toBe("msg-0");
|
|
161
|
+
expect(messageId).toMatch(
|
|
162
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("should preserve legitimate provider IDs", async () => {
|
|
167
|
+
const agent = new BuiltInAgent({ model: "openai:gpt-4o-mini" });
|
|
168
|
+
|
|
169
|
+
vi.mocked(streamText).mockReturnValue(
|
|
170
|
+
mockStreamTextResponse([
|
|
171
|
+
{ type: "text-start", id: "custom-msg-id-123" },
|
|
172
|
+
textDelta("Hello"),
|
|
173
|
+
finish(),
|
|
174
|
+
]) as any,
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const input: RunAgentInput = {
|
|
178
|
+
threadId: "thread-4",
|
|
179
|
+
runId: "run-4",
|
|
180
|
+
messages: [{ id: "1", role: "user", content: "Hi" }],
|
|
181
|
+
tools: [],
|
|
182
|
+
context: [],
|
|
183
|
+
state: {},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const events = await collectEvents(agent["run"](input));
|
|
187
|
+
|
|
188
|
+
const textChunks = events.filter(
|
|
189
|
+
(e) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
190
|
+
);
|
|
191
|
+
expect(textChunks.length).toBeGreaterThan(0);
|
|
192
|
+
// Legitimate IDs should be preserved
|
|
193
|
+
expect((textChunks[0] as any).messageId).toBe("custom-msg-id-123");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
@@ -11,24 +11,32 @@ import {
|
|
|
11
11
|
} from "@ag-ui/client";
|
|
12
12
|
import { randomUUID } from "@copilotkit/shared";
|
|
13
13
|
|
|
14
|
+
type ContentPartSource =
|
|
15
|
+
| { type: "data"; value: string; mimeType: string }
|
|
16
|
+
| { type: "url"; value: string; mimeType?: string };
|
|
17
|
+
|
|
14
18
|
/**
|
|
15
19
|
* A TanStack AI content part (text, image, audio, video, or document).
|
|
16
20
|
*/
|
|
17
21
|
export type TanStackContentPart =
|
|
18
22
|
| { type: "text"; content: string }
|
|
19
|
-
| {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
| { type: "url"; value: string; mimeType?: string };
|
|
24
|
-
};
|
|
23
|
+
| { type: "image"; source: ContentPartSource }
|
|
24
|
+
| { type: "audio"; source: ContentPartSource }
|
|
25
|
+
| { type: "video"; source: ContentPartSource }
|
|
26
|
+
| { type: "document"; source: ContentPartSource };
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Message format expected by TanStack AI's `chat()`.
|
|
30
|
+
*
|
|
31
|
+
* Content is typed as `any[]` for the multimodal case so messages are directly
|
|
32
|
+
* passable to any adapter without casts — different adapters constrain which
|
|
33
|
+
* modalities they accept (e.g. OpenAI only allows text + image).
|
|
34
|
+
* Use `TanStackContentPart` to inspect individual parts if needed.
|
|
28
35
|
*/
|
|
29
36
|
export interface TanStackChatMessage {
|
|
30
37
|
role: "user" | "assistant" | "tool";
|
|
31
|
-
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
content: string | null | any[];
|
|
32
40
|
name?: string;
|
|
33
41
|
toolCalls?: Array<{
|
|
34
42
|
id: string;
|
package/src/agent/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
StateSnapshotEvent,
|
|
21
21
|
StateDeltaEvent,
|
|
22
22
|
} from "@ag-ui/client";
|
|
23
|
+
import type { AgentCapabilities } from "@ag-ui/core";
|
|
23
24
|
import {
|
|
24
25
|
streamText,
|
|
25
26
|
LanguageModel,
|
|
@@ -817,6 +818,15 @@ export interface BuiltInAgentClassicConfig {
|
|
|
817
818
|
* Example: `{ openai: { reasoningEffort: "high" } }`
|
|
818
819
|
*/
|
|
819
820
|
providerOptions?: Record<string, any>;
|
|
821
|
+
/**
|
|
822
|
+
* Explicit agent capabilities. **Shallow-merged** at the category level on
|
|
823
|
+
* top of auto-inferred defaults — providing a category (e.g. `tools`)
|
|
824
|
+
* replaces that entire category, not individual fields within it.
|
|
825
|
+
*
|
|
826
|
+
* For example, `{ tools: { supported: true } }` will drop the inferred
|
|
827
|
+
* `clientProvided` value. Include all fields for any category you override.
|
|
828
|
+
*/
|
|
829
|
+
capabilities?: Partial<AgentCapabilities>;
|
|
820
830
|
}
|
|
821
831
|
|
|
822
832
|
/**
|
|
@@ -854,6 +864,29 @@ export class BuiltInAgent extends AbstractAgent {
|
|
|
854
864
|
return this.config?.overridableProperties?.includes(property) ?? false;
|
|
855
865
|
}
|
|
856
866
|
|
|
867
|
+
async getCapabilities(): Promise<AgentCapabilities> {
|
|
868
|
+
const inferred: AgentCapabilities = {
|
|
869
|
+
tools: {
|
|
870
|
+
supported: true,
|
|
871
|
+
clientProvided: true,
|
|
872
|
+
},
|
|
873
|
+
transport: {
|
|
874
|
+
streaming: true,
|
|
875
|
+
},
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
if (!this.config.capabilities) {
|
|
879
|
+
return inferred;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Shallow merge at the category level — explicit overrides replace
|
|
883
|
+
// entire categories when provided, inferred defaults fill the rest.
|
|
884
|
+
return {
|
|
885
|
+
...inferred,
|
|
886
|
+
...this.config.capabilities,
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
857
890
|
run(input: RunAgentInput): Observable<BaseEvent> {
|
|
858
891
|
if (isFactoryConfig(this.config)) {
|
|
859
892
|
return this.runFactory(input, this.config);
|
|
@@ -1234,13 +1267,17 @@ export class BuiltInAgent extends AbstractAgent {
|
|
|
1234
1267
|
break;
|
|
1235
1268
|
}
|
|
1236
1269
|
case "reasoning-start": {
|
|
1237
|
-
// Use SDK-provided id, or generate a fresh UUID if id is falsy
|
|
1238
|
-
//
|
|
1270
|
+
// Use SDK-provided id, or generate a fresh UUID if the id is falsy,
|
|
1271
|
+
// "0", or matches the non-unique pattern emitted by @ai-sdk/openai-compatible
|
|
1272
|
+
// (e.g. "txt-0", "reasoning-0", "msg-0").
|
|
1239
1273
|
const providedId = "id" in part ? part.id : undefined;
|
|
1240
|
-
|
|
1241
|
-
providedId
|
|
1242
|
-
|
|
1243
|
-
|
|
1274
|
+
const isNonUniqueId =
|
|
1275
|
+
!providedId ||
|
|
1276
|
+
providedId === "0" ||
|
|
1277
|
+
/^(txt|reasoning|msg)-0$/.test(providedId);
|
|
1278
|
+
reasoningMessageId = isNonUniqueId
|
|
1279
|
+
? randomUUID()
|
|
1280
|
+
: (providedId as typeof reasoningMessageId);
|
|
1244
1281
|
const reasoningStartEvent: ReasoningStartEvent = {
|
|
1245
1282
|
type: EventType.REASONING_START,
|
|
1246
1283
|
messageId: reasoningMessageId,
|
|
@@ -1308,12 +1345,16 @@ export class BuiltInAgent extends AbstractAgent {
|
|
|
1308
1345
|
|
|
1309
1346
|
case "text-start": {
|
|
1310
1347
|
// New text message starting - use the SDK-provided id
|
|
1311
|
-
// Use randomUUID() if part.id is falsy
|
|
1348
|
+
// Use randomUUID() if part.id is falsy, "0", or matches the non-unique
|
|
1349
|
+
// pattern emitted by @ai-sdk/openai-compatible (e.g. "txt-0", "msg-0").
|
|
1312
1350
|
const providedId = "id" in part ? part.id : undefined;
|
|
1313
|
-
|
|
1314
|
-
providedId
|
|
1315
|
-
|
|
1316
|
-
|
|
1351
|
+
const isNonUniqueTextId =
|
|
1352
|
+
!providedId ||
|
|
1353
|
+
providedId === "0" ||
|
|
1354
|
+
/^(txt|reasoning|msg)-0$/.test(providedId);
|
|
1355
|
+
messageId = isNonUniqueTextId
|
|
1356
|
+
? randomUUID()
|
|
1357
|
+
: (providedId as typeof messageId);
|
|
1317
1358
|
break;
|
|
1318
1359
|
}
|
|
1319
1360
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test for #2986: instanceof Request fails with @hono/node-server polyfill
|
|
5
|
+
*
|
|
6
|
+
* When Hono polyfills the Request class, `instanceof Request` fails because
|
|
7
|
+
* the polyfilled Request has a different prototype. We need duck-type checking.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Simulates a polyfilled Request object that does NOT pass instanceof Request
|
|
11
|
+
function createPolyfillRequest(url: string, method: string = "GET"): object {
|
|
12
|
+
return {
|
|
13
|
+
url,
|
|
14
|
+
method,
|
|
15
|
+
headers: new Headers({ "content-type": "application/json" }),
|
|
16
|
+
body: null,
|
|
17
|
+
clone: () => createPolyfillRequest(url, method),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// This is the duck-type check that should replace instanceof
|
|
22
|
+
function isRequestLike(obj: unknown): obj is Request {
|
|
23
|
+
return (
|
|
24
|
+
typeof obj === "object" &&
|
|
25
|
+
obj !== null &&
|
|
26
|
+
"url" in obj &&
|
|
27
|
+
"method" in obj &&
|
|
28
|
+
"headers" in obj &&
|
|
29
|
+
typeof (obj as any).url === "string" &&
|
|
30
|
+
typeof (obj as any).method === "string"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("Request duck-type detection (#2986)", () => {
|
|
35
|
+
it("should detect a native Request object", () => {
|
|
36
|
+
const req = new Request("http://localhost:3000/api/copilotkit", {
|
|
37
|
+
method: "POST",
|
|
38
|
+
});
|
|
39
|
+
expect(isRequestLike(req)).toBe(true);
|
|
40
|
+
expect(req instanceof Request).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should detect a polyfilled Request object that fails instanceof", () => {
|
|
44
|
+
const polyfilled = createPolyfillRequest(
|
|
45
|
+
"http://localhost:3000/api/copilotkit",
|
|
46
|
+
"POST",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// instanceof fails for polyfilled objects
|
|
50
|
+
expect(polyfilled instanceof Request).toBe(false);
|
|
51
|
+
|
|
52
|
+
// But duck-type check succeeds
|
|
53
|
+
expect(isRequestLike(polyfilled)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should NOT match null or undefined", () => {
|
|
57
|
+
expect(isRequestLike(null)).toBe(false);
|
|
58
|
+
expect(isRequestLike(undefined)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should NOT match an object missing required properties", () => {
|
|
62
|
+
expect(isRequestLike({ url: "http://test.com" })).toBe(false);
|
|
63
|
+
expect(isRequestLike({ method: "GET" })).toBe(false);
|
|
64
|
+
expect(isRequestLike({})).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -158,11 +158,25 @@ export function copilotRuntimeNodeHttpEndpoint(
|
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
+
// Duck-type check for Request-like objects (handles polyfilled Request from @hono/node-server)
|
|
162
|
+
function isRequestLike(obj: unknown): obj is Request {
|
|
163
|
+
return (
|
|
164
|
+
obj instanceof Request ||
|
|
165
|
+
(typeof obj === "object" &&
|
|
166
|
+
obj !== null &&
|
|
167
|
+
"url" in obj &&
|
|
168
|
+
"method" in obj &&
|
|
169
|
+
"headers" in obj &&
|
|
170
|
+
typeof (obj as any).url === "string" &&
|
|
171
|
+
typeof (obj as any).method === "string")
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
161
175
|
return function (
|
|
162
176
|
reqOrRequest: IncomingMessage | Request,
|
|
163
177
|
res?: ServerResponse,
|
|
164
178
|
): Promise<void> | Promise<Response> | Response {
|
|
165
|
-
if (reqOrRequest
|
|
179
|
+
if (isRequestLike(reqOrRequest) && !res) {
|
|
166
180
|
return honoApp.fetch(reqOrRequest as Request);
|
|
167
181
|
}
|
|
168
182
|
if (!res) {
|