@copilotkit/runtime 1.54.1 → 1.55.0-next.7
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/.eslintrc.js +4 -4
- package/CHANGELOG.md +113 -113
- package/dist/_virtual/_rolldown/runtime.mjs +25 -1
- package/dist/agent/index.cjs +643 -0
- package/dist/agent/index.cjs.map +1 -0
- package/dist/agent/index.d.cts +263 -0
- package/dist/agent/index.d.cts.map +1 -0
- package/dist/agent/index.d.mts +263 -0
- package/dist/agent/index.d.mts.map +1 -0
- package/dist/agent/index.mjs +635 -0
- package/dist/agent/index.mjs.map +1 -0
- package/dist/graphql/message-conversion/agui-to-gql.cjs.map +1 -1
- package/dist/graphql/message-conversion/agui-to-gql.mjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.cjs +2 -2
- package/dist/lib/integrations/nextjs/app-router.cjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.mjs +1 -1
- package/dist/lib/integrations/nextjs/app-router.mjs.map +1 -1
- package/dist/lib/integrations/node-http/index.cjs +2 -3
- package/dist/lib/integrations/node-http/index.cjs.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +1 -1
- package/dist/lib/integrations/node-http/index.mjs.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts +2 -2
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts +3 -3
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +7 -5
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +10 -8
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +10 -8
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +7 -5
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.cjs +2 -2
- package/dist/lib/runtime/telemetry-agent-runner.cjs.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.cts +2 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.cts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.mts +2 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.mts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs.map +1 -1
- package/dist/lib/telemetry-client.cjs +1 -1
- package/dist/lib/telemetry-client.mjs +1 -1
- package/dist/package.cjs +21 -4
- package/dist/package.mjs +21 -4
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +1 -1
- package/dist/v2/index.cjs +41 -15
- package/dist/v2/index.d.cts +14 -2
- package/dist/v2/index.d.mts +14 -2
- package/dist/v2/index.mjs +13 -4
- package/dist/v2/runtime/endpoints/express-single.cjs +190 -0
- package/dist/v2/runtime/endpoints/express-single.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.d.cts +16 -0
- package/dist/v2/runtime/endpoints/express-single.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.d.mts +16 -0
- package/dist/v2/runtime/endpoints/express-single.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.mjs +187 -0
- package/dist/v2/runtime/endpoints/express-single.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-utils.cjs +119 -0
- package/dist/v2/runtime/endpoints/express-utils.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-utils.mjs +117 -0
- package/dist/v2/runtime/endpoints/express-utils.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/express.cjs +217 -0
- package/dist/v2/runtime/endpoints/express.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express.d.cts +16 -0
- package/dist/v2/runtime/endpoints/express.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/express.d.mts +16 -0
- package/dist/v2/runtime/endpoints/express.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/express.mjs +214 -0
- package/dist/v2/runtime/endpoints/express.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.cjs +141 -0
- package/dist/v2/runtime/endpoints/hono-single.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.d.cts +41 -0
- package/dist/v2/runtime/endpoints/hono-single.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.d.mts +41 -0
- package/dist/v2/runtime/endpoints/hono-single.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.mjs +140 -0
- package/dist/v2/runtime/endpoints/hono-single.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono.cjs +248 -0
- package/dist/v2/runtime/endpoints/hono.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono.d.cts +164 -0
- package/dist/v2/runtime/endpoints/hono.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/hono.d.mts +164 -0
- package/dist/v2/runtime/endpoints/hono.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/hono.mjs +247 -0
- package/dist/v2/runtime/endpoints/hono.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/index.d.cts +5 -0
- package/dist/v2/runtime/endpoints/index.d.mts +5 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs +68 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs +65 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs.map +1 -0
- package/dist/v2/runtime/handlers/get-runtime-info.cjs +51 -0
- package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -0
- package/dist/v2/runtime/handlers/get-runtime-info.mjs +51 -0
- package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-connect.cjs +49 -0
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-connect.mjs +49 -0
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs +61 -0
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.mjs +61 -0
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-stop.cjs +47 -0
- package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-stop.mjs +46 -0
- package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-transcribe.cjs +112 -0
- package/dist/v2/runtime/handlers/handle-transcribe.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-transcribe.mjs +111 -0
- package/dist/v2/runtime/handlers/handle-transcribe.mjs.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.cjs +26 -0
- package/dist/v2/runtime/handlers/header-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.mjs +25 -0
- package/dist/v2/runtime/handlers/header-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/connect.cjs +37 -0
- package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/connect.mjs +37 -0
- package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs +89 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs +88 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +146 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +145 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/threads.cjs +159 -0
- package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/threads.mjs +154 -0
- package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +74 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +70 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +21 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +20 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/json-response.cjs +12 -0
- package/dist/v2/runtime/handlers/shared/json-response.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/json-response.mjs +10 -0
- package/dist/v2/runtime/handlers/shared/json-response.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +20 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +20 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +69 -0
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +68 -0
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/connect.cjs +18 -0
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/connect.mjs +18 -0
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/run.cjs +18 -0
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/run.mjs +18 -0
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -0
- package/dist/v2/runtime/index.d.cts +13 -0
- package/dist/v2/runtime/index.d.mts +14 -0
- package/dist/v2/runtime/intelligence-platform/client.cjs +333 -0
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts +336 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts +336 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.mjs +331 -0
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/index.d.mts +2 -0
- package/dist/v2/runtime/middleware-sse-parser.cjs +138 -0
- package/dist/v2/runtime/middleware-sse-parser.cjs.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.d.cts +22 -0
- package/dist/v2/runtime/middleware-sse-parser.d.cts.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.d.mts +22 -0
- package/dist/v2/runtime/middleware-sse-parser.d.mts.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.mjs +137 -0
- package/dist/v2/runtime/middleware-sse-parser.mjs.map +1 -0
- package/dist/v2/runtime/middleware.cjs +35 -0
- package/dist/v2/runtime/middleware.cjs.map +1 -0
- package/dist/v2/runtime/middleware.d.cts +32 -0
- package/dist/v2/runtime/middleware.d.cts.map +1 -0
- package/dist/v2/runtime/middleware.d.mts +32 -0
- package/dist/v2/runtime/middleware.d.mts.map +1 -0
- package/dist/v2/runtime/middleware.mjs +33 -0
- package/dist/v2/runtime/middleware.mjs.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.cjs +8 -0
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.cts +32 -0
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.mts +32 -0
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.mjs +7 -0
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -0
- package/dist/v2/runtime/runner/in-memory.cjs +223 -0
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -0
- package/dist/v2/runtime/runner/in-memory.d.cts +15 -0
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -0
- package/dist/v2/runtime/runner/in-memory.d.mts +15 -0
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -0
- package/dist/v2/runtime/runner/in-memory.mjs +222 -0
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -0
- package/dist/v2/runtime/runner/index.d.cts +6 -0
- package/dist/v2/runtime/runner/index.d.mts +6 -0
- package/dist/v2/runtime/runner/index.mjs +7 -0
- package/dist/v2/runtime/runner/intelligence.cjs +246 -0
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -0
- package/dist/v2/runtime/runner/intelligence.d.cts +57 -0
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -0
- package/dist/v2/runtime/runner/intelligence.d.mts +57 -0
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -0
- package/dist/v2/runtime/runner/intelligence.mjs +245 -0
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -0
- package/dist/v2/runtime/runtime.cjs +101 -0
- package/dist/v2/runtime/runtime.cjs.map +1 -0
- package/dist/v2/runtime/runtime.d.cts +132 -0
- package/dist/v2/runtime/runtime.d.cts.map +1 -0
- package/dist/v2/runtime/runtime.d.mts +133 -0
- package/dist/v2/runtime/runtime.d.mts.map +1 -0
- package/dist/v2/runtime/runtime.mjs +97 -0
- package/dist/v2/runtime/runtime.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/scarf-client.cjs +32 -0
- package/dist/v2/runtime/telemetry/scarf-client.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/scarf-client.mjs +32 -0
- package/dist/v2/runtime/telemetry/scarf-client.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +35 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +35 -0
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.cjs +8 -0
- package/dist/v2/runtime/transcription-service/transcription-service.cjs.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.cts +15 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.cts.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.mts +15 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.mts.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.mjs +7 -0
- package/dist/v2/runtime/transcription-service/transcription-service.mjs.map +1 -0
- package/package.json +24 -7
- package/src/agent/__tests__/ai-sdk-v6-compat.test.ts +116 -0
- package/src/agent/__tests__/basic-agent.test.ts +1248 -0
- package/src/agent/__tests__/config-tools-execution.test.ts +516 -0
- package/src/agent/__tests__/mcp-clients.test.ts +260 -0
- package/src/agent/__tests__/property-overrides.test.ts +598 -0
- package/src/agent/__tests__/standard-schema-tools.test.ts +313 -0
- package/src/agent/__tests__/standard-schema-types.test.ts +158 -0
- package/src/agent/__tests__/state-tools.test.ts +436 -0
- package/src/agent/__tests__/test-helpers.ts +178 -0
- package/src/agent/__tests__/utils.test.ts +536 -0
- package/src/agent/__tests__/zod-regression.test.ts +350 -0
- package/src/agent/index.ts +1305 -0
- package/src/graphql/message-conversion/agui-to-gql.test.ts +1 -1
- package/src/graphql/message-conversion/agui-to-gql.ts +1 -1
- package/src/graphql/message-conversion/gql-to-agui.ts +1 -1
- package/src/graphql/message-conversion/roundtrip-conversion.test.ts +1 -1
- package/src/lib/integrations/nextjs/app-router.ts +2 -2
- package/src/lib/integrations/node-http/index.ts +2 -2
- package/src/lib/runtime/copilot-runtime.ts +3 -5
- package/src/lib/runtime/telemetry-agent-runner.ts +1 -1
- package/src/service-adapters/conversion.test.ts +1 -1
- package/src/service-adapters/conversion.ts +1 -28
- package/src/v2/index.ts +5 -2
- package/src/v2/runtime/__tests__/cors-credentials.test.ts +320 -0
- package/src/v2/runtime/__tests__/express-abort-signal.test.ts +25 -0
- package/src/v2/runtime/__tests__/express-body-order.test.ts +76 -0
- package/src/v2/runtime/__tests__/express-single-sse.test.ts +122 -0
- package/src/v2/runtime/__tests__/get-runtime-info.test.ts +141 -0
- package/src/v2/runtime/__tests__/handle-connect.test.ts +423 -0
- package/src/v2/runtime/__tests__/handle-run.test.ts +910 -0
- package/src/v2/runtime/__tests__/handle-threads.test.ts +388 -0
- package/src/v2/runtime/__tests__/handle-transcribe.test.ts +301 -0
- package/src/v2/runtime/__tests__/header-utils.test.ts +88 -0
- package/src/v2/runtime/__tests__/in-process-agent-runner-messages.test.ts +230 -0
- package/src/v2/runtime/__tests__/in-process-agent-runner.test.ts +1030 -0
- package/src/v2/runtime/__tests__/middleware-express.test.ts +206 -0
- package/src/v2/runtime/__tests__/middleware-single-express.test.ts +211 -0
- package/src/v2/runtime/__tests__/middleware-single.test.ts +225 -0
- package/src/v2/runtime/__tests__/middleware-sse-parser.test.ts +187 -0
- package/src/v2/runtime/__tests__/middleware.test.ts +251 -0
- package/src/v2/runtime/__tests__/routing-express.test.ts +174 -0
- package/src/v2/runtime/__tests__/routing-single-express.test.ts +168 -0
- package/src/v2/runtime/__tests__/routing-single.test.ts +193 -0
- package/src/v2/runtime/__tests__/routing.test.ts +257 -0
- package/src/v2/runtime/__tests__/runtime.test.ts +123 -0
- package/src/v2/runtime/__tests__/telemetry.test.ts +167 -0
- package/src/v2/runtime/__tests__/thread-names.test.ts +188 -0
- package/src/v2/runtime/endpoints/express-single.ts +231 -0
- package/src/v2/runtime/endpoints/express-utils.ts +182 -0
- package/src/v2/runtime/endpoints/express.ts +275 -0
- package/src/v2/runtime/endpoints/hono-single.ts +212 -0
- package/src/v2/runtime/endpoints/hono.ts +314 -0
- package/src/v2/runtime/endpoints/index.ts +4 -0
- package/src/v2/runtime/endpoints/single-route-helpers.ts +125 -0
- package/src/v2/runtime/express.ts +2 -0
- package/src/v2/runtime/handler.ts +3 -0
- package/src/v2/runtime/handlers/get-runtime-info.ts +79 -0
- package/src/v2/runtime/handlers/handle-connect.ts +76 -0
- package/src/v2/runtime/handlers/handle-run.ts +89 -0
- package/src/v2/runtime/handlers/handle-stop.ts +76 -0
- package/src/v2/runtime/handlers/handle-threads.ts +7 -0
- package/src/v2/runtime/handlers/handle-transcribe.ts +256 -0
- package/src/v2/runtime/handlers/header-utils.ts +24 -0
- package/src/v2/runtime/handlers/intelligence/connect.ts +65 -0
- package/src/v2/runtime/handlers/intelligence/run.ts +152 -0
- package/src/v2/runtime/handlers/intelligence/thread-names.ts +246 -0
- package/src/v2/runtime/handlers/intelligence/threads.ts +233 -0
- package/src/v2/runtime/handlers/shared/agent-utils.ts +136 -0
- package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -0
- package/src/v2/runtime/handlers/shared/json-response.ts +6 -0
- package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +25 -0
- package/src/v2/runtime/handlers/shared/sse-response.ts +100 -0
- package/src/v2/runtime/handlers/sse/connect.ts +24 -0
- package/src/v2/runtime/handlers/sse/run.ts +27 -0
- package/src/v2/runtime/index.ts +20 -0
- package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +605 -0
- package/src/v2/runtime/intelligence-platform/client.ts +659 -0
- package/src/v2/runtime/intelligence-platform/index.ts +10 -0
- package/src/v2/runtime/middleware-sse-parser.ts +200 -0
- package/src/v2/runtime/middleware.ts +115 -0
- package/src/v2/runtime/runner/__tests__/finalize-events.test.ts +109 -0
- package/src/v2/runtime/runner/__tests__/in-memory-runner.e2e.test.ts +775 -0
- package/src/v2/runtime/runner/__tests__/in-memory-runner.test.ts +363 -0
- package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +981 -0
- package/src/v2/runtime/runner/agent-runner.ts +36 -0
- package/src/v2/runtime/runner/in-memory.ts +381 -0
- package/src/v2/runtime/runner/index.ts +4 -0
- package/src/v2/runtime/runner/intelligence.ts +429 -0
- package/src/v2/runtime/runtime.ts +260 -0
- package/src/v2/runtime/telemetry/events.ts +35 -0
- package/src/v2/runtime/telemetry/index.ts +7 -0
- package/src/v2/runtime/telemetry/scarf-client.ts +39 -0
- package/src/v2/runtime/telemetry/telemetry-client.ts +70 -0
- package/src/v2/runtime/transcription-service/transcription-service.ts +11 -0
- package/tsconfig.json +9 -2
- package/tsdown.config.ts +1 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
handleArchiveThread,
|
|
5
|
+
handleDeleteThread,
|
|
6
|
+
handleListThreads,
|
|
7
|
+
handleSubscribeToThreads,
|
|
8
|
+
handleUpdateThread,
|
|
9
|
+
} from "../handlers/handle-threads";
|
|
10
|
+
import { CopilotRuntime } from "../runtime";
|
|
11
|
+
|
|
12
|
+
describe("thread handlers", () => {
|
|
13
|
+
const createIdentifyUser = () => vi.fn().mockResolvedValue({ id: "user-1" });
|
|
14
|
+
|
|
15
|
+
const createIntelligenceRuntime = (options?: {
|
|
16
|
+
identifyUser?: (
|
|
17
|
+
request: Request,
|
|
18
|
+
) => { id: string } | Promise<{ id: string }>;
|
|
19
|
+
intelligence?: Record<string, unknown>;
|
|
20
|
+
}) =>
|
|
21
|
+
({
|
|
22
|
+
agents: Promise.resolve({}),
|
|
23
|
+
transcriptionService: undefined,
|
|
24
|
+
beforeRequestMiddleware: undefined,
|
|
25
|
+
afterRequestMiddleware: undefined,
|
|
26
|
+
runner: {
|
|
27
|
+
run: vi.fn(),
|
|
28
|
+
connect: vi.fn(),
|
|
29
|
+
isRunning: vi.fn(),
|
|
30
|
+
stop: vi.fn(),
|
|
31
|
+
},
|
|
32
|
+
mode: "intelligence",
|
|
33
|
+
generateThreadNames: false,
|
|
34
|
+
identifyUser: options?.identifyUser ?? createIdentifyUser(),
|
|
35
|
+
intelligence: options?.intelligence,
|
|
36
|
+
}) as unknown as CopilotRuntime;
|
|
37
|
+
|
|
38
|
+
const createMutationRequest = (
|
|
39
|
+
path: string,
|
|
40
|
+
method: "PATCH" | "POST" | "DELETE",
|
|
41
|
+
body: Record<string, unknown>,
|
|
42
|
+
) =>
|
|
43
|
+
new Request(`https://example.com${path}`, {
|
|
44
|
+
method,
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify(body),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("returns 422 when intelligence is not configured for listThreads", async () => {
|
|
50
|
+
const runtime = new CopilotRuntime({ agents: {} });
|
|
51
|
+
|
|
52
|
+
const response = await handleListThreads({
|
|
53
|
+
runtime,
|
|
54
|
+
request: new Request("https://example.com/threads?agentId=agent-1"),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(response.status).toBe(422);
|
|
58
|
+
await expect(response.json()).resolves.toEqual({
|
|
59
|
+
error:
|
|
60
|
+
"Missing CopilotKitIntelligence configuration. Thread operations require a CopilotKitIntelligence instance to be provided in CopilotRuntime options.",
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("lists threads using identifyUser and the request agentId", async () => {
|
|
65
|
+
const intelligence = {
|
|
66
|
+
listThreads: vi.fn().mockResolvedValue({
|
|
67
|
+
threads: [{ id: "thread-1", name: "Hello" }],
|
|
68
|
+
joinCode: "jc-1",
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
const identifyUser = createIdentifyUser();
|
|
72
|
+
const runtime = createIntelligenceRuntime({ intelligence, identifyUser });
|
|
73
|
+
const request = new Request("https://example.com/threads?agentId=agent-1");
|
|
74
|
+
|
|
75
|
+
const response = await handleListThreads({
|
|
76
|
+
runtime,
|
|
77
|
+
request,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(response.status).toBe(200);
|
|
81
|
+
expect(identifyUser).toHaveBeenCalledTimes(1);
|
|
82
|
+
expect(identifyUser).toHaveBeenCalledWith(request);
|
|
83
|
+
expect(intelligence.listThreads).toHaveBeenCalledWith({
|
|
84
|
+
userId: "user-1",
|
|
85
|
+
agentId: "agent-1",
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("returns 400 when identifyUser returns an invalid id for thread list", async () => {
|
|
90
|
+
const intelligence = {
|
|
91
|
+
listThreads: vi.fn(),
|
|
92
|
+
};
|
|
93
|
+
const runtime = createIntelligenceRuntime({
|
|
94
|
+
intelligence,
|
|
95
|
+
identifyUser: vi.fn().mockResolvedValue({ id: "" }),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const response = await handleListThreads({
|
|
99
|
+
runtime,
|
|
100
|
+
request: new Request("https://example.com/threads?agentId=agent-1"),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(response.status).toBe(400);
|
|
104
|
+
expect(intelligence.listThreads).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("returns 500 when identifyUser throws for thread subscription", async () => {
|
|
108
|
+
const intelligence = {
|
|
109
|
+
ɵsubscribeToThreads: vi.fn(),
|
|
110
|
+
};
|
|
111
|
+
const runtime = createIntelligenceRuntime({
|
|
112
|
+
intelligence,
|
|
113
|
+
identifyUser: vi.fn().mockRejectedValue(new Error("auth failed")),
|
|
114
|
+
});
|
|
115
|
+
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const response = await handleSubscribeToThreads({
|
|
119
|
+
runtime,
|
|
120
|
+
request: new Request("https://example.com/threads/subscribe", {
|
|
121
|
+
method: "POST",
|
|
122
|
+
}),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(response.status).toBe(500);
|
|
126
|
+
expect(intelligence.ɵsubscribeToThreads).not.toHaveBeenCalled();
|
|
127
|
+
} finally {
|
|
128
|
+
errorSpy.mockRestore();
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("updates, archives, and deletes threads using identifyUser and ignoring request userId", async () => {
|
|
133
|
+
const intelligence = {
|
|
134
|
+
updateThread: vi
|
|
135
|
+
.fn()
|
|
136
|
+
.mockResolvedValue({ id: "thread-1", name: "Renamed" }),
|
|
137
|
+
archiveThread: vi.fn().mockResolvedValue(undefined),
|
|
138
|
+
deleteThread: vi.fn().mockResolvedValue(undefined),
|
|
139
|
+
};
|
|
140
|
+
const identifyUser = createIdentifyUser();
|
|
141
|
+
const runtime = createIntelligenceRuntime({ intelligence, identifyUser });
|
|
142
|
+
const mutationBody = {
|
|
143
|
+
userId: "ignored-user",
|
|
144
|
+
agentId: "agent-1",
|
|
145
|
+
name: "Renamed",
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const updateRequest = createMutationRequest(
|
|
149
|
+
"/threads/thread-1",
|
|
150
|
+
"PATCH",
|
|
151
|
+
mutationBody,
|
|
152
|
+
);
|
|
153
|
+
const updateResponse = await handleUpdateThread({
|
|
154
|
+
runtime,
|
|
155
|
+
request: updateRequest,
|
|
156
|
+
threadId: "thread-1",
|
|
157
|
+
});
|
|
158
|
+
expect(updateResponse.status).toBe(200);
|
|
159
|
+
expect(identifyUser).toHaveBeenCalledWith(updateRequest);
|
|
160
|
+
expect(intelligence.updateThread).toHaveBeenCalledWith({
|
|
161
|
+
threadId: "thread-1",
|
|
162
|
+
userId: "user-1",
|
|
163
|
+
agentId: "agent-1",
|
|
164
|
+
updates: { name: "Renamed" },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const archiveRequest = createMutationRequest(
|
|
168
|
+
"/threads/thread-1/archive",
|
|
169
|
+
"POST",
|
|
170
|
+
mutationBody,
|
|
171
|
+
);
|
|
172
|
+
const archiveResponse = await handleArchiveThread({
|
|
173
|
+
runtime,
|
|
174
|
+
request: archiveRequest,
|
|
175
|
+
threadId: "thread-1",
|
|
176
|
+
});
|
|
177
|
+
expect(archiveResponse.status).toBe(200);
|
|
178
|
+
expect(identifyUser).toHaveBeenCalledWith(archiveRequest);
|
|
179
|
+
expect(intelligence.archiveThread).toHaveBeenCalledWith({
|
|
180
|
+
threadId: "thread-1",
|
|
181
|
+
userId: "user-1",
|
|
182
|
+
agentId: "agent-1",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const deleteRequest = createMutationRequest(
|
|
186
|
+
"/threads/thread-1",
|
|
187
|
+
"DELETE",
|
|
188
|
+
mutationBody,
|
|
189
|
+
);
|
|
190
|
+
const deleteResponse = await handleDeleteThread({
|
|
191
|
+
runtime,
|
|
192
|
+
request: deleteRequest,
|
|
193
|
+
threadId: "thread-1",
|
|
194
|
+
});
|
|
195
|
+
expect(deleteResponse.status).toBe(200);
|
|
196
|
+
expect(identifyUser).toHaveBeenCalledWith(deleteRequest);
|
|
197
|
+
expect(identifyUser).toHaveBeenCalledTimes(3);
|
|
198
|
+
expect(intelligence.deleteThread).toHaveBeenCalledWith({
|
|
199
|
+
threadId: "thread-1",
|
|
200
|
+
userId: "user-1",
|
|
201
|
+
agentId: "agent-1",
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("subscribes to threads using identifyUser", async () => {
|
|
206
|
+
const intelligence = {
|
|
207
|
+
ɵsubscribeToThreads: vi
|
|
208
|
+
.fn()
|
|
209
|
+
.mockResolvedValue({ joinToken: "join-token-1" }),
|
|
210
|
+
};
|
|
211
|
+
const identifyUser = createIdentifyUser();
|
|
212
|
+
const runtime = createIntelligenceRuntime({ intelligence, identifyUser });
|
|
213
|
+
const request = new Request("https://example.com/threads/subscribe", {
|
|
214
|
+
method: "POST",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const response = await handleSubscribeToThreads({
|
|
218
|
+
runtime,
|
|
219
|
+
request,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(response.status).toBe(200);
|
|
223
|
+
expect(identifyUser).toHaveBeenCalledTimes(1);
|
|
224
|
+
expect(identifyUser).toHaveBeenCalledWith(request);
|
|
225
|
+
await expect(response.json()).resolves.toEqual({
|
|
226
|
+
joinToken: "join-token-1",
|
|
227
|
+
});
|
|
228
|
+
expect(intelligence.ɵsubscribeToThreads).toHaveBeenCalledWith({
|
|
229
|
+
userId: "user-1",
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("returns 400 when agentId is invalid for thread mutations", async () => {
|
|
234
|
+
const intelligence = {
|
|
235
|
+
updateThread: vi.fn(),
|
|
236
|
+
};
|
|
237
|
+
const runtime = createIntelligenceRuntime({ intelligence });
|
|
238
|
+
|
|
239
|
+
const response = await handleUpdateThread({
|
|
240
|
+
runtime,
|
|
241
|
+
request: new Request("https://example.com/threads/thread-1", {
|
|
242
|
+
method: "PATCH",
|
|
243
|
+
headers: { "Content-Type": "application/json" },
|
|
244
|
+
body: JSON.stringify({ agentId: "" }),
|
|
245
|
+
}),
|
|
246
|
+
threadId: "thread-1",
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(response.status).toBe(400);
|
|
250
|
+
expect(intelligence.updateThread).not.toHaveBeenCalled();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("returns 400 when identifyUser returns an invalid id for thread mutations", async () => {
|
|
254
|
+
const intelligence = {
|
|
255
|
+
updateThread: vi.fn(),
|
|
256
|
+
archiveThread: vi.fn(),
|
|
257
|
+
deleteThread: vi.fn(),
|
|
258
|
+
};
|
|
259
|
+
const runtime = createIntelligenceRuntime({
|
|
260
|
+
intelligence,
|
|
261
|
+
identifyUser: vi.fn().mockResolvedValue({ id: "" }),
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const updateResponse = await handleUpdateThread({
|
|
265
|
+
runtime,
|
|
266
|
+
request: createMutationRequest("/threads/thread-1", "PATCH", {
|
|
267
|
+
agentId: "agent-1",
|
|
268
|
+
}),
|
|
269
|
+
threadId: "thread-1",
|
|
270
|
+
});
|
|
271
|
+
expect(updateResponse.status).toBe(400);
|
|
272
|
+
|
|
273
|
+
const archiveResponse = await handleArchiveThread({
|
|
274
|
+
runtime,
|
|
275
|
+
request: createMutationRequest("/threads/thread-1/archive", "POST", {
|
|
276
|
+
agentId: "agent-1",
|
|
277
|
+
}),
|
|
278
|
+
threadId: "thread-1",
|
|
279
|
+
});
|
|
280
|
+
expect(archiveResponse.status).toBe(400);
|
|
281
|
+
|
|
282
|
+
const deleteResponse = await handleDeleteThread({
|
|
283
|
+
runtime,
|
|
284
|
+
request: createMutationRequest("/threads/thread-1", "DELETE", {
|
|
285
|
+
agentId: "agent-1",
|
|
286
|
+
}),
|
|
287
|
+
threadId: "thread-1",
|
|
288
|
+
});
|
|
289
|
+
expect(deleteResponse.status).toBe(400);
|
|
290
|
+
|
|
291
|
+
expect(intelligence.updateThread).not.toHaveBeenCalled();
|
|
292
|
+
expect(intelligence.archiveThread).not.toHaveBeenCalled();
|
|
293
|
+
expect(intelligence.deleteThread).not.toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("returns 422 when intelligence is not configured for thread mutations", async () => {
|
|
297
|
+
const runtime = new CopilotRuntime({ agents: {} });
|
|
298
|
+
const mutationRequest = new Request(
|
|
299
|
+
"https://example.com/threads/thread-1",
|
|
300
|
+
{
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: { "Content-Type": "application/json" },
|
|
303
|
+
body: JSON.stringify({ userId: "user-1", agentId: "agent-1" }),
|
|
304
|
+
},
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
const updateResponse = await handleUpdateThread({
|
|
308
|
+
runtime,
|
|
309
|
+
request: mutationRequest.clone(),
|
|
310
|
+
threadId: "thread-1",
|
|
311
|
+
});
|
|
312
|
+
expect(updateResponse.status).toBe(422);
|
|
313
|
+
|
|
314
|
+
const archiveResponse = await handleArchiveThread({
|
|
315
|
+
runtime,
|
|
316
|
+
request: mutationRequest.clone(),
|
|
317
|
+
threadId: "thread-1",
|
|
318
|
+
});
|
|
319
|
+
expect(archiveResponse.status).toBe(422);
|
|
320
|
+
|
|
321
|
+
const deleteResponse = await handleDeleteThread({
|
|
322
|
+
runtime,
|
|
323
|
+
request: mutationRequest.clone(),
|
|
324
|
+
threadId: "thread-1",
|
|
325
|
+
});
|
|
326
|
+
expect(deleteResponse.status).toBe(422);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it("returns 422 when intelligence is not configured for thread subscription", async () => {
|
|
330
|
+
const runtime = new CopilotRuntime({ agents: {} });
|
|
331
|
+
|
|
332
|
+
const response = await handleSubscribeToThreads({
|
|
333
|
+
runtime,
|
|
334
|
+
request: new Request("https://example.com/threads/subscribe", {
|
|
335
|
+
method: "POST",
|
|
336
|
+
}),
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
expect(response.status).toBe(422);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it("forwards includeArchived, limit, and cursor query params to listThreads", async () => {
|
|
343
|
+
const intelligence = {
|
|
344
|
+
listThreads: vi.fn().mockResolvedValue({
|
|
345
|
+
threads: [{ id: "thread-1", name: "Hello" }],
|
|
346
|
+
joinCode: "jc-1",
|
|
347
|
+
nextCursor: "cursor-xyz",
|
|
348
|
+
}),
|
|
349
|
+
};
|
|
350
|
+
const identifyUser = createIdentifyUser();
|
|
351
|
+
const runtime = createIntelligenceRuntime({ intelligence, identifyUser });
|
|
352
|
+
const request = new Request(
|
|
353
|
+
"https://example.com/threads?agentId=agent-1&includeArchived=true&limit=10&cursor=prev-cursor",
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
const response = await handleListThreads({ runtime, request });
|
|
357
|
+
|
|
358
|
+
expect(response.status).toBe(200);
|
|
359
|
+
expect(intelligence.listThreads).toHaveBeenCalledWith({
|
|
360
|
+
userId: "user-1",
|
|
361
|
+
agentId: "agent-1",
|
|
362
|
+
includeArchived: true,
|
|
363
|
+
limit: 10,
|
|
364
|
+
cursor: "prev-cursor",
|
|
365
|
+
});
|
|
366
|
+
const body = await response.json();
|
|
367
|
+
expect(body.nextCursor).toBe("cursor-xyz");
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("omits includeArchived, limit, and cursor when not provided", async () => {
|
|
371
|
+
const intelligence = {
|
|
372
|
+
listThreads: vi.fn().mockResolvedValue({
|
|
373
|
+
threads: [],
|
|
374
|
+
joinCode: "jc-1",
|
|
375
|
+
}),
|
|
376
|
+
};
|
|
377
|
+
const identifyUser = createIdentifyUser();
|
|
378
|
+
const runtime = createIntelligenceRuntime({ intelligence, identifyUser });
|
|
379
|
+
const request = new Request("https://example.com/threads?agentId=agent-1");
|
|
380
|
+
|
|
381
|
+
await handleListThreads({ runtime, request });
|
|
382
|
+
|
|
383
|
+
expect(intelligence.listThreads).toHaveBeenCalledWith({
|
|
384
|
+
userId: "user-1",
|
|
385
|
+
agentId: "agent-1",
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
});
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { handleTranscribe } from "../handlers/handle-transcribe";
|
|
2
|
+
import { CopilotRuntime } from "../runtime";
|
|
3
|
+
import {
|
|
4
|
+
TranscriptionService,
|
|
5
|
+
TranscribeFileOptions,
|
|
6
|
+
} from "../transcription-service/transcription-service";
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
|
|
9
|
+
// Mock TranscriptionService
|
|
10
|
+
class MockTranscriptionService extends TranscriptionService {
|
|
11
|
+
public lastOptions?: TranscribeFileOptions;
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
private shouldThrow = false,
|
|
15
|
+
private returnText = "Mock transcription",
|
|
16
|
+
) {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async transcribeFile(options: TranscribeFileOptions): Promise<string> {
|
|
21
|
+
this.lastOptions = options;
|
|
22
|
+
if (this.shouldThrow) {
|
|
23
|
+
throw new Error("Transcription service error");
|
|
24
|
+
}
|
|
25
|
+
return this.returnText;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("handleTranscribe", () => {
|
|
30
|
+
const createMockRuntime = (
|
|
31
|
+
transcriptionService?: TranscriptionService,
|
|
32
|
+
): CopilotRuntime => {
|
|
33
|
+
return {
|
|
34
|
+
agents: Promise.resolve({}),
|
|
35
|
+
transcriptionService,
|
|
36
|
+
beforeRequestMiddleware: undefined,
|
|
37
|
+
afterRequestMiddleware: undefined,
|
|
38
|
+
} as CopilotRuntime;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const createMockAudioFile = (
|
|
42
|
+
name = "test.mp3",
|
|
43
|
+
type = "audio/mpeg",
|
|
44
|
+
size = 1024,
|
|
45
|
+
): File => {
|
|
46
|
+
const content = new Uint8Array(size);
|
|
47
|
+
return new File([content], name, { type });
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const createFormDataRequest = (audioFile?: File): Request => {
|
|
51
|
+
const formData = new FormData();
|
|
52
|
+
if (audioFile) {
|
|
53
|
+
formData.append("audio", audioFile);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new Request("https://example.com/transcribe", {
|
|
57
|
+
method: "POST",
|
|
58
|
+
body: formData,
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const createJsonRequest = (): Request => {
|
|
63
|
+
return new Request("https://example.com/transcribe", {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { "Content-Type": "application/json" },
|
|
66
|
+
body: JSON.stringify({ test: "data" }),
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
it("should successfully transcribe an audio file", async () => {
|
|
71
|
+
const mockService = new MockTranscriptionService(false, "Hello world");
|
|
72
|
+
const runtime = createMockRuntime(mockService);
|
|
73
|
+
const audioFile = createMockAudioFile("test.mp3", "audio/mpeg", 2048);
|
|
74
|
+
const request = createFormDataRequest(audioFile);
|
|
75
|
+
|
|
76
|
+
const response = await handleTranscribe({ runtime, request });
|
|
77
|
+
|
|
78
|
+
expect(response.status).toBe(200);
|
|
79
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
80
|
+
|
|
81
|
+
const body = await response.json();
|
|
82
|
+
expect(body).toEqual({
|
|
83
|
+
text: "Hello world",
|
|
84
|
+
size: 2048,
|
|
85
|
+
type: "audio/mpeg",
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should return 503 when transcription service is not configured", async () => {
|
|
90
|
+
const runtime = createMockRuntime(); // No transcription service
|
|
91
|
+
const audioFile = createMockAudioFile();
|
|
92
|
+
const request = createFormDataRequest(audioFile);
|
|
93
|
+
|
|
94
|
+
const response = await handleTranscribe({ runtime, request });
|
|
95
|
+
|
|
96
|
+
expect(response.status).toBe(503);
|
|
97
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
98
|
+
|
|
99
|
+
const body = await response.json();
|
|
100
|
+
expect(body).toEqual({
|
|
101
|
+
error: "service_not_configured",
|
|
102
|
+
message: "Transcription service is not configured",
|
|
103
|
+
retryable: false,
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should return 400 when request is not form data", async () => {
|
|
108
|
+
const mockService = new MockTranscriptionService();
|
|
109
|
+
const runtime = createMockRuntime(mockService);
|
|
110
|
+
const request = createJsonRequest();
|
|
111
|
+
|
|
112
|
+
const response = await handleTranscribe({ runtime, request });
|
|
113
|
+
|
|
114
|
+
expect(response.status).toBe(400);
|
|
115
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
116
|
+
|
|
117
|
+
const body = await response.json();
|
|
118
|
+
expect(body).toEqual({
|
|
119
|
+
error: "invalid_request",
|
|
120
|
+
message:
|
|
121
|
+
"Request must include 'audio' field with base64-encoded audio data",
|
|
122
|
+
retryable: false,
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should return 400 when no audio file is provided", async () => {
|
|
127
|
+
const mockService = new MockTranscriptionService();
|
|
128
|
+
const runtime = createMockRuntime(mockService);
|
|
129
|
+
const request = createFormDataRequest(); // No audio file
|
|
130
|
+
|
|
131
|
+
const response = await handleTranscribe({ runtime, request });
|
|
132
|
+
|
|
133
|
+
expect(response.status).toBe(400);
|
|
134
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
135
|
+
|
|
136
|
+
const body = await response.json();
|
|
137
|
+
expect(body).toEqual({
|
|
138
|
+
error: "invalid_request",
|
|
139
|
+
message:
|
|
140
|
+
"No audio file found in form data. Please include an 'audio' field.",
|
|
141
|
+
retryable: false,
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should accept various valid audio file types", async () => {
|
|
146
|
+
const mockService = new MockTranscriptionService();
|
|
147
|
+
const runtime = createMockRuntime(mockService);
|
|
148
|
+
|
|
149
|
+
const validTypes = [
|
|
150
|
+
"audio/mpeg",
|
|
151
|
+
"audio/mp3",
|
|
152
|
+
"audio/mp4",
|
|
153
|
+
"audio/wav",
|
|
154
|
+
"audio/webm",
|
|
155
|
+
"audio/ogg",
|
|
156
|
+
"audio/flac",
|
|
157
|
+
"audio/aac",
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
for (const type of validTypes) {
|
|
161
|
+
const audioFile = createMockAudioFile(`test.${type.split("/")[1]}`, type);
|
|
162
|
+
const request = createFormDataRequest(audioFile);
|
|
163
|
+
|
|
164
|
+
const response = await handleTranscribe({ runtime, request });
|
|
165
|
+
expect(response.status).toBe(200);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should accept files with empty type (some browsers/systems)", async () => {
|
|
170
|
+
const mockService = new MockTranscriptionService();
|
|
171
|
+
const runtime = createMockRuntime(mockService);
|
|
172
|
+
const audioFile = createMockAudioFile("test.mp3", ""); // Empty type
|
|
173
|
+
const request = createFormDataRequest(audioFile);
|
|
174
|
+
|
|
175
|
+
const response = await handleTranscribe({ runtime, request });
|
|
176
|
+
|
|
177
|
+
expect(response.status).toBe(200);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should accept files with application/octet-stream type (fallback)", async () => {
|
|
181
|
+
const mockService = new MockTranscriptionService();
|
|
182
|
+
const runtime = createMockRuntime(mockService);
|
|
183
|
+
const audioFile = createMockAudioFile(
|
|
184
|
+
"test.mp3",
|
|
185
|
+
"application/octet-stream",
|
|
186
|
+
);
|
|
187
|
+
const request = createFormDataRequest(audioFile);
|
|
188
|
+
|
|
189
|
+
const response = await handleTranscribe({ runtime, request });
|
|
190
|
+
|
|
191
|
+
expect(response.status).toBe(200);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should return 400 for invalid file types", async () => {
|
|
195
|
+
const mockService = new MockTranscriptionService();
|
|
196
|
+
const runtime = createMockRuntime(mockService);
|
|
197
|
+
const audioFile = createMockAudioFile("test.txt", "text/plain");
|
|
198
|
+
const request = createFormDataRequest(audioFile);
|
|
199
|
+
|
|
200
|
+
const response = await handleTranscribe({ runtime, request });
|
|
201
|
+
|
|
202
|
+
expect(response.status).toBe(400);
|
|
203
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
204
|
+
|
|
205
|
+
const body = await response.json();
|
|
206
|
+
expect(body.error).toBe("invalid_audio_format");
|
|
207
|
+
expect(body.message).toContain("Unsupported audio format: text/plain");
|
|
208
|
+
expect(body.retryable).toBe(false);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should return 500 when transcription service throws an error", async () => {
|
|
212
|
+
const mockService = new MockTranscriptionService(true); // Will throw error
|
|
213
|
+
const runtime = createMockRuntime(mockService);
|
|
214
|
+
const audioFile = createMockAudioFile();
|
|
215
|
+
const request = createFormDataRequest(audioFile);
|
|
216
|
+
|
|
217
|
+
const response = await handleTranscribe({ runtime, request });
|
|
218
|
+
|
|
219
|
+
expect(response.status).toBe(500);
|
|
220
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
221
|
+
|
|
222
|
+
const body = await response.json();
|
|
223
|
+
expect(body).toEqual({
|
|
224
|
+
error: "provider_error",
|
|
225
|
+
message: "Transcription service error",
|
|
226
|
+
retryable: true,
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should handle form data parsing errors gracefully", async () => {
|
|
231
|
+
const mockService = new MockTranscriptionService();
|
|
232
|
+
const runtime = createMockRuntime(mockService);
|
|
233
|
+
|
|
234
|
+
// Create a request with malformed form data
|
|
235
|
+
const request = new Request("https://example.com/transcribe", {
|
|
236
|
+
method: "POST",
|
|
237
|
+
headers: { "Content-Type": "multipart/form-data; boundary=invalid" },
|
|
238
|
+
body: "invalid form data",
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const response = await handleTranscribe({ runtime, request });
|
|
242
|
+
|
|
243
|
+
expect(response.status).toBe(500);
|
|
244
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
245
|
+
|
|
246
|
+
const body = await response.json();
|
|
247
|
+
expect(body.error).toBe("provider_error");
|
|
248
|
+
expect(body.retryable).toBe(true);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("should handle non-File objects in form data", async () => {
|
|
252
|
+
const mockService = new MockTranscriptionService();
|
|
253
|
+
const runtime = createMockRuntime(mockService);
|
|
254
|
+
|
|
255
|
+
const formData = new FormData();
|
|
256
|
+
formData.append("audio", "not a file"); // String instead of File
|
|
257
|
+
|
|
258
|
+
const request = new Request("https://example.com/transcribe", {
|
|
259
|
+
method: "POST",
|
|
260
|
+
body: formData,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const response = await handleTranscribe({ runtime, request });
|
|
264
|
+
|
|
265
|
+
expect(response.status).toBe(400);
|
|
266
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
267
|
+
|
|
268
|
+
const body = await response.json();
|
|
269
|
+
expect(body).toEqual({
|
|
270
|
+
error: "invalid_request",
|
|
271
|
+
message:
|
|
272
|
+
"No audio file found in form data. Please include an 'audio' field.",
|
|
273
|
+
retryable: false,
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should pass file metadata to transcription service", async () => {
|
|
278
|
+
const mockService = new MockTranscriptionService();
|
|
279
|
+
const runtime = createMockRuntime(mockService);
|
|
280
|
+
const audioFile = createMockAudioFile(
|
|
281
|
+
"my-recording.wav",
|
|
282
|
+
"audio/wav",
|
|
283
|
+
2048,
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
const request = createFormDataRequest(audioFile);
|
|
287
|
+
|
|
288
|
+
const response = await handleTranscribe({ runtime, request });
|
|
289
|
+
|
|
290
|
+
expect(response.status).toBe(200);
|
|
291
|
+
expect(mockService.lastOptions).toEqual({
|
|
292
|
+
audioFile: expect.objectContaining({
|
|
293
|
+
name: "my-recording.wav",
|
|
294
|
+
type: "audio/wav",
|
|
295
|
+
size: 2048,
|
|
296
|
+
}),
|
|
297
|
+
mimeType: "audio/wav",
|
|
298
|
+
size: 2048,
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
});
|