@copilotkit/runtime 1.66.1-canary.rn-tool-render → 1.66.2-canary.1785866877
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/package.cjs +1 -1
- package/dist/runtime/package.mjs +1 -1
- package/dist/v2/runtime/core/channel-manager.cjs +109 -28
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +109 -28
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs +303 -44
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts +22 -0
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts +22 -0
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs +304 -45
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.cjs","names":["resolveIntelligenceUser","isHandlerResponse","generateThreadNameForNewThread","EventType"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run.cjs","names":["resolveIntelligenceUser","isHandlerResponse","generateThreadNameForNewThread","EventType"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -104,6 +104,7 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
104
104
|
return Response.json({ error: "Thread history lookup failed" }, { status: 502 });
|
|
105
105
|
}
|
|
106
106
|
telemetry.capture("oss.runtime.agent_execution_stream_started", {});
|
|
107
|
+
let heartbeatStopped = false;
|
|
107
108
|
let heartbeatTimer;
|
|
108
109
|
heartbeatTimer = setInterval(() => {
|
|
109
110
|
runtime.intelligence.ɵrenewThreadLock({
|
|
@@ -112,6 +113,7 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
112
113
|
ttlSeconds: runtime.lockTtlSeconds,
|
|
113
114
|
...runtime.lockKeyPrefix !== void 0 ? { lockKeyPrefix: runtime.lockKeyPrefix } : {}
|
|
114
115
|
}).catch((err) => {
|
|
116
|
+
if (heartbeatStopped) return;
|
|
115
117
|
logger.error("Failed to renew thread lock:", err);
|
|
116
118
|
clearHeartbeat();
|
|
117
119
|
try {
|
|
@@ -122,6 +124,7 @@ async function handleIntelligenceRun({ runtime, request, agentId, agent, input }
|
|
|
122
124
|
});
|
|
123
125
|
}, runtime.lockHeartbeatIntervalSeconds * 1e3);
|
|
124
126
|
const clearHeartbeat = () => {
|
|
127
|
+
heartbeatStopped = true;
|
|
125
128
|
if (heartbeatTimer !== void 0) {
|
|
126
129
|
clearInterval(heartbeatTimer);
|
|
127
130
|
heartbeatTimer = void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run.mjs","names":[],"sources":["../../../../../src/v2/runtime/handlers/intelligence/run.ts"],"sourcesContent":["import type {\n AbstractAgent,\n BaseEvent,\n Message,\n RunAgentInput,\n} from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport { generateThreadNameForNewThread } from \"./thread-names\";\nimport { logger } from \"@copilotkit/shared\";\nimport { telemetry } from \"../../telemetry\";\nimport { resolveIntelligenceUser } from \"../shared/resolve-intelligence-user\";\nimport { isHandlerResponse } from \"../shared/json-response\";\nimport type { AgentRunnerRunRequest } from \"../../runner/agent-runner\";\nimport type { Observable } from \"rxjs\";\n\n/**\n * Builds browser-facing realtime connection metadata owned by the runtime.\n */\nfunction buildRealtimeConnectionInfo(params: {\n clientUrl: string;\n threadId: string;\n}): { clientUrl: string; topic: string } {\n return {\n clientUrl: params.clientUrl,\n topic: `thread:${params.threadId}`,\n };\n}\n\ninterface RunnerStartupBoundary {\n events: Observable<BaseEvent>;\n startup: Promise<void>;\n}\n\ninterface RunnerWithStartupBoundary {\n runWithStartupBoundary(request: AgentRunnerRunRequest): RunnerStartupBoundary;\n}\n\nfunction hasRunnerStartupBoundary(\n runner: CopilotIntelligenceRuntimeLike[\"runner\"],\n): runner is CopilotIntelligenceRuntimeLike[\"runner\"] &\n RunnerWithStartupBoundary {\n const candidate = runner as { runWithStartupBoundary?: unknown };\n\n return (\n typeof candidate.runWithStartupBoundary === \"function\" &&\n (Object.prototype.hasOwnProperty.call(runner, \"runWithStartupBoundary\") ||\n Object.prototype.hasOwnProperty.call(runner, \"threads\"))\n );\n}\n\ninterface HandleIntelligenceRunParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n input: RunAgentInput;\n}\n\nexport async function handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n}: HandleIntelligenceRunParams): Promise<Response> {\n if (!runtime.intelligence) {\n return Response.json(\n {\n error: \"Intelligence not configured\",\n message: \"Intelligence mode requires a CopilotKitIntelligence\",\n },\n { status: 500 },\n );\n }\n\n const user = await resolveIntelligenceUser({ runtime, request });\n if (isHandlerResponse(user)) {\n return user;\n }\n const userId = user.id;\n\n try {\n const { thread, created } = await runtime.intelligence.getOrCreateThread({\n threadId: input.threadId,\n userId,\n agentId,\n });\n\n if (created && runtime.generateThreadNames && !thread.name?.trim()) {\n void generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput: input,\n thread,\n userId,\n }).catch((nameError) => {\n logger.error(\"Failed to generate thread name:\", nameError);\n });\n }\n } catch (error) {\n logger.error(\"Failed to get or create thread:\", error);\n return Response.json(\n {\n error: \"Failed to initialize thread\",\n },\n { status: 502 },\n );\n }\n\n let canonicalThreadId = input.threadId;\n let canonicalRunId = input.runId;\n let joinToken: string | undefined;\n try {\n const lockResult = await runtime.intelligence.ɵacquireThreadLock({\n threadId: input.threadId,\n runId: input.runId,\n userId,\n agentId,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n ttlSeconds: runtime.lockTtlSeconds,\n });\n canonicalThreadId = lockResult.threadId;\n canonicalRunId = lockResult.runId;\n joinToken = lockResult.joinToken;\n } catch (error) {\n logger.error(\"Thread lock denied:\", error);\n return Response.json(\n {\n error: \"Thread lock denied\",\n },\n { status: 409 },\n );\n }\n\n const cleanupLock = (reason: string): Promise<void> =>\n runtime.intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId || input.threadId,\n runId: canonicalRunId || input.runId,\n })\n .catch((cleanupError) => {\n logger.error(\n { err: cleanupError, reason },\n \"Failed to cleanup thread lock\",\n );\n });\n\n if (!canonicalThreadId || !canonicalRunId || !joinToken) {\n await cleanupLock(\"malformed-lock-response\");\n return Response.json(\n {\n error: \"Run connection credentials not available\",\n message:\n \"Intelligence platform did not return canonical threadId, runId, and joinToken\",\n },\n { status: 502 },\n );\n }\n\n const canonicalInput: RunAgentInput = {\n ...input,\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n };\n\n let persistedInputMessages: Message[] | undefined;\n if (Array.isArray(input.messages)) {\n try {\n const history = await runtime.intelligence.getThreadMessages({\n threadId: canonicalThreadId,\n userId,\n });\n const historicMessageIds = new Set(\n history.messages.map((message) => message.id),\n );\n persistedInputMessages = input.messages.filter(\n (message) => !historicMessageIds.has(message.id),\n );\n } catch (error) {\n logger.error(\"Thread history lookup failed:\", error);\n await cleanupLock(\"thread-history-lookup-failed\");\n return Response.json(\n {\n error: \"Thread history lookup failed\",\n },\n { status: 502 },\n );\n }\n }\n\n telemetry.capture(\"oss.runtime.agent_execution_stream_started\", {});\n\n // Start heartbeat timer to renew the thread lock.\n let heartbeatStopped = false;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n heartbeatTimer = setInterval(() => {\n runtime.intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: runtime.lockTtlSeconds,\n ...(runtime.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: runtime.lockKeyPrefix }\n : {}),\n })\n .catch((err) => {\n if (heartbeatStopped) {\n return;\n }\n\n logger.error(\"Failed to renew thread lock:\", err);\n clearHeartbeat();\n try {\n agent.abortRun();\n } catch (abortError) {\n logger.error(\n \"Failed to abort agent after lock renewal failure:\",\n abortError,\n );\n }\n });\n }, runtime.lockHeartbeatIntervalSeconds * 1_000);\n\n const clearHeartbeat = () => {\n heartbeatStopped = true;\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n };\n\n const runStarted = { current: false };\n let immediateStartupErrorMessage: string | undefined;\n let immediateStartupCleanup: Promise<void> | undefined;\n\n const runRequest: AgentRunnerRunRequest = {\n threadId: canonicalThreadId,\n agent,\n input: canonicalInput,\n ...(persistedInputMessages !== undefined ? { persistedInputMessages } : {}),\n };\n\n try {\n const runStart = hasRunnerStartupBoundary(runtime.runner)\n ? runtime.runner.runWithStartupBoundary(runRequest)\n : {\n events: runtime.runner.run(runRequest),\n startup: Promise.resolve(),\n };\n\n runStart.events.subscribe({\n next: (event: BaseEvent) => {\n if (event.type === EventType.RUN_STARTED) {\n runStarted.current = true;\n }\n if (event.type === EventType.RUN_ERROR && !runStarted.current) {\n clearHeartbeat();\n immediateStartupErrorMessage =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Runner failed before the run started\";\n immediateStartupCleanup = cleanupLock(\"runner-start-failed\");\n }\n },\n error: (error) => {\n clearHeartbeat();\n if (!runStarted.current) {\n immediateStartupErrorMessage =\n error instanceof Error ? error.message : String(error);\n immediateStartupCleanup = cleanupLock(\"runner-start-error\");\n } else {\n cleanupLock(\"runner-error\");\n }\n telemetry.capture(\"oss.runtime.agent_execution_stream_errored\", {\n error: error instanceof Error ? error.message : String(error),\n });\n logger.error(\"Error running agent:\", error);\n },\n complete: () => {\n clearHeartbeat();\n telemetry.capture(\"oss.runtime.agent_execution_stream_ended\", {});\n },\n });\n\n await runStart.startup;\n } catch (error) {\n clearHeartbeat();\n await (immediateStartupCleanup ?? cleanupLock(\"runner-start-threw\"));\n logger.error(\"Error starting agent runner:\", error);\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: error instanceof Error ? error.message : String(error),\n },\n { status: 502 },\n );\n }\n\n if (immediateStartupErrorMessage) {\n await immediateStartupCleanup;\n return Response.json(\n {\n error: \"Failed to start runner\",\n message: immediateStartupErrorMessage,\n },\n { status: 502 },\n );\n }\n\n // IntelligenceAgentRunner resolves this boundary after Phoenix channel join.\n // Other runner implementations fall back to construction/subscription errors.\n return Response.json(\n {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n joinToken,\n realtime: buildRealtimeConnectionInfo({\n clientUrl: runtime.intelligence.ɵgetClientWsUrl(),\n threadId: canonicalThreadId,\n }),\n },\n {\n headers: { \"Cache-Control\": \"no-cache\" },\n },\n );\n}\n"],"mappings":"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"}
|
|
@@ -5,10 +5,16 @@ let _copilotkit_shared = require("@copilotkit/shared");
|
|
|
5
5
|
let rxjs = require("rxjs");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let _ag_ui_client = require("@ag-ui/client");
|
|
8
|
-
let rxjs_operators = require("rxjs/operators");
|
|
9
8
|
let phoenix = require("phoenix");
|
|
10
9
|
|
|
11
10
|
//#region src/v2/runtime/runner/intelligence.ts
|
|
11
|
+
const MAX_CONSECUTIVE_SOCKET_ERRORS = 5;
|
|
12
|
+
const EVENT_RETRY_BASE_MS = 100;
|
|
13
|
+
const EVENT_RETRY_MAX_MS = 2e3;
|
|
14
|
+
const RUNNER_EVENT_BATCH_CAPABILITY = "runner_event_batch_v1";
|
|
15
|
+
const MAX_RUNNER_EVENT_BATCH_SIZE = 32;
|
|
16
|
+
const RUNNER_EVENT_BATCH_FLUSH_MS = 5;
|
|
17
|
+
const EVENT_DURABILITY_DEADLINE_MS = 6e4;
|
|
12
18
|
var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
13
19
|
constructor(options) {
|
|
14
20
|
super();
|
|
@@ -99,12 +105,17 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
99
105
|
const { threadId, agent, input } = request;
|
|
100
106
|
if (this.threads.get(threadId)?.isRunning) throw new Error("Thread already running");
|
|
101
107
|
return new rxjs.Observable((observer) => {
|
|
108
|
+
if (this.threads.get(threadId)?.isRunning) {
|
|
109
|
+
observer.error(/* @__PURE__ */ new Error("Thread already running"));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
102
112
|
const socket = this.createSocket(request.authToken);
|
|
103
113
|
const channel = socket.channel(`ingestion:${input.runId}`, {
|
|
104
114
|
thread_id: threadId,
|
|
105
115
|
run_id: input.runId
|
|
106
116
|
});
|
|
107
117
|
const state = {
|
|
118
|
+
threadId,
|
|
108
119
|
runId: input.runId,
|
|
109
120
|
socket,
|
|
110
121
|
channel,
|
|
@@ -113,29 +124,84 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
113
124
|
agent,
|
|
114
125
|
currentEvents: [],
|
|
115
126
|
nextEventSeq: 1,
|
|
116
|
-
hasRunStarted: false
|
|
127
|
+
hasRunStarted: false,
|
|
128
|
+
hasJoined: false,
|
|
129
|
+
supportsRunnerEventBatch: false,
|
|
130
|
+
producerFinished: false,
|
|
131
|
+
pendingEvents: /* @__PURE__ */ new Map(),
|
|
132
|
+
activeEventBatch: null,
|
|
133
|
+
nextEventPushAttempt: 0,
|
|
134
|
+
eventRetryTimer: null,
|
|
135
|
+
eventFlushTimer: null,
|
|
136
|
+
eventDeadlineTimer: null,
|
|
137
|
+
socketReconnectWatchdog: null,
|
|
138
|
+
eventRetryAttempt: 0,
|
|
139
|
+
completeRun: () => observer.complete(),
|
|
140
|
+
failRun: (error) => observer.error(error)
|
|
117
141
|
};
|
|
118
142
|
this.threads.set(threadId, state);
|
|
119
|
-
|
|
120
|
-
let
|
|
121
|
-
socket.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
143
|
+
let consecutiveSocketErrors = 0;
|
|
144
|
+
let plannedRestart = false;
|
|
145
|
+
socket.onClose((event) => {
|
|
146
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
147
|
+
plannedRestart = plannedRestart || event?.code === 1012;
|
|
148
|
+
if (event?.code !== 1e3 && state.socketReconnectWatchdog === null) state.socketReconnectWatchdog = setTimeout(() => {
|
|
149
|
+
state.socketReconnectWatchdog = null;
|
|
150
|
+
if (!state.isRunning || socket.isConnected()) return;
|
|
151
|
+
socket.disconnect(() => {
|
|
152
|
+
if (state.isRunning && !socket.isConnected()) socket.connect();
|
|
153
|
+
});
|
|
154
|
+
}, 1e3);
|
|
126
155
|
});
|
|
127
156
|
socket.onOpen(() => {
|
|
128
|
-
|
|
157
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
158
|
+
if (state.socketReconnectWatchdog !== null) {
|
|
159
|
+
clearTimeout(state.socketReconnectWatchdog);
|
|
160
|
+
state.socketReconnectWatchdog = null;
|
|
161
|
+
}
|
|
162
|
+
consecutiveSocketErrors = 0;
|
|
163
|
+
plannedRestart = false;
|
|
164
|
+
});
|
|
165
|
+
socket.onError(() => {
|
|
166
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
167
|
+
if (plannedRestart || state.hasJoined) return;
|
|
168
|
+
consecutiveSocketErrors += 1;
|
|
169
|
+
if (consecutiveSocketErrors >= MAX_CONSECUTIVE_SOCKET_ERRORS) state.agent?.abortRun();
|
|
129
170
|
});
|
|
130
171
|
channel.on(_copilotkit_shared.AG_UI_CHANNEL_EVENT, (payload) => {
|
|
131
|
-
if (payload.type === _ag_ui_client.EventType.CUSTOM && payload.name === "stop") this.stop({
|
|
172
|
+
if (this.isCurrentThreadState(threadId, state) && payload.type === _ag_ui_client.EventType.CUSTOM && payload.name === "stop") this.stop({
|
|
173
|
+
threadId,
|
|
174
|
+
runId: state.runId
|
|
175
|
+
});
|
|
132
176
|
});
|
|
133
|
-
channel.join().receive("ok", () => {
|
|
177
|
+
channel.join().receive("ok", (response) => {
|
|
178
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
179
|
+
const supportsRunnerEventBatch = this.supportsRunnerEventBatch(response);
|
|
180
|
+
const activeEventBatch = state.supportsRunnerEventBatch === supportsRunnerEventBatch ? state.activeEventBatch : null;
|
|
181
|
+
state.supportsRunnerEventBatch = supportsRunnerEventBatch;
|
|
182
|
+
if (state.hasJoined) {
|
|
183
|
+
this.resetPendingEventRetry(state);
|
|
184
|
+
if (activeEventBatch !== null) {
|
|
185
|
+
state.activeEventBatch = activeEventBatch;
|
|
186
|
+
this.retryActiveEventBatch(state);
|
|
187
|
+
} else this.replayPendingEvents(state);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
state.hasJoined = true;
|
|
134
191
|
startupBoundary?.resolveStartup();
|
|
135
192
|
this.executeAgentRun(request, state, threadId, (event) => {
|
|
136
193
|
observer.next(event);
|
|
137
|
-
})
|
|
194
|
+
});
|
|
138
195
|
}).receive("error", (resp) => {
|
|
196
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
197
|
+
if (state.hasJoined) {
|
|
198
|
+
if (this.isPermanentEventFailure(resp)) {
|
|
199
|
+
const reason = typeof resp.reason === "string" ? `: ${resp.reason}` : "";
|
|
200
|
+
this.failThread(threadId, state, /* @__PURE__ */ new Error(`Gateway permanently rejected channel rejoin${reason}`));
|
|
201
|
+
}
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (this.isRetryableJoinError(resp)) return;
|
|
139
205
|
const error = /* @__PURE__ */ new Error(`Failed to join channel: ${JSON.stringify(resp)}`);
|
|
140
206
|
const errorEvent = {
|
|
141
207
|
type: _ag_ui_client.EventType.RUN_ERROR,
|
|
@@ -144,10 +210,12 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
144
210
|
};
|
|
145
211
|
observer.next(errorEvent);
|
|
146
212
|
state.currentEvents.push(errorEvent);
|
|
147
|
-
this.removeThread(threadId);
|
|
213
|
+
this.removeThread(threadId, state);
|
|
148
214
|
startupBoundary?.rejectStartup(error);
|
|
149
215
|
observer.complete();
|
|
150
216
|
}).receive("timeout", () => {
|
|
217
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
218
|
+
if (state.hasJoined) return;
|
|
151
219
|
const error = /* @__PURE__ */ new Error("Timed out joining channel");
|
|
152
220
|
const errorEvent = {
|
|
153
221
|
type: _ag_ui_client.EventType.RUN_ERROR,
|
|
@@ -156,12 +224,12 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
156
224
|
};
|
|
157
225
|
observer.next(errorEvent);
|
|
158
226
|
state.currentEvents.push(errorEvent);
|
|
159
|
-
this.removeThread(threadId);
|
|
227
|
+
this.removeThread(threadId, state);
|
|
160
228
|
startupBoundary?.rejectStartup(error);
|
|
161
229
|
observer.complete();
|
|
162
230
|
});
|
|
163
231
|
return () => {
|
|
164
|
-
this.removeThread(threadId);
|
|
232
|
+
this.removeThread(threadId, state);
|
|
165
233
|
};
|
|
166
234
|
});
|
|
167
235
|
}
|
|
@@ -204,13 +272,14 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
204
272
|
} catch {}
|
|
205
273
|
return Promise.resolve(true);
|
|
206
274
|
}
|
|
207
|
-
executeAgentRun(request, state, threadId, onRunError) {
|
|
208
|
-
const { currentEvents
|
|
275
|
+
async executeAgentRun(request, state, threadId, onRunError) {
|
|
276
|
+
const { currentEvents } = state;
|
|
209
277
|
const pushCanonicalEvent = (event) => {
|
|
278
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
210
279
|
const canonicalEvent = this.stampRunnerMetadata(this.stampCanonicalRunOwnership(event, request), state);
|
|
211
280
|
currentEvents.push(canonicalEvent);
|
|
212
281
|
if (canonicalEvent.type === _ag_ui_client.EventType.RUN_STARTED) state.hasRunStarted = true;
|
|
213
|
-
|
|
282
|
+
this.queueRunnerEvent(this.createRunnerEventPayload(canonicalEvent, request, state), state);
|
|
214
283
|
};
|
|
215
284
|
const getPersistedInputMessages = () => request.persistedInputMessages ?? request.input.messages;
|
|
216
285
|
const buildRunStartedEvent = (source) => {
|
|
@@ -237,33 +306,212 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
237
306
|
pushCanonicalEvent(buildRunStartedEvent());
|
|
238
307
|
}
|
|
239
308
|
};
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
309
|
+
try {
|
|
310
|
+
await request.agent.runAgent(request.input, { onEvent: ({ event }) => {
|
|
311
|
+
if (event.type === _ag_ui_client.EventType.RUN_STARTED) {
|
|
312
|
+
pushCanonicalEvent(buildRunStartedEvent(event));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
ensureRunStarted();
|
|
316
|
+
pushCanonicalEvent(event);
|
|
317
|
+
} });
|
|
318
|
+
} catch (error) {
|
|
319
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
248
320
|
ensureRunStarted();
|
|
249
321
|
const existingError = currentEvents.find((event) => event.type === _ag_ui_client.EventType.RUN_ERROR);
|
|
250
|
-
if (existingError)
|
|
251
|
-
|
|
252
|
-
|
|
322
|
+
if (existingError) onRunError(existingError);
|
|
323
|
+
else {
|
|
324
|
+
const errorEvent = {
|
|
325
|
+
type: _ag_ui_client.EventType.RUN_ERROR,
|
|
326
|
+
message: error instanceof Error ? error.message : String(error)
|
|
327
|
+
};
|
|
328
|
+
pushCanonicalEvent(errorEvent);
|
|
329
|
+
onRunError(errorEvent);
|
|
253
330
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
message: error instanceof Error ? error.message : String(error)
|
|
257
|
-
};
|
|
258
|
-
pushCanonicalEvent(errorEvent);
|
|
259
|
-
onRunError(errorEvent);
|
|
260
|
-
return rxjs.EMPTY;
|
|
261
|
-
}), (0, rxjs_operators.finalize)(() => {
|
|
331
|
+
} finally {
|
|
332
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
262
333
|
ensureRunStarted();
|
|
263
334
|
const appended = (0, _copilotkit_shared.finalizeRunEvents)(currentEvents, { stopRequested: state.stopRequested });
|
|
264
|
-
for (const event of appended)
|
|
265
|
-
|
|
266
|
-
|
|
335
|
+
for (const event of appended) {
|
|
336
|
+
const canonicalEvent = this.stampRunnerMetadata(this.stampCanonicalRunOwnership(event, request), state);
|
|
337
|
+
this.queueRunnerEvent(this.createRunnerEventPayload(canonicalEvent, request, state), state);
|
|
338
|
+
}
|
|
339
|
+
state.producerFinished = true;
|
|
340
|
+
this.completeWhenDurable(threadId, state);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/** Queue one immutable event payload until Redis-backed gateway acknowledgement. */
|
|
344
|
+
queueRunnerEvent(payload, state) {
|
|
345
|
+
if (!this.isCurrentThreadState(state.threadId, state)) return;
|
|
346
|
+
const eventId = this.runnerEventId(payload);
|
|
347
|
+
if (!state.pendingEvents.has(eventId)) state.pendingEvents.set(eventId, {
|
|
348
|
+
payload: structuredClone(payload),
|
|
349
|
+
queuedAt: Date.now()
|
|
350
|
+
});
|
|
351
|
+
this.scheduleEventDeadline(state);
|
|
352
|
+
this.replayPendingEvents(state);
|
|
353
|
+
}
|
|
354
|
+
pushPendingEventBatch(eventIds, events, state) {
|
|
355
|
+
if (!this.isCurrentThreadState(state.threadId, state) || this.failIfEventDeadlineExceeded(state) || state.channel.state !== "joined" || !state.socket.isConnected()) return;
|
|
356
|
+
const attempt = ++state.nextEventPushAttempt;
|
|
357
|
+
state.activeEventBatch = {
|
|
358
|
+
eventIds,
|
|
359
|
+
attempt
|
|
360
|
+
};
|
|
361
|
+
const payloads = events.map((event) => event.payload);
|
|
362
|
+
const isBatch = state.supportsRunnerEventBatch;
|
|
363
|
+
state.channel.push(isBatch ? "events" : "event", isBatch ? { events: payloads } : payloads[0]).receive("ok", () => {
|
|
364
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.activeEventBatch?.attempt !== attempt) return;
|
|
365
|
+
if (this.failIfEventDeadlineExceeded(state)) return;
|
|
366
|
+
for (const eventId of eventIds) state.pendingEvents.delete(eventId);
|
|
367
|
+
state.activeEventBatch = null;
|
|
368
|
+
state.eventRetryAttempt = 0;
|
|
369
|
+
if (state.pendingEvents.size === 0) {
|
|
370
|
+
this.clearPendingEventRetry(state);
|
|
371
|
+
this.clearPendingEventFlush(state);
|
|
372
|
+
}
|
|
373
|
+
this.scheduleEventDeadline(state);
|
|
374
|
+
this.completeWhenDurable(state.threadId, state);
|
|
375
|
+
this.replayPendingEvents(state);
|
|
376
|
+
}).receive("error", (response) => this.handlePendingEventFailure(state, attempt, response)).receive("timeout", () => this.handlePendingEventFailure(state, attempt));
|
|
377
|
+
}
|
|
378
|
+
handlePendingEventFailure(state, attempt, response) {
|
|
379
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.activeEventBatch?.attempt !== attempt) return;
|
|
380
|
+
if (this.failIfEventDeadlineExceeded(state)) return;
|
|
381
|
+
if (this.isPermanentEventFailure(response)) {
|
|
382
|
+
const reason = typeof response === "object" && response !== null && typeof response.reason === "string" ? response.reason : "permanent_gateway_rejection";
|
|
383
|
+
this.failThread(state.threadId, state, /* @__PURE__ */ new Error(`Runner event durability failed: ${reason}`));
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.schedulePendingEventRetry(state);
|
|
387
|
+
}
|
|
388
|
+
schedulePendingEventRetry(state) {
|
|
389
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.pendingEvents.size === 0 || state.eventRetryTimer !== null) return;
|
|
390
|
+
const delay = Math.min(EVENT_RETRY_BASE_MS * 2 ** state.eventRetryAttempt, EVENT_RETRY_MAX_MS);
|
|
391
|
+
state.eventRetryAttempt += 1;
|
|
392
|
+
state.eventRetryTimer = setTimeout(() => {
|
|
393
|
+
state.eventRetryTimer = null;
|
|
394
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.pendingEvents.size === 0) return;
|
|
395
|
+
this.retryActiveEventBatch(state);
|
|
396
|
+
}, delay);
|
|
397
|
+
}
|
|
398
|
+
clearPendingEventRetry(state) {
|
|
399
|
+
if (state.eventRetryTimer !== null) {
|
|
400
|
+
clearTimeout(state.eventRetryTimer);
|
|
401
|
+
state.eventRetryTimer = null;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
schedulePendingEventFlush(state) {
|
|
405
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.pendingEvents.size === 0 || state.activeEventBatch !== null || state.eventFlushTimer !== null) return;
|
|
406
|
+
const oldestQueuedAt = Math.min(...[...state.pendingEvents.values()].map((event) => event.queuedAt));
|
|
407
|
+
const delay = Math.max(0, oldestQueuedAt + RUNNER_EVENT_BATCH_FLUSH_MS - Date.now());
|
|
408
|
+
state.eventFlushTimer = setTimeout(() => {
|
|
409
|
+
state.eventFlushTimer = null;
|
|
410
|
+
if (!this.isCurrentThreadState(state.threadId, state)) return;
|
|
411
|
+
this.flushPendingEventBatch(state);
|
|
412
|
+
}, delay);
|
|
413
|
+
}
|
|
414
|
+
clearPendingEventFlush(state) {
|
|
415
|
+
if (state.eventFlushTimer !== null) {
|
|
416
|
+
clearTimeout(state.eventFlushTimer);
|
|
417
|
+
state.eventFlushTimer = null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
resetPendingEventRetry(state) {
|
|
421
|
+
this.clearPendingEventRetry(state);
|
|
422
|
+
this.clearPendingEventFlush(state);
|
|
423
|
+
state.eventRetryAttempt = 0;
|
|
424
|
+
state.activeEventBatch = null;
|
|
425
|
+
}
|
|
426
|
+
replayPendingEvents(state) {
|
|
427
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.activeEventBatch !== null) return;
|
|
428
|
+
const pendingEvents = [...state.pendingEvents.entries()].sort(([, left], [, right]) => this.runnerEventSeq(left.payload) - this.runnerEventSeq(right.payload));
|
|
429
|
+
if (pendingEvents.length === 0) return;
|
|
430
|
+
const batchSize = state.supportsRunnerEventBatch ? MAX_RUNNER_EVENT_BATCH_SIZE : 1;
|
|
431
|
+
if (!state.supportsRunnerEventBatch || pendingEvents.length >= batchSize) {
|
|
432
|
+
this.clearPendingEventFlush(state);
|
|
433
|
+
const batch = pendingEvents.slice(0, batchSize);
|
|
434
|
+
this.pushPendingEventBatch(batch.map(([eventId]) => eventId), batch.map(([, event]) => event), state);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
this.schedulePendingEventFlush(state);
|
|
438
|
+
}
|
|
439
|
+
flushPendingEventBatch(state) {
|
|
440
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.activeEventBatch !== null || state.pendingEvents.size === 0) return;
|
|
441
|
+
const batch = [...state.pendingEvents.entries()].sort(([, left], [, right]) => this.runnerEventSeq(left.payload) - this.runnerEventSeq(right.payload)).slice(0, MAX_RUNNER_EVENT_BATCH_SIZE);
|
|
442
|
+
this.pushPendingEventBatch(batch.map(([eventId]) => eventId), batch.map(([, event]) => event), state);
|
|
443
|
+
}
|
|
444
|
+
retryActiveEventBatch(state) {
|
|
445
|
+
if (!this.isCurrentThreadState(state.threadId, state) || this.failIfEventDeadlineExceeded(state)) return;
|
|
446
|
+
const activeBatch = state.activeEventBatch;
|
|
447
|
+
if (activeBatch === null) {
|
|
448
|
+
this.replayPendingEvents(state);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const events = activeBatch.eventIds.map((eventId) => state.pendingEvents.get(eventId)).filter((event) => event !== void 0);
|
|
452
|
+
if (events.length !== activeBatch.eventIds.length) {
|
|
453
|
+
state.activeEventBatch = null;
|
|
454
|
+
this.replayPendingEvents(state);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
this.pushPendingEventBatch(activeBatch.eventIds, events, state);
|
|
458
|
+
}
|
|
459
|
+
completeWhenDurable(threadId, state) {
|
|
460
|
+
if (!this.isCurrentThreadState(threadId, state) || !state.producerFinished || state.pendingEvents.size !== 0) return;
|
|
461
|
+
if (this.threads.get(threadId) !== state) return;
|
|
462
|
+
this.removeThread(threadId, state);
|
|
463
|
+
state.completeRun();
|
|
464
|
+
}
|
|
465
|
+
runnerEventId(payload) {
|
|
466
|
+
return payload.metadata.cpki_event_id;
|
|
467
|
+
}
|
|
468
|
+
runnerEventSeq(payload) {
|
|
469
|
+
return payload.metadata.cpki_event_seq;
|
|
470
|
+
}
|
|
471
|
+
supportsRunnerEventBatch(response) {
|
|
472
|
+
if (typeof response !== "object" || response === null) return false;
|
|
473
|
+
const capabilities = response.capabilities;
|
|
474
|
+
return Array.isArray(capabilities) && capabilities.includes(RUNNER_EVENT_BATCH_CAPABILITY);
|
|
475
|
+
}
|
|
476
|
+
isRetryableJoinError(response) {
|
|
477
|
+
if (typeof response !== "object" || response === null) return false;
|
|
478
|
+
const value = response;
|
|
479
|
+
if (value.retryable === false) return false;
|
|
480
|
+
return value.retryable === true || value.reason === "gateway_draining";
|
|
481
|
+
}
|
|
482
|
+
isPermanentEventFailure(response) {
|
|
483
|
+
return typeof response === "object" && response !== null && response.retryable === false;
|
|
484
|
+
}
|
|
485
|
+
scheduleEventDeadline(state) {
|
|
486
|
+
if (state.eventDeadlineTimer !== null) {
|
|
487
|
+
clearTimeout(state.eventDeadlineTimer);
|
|
488
|
+
state.eventDeadlineTimer = null;
|
|
489
|
+
}
|
|
490
|
+
if (!this.isCurrentThreadState(state.threadId, state) || state.pendingEvents.size === 0) return;
|
|
491
|
+
const deadline = Math.min(...[...state.pendingEvents.values()].map((event) => event.queuedAt)) + EVENT_DURABILITY_DEADLINE_MS;
|
|
492
|
+
state.eventDeadlineTimer = setTimeout(() => {
|
|
493
|
+
state.eventDeadlineTimer = null;
|
|
494
|
+
if (!this.isCurrentThreadState(state.threadId, state)) return;
|
|
495
|
+
if (!this.failIfEventDeadlineExceeded(state)) this.scheduleEventDeadline(state);
|
|
496
|
+
}, Math.max(0, deadline - Date.now()));
|
|
497
|
+
}
|
|
498
|
+
failThread(threadId, state, error) {
|
|
499
|
+
if (!this.isCurrentThreadState(threadId, state)) return;
|
|
500
|
+
this.removeThread(threadId, state);
|
|
501
|
+
try {
|
|
502
|
+
state.agent?.abortRun();
|
|
503
|
+
} catch {}
|
|
504
|
+
state.failRun(error);
|
|
505
|
+
}
|
|
506
|
+
failIfEventDeadlineExceeded(state) {
|
|
507
|
+
if (state.pendingEvents.size === 0) return false;
|
|
508
|
+
const oldestQueuedAt = Math.min(...[...state.pendingEvents.values()].map((event) => event.queuedAt));
|
|
509
|
+
if (Date.now() < oldestQueuedAt + EVENT_DURABILITY_DEADLINE_MS) return false;
|
|
510
|
+
this.failThread(state.threadId, state, /* @__PURE__ */ new Error("Timed out trying to durably deliver runner events"));
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
isCurrentThreadState(threadId, state) {
|
|
514
|
+
return state.isRunning && this.threads.get(threadId) === state;
|
|
267
515
|
}
|
|
268
516
|
/**
|
|
269
517
|
* Tear down all resources for a thread: leave the channel,
|
|
@@ -272,10 +520,21 @@ var IntelligenceAgentRunner = class extends require_agent_runner.AgentRunner {
|
|
|
272
520
|
* Idempotent — safe to call multiple times for the same threadId
|
|
273
521
|
* (e.g. from join error handlers, finalize, and Observable teardown).
|
|
274
522
|
*/
|
|
275
|
-
removeThread(threadId) {
|
|
276
|
-
|
|
277
|
-
if (!state) return;
|
|
523
|
+
removeThread(threadId, state) {
|
|
524
|
+
if (this.threads.get(threadId) !== state) return;
|
|
278
525
|
this.threads.delete(threadId);
|
|
526
|
+
state.isRunning = false;
|
|
527
|
+
this.clearPendingEventRetry(state);
|
|
528
|
+
this.clearPendingEventFlush(state);
|
|
529
|
+
if (state.eventDeadlineTimer !== null) {
|
|
530
|
+
clearTimeout(state.eventDeadlineTimer);
|
|
531
|
+
state.eventDeadlineTimer = null;
|
|
532
|
+
}
|
|
533
|
+
state.activeEventBatch = null;
|
|
534
|
+
if (state.socketReconnectWatchdog !== null) {
|
|
535
|
+
clearTimeout(state.socketReconnectWatchdog);
|
|
536
|
+
state.socketReconnectWatchdog = null;
|
|
537
|
+
}
|
|
279
538
|
try {
|
|
280
539
|
state.channel.leave();
|
|
281
540
|
} catch {}
|