@copilotkit/runtime 1.61.1 → 1.61.2
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/aisdk.cjs +52 -1
- package/dist/agent/converters/aisdk.cjs.map +1 -1
- package/dist/agent/converters/aisdk.d.cts +6 -2
- package/dist/agent/converters/aisdk.d.cts.map +1 -1
- package/dist/agent/converters/aisdk.d.mts +6 -2
- package/dist/agent/converters/aisdk.d.mts.map +1 -1
- package/dist/agent/converters/aisdk.mjs +52 -1
- package/dist/agent/converters/aisdk.mjs.map +1 -1
- package/dist/agent/converters/tanstack.cjs +17 -1
- package/dist/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts +6 -2
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts +6 -2
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs +17 -1
- package/dist/agent/converters/tanstack.mjs.map +1 -1
- package/dist/agent/index.cjs +165 -39
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +42 -4
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts +42 -4
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +165 -40
- package/dist/agent/index.mjs.map +1 -1
- package/dist/graphql/message-conversion/agui-to-gql.cjs +5 -3
- package/dist/graphql/message-conversion/agui-to-gql.cjs.map +1 -1
- package/dist/graphql/message-conversion/agui-to-gql.mjs +5 -3
- package/dist/graphql/message-conversion/agui-to-gql.mjs.map +1 -1
- package/dist/lib/integrations/node-http/request-handler.cjs.map +1 -1
- package/dist/lib/integrations/node-http/request-handler.mjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- 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.map +1 -1
- package/dist/service-adapters/openai/utils.cjs.map +1 -1
- package/dist/service-adapters/openai/utils.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -0
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +3 -3
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +3 -3
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs.map +1 -1
- package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs.map +1 -1
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs +1 -1
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs.map +1 -1
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs +1 -1
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.cjs +4 -3
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/handle-run.mjs +4 -3
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +0 -2
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +0 -2
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +8 -4
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +8 -4
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.mjs","names":["pkg"],"sources":["../../../../src/v2/runtime/core/runtime.ts"],"sourcesContent":["import type {\n MaybePromise,\n NonEmptyRecord,\n RuntimeMode,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_MODE_SSE,\n RUNTIME_MODE_INTELLIGENCE,\n} from \"@copilotkit/shared\";\nimport { createLicenseChecker } from \"@copilotkit/license-verifier\";\nimport type { LicenseChecker } from \"@copilotkit/license-verifier\";\nimport { resolveDebugConfig } from \"@copilotkit/shared\";\nimport type { ResolvedDebugConfig, DebugConfig } from \"@copilotkit/shared\";\nimport type { AbstractAgent } from \"@ag-ui/client\";\nimport type { MCPClientConfig } from \"@ag-ui/mcp-apps-middleware\";\nimport type { A2UIMiddlewareConfig } from \"@ag-ui/a2ui-middleware\";\nimport pkg from \"../../../../package.json\";\nimport type {\n BeforeRequestMiddleware,\n AfterRequestMiddleware,\n} from \"./middleware\";\nimport { createLogger } from \"../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../lib/logger\";\nimport { logRuntimeTelemetryDisclosure } from \"../../../lib/telemetry-disclosure\";\nimport type { TranscriptionService } from \"../transcription-service/transcription-service\";\nimport { DebugEventBus } from \"./debug-event-bus\";\nimport type { AgentRunner } from \"../runner/agent-runner\";\nimport { InMemoryAgentRunner } from \"../runner/in-memory\";\nimport { IntelligenceAgentRunner } from \"../runner/intelligence\";\nimport type { CopilotKitIntelligence } from \"../intelligence-platform\";\nimport telemetry from \"../telemetry/telemetry-client\";\n\nexport const VERSION = pkg.version;\n\ninterface BaseCopilotRuntimeMiddlewareOptions {\n /** If set, middleware only applies to these named agents. Applies to all agents if omitted. */\n agents?: string[];\n}\n\nexport type McpAppsServerConfig = MCPClientConfig & {\n /** Agent to bind this server to. If omitted, the server is available to all agents. */\n agentId?: string;\n};\n\nexport interface McpAppsConfig {\n /** List of MCP server configurations. */\n servers: McpAppsServerConfig[];\n}\n\nexport interface OpenGenerativeUIOptions extends BaseCopilotRuntimeMiddlewareOptions {}\n\nexport type OpenGenerativeUIConfig = boolean | OpenGenerativeUIOptions;\n\ninterface CopilotRuntimeMiddlewares {\n /**\n * Auto-apply A2UIMiddleware to agents at run time.\n * Pass an object to enable and customise behaviour, or omit to disable.\n */\n a2ui?: BaseCopilotRuntimeMiddlewareOptions &\n A2UIMiddlewareConfig & {\n /**\n * Explicit on/off switch. Omit (or set `true`) to enable; set `false`\n * to disable A2UI for this runtime while keeping the rest of the config\n * (e.g. a `schema`/`catalog`) in place. A bare `a2ui: {}` stays enabled\n * for backwards compatibility.\n */\n enabled?: boolean;\n };\n /** Auto-apply MCPAppsMiddleware to agents at run time. */\n mcpApps?: McpAppsConfig;\n /** Auto-apply OpenGenerativeUIMiddleware to agents at run time. */\n openGenerativeUI?: OpenGenerativeUIConfig;\n}\n\n/**\n * Context passed to agent factory functions for per-request agent resolution.\n */\nexport interface AgentFactoryContext {\n /** The incoming HTTP request. */\n request: Request;\n}\n\n/**\n * A function that dynamically creates agents on a per-request basis.\n * Useful for multi-tenant scenarios or request-scoped agent configuration.\n */\nexport type AgentsFactory = (\n ctx: AgentFactoryContext,\n) => MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>;\n\n/**\n * Agents can be provided as:\n * - A static record of agents\n * - A Promise that resolves to a record of agents\n * - A factory function that receives request context and returns agents (or a Promise of agents)\n */\nexport type AgentsConfig =\n | MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>\n | AgentsFactory;\n\n/**\n * Resolve an AgentsConfig value to a concrete record of agents.\n * If the config is a factory function, it is called with the given request context.\n * Otherwise it is awaited directly (static record or Promise).\n */\nexport async function resolveAgents(\n agents: AgentsConfig,\n request?: Request,\n): Promise<Record<string, AbstractAgent>> {\n if (typeof agents === \"function\") {\n if (!request) {\n throw new Error(\n \"Agent factory function requires a request context, but none was provided.\",\n );\n }\n return agents({ request });\n }\n return agents;\n}\n\ninterface BaseCopilotRuntimeOptions extends CopilotRuntimeMiddlewares {\n /**\n * Map of available agents, or a factory function for per-request agent resolution.\n *\n * Static record:\n * ```ts\n * agents: { support: new SupportAgent(), technical: new TechnicalAgent() }\n * ```\n *\n * Factory function (called per-request):\n * ```ts\n * agents: ({ request }) => {\n * const tenantId = request.headers.get(\"x-tenant-id\");\n * return { default: createAgentForTenant(tenantId) };\n * }\n * ```\n */\n agents: AgentsConfig;\n /** Optional transcription service for audio processing. */\n transcriptionService?: TranscriptionService;\n /** Optional *before* middleware – callback function or webhook URL. */\n beforeRequestMiddleware?: BeforeRequestMiddleware;\n /** Optional *after* middleware – callback function or webhook URL. */\n afterRequestMiddleware?: AfterRequestMiddleware;\n /** Signed license token for server-side feature verification. Falls back to COPILOTKIT_LICENSE_TOKEN env var. */\n licenseToken?: string;\n /** Enable debug logging for the event pipeline. */\n debug?: DebugConfig;\n}\n\nexport interface CopilotRuntimeUser {\n id: string;\n name: string;\n}\n\nexport type IdentifyUserCallback = (\n request: Request,\n) => MaybePromise<CopilotRuntimeUser>;\n\nexport interface CopilotSseRuntimeOptions extends BaseCopilotRuntimeOptions {\n /** The runner to use for running agents in SSE mode. */\n runner?: AgentRunner;\n intelligence?: undefined;\n generateThreadNames?: undefined;\n}\n\nexport interface CopilotIntelligenceRuntimeOptions extends BaseCopilotRuntimeOptions {\n /** Configures Intelligence mode for durable threads and realtime events. */\n intelligence: CopilotKitIntelligence;\n /** Resolves the authenticated user for intelligence requests. */\n identifyUser: IdentifyUserCallback;\n /** Auto-generate short names for newly created threads. */\n generateThreadNames?: boolean;\n /** Max delay (ms) for WebSocket reconnect backoff. @default 10_000 */\n maxReconnectMs?: number;\n /** Max delay (ms) for channel rejoin backoff. @default 30_000 */\n maxRejoinMs?: number;\n /** Lock TTL in seconds. Clamped to a maximum of 3600 (1 hour). @default 20 */\n lockTtlSeconds?: number;\n /** Custom Redis key prefix for the thread lock. */\n lockKeyPrefix?: string;\n /** Interval in seconds at which the runtime renews the thread lock. Clamped to a maximum of 3000 (50 minutes). @default 15 */\n lockHeartbeatIntervalSeconds?: number;\n}\n\nexport type CopilotRuntimeOptions =\n | CopilotSseRuntimeOptions\n | CopilotIntelligenceRuntimeOptions;\n\nexport interface CopilotRuntimeLike {\n agents: CopilotRuntimeOptions[\"agents\"];\n transcriptionService: CopilotRuntimeOptions[\"transcriptionService\"];\n beforeRequestMiddleware: CopilotRuntimeOptions[\"beforeRequestMiddleware\"];\n afterRequestMiddleware: CopilotRuntimeOptions[\"afterRequestMiddleware\"];\n runner: AgentRunner;\n a2ui: CopilotRuntimeOptions[\"a2ui\"];\n mcpApps: CopilotRuntimeOptions[\"mcpApps\"];\n openGenerativeUI: CopilotRuntimeOptions[\"openGenerativeUI\"];\n intelligence?: CopilotKitIntelligence;\n identifyUser?: IdentifyUserCallback;\n mode: RuntimeMode;\n licenseChecker?: LicenseChecker;\n debugEventBus?: DebugEventBus;\n debug: ResolvedDebugConfig;\n debugLogger?: CopilotRuntimeLogger;\n}\n\nexport interface CopilotSseRuntimeLike extends CopilotRuntimeLike {\n intelligence?: undefined;\n mode: RUNTIME_MODE_SSE;\n}\n\nexport interface CopilotIntelligenceRuntimeLike extends CopilotRuntimeLike {\n intelligence: CopilotKitIntelligence;\n identifyUser: IdentifyUserCallback;\n generateThreadNames: boolean;\n lockTtlSeconds: number;\n lockKeyPrefix?: string;\n lockHeartbeatIntervalSeconds: number;\n mode: RUNTIME_MODE_INTELLIGENCE;\n}\n\nabstract class BaseCopilotRuntime implements CopilotRuntimeLike {\n public agents: CopilotRuntimeOptions[\"agents\"];\n public transcriptionService: CopilotRuntimeOptions[\"transcriptionService\"];\n public beforeRequestMiddleware: CopilotRuntimeOptions[\"beforeRequestMiddleware\"];\n public afterRequestMiddleware: CopilotRuntimeOptions[\"afterRequestMiddleware\"];\n public runner: AgentRunner;\n public a2ui: CopilotRuntimeOptions[\"a2ui\"];\n public mcpApps: CopilotRuntimeOptions[\"mcpApps\"];\n public openGenerativeUI: CopilotRuntimeOptions[\"openGenerativeUI\"];\n public licenseChecker?: LicenseChecker;\n public readonly debugEventBus?: DebugEventBus;\n public debug: ResolvedDebugConfig;\n public debugLogger?: CopilotRuntimeLogger;\n\n /**\n * License token resolved once with the env fallback, so telemetry\n * attribution (below) and subclass feature gating\n * (CopilotIntelligenceRuntime's licenseChecker) read the exact same value\n * instead of each re-applying `?? COPILOTKIT_LICENSE_TOKEN`.\n */\n protected readonly resolvedLicenseToken?: string;\n\n abstract readonly intelligence?: CopilotKitIntelligence;\n abstract readonly mode: RuntimeMode;\n\n constructor(options: BaseCopilotRuntimeOptions, runner: AgentRunner) {\n logRuntimeTelemetryDisclosure();\n\n const {\n agents,\n transcriptionService,\n beforeRequestMiddleware,\n afterRequestMiddleware,\n a2ui,\n mcpApps,\n openGenerativeUI,\n } = options;\n\n this.agents = agents;\n this.transcriptionService = transcriptionService;\n this.beforeRequestMiddleware = beforeRequestMiddleware;\n this.afterRequestMiddleware = afterRequestMiddleware;\n this.a2ui = a2ui || undefined;\n this.mcpApps = mcpApps;\n this.openGenerativeUI = openGenerativeUI;\n this.runner = runner;\n\n // Resolve the license token once (matching the license-verifier's env\n // fallback) so telemetry attribution and subclass feature gating share\n // one value.\n this.resolvedLicenseToken =\n options.licenseToken ?? process.env.COPILOTKIT_LICENSE_TOKEN;\n\n // Attribute telemetry to the licensed customer for *every* runtime mode.\n // Done in the shared base (not the subclasses) so SSE and Intelligence\n // runtimes behave identically — previously only CopilotIntelligenceRuntime\n // set this, so self-hosted SSE users never got a telemetry_id on their\n // runtime events even with a license token configured.\n if (this.resolvedLicenseToken) {\n telemetry.setLicenseToken(this.resolvedLicenseToken);\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n this.debugEventBus = new DebugEventBus();\n }\n this.debug = resolveDebugConfig(options.debug);\n if (this.debug.enabled) {\n this.debugLogger = createLogger({\n level: \"debug\",\n component: \"copilotkit-debug\",\n });\n }\n }\n}\n\nexport class CopilotSseRuntime\n extends BaseCopilotRuntime\n implements CopilotSseRuntimeLike\n{\n readonly intelligence = undefined;\n readonly mode = RUNTIME_MODE_SSE;\n\n constructor(options: CopilotSseRuntimeOptions) {\n super(options, options.runner ?? new InMemoryAgentRunner());\n }\n}\n\nexport class CopilotIntelligenceRuntime\n extends BaseCopilotRuntime\n implements CopilotIntelligenceRuntimeLike\n{\n readonly intelligence: CopilotKitIntelligence;\n readonly identifyUser: IdentifyUserCallback;\n readonly generateThreadNames: boolean;\n readonly lockTtlSeconds: number;\n readonly lockKeyPrefix?: string;\n readonly lockHeartbeatIntervalSeconds: number;\n readonly mode = RUNTIME_MODE_INTELLIGENCE;\n\n /** Maximum allowed lock TTL in seconds (1 hour). */\n static readonly MAX_LOCK_TTL_SECONDS = 3_600;\n /** Maximum allowed heartbeat interval in seconds (50 minutes). */\n static readonly MAX_HEARTBEAT_INTERVAL_SECONDS = 3_000;\n\n constructor(options: CopilotIntelligenceRuntimeOptions) {\n super(\n options,\n new IntelligenceAgentRunner({\n url: options.intelligence.ɵgetRunnerWsUrl(),\n authToken: options.intelligence.ɵgetRunnerAuthToken(),\n maxReconnectMs: options.maxReconnectMs,\n maxRejoinMs: options.maxRejoinMs,\n }),\n );\n this.intelligence = options.intelligence;\n this.identifyUser = options.identifyUser;\n this.generateThreadNames = options.generateThreadNames ?? true;\n // Telemetry attribution is handled by the base constructor for all modes;\n // here we only need the token for feature gating. Reuse the base-resolved\n // value so gating and attribution can never disagree.\n this.licenseChecker = createLicenseChecker(this.resolvedLicenseToken);\n this.lockTtlSeconds = Math.min(\n options.lockTtlSeconds ?? 20,\n CopilotIntelligenceRuntime.MAX_LOCK_TTL_SECONDS,\n );\n this.lockKeyPrefix = options.lockKeyPrefix;\n this.lockHeartbeatIntervalSeconds = Math.min(\n options.lockHeartbeatIntervalSeconds ?? 15,\n CopilotIntelligenceRuntime.MAX_HEARTBEAT_INTERVAL_SECONDS,\n );\n }\n}\n\nfunction hasIntelligenceOptions(\n options: CopilotRuntimeOptions,\n): options is CopilotIntelligenceRuntimeOptions {\n return \"intelligence\" in options && !!options.intelligence;\n}\n\nexport function isIntelligenceRuntime(\n runtime: CopilotRuntimeLike,\n): runtime is CopilotIntelligenceRuntimeLike {\n return runtime.mode === RUNTIME_MODE_INTELLIGENCE && !!runtime.intelligence;\n}\n\n/**\n * Single source of truth for \"is A2UI on for this runtime?\". Both the run path\n * (which applies `A2UIMiddleware`) and the `/info` response (which tells the\n * client whether to mount the A2UI renderer + catalog context) MUST go through\n * this, so they can never disagree — the divergence between them was the root\n * of CopilotKit/CopilotKit#5369.\n *\n * Backwards compatible: any config object is enabled (matching the historical\n * `!!runtime.a2ui`); only an explicit `enabled: false` turns it off.\n */\nexport function isA2UIEnabled(\n a2ui: CopilotRuntimeOptions[\"a2ui\"],\n): a2ui is NonNullable<CopilotRuntimeOptions[\"a2ui\"]> {\n return !!a2ui && a2ui.enabled !== false;\n}\n\n/**\n * Compatibility shim that preserves the legacy `CopilotRuntime` entrypoint.\n * New code should prefer `CopilotSseRuntime` or `CopilotIntelligenceRuntime`.\n */\nexport class CopilotRuntime implements CopilotRuntimeLike {\n private delegate: CopilotRuntimeLike;\n\n constructor(options: CopilotRuntimeOptions) {\n this.delegate = hasIntelligenceOptions(options)\n ? new CopilotIntelligenceRuntime(options)\n : new CopilotSseRuntime(options);\n }\n\n get agents(): CopilotRuntimeOptions[\"agents\"] {\n return this.delegate.agents;\n }\n\n get transcriptionService(): CopilotRuntimeOptions[\"transcriptionService\"] {\n return this.delegate.transcriptionService;\n }\n\n get beforeRequestMiddleware(): CopilotRuntimeOptions[\"beforeRequestMiddleware\"] {\n return this.delegate.beforeRequestMiddleware;\n }\n\n get afterRequestMiddleware(): CopilotRuntimeOptions[\"afterRequestMiddleware\"] {\n return this.delegate.afterRequestMiddleware;\n }\n\n get runner(): AgentRunner {\n return this.delegate.runner;\n }\n\n get a2ui(): CopilotRuntimeOptions[\"a2ui\"] {\n return this.delegate.a2ui;\n }\n\n get mcpApps(): CopilotRuntimeOptions[\"mcpApps\"] {\n return this.delegate.mcpApps;\n }\n\n get openGenerativeUI(): CopilotRuntimeOptions[\"openGenerativeUI\"] {\n return this.delegate.openGenerativeUI;\n }\n\n get intelligence(): CopilotKitIntelligence | undefined {\n return this.delegate.intelligence;\n }\n\n get generateThreadNames(): boolean | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.generateThreadNames\n : undefined;\n }\n\n get identifyUser(): IdentifyUserCallback | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.identifyUser\n : undefined;\n }\n\n get lockTtlSeconds(): number | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockTtlSeconds\n : undefined;\n }\n\n get lockKeyPrefix(): string | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockKeyPrefix\n : undefined;\n }\n\n get lockHeartbeatIntervalSeconds(): number | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockHeartbeatIntervalSeconds\n : undefined;\n }\n\n get mode(): RuntimeMode {\n return this.delegate.mode;\n }\n\n get licenseChecker() {\n return this.delegate.licenseChecker;\n }\n\n get debugEventBus() {\n return this.delegate.debugEventBus;\n }\n\n get debug(): ResolvedDebugConfig {\n return this.delegate.debug;\n }\n\n get debugLogger(): CopilotRuntimeLogger | undefined {\n return this.delegate.debugLogger;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runtime.mjs","names":["pkg"],"sources":["../../../../src/v2/runtime/core/runtime.ts"],"sourcesContent":["import type {\n MaybePromise,\n NonEmptyRecord,\n RuntimeMode,\n} from \"@copilotkit/shared\";\nimport {\n RUNTIME_MODE_SSE,\n RUNTIME_MODE_INTELLIGENCE,\n} from \"@copilotkit/shared\";\nimport { createLicenseChecker } from \"@copilotkit/license-verifier\";\nimport type { LicenseChecker } from \"@copilotkit/license-verifier\";\nimport { resolveDebugConfig } from \"@copilotkit/shared\";\nimport type { ResolvedDebugConfig, DebugConfig } from \"@copilotkit/shared\";\nimport type { AbstractAgent } from \"@ag-ui/client\";\nimport type { MCPClientConfig } from \"@ag-ui/mcp-apps-middleware\";\nimport type { A2UIMiddlewareConfig } from \"@ag-ui/a2ui-middleware\";\nimport pkg from \"../../../../package.json\";\nimport type {\n BeforeRequestMiddleware,\n AfterRequestMiddleware,\n} from \"./middleware\";\nimport { createLogger } from \"../../../lib/logger\";\nimport type { CopilotRuntimeLogger } from \"../../../lib/logger\";\nimport { logRuntimeTelemetryDisclosure } from \"../../../lib/telemetry-disclosure\";\nimport type { TranscriptionService } from \"../transcription-service/transcription-service\";\nimport { DebugEventBus } from \"./debug-event-bus\";\nimport type { AgentRunner } from \"../runner/agent-runner\";\nimport { InMemoryAgentRunner } from \"../runner/in-memory\";\nimport { IntelligenceAgentRunner } from \"../runner/intelligence\";\nimport type { CopilotKitIntelligence } from \"../intelligence-platform\";\nimport telemetry from \"../telemetry/telemetry-client\";\n\nexport const VERSION = pkg.version;\n\ninterface BaseCopilotRuntimeMiddlewareOptions {\n /** If set, middleware only applies to these named agents. Applies to all agents if omitted. */\n agents?: string[];\n}\n\nexport type McpAppsServerConfig = MCPClientConfig & {\n /** Agent to bind this server to. If omitted, the server is available to all agents. */\n agentId?: string;\n};\n\nexport interface McpAppsConfig {\n /** List of MCP server configurations. */\n servers: McpAppsServerConfig[];\n}\n\nexport interface OpenGenerativeUIOptions extends BaseCopilotRuntimeMiddlewareOptions {}\n\nexport type OpenGenerativeUIConfig = boolean | OpenGenerativeUIOptions;\n\ninterface CopilotRuntimeMiddlewares {\n /**\n * Auto-apply A2UIMiddleware to agents at run time.\n * Pass an object to enable and customise behaviour, or omit to disable.\n */\n a2ui?: BaseCopilotRuntimeMiddlewareOptions &\n A2UIMiddlewareConfig & {\n /**\n * Explicit on/off switch. Omit (or set `true`) to enable; set `false`\n * to disable A2UI for this runtime while keeping the rest of the config\n * (e.g. a `schema`/`catalog`) in place. A bare `a2ui: {}` stays enabled\n * for backwards compatibility.\n */\n enabled?: boolean;\n };\n /** Auto-apply MCPAppsMiddleware to agents at run time. */\n mcpApps?: McpAppsConfig;\n /** Auto-apply OpenGenerativeUIMiddleware to agents at run time. */\n openGenerativeUI?: OpenGenerativeUIConfig;\n}\n\n/**\n * Context passed to agent factory functions for per-request agent resolution.\n */\nexport interface AgentFactoryContext {\n /** The incoming HTTP request. */\n request: Request;\n}\n\n/**\n * A function that dynamically creates agents on a per-request basis.\n * Useful for multi-tenant scenarios or request-scoped agent configuration.\n */\nexport type AgentsFactory = (\n ctx: AgentFactoryContext,\n) => MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>;\n\n/**\n * Agents can be provided as:\n * - A static record of agents\n * - A Promise that resolves to a record of agents\n * - A factory function that receives request context and returns agents (or a Promise of agents)\n */\nexport type AgentsConfig =\n | MaybePromise<NonEmptyRecord<Record<string, AbstractAgent>>>\n | AgentsFactory;\n\n/**\n * Resolve an AgentsConfig value to a concrete record of agents.\n * If the config is a factory function, it is called with the given request context.\n * Otherwise it is awaited directly (static record or Promise).\n */\nexport async function resolveAgents(\n agents: AgentsConfig,\n request?: Request,\n): Promise<Record<string, AbstractAgent>> {\n if (typeof agents === \"function\") {\n if (!request) {\n throw new Error(\n \"Agent factory function requires a request context, but none was provided.\",\n );\n }\n return agents({ request });\n }\n return agents;\n}\n\ninterface BaseCopilotRuntimeOptions extends CopilotRuntimeMiddlewares {\n /**\n * Map of available agents, or a factory function for per-request agent resolution.\n *\n * Static record:\n * ```ts\n * agents: { support: new SupportAgent(), technical: new TechnicalAgent() }\n * ```\n *\n * Factory function (called per-request):\n * ```ts\n * agents: ({ request }) => {\n * const tenantId = request.headers.get(\"x-tenant-id\");\n * return { default: createAgentForTenant(tenantId) };\n * }\n * ```\n */\n agents: AgentsConfig;\n /** Optional transcription service for audio processing. */\n transcriptionService?: TranscriptionService;\n /** Optional *before* middleware – callback function or webhook URL. */\n beforeRequestMiddleware?: BeforeRequestMiddleware;\n /** Optional *after* middleware – callback function or webhook URL. */\n afterRequestMiddleware?: AfterRequestMiddleware;\n /** Signed license token for server-side feature verification. Falls back to COPILOTKIT_LICENSE_TOKEN env var. */\n licenseToken?: string;\n /** Enable debug logging for the event pipeline. */\n debug?: DebugConfig;\n}\n\nexport interface CopilotRuntimeUser {\n id: string;\n name: string;\n}\n\nexport type IdentifyUserCallback = (\n request: Request,\n) => MaybePromise<CopilotRuntimeUser>;\n\nexport interface CopilotSseRuntimeOptions extends BaseCopilotRuntimeOptions {\n /** The runner to use for running agents in SSE mode. */\n runner?: AgentRunner;\n intelligence?: undefined;\n generateThreadNames?: undefined;\n}\n\nexport interface CopilotIntelligenceRuntimeOptions extends BaseCopilotRuntimeOptions {\n /** Configures Intelligence mode for durable threads and realtime events. */\n intelligence: CopilotKitIntelligence;\n /** Resolves the authenticated user for intelligence requests. */\n identifyUser: IdentifyUserCallback;\n /** Auto-generate short names for newly created threads. */\n generateThreadNames?: boolean;\n /** Max delay (ms) for WebSocket reconnect backoff. @default 10_000 */\n maxReconnectMs?: number;\n /** Max delay (ms) for channel rejoin backoff. @default 30_000 */\n maxRejoinMs?: number;\n /** Lock TTL in seconds. Clamped to a maximum of 3600 (1 hour). @default 20 */\n lockTtlSeconds?: number;\n /** Custom Redis key prefix for the thread lock. */\n lockKeyPrefix?: string;\n /** Interval in seconds at which the runtime renews the thread lock. Clamped to a maximum of 3000 (50 minutes). @default 15 */\n lockHeartbeatIntervalSeconds?: number;\n}\n\nexport type CopilotRuntimeOptions =\n | CopilotSseRuntimeOptions\n | CopilotIntelligenceRuntimeOptions;\n\nexport interface CopilotRuntimeLike {\n agents: CopilotRuntimeOptions[\"agents\"];\n transcriptionService: CopilotRuntimeOptions[\"transcriptionService\"];\n beforeRequestMiddleware: CopilotRuntimeOptions[\"beforeRequestMiddleware\"];\n afterRequestMiddleware: CopilotRuntimeOptions[\"afterRequestMiddleware\"];\n runner: AgentRunner;\n a2ui: CopilotRuntimeOptions[\"a2ui\"];\n mcpApps: CopilotRuntimeOptions[\"mcpApps\"];\n openGenerativeUI: CopilotRuntimeOptions[\"openGenerativeUI\"];\n intelligence?: CopilotKitIntelligence;\n identifyUser?: IdentifyUserCallback;\n mode: RuntimeMode;\n licenseChecker?: LicenseChecker;\n debugEventBus?: DebugEventBus;\n debug: ResolvedDebugConfig;\n debugLogger?: CopilotRuntimeLogger;\n}\n\nexport interface CopilotSseRuntimeLike extends CopilotRuntimeLike {\n intelligence?: undefined;\n mode: typeof RUNTIME_MODE_SSE;\n}\n\nexport interface CopilotIntelligenceRuntimeLike extends CopilotRuntimeLike {\n intelligence: CopilotKitIntelligence;\n identifyUser: IdentifyUserCallback;\n generateThreadNames: boolean;\n lockTtlSeconds: number;\n lockKeyPrefix?: string;\n lockHeartbeatIntervalSeconds: number;\n mode: typeof RUNTIME_MODE_INTELLIGENCE;\n}\n\nabstract class BaseCopilotRuntime implements CopilotRuntimeLike {\n public agents: CopilotRuntimeOptions[\"agents\"];\n public transcriptionService: CopilotRuntimeOptions[\"transcriptionService\"];\n public beforeRequestMiddleware: CopilotRuntimeOptions[\"beforeRequestMiddleware\"];\n public afterRequestMiddleware: CopilotRuntimeOptions[\"afterRequestMiddleware\"];\n public runner: AgentRunner;\n public a2ui: CopilotRuntimeOptions[\"a2ui\"];\n public mcpApps: CopilotRuntimeOptions[\"mcpApps\"];\n public openGenerativeUI: CopilotRuntimeOptions[\"openGenerativeUI\"];\n public licenseChecker?: LicenseChecker;\n public readonly debugEventBus?: DebugEventBus;\n public debug: ResolvedDebugConfig;\n public debugLogger?: CopilotRuntimeLogger;\n\n /**\n * License token resolved once with the env fallback, so telemetry\n * attribution (below) and subclass feature gating\n * (CopilotIntelligenceRuntime's licenseChecker) read the exact same value\n * instead of each re-applying `?? COPILOTKIT_LICENSE_TOKEN`.\n */\n protected readonly resolvedLicenseToken?: string;\n\n abstract readonly intelligence?: CopilotKitIntelligence;\n abstract readonly mode: RuntimeMode;\n\n constructor(options: BaseCopilotRuntimeOptions, runner: AgentRunner) {\n logRuntimeTelemetryDisclosure();\n\n const {\n agents,\n transcriptionService,\n beforeRequestMiddleware,\n afterRequestMiddleware,\n a2ui,\n mcpApps,\n openGenerativeUI,\n } = options;\n\n this.agents = agents;\n this.transcriptionService = transcriptionService;\n this.beforeRequestMiddleware = beforeRequestMiddleware;\n this.afterRequestMiddleware = afterRequestMiddleware;\n this.a2ui = a2ui || undefined;\n this.mcpApps = mcpApps;\n this.openGenerativeUI = openGenerativeUI;\n this.runner = runner;\n\n // Resolve the license token once (matching the license-verifier's env\n // fallback) so telemetry attribution and subclass feature gating share\n // one value.\n this.resolvedLicenseToken =\n options.licenseToken ?? process.env.COPILOTKIT_LICENSE_TOKEN;\n\n // Attribute telemetry to the licensed customer for *every* runtime mode.\n // Done in the shared base (not the subclasses) so SSE and Intelligence\n // runtimes behave identically — previously only CopilotIntelligenceRuntime\n // set this, so self-hosted SSE users never got a telemetry_id on their\n // runtime events even with a license token configured.\n if (this.resolvedLicenseToken) {\n telemetry.setLicenseToken(this.resolvedLicenseToken);\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n this.debugEventBus = new DebugEventBus();\n }\n this.debug = resolveDebugConfig(options.debug);\n if (this.debug.enabled) {\n this.debugLogger = createLogger({\n level: \"debug\",\n component: \"copilotkit-debug\",\n });\n }\n }\n}\n\nexport class CopilotSseRuntime\n extends BaseCopilotRuntime\n implements CopilotSseRuntimeLike\n{\n readonly intelligence = undefined;\n readonly mode = RUNTIME_MODE_SSE;\n\n constructor(options: CopilotSseRuntimeOptions) {\n super(options, options.runner ?? new InMemoryAgentRunner());\n }\n}\n\nexport class CopilotIntelligenceRuntime\n extends BaseCopilotRuntime\n implements CopilotIntelligenceRuntimeLike\n{\n readonly intelligence: CopilotKitIntelligence;\n readonly identifyUser: IdentifyUserCallback;\n readonly generateThreadNames: boolean;\n readonly lockTtlSeconds: number;\n readonly lockKeyPrefix?: string;\n readonly lockHeartbeatIntervalSeconds: number;\n readonly mode = RUNTIME_MODE_INTELLIGENCE;\n\n /** Maximum allowed lock TTL in seconds (1 hour). */\n static readonly MAX_LOCK_TTL_SECONDS = 3_600;\n /** Maximum allowed heartbeat interval in seconds (50 minutes). */\n static readonly MAX_HEARTBEAT_INTERVAL_SECONDS = 3_000;\n\n constructor(options: CopilotIntelligenceRuntimeOptions) {\n super(\n options,\n new IntelligenceAgentRunner({\n url: options.intelligence.ɵgetRunnerWsUrl(),\n authToken: options.intelligence.ɵgetRunnerAuthToken(),\n maxReconnectMs: options.maxReconnectMs,\n maxRejoinMs: options.maxRejoinMs,\n }),\n );\n this.intelligence = options.intelligence;\n this.identifyUser = options.identifyUser;\n this.generateThreadNames = options.generateThreadNames ?? true;\n // Telemetry attribution is handled by the base constructor for all modes;\n // here we only need the token for feature gating. Reuse the base-resolved\n // value so gating and attribution can never disagree.\n this.licenseChecker = createLicenseChecker(this.resolvedLicenseToken);\n this.lockTtlSeconds = Math.min(\n options.lockTtlSeconds ?? 20,\n CopilotIntelligenceRuntime.MAX_LOCK_TTL_SECONDS,\n );\n this.lockKeyPrefix = options.lockKeyPrefix;\n this.lockHeartbeatIntervalSeconds = Math.min(\n options.lockHeartbeatIntervalSeconds ?? 15,\n CopilotIntelligenceRuntime.MAX_HEARTBEAT_INTERVAL_SECONDS,\n );\n }\n}\n\nfunction hasIntelligenceOptions(\n options: CopilotRuntimeOptions,\n): options is CopilotIntelligenceRuntimeOptions {\n return \"intelligence\" in options && !!options.intelligence;\n}\n\nexport function isIntelligenceRuntime(\n runtime: CopilotRuntimeLike,\n): runtime is CopilotIntelligenceRuntimeLike {\n return runtime.mode === RUNTIME_MODE_INTELLIGENCE && !!runtime.intelligence;\n}\n\n/**\n * Single source of truth for \"is A2UI on for this runtime?\". Both the run path\n * (which applies `A2UIMiddleware`) and the `/info` response (which tells the\n * client whether to mount the A2UI renderer + catalog context) MUST go through\n * this, so they can never disagree — the divergence between them was the root\n * of CopilotKit/CopilotKit#5369.\n *\n * Backwards compatible: any config object is enabled (matching the historical\n * `!!runtime.a2ui`); only an explicit `enabled: false` turns it off.\n */\nexport function isA2UIEnabled(\n a2ui: CopilotRuntimeOptions[\"a2ui\"],\n): a2ui is NonNullable<CopilotRuntimeOptions[\"a2ui\"]> {\n return !!a2ui && a2ui.enabled !== false;\n}\n\n/**\n * Compatibility shim that preserves the legacy `CopilotRuntime` entrypoint.\n * New code should prefer `CopilotSseRuntime` or `CopilotIntelligenceRuntime`.\n */\nexport class CopilotRuntime implements CopilotRuntimeLike {\n private delegate: CopilotRuntimeLike;\n\n constructor(options: CopilotRuntimeOptions) {\n this.delegate = hasIntelligenceOptions(options)\n ? new CopilotIntelligenceRuntime(options)\n : new CopilotSseRuntime(options);\n }\n\n get agents(): CopilotRuntimeOptions[\"agents\"] {\n return this.delegate.agents;\n }\n\n get transcriptionService(): CopilotRuntimeOptions[\"transcriptionService\"] {\n return this.delegate.transcriptionService;\n }\n\n get beforeRequestMiddleware(): CopilotRuntimeOptions[\"beforeRequestMiddleware\"] {\n return this.delegate.beforeRequestMiddleware;\n }\n\n get afterRequestMiddleware(): CopilotRuntimeOptions[\"afterRequestMiddleware\"] {\n return this.delegate.afterRequestMiddleware;\n }\n\n get runner(): AgentRunner {\n return this.delegate.runner;\n }\n\n get a2ui(): CopilotRuntimeOptions[\"a2ui\"] {\n return this.delegate.a2ui;\n }\n\n get mcpApps(): CopilotRuntimeOptions[\"mcpApps\"] {\n return this.delegate.mcpApps;\n }\n\n get openGenerativeUI(): CopilotRuntimeOptions[\"openGenerativeUI\"] {\n return this.delegate.openGenerativeUI;\n }\n\n get intelligence(): CopilotKitIntelligence | undefined {\n return this.delegate.intelligence;\n }\n\n get generateThreadNames(): boolean | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.generateThreadNames\n : undefined;\n }\n\n get identifyUser(): IdentifyUserCallback | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.identifyUser\n : undefined;\n }\n\n get lockTtlSeconds(): number | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockTtlSeconds\n : undefined;\n }\n\n get lockKeyPrefix(): string | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockKeyPrefix\n : undefined;\n }\n\n get lockHeartbeatIntervalSeconds(): number | undefined {\n return isIntelligenceRuntime(this.delegate)\n ? this.delegate.lockHeartbeatIntervalSeconds\n : undefined;\n }\n\n get mode(): RuntimeMode {\n return this.delegate.mode;\n }\n\n get licenseChecker() {\n return this.delegate.licenseChecker;\n }\n\n get debugEventBus() {\n return this.delegate.debugEventBus;\n }\n\n get debug(): ResolvedDebugConfig {\n return this.delegate.debug;\n }\n\n get debugLogger(): CopilotRuntimeLogger | undefined {\n return this.delegate.debugLogger;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express-fetch-bridge.cjs","names":["createCopilotNodeHandler"],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Check if the stream has already been consumed.\n const state = (req as any)._readableState;\n return Boolean(\n req.readableEnded || req.complete || state?.ended || state?.endEmitted,\n );\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n return { body };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAcA,oDAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,wDAAmB,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,6BAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;CAGxD,MAAM,QAAS,IAAY;AAC3B,QAAO,QACL,IAAI,iBAAiB,IAAI,YAAY,OAAO,SAAS,OAAO,WAC7D;;AAGH,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"express-fetch-bridge.cjs","names":["createCopilotNodeHandler"],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Check if the stream has already been consumed.\n const state = (req as any)._readableState;\n return Boolean(\n req.readableEnded || req.complete || state?.ended || state?.endEmitted,\n );\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n // Buffer/Uint8Array<ArrayBufferLike> are valid fetch bodies at runtime,\n // but the DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return { body: body as BodyInit };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAcA,oDAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,wDAAmB,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,6BAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;CAGxD,MAAM,QAAS,IAAY;AAC3B,QAAO,QACL,IAAI,iBAAiB,IAAI,YAAY,OAAO,SAAS,OAAO,WAC7D;;AAGH,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,WAG3C,QAAO,EAAQ,MAAkB;AAEnC,KAAI,OAAO,SAAS,SAClB,QAAO,EAAE,MAAM;AAEjB,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;EAAE,MAAM,KAAK,UAAU,KAAK;EAAE,aAAa;EAAoB;AAExE,QAAO,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express-fetch-bridge.mjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Check if the stream has already been consumed.\n const state = (req as any)._readableState;\n return Boolean(\n req.readableEnded || req.complete || state?.ended || state?.endEmitted,\n );\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n return { body };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAc,yBAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,SAAM,aAAa,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,UAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;CAGxD,MAAM,QAAS,IAAY;AAC3B,QAAO,QACL,IAAI,iBAAiB,IAAI,YAAY,OAAO,SAAS,OAAO,WAC7D;;AAGH,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"express-fetch-bridge.mjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/express-fetch-bridge.ts"],"sourcesContent":["/**\n * Express-aware Node ↔ Fetch bridge.\n *\n * When Express body-parsing middleware (e.g. `express.json()`) runs before the\n * CopilotKit router, the Node request stream is already consumed and `req.body`\n * holds the parsed content. The generic `createCopilotNodeHandler` (which uses\n * `@remix-run/node-fetch-server`) would hang because it tries to read from the\n * exhausted stream.\n *\n * This module detects the pre-parsed case and re-serialises `req.body` into the\n * Fetch `Request`, falling back to the generic `createCopilotNodeHandler` when the\n * stream is still available.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { sendResponse } from \"@remix-run/node-fetch-server\";\nimport { createCopilotNodeHandler } from \"./node-fetch-handler\";\nimport type { CopilotRuntimeFetchHandler } from \"../core/fetch-handler\";\nimport { logger } from \"@copilotkit/shared\";\n\nconst METHODS_WITHOUT_BODY = new Set([\"GET\", \"HEAD\", \"OPTIONS\"]);\n\nexport type ExpressNodeHandler = (\n req: IncomingMessage,\n res: ServerResponse,\n) => Promise<void>;\n\n/**\n * Creates a Node HTTP handler from a fetch handler, with Express body-parser\n * compatibility. Use this instead of `createNodeFetchHandler` in Express adapters.\n *\n * When the body stream hasn't been consumed, delegates to the generic\n * `createCopilotNodeHandler`. Only intercepts when Express middleware has\n * pre-parsed the body.\n */\nexport function createExpressNodeHandler(\n handler: CopilotRuntimeFetchHandler,\n): ExpressNodeHandler {\n const nodeHandler = createCopilotNodeHandler(handler);\n\n return async (req: IncomingMessage, res: ServerResponse) => {\n const method = (req.method ?? \"GET\").toUpperCase();\n\n // Fast path: if no body parser consumed the stream, use the generic handler.\n if (METHODS_WITHOUT_BODY.has(method) || !hasPreParsedBody(req)) {\n return nodeHandler(req, res);\n }\n\n // Slow path: body was consumed by Express middleware — rebuild the Request.\n try {\n const fetchReq = buildPreParsedRequest(req, res);\n const fetchRes = await handler(fetchReq);\n await sendResponse(res, fetchRes);\n } catch (err: unknown) {\n logger.error({ err }, \"Error in Express fetch bridge (pre-parsed path)\");\n if (!res.headersSent) {\n res.statusCode = 500;\n res.end(\"Internal Server Error\");\n }\n }\n };\n}\n\n/**\n * Build a Fetch Request from a Node IncomingMessage whose body stream has\n * already been consumed by an Express body parser.\n */\nfunction buildPreParsedRequest(\n req: IncomingMessage,\n res: ServerResponse,\n): Request {\n const expressReq = req as IncomingMessage & { body?: unknown };\n const method = (req.method ?? \"GET\").toUpperCase();\n\n const protocol = (req as any).protocol || \"http\";\n const host = req.headers.host ?? \"localhost\";\n const url = `${protocol}://${host}${(req as any).originalUrl ?? req.url ?? \"\"}`;\n\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n\n // Wire an AbortSignal so client disconnects propagate to the fetch handler\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n\n const init: RequestInit & { duplex?: \"half\" } = {\n method,\n headers,\n signal: controller.signal,\n };\n\n const { body, contentType } = synthesizeBody(expressReq.body);\n if (contentType) {\n headers.set(\"content-type\", contentType);\n }\n headers.delete(\"content-length\");\n if (body !== undefined) {\n init.body = body;\n }\n\n return new Request(url, init);\n}\n\nfunction hasPreParsedBody(req: IncomingMessage & { body?: unknown }): boolean {\n if (req.body === undefined || req.body === null) return false;\n\n // Check if the stream has already been consumed.\n const state = (req as any)._readableState;\n return Boolean(\n req.readableEnded || req.complete || state?.ended || state?.endEmitted,\n );\n}\n\nfunction synthesizeBody(body: unknown): {\n body?: BodyInit;\n contentType?: string;\n} {\n if (Buffer.isBuffer(body) || body instanceof Uint8Array) {\n // Buffer/Uint8Array<ArrayBufferLike> are valid fetch bodies at runtime,\n // but the DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return { body: body as BodyInit };\n }\n if (typeof body === \"string\") {\n return { body };\n }\n if (typeof body === \"object\" && body !== null) {\n return { body: JSON.stringify(body), contentType: \"application/json\" };\n }\n return {};\n}\n"],"mappings":";;;;;;AAoBA,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAU,CAAC;;;;;;;;;AAehE,SAAgB,yBACd,SACoB;CACpB,MAAM,cAAc,yBAAyB,QAAQ;AAErD,QAAO,OAAO,KAAsB,QAAwB;EAC1D,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;AAGlD,MAAI,qBAAqB,IAAI,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAC5D,QAAO,YAAY,KAAK,IAAI;AAI9B,MAAI;AAGF,SAAM,aAAa,KADF,MAAM,QADN,sBAAsB,KAAK,IAAI,CACR,CACP;WAC1B,KAAc;AACrB,UAAO,MAAM,EAAE,KAAK,EAAE,kDAAkD;AACxE,OAAI,CAAC,IAAI,aAAa;AACpB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;;;;;;;;;AAUxC,SAAS,sBACP,KACA,KACS;CACT,MAAM,aAAa;CACnB,MAAM,UAAU,IAAI,UAAU,OAAO,aAAa;CAIlD,MAAM,MAAM,GAFM,IAAY,YAAY,OAElB,KADX,IAAI,QAAQ,QAAQ,cACI,IAAY,eAAe,IAAI,OAAO;CAE3E,MAAM,UAAU,IAAI,SAAS;AAC7B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,QAAQ,EAAE;AACtD,MAAI,UAAU,OAAW;AACzB,MAAI,MAAM,QAAQ,MAAM,CACtB,MAAK,MAAM,KAAK,MAAO,SAAQ,OAAO,KAAK,EAAE;MAE7C,SAAQ,IAAI,KAAK,MAAM;;CAK3B,MAAM,aAAa,IAAI,iBAAiB;AACxC,KAAI,GAAG,eAAe;AACpB,MAAI,CAAC,IAAI,iBAAkB,YAAW,OAAO;GAC7C;CAEF,MAAM,OAA0C;EAC9C;EACA;EACA,QAAQ,WAAW;EACpB;CAED,MAAM,EAAE,MAAM,gBAAgB,eAAe,WAAW,KAAK;AAC7D,KAAI,YACF,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,SAAQ,OAAO,iBAAiB;AAChC,KAAI,SAAS,OACX,MAAK,OAAO;AAGd,QAAO,IAAI,QAAQ,KAAK,KAAK;;AAG/B,SAAS,iBAAiB,KAAoD;AAC5E,KAAI,IAAI,SAAS,UAAa,IAAI,SAAS,KAAM,QAAO;CAGxD,MAAM,QAAS,IAAY;AAC3B,QAAO,QACL,IAAI,iBAAiB,IAAI,YAAY,OAAO,SAAS,OAAO,WAC7D;;AAGH,SAAS,eAAe,MAGtB;AACA,KAAI,OAAO,SAAS,KAAK,IAAI,gBAAgB,WAG3C,QAAO,EAAQ,MAAkB;AAEnC,KAAI,OAAO,SAAS,SAClB,QAAO,EAAE,MAAM;AAEjB,KAAI,OAAO,SAAS,YAAY,SAAS,KACvC,QAAO;EAAE,MAAM,KAAK,UAAU,KAAK;EAAE,aAAa;EAAoB;AAExE,QAAO,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-route-helpers.cjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/single-route-helpers.ts"],"sourcesContent":["const METHOD_NAMES = [\n \"agent/run\",\n \"agent/connect\",\n \"agent/stop\",\n \"info\",\n \"transcribe\",\n] as const;\n\nexport type EndpointMethod = (typeof METHOD_NAMES)[number];\n\ninterface JsonEnvelope {\n method?: string;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport interface MethodCall {\n method: EndpointMethod;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport async function parseMethodCall(request: Request): Promise<MethodCall> {\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"application/json\")) {\n throw createResponseError(\n \"Single-route endpoint expects JSON payloads\",\n 415,\n );\n }\n\n let jsonEnvelope: JsonEnvelope;\n try {\n jsonEnvelope = (await request.clone().json()) as JsonEnvelope;\n } catch
|
|
1
|
+
{"version":3,"file":"single-route-helpers.cjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/single-route-helpers.ts"],"sourcesContent":["const METHOD_NAMES = [\n \"agent/run\",\n \"agent/connect\",\n \"agent/stop\",\n \"info\",\n \"transcribe\",\n] as const;\n\nexport type EndpointMethod = (typeof METHOD_NAMES)[number];\n\ninterface JsonEnvelope {\n method?: string;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport interface MethodCall {\n method: EndpointMethod;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport async function parseMethodCall(request: Request): Promise<MethodCall> {\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"application/json\")) {\n throw createResponseError(\n \"Single-route endpoint expects JSON payloads\",\n 415,\n );\n }\n\n let jsonEnvelope: JsonEnvelope;\n try {\n jsonEnvelope = (await request.clone().json()) as JsonEnvelope;\n } catch {\n throw createResponseError(\"Invalid JSON payload\", 400);\n }\n\n const method = validateMethod(jsonEnvelope.method);\n\n return {\n method,\n params: jsonEnvelope.params,\n body: jsonEnvelope.body,\n };\n}\n\nexport function expectString(\n params: Record<string, unknown> | undefined,\n key: string,\n): string {\n const value = params?.[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n\n throw createResponseError(`Missing or invalid parameter '${key}'`, 400);\n}\n\nexport function createJsonRequest(base: Request, body: unknown): Request {\n if (body === undefined || body === null) {\n throw createResponseError(\"Missing request body for JSON handler\", 400);\n }\n\n const headers = new Headers(base.headers);\n headers.set(\"content-type\", \"application/json\");\n headers.delete(\"content-length\");\n\n const serializedBody = serializeJsonBody(body);\n\n return new Request(base.url, {\n method: \"POST\",\n headers,\n body: serializedBody,\n signal: base.signal,\n });\n}\n\nexport function createResponseError(message: string, status: number): Response {\n return new Response(\n JSON.stringify({\n error: \"invalid_request\",\n message,\n }),\n {\n status,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n },\n );\n}\n\nfunction validateMethod(method: string | undefined): EndpointMethod {\n if (!method) {\n throw createResponseError(\"Missing method field\", 400);\n }\n\n if ((METHOD_NAMES as readonly string[]).includes(method)) {\n return method as EndpointMethod;\n }\n\n throw createResponseError(`Unsupported method '${method}'`, 400);\n}\n\nfunction serializeJsonBody(body: unknown): BodyInit {\n if (typeof body === \"string\") {\n return body;\n }\n\n if (\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof Uint8Array\n ) {\n // Uint8Array<ArrayBufferLike> is a valid fetch body at runtime, but the\n // DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return body as BodyInit;\n }\n\n if (body instanceof FormData || body instanceof URLSearchParams) {\n return body;\n }\n\n return JSON.stringify(body);\n}\n"],"mappings":";;;AAAA,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACD;AAgBD,eAAsB,gBAAgB,SAAuC;AAG3E,KAAI,EAFgB,QAAQ,QAAQ,IAAI,eAAe,IAAI,IAE1C,SAAS,mBAAmB,CAC3C,OAAM,oBACJ,+CACA,IACD;CAGH,IAAI;AACJ,KAAI;AACF,iBAAgB,MAAM,QAAQ,OAAO,CAAC,MAAM;SACtC;AACN,QAAM,oBAAoB,wBAAwB,IAAI;;AAKxD,QAAO;EACL,QAHa,eAAe,aAAa,OAAO;EAIhD,QAAQ,aAAa;EACrB,MAAM,aAAa;EACpB;;AAGH,SAAgB,aACd,QACA,KACQ;CACR,MAAM,QAAQ,SAAS;AACvB,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACrD,QAAO;AAGT,OAAM,oBAAoB,iCAAiC,IAAI,IAAI,IAAI;;AAGzE,SAAgB,kBAAkB,MAAe,MAAwB;AACvE,KAAI,SAAS,UAAa,SAAS,KACjC,OAAM,oBAAoB,yCAAyC,IAAI;CAGzE,MAAM,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACzC,SAAQ,IAAI,gBAAgB,mBAAmB;AAC/C,SAAQ,OAAO,iBAAiB;CAEhC,MAAM,iBAAiB,kBAAkB,KAAK;AAE9C,QAAO,IAAI,QAAQ,KAAK,KAAK;EAC3B,QAAQ;EACR;EACA,MAAM;EACN,QAAQ,KAAK;EACd,CAAC;;AAGJ,SAAgB,oBAAoB,SAAiB,QAA0B;AAC7E,QAAO,IAAI,SACT,KAAK,UAAU;EACb,OAAO;EACP;EACD,CAAC,EACF;EACE;EACA,SAAS,EACP,gBAAgB,oBACjB;EACF,CACF;;AAGH,SAAS,eAAe,QAA4C;AAClE,KAAI,CAAC,OACH,OAAM,oBAAoB,wBAAwB,IAAI;AAGxD,KAAK,aAAmC,SAAS,OAAO,CACtD,QAAO;AAGT,OAAM,oBAAoB,uBAAuB,OAAO,IAAI,IAAI;;AAGlE,SAAS,kBAAkB,MAAyB;AAClD,KAAI,OAAO,SAAS,SAClB,QAAO;AAGT,KACE,gBAAgB,QAChB,gBAAgB,eAChB,gBAAgB,WAIhB,QAAO;AAGT,KAAI,gBAAgB,YAAY,gBAAgB,gBAC9C,QAAO;AAGT,QAAO,KAAK,UAAU,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"single-route-helpers.mjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/single-route-helpers.ts"],"sourcesContent":["const METHOD_NAMES = [\n \"agent/run\",\n \"agent/connect\",\n \"agent/stop\",\n \"info\",\n \"transcribe\",\n] as const;\n\nexport type EndpointMethod = (typeof METHOD_NAMES)[number];\n\ninterface JsonEnvelope {\n method?: string;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport interface MethodCall {\n method: EndpointMethod;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport async function parseMethodCall(request: Request): Promise<MethodCall> {\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"application/json\")) {\n throw createResponseError(\n \"Single-route endpoint expects JSON payloads\",\n 415,\n );\n }\n\n let jsonEnvelope: JsonEnvelope;\n try {\n jsonEnvelope = (await request.clone().json()) as JsonEnvelope;\n } catch
|
|
1
|
+
{"version":3,"file":"single-route-helpers.mjs","names":[],"sources":["../../../../src/v2/runtime/endpoints/single-route-helpers.ts"],"sourcesContent":["const METHOD_NAMES = [\n \"agent/run\",\n \"agent/connect\",\n \"agent/stop\",\n \"info\",\n \"transcribe\",\n] as const;\n\nexport type EndpointMethod = (typeof METHOD_NAMES)[number];\n\ninterface JsonEnvelope {\n method?: string;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport interface MethodCall {\n method: EndpointMethod;\n params?: Record<string, unknown>;\n body?: unknown;\n}\n\nexport async function parseMethodCall(request: Request): Promise<MethodCall> {\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n if (!contentType.includes(\"application/json\")) {\n throw createResponseError(\n \"Single-route endpoint expects JSON payloads\",\n 415,\n );\n }\n\n let jsonEnvelope: JsonEnvelope;\n try {\n jsonEnvelope = (await request.clone().json()) as JsonEnvelope;\n } catch {\n throw createResponseError(\"Invalid JSON payload\", 400);\n }\n\n const method = validateMethod(jsonEnvelope.method);\n\n return {\n method,\n params: jsonEnvelope.params,\n body: jsonEnvelope.body,\n };\n}\n\nexport function expectString(\n params: Record<string, unknown> | undefined,\n key: string,\n): string {\n const value = params?.[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n\n throw createResponseError(`Missing or invalid parameter '${key}'`, 400);\n}\n\nexport function createJsonRequest(base: Request, body: unknown): Request {\n if (body === undefined || body === null) {\n throw createResponseError(\"Missing request body for JSON handler\", 400);\n }\n\n const headers = new Headers(base.headers);\n headers.set(\"content-type\", \"application/json\");\n headers.delete(\"content-length\");\n\n const serializedBody = serializeJsonBody(body);\n\n return new Request(base.url, {\n method: \"POST\",\n headers,\n body: serializedBody,\n signal: base.signal,\n });\n}\n\nexport function createResponseError(message: string, status: number): Response {\n return new Response(\n JSON.stringify({\n error: \"invalid_request\",\n message,\n }),\n {\n status,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n },\n );\n}\n\nfunction validateMethod(method: string | undefined): EndpointMethod {\n if (!method) {\n throw createResponseError(\"Missing method field\", 400);\n }\n\n if ((METHOD_NAMES as readonly string[]).includes(method)) {\n return method as EndpointMethod;\n }\n\n throw createResponseError(`Unsupported method '${method}'`, 400);\n}\n\nfunction serializeJsonBody(body: unknown): BodyInit {\n if (typeof body === \"string\") {\n return body;\n }\n\n if (\n body instanceof Blob ||\n body instanceof ArrayBuffer ||\n body instanceof Uint8Array\n ) {\n // Uint8Array<ArrayBufferLike> is a valid fetch body at runtime, but the\n // DOM lib's BodyInit only admits ArrayBuffer-backed views.\n return body as BodyInit;\n }\n\n if (body instanceof FormData || body instanceof URLSearchParams) {\n return body;\n }\n\n return JSON.stringify(body);\n}\n"],"mappings":";;AAAA,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACD;AAgBD,eAAsB,gBAAgB,SAAuC;AAG3E,KAAI,EAFgB,QAAQ,QAAQ,IAAI,eAAe,IAAI,IAE1C,SAAS,mBAAmB,CAC3C,OAAM,oBACJ,+CACA,IACD;CAGH,IAAI;AACJ,KAAI;AACF,iBAAgB,MAAM,QAAQ,OAAO,CAAC,MAAM;SACtC;AACN,QAAM,oBAAoB,wBAAwB,IAAI;;AAKxD,QAAO;EACL,QAHa,eAAe,aAAa,OAAO;EAIhD,QAAQ,aAAa;EACrB,MAAM,aAAa;EACpB;;AAGH,SAAgB,aACd,QACA,KACQ;CACR,MAAM,QAAQ,SAAS;AACvB,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,EACrD,QAAO;AAGT,OAAM,oBAAoB,iCAAiC,IAAI,IAAI,IAAI;;AAGzE,SAAgB,kBAAkB,MAAe,MAAwB;AACvE,KAAI,SAAS,UAAa,SAAS,KACjC,OAAM,oBAAoB,yCAAyC,IAAI;CAGzE,MAAM,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACzC,SAAQ,IAAI,gBAAgB,mBAAmB;AAC/C,SAAQ,OAAO,iBAAiB;CAEhC,MAAM,iBAAiB,kBAAkB,KAAK;AAE9C,QAAO,IAAI,QAAQ,KAAK,KAAK;EAC3B,QAAQ;EACR;EACA,MAAM;EACN,QAAQ,KAAK;EACd,CAAC;;AAGJ,SAAgB,oBAAoB,SAAiB,QAA0B;AAC7E,QAAO,IAAI,SACT,KAAK,UAAU;EACb,OAAO;EACP;EACD,CAAC,EACF;EACE;EACA,SAAS,EACP,gBAAgB,oBACjB;EACF,CACF;;AAGH,SAAS,eAAe,QAA4C;AAClE,KAAI,CAAC,OACH,OAAM,oBAAoB,wBAAwB,IAAI;AAGxD,KAAK,aAAmC,SAAS,OAAO,CACtD,QAAO;AAGT,OAAM,oBAAoB,uBAAuB,OAAO,IAAI,IAAI;;AAGlE,SAAS,kBAAkB,MAAyB;AAClD,KAAI,OAAO,SAAS,SAClB,QAAO;AAGT,KACE,gBAAgB,QAChB,gBAAgB,eAChB,gBAAgB,WAIhB,QAAO;AAGT,KAAI,gBAAgB,YAAY,gBAAgB,gBAC9C,QAAO;AAGT,QAAO,KAAK,UAAU,KAAK"}
|
|
@@ -17,19 +17,20 @@ async function handleRunAgent({ runtime, request, agentId }) {
|
|
|
17
17
|
const agent = await require_agent_utils.cloneAgentForRequest(runtime, agentId, request);
|
|
18
18
|
if (agent instanceof Response) return agent;
|
|
19
19
|
agent.agentId = agentId;
|
|
20
|
+
const input = await require_agent_utils.parseRunRequest(request);
|
|
21
|
+
if (input instanceof Response) return input;
|
|
20
22
|
require_agent_utils.configureAgentForRequest({
|
|
21
23
|
runtime,
|
|
22
24
|
request,
|
|
23
25
|
agentId,
|
|
24
|
-
agent
|
|
26
|
+
agent,
|
|
27
|
+
providerA2UIHasCatalog: input.forwardedProps?.a2uiCatalogAvailable === true
|
|
25
28
|
});
|
|
26
29
|
await require_agent_utils.attachIntelligenceEnterpriseLearning({
|
|
27
30
|
runtime,
|
|
28
31
|
request,
|
|
29
32
|
agent
|
|
30
33
|
});
|
|
31
|
-
const input = await require_agent_utils.parseRunRequest(request);
|
|
32
|
-
if (input instanceof Response) return input;
|
|
33
34
|
agent.setMessages(input.messages);
|
|
34
35
|
agent.setState(input.state);
|
|
35
36
|
agent.threadId = input.threadId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-run.cjs","names":["cloneAgentForRequest","
|
|
1
|
+
{"version":3,"file":"handle-run.cjs","names":["cloneAgentForRequest","parseRunRequest","attachIntelligenceEnterpriseLearning","isIntelligenceRuntime","handleIntelligenceRun","handleSseRun"],"sources":["../../../../src/v2/runtime/handlers/handle-run.ts"],"sourcesContent":["import { isIntelligenceRuntime } from \"../core/runtime\";\nimport { telemetry } from \"../telemetry\";\nimport type { RunAgentParameters } from \"./shared/agent-utils\";\nimport {\n attachIntelligenceEnterpriseLearning,\n cloneAgentForRequest,\n configureAgentForRequest,\n parseRunRequest,\n} from \"./shared/agent-utils\";\nimport { handleIntelligenceRun } from \"./intelligence/run\";\nimport { handleSseRun } from \"./sse/run\";\n\nexport async function handleRunAgent({\n runtime,\n request,\n agentId,\n}: RunAgentParameters) {\n telemetry.capture(\"oss.runtime.copilot_request_created\", {\n \"cloud.guardrails.enabled\": false,\n requestType: \"run\",\n \"cloud.api_key_provided\": !!request.headers.get(\n \"x-copilotcloud-public-api-key\",\n ),\n ...(request.headers.get(\"x-copilotcloud-public-api-key\")\n ? {\n \"cloud.public_api_key\": request.headers.get(\n \"x-copilotcloud-public-api-key\",\n )!,\n }\n : {}),\n });\n\n try {\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (agent instanceof Response) {\n return agent;\n }\n\n // Ensure the clone carries the registry key so InMemoryAgentRunner can\n // tag historic runs with the correct agentId for filtering.\n agent.agentId = agentId;\n\n // Parse the body before configuring middleware: the request is single-read,\n // and middleware configuration needs the A2UI catalog signal the React\n // provider forwards (see `a2uiCatalogAvailable` below). Middleware is applied\n // to the agent here; the run itself is kicked off later, so this is safe.\n const input = await parseRunRequest(request);\n if (input instanceof Response) {\n return input;\n }\n\n // `<CopilotKit a2ui={{ catalog }}>` forwards this flag on every run. Its\n // presence alone is enough to turn A2UI on end-to-end — no runtime-side\n // `a2ui` config required.\n const providerA2UIHasCatalog =\n (input.forwardedProps as Record<string, unknown> | undefined)\n ?.a2uiCatalogAvailable === true;\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n providerA2UIHasCatalog,\n });\n await attachIntelligenceEnterpriseLearning({ runtime, request, agent });\n\n agent.setMessages(input.messages);\n agent.setState(input.state);\n agent.threadId = input.threadId;\n\n if (runtime.debug?.lifecycle && runtime.debugLogger) {\n runtime.debugLogger.debug(\n { agentName: agentId, threadId: input.threadId },\n \"Agent run started\",\n );\n }\n\n if (isIntelligenceRuntime(runtime)) {\n return handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n });\n }\n\n return handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug: runtime.debug,\n logger: runtime.debugLogger,\n });\n } catch (error) {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n\n return new Response(\n JSON.stringify({\n error: \"Failed to run agent\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n }),\n {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":";;;;;;;;AAYA,eAAsB,eAAe,EACnC,SACA,SACA,WACqB;AACrB,kCAAU,QAAQ,uCAAuC;EACvD,4BAA4B;EAC5B,aAAa;EACb,0BAA0B,CAAC,CAAC,QAAQ,QAAQ,IAC1C,gCACD;EACD,GAAI,QAAQ,QAAQ,IAAI,gCAAgC,GACpD,EACE,wBAAwB,QAAQ,QAAQ,IACtC,gCACD,EACF,GACD,EAAE;EACP,CAAC;AAEF,KAAI;EACF,MAAM,QAAQ,MAAMA,yCAAqB,SAAS,SAAS,QAAQ;AACnE,MAAI,iBAAiB,SACnB,QAAO;AAKT,QAAM,UAAU;EAMhB,MAAM,QAAQ,MAAMC,oCAAgB,QAAQ;AAC5C,MAAI,iBAAiB,SACnB,QAAO;AAUT,+CAAyB;GACvB;GACA;GACA;GACA;GACA,wBARC,MAAM,gBACH,yBAAyB;GAQ9B,CAAC;AACF,QAAMC,yDAAqC;GAAE;GAAS;GAAS;GAAO,CAAC;AAEvE,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,SAAS,MAAM,MAAM;AAC3B,QAAM,WAAW,MAAM;AAEvB,MAAI,QAAQ,OAAO,aAAa,QAAQ,YACtC,SAAQ,YAAY,MAClB;GAAE,WAAW;GAAS,UAAU,MAAM;GAAU,EAChD,oBACD;AAGH,MAAIC,sCAAsB,QAAQ,CAChC,QAAOC,kCAAsB;GAC3B;GACA;GACA;GACA;GACA;GACD,CAAC;AAGJ,SAAOC,2BAAa;GAClB;GACA;GACA;GACA;GACA;GACA,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACjB,CAAC;UACK,OAAO;AACd,UAAQ,MAAM,wBAAwB,MAAM;AAC5C,UAAQ,MACN,gBACA,iBAAiB,QAAQ,MAAM,QAAQ,iBACxC;AACD,UAAQ,MAAM,kBAAkB;GAC9B,MAAM,iBAAiB,QAAQ,MAAM,OAAO;GAC5C,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC/D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;GAC/C,CAAC;AAEF,SAAO,IAAI,SACT,KAAK,UAAU;GACb,OAAO;GACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;GACnD,CAAC,EACF;GACE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAChD,CACF"}
|
|
@@ -17,19 +17,20 @@ async function handleRunAgent({ runtime, request, agentId }) {
|
|
|
17
17
|
const agent = await cloneAgentForRequest(runtime, agentId, request);
|
|
18
18
|
if (agent instanceof Response) return agent;
|
|
19
19
|
agent.agentId = agentId;
|
|
20
|
+
const input = await parseRunRequest(request);
|
|
21
|
+
if (input instanceof Response) return input;
|
|
20
22
|
configureAgentForRequest({
|
|
21
23
|
runtime,
|
|
22
24
|
request,
|
|
23
25
|
agentId,
|
|
24
|
-
agent
|
|
26
|
+
agent,
|
|
27
|
+
providerA2UIHasCatalog: input.forwardedProps?.a2uiCatalogAvailable === true
|
|
25
28
|
});
|
|
26
29
|
await attachIntelligenceEnterpriseLearning({
|
|
27
30
|
runtime,
|
|
28
31
|
request,
|
|
29
32
|
agent
|
|
30
33
|
});
|
|
31
|
-
const input = await parseRunRequest(request);
|
|
32
|
-
if (input instanceof Response) return input;
|
|
33
34
|
agent.setMessages(input.messages);
|
|
34
35
|
agent.setState(input.state);
|
|
35
36
|
agent.threadId = input.threadId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-run.mjs","names":[],"sources":["../../../../src/v2/runtime/handlers/handle-run.ts"],"sourcesContent":["import { isIntelligenceRuntime } from \"../core/runtime\";\nimport { telemetry } from \"../telemetry\";\nimport type { RunAgentParameters } from \"./shared/agent-utils\";\nimport {\n attachIntelligenceEnterpriseLearning,\n cloneAgentForRequest,\n configureAgentForRequest,\n parseRunRequest,\n} from \"./shared/agent-utils\";\nimport { handleIntelligenceRun } from \"./intelligence/run\";\nimport { handleSseRun } from \"./sse/run\";\n\nexport async function handleRunAgent({\n runtime,\n request,\n agentId,\n}: RunAgentParameters) {\n telemetry.capture(\"oss.runtime.copilot_request_created\", {\n \"cloud.guardrails.enabled\": false,\n requestType: \"run\",\n \"cloud.api_key_provided\": !!request.headers.get(\n \"x-copilotcloud-public-api-key\",\n ),\n ...(request.headers.get(\"x-copilotcloud-public-api-key\")\n ? {\n \"cloud.public_api_key\": request.headers.get(\n \"x-copilotcloud-public-api-key\",\n )!,\n }\n : {}),\n });\n\n try {\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (agent instanceof Response) {\n return agent;\n }\n\n // Ensure the clone carries the registry key so InMemoryAgentRunner can\n // tag historic runs with the correct agentId for filtering.\n agent.agentId = agentId;\n\n
|
|
1
|
+
{"version":3,"file":"handle-run.mjs","names":[],"sources":["../../../../src/v2/runtime/handlers/handle-run.ts"],"sourcesContent":["import { isIntelligenceRuntime } from \"../core/runtime\";\nimport { telemetry } from \"../telemetry\";\nimport type { RunAgentParameters } from \"./shared/agent-utils\";\nimport {\n attachIntelligenceEnterpriseLearning,\n cloneAgentForRequest,\n configureAgentForRequest,\n parseRunRequest,\n} from \"./shared/agent-utils\";\nimport { handleIntelligenceRun } from \"./intelligence/run\";\nimport { handleSseRun } from \"./sse/run\";\n\nexport async function handleRunAgent({\n runtime,\n request,\n agentId,\n}: RunAgentParameters) {\n telemetry.capture(\"oss.runtime.copilot_request_created\", {\n \"cloud.guardrails.enabled\": false,\n requestType: \"run\",\n \"cloud.api_key_provided\": !!request.headers.get(\n \"x-copilotcloud-public-api-key\",\n ),\n ...(request.headers.get(\"x-copilotcloud-public-api-key\")\n ? {\n \"cloud.public_api_key\": request.headers.get(\n \"x-copilotcloud-public-api-key\",\n )!,\n }\n : {}),\n });\n\n try {\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (agent instanceof Response) {\n return agent;\n }\n\n // Ensure the clone carries the registry key so InMemoryAgentRunner can\n // tag historic runs with the correct agentId for filtering.\n agent.agentId = agentId;\n\n // Parse the body before configuring middleware: the request is single-read,\n // and middleware configuration needs the A2UI catalog signal the React\n // provider forwards (see `a2uiCatalogAvailable` below). Middleware is applied\n // to the agent here; the run itself is kicked off later, so this is safe.\n const input = await parseRunRequest(request);\n if (input instanceof Response) {\n return input;\n }\n\n // `<CopilotKit a2ui={{ catalog }}>` forwards this flag on every run. Its\n // presence alone is enough to turn A2UI on end-to-end — no runtime-side\n // `a2ui` config required.\n const providerA2UIHasCatalog =\n (input.forwardedProps as Record<string, unknown> | undefined)\n ?.a2uiCatalogAvailable === true;\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n providerA2UIHasCatalog,\n });\n await attachIntelligenceEnterpriseLearning({ runtime, request, agent });\n\n agent.setMessages(input.messages);\n agent.setState(input.state);\n agent.threadId = input.threadId;\n\n if (runtime.debug?.lifecycle && runtime.debugLogger) {\n runtime.debugLogger.debug(\n { agentName: agentId, threadId: input.threadId },\n \"Agent run started\",\n );\n }\n\n if (isIntelligenceRuntime(runtime)) {\n return handleIntelligenceRun({\n runtime,\n request,\n agentId,\n agent,\n input,\n });\n }\n\n return handleSseRun({\n runtime,\n request,\n agent,\n input,\n agentId,\n debug: runtime.debug,\n logger: runtime.debugLogger,\n });\n } catch (error) {\n console.error(\"Error running agent:\", error);\n console.error(\n \"Error stack:\",\n error instanceof Error ? error.stack : \"No stack trace\",\n );\n console.error(\"Error details:\", {\n name: error instanceof Error ? error.name : \"Unknown\",\n message: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error ? error.cause : undefined,\n });\n\n return new Response(\n JSON.stringify({\n error: \"Failed to run agent\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n }),\n {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":";;;;;;;;AAYA,eAAsB,eAAe,EACnC,SACA,SACA,WACqB;AACrB,WAAU,QAAQ,uCAAuC;EACvD,4BAA4B;EAC5B,aAAa;EACb,0BAA0B,CAAC,CAAC,QAAQ,QAAQ,IAC1C,gCACD;EACD,GAAI,QAAQ,QAAQ,IAAI,gCAAgC,GACpD,EACE,wBAAwB,QAAQ,QAAQ,IACtC,gCACD,EACF,GACD,EAAE;EACP,CAAC;AAEF,KAAI;EACF,MAAM,QAAQ,MAAM,qBAAqB,SAAS,SAAS,QAAQ;AACnE,MAAI,iBAAiB,SACnB,QAAO;AAKT,QAAM,UAAU;EAMhB,MAAM,QAAQ,MAAM,gBAAgB,QAAQ;AAC5C,MAAI,iBAAiB,SACnB,QAAO;AAUT,2BAAyB;GACvB;GACA;GACA;GACA;GACA,wBARC,MAAM,gBACH,yBAAyB;GAQ9B,CAAC;AACF,QAAM,qCAAqC;GAAE;GAAS;GAAS;GAAO,CAAC;AAEvE,QAAM,YAAY,MAAM,SAAS;AACjC,QAAM,SAAS,MAAM,MAAM;AAC3B,QAAM,WAAW,MAAM;AAEvB,MAAI,QAAQ,OAAO,aAAa,QAAQ,YACtC,SAAQ,YAAY,MAClB;GAAE,WAAW;GAAS,UAAU,MAAM;GAAU,EAChD,oBACD;AAGH,MAAI,sBAAsB,QAAQ,CAChC,QAAO,sBAAsB;GAC3B;GACA;GACA;GACA;GACA;GACD,CAAC;AAGJ,SAAO,aAAa;GAClB;GACA;GACA;GACA;GACA;GACA,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACjB,CAAC;UACK,OAAO;AACd,UAAQ,MAAM,wBAAwB,MAAM;AAC5C,UAAQ,MACN,gBACA,iBAAiB,QAAQ,MAAM,QAAQ,iBACxC;AACD,UAAQ,MAAM,kBAAkB;GAC9B,MAAM,iBAAiB,QAAQ,MAAM,OAAO;GAC5C,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC/D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;GAC/C,CAAC;AAEF,SAAO,IAAI,SACT,KAAK,UAAU;GACb,OAAO;GACP,SAAS,iBAAiB,QAAQ,MAAM,UAAU;GACnD,CAAC,EACF;GACE,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAChD,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-names.cjs","names":["cloneAgentForRequest","isHandlerResponse"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/thread-names.ts"],"sourcesContent":["import type { Message, RunAgentInput } from \"@ag-ui/client\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { logger } from \"@copilotkit/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport {\n cloneAgentForRequest,\n configureAgentForRequest,\n} from \"../shared/agent-utils\";\nimport type { ThreadSummary } from \"../../intelligence-platform\";\nimport { isHandlerResponse } from \"../shared/json-response\";\n\nconst THREAD_NAME_SYSTEM_PROMPT = [\n \"You generate short, specific conversation titles.\",\n 'Return JSON only in this exact shape: {\"title\":\"...\"}',\n \"The title must be 2 to 5 words.\",\n \"Use sentence case.\",\n \"No quotes.\",\n \"No emoji.\",\n \"No markdown characters or formatting.\",\n \"Do not use *, _, #, `, [, ], (, ), !, ~, >, or |.\",\n \"No trailing punctuation.\",\n \"No explanations.\",\n \"Do not call tools.\",\n].join(\"\\n\");\n\nconst MAX_TITLE_LENGTH = 80;\nconst MAX_TITLE_WORDS = 8;\nconst MAX_TRANSCRIPT_MESSAGES = 8;\nconst MAX_TITLE_GENERATION_ATTEMPTS = 3;\nconst FALLBACK_THREAD_TITLE = \"Untitled\";\n\ninterface GenerateThreadNameParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n sourceInput: RunAgentInput;\n thread: ThreadSummary;\n userId: string;\n}\n\nexport async function generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput,\n thread,\n userId,\n}: GenerateThreadNameParams): Promise<void> {\n if (!runtime.generateThreadNames || hasThreadName(thread.name)) {\n return;\n }\n\n const prompt = buildThreadTitlePrompt(sourceInput.messages);\n if (!prompt) {\n return;\n }\n\n let generatedTitle: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_TITLE_GENERATION_ATTEMPTS; attempt++) {\n try {\n generatedTitle = await runTitleGenerationAttempt({\n runtime,\n request,\n agentId,\n threadId: thread.id,\n prompt,\n });\n\n if (generatedTitle) {\n break;\n }\n\n logger.warn(\n { agentId, attempt, threadId: thread.id },\n \"Thread name generation returned an empty or invalid title\",\n );\n } catch (error) {\n logger.warn(\n { err: error, agentId, attempt, threadId: thread.id },\n \"Thread name generation attempt failed\",\n );\n }\n }\n\n await runtime.intelligence.updateThread({\n threadId: thread.id,\n userId,\n agentId,\n updates: { name: generatedTitle ?? FALLBACK_THREAD_TITLE },\n });\n}\n\nasync function runTitleGenerationAttempt(params: {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n prompt: string;\n}): Promise<string | null> {\n const { runtime, request, agentId, threadId, prompt } = params;\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (isHandlerResponse(agent)) {\n logger.warn(\n { agentId, threadId },\n \"Skipping thread naming because the agent could not be cloned\",\n );\n return null;\n }\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n });\n\n const messages: Message[] = [\n {\n id: randomUUID(),\n role: \"system\",\n content: THREAD_NAME_SYSTEM_PROMPT,\n },\n {\n id: randomUUID(),\n role: \"user\",\n content: prompt,\n },\n ];\n\n agent.setMessages(messages);\n agent.setState({});\n agent.threadId = randomUUID();\n const { newMessages } = await agent.runAgent({\n messages,\n state: {},\n tools: [],\n context: [],\n forwardedProps: {},\n });\n\n return selectGeneratedTitleFromMessages(newMessages);\n}\n\nfunction buildThreadTitlePrompt(\n messages: Message[] | undefined,\n): string | null {\n const transcript = (messages ?? [])\n .filter((message) =>\n [\"user\", \"assistant\", \"system\", \"developer\"].includes(message.role),\n )\n .map((message) => {\n const content = stringifyMessageContent(message.content);\n if (!content) {\n return null;\n }\n\n return `${message.role}: ${content}`;\n })\n .filter((message): message is string => !!message)\n .slice(-MAX_TRANSCRIPT_MESSAGES);\n\n if (transcript.length === 0) {\n return null;\n }\n\n return [\n \"Generate a short title for this conversation.\",\n \"Conversation:\",\n transcript.join(\"\\n\"),\n ].join(\"\\n\\n\");\n}\n\nfunction stringifyMessageContent(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content.trim();\n }\n\n if (content == null) {\n return \"\";\n }\n\n try {\n return JSON.stringify(content).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction normalizeGeneratedTitle(rawTitle: string): string | null {\n let candidate = rawTitle.trim();\n if (!candidate) {\n return null;\n }\n\n candidate = candidate\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/, \"\")\n .trim();\n\n const jsonLike = isJsonLike(candidate);\n\n try {\n const parsed = JSON.parse(candidate) as { title?: unknown };\n if (typeof parsed.title === \"string\") {\n candidate = parsed.title;\n } else if (jsonLike) {\n return null;\n }\n } catch {\n if (jsonLike) {\n return null;\n }\n }\n\n candidate = candidate\n .replace(/^[\"'`]+|[\"'`]+$/g, \"\")\n .replace(/[*_#[\\]()!~>|]+/g, \"\")\n .replace(/[.!?,;:]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n if (!candidate) {\n return null;\n }\n\n if (candidate.length > MAX_TITLE_LENGTH) {\n candidate = candidate.slice(0, MAX_TITLE_LENGTH).trim();\n }\n\n if (candidate.split(/\\s+/).length > MAX_TITLE_WORDS) {\n return null;\n }\n\n return candidate;\n}\n\nfunction selectGeneratedTitleFromMessages(messages: Message[]): string | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message.role !== \"assistant\" || typeof message.content !== \"string\") {\n continue;\n }\n\n const title = normalizeGeneratedTitle(message.content);\n if (title) {\n return title;\n }\n }\n\n return null;\n}\n\nfunction isJsonLike(candidate: string): boolean {\n return (\n (candidate.startsWith(\"{\") && candidate.endsWith(\"}\")) ||\n (candidate.startsWith(\"[\") && candidate.endsWith(\"]\"))\n );\n}\n\nfunction hasThreadName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && name.trim().length > 0;\n}\n\n/** @internal Exported for testing only. */\nexport const ɵnormalizeGeneratedTitle = normalizeGeneratedTitle;\n/** @internal Exported for testing only. */\nexport const ɵselectGeneratedTitleFromMessages =\n selectGeneratedTitleFromMessages;\n/** @internal Exported for testing only. */\nexport const ɵbuildThreadTitlePrompt = buildThreadTitlePrompt;\n/** @internal Exported for testing only. */\nexport const ɵhasThreadName = hasThreadName;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thread-names.cjs","names":["cloneAgentForRequest","isHandlerResponse"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/thread-names.ts"],"sourcesContent":["import type { Message, RunAgentInput } from \"@ag-ui/client\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { logger } from \"@copilotkit/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport {\n cloneAgentForRequest,\n configureAgentForRequest,\n} from \"../shared/agent-utils\";\nimport type { ThreadSummary } from \"../../intelligence-platform\";\nimport { isHandlerResponse } from \"../shared/json-response\";\n\nconst THREAD_NAME_SYSTEM_PROMPT = [\n \"You generate short, specific conversation titles.\",\n 'Return JSON only in this exact shape: {\"title\":\"...\"}',\n \"The title must be 2 to 5 words.\",\n \"Use sentence case.\",\n \"No quotes.\",\n \"No emoji.\",\n \"No markdown characters or formatting.\",\n \"Do not use *, _, #, `, [, ], (, ), !, ~, >, or |.\",\n \"No trailing punctuation.\",\n \"No explanations.\",\n \"Do not call tools.\",\n].join(\"\\n\");\n\nconst MAX_TITLE_LENGTH = 80;\nconst MAX_TITLE_WORDS = 8;\nconst MAX_TRANSCRIPT_MESSAGES = 8;\nconst MAX_TITLE_GENERATION_ATTEMPTS = 3;\nconst FALLBACK_THREAD_TITLE = \"Untitled\";\n\ninterface GenerateThreadNameParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n sourceInput: RunAgentInput;\n thread: ThreadSummary;\n userId: string;\n}\n\nexport async function generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput,\n thread,\n userId,\n}: GenerateThreadNameParams): Promise<void> {\n if (!runtime.generateThreadNames || hasThreadName(thread.name)) {\n return;\n }\n\n const prompt = buildThreadTitlePrompt(sourceInput.messages);\n if (!prompt) {\n return;\n }\n\n let generatedTitle: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_TITLE_GENERATION_ATTEMPTS; attempt++) {\n try {\n generatedTitle = await runTitleGenerationAttempt({\n runtime,\n request,\n agentId,\n threadId: thread.id,\n prompt,\n });\n\n if (generatedTitle) {\n break;\n }\n\n logger.warn(\n { agentId, attempt, threadId: thread.id },\n \"Thread name generation returned an empty or invalid title\",\n );\n } catch (error) {\n logger.warn(\n { err: error, agentId, attempt, threadId: thread.id },\n \"Thread name generation attempt failed\",\n );\n }\n }\n\n await runtime.intelligence.updateThread({\n threadId: thread.id,\n userId,\n agentId,\n updates: { name: generatedTitle ?? FALLBACK_THREAD_TITLE },\n });\n}\n\nasync function runTitleGenerationAttempt(params: {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n prompt: string;\n}): Promise<string | null> {\n const { runtime, request, agentId, threadId, prompt } = params;\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (isHandlerResponse(agent)) {\n logger.warn(\n { agentId, threadId },\n \"Skipping thread naming because the agent could not be cloned\",\n );\n return null;\n }\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n });\n\n const messages: Message[] = [\n {\n id: randomUUID(),\n role: \"system\",\n content: THREAD_NAME_SYSTEM_PROMPT,\n },\n {\n id: randomUUID(),\n role: \"user\",\n content: prompt,\n },\n ];\n\n agent.setMessages(messages);\n agent.setState({});\n agent.threadId = randomUUID();\n // Messages and state are picked up from the agent itself (set above);\n // RunAgentParameters no longer accepts them directly.\n const { newMessages } = await agent.runAgent({\n tools: [],\n context: [],\n forwardedProps: {},\n });\n\n return selectGeneratedTitleFromMessages(newMessages);\n}\n\nfunction buildThreadTitlePrompt(\n messages: Message[] | undefined,\n): string | null {\n const transcript = (messages ?? [])\n .filter((message) =>\n [\"user\", \"assistant\", \"system\", \"developer\"].includes(message.role),\n )\n .map((message) => {\n const content = stringifyMessageContent(message.content);\n if (!content) {\n return null;\n }\n\n return `${message.role}: ${content}`;\n })\n .filter((message): message is string => !!message)\n .slice(-MAX_TRANSCRIPT_MESSAGES);\n\n if (transcript.length === 0) {\n return null;\n }\n\n return [\n \"Generate a short title for this conversation.\",\n \"Conversation:\",\n transcript.join(\"\\n\"),\n ].join(\"\\n\\n\");\n}\n\nfunction stringifyMessageContent(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content.trim();\n }\n\n if (content == null) {\n return \"\";\n }\n\n try {\n return JSON.stringify(content).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction normalizeGeneratedTitle(rawTitle: string): string | null {\n let candidate = rawTitle.trim();\n if (!candidate) {\n return null;\n }\n\n candidate = candidate\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/, \"\")\n .trim();\n\n const jsonLike = isJsonLike(candidate);\n\n try {\n const parsed = JSON.parse(candidate) as { title?: unknown };\n if (typeof parsed.title === \"string\") {\n candidate = parsed.title;\n } else if (jsonLike) {\n return null;\n }\n } catch {\n if (jsonLike) {\n return null;\n }\n }\n\n candidate = candidate\n .replace(/^[\"'`]+|[\"'`]+$/g, \"\")\n .replace(/[*_#[\\]()!~>|]+/g, \"\")\n .replace(/[.!?,;:]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n if (!candidate) {\n return null;\n }\n\n if (candidate.length > MAX_TITLE_LENGTH) {\n candidate = candidate.slice(0, MAX_TITLE_LENGTH).trim();\n }\n\n if (candidate.split(/\\s+/).length > MAX_TITLE_WORDS) {\n return null;\n }\n\n return candidate;\n}\n\nfunction selectGeneratedTitleFromMessages(messages: Message[]): string | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message.role !== \"assistant\" || typeof message.content !== \"string\") {\n continue;\n }\n\n const title = normalizeGeneratedTitle(message.content);\n if (title) {\n return title;\n }\n }\n\n return null;\n}\n\nfunction isJsonLike(candidate: string): boolean {\n return (\n (candidate.startsWith(\"{\") && candidate.endsWith(\"}\")) ||\n (candidate.startsWith(\"[\") && candidate.endsWith(\"]\"))\n );\n}\n\nfunction hasThreadName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && name.trim().length > 0;\n}\n\n/** @internal Exported for testing only. */\nexport const ɵnormalizeGeneratedTitle = normalizeGeneratedTitle;\n/** @internal Exported for testing only. */\nexport const ɵselectGeneratedTitleFromMessages =\n selectGeneratedTitleFromMessages;\n/** @internal Exported for testing only. */\nexport const ɵbuildThreadTitlePrompt = buildThreadTitlePrompt;\n/** @internal Exported for testing only. */\nexport const ɵhasThreadName = hasThreadName;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-names.mjs","names":["randomUUID"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/thread-names.ts"],"sourcesContent":["import type { Message, RunAgentInput } from \"@ag-ui/client\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { logger } from \"@copilotkit/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport {\n cloneAgentForRequest,\n configureAgentForRequest,\n} from \"../shared/agent-utils\";\nimport type { ThreadSummary } from \"../../intelligence-platform\";\nimport { isHandlerResponse } from \"../shared/json-response\";\n\nconst THREAD_NAME_SYSTEM_PROMPT = [\n \"You generate short, specific conversation titles.\",\n 'Return JSON only in this exact shape: {\"title\":\"...\"}',\n \"The title must be 2 to 5 words.\",\n \"Use sentence case.\",\n \"No quotes.\",\n \"No emoji.\",\n \"No markdown characters or formatting.\",\n \"Do not use *, _, #, `, [, ], (, ), !, ~, >, or |.\",\n \"No trailing punctuation.\",\n \"No explanations.\",\n \"Do not call tools.\",\n].join(\"\\n\");\n\nconst MAX_TITLE_LENGTH = 80;\nconst MAX_TITLE_WORDS = 8;\nconst MAX_TRANSCRIPT_MESSAGES = 8;\nconst MAX_TITLE_GENERATION_ATTEMPTS = 3;\nconst FALLBACK_THREAD_TITLE = \"Untitled\";\n\ninterface GenerateThreadNameParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n sourceInput: RunAgentInput;\n thread: ThreadSummary;\n userId: string;\n}\n\nexport async function generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput,\n thread,\n userId,\n}: GenerateThreadNameParams): Promise<void> {\n if (!runtime.generateThreadNames || hasThreadName(thread.name)) {\n return;\n }\n\n const prompt = buildThreadTitlePrompt(sourceInput.messages);\n if (!prompt) {\n return;\n }\n\n let generatedTitle: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_TITLE_GENERATION_ATTEMPTS; attempt++) {\n try {\n generatedTitle = await runTitleGenerationAttempt({\n runtime,\n request,\n agentId,\n threadId: thread.id,\n prompt,\n });\n\n if (generatedTitle) {\n break;\n }\n\n logger.warn(\n { agentId, attempt, threadId: thread.id },\n \"Thread name generation returned an empty or invalid title\",\n );\n } catch (error) {\n logger.warn(\n { err: error, agentId, attempt, threadId: thread.id },\n \"Thread name generation attempt failed\",\n );\n }\n }\n\n await runtime.intelligence.updateThread({\n threadId: thread.id,\n userId,\n agentId,\n updates: { name: generatedTitle ?? FALLBACK_THREAD_TITLE },\n });\n}\n\nasync function runTitleGenerationAttempt(params: {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n prompt: string;\n}): Promise<string | null> {\n const { runtime, request, agentId, threadId, prompt } = params;\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (isHandlerResponse(agent)) {\n logger.warn(\n { agentId, threadId },\n \"Skipping thread naming because the agent could not be cloned\",\n );\n return null;\n }\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n });\n\n const messages: Message[] = [\n {\n id: randomUUID(),\n role: \"system\",\n content: THREAD_NAME_SYSTEM_PROMPT,\n },\n {\n id: randomUUID(),\n role: \"user\",\n content: prompt,\n },\n ];\n\n agent.setMessages(messages);\n agent.setState({});\n agent.threadId = randomUUID();\n const { newMessages } = await agent.runAgent({\n messages,\n state: {},\n tools: [],\n context: [],\n forwardedProps: {},\n });\n\n return selectGeneratedTitleFromMessages(newMessages);\n}\n\nfunction buildThreadTitlePrompt(\n messages: Message[] | undefined,\n): string | null {\n const transcript = (messages ?? [])\n .filter((message) =>\n [\"user\", \"assistant\", \"system\", \"developer\"].includes(message.role),\n )\n .map((message) => {\n const content = stringifyMessageContent(message.content);\n if (!content) {\n return null;\n }\n\n return `${message.role}: ${content}`;\n })\n .filter((message): message is string => !!message)\n .slice(-MAX_TRANSCRIPT_MESSAGES);\n\n if (transcript.length === 0) {\n return null;\n }\n\n return [\n \"Generate a short title for this conversation.\",\n \"Conversation:\",\n transcript.join(\"\\n\"),\n ].join(\"\\n\\n\");\n}\n\nfunction stringifyMessageContent(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content.trim();\n }\n\n if (content == null) {\n return \"\";\n }\n\n try {\n return JSON.stringify(content).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction normalizeGeneratedTitle(rawTitle: string): string | null {\n let candidate = rawTitle.trim();\n if (!candidate) {\n return null;\n }\n\n candidate = candidate\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/, \"\")\n .trim();\n\n const jsonLike = isJsonLike(candidate);\n\n try {\n const parsed = JSON.parse(candidate) as { title?: unknown };\n if (typeof parsed.title === \"string\") {\n candidate = parsed.title;\n } else if (jsonLike) {\n return null;\n }\n } catch {\n if (jsonLike) {\n return null;\n }\n }\n\n candidate = candidate\n .replace(/^[\"'`]+|[\"'`]+$/g, \"\")\n .replace(/[*_#[\\]()!~>|]+/g, \"\")\n .replace(/[.!?,;:]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n if (!candidate) {\n return null;\n }\n\n if (candidate.length > MAX_TITLE_LENGTH) {\n candidate = candidate.slice(0, MAX_TITLE_LENGTH).trim();\n }\n\n if (candidate.split(/\\s+/).length > MAX_TITLE_WORDS) {\n return null;\n }\n\n return candidate;\n}\n\nfunction selectGeneratedTitleFromMessages(messages: Message[]): string | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message.role !== \"assistant\" || typeof message.content !== \"string\") {\n continue;\n }\n\n const title = normalizeGeneratedTitle(message.content);\n if (title) {\n return title;\n }\n }\n\n return null;\n}\n\nfunction isJsonLike(candidate: string): boolean {\n return (\n (candidate.startsWith(\"{\") && candidate.endsWith(\"}\")) ||\n (candidate.startsWith(\"[\") && candidate.endsWith(\"]\"))\n );\n}\n\nfunction hasThreadName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && name.trim().length > 0;\n}\n\n/** @internal Exported for testing only. */\nexport const ɵnormalizeGeneratedTitle = normalizeGeneratedTitle;\n/** @internal Exported for testing only. */\nexport const ɵselectGeneratedTitleFromMessages =\n selectGeneratedTitleFromMessages;\n/** @internal Exported for testing only. */\nexport const ɵbuildThreadTitlePrompt = buildThreadTitlePrompt;\n/** @internal Exported for testing only. */\nexport const ɵhasThreadName = hasThreadName;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thread-names.mjs","names":["randomUUID"],"sources":["../../../../../src/v2/runtime/handlers/intelligence/thread-names.ts"],"sourcesContent":["import type { Message, RunAgentInput } from \"@ag-ui/client\";\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { logger } from \"@copilotkit/shared\";\nimport { randomUUID } from \"node:crypto\";\nimport type { CopilotIntelligenceRuntimeLike } from \"../../core/runtime\";\nimport {\n cloneAgentForRequest,\n configureAgentForRequest,\n} from \"../shared/agent-utils\";\nimport type { ThreadSummary } from \"../../intelligence-platform\";\nimport { isHandlerResponse } from \"../shared/json-response\";\n\nconst THREAD_NAME_SYSTEM_PROMPT = [\n \"You generate short, specific conversation titles.\",\n 'Return JSON only in this exact shape: {\"title\":\"...\"}',\n \"The title must be 2 to 5 words.\",\n \"Use sentence case.\",\n \"No quotes.\",\n \"No emoji.\",\n \"No markdown characters or formatting.\",\n \"Do not use *, _, #, `, [, ], (, ), !, ~, >, or |.\",\n \"No trailing punctuation.\",\n \"No explanations.\",\n \"Do not call tools.\",\n].join(\"\\n\");\n\nconst MAX_TITLE_LENGTH = 80;\nconst MAX_TITLE_WORDS = 8;\nconst MAX_TRANSCRIPT_MESSAGES = 8;\nconst MAX_TITLE_GENERATION_ATTEMPTS = 3;\nconst FALLBACK_THREAD_TITLE = \"Untitled\";\n\ninterface GenerateThreadNameParams {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n sourceInput: RunAgentInput;\n thread: ThreadSummary;\n userId: string;\n}\n\nexport async function generateThreadNameForNewThread({\n runtime,\n request,\n agentId,\n sourceInput,\n thread,\n userId,\n}: GenerateThreadNameParams): Promise<void> {\n if (!runtime.generateThreadNames || hasThreadName(thread.name)) {\n return;\n }\n\n const prompt = buildThreadTitlePrompt(sourceInput.messages);\n if (!prompt) {\n return;\n }\n\n let generatedTitle: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_TITLE_GENERATION_ATTEMPTS; attempt++) {\n try {\n generatedTitle = await runTitleGenerationAttempt({\n runtime,\n request,\n agentId,\n threadId: thread.id,\n prompt,\n });\n\n if (generatedTitle) {\n break;\n }\n\n logger.warn(\n { agentId, attempt, threadId: thread.id },\n \"Thread name generation returned an empty or invalid title\",\n );\n } catch (error) {\n logger.warn(\n { err: error, agentId, attempt, threadId: thread.id },\n \"Thread name generation attempt failed\",\n );\n }\n }\n\n await runtime.intelligence.updateThread({\n threadId: thread.id,\n userId,\n agentId,\n updates: { name: generatedTitle ?? FALLBACK_THREAD_TITLE },\n });\n}\n\nasync function runTitleGenerationAttempt(params: {\n runtime: CopilotIntelligenceRuntimeLike;\n request: Request;\n agentId: string;\n threadId: string;\n prompt: string;\n}): Promise<string | null> {\n const { runtime, request, agentId, threadId, prompt } = params;\n const agent = await cloneAgentForRequest(runtime, agentId, request);\n if (isHandlerResponse(agent)) {\n logger.warn(\n { agentId, threadId },\n \"Skipping thread naming because the agent could not be cloned\",\n );\n return null;\n }\n\n configureAgentForRequest({\n runtime,\n request,\n agentId,\n agent,\n });\n\n const messages: Message[] = [\n {\n id: randomUUID(),\n role: \"system\",\n content: THREAD_NAME_SYSTEM_PROMPT,\n },\n {\n id: randomUUID(),\n role: \"user\",\n content: prompt,\n },\n ];\n\n agent.setMessages(messages);\n agent.setState({});\n agent.threadId = randomUUID();\n // Messages and state are picked up from the agent itself (set above);\n // RunAgentParameters no longer accepts them directly.\n const { newMessages } = await agent.runAgent({\n tools: [],\n context: [],\n forwardedProps: {},\n });\n\n return selectGeneratedTitleFromMessages(newMessages);\n}\n\nfunction buildThreadTitlePrompt(\n messages: Message[] | undefined,\n): string | null {\n const transcript = (messages ?? [])\n .filter((message) =>\n [\"user\", \"assistant\", \"system\", \"developer\"].includes(message.role),\n )\n .map((message) => {\n const content = stringifyMessageContent(message.content);\n if (!content) {\n return null;\n }\n\n return `${message.role}: ${content}`;\n })\n .filter((message): message is string => !!message)\n .slice(-MAX_TRANSCRIPT_MESSAGES);\n\n if (transcript.length === 0) {\n return null;\n }\n\n return [\n \"Generate a short title for this conversation.\",\n \"Conversation:\",\n transcript.join(\"\\n\"),\n ].join(\"\\n\\n\");\n}\n\nfunction stringifyMessageContent(content: Message[\"content\"]): string {\n if (typeof content === \"string\") {\n return content.trim();\n }\n\n if (content == null) {\n return \"\";\n }\n\n try {\n return JSON.stringify(content).trim();\n } catch {\n return \"\";\n }\n}\n\nfunction normalizeGeneratedTitle(rawTitle: string): string | null {\n let candidate = rawTitle.trim();\n if (!candidate) {\n return null;\n }\n\n candidate = candidate\n .replace(/^```(?:json)?\\s*/i, \"\")\n .replace(/\\s*```$/, \"\")\n .trim();\n\n const jsonLike = isJsonLike(candidate);\n\n try {\n const parsed = JSON.parse(candidate) as { title?: unknown };\n if (typeof parsed.title === \"string\") {\n candidate = parsed.title;\n } else if (jsonLike) {\n return null;\n }\n } catch {\n if (jsonLike) {\n return null;\n }\n }\n\n candidate = candidate\n .replace(/^[\"'`]+|[\"'`]+$/g, \"\")\n .replace(/[*_#[\\]()!~>|]+/g, \"\")\n .replace(/[.!?,;:]+$/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n if (!candidate) {\n return null;\n }\n\n if (candidate.length > MAX_TITLE_LENGTH) {\n candidate = candidate.slice(0, MAX_TITLE_LENGTH).trim();\n }\n\n if (candidate.split(/\\s+/).length > MAX_TITLE_WORDS) {\n return null;\n }\n\n return candidate;\n}\n\nfunction selectGeneratedTitleFromMessages(messages: Message[]): string | null {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index];\n if (message.role !== \"assistant\" || typeof message.content !== \"string\") {\n continue;\n }\n\n const title = normalizeGeneratedTitle(message.content);\n if (title) {\n return title;\n }\n }\n\n return null;\n}\n\nfunction isJsonLike(candidate: string): boolean {\n return (\n (candidate.startsWith(\"{\") && candidate.endsWith(\"}\")) ||\n (candidate.startsWith(\"[\") && candidate.endsWith(\"]\"))\n );\n}\n\nfunction hasThreadName(name: string | null | undefined): boolean {\n return typeof name === \"string\" && name.trim().length > 0;\n}\n\n/** @internal Exported for testing only. */\nexport const ɵnormalizeGeneratedTitle = normalizeGeneratedTitle;\n/** @internal Exported for testing only. */\nexport const ɵselectGeneratedTitleFromMessages =\n selectGeneratedTitleFromMessages;\n/** @internal Exported for testing only. */\nexport const ɵbuildThreadTitlePrompt = buildThreadTitlePrompt;\n/** @internal Exported for testing only. */\nexport const ɵhasThreadName = hasThreadName;\n"],"mappings":"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"}
|
|
@@ -24,11 +24,15 @@ async function cloneAgentForRequest(runtime, agentId, request) {
|
|
|
24
24
|
return agents[agentId].clone();
|
|
25
25
|
}
|
|
26
26
|
function configureAgentForRequest(params) {
|
|
27
|
-
const { runtime, request, agentId } = params;
|
|
27
|
+
const { runtime, request, agentId, providerA2UIHasCatalog } = params;
|
|
28
28
|
const agent = params.agent;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const a2uiEnabledByCatalog = !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;
|
|
30
|
+
if (require_runtime$1.isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {
|
|
31
|
+
const { agents: targetAgents, enabled: _enabled, injectA2UITool, ...a2uiOptions } = runtime.a2ui ?? {};
|
|
32
|
+
if ((!targetAgents || targetAgents.includes(agentId)) && typeof agent.use === "function") agent.use(new _ag_ui_a2ui_middleware.A2UIMiddleware({
|
|
33
|
+
...a2uiOptions,
|
|
34
|
+
injectA2UITool: injectA2UITool ?? (providerA2UIHasCatalog ? true : void 0)
|
|
35
|
+
}));
|
|
32
36
|
}
|
|
33
37
|
if (runtime.mcpApps?.servers?.length) {
|
|
34
38
|
const mcpServers = runtime.mcpApps.servers.filter((server) => !server.agentId || server.agentId === agentId).map((server) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","MCPAppsMiddleware","OpenGenerativeUIMiddleware","extractForwardableHeaders","isIntelligenceRuntime","resolveIntelligenceUser","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/client\";\nimport { A2UIMiddleware } from \"@ag-ui/a2ui-middleware\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport { OpenGenerativeUIMiddleware } from \"../../open-generative-ui-middleware\";\nimport { INTELLIGENCE_USER_ID_HEADER } from \"../../intelligence-platform/client\";\nimport { extractForwardableHeaders } from \"../header-utils\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n}): void {\n const { runtime, request, agentId } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (isA2UIEnabled(runtime.a2ui)) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n ...a2uiOptions\n } = runtime.a2ui;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new A2UIMiddleware(a2uiOptions));\n }\n }\n\n if (runtime.mcpApps?.servers?.length) {\n const mcpServers = runtime.mcpApps.servers\n .filter((server) => !server.agentId || server.agentId === agentId)\n .map((server) => {\n const mcpServer = { ...server };\n delete mcpServer.agentId;\n return mcpServer;\n });\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n agent.headers = {\n ...agent.headers,\n ...extractForwardableHeaders(request),\n };\n}\n\n/**\n * Attach the Intelligence platform's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (\n !isIntelligenceRuntime(runtime) ||\n !runtime.intelligence?.ɵisEnterpriseLearningEnabled?.()\n ) {\n return;\n }\n\n // Enterprise learning is enabled, but this agent's framework can't take\n // middleware — surface it rather than silently shipping a run with none\n // of the tools the operator opted into.\n if (typeof agent.use !== \"function\") {\n logger.warn(\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\",\n );\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return;\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n },\n },\n ]),\n );\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return RunAgentInputSchema.parse(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = RunAgentInputSchema.parse(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-utils.cjs","names":["resolveAgents","isA2UIEnabled","A2UIMiddleware","MCPAppsMiddleware","OpenGenerativeUIMiddleware","extractForwardableHeaders","isIntelligenceRuntime","resolveIntelligenceUser","MCPMiddleware","INTELLIGENCE_USER_ID_HEADER","RunAgentInputSchema"],"sources":["../../../../../src/v2/runtime/handlers/shared/agent-utils.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentInput } from \"@ag-ui/client\";\nimport { RunAgentInputSchema } from \"@ag-ui/client\";\nimport { A2UIMiddleware } from \"@ag-ui/a2ui-middleware\";\nimport { MCPAppsMiddleware } from \"@ag-ui/mcp-apps-middleware\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { CopilotRuntimeLike } from \"../../core/runtime\";\nimport {\n isA2UIEnabled,\n isIntelligenceRuntime,\n resolveAgents,\n} from \"../../core/runtime\";\nimport { OpenGenerativeUIMiddleware } from \"../../open-generative-ui-middleware\";\nimport { INTELLIGENCE_USER_ID_HEADER } from \"../../intelligence-platform/client\";\nimport { extractForwardableHeaders } from \"../header-utils\";\nimport { resolveIntelligenceUser } from \"./resolve-intelligence-user\";\nimport { logger } from \"@copilotkit/shared\";\n\ntype MiddlewareCapableAgent = AbstractAgent & {\n use?: (middleware: unknown) => void;\n headers?: Record<string, string>;\n};\n\nexport interface RunAgentParameters {\n request: Request;\n runtime: CopilotRuntimeLike;\n agentId: string;\n}\n\nexport interface ConnectRequestBody extends RunAgentInput {\n lastSeenEventId?: string | null;\n}\n\nexport async function cloneAgentForRequest(\n runtime: CopilotRuntimeLike,\n agentId: string,\n request?: Request,\n): Promise<AbstractAgent | Response> {\n const agents = await resolveAgents(runtime.agents, request);\n\n if (!agents[agentId]) {\n return new Response(\n JSON.stringify({\n error: \"Agent not found\",\n message: `Agent '${agentId}' does not exist`,\n }),\n {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n\n return (agents[agentId] as AbstractAgent).clone() as AbstractAgent;\n}\n\nexport function configureAgentForRequest(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agentId: string;\n agent: AbstractAgent;\n /**\n * True when the React provider was given an A2UI catalog\n * (`<CopilotKit a2ui={{ catalog }}>`), forwarded per-run. A catalog alone is\n * enough to enable A2UI and inject the render tool — the developer no longer\n * has to also set `a2ui.injectA2UITool` on the runtime.\n */\n providerA2UIHasCatalog?: boolean;\n}): void {\n const { runtime, request, agentId, providerA2UIHasCatalog } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n // A2UI is on when the runtime explicitly enables it, OR when the provider\n // forwarded a catalog — but an explicit `enabled: false` always wins (we\n // provide a quick default, never override a deeper opt-out).\n const a2uiEnabledByCatalog =\n !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;\n\n if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {\n // `enabled` is a CopilotKit-level switch, not an A2UIMiddleware option —\n // drop it (alongside the agent filter) before forwarding to the middleware.\n const {\n agents: targetAgents,\n enabled: _enabled,\n injectA2UITool,\n ...a2uiOptions\n } = runtime.a2ui ?? {};\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(\n new A2UIMiddleware({\n ...a2uiOptions,\n // Default render-tool injection on when a catalog is present and the\n // developer hasn't set it explicitly. `??` means an explicit value\n // (including `false`) is always respected.\n injectA2UITool:\n injectA2UITool ?? (providerA2UIHasCatalog ? true : undefined),\n }),\n );\n }\n }\n\n if (runtime.mcpApps?.servers?.length) {\n const mcpServers = runtime.mcpApps.servers\n .filter((server) => !server.agentId || server.agentId === agentId)\n .map((server) => {\n const mcpServer = { ...server };\n delete mcpServer.agentId;\n return mcpServer;\n });\n\n if (mcpServers.length > 0 && typeof agent.use === \"function\") {\n agent.use(new MCPAppsMiddleware({ mcpServers }));\n }\n }\n\n if (runtime.openGenerativeUI) {\n const config = runtime.openGenerativeUI;\n const targetAgents = typeof config === \"object\" ? config.agents : undefined;\n const shouldApply = !targetAgents || targetAgents.includes(agentId);\n if (shouldApply && typeof agent.use === \"function\") {\n agent.use(new OpenGenerativeUIMiddleware());\n }\n }\n\n agent.headers = {\n ...agent.headers,\n ...extractForwardableHeaders(request),\n };\n}\n\n/**\n * Attach the Intelligence platform's MCP tools to the agent run when\n * `CopilotKitIntelligence` was constructed with\n * `enableEnterpriseLearning: true`. Uses `@ag-ui/mcp-middleware`, so the\n * tools are available uniformly across agent frameworks (not just\n * `BuiltInAgent`).\n *\n * The middleware sits on a per-request agent clone, so the per-request\n * auth (Bearer apiKey + resolved user-id) is baked into the transport\n * headers at attach time. If user resolution fails, attachment is\n * skipped silently — the intelligence run handler will reject the\n * request with the same error. Note this means `identifyUser` is\n * resolved twice per learning-enabled run (here and in the run handler);\n * the callback is expected to be idempotent and side-effect-free.\n *\n * Intentionally split out from `configureAgentForRequest`: this is only\n * relevant to actual agent runs, not auxiliary flows like thread-name\n * generation (which has no need for MCP tools and shouldn't pay the\n * `listTools` round-trip).\n */\nexport async function attachIntelligenceEnterpriseLearning(params: {\n runtime: CopilotRuntimeLike;\n request: Request;\n agent: AbstractAgent;\n}): Promise<void> {\n const { runtime, request } = params;\n const agent = params.agent as MiddlewareCapableAgent;\n\n if (\n !isIntelligenceRuntime(runtime) ||\n !runtime.intelligence?.ɵisEnterpriseLearningEnabled?.()\n ) {\n return;\n }\n\n // Enterprise learning is enabled, but this agent's framework can't take\n // middleware — surface it rather than silently shipping a run with none\n // of the tools the operator opted into.\n if (typeof agent.use !== \"function\") {\n logger.warn(\n \"CopilotKitIntelligence.enableEnterpriseLearning is enabled, but the agent \" +\n \"does not support middleware (no `.use()` method); Intelligence tools were \" +\n \"not attached for this run.\",\n );\n return;\n }\n\n const userResult = await resolveIntelligenceUser({ runtime, request });\n if (userResult instanceof Response) return;\n\n agent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${runtime.intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${runtime.intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_USER_ID_HEADER]: userResult.id,\n },\n },\n ]),\n );\n}\n\nexport async function parseRunRequest(\n request: Request,\n): Promise<RunAgentInput | Response> {\n try {\n const requestBody = await request.json();\n return RunAgentInputSchema.parse(requestBody);\n } catch (error) {\n logger.error(\"Invalid run request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n\nexport async function parseConnectRequest(request: Request): Promise<\n | Response\n | {\n input: RunAgentInput;\n lastSeenEventId: string | null;\n }\n> {\n try {\n const requestBody = await request.json();\n const input = RunAgentInputSchema.parse(requestBody);\n let lastSeenEventId: string | null = null;\n\n if (\n \"lastSeenEventId\" in (requestBody as Record<string, unknown>) &&\n (typeof (requestBody as Record<string, unknown>).lastSeenEventId ===\n \"string\" ||\n (requestBody as Record<string, unknown>).lastSeenEventId === null)\n ) {\n lastSeenEventId =\n (requestBody as ConnectRequestBody).lastSeenEventId ?? null;\n }\n\n return { input, lastSeenEventId };\n } catch (error) {\n logger.error(\"Invalid connect request body:\", error);\n return new Response(\n JSON.stringify({\n error: \"Invalid request body\",\n details: error instanceof Error ? error.message : String(error),\n }),\n {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -23,11 +23,15 @@ async function cloneAgentForRequest(runtime, agentId, request) {
|
|
|
23
23
|
return agents[agentId].clone();
|
|
24
24
|
}
|
|
25
25
|
function configureAgentForRequest(params) {
|
|
26
|
-
const { runtime, request, agentId } = params;
|
|
26
|
+
const { runtime, request, agentId, providerA2UIHasCatalog } = params;
|
|
27
27
|
const agent = params.agent;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const a2uiEnabledByCatalog = !!providerA2UIHasCatalog && runtime.a2ui?.enabled !== false;
|
|
29
|
+
if (isA2UIEnabled(runtime.a2ui) || a2uiEnabledByCatalog) {
|
|
30
|
+
const { agents: targetAgents, enabled: _enabled, injectA2UITool, ...a2uiOptions } = runtime.a2ui ?? {};
|
|
31
|
+
if ((!targetAgents || targetAgents.includes(agentId)) && typeof agent.use === "function") agent.use(new A2UIMiddleware({
|
|
32
|
+
...a2uiOptions,
|
|
33
|
+
injectA2UITool: injectA2UITool ?? (providerA2UIHasCatalog ? true : void 0)
|
|
34
|
+
}));
|
|
31
35
|
}
|
|
32
36
|
if (runtime.mcpApps?.servers?.length) {
|
|
33
37
|
const mcpServers = runtime.mcpApps.servers.filter((server) => !server.agentId || server.agentId === agentId).map((server) => {
|