@copilotkit/aimock 1.16.3 → 1.17.0
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +30 -0
- package/README.md +10 -10
- package/dist/a2a-mock.d.cts +2 -2
- package/dist/a2a-mock.d.cts.map +1 -1
- package/dist/a2a-mock.d.ts +2 -2
- package/dist/a2a-mock.d.ts.map +1 -1
- package/dist/a2a-mock.js +2 -2
- package/dist/a2a-mock.js.map +1 -1
- package/dist/agui-handler.cjs +120 -5
- package/dist/agui-handler.cjs.map +1 -1
- package/dist/agui-handler.d.cts +41 -5
- package/dist/agui-handler.d.cts.map +1 -1
- package/dist/agui-handler.d.ts +41 -5
- package/dist/agui-handler.d.ts.map +1 -1
- package/dist/agui-handler.js +114 -6
- package/dist/agui-handler.js.map +1 -1
- package/dist/agui-mock.cjs +18 -7
- package/dist/agui-mock.cjs.map +1 -1
- package/dist/agui-mock.d.cts +2 -2
- package/dist/agui-mock.d.cts.map +1 -1
- package/dist/agui-mock.d.ts +2 -2
- package/dist/agui-mock.d.ts.map +1 -1
- package/dist/agui-mock.js +20 -9
- package/dist/agui-mock.js.map +1 -1
- package/dist/agui-recorder.cjs +43 -22
- package/dist/agui-recorder.cjs.map +1 -1
- package/dist/agui-recorder.d.cts +4 -3
- package/dist/agui-recorder.d.cts.map +1 -1
- package/dist/agui-recorder.d.ts +4 -3
- package/dist/agui-recorder.d.ts.map +1 -1
- package/dist/agui-recorder.js +45 -24
- package/dist/agui-recorder.js.map +1 -1
- package/dist/agui-stub.cjs +28 -0
- package/dist/agui-stub.d.cts +5 -0
- package/dist/agui-stub.d.ts +5 -0
- package/dist/agui-stub.js +5 -0
- package/dist/agui-types.d.cts +33 -6
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/agui-types.d.ts +33 -6
- package/dist/agui-types.d.ts.map +1 -1
- package/dist/aimock-cli.cjs +1 -1
- package/dist/aimock-cli.js +1 -1
- package/dist/aws-event-stream.d.cts +2 -2
- package/dist/aws-event-stream.d.cts.map +1 -1
- package/dist/aws-event-stream.d.ts +2 -2
- package/dist/aws-event-stream.d.ts.map +1 -1
- package/dist/bedrock-converse.d.cts +3 -3
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts +3 -3
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock.d.cts +3 -3
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts +3 -3
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/chaos.d.cts +3 -3
- package/dist/chaos.d.cts.map +1 -1
- package/dist/chaos.d.ts +3 -3
- package/dist/chaos.d.ts.map +1 -1
- package/dist/cli.cjs +6 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +6 -5
- package/dist/cli.js.map +1 -1
- package/dist/cohere.d.cts +2 -2
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts +2 -2
- package/dist/cohere.d.ts.map +1 -1
- package/dist/config-loader.cjs +3 -3
- package/dist/config-loader.d.cts +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/config-loader.d.ts +1 -1
- package/dist/config-loader.js +2 -2
- package/dist/convert-vidaimock.cjs +1 -1
- package/dist/convert-vidaimock.js +1 -1
- package/dist/convert.cjs +1 -1
- package/dist/convert.js +1 -1
- package/dist/elevenlabs-audio.cjs +209 -0
- package/dist/elevenlabs-audio.cjs.map +1 -0
- package/dist/elevenlabs-audio.d.cts +11 -0
- package/dist/elevenlabs-audio.d.cts.map +1 -0
- package/dist/elevenlabs-audio.d.ts +11 -0
- package/dist/elevenlabs-audio.d.ts.map +1 -0
- package/dist/elevenlabs-audio.js +209 -0
- package/dist/elevenlabs-audio.js.map +1 -0
- package/dist/embeddings.d.cts +2 -2
- package/dist/embeddings.d.cts.map +1 -1
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/fal-audio.cjs +477 -0
- package/dist/fal-audio.cjs.map +1 -0
- package/dist/fal-audio.d.cts +10 -0
- package/dist/fal-audio.d.cts.map +1 -0
- package/dist/fal-audio.d.ts +10 -0
- package/dist/fal-audio.d.ts.map +1 -0
- package/dist/fal-audio.js +474 -0
- package/dist/fal-audio.js.map +1 -0
- package/dist/fixture-loader.cjs +14 -1
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.js +14 -1
- package/dist/fixture-loader.js.map +1 -1
- package/dist/fixtures-remote.cjs +1 -1
- package/dist/fixtures-remote.js +1 -1
- package/dist/gemini-interactions.cjs +617 -0
- package/dist/gemini-interactions.cjs.map +1 -0
- package/dist/gemini-interactions.d.cts +46 -0
- package/dist/gemini-interactions.d.cts.map +1 -0
- package/dist/gemini-interactions.d.ts +46 -0
- package/dist/gemini-interactions.d.ts.map +1 -0
- package/dist/gemini-interactions.js +616 -0
- package/dist/gemini-interactions.js.map +1 -0
- package/dist/gemini.cjs +76 -0
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts +2 -2
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts +2 -2
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +77 -1
- package/dist/gemini.js.map +1 -1
- package/dist/helpers.cjs +24 -1
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +13 -3
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +13 -3
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +23 -2
- package/dist/helpers.js.map +1 -1
- package/dist/images.d.cts +2 -2
- package/dist/images.d.cts.map +1 -1
- package/dist/images.d.ts +2 -2
- package/dist/images.d.ts.map +1 -1
- package/dist/index.cjs +21 -4
- package/dist/index.d.cts +10 -7
- package/dist/index.d.ts +10 -7
- package/dist/index.js +10 -7
- package/dist/jest.cjs +1 -1
- package/dist/jest.js +1 -1
- package/dist/jsonrpc.d.cts +3 -3
- package/dist/jsonrpc.d.cts.map +1 -1
- package/dist/jsonrpc.d.ts +3 -3
- package/dist/jsonrpc.d.ts.map +1 -1
- package/dist/llmock.cjs +38 -2
- package/dist/llmock.cjs.map +1 -1
- package/dist/llmock.d.cts +4 -0
- package/dist/llmock.d.cts.map +1 -1
- package/dist/llmock.d.ts +4 -0
- package/dist/llmock.d.ts.map +1 -1
- package/dist/llmock.js +38 -2
- package/dist/llmock.js.map +1 -1
- package/dist/logger.cjs +5 -4
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.d.cts +1 -1
- package/dist/logger.d.cts.map +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +5 -4
- package/dist/logger.js.map +1 -1
- package/dist/mcp-mock.d.cts +2 -2
- package/dist/mcp-mock.d.cts.map +1 -1
- package/dist/mcp-mock.d.ts +2 -2
- package/dist/mcp-mock.d.ts.map +1 -1
- package/dist/mcp-mock.js +2 -2
- package/dist/mcp-mock.js.map +1 -1
- package/dist/messages.d.cts +2 -2
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts +2 -2
- package/dist/messages.d.ts.map +1 -1
- package/dist/moderation.d.cts +3 -3
- package/dist/moderation.d.cts.map +1 -1
- package/dist/moderation.d.ts +3 -3
- package/dist/moderation.d.ts.map +1 -1
- package/dist/ndjson-writer.d.cts +2 -2
- package/dist/ndjson-writer.d.cts.map +1 -1
- package/dist/ndjson-writer.d.ts +2 -2
- package/dist/ndjson-writer.d.ts.map +1 -1
- package/dist/ollama.d.cts +3 -3
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts +3 -3
- package/dist/ollama.d.ts.map +1 -1
- package/dist/recorder.cjs +64 -21
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.d.cts +2 -2
- package/dist/recorder.d.cts.map +1 -1
- package/dist/recorder.d.ts +2 -2
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +66 -23
- package/dist/recorder.js.map +1 -1
- package/dist/rerank.d.cts +3 -3
- package/dist/rerank.d.cts.map +1 -1
- package/dist/rerank.d.ts +3 -3
- package/dist/rerank.d.ts.map +1 -1
- package/dist/responses.d.cts +2 -2
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +2 -2
- package/dist/responses.d.ts.map +1 -1
- package/dist/router.cjs +3 -3
- package/dist/router.cjs.map +1 -1
- package/dist/router.js +3 -3
- package/dist/router.js.map +1 -1
- package/dist/search.d.cts +3 -3
- package/dist/search.d.cts.map +1 -1
- package/dist/search.d.ts +3 -3
- package/dist/search.d.ts.map +1 -1
- package/dist/server.cjs +170 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +173 -4
- package/dist/server.js.map +1 -1
- package/dist/speech.cjs +18 -9
- package/dist/speech.cjs.map +1 -1
- package/dist/speech.d.cts +2 -2
- package/dist/speech.d.cts.map +1 -1
- package/dist/speech.d.ts +2 -2
- package/dist/speech.d.ts.map +1 -1
- package/dist/speech.js +18 -9
- package/dist/speech.js.map +1 -1
- package/dist/sse-writer.d.cts +3 -3
- package/dist/sse-writer.d.cts.map +1 -1
- package/dist/sse-writer.d.ts +3 -3
- package/dist/sse-writer.d.ts.map +1 -1
- package/dist/stream-collapse.cjs +80 -9
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +11 -1
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +11 -1
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +80 -10
- package/dist/stream-collapse.js.map +1 -1
- package/dist/suite.cjs +1 -1
- package/dist/suite.d.cts +2 -2
- package/dist/suite.d.ts +2 -2
- package/dist/suite.js +1 -1
- package/dist/transcription.d.cts +2 -2
- package/dist/transcription.d.cts.map +1 -1
- package/dist/transcription.d.ts +2 -2
- package/dist/transcription.d.ts.map +1 -1
- package/dist/types.d.cts +10 -7
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +10 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-mock.d.cts +2 -2
- package/dist/vector-mock.d.cts.map +1 -1
- package/dist/vector-mock.d.ts +2 -2
- package/dist/vector-mock.d.ts.map +1 -1
- package/dist/vector-mock.js +2 -2
- package/dist/vector-mock.js.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/video.d.cts +3 -3
- package/dist/video.d.cts.map +1 -1
- package/dist/video.d.ts +3 -3
- package/dist/video.d.ts.map +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.js +1 -1
- package/dist/ws-framing.d.cts +2 -2
- package/dist/ws-framing.d.cts.map +1 -1
- package/dist/ws-framing.d.ts +2 -2
- package/dist/ws-framing.d.ts.map +1 -1
- package/dist/ws-gemini-live.cjs +145 -2
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +146 -3
- package/dist/ws-gemini-live.js.map +1 -1
- package/package.json +16 -2
- package/skills/write-fixtures/SKILL.md +10 -10
package/dist/vector-mock.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Journal } from "./journal.js";
|
|
|
2
2
|
import { MetricsRegistry } from "./metrics.js";
|
|
3
3
|
import { JournalEntry, Mountable } from "./types.js";
|
|
4
4
|
import { QueryResult, VectorEntry, VectorMockOptions, VectorQuery } from "./vector-types.js";
|
|
5
|
-
import * as http from "node:http";
|
|
5
|
+
import * as http$1 from "node:http";
|
|
6
6
|
|
|
7
7
|
//#region src/vector-mock.d.ts
|
|
8
8
|
declare class VectorMock implements Mountable {
|
|
@@ -20,7 +20,7 @@ declare class VectorMock implements Mountable {
|
|
|
20
20
|
upsert(collection: string, vectors: VectorEntry[]): this;
|
|
21
21
|
onQuery(collection: string, results: QueryResult[] | ((query: VectorQuery) => QueryResult[])): this;
|
|
22
22
|
deleteCollection(name: string): this;
|
|
23
|
-
handleRequest(req: http.IncomingMessage, res: http.ServerResponse, pathname: string): Promise<boolean>;
|
|
23
|
+
handleRequest(req: http$1.IncomingMessage, res: http$1.ServerResponse, pathname: string): Promise<boolean>;
|
|
24
24
|
health(): {
|
|
25
25
|
status: string;
|
|
26
26
|
collections: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-mock.d.ts","names":[],"sources":["../src/vector-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAea,UAAA,YAAsB;;EAAtB,QAAA,aAAW;EAAA,QAAA,MAAA;UASA,OAAA;UAkBc,QAAA;UAgBzB,OAAA;UAAyB,cAAA;aAAgB,CAAA,OAAA,CAAA,EAlC9B,iBAkC8B;eAiBxC,CAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IACL,SAAK,EAAA,MAAA;MAET,IAAA;QA2CiB,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EA/EgB,WA+EhB,EAAA,CAAA,EAAA,IAAA;SAIE,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAnEX,WAmEW,EAAA,GAAA,CAAA,CAAA,KAAA,EAnEc,WAmEd,EAAA,GAnE8B,WAmE9B,EAAA,CAAA,CAAA,EAAA,IAAA;kBAMP,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;eA4DD,CAAA,GAAA,EApHP,
|
|
1
|
+
{"version":3,"file":"vector-mock.d.ts","names":[],"sources":["../src/vector-mock.ts"],"sourcesContent":[],"mappings":";;;;;;;cAea,UAAA,YAAsB;;EAAtB,QAAA,aAAW;EAAA,QAAA,MAAA;UASA,OAAA;UAkBc,QAAA;UAgBzB,OAAA;UAAyB,cAAA;aAAgB,CAAA,OAAA,CAAA,EAlC9B,iBAkC8B;eAiBxC,CAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IACL,SAAK,EAAA,MAAA;MAET,IAAA;QA2CiB,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EA/EgB,WA+EhB,EAAA,CAAA,EAAA,IAAA;SAIE,CAAA,UAAA,EAAA,MAAA,EAAA,OAAA,EAnEX,WAmEW,EAAA,GAAA,CAAA,CAAA,KAAA,EAnEc,WAmEd,EAAA,GAnE8B,WAmE9B,EAAA,CAAA,CAAA,EAAA,IAAA;kBAMP,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;eA4DD,CAAA,GAAA,EApHP,MAAA,CAAK,eAoHE,EAAA,GAAA,EAnHP,MAAA,CAAK,cAmHE,EAAA,QAAA,EAAA,MAAA,CAAA,EAjHX,OAiHW,CAAA,OAAA,CAAA;QAaC,CAAA,CAAA,EAAA;IA7LkB,MAAA,EAAA,MAAA;IAAS,WAAA,EAAA,MAAA;;sBA0GtB;wBAIE;WAMP;UA4DD;iBAaC"}
|
package/dist/vector-mock.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { flattenHeaders, readBody } from "./helpers.js";
|
|
2
2
|
import { createVectorRequestHandler } from "./vector-handler.js";
|
|
3
|
-
import * as http from "node:http";
|
|
3
|
+
import * as http$1 from "node:http";
|
|
4
4
|
|
|
5
5
|
//#region src/vector-mock.ts
|
|
6
6
|
var VectorMock = class {
|
|
@@ -100,7 +100,7 @@ var VectorMock = class {
|
|
|
100
100
|
const host = this.options.host ?? "127.0.0.1";
|
|
101
101
|
const port = this.options.port ?? 0;
|
|
102
102
|
return new Promise((resolve, reject) => {
|
|
103
|
-
const srv = http.createServer((req, res) => {
|
|
103
|
+
const srv = http$1.createServer((req, res) => {
|
|
104
104
|
const chunks = [];
|
|
105
105
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
106
106
|
req.on("end", () => {
|
package/dist/vector-mock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-mock.js","names":[],"sources":["../src/vector-mock.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type { Mountable, JournalEntry } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\nimport type {\n VectorMockOptions,\n VectorCollection,\n VectorEntry,\n QueryResult,\n VectorQuery,\n QueryHandler,\n} from \"./vector-types.js\";\nimport { createVectorRequestHandler, type VectorState } from \"./vector-handler.js\";\nimport { flattenHeaders, readBody } from \"./helpers.js\";\n\nexport class VectorMock implements Mountable {\n private collections: Map<string, VectorCollection> = new Map();\n private queryHandlers: Map<string, QueryHandler> = new Map();\n private server: http.Server | null = null;\n private journal: Journal | null = null;\n private registry: MetricsRegistry | null = null;\n private options: VectorMockOptions;\n private requestHandler: ReturnType<typeof createVectorRequestHandler>;\n\n constructor(options?: VectorMockOptions) {\n this.options = options ?? {};\n this.requestHandler = this.buildHandler();\n }\n\n // ---- Configuration ----\n\n addCollection(name: string, opts: { dimension: number }): this {\n const collection: VectorCollection = {\n name,\n dimension: opts.dimension,\n vectors: new Map(),\n };\n this.collections.set(name, collection);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n upsert(collection: string, vectors: VectorEntry[]): this {\n let col = this.collections.get(collection);\n if (!col) {\n const dim = vectors.length > 0 ? vectors[0].values.length : 0;\n col = { name: collection, dimension: dim, vectors: new Map() };\n this.collections.set(collection, col);\n }\n for (const v of vectors) {\n col.vectors.set(v.id, v);\n }\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n onQuery(\n collection: string,\n results: QueryResult[] | ((query: VectorQuery) => QueryResult[]),\n ): this {\n this.queryHandlers.set(collection, results);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n deleteCollection(name: string): this {\n this.collections.delete(name);\n this.queryHandlers.delete(name);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n // ---- Mountable interface ----\n\n async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n const body = await readBody(req);\n let parsed: Record<string, unknown> = {};\n try {\n if (body) parsed = JSON.parse(body);\n } catch {\n if (req.method !== \"GET\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Malformed JSON body\" }));\n return true;\n }\n }\n\n const handled = this.requestHandler(req, res, pathname, parsed);\n\n // Record vector operation metric\n if (handled && this.registry) {\n const { operation, provider } = classifyVectorRequest(req.method ?? \"GET\", pathname);\n this.registry.incrementCounter(\"aimock_vector_requests_total\", { operation, provider });\n }\n\n // Journal the request after the handler completes\n if (handled && this.journal) {\n this.journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"vector\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n\n return handled;\n }\n\n health(): { status: string; collections: number } {\n return {\n status: \"ok\",\n collections: this.collections.size,\n };\n }\n\n setJournal(journal: Journal): void {\n this.journal = journal;\n }\n\n setRegistry(registry: MetricsRegistry): void {\n this.registry = registry;\n }\n\n // ---- Standalone mode ----\n\n async start(): Promise<string> {\n if (this.server) {\n throw new Error(\"Server already started\");\n }\n\n const host = this.options.host ?? \"127.0.0.1\";\n const port = this.options.port ?? 0;\n\n return new Promise((resolve, reject) => {\n const srv = http.createServer((req, res) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => {\n const body = Buffer.concat(chunks).toString();\n let parsed: Record<string, unknown> = {};\n try {\n if (body) parsed = JSON.parse(body);\n } catch {\n if (req.method !== \"GET\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Malformed JSON body\" }));\n return;\n }\n }\n\n const url = new URL(req.url ?? \"/\", `http://${host}`);\n\n const handled = this.requestHandler(req, res, url.pathname, parsed);\n\n if (handled && this.journal) {\n this.journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"vector\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n if (!handled) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n }\n });\n });\n\n srv.listen(port, host, () => {\n this.server = srv;\n const addr = srv.address();\n if (typeof addr === \"object\" && addr !== null) {\n resolve(`http://${host}:${addr.port}`);\n } else {\n resolve(`http://${host}:${port}`);\n }\n });\n\n srv.on(\"error\", reject);\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n throw new Error(\"Server not started\");\n }\n const srv = this.server;\n this.server = null;\n await new Promise<void>((resolve, reject) => {\n srv.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n // ---- Inspection ----\n\n getRequests(): JournalEntry[] {\n if (!this.journal) return [];\n return this.journal.getAll().filter((e) => e.service === \"vector\");\n }\n\n reset(): this {\n this.collections.clear();\n this.queryHandlers.clear();\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n // ---- Internal ----\n\n private buildHandler() {\n const state: VectorState = {\n collections: this.collections,\n queryHandlers: this.queryHandlers,\n };\n return createVectorRequestHandler(state);\n }\n}\n\n// ---- Helpers ----\n\n/**\n * Classify a vector request by operation and provider based on HTTP method and pathname.\n */\nfunction classifyVectorRequest(\n method: string,\n pathname: string,\n): { operation: string; provider: string } {\n // Pinecone paths\n if (pathname === \"/query\" && method === \"POST\") {\n return { operation: \"query\", provider: \"pinecone\" };\n }\n if (pathname === \"/vectors/upsert\" && method === \"POST\") {\n return { operation: \"upsert\", provider: \"pinecone\" };\n }\n if (pathname === \"/vectors/delete\" && method === \"POST\") {\n return { operation: \"delete\", provider: \"pinecone\" };\n }\n if (pathname === \"/describe-index-stats\" && method === \"GET\") {\n return { operation: \"describe\", provider: \"pinecone\" };\n }\n\n // Qdrant paths\n if (/^\\/collections\\/[^/]+\\/points\\/search$/.test(pathname) && method === \"POST\") {\n return { operation: \"query\", provider: \"qdrant\" };\n }\n if (/^\\/collections\\/[^/]+\\/points$/.test(pathname) && method === \"PUT\") {\n return { operation: \"upsert\", provider: \"qdrant\" };\n }\n if (/^\\/collections\\/[^/]+\\/points\\/delete$/.test(pathname) && method === \"POST\") {\n return { operation: \"delete\", provider: \"qdrant\" };\n }\n\n // ChromaDB paths\n if (/^\\/api\\/v1\\/collections\\/[^/]+\\/query$/.test(pathname) && method === \"POST\") {\n return { operation: \"query\", provider: \"chromadb\" };\n }\n if (/^\\/api\\/v1\\/collections\\/[^/]+\\/add$/.test(pathname) && method === \"POST\") {\n return { operation: \"upsert\", provider: \"chromadb\" };\n }\n if (pathname === \"/api/v1/collections\" && method === \"GET\") {\n return { operation: \"list\", provider: \"chromadb\" };\n }\n if (/^\\/api\\/v1\\/collections\\/[^/]+$/.test(pathname) && method === \"DELETE\") {\n return { operation: \"delete\", provider: \"chromadb\" };\n }\n\n return { operation: \"unknown\", provider: \"unknown\" };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vector-mock.js","names":["http"],"sources":["../src/vector-mock.ts"],"sourcesContent":["import * as http from \"node:http\";\nimport type { Mountable, JournalEntry } from \"./types.js\";\nimport type { Journal } from \"./journal.js\";\nimport type { MetricsRegistry } from \"./metrics.js\";\nimport type {\n VectorMockOptions,\n VectorCollection,\n VectorEntry,\n QueryResult,\n VectorQuery,\n QueryHandler,\n} from \"./vector-types.js\";\nimport { createVectorRequestHandler, type VectorState } from \"./vector-handler.js\";\nimport { flattenHeaders, readBody } from \"./helpers.js\";\n\nexport class VectorMock implements Mountable {\n private collections: Map<string, VectorCollection> = new Map();\n private queryHandlers: Map<string, QueryHandler> = new Map();\n private server: http.Server | null = null;\n private journal: Journal | null = null;\n private registry: MetricsRegistry | null = null;\n private options: VectorMockOptions;\n private requestHandler: ReturnType<typeof createVectorRequestHandler>;\n\n constructor(options?: VectorMockOptions) {\n this.options = options ?? {};\n this.requestHandler = this.buildHandler();\n }\n\n // ---- Configuration ----\n\n addCollection(name: string, opts: { dimension: number }): this {\n const collection: VectorCollection = {\n name,\n dimension: opts.dimension,\n vectors: new Map(),\n };\n this.collections.set(name, collection);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n upsert(collection: string, vectors: VectorEntry[]): this {\n let col = this.collections.get(collection);\n if (!col) {\n const dim = vectors.length > 0 ? vectors[0].values.length : 0;\n col = { name: collection, dimension: dim, vectors: new Map() };\n this.collections.set(collection, col);\n }\n for (const v of vectors) {\n col.vectors.set(v.id, v);\n }\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n onQuery(\n collection: string,\n results: QueryResult[] | ((query: VectorQuery) => QueryResult[]),\n ): this {\n this.queryHandlers.set(collection, results);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n deleteCollection(name: string): this {\n this.collections.delete(name);\n this.queryHandlers.delete(name);\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n // ---- Mountable interface ----\n\n async handleRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n pathname: string,\n ): Promise<boolean> {\n const body = await readBody(req);\n let parsed: Record<string, unknown> = {};\n try {\n if (body) parsed = JSON.parse(body);\n } catch {\n if (req.method !== \"GET\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Malformed JSON body\" }));\n return true;\n }\n }\n\n const handled = this.requestHandler(req, res, pathname, parsed);\n\n // Record vector operation metric\n if (handled && this.registry) {\n const { operation, provider } = classifyVectorRequest(req.method ?? \"GET\", pathname);\n this.registry.incrementCounter(\"aimock_vector_requests_total\", { operation, provider });\n }\n\n // Journal the request after the handler completes\n if (handled && this.journal) {\n this.journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"vector\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n\n return handled;\n }\n\n health(): { status: string; collections: number } {\n return {\n status: \"ok\",\n collections: this.collections.size,\n };\n }\n\n setJournal(journal: Journal): void {\n this.journal = journal;\n }\n\n setRegistry(registry: MetricsRegistry): void {\n this.registry = registry;\n }\n\n // ---- Standalone mode ----\n\n async start(): Promise<string> {\n if (this.server) {\n throw new Error(\"Server already started\");\n }\n\n const host = this.options.host ?? \"127.0.0.1\";\n const port = this.options.port ?? 0;\n\n return new Promise((resolve, reject) => {\n const srv = http.createServer((req, res) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => {\n const body = Buffer.concat(chunks).toString();\n let parsed: Record<string, unknown> = {};\n try {\n if (body) parsed = JSON.parse(body);\n } catch {\n if (req.method !== \"GET\") {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Malformed JSON body\" }));\n return;\n }\n }\n\n const url = new URL(req.url ?? \"/\", `http://${host}`);\n\n const handled = this.requestHandler(req, res, url.pathname, parsed);\n\n if (handled && this.journal) {\n this.journal.add({\n method: req.method ?? \"GET\",\n path: req.url ?? \"/\",\n headers: flattenHeaders(req.headers),\n body: null,\n service: \"vector\",\n response: { status: res.statusCode, fixture: null },\n });\n }\n if (!handled) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Not found\" }));\n }\n });\n });\n\n srv.listen(port, host, () => {\n this.server = srv;\n const addr = srv.address();\n if (typeof addr === \"object\" && addr !== null) {\n resolve(`http://${host}:${addr.port}`);\n } else {\n resolve(`http://${host}:${port}`);\n }\n });\n\n srv.on(\"error\", reject);\n });\n }\n\n async stop(): Promise<void> {\n if (!this.server) {\n throw new Error(\"Server not started\");\n }\n const srv = this.server;\n this.server = null;\n await new Promise<void>((resolve, reject) => {\n srv.close((err) => (err ? reject(err) : resolve()));\n });\n }\n\n // ---- Inspection ----\n\n getRequests(): JournalEntry[] {\n if (!this.journal) return [];\n return this.journal.getAll().filter((e) => e.service === \"vector\");\n }\n\n reset(): this {\n this.collections.clear();\n this.queryHandlers.clear();\n this.requestHandler = this.buildHandler();\n return this;\n }\n\n // ---- Internal ----\n\n private buildHandler() {\n const state: VectorState = {\n collections: this.collections,\n queryHandlers: this.queryHandlers,\n };\n return createVectorRequestHandler(state);\n }\n}\n\n// ---- Helpers ----\n\n/**\n * Classify a vector request by operation and provider based on HTTP method and pathname.\n */\nfunction classifyVectorRequest(\n method: string,\n pathname: string,\n): { operation: string; provider: string } {\n // Pinecone paths\n if (pathname === \"/query\" && method === \"POST\") {\n return { operation: \"query\", provider: \"pinecone\" };\n }\n if (pathname === \"/vectors/upsert\" && method === \"POST\") {\n return { operation: \"upsert\", provider: \"pinecone\" };\n }\n if (pathname === \"/vectors/delete\" && method === \"POST\") {\n return { operation: \"delete\", provider: \"pinecone\" };\n }\n if (pathname === \"/describe-index-stats\" && method === \"GET\") {\n return { operation: \"describe\", provider: \"pinecone\" };\n }\n\n // Qdrant paths\n if (/^\\/collections\\/[^/]+\\/points\\/search$/.test(pathname) && method === \"POST\") {\n return { operation: \"query\", provider: \"qdrant\" };\n }\n if (/^\\/collections\\/[^/]+\\/points$/.test(pathname) && method === \"PUT\") {\n return { operation: \"upsert\", provider: \"qdrant\" };\n }\n if (/^\\/collections\\/[^/]+\\/points\\/delete$/.test(pathname) && method === \"POST\") {\n return { operation: \"delete\", provider: \"qdrant\" };\n }\n\n // ChromaDB paths\n if (/^\\/api\\/v1\\/collections\\/[^/]+\\/query$/.test(pathname) && method === \"POST\") {\n return { operation: \"query\", provider: \"chromadb\" };\n }\n if (/^\\/api\\/v1\\/collections\\/[^/]+\\/add$/.test(pathname) && method === \"POST\") {\n return { operation: \"upsert\", provider: \"chromadb\" };\n }\n if (pathname === \"/api/v1/collections\" && method === \"GET\") {\n return { operation: \"list\", provider: \"chromadb\" };\n }\n if (/^\\/api\\/v1\\/collections\\/[^/]+$/.test(pathname) && method === \"DELETE\") {\n return { operation: \"delete\", provider: \"chromadb\" };\n }\n\n return { operation: \"unknown\", provider: \"unknown\" };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,
|
|
1
|
+
{"version":3,"file":"vector-types.d.ts","names":[],"sources":["../src/vector-types.ts"],"sourcesContent":[],"mappings":";UAAiB,iBAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAKA,IAAA,CAAA,EAAA,MAAA;;AAGM,UAHN,gBAAA,CAGM;MAAZ,EAAA,MAAA;EAAG,SAAA,EAAA,MAAA;EAGG,OAAA,EAHN,GAGM,CAAA,MAAW,EAHL,WAMV,CAAM;AAGnB;AAOiB,UAbA,WAAA,CAaW;EAOhB,EAAA,EAAA,MAAA;EAAY,MAAA,EAAA,MAAA,EAAA;UAAG,CAAA,EAjBd,MAiBc,CAAA,MAAA,EAAA,OAAA,CAAA;;AAAyC,UAdnD,WAAA,CAcmD;EAAW,EAAA,EAAA,MAAA;;aAXlE;;;UAII,WAAA;;;;;;KAOL,YAAA,GAAe,yBAAyB,gBAAgB"}
|
package/dist/video.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Journal } from "./journal.cjs";
|
|
2
2
|
import { Fixture, HandlerDefaults, VideoResponse } from "./types.cjs";
|
|
3
|
-
import * as http from "node:http";
|
|
3
|
+
import * as http$1 from "node:http";
|
|
4
4
|
|
|
5
5
|
//#region src/video.d.ts
|
|
6
6
|
|
|
@@ -18,8 +18,8 @@ declare class VideoStateMap {
|
|
|
18
18
|
clear(): void;
|
|
19
19
|
get size(): number;
|
|
20
20
|
}
|
|
21
|
-
declare function handleVideoCreate(req: http.IncomingMessage, res: http.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
|
|
22
|
-
declare function handleVideoStatus(req: http.IncomingMessage, res: http.ServerResponse, videoId: string, journal: Journal, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): void;
|
|
21
|
+
declare function handleVideoCreate(req: http$1.IncomingMessage, res: http$1.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
|
|
22
|
+
declare function handleVideoStatus(req: http$1.IncomingMessage, res: http$1.ServerResponse, videoId: string, journal: Journal, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): void;
|
|
23
23
|
//# sourceMappingURL=video.d.ts.map
|
|
24
24
|
|
|
25
25
|
//#endregion
|
package/dist/video.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,
|
|
1
|
+
{"version":3,"file":"video.d.cts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAA,MAAK,EAAA,KAAA,EA3Bc,aA2Bd,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA,OAAA;OAEA,CAAA,CAAA,EAAA,IAAA;MACD,IAAA,CAAA,CAAA,EAAA,MAAA;;AAEa,iBAPF,iBAAA,CAOO,GAAA,EANtB,MAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,MAAA,CAAK,cAKiB,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAHjB,OAGiB,EAAA,EAAA,OAAA,EAFlB,OAEkB,EAAA,QAAA,EADjB,eACiB,EAAA,cAAA,EAAA,CAAA,GAAA,EAAL,MAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAsLC,iBAAA,CAtLD,GAAA,EAuLR,MAAA,CAAK,eAvLG,EAAA,GAAA,EAwLR,MAAA,CAAK,cAxLG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EA0LJ,OA1LI,EAAA,cAAA,EAAA,CAAA,GAAA,EA2LS,MAAA,CAAK,cA3Ld,EAAA,GAAA,IAAA,EAAA,WAAA,EA4LA,aA5LA,CAAA,EAAA,IAAA"}
|
package/dist/video.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Journal } from "./journal.js";
|
|
2
2
|
import { Fixture, HandlerDefaults, VideoResponse } from "./types.js";
|
|
3
|
-
import * as http from "node:http";
|
|
3
|
+
import * as http$1 from "node:http";
|
|
4
4
|
|
|
5
5
|
//#region src/video.d.ts
|
|
6
6
|
|
|
@@ -18,8 +18,8 @@ declare class VideoStateMap {
|
|
|
18
18
|
clear(): void;
|
|
19
19
|
get size(): number;
|
|
20
20
|
}
|
|
21
|
-
declare function handleVideoCreate(req: http.IncomingMessage, res: http.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
|
|
22
|
-
declare function handleVideoStatus(req: http.IncomingMessage, res: http.ServerResponse, videoId: string, journal: Journal, setCorsHeaders: (res: http.ServerResponse) => void, videoStates: VideoStateMap): void;
|
|
21
|
+
declare function handleVideoCreate(req: http$1.IncomingMessage, res: http$1.ServerResponse, raw: string, fixtures: Fixture[], journal: Journal, defaults: HandlerDefaults, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): Promise<void>;
|
|
22
|
+
declare function handleVideoStatus(req: http$1.IncomingMessage, res: http$1.ServerResponse, videoId: string, journal: Journal, setCorsHeaders: (res: http$1.ServerResponse) => void, videoStates: VideoStateMap): void;
|
|
23
23
|
//# sourceMappingURL=video.d.ts.map
|
|
24
24
|
|
|
25
25
|
//#endregion
|
package/dist/video.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,
|
|
1
|
+
{"version":3,"file":"video.d.ts","names":[],"sources":["../src/video.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA+BA;;;;AAauC,cAb1B,aAAA,CAa0B;EA0BjB,iBAAA,OAAiB;EAAA,GAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EApCnB,aAoCmB,CAAA,OAAA,CAAA,GAAA,SAAA;KAChC,CAAA,GAAA,EAAA,MAAK,EAAA,KAAA,EA3Bc,aA2Bd,CAAA,OAAA,CAAA,CAAA,EAAA,IAAA;QACL,CAAA,GAAK,EAAA,MAAA,CAAA,EAAA,OAAA;OAEA,CAAA,CAAA,EAAA,IAAA;MACD,IAAA,CAAA,CAAA,EAAA,MAAA;;AAEa,iBAPF,iBAAA,CAOO,GAAA,EANtB,MAAA,CAAK,eAMiB,EAAA,GAAA,EALtB,MAAA,CAAK,cAKiB,EAAA,GAAA,EAAA,MAAA,EAAA,QAAA,EAHjB,OAGiB,EAAA,EAAA,OAAA,EAFlB,OAEkB,EAAA,QAAA,EADjB,eACiB,EAAA,cAAA,EAAA,CAAA,GAAA,EAAL,MAAA,CAAK,cAAA,EAAA,GAAA,IAAA,EAAA,WAAA,EACd,aADc,CAAA,EAE1B,OAF0B,CAAA,IAAA,CAAA;AACd,iBAsLC,iBAAA,CAtLD,GAAA,EAuLR,MAAA,CAAK,eAvLG,EAAA,GAAA,EAwLR,MAAA,CAAK,cAxLG,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EA0LJ,OA1LI,EAAA,cAAA,EAAA,CAAA,GAAA,EA2LS,MAAA,CAAK,cA3Ld,EAAA,GAAA,IAAA,EAAA,WAAA,EA4LA,aA5LA,CAAA,EAAA,IAAA"}
|
package/dist/vitest.cjs
CHANGED
|
@@ -2,8 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
3
3
|
const require_fixture_loader = require('./fixture-loader.cjs');
|
|
4
4
|
const require_llmock = require('./llmock.cjs');
|
|
5
|
-
let node_path = require("node:path");
|
|
6
5
|
let node_fs = require("node:fs");
|
|
6
|
+
let node_path = require("node:path");
|
|
7
7
|
let vitest = require("vitest");
|
|
8
8
|
|
|
9
9
|
//#region src/vitest.ts
|
package/dist/vitest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { loadFixtureFile, loadFixturesFromDir } from "./fixture-loader.js";
|
|
2
2
|
import { LLMock } from "./llmock.js";
|
|
3
|
-
import { resolve } from "node:path";
|
|
4
3
|
import { statSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
5
|
import { afterAll, beforeAll, beforeEach } from "vitest";
|
|
6
6
|
|
|
7
7
|
//#region src/vitest.ts
|
package/dist/ws-framing.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as http from "node:http";
|
|
1
|
+
import * as http$1 from "node:http";
|
|
2
2
|
import * as net from "node:net";
|
|
3
3
|
import { EventEmitter } from "node:events";
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ declare class WebSocketConnection extends EventEmitter {
|
|
|
19
19
|
private handleFrame;
|
|
20
20
|
}
|
|
21
21
|
declare function computeAcceptKey(wsKey: string): string;
|
|
22
|
-
declare function upgradeToWebSocket(req: http.IncomingMessage, socket: net.Socket): WebSocketConnection;
|
|
22
|
+
declare function upgradeToWebSocket(req: http$1.IncomingMessage, socket: net.Socket): WebSocketConnection;
|
|
23
23
|
//# sourceMappingURL=ws-framing.d.ts.map
|
|
24
24
|
//#endregion
|
|
25
25
|
export { WebSocketConnection, computeAcceptKey, upgradeToWebSocket };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-framing.d.cts","names":[],"sources":["../src/ws-framing.ts"],"sourcesContent":[],"mappings":";;;;;;AA+NgB,cAzMH,mBAAA,SAA4B,YAAA,CAyMT;EAMhB,QAAA,MAAA;EAAkB,QAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"ws-framing.d.cts","names":[],"sources":["../src/ws-framing.ts"],"sourcesContent":[],"mappings":";;;;;;AA+NgB,cAzMH,mBAAA,SAA4B,YAAA,CAyMT;EAMhB,QAAA,MAAA;EAAkB,QAAA,MAAA;UAC3B,MAAK;UACE,SAAA;aACX,CAAA,MAAA,EA1MmB,GAAA,CAAI,MA0MvB;EAAmB,IAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;;;;;;;;iBATN,gBAAA;iBAMA,kBAAA,MACT,MAAA,CAAK,yBACF,GAAA,CAAI,SACX"}
|
package/dist/ws-framing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as http from "node:http";
|
|
1
|
+
import * as http$1 from "node:http";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import * as net from "node:net";
|
|
4
4
|
|
|
@@ -19,7 +19,7 @@ declare class WebSocketConnection extends EventEmitter {
|
|
|
19
19
|
private handleFrame;
|
|
20
20
|
}
|
|
21
21
|
declare function computeAcceptKey(wsKey: string): string;
|
|
22
|
-
declare function upgradeToWebSocket(req: http.IncomingMessage, socket: net.Socket): WebSocketConnection;
|
|
22
|
+
declare function upgradeToWebSocket(req: http$1.IncomingMessage, socket: net.Socket): WebSocketConnection;
|
|
23
23
|
//# sourceMappingURL=ws-framing.d.ts.map
|
|
24
24
|
//#endregion
|
|
25
25
|
export { WebSocketConnection, computeAcceptKey, upgradeToWebSocket };
|
package/dist/ws-framing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-framing.d.ts","names":[],"sources":["../src/ws-framing.ts"],"sourcesContent":[],"mappings":";;;;;;AA+NgB,cAzMH,mBAAA,SAA4B,YAAA,CAyMT;EAMhB,QAAA,MAAA;EAAkB,QAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"ws-framing.d.ts","names":[],"sources":["../src/ws-framing.ts"],"sourcesContent":[],"mappings":";;;;;;AA+NgB,cAzMH,mBAAA,SAA4B,YAAA,CAyMT;EAMhB,QAAA,MAAA;EAAkB,QAAA,MAAA;UAC3B,MAAK;UACE,SAAA;aACX,CAAA,MAAA,EA1MmB,GAAA,CAAI,MA0MvB;EAAmB,IAAA,CAAA,IAAA,EAAA,MAAA,CAAA,EAAA,IAAA;;;;;;;;iBATN,gBAAA;iBAMA,kBAAA,MACT,MAAA,CAAK,yBACF,GAAA,CAAI,SACX"}
|
package/dist/ws-gemini-live.cjs
CHANGED
|
@@ -15,7 +15,7 @@ function geminiTurnsToMessages(turns) {
|
|
|
15
15
|
const role = turn.role ?? "user";
|
|
16
16
|
if (role === "user") {
|
|
17
17
|
const funcResponses = turn.parts.filter((p) => p.functionResponse);
|
|
18
|
-
const textParts = turn.parts.filter((p) => p.text !== void 0);
|
|
18
|
+
const textParts = turn.parts.filter((p) => p.text !== void 0 && !p.thought);
|
|
19
19
|
if (funcResponses.length > 0) {
|
|
20
20
|
for (let i = 0; i < funcResponses.length; i++) {
|
|
21
21
|
const fr = funcResponses[i].functionResponse;
|
|
@@ -38,7 +38,7 @@ function geminiTurnsToMessages(turns) {
|
|
|
38
38
|
}
|
|
39
39
|
} else if (role === "model") {
|
|
40
40
|
const funcCalls = turn.parts.filter((p) => p.functionCall);
|
|
41
|
-
const textParts = turn.parts.filter((p) => p.text !== void 0);
|
|
41
|
+
const textParts = turn.parts.filter((p) => p.text !== void 0 && !p.thought);
|
|
42
42
|
if (funcCalls.length > 0) messages.push({
|
|
43
43
|
role: "assistant",
|
|
44
44
|
content: null,
|
|
@@ -178,6 +178,16 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
|
|
|
178
178
|
if (!fixture) {
|
|
179
179
|
if (defaults.strict) {
|
|
180
180
|
defaults.logger.warn(`STRICT: No fixture matched for WebSocket message`);
|
|
181
|
+
journal.add({
|
|
182
|
+
method: "WS",
|
|
183
|
+
path,
|
|
184
|
+
headers: {},
|
|
185
|
+
body: completionReq,
|
|
186
|
+
response: {
|
|
187
|
+
status: 404,
|
|
188
|
+
fixture: null
|
|
189
|
+
}
|
|
190
|
+
});
|
|
181
191
|
ws.close(1008, "Strict mode: no fixture matched");
|
|
182
192
|
return;
|
|
183
193
|
}
|
|
@@ -221,6 +231,139 @@ async function processMessage(raw, ws, fixtures, journal, defaults, session) {
|
|
|
221
231
|
} }));
|
|
222
232
|
return;
|
|
223
233
|
}
|
|
234
|
+
if (require_helpers.isAudioResponse(response)) {
|
|
235
|
+
journal.add({
|
|
236
|
+
method: "WS",
|
|
237
|
+
path,
|
|
238
|
+
headers: {},
|
|
239
|
+
body: completionReq,
|
|
240
|
+
response: {
|
|
241
|
+
status: 200,
|
|
242
|
+
fixture
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
const audioResp = response;
|
|
246
|
+
let mimeType;
|
|
247
|
+
let data;
|
|
248
|
+
if (typeof audioResp.audio === "string") {
|
|
249
|
+
mimeType = require_helpers.formatToMime(audioResp.format ?? "mp3");
|
|
250
|
+
data = audioResp.audio;
|
|
251
|
+
} else {
|
|
252
|
+
mimeType = audioResp.audio.contentType ?? "audio/mpeg";
|
|
253
|
+
data = audioResp.audio.b64Json;
|
|
254
|
+
}
|
|
255
|
+
ws.send(JSON.stringify({ serverContent: {
|
|
256
|
+
modelTurn: { parts: [{ inlineData: {
|
|
257
|
+
mimeType,
|
|
258
|
+
data
|
|
259
|
+
} }] },
|
|
260
|
+
turnComplete: true
|
|
261
|
+
} }));
|
|
262
|
+
session.conversationHistory.push({
|
|
263
|
+
role: "assistant",
|
|
264
|
+
content: "[audio]"
|
|
265
|
+
});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (require_helpers.isContentWithToolCallsResponse(response)) {
|
|
269
|
+
const journalEntry = journal.add({
|
|
270
|
+
method: "WS",
|
|
271
|
+
path,
|
|
272
|
+
headers: {},
|
|
273
|
+
body: completionReq,
|
|
274
|
+
response: {
|
|
275
|
+
status: 200,
|
|
276
|
+
fixture
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
const content = response.content;
|
|
280
|
+
const chunkList = [];
|
|
281
|
+
for (let i = 0; i < content.length; i += chunkSize) chunkList.push(content.slice(i, i + chunkSize));
|
|
282
|
+
const interruption = require_interruption.createInterruptionSignal(fixture);
|
|
283
|
+
let interrupted = false;
|
|
284
|
+
if (content.length === 0) {
|
|
285
|
+
if (!ws.isClosed) ws.send(JSON.stringify({ serverContent: {
|
|
286
|
+
modelTurn: { parts: [{ text: "" }] },
|
|
287
|
+
turnComplete: false
|
|
288
|
+
} }));
|
|
289
|
+
} else for (let i = 0; i < chunkList.length; i++) {
|
|
290
|
+
if (ws.isClosed) break;
|
|
291
|
+
if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
|
|
292
|
+
if (interruption?.signal.aborted) {
|
|
293
|
+
interrupted = true;
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
if (ws.isClosed) break;
|
|
297
|
+
ws.send(JSON.stringify({ serverContent: {
|
|
298
|
+
modelTurn: { parts: [{ text: chunkList[i] }] },
|
|
299
|
+
turnComplete: false
|
|
300
|
+
} }));
|
|
301
|
+
interruption?.tick();
|
|
302
|
+
if (interruption?.signal.aborted) {
|
|
303
|
+
interrupted = true;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (interrupted) {
|
|
308
|
+
ws.destroy();
|
|
309
|
+
journalEntry.response.interrupted = true;
|
|
310
|
+
journalEntry.response.interruptReason = interruption?.reason();
|
|
311
|
+
interruption?.cleanup();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const resolvedToolCalls = response.toolCalls.map((tc) => ({
|
|
315
|
+
...tc,
|
|
316
|
+
resolvedId: tc.id ?? require_helpers.generateToolCallId()
|
|
317
|
+
}));
|
|
318
|
+
if (!ws.isClosed) {
|
|
319
|
+
if (latency > 0) await require_sse_writer.delay(latency, interruption?.signal);
|
|
320
|
+
if (interruption?.signal.aborted) {
|
|
321
|
+
ws.destroy();
|
|
322
|
+
journalEntry.response.interrupted = true;
|
|
323
|
+
journalEntry.response.interruptReason = interruption?.reason();
|
|
324
|
+
interruption?.cleanup();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const functionCalls = resolvedToolCalls.map((tc) => {
|
|
328
|
+
let argsObj;
|
|
329
|
+
try {
|
|
330
|
+
argsObj = JSON.parse(tc.arguments || "{}");
|
|
331
|
+
} catch {
|
|
332
|
+
defaults.logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
|
|
333
|
+
argsObj = {};
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
name: tc.name,
|
|
337
|
+
args: argsObj,
|
|
338
|
+
id: tc.resolvedId
|
|
339
|
+
};
|
|
340
|
+
});
|
|
341
|
+
ws.send(JSON.stringify({ toolCall: { functionCalls } }));
|
|
342
|
+
interruption?.tick();
|
|
343
|
+
}
|
|
344
|
+
if (interruption?.signal.aborted) {
|
|
345
|
+
ws.destroy();
|
|
346
|
+
journalEntry.response.interrupted = true;
|
|
347
|
+
journalEntry.response.interruptReason = interruption?.reason();
|
|
348
|
+
interruption?.cleanup();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
interruption?.cleanup();
|
|
352
|
+
if (!ws.isClosed) ws.send(JSON.stringify({ serverContent: { turnComplete: true } }));
|
|
353
|
+
session.conversationHistory.push({
|
|
354
|
+
role: "assistant",
|
|
355
|
+
content: content || null,
|
|
356
|
+
tool_calls: resolvedToolCalls.map((tc) => ({
|
|
357
|
+
id: tc.resolvedId,
|
|
358
|
+
type: "function",
|
|
359
|
+
function: {
|
|
360
|
+
name: tc.name,
|
|
361
|
+
arguments: tc.arguments
|
|
362
|
+
}
|
|
363
|
+
}))
|
|
364
|
+
});
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
224
367
|
if (require_helpers.isTextResponse(response)) {
|
|
225
368
|
const journalEntry = journal.add({
|
|
226
369
|
method: "WS",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-gemini-live.cjs","names":["DEFAULT_TEST_ID","matchFixture","isErrorResponse","isTextResponse","createInterruptionSignal","delay","isToolCallResponse"],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":["/**\n * WebSocket handler for Gemini Live BidiGenerateContent API.\n *\n * Accepts setup, clientContent, and toolResponse messages over WebSocket\n * and responds with setupComplete, serverContent, toolCall, and error\n * messages in the Gemini Live streaming format.\n */\n\nimport type { Fixture, ChatMessage, ChatCompletionRequest, ToolDefinition } from \"./types.js\";\nimport { matchFixture } from \"./router.js\";\nimport { isTextResponse, isToolCallResponse, isErrorResponse } from \"./helpers.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport { delay } from \"./sse-writer.js\";\nimport { DEFAULT_TEST_ID, type Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport type { WebSocketConnection } from \"./ws-framing.js\";\n\n// ─── Gemini Live protocol types ─────────────────────────────────────────────\n\ninterface GeminiLivePart {\n text?: string;\n functionCall?: { name: string; args: Record<string, unknown> };\n functionResponse?: { name: string; response: unknown; id?: string };\n}\n\ninterface GeminiLiveTurn {\n role: string;\n parts: GeminiLivePart[];\n}\n\ninterface GeminiLiveFunctionDeclaration {\n name: string;\n description?: string;\n parameters?: object;\n}\n\ninterface GeminiLiveToolDef {\n functionDeclarations?: GeminiLiveFunctionDeclaration[];\n}\n\ninterface GeminiLiveSetup {\n model?: string;\n generationConfig?: Record<string, unknown>;\n tools?: GeminiLiveToolDef[];\n}\n\ninterface GeminiLiveClientContent {\n turns: GeminiLiveTurn[];\n turnComplete?: boolean;\n}\n\ninterface GeminiLiveFunctionResponse {\n id?: string;\n name: string;\n response: unknown;\n}\n\ninterface GeminiLiveToolResponse {\n functionResponses: GeminiLiveFunctionResponse[];\n}\n\ninterface GeminiLiveMessage {\n setup?: GeminiLiveSetup;\n clientContent?: GeminiLiveClientContent;\n toolResponse?: GeminiLiveToolResponse;\n}\n\n// ─── Session state ──────────────────────────────────────────────────────────\n\ninterface SessionState {\n setupDone: boolean;\n model: string;\n tools: ToolDefinition[];\n conversationHistory: ChatMessage[];\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nconst WS_PATH = \"/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent\";\n\n/**\n * Convert Gemini Live turns into ChatMessage[] for fixture matching.\n */\nfunction geminiTurnsToMessages(turns: GeminiLiveTurn[]): ChatMessage[] {\n const messages: ChatMessage[] = [];\n\n for (const turn of turns) {\n const role = turn.role ?? \"user\";\n\n if (role === \"user\") {\n const funcResponses = turn.parts.filter((p) => p.functionResponse);\n const textParts = turn.parts.filter((p) => p.text !== undefined);\n\n if (funcResponses.length > 0) {\n for (let i = 0; i < funcResponses.length; i++) {\n const part = funcResponses[i];\n const fr = part.functionResponse!;\n messages.push({\n role: \"tool\",\n content: typeof fr.response === \"string\" ? fr.response : JSON.stringify(fr.response),\n tool_call_id: fr.id ?? `call_gemini_${fr.name}_${i}`,\n });\n }\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.map((p) => p.text!).join(\"\"),\n });\n }\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"user\", content: text });\n }\n } else if (role === \"model\") {\n const funcCalls = turn.parts.filter((p) => p.functionCall);\n const textParts = turn.parts.filter((p) => p.text !== undefined);\n\n if (funcCalls.length > 0) {\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: funcCalls.map((p, i) => ({\n id: `call_gemini_${p.functionCall!.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: p.functionCall!.name,\n arguments: JSON.stringify(p.functionCall!.args),\n },\n })),\n });\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"assistant\", content: text });\n }\n }\n }\n\n return messages;\n}\n\n/**\n * Convert toolResponse messages into ChatMessage[] for fixture matching.\n */\nfunction toolResponseToMessages(toolResponse: GeminiLiveToolResponse): ChatMessage[] {\n return toolResponse.functionResponses.map((fr, i) => ({\n role: \"tool\" as const,\n content: typeof fr.response === \"string\" ? fr.response : JSON.stringify(fr.response),\n tool_call_id: fr.id ?? `call_gemini_${fr.name}_${i}`,\n }));\n}\n\n/**\n * Convert Gemini tool definitions to ChatCompletion ToolDefinition[].\n */\nfunction convertTools(geminiTools?: GeminiLiveToolDef[]): ToolDefinition[] {\n if (!geminiTools || geminiTools.length === 0) return [];\n const decls = geminiTools.flatMap((t) => t.functionDeclarations ?? []);\n return decls.map((d) => ({\n type: \"function\" as const,\n function: {\n name: d.name,\n description: d.description,\n parameters: d.parameters,\n },\n }));\n}\n\n// ─── Main handler ───────────────────────────────────────────────────────────\n\nexport function handleWebSocketGeminiLive(\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n defaults: {\n latency: number;\n chunkSize: number;\n model: string;\n logger: Logger;\n strict?: boolean;\n requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;\n testId?: string;\n },\n): void {\n const { logger } = defaults;\n const session: SessionState = {\n setupDone: false,\n model: defaults.model,\n tools: [],\n conversationHistory: [],\n };\n\n let pending = Promise.resolve();\n ws.on(\"message\", (raw: string) => {\n pending = pending.then(() =>\n processMessage(raw, ws, fixtures, journal, defaults, session).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n logger.error(`WebSocket Gemini Live error: ${msg}`);\n try {\n ws.send(\n JSON.stringify({\n error: { code: 500, message: msg, status: \"INTERNAL\" },\n }),\n );\n } catch {\n // Connection already gone — original error already logged above\n }\n }),\n );\n });\n}\n\nasync function processMessage(\n raw: string,\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n defaults: {\n latency: number;\n chunkSize: number;\n model: string;\n logger: Logger;\n strict?: boolean;\n requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;\n testId?: string;\n },\n session: SessionState,\n): Promise<void> {\n let parsed: GeminiLiveMessage;\n try {\n parsed = JSON.parse(raw) as GeminiLiveMessage;\n } catch {\n ws.send(\n JSON.stringify({\n error: { code: 400, message: \"Malformed JSON\", status: \"INVALID_ARGUMENT\" },\n }),\n );\n return;\n }\n\n // Handle setup message\n if (parsed.setup) {\n session.setupDone = true;\n session.model = parsed.setup.model ?? defaults.model;\n session.tools = convertTools(parsed.setup.tools);\n ws.send(JSON.stringify({ setupComplete: {} }));\n return;\n }\n\n // Reject messages before setup\n if (!session.setupDone) {\n ws.send(\n JSON.stringify({\n error: { code: 400, message: \"Setup required\", status: \"FAILED_PRECONDITION\" },\n }),\n );\n return;\n }\n\n // Build messages from this interaction\n let newMessages: ChatMessage[];\n\n if (parsed.clientContent) {\n if (!parsed.clientContent.turns || !Array.isArray(parsed.clientContent.turns)) {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Missing 'turns' in clientContent\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n newMessages = geminiTurnsToMessages(parsed.clientContent.turns);\n } else if (parsed.toolResponse) {\n if (\n !parsed.toolResponse.functionResponses ||\n !Array.isArray(parsed.toolResponse.functionResponses)\n ) {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Missing 'functionResponses' in toolResponse\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n newMessages = toolResponseToMessages(parsed.toolResponse);\n } else {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Expected clientContent or toolResponse\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n\n // Build completion request for fixture matching (include new messages speculatively)\n const completionReq: ChatCompletionRequest = {\n model: session.model,\n messages: [...session.conversationHistory, ...newMessages],\n stream: true,\n tools: session.tools.length > 0 ? session.tools : undefined,\n };\n\n const testId = defaults.testId ?? DEFAULT_TEST_ID;\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n const path = WS_PATH;\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (!fixture) {\n if (defaults.strict) {\n defaults.logger.warn(`STRICT: No fixture matched for WebSocket message`);\n ws.close(1008, \"Strict mode: no fixture matched\");\n return;\n }\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 404, fixture: null },\n });\n ws.send(\n JSON.stringify({\n error: { code: 404, message: \"No fixture matched\", status: \"NOT_FOUND\" },\n }),\n );\n return;\n }\n\n // Commit messages to conversation history only after successful fixture match\n session.conversationHistory.push(...newMessages);\n\n const response = fixture.response;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status, fixture },\n });\n ws.send(\n JSON.stringify({\n error: { code: status, message: response.error.message, status: \"ERROR\" },\n }),\n );\n return;\n }\n\n // Text response — stream chunks with serverContent\n if (isTextResponse(response)) {\n const journalEntry = journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const content = response.content;\n\n if (content.length === 0) {\n if (ws.isClosed) return;\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: \"\" }] },\n turnComplete: true,\n },\n }),\n );\n return;\n }\n\n // Chunk the content\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n\n const interruption = createInterruptionSignal(fixture);\n let interrupted = false;\n\n for (let i = 0; i < chunks.length; i++) {\n if (ws.isClosed) break;\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n if (ws.isClosed) break;\n\n const isLast = i === chunks.length - 1;\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: chunks[i] }] },\n turnComplete: isLast,\n },\n }),\n );\n interruption?.tick();\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n }\n\n if (interrupted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n interruption?.cleanup();\n\n // Add assistant response to conversation history\n session.conversationHistory.push({ role: \"assistant\", content });\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n const journalEntry = journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const interruption = createInterruptionSignal(fixture);\n\n if (ws.isClosed) {\n interruption?.cleanup();\n return;\n }\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n if (ws.isClosed) {\n interruption?.cleanup();\n return;\n }\n\n const functionCalls = response.toolCalls.map((tc, i) => {\n let argsObj: Record<string, unknown>;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\") as Record<string, unknown>;\n } catch {\n defaults.logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n name: tc.name,\n args: argsObj,\n id: tc.id ?? `call_gemini_${tc.name}_${i}`,\n };\n });\n\n ws.send(JSON.stringify({ toolCall: { functionCalls } }));\n interruption?.tick();\n\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n interruption?.cleanup();\n\n // Add assistant tool_calls to conversation history\n session.conversationHistory.push({\n role: \"assistant\",\n content: null,\n tool_calls: response.toolCalls.map((tc, i) => ({\n id: tc.id ?? `call_gemini_${tc.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: tc.arguments,\n },\n })),\n });\n return;\n }\n\n // Unknown response type\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 500, fixture },\n });\n ws.send(\n JSON.stringify({\n error: {\n code: 500,\n message: \"Fixture response did not match any known type\",\n status: \"INTERNAL\",\n },\n }),\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ws-gemini-live.cjs","names":["DEFAULT_TEST_ID","matchFixture","isErrorResponse","isAudioResponse","formatToMime","isContentWithToolCallsResponse","createInterruptionSignal","delay","generateToolCallId","isTextResponse","isToolCallResponse"],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":["/**\n * WebSocket handler for Gemini Live BidiGenerateContent API.\n *\n * Accepts setup, clientContent, and toolResponse messages over WebSocket\n * and responds with setupComplete, serverContent, toolCall, and error\n * messages in the Gemini Live streaming format.\n */\n\nimport type {\n Fixture,\n ChatMessage,\n ChatCompletionRequest,\n ToolDefinition,\n AudioResponse,\n} from \"./types.js\";\nimport { matchFixture } from \"./router.js\";\nimport {\n isTextResponse,\n isToolCallResponse,\n isContentWithToolCallsResponse,\n isErrorResponse,\n isAudioResponse,\n formatToMime,\n generateToolCallId,\n} from \"./helpers.js\";\nimport { createInterruptionSignal } from \"./interruption.js\";\nimport { delay } from \"./sse-writer.js\";\nimport { DEFAULT_TEST_ID, type Journal } from \"./journal.js\";\nimport type { Logger } from \"./logger.js\";\nimport type { WebSocketConnection } from \"./ws-framing.js\";\n\n// ─── Gemini Live protocol types ─────────────────────────────────────────────\n\ninterface GeminiLivePart {\n text?: string;\n thought?: boolean;\n functionCall?: { name: string; args: Record<string, unknown> };\n functionResponse?: { name: string; response: unknown; id?: string };\n inlineData?: { mimeType: string; data: string };\n}\n\ninterface GeminiLiveTurn {\n role: string;\n parts: GeminiLivePart[];\n}\n\ninterface GeminiLiveFunctionDeclaration {\n name: string;\n description?: string;\n parameters?: object;\n}\n\ninterface GeminiLiveToolDef {\n functionDeclarations?: GeminiLiveFunctionDeclaration[];\n}\n\ninterface GeminiLiveSetup {\n model?: string;\n generationConfig?: Record<string, unknown>;\n tools?: GeminiLiveToolDef[];\n}\n\ninterface GeminiLiveClientContent {\n turns: GeminiLiveTurn[];\n turnComplete?: boolean;\n}\n\ninterface GeminiLiveFunctionResponse {\n id?: string;\n name: string;\n response: unknown;\n}\n\ninterface GeminiLiveToolResponse {\n functionResponses: GeminiLiveFunctionResponse[];\n}\n\ninterface GeminiLiveMessage {\n setup?: GeminiLiveSetup;\n clientContent?: GeminiLiveClientContent;\n toolResponse?: GeminiLiveToolResponse;\n}\n\n// ─── Session state ──────────────────────────────────────────────────────────\n\ninterface SessionState {\n setupDone: boolean;\n model: string;\n tools: ToolDefinition[];\n conversationHistory: ChatMessage[];\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\nconst WS_PATH = \"/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent\";\n\n/**\n * Convert Gemini Live turns into ChatMessage[] for fixture matching.\n */\nfunction geminiTurnsToMessages(turns: GeminiLiveTurn[]): ChatMessage[] {\n const messages: ChatMessage[] = [];\n\n for (const turn of turns) {\n const role = turn.role ?? \"user\";\n\n if (role === \"user\") {\n const funcResponses = turn.parts.filter((p) => p.functionResponse);\n // inlineData parts (e.g. client audio input) are silently skipped —\n // only text and functionResponse parts are relevant for fixture matching.\n const textParts = turn.parts.filter((p) => p.text !== undefined && !p.thought);\n\n if (funcResponses.length > 0) {\n for (let i = 0; i < funcResponses.length; i++) {\n const part = funcResponses[i];\n const fr = part.functionResponse!;\n messages.push({\n role: \"tool\",\n content: typeof fr.response === \"string\" ? fr.response : JSON.stringify(fr.response),\n tool_call_id: fr.id ?? `call_gemini_${fr.name}_${i}`,\n });\n }\n if (textParts.length > 0) {\n messages.push({\n role: \"user\",\n content: textParts.map((p) => p.text!).join(\"\"),\n });\n }\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"user\", content: text });\n }\n } else if (role === \"model\") {\n const funcCalls = turn.parts.filter((p) => p.functionCall);\n const textParts = turn.parts.filter((p) => p.text !== undefined && !p.thought);\n\n if (funcCalls.length > 0) {\n messages.push({\n role: \"assistant\",\n content: null,\n tool_calls: funcCalls.map((p, i) => ({\n id: `call_gemini_${p.functionCall!.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: p.functionCall!.name,\n arguments: JSON.stringify(p.functionCall!.args),\n },\n })),\n });\n } else {\n const text = textParts.map((p) => p.text!).join(\"\");\n messages.push({ role: \"assistant\", content: text });\n }\n }\n }\n\n return messages;\n}\n\n/**\n * Convert toolResponse messages into ChatMessage[] for fixture matching.\n */\nfunction toolResponseToMessages(toolResponse: GeminiLiveToolResponse): ChatMessage[] {\n return toolResponse.functionResponses.map((fr, i) => ({\n role: \"tool\" as const,\n content: typeof fr.response === \"string\" ? fr.response : JSON.stringify(fr.response),\n tool_call_id: fr.id ?? `call_gemini_${fr.name}_${i}`,\n }));\n}\n\n/**\n * Convert Gemini tool definitions to ChatCompletion ToolDefinition[].\n */\nfunction convertTools(geminiTools?: GeminiLiveToolDef[]): ToolDefinition[] {\n if (!geminiTools || geminiTools.length === 0) return [];\n const decls = geminiTools.flatMap((t) => t.functionDeclarations ?? []);\n return decls.map((d) => ({\n type: \"function\" as const,\n function: {\n name: d.name,\n description: d.description,\n parameters: d.parameters,\n },\n }));\n}\n\n// ─── Main handler ───────────────────────────────────────────────────────────\n\nexport function handleWebSocketGeminiLive(\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n defaults: {\n latency: number;\n chunkSize: number;\n model: string;\n logger: Logger;\n strict?: boolean;\n requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;\n testId?: string;\n },\n): void {\n const { logger } = defaults;\n const session: SessionState = {\n setupDone: false,\n model: defaults.model,\n tools: [],\n conversationHistory: [],\n };\n\n let pending = Promise.resolve();\n ws.on(\"message\", (raw: string) => {\n pending = pending.then(() =>\n processMessage(raw, ws, fixtures, journal, defaults, session).catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : \"Internal error\";\n logger.error(`WebSocket Gemini Live error: ${msg}`);\n try {\n ws.send(\n JSON.stringify({\n error: { code: 500, message: msg, status: \"INTERNAL\" },\n }),\n );\n } catch {\n // Connection already gone — original error already logged above\n }\n }),\n );\n });\n}\n\nasync function processMessage(\n raw: string,\n ws: WebSocketConnection,\n fixtures: Fixture[],\n journal: Journal,\n defaults: {\n latency: number;\n chunkSize: number;\n model: string;\n logger: Logger;\n strict?: boolean;\n requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;\n testId?: string;\n },\n session: SessionState,\n): Promise<void> {\n let parsed: GeminiLiveMessage;\n try {\n parsed = JSON.parse(raw) as GeminiLiveMessage;\n } catch {\n ws.send(\n JSON.stringify({\n error: { code: 400, message: \"Malformed JSON\", status: \"INVALID_ARGUMENT\" },\n }),\n );\n return;\n }\n\n // Handle setup message\n if (parsed.setup) {\n session.setupDone = true;\n session.model = parsed.setup.model ?? defaults.model;\n session.tools = convertTools(parsed.setup.tools);\n ws.send(JSON.stringify({ setupComplete: {} }));\n return;\n }\n\n // Reject messages before setup\n if (!session.setupDone) {\n ws.send(\n JSON.stringify({\n error: { code: 400, message: \"Setup required\", status: \"FAILED_PRECONDITION\" },\n }),\n );\n return;\n }\n\n // Build messages from this interaction\n let newMessages: ChatMessage[];\n\n if (parsed.clientContent) {\n if (!parsed.clientContent.turns || !Array.isArray(parsed.clientContent.turns)) {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Missing 'turns' in clientContent\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n newMessages = geminiTurnsToMessages(parsed.clientContent.turns);\n } else if (parsed.toolResponse) {\n if (\n !parsed.toolResponse.functionResponses ||\n !Array.isArray(parsed.toolResponse.functionResponses)\n ) {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Missing 'functionResponses' in toolResponse\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n newMessages = toolResponseToMessages(parsed.toolResponse);\n } else {\n ws.send(\n JSON.stringify({\n error: {\n code: 400,\n message: \"Expected clientContent or toolResponse\",\n status: \"INVALID_ARGUMENT\",\n },\n }),\n );\n return;\n }\n\n // Build completion request for fixture matching (include new messages speculatively)\n const completionReq: ChatCompletionRequest = {\n model: session.model,\n messages: [...session.conversationHistory, ...newMessages],\n stream: true,\n tools: session.tools.length > 0 ? session.tools : undefined,\n };\n\n const testId = defaults.testId ?? DEFAULT_TEST_ID;\n const fixture = matchFixture(\n fixtures,\n completionReq,\n journal.getFixtureMatchCountsForTest(testId),\n defaults.requestTransform,\n );\n const path = WS_PATH;\n\n if (fixture) {\n journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n }\n\n if (!fixture) {\n if (defaults.strict) {\n defaults.logger.warn(`STRICT: No fixture matched for WebSocket message`);\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 404, fixture: null },\n });\n ws.close(1008, \"Strict mode: no fixture matched\");\n return;\n }\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 404, fixture: null },\n });\n ws.send(\n JSON.stringify({\n error: { code: 404, message: \"No fixture matched\", status: \"NOT_FOUND\" },\n }),\n );\n return;\n }\n\n // Commit messages to conversation history only after successful fixture match\n session.conversationHistory.push(...newMessages);\n\n const response = fixture.response;\n const latency = fixture.latency ?? defaults.latency;\n const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);\n\n // Error response\n if (isErrorResponse(response)) {\n const status = response.status ?? 500;\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status, fixture },\n });\n ws.send(\n JSON.stringify({\n error: { code: status, message: response.error.message, status: \"ERROR\" },\n }),\n );\n return;\n }\n\n // Audio response — single frame with inlineData and turnComplete: true\n if (isAudioResponse(response)) {\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const audioResp = response as AudioResponse;\n let mimeType: string;\n let data: string;\n\n if (typeof audioResp.audio === \"string\") {\n mimeType = formatToMime(audioResp.format ?? \"mp3\");\n data = audioResp.audio;\n } else {\n mimeType = audioResp.audio.contentType ?? \"audio/mpeg\";\n data = audioResp.audio.b64Json;\n }\n\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: {\n parts: [{ inlineData: { mimeType, data } }],\n },\n turnComplete: true,\n },\n }),\n );\n\n session.conversationHistory.push({\n role: \"assistant\",\n content: \"[audio]\",\n });\n return;\n }\n\n // Content + tool calls response (must be checked before isTextResponse / isToolCallResponse)\n if (isContentWithToolCallsResponse(response)) {\n const journalEntry = journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const content = response.content;\n const chunkList: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunkList.push(content.slice(i, i + chunkSize));\n }\n\n const interruption = createInterruptionSignal(fixture);\n let interrupted = false;\n\n // Stream text content chunks\n if (content.length === 0) {\n if (!ws.isClosed) {\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: \"\" }] },\n turnComplete: false,\n },\n }),\n );\n }\n } else {\n for (let i = 0; i < chunkList.length; i++) {\n if (ws.isClosed) break;\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n if (ws.isClosed) break;\n\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: chunkList[i] }] },\n turnComplete: false,\n },\n }),\n );\n interruption?.tick();\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n }\n }\n\n if (interrupted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n // Pre-compute tool calls with stable IDs so wire message and history match\n const resolvedToolCalls = response.toolCalls.map((tc) => ({\n ...tc,\n resolvedId: tc.id ?? generateToolCallId(),\n }));\n\n // Send tool calls\n if (!ws.isClosed) {\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n const functionCalls = resolvedToolCalls.map((tc) => {\n let argsObj: Record<string, unknown>;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\") as Record<string, unknown>;\n } catch {\n defaults.logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n name: tc.name,\n args: argsObj,\n id: tc.resolvedId,\n };\n });\n\n ws.send(JSON.stringify({ toolCall: { functionCalls } }));\n interruption?.tick();\n }\n\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n interruption?.cleanup();\n\n // Send turnComplete\n if (!ws.isClosed) {\n ws.send(\n JSON.stringify({\n serverContent: { turnComplete: true },\n }),\n );\n }\n\n // Add to conversation history using the same resolved IDs from the wire message\n session.conversationHistory.push({\n role: \"assistant\",\n content: content || null,\n tool_calls: resolvedToolCalls.map((tc) => ({\n id: tc.resolvedId,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: tc.arguments,\n },\n })),\n });\n return;\n }\n\n // Text response — stream chunks with serverContent\n if (isTextResponse(response)) {\n const journalEntry = journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const content = response.content;\n\n if (content.length === 0) {\n if (ws.isClosed) return;\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: \"\" }] },\n turnComplete: true,\n },\n }),\n );\n return;\n }\n\n // Chunk the content\n const chunks: string[] = [];\n for (let i = 0; i < content.length; i += chunkSize) {\n chunks.push(content.slice(i, i + chunkSize));\n }\n\n const interruption = createInterruptionSignal(fixture);\n let interrupted = false;\n\n for (let i = 0; i < chunks.length; i++) {\n if (ws.isClosed) break;\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n if (ws.isClosed) break;\n\n const isLast = i === chunks.length - 1;\n ws.send(\n JSON.stringify({\n serverContent: {\n modelTurn: { parts: [{ text: chunks[i] }] },\n turnComplete: isLast,\n },\n }),\n );\n interruption?.tick();\n if (interruption?.signal.aborted) {\n interrupted = true;\n break;\n }\n }\n\n if (interrupted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n interruption?.cleanup();\n\n // Add assistant response to conversation history\n session.conversationHistory.push({ role: \"assistant\", content });\n return;\n }\n\n // Tool call response\n if (isToolCallResponse(response)) {\n const journalEntry = journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 200, fixture },\n });\n\n const interruption = createInterruptionSignal(fixture);\n\n if (ws.isClosed) {\n interruption?.cleanup();\n return;\n }\n if (latency > 0) await delay(latency, interruption?.signal);\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n if (ws.isClosed) {\n interruption?.cleanup();\n return;\n }\n\n const functionCalls = response.toolCalls.map((tc, i) => {\n let argsObj: Record<string, unknown>;\n try {\n argsObj = JSON.parse(tc.arguments || \"{}\") as Record<string, unknown>;\n } catch {\n defaults.logger.warn(\n `Malformed JSON in fixture tool call arguments for \"${tc.name}\": ${tc.arguments}`,\n );\n argsObj = {};\n }\n return {\n name: tc.name,\n args: argsObj,\n id: tc.id ?? `call_gemini_${tc.name}_${i}`,\n };\n });\n\n ws.send(JSON.stringify({ toolCall: { functionCalls } }));\n interruption?.tick();\n\n if (interruption?.signal.aborted) {\n ws.destroy();\n journalEntry.response.interrupted = true;\n journalEntry.response.interruptReason = interruption?.reason();\n interruption?.cleanup();\n return;\n }\n\n interruption?.cleanup();\n\n // Add assistant tool_calls to conversation history\n session.conversationHistory.push({\n role: \"assistant\",\n content: null,\n tool_calls: response.toolCalls.map((tc, i) => ({\n id: tc.id ?? `call_gemini_${tc.name}_${i}`,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: tc.arguments,\n },\n })),\n });\n return;\n }\n\n // Unknown response type\n journal.add({\n method: \"WS\",\n path,\n headers: {},\n body: completionReq,\n response: { status: 500, fixture },\n });\n ws.send(\n JSON.stringify({\n error: {\n code: 500,\n message: \"Fixture response did not match any known type\",\n status: \"INTERNAL\",\n },\n }),\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-gemini-live.d.cts","names":[],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"ws-gemini-live.d.cts","names":[],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":[],"mappings":";;;;;;;AAmMY,iBARI,yBAAA,CAQJ,EAAA,EAPN,mBAOM,EAAA,QAAA,EANA,OAMA,EAAA,EAAA,OAAA,EALD,OAKC,EAAA,QAAA,EAAA;SAEiB,EAAA,MAAA;WAA0B,EAAA,MAAA;EAAqB,KAAA,EAAA,MAAA;UAFhE;;2BAEiB,0BAA0B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-gemini-live.d.ts","names":[],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"ws-gemini-live.d.ts","names":[],"sources":["../src/ws-gemini-live.ts"],"sourcesContent":[],"mappings":";;;;;;;AAmMY,iBARI,yBAAA,CAQJ,EAAA,EAPN,mBAOM,EAAA,QAAA,EANA,OAMA,EAAA,EAAA,OAAA,EALD,OAKC,EAAA,QAAA,EAAA;SAEiB,EAAA,MAAA;WAA0B,EAAA,MAAA;EAAqB,KAAA,EAAA,MAAA;UAFhE;;2BAEiB,0BAA0B"}
|