@simulacra-ai/google 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +6 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
package/dist/index.cjs
CHANGED
|
@@ -324,7 +324,7 @@ function from_gemini_part(part) {
|
|
|
324
324
|
thought: part.text ?? ""
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
|
-
if (part
|
|
327
|
+
if ("text" in part) {
|
|
328
328
|
return {
|
|
329
329
|
type: "text",
|
|
330
330
|
text: part.text ?? ""
|
|
@@ -479,7 +479,6 @@ function map_stop_reason(response) {
|
|
|
479
479
|
stop_reason: "error",
|
|
480
480
|
stop_details: finishMessage
|
|
481
481
|
};
|
|
482
|
-
case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:
|
|
483
482
|
case gemini.FinishReason.SAFETY:
|
|
484
483
|
case gemini.FinishReason.RECITATION:
|
|
485
484
|
case gemini.FinishReason.LANGUAGE:
|
|
@@ -487,6 +486,11 @@ function map_stop_reason(response) {
|
|
|
487
486
|
case gemini.FinishReason.PROHIBITED_CONTENT:
|
|
488
487
|
case gemini.FinishReason.SPII:
|
|
489
488
|
case gemini.FinishReason.IMAGE_SAFETY:
|
|
489
|
+
return {
|
|
490
|
+
stop_reason: "error",
|
|
491
|
+
stop_details: finishMessage
|
|
492
|
+
};
|
|
493
|
+
case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:
|
|
490
494
|
}
|
|
491
495
|
}
|
|
492
496
|
return {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/google-provider.ts","../src/google-tool-code-context-transformer.ts"],"sourcesContent":["export { GoogleProvider, type GoogleProviderConfig } from \"./google-provider.ts\";\nexport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n","import crypto from \"node:crypto\";\n\nimport * as gemini from \"@google/genai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n EnumParameterType,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolDefinition,\n} from \"@simulacra-ai/core\";\nimport { deep_merge, peek_generator, undefined_if_empty } from \"@simulacra-ai/core\";\nimport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n\n/**\n * Configuration options for the Google Gemini provider.\n */\nexport interface GoogleProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gemini-2.0-flash-exp\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /** Configuration for extended thinking mode. */\n thinking?: {\n /** Whether to enable extended thinking. */\n enable: boolean;\n /** The token budget allocated for thinking. */\n budget_tokens?: number;\n };\n}\n\n/**\n * Model provider implementation for Google's Gemini models.\n *\n * This provider wraps the Google Generative AI SDK to provide streaming completions\n * with support for tool use, extended thinking, and multimodal content. It handles\n * message formatting, content streaming, and usage tracking according to the\n * ModelProvider interface.\n */\nexport class GoogleProvider implements ModelProvider {\n readonly #sdk: gemini.GoogleGenAI;\n readonly #config: GoogleProviderConfig;\n\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new Google Gemini provider instance.\n *\n * @param sdk - The initialized Google Generative AI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers. Defaults to GoogleToolCodeContextTransformer.\n */\n constructor(\n sdk: gemini.GoogleGenAI,\n config: GoogleProviderConfig,\n context_transformers: ProviderContextTransformer[] = [new GoogleToolCodeContextTransformer()],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, thinking, ...api_extras } = this.#config;\n const params: gemini.GenerateContentParameters = {\n model,\n\n config: {\n ...api_extras,\n systemInstruction: request.system,\n maxOutputTokens: max_tokens,\n thinkingConfig: {\n includeThoughts: thinking?.enable,\n thinkingBudget: thinking?.budget_tokens,\n },\n ...(request.tools.length > 0\n ? {\n tools: [\n {\n functionDeclarations: request.tools.map((t) => to_gemini_tool(t)),\n },\n ],\n }\n : {}),\n },\n contents: request.messages.map((m) => to_gemini_content(m)),\n };\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const response = await this.#sdk.models.generateContentStream(params);\n const { peeked_value: _peeked_value, generator } = (await peek_generator(response)) as {\n peeked_value: gemini.GenerateContentResponse;\n generator: AsyncGenerator<gemini.GenerateContentResponse>;\n };\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(generator, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new GoogleProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncGenerator<gemini.GenerateContentResponse>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: Partial<gemini.GenerateContentResponse> | undefined;\n const completed_parts = new Set<number>();\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { candidates: candidates_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n candidates: response?.candidates ?? [],\n };\n const candidates = response.candidates as gemini.Candidate[];\n\n for (const candidate_chunk of candidates_chunk ?? []) {\n if (!candidates[candidate_chunk.index ?? 0]) {\n candidates[candidate_chunk.index ?? 0] = candidate_chunk;\n const message = from_gemini_content(candidate_chunk.content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage });\n }\n receiver.start_message({ message, usage });\n continue;\n }\n const { content: content_chunk, ...rest } = candidate_chunk;\n const candidate = (candidates[candidate_chunk.index ?? 0] = {\n ...candidates[candidate_chunk.index ?? 0],\n ...rest,\n content: {\n ...candidates[candidate_chunk.index ?? 0]?.content,\n parts: candidates[candidate_chunk.index ?? 0]?.content?.parts ?? [],\n },\n });\n\n for (const part_chunk of content_chunk?.parts ?? []) {\n const [part] = candidate.content.parts.slice(-1);\n if (!part) {\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n } else {\n if (part_chunk.thought && part.thought) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (!part_chunk.thought && !part.thought && part_chunk.text && part.text) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (part_chunk.functionCall && part.functionCall) {\n part.functionCall = deep_merge(part.functionCall, part_chunk.functionCall);\n } else if (part_chunk.executableCode && part.executableCode) {\n if (part_chunk.executableCode.code && part.executableCode.code) {\n part.executableCode.code += part_chunk.executableCode.code;\n delete part_chunk.executableCode.code;\n }\n part.executableCode = deep_merge(part.executableCode, part_chunk.executableCode);\n } else if (part_chunk.videoMetadata && part.videoMetadata) {\n part.videoMetadata = deep_merge(part.videoMetadata, part_chunk.videoMetadata);\n } else if (part_chunk.fileData && part.fileData) {\n part.fileData = deep_merge(part.fileData, part_chunk.fileData);\n } else if (part_chunk.inlineData && part.inlineData) {\n part.inlineData = deep_merge(part.inlineData, part_chunk.inlineData);\n } else {\n receiver.complete_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n completed_parts.add(candidate.content.parts.length - 1);\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n continue;\n }\n receiver.update_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n }\n }\n }\n }\n if (!response || !response.candidates?.[0]) {\n throw new Error(\"no data\", { cause: JSON.stringify(response?.promptFeedback ?? response) });\n }\n receiver.response_raw({ ...response });\n\n const message = from_gemini_content(response.candidates[0].content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (let i = 0; i < message.content.length; i++) {\n if (!completed_parts.has(i)) {\n receiver.complete_content({ content: message.content[i], message, usage });\n }\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction to_gemini_tool(tool: ToolDefinition): gemini.FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: gemini.Type.OBJECT,\n properties: undefined_if_empty(\n Object.fromEntries(\n tool.parameters.map((p) => [p.name, to_gemini_tool_schema(p, p.description)]),\n ),\n ),\n required: undefined_if_empty(tool.parameters.filter((p) => p.required).map((p) => p.name)),\n },\n };\n}\n\nfunction from_gemini_content(content?: gemini.Content) {\n if (!content) {\n return;\n }\n return {\n role: content.role === \"model\" ? \"assistant\" : \"user\",\n content: content.parts?.map((p: gemini.Part) => from_gemini_part(p)).filter(Boolean),\n };\n}\n\nfunction from_gemini_part(part: gemini.Part) {\n if (!part) {\n return;\n }\n if (part.thought) {\n return {\n type: \"thinking\",\n thought: part.text ?? \"\",\n };\n }\n if (part.text) {\n return {\n type: \"text\",\n text: part.text ?? \"\",\n };\n }\n if (part.functionCall) {\n return {\n type: \"tool\",\n tool_request_id: part.functionCall.id ?? crypto.randomUUID(),\n tool: part.functionCall.name ?? \"\",\n params: part.functionCall.args ?? {},\n };\n }\n if (part.functionResponse) {\n return {\n type: \"tool_result\",\n tool_request_id: part.functionResponse.id ?? \"\",\n tool: part.functionResponse.name ?? \"\",\n result: part.functionResponse.response ?? {},\n };\n }\n return {\n type: \"raw\",\n model_kind: \"google\",\n data: JSON.stringify(part),\n };\n}\n\nfunction to_gemini_content(message: Message): gemini.Content {\n return {\n role: message.role === \"assistant\" ? \"model\" : \"user\",\n parts: message.content.map((c) => to_gemini_part(c)),\n };\n}\n\nfunction to_gemini_part(content: Readonly<Content>) {\n switch (content.type) {\n case \"text\":\n return {\n text: content.text,\n };\n case \"tool\":\n return {\n functionCall: {\n id: content.tool_request_id,\n name: content.tool,\n args: content.params,\n },\n };\n case \"raw\":\n if (content.model_kind === \"google\") {\n try {\n return {\n ...JSON.parse(content.data),\n };\n } catch {\n return {\n text: content.data,\n };\n }\n }\n return {\n text: content.data,\n };\n case \"tool_result\":\n return {\n functionResponse: {\n id: content.tool_request_id,\n name: content.tool,\n response: content.result,\n },\n };\n case \"thinking\":\n return {\n thought: true,\n text: content.thought,\n };\n default:\n throw new Error(\"unexpected content type\");\n }\n}\n\nfunction to_gemini_tool_schema(parameter_type: ParameterType, description?: string): gemini.Schema {\n switch (parameter_type.type) {\n case \"string\":\n return {\n type: gemini.Type.STRING,\n description,\n enum: (parameter_type as EnumParameterType).enum,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"number\":\n return {\n type: gemini.Type.NUMBER,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"boolean\":\n return {\n type: gemini.Type.BOOLEAN,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"object\":\n return {\n type: gemini.Type.OBJECT,\n description,\n properties: Object.fromEntries(\n Object.entries(parameter_type.properties).map(([name, p]) => [\n name,\n to_gemini_tool_schema(p, p.description),\n ]),\n ),\n required: undefined_if_empty(\n Object.entries(parameter_type.properties)\n .filter(([, p]) => p.required)\n .map(([name]) => name),\n ),\n };\n case \"array\":\n return {\n type: gemini.Type.ARRAY,\n description,\n items: to_gemini_tool_schema(parameter_type.items, parameter_type.items.description),\n };\n }\n}\n\nfunction from_gemini_usage(usage: gemini.GenerateContentResponseUsageMetadata | undefined) {\n return {\n cache_read_input_tokens: usage?.cachedContentTokenCount,\n input_tokens: usage?.promptTokenCount,\n output_tokens: usage?.candidatesTokenCount,\n };\n}\n\nfunction map_stop_reason(\n response: Partial<gemini.GenerateContentResponse>,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const { finishReason, finishMessage } of response?.candidates ?? []) {\n switch (finishReason) {\n case gemini.FinishReason.STOP:\n if (response.candidates?.[0].content?.parts?.some((p: gemini.Part) => !!p.functionCall)) {\n return {\n stop_reason: \"tool_use\",\n stop_details: finishMessage,\n };\n } else {\n return {\n stop_reason: \"end_turn\",\n stop_details: finishMessage,\n };\n }\n case gemini.FinishReason.MAX_TOKENS:\n return {\n stop_reason: \"max_tokens\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.MALFORMED_FUNCTION_CALL:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:\n case gemini.FinishReason.SAFETY:\n case gemini.FinishReason.RECITATION:\n case gemini.FinishReason.LANGUAGE:\n case gemini.FinishReason.BLOCKLIST:\n case gemini.FinishReason.PROHIBITED_CONTENT:\n case gemini.FinishReason.SPII:\n case gemini.FinishReason.IMAGE_SAFETY:\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n","import crypto from \"node:crypto\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n ProviderContextTransformer,\n TextContent,\n ToolContent,\n} from \"@simulacra-ai/core\";\n\n/**\n * Provider context transformer that extracts tool calls from Gemini's code execution blocks.\n *\n * Gemini models sometimes return tool calls as executable code in markdown code blocks\n * tagged with \"tool_code\". This transformer parses those blocks and converts them into\n * standard tool call content that the framework can execute.\n */\nexport class GoogleToolCodeContextTransformer implements ProviderContextTransformer {\n /**\n * Transforms completion messages by extracting tool calls from code blocks.\n *\n * Scans text content for code blocks tagged as \"tool_code\" and parses them into\n * proper tool call content. The original code blocks are replaced with newlines\n * in the text content.\n *\n * @param message - The completion message to transform.\n * @returns A promise resolving to the transformed message.\n */\n transform_completion(message: AssistantMessage) {\n if (message.role !== \"assistant\") {\n return Promise.resolve(message);\n }\n\n return Promise.resolve({\n ...message,\n content: message.content.flatMap((c) => {\n if (c.type !== \"text\") {\n return [c];\n }\n return this.extract_tool_calls(c);\n }),\n });\n }\n\n private extract_tool_calls(content: TextContent) {\n const tool_calls: ToolContent[] = [];\n const remaining_text = content.text.replaceAll(\n /```(?:tool_code)\\n(.*?)\\n```/gs,\n (_, tool_code) => {\n const tool_call = this.parse_tool_call(content, tool_code);\n if (tool_call) {\n tool_calls.push(tool_call);\n }\n return \"\\n\";\n },\n );\n\n return [{ ...content, text: remaining_text }, ...tool_calls] as AssistantContent[];\n }\n\n private parse_tool_call(content: AssistantContent, tool_code?: string) {\n const function_match = tool_code?.match(/^print\\((\\w+)\\((.*)\\)\\)$/);\n if (!function_match) {\n return;\n }\n const [_, name, params_text] = function_match;\n const params = Object.fromEntries(\n Array.from(\n params_text.matchAll(\n /(\\w+)\\s*=\\s*((\"(?:\\\\\"|[^\"])*\")|(-?[\\d.]+)|([Tt]rue|[Ff]alse))\\s*(,|$)/g,\n ),\n ).map(([_match, key, _full, str, num, bool]: string[]) => {\n if (bool !== undefined) {\n return [key, bool.toLocaleLowerCase() === \"true\"];\n }\n if (!isNaN(Number(num))) {\n return [key, Number(num)];\n }\n try {\n return [key, JSON.parse(str)];\n } catch {\n return [key, str];\n }\n }),\n );\n\n return {\n type: \"tool\",\n tool_request_id: content.id ?? crypto.randomUUID(),\n tool: name,\n params: params,\n } as ToolContent;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,sBAAmB;AAEnB,aAAwB;AAiBxB,kBAA+D;;;ACnB/D,yBAAmB;AAiBZ,IAAM,mCAAN,MAA6E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWlF,qBAAqB,SAA2B;AAC9C,QAAI,QAAQ,SAAS,aAAa;AAChC,aAAO,QAAQ,QAAQ,OAAO;AAAA,IAChC;AAEA,WAAO,QAAQ,QAAQ;AAAA,MACrB,GAAG;AAAA,MACH,SAAS,QAAQ,QAAQ,QAAQ,CAAC,MAAM;AACtC,YAAI,EAAE,SAAS,QAAQ;AACrB,iBAAO,CAAC,CAAC;AAAA,QACX;AACA,eAAO,KAAK,mBAAmB,CAAC;AAAA,MAClC,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB,SAAsB;AAC/C,UAAM,aAA4B,CAAC;AACnC,UAAM,iBAAiB,QAAQ,KAAK;AAAA,MAClC;AAAA,MACA,CAAC,GAAG,cAAc;AAChB,cAAM,YAAY,KAAK,gBAAgB,SAAS,SAAS;AACzD,YAAI,WAAW;AACb,qBAAW,KAAK,SAAS;AAAA,QAC3B;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,CAAC,EAAE,GAAG,SAAS,MAAM,eAAe,GAAG,GAAG,UAAU;AAAA,EAC7D;AAAA,EAEQ,gBAAgB,SAA2B,WAAoB;AACrE,UAAM,iBAAiB,WAAW,MAAM,0BAA0B;AAClE,QAAI,CAAC,gBAAgB;AACnB;AAAA,IACF;AACA,UAAM,CAAC,GAAG,MAAM,WAAW,IAAI;AAC/B,UAAM,SAAS,OAAO;AAAA,MACpB,MAAM;AAAA,QACJ,YAAY;AAAA,UACV;AAAA,QACF;AAAA,MACF,EAAE,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,KAAK,KAAK,IAAI,MAAgB;AACxD,YAAI,SAAS,QAAW;AACtB,iBAAO,CAAC,KAAK,KAAK,kBAAkB,MAAM,MAAM;AAAA,QAClD;AACA,YAAI,CAAC,MAAM,OAAO,GAAG,CAAC,GAAG;AACvB,iBAAO,CAAC,KAAK,OAAO,GAAG,CAAC;AAAA,QAC1B;AACA,YAAI;AACF,iBAAO,CAAC,KAAK,KAAK,MAAM,GAAG,CAAC;AAAA,QAC9B,QAAQ;AACN,iBAAO,CAAC,KAAK,GAAG;AAAA,QAClB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,iBAAiB,QAAQ,MAAM,mBAAAC,QAAO,WAAW;AAAA,MACjD,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;;;AD9CO,IAAM,iBAAN,MAAM,gBAAwC;AAAA,EAC1C;AAAA,EACA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,YACE,KACA,QACA,uBAAqD,CAAC,IAAI,iCAAiC,CAAC,GAC5F;AACA,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,uBAAuB;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBACJ,SACA,UACA,cACe;AACf,UAAM,EAAE,OAAO,YAAY,UAAU,GAAG,WAAW,IAAI,KAAK;AAC5D,UAAM,SAA2C;AAAA,MAC/C;AAAA,MAEA,QAAQ;AAAA,QACN,GAAG;AAAA,QACH,mBAAmB,QAAQ;AAAA,QAC3B,iBAAiB;AAAA,QACjB,gBAAgB;AAAA,UACd,iBAAiB,UAAU;AAAA,UAC3B,gBAAgB,UAAU;AAAA,QAC5B;AAAA,QACA,GAAI,QAAQ,MAAM,SAAS,IACvB;AAAA,UACE,OAAO;AAAA,YACL;AAAA,cACE,sBAAsB,QAAQ,MAAM,IAAI,CAAC,MAAM,eAAe,CAAC,CAAC;AAAA,YAClE;AAAA,UACF;AAAA,QACF,IACA,CAAC;AAAA,MACP;AAAA,MACA,UAAU,QAAQ,SAAS,IAAI,CAAC,MAAM,kBAAkB,CAAC,CAAC;AAAA,IAC5D;AACA,aAAS,eAAe,EAAE,OAAO,CAAC;AAClC,aAAS,YAAY,MAAM;AAE3B,UAAM,WAAW,MAAM,KAAK,KAAK,OAAO,sBAAsB,MAAM;AACpE,UAAM,EAAE,cAAc,eAAe,UAAU,IAAK,UAAM,4BAAe,QAAQ;AAQjF,SAAK,iBAAiB,WAAW,UAAU,YAAY;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAuB;AACrB,WAAO,IAAI,gBAAe,KAAK,MAAM,KAAK,SAAS,KAAK,oBAAoB;AAAA,EAC9E;AAAA,EAEA,MAAM,iBACJ,QACA,UACA,cACA;AACA,QAAI;AACF,UAAI;AACJ,YAAM,kBAAkB,oBAAI,IAAY;AACxC,uBAAiB,kBAAkB,QAAQ;AACzC,YAAI,aAAa,2BAA2B;AAC1C,mBAAS,OAAO;AAChB;AAAA,QACF;AACA,iBAAS,WAAW,cAAc;AAElC,cAAM,EAAE,YAAY,kBAAkB,GAAG,KAAK,IAAI;AAClD,mBAAW;AAAA,UACT,GAAG;AAAA,UACH,GAAG;AAAA,UACH,YAAY,UAAU,cAAc,CAAC;AAAA,QACvC;AACA,cAAM,aAAa,SAAS;AAE5B,mBAAW,mBAAmB,oBAAoB,CAAC,GAAG;AACpD,cAAI,CAAC,WAAW,gBAAgB,SAAS,CAAC,GAAG;AAC3C,uBAAW,gBAAgB,SAAS,CAAC,IAAI;AACzC,kBAAMC,WAAU,oBAAoB,gBAAgB,OAAO;AAC3D,kBAAMC,SAAQ,kBAAkB,SAAS,aAAa;AACtD,uBAAW,WAAWD,SAAQ,SAAS;AACrC,uBAAS,cAAc,EAAE,SAAS,SAAAA,UAAS,OAAAC,OAAM,CAAC;AAAA,YACpD;AACA,qBAAS,cAAc,EAAE,SAAAD,UAAS,OAAAC,OAAM,CAAC;AACzC;AAAA,UACF;AACA,gBAAM,EAAE,SAAS,eAAe,GAAGC,MAAK,IAAI;AAC5C,gBAAM,YAAa,WAAW,gBAAgB,SAAS,CAAC,IAAI;AAAA,YAC1D,GAAG,WAAW,gBAAgB,SAAS,CAAC;AAAA,YACxC,GAAGA;AAAA,YACH,SAAS;AAAA,cACP,GAAG,WAAW,gBAAgB,SAAS,CAAC,GAAG;AAAA,cAC3C,OAAO,WAAW,gBAAgB,SAAS,CAAC,GAAG,SAAS,SAAS,CAAC;AAAA,YACpE;AAAA,UACF;AAEA,qBAAW,cAAc,eAAe,SAAS,CAAC,GAAG;AACnD,kBAAM,CAAC,IAAI,IAAI,UAAU,QAAQ,MAAM,MAAM,EAAE;AAC/C,gBAAI,CAAC,MAAM;AACT,wBAAU,QAAQ,MAAM,KAAK,UAAU;AACvC,uBAAS,cAAc;AAAA,gBACrB,SAAS,oBAAoB,UAAU,OAAO;AAAA,gBAC9C,SAAS,iBAAiB,UAAU;AAAA,gBACpC,OAAO,kBAAkB,SAAS,aAAa;AAAA,cACjD,CAAC;AACD,uBAAS,eAAe;AAAA,gBACtB,SAAS,oBAAoB,UAAU,OAAO;AAAA,gBAC9C,OAAO,kBAAkB,UAAU,aAAa;AAAA,cAClD,CAAC;AAAA,YACH,OAAO;AACL,kBAAI,WAAW,WAAW,KAAK,SAAS;AACtC,qBAAK,QAAQ,KAAK,QAAQ,OAAO,WAAW,QAAQ;AAAA,cACtD,WAAW,CAAC,WAAW,WAAW,CAAC,KAAK,WAAW,WAAW,QAAQ,KAAK,MAAM;AAC/E,qBAAK,QAAQ,KAAK,QAAQ,OAAO,WAAW,QAAQ;AAAA,cACtD,WAAW,WAAW,gBAAgB,KAAK,cAAc;AACvD,qBAAK,mBAAe,wBAAW,KAAK,cAAc,WAAW,YAAY;AAAA,cAC3E,WAAW,WAAW,kBAAkB,KAAK,gBAAgB;AAC3D,oBAAI,WAAW,eAAe,QAAQ,KAAK,eAAe,MAAM;AAC9D,uBAAK,eAAe,QAAQ,WAAW,eAAe;AACtD,yBAAO,WAAW,eAAe;AAAA,gBACnC;AACA,qBAAK,qBAAiB,wBAAW,KAAK,gBAAgB,WAAW,cAAc;AAAA,cACjF,WAAW,WAAW,iBAAiB,KAAK,eAAe;AACzD,qBAAK,oBAAgB,wBAAW,KAAK,eAAe,WAAW,aAAa;AAAA,cAC9E,WAAW,WAAW,YAAY,KAAK,UAAU;AAC/C,qBAAK,eAAW,wBAAW,KAAK,UAAU,WAAW,QAAQ;AAAA,cAC/D,WAAW,WAAW,cAAc,KAAK,YAAY;AACnD,qBAAK,iBAAa,wBAAW,KAAK,YAAY,WAAW,UAAU;AAAA,cACrE,OAAO;AACL,yBAAS,iBAAiB;AAAA,kBACxB,SAAS,oBAAoB,UAAU,OAAO;AAAA,kBAC9C,SAAS,iBAAiB,IAAI;AAAA,kBAC9B,OAAO,kBAAkB,SAAS,aAAa;AAAA,gBACjD,CAAC;AACD,gCAAgB,IAAI,UAAU,QAAQ,MAAM,SAAS,CAAC;AACtD,0BAAU,QAAQ,MAAM,KAAK,UAAU;AACvC,yBAAS,cAAc;AAAA,kBACrB,SAAS,oBAAoB,UAAU,OAAO;AAAA,kBAC9C,SAAS,iBAAiB,UAAU;AAAA,kBACpC,OAAO,kBAAkB,SAAS,aAAa;AAAA,gBACjD,CAAC;AACD,yBAAS,eAAe;AAAA,kBACtB,SAAS,oBAAoB,UAAU,OAAO;AAAA,kBAC9C,OAAO,kBAAkB,UAAU,aAAa;AAAA,gBAClD,CAAC;AACD;AAAA,cACF;AACA,uBAAS,eAAe;AAAA,gBACtB,SAAS,oBAAoB,UAAU,OAAO;AAAA,gBAC9C,SAAS,iBAAiB,IAAI;AAAA,gBAC9B,OAAO,kBAAkB,SAAS,aAAa;AAAA,cACjD,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,YAAY,CAAC,SAAS,aAAa,CAAC,GAAG;AAC1C,cAAM,IAAI,MAAM,WAAW,EAAE,OAAO,KAAK,UAAU,UAAU,kBAAkB,QAAQ,EAAE,CAAC;AAAA,MAC5F;AACA,eAAS,aAAa,EAAE,GAAG,SAAS,CAAC;AAErC,YAAM,UAAU,oBAAoB,SAAS,WAAW,CAAC,EAAE,OAAO;AAClE,YAAM,QAAQ,kBAAkB,SAAS,aAAa;AACtD,eAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC/C,YAAI,CAAC,gBAAgB,IAAI,CAAC,GAAG;AAC3B,mBAAS,iBAAiB,EAAE,SAAS,QAAQ,QAAQ,CAAC,GAAG,SAAS,MAAM,CAAC;AAAA,QAC3E;AAAA,MACF;AACA,eAAS,iBAAiB,EAAE,SAAS,OAAO,GAAG,gBAAgB,QAAQ,EAAE,CAAC;AAAA,IAC5E,SAAS,OAAO;AACd,eAAS,MAAM,KAAK;AAAA,IACtB;AAAA,EACF;AACF;AAEA,SAAS,eAAe,MAAkD;AACxE,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,YAAY;AAAA,MACV,MAAa,YAAK;AAAA,MAClB,gBAAY;AAAA,QACV,OAAO;AAAA,UACL,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,sBAAsB,GAAG,EAAE,WAAW,CAAC,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,MACA,cAAU,gCAAmB,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAAA,IAC3F;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,SAA0B;AACrD,MAAI,CAAC,SAAS;AACZ;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,SAAS,UAAU,cAAc;AAAA,IAC/C,SAAS,QAAQ,OAAO,IAAI,CAAC,MAAmB,iBAAiB,CAAC,CAAC,EAAE,OAAO,OAAO;AAAA,EACrF;AACF;AAEA,SAAS,iBAAiB,MAAmB;AAC3C,MAAI,CAAC,MAAM;AACT;AAAA,EACF;AACA,MAAI,KAAK,SAAS;AAChB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,KAAK,QAAQ;AAAA,IACxB;AAAA,EACF;AACA,MAAI,KAAK,MAAM;AACb,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AACA,MAAI,KAAK,cAAc;AACrB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,iBAAiB,KAAK,aAAa,MAAM,oBAAAC,QAAO,WAAW;AAAA,MAC3D,MAAM,KAAK,aAAa,QAAQ;AAAA,MAChC,QAAQ,KAAK,aAAa,QAAQ,CAAC;AAAA,IACrC;AAAA,EACF;AACA,MAAI,KAAK,kBAAkB;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,iBAAiB,KAAK,iBAAiB,MAAM;AAAA,MAC7C,MAAM,KAAK,iBAAiB,QAAQ;AAAA,MACpC,QAAQ,KAAK,iBAAiB,YAAY,CAAC;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B;AACF;AAEA,SAAS,kBAAkB,SAAkC;AAC3D,SAAO;AAAA,IACL,MAAM,QAAQ,SAAS,cAAc,UAAU;AAAA,IAC/C,OAAO,QAAQ,QAAQ,IAAI,CAAC,MAAM,eAAe,CAAC,CAAC;AAAA,EACrD;AACF;AAEA,SAAS,eAAe,SAA4B;AAClD,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,QACL,MAAM,QAAQ;AAAA,MAChB;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,cAAc;AAAA,UACZ,IAAI,QAAQ;AAAA,UACZ,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ;AAAA,QAChB;AAAA,MACF;AAAA,IACF,KAAK;AACH,UAAI,QAAQ,eAAe,UAAU;AACnC,YAAI;AACF,iBAAO;AAAA,YACL,GAAG,KAAK,MAAM,QAAQ,IAAI;AAAA,UAC5B;AAAA,QACF,QAAQ;AACN,iBAAO;AAAA,YACL,MAAM,QAAQ;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,QACL,MAAM,QAAQ;AAAA,MAChB;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,kBAAkB;AAAA,UAChB,IAAI,QAAQ;AAAA,UACZ,MAAM,QAAQ;AAAA,UACd,UAAU,QAAQ;AAAA,QACpB;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,QAAQ;AAAA,MAChB;AAAA,IACF;AACE,YAAM,IAAI,MAAM,yBAAyB;AAAA,EAC7C;AACF;AAEA,SAAS,sBAAsB,gBAA+B,aAAqC;AACjG,UAAQ,eAAe,MAAM;AAAA,IAC3B,KAAK;AACH,aAAO;AAAA,QACL,MAAa,YAAK;AAAA,QAClB;AAAA,QACA,MAAO,eAAqC;AAAA,QAC5C,SAAS,CAAC,eAAe,WAAW,eAAe,UAAU;AAAA,MAC/D;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAa,YAAK;AAAA,QAClB;AAAA,QACA,SAAS,CAAC,eAAe,WAAW,eAAe,UAAU;AAAA,MAC/D;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAa,YAAK;AAAA,QAClB;AAAA,QACA,SAAS,CAAC,eAAe,WAAW,eAAe,UAAU;AAAA,MAC/D;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAa,YAAK;AAAA,QAClB;AAAA,QACA,YAAY,OAAO;AAAA,UACjB,OAAO,QAAQ,eAAe,UAAU,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM;AAAA,YAC3D;AAAA,YACA,sBAAsB,GAAG,EAAE,WAAW;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,QACA,cAAU;AAAA,UACR,OAAO,QAAQ,eAAe,UAAU,EACrC,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAC5B,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAa,YAAK;AAAA,QAClB;AAAA,QACA,OAAO,sBAAsB,eAAe,OAAO,eAAe,MAAM,WAAW;AAAA,MACrF;AAAA,EACJ;AACF;AAEA,SAAS,kBAAkB,OAAgE;AACzF,SAAO;AAAA,IACL,yBAAyB,OAAO;AAAA,IAChC,cAAc,OAAO;AAAA,IACrB,eAAe,OAAO;AAAA,EACxB;AACF;AAEA,SAAS,gBACP,UAC8D;AAC9D,aAAW,EAAE,cAAc,cAAc,KAAK,UAAU,cAAc,CAAC,GAAG;AACxE,YAAQ,cAAc;AAAA,MACpB,KAAY,oBAAa;AACvB,YAAI,SAAS,aAAa,CAAC,EAAE,SAAS,OAAO,KAAK,CAAC,MAAmB,CAAC,CAAC,EAAE,YAAY,GAAG;AACvF,iBAAO;AAAA,YACL,aAAa;AAAA,YACb,cAAc;AAAA,UAChB;AAAA,QACF,OAAO;AACL,iBAAO;AAAA,YACL,aAAa;AAAA,YACb,cAAc;AAAA,UAChB;AAAA,QACF;AAAA,MACF,KAAY,oBAAa;AACvB,eAAO;AAAA,UACL,aAAa;AAAA,UACb,cAAc;AAAA,QAChB;AAAA,MACF,KAAY,oBAAa;AACvB,eAAO;AAAA,UACL,aAAa;AAAA,UACb,cAAc;AAAA,QAChB;AAAA,MACF,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,MACzB,KAAY,oBAAa;AAAA,IAC3B;AAAA,EACF;AACA,SAAO;AAAA,IACL,aAAa;AAAA,EACf;AACF;","names":["import_node_crypto","crypto","message","usage","rest","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/google-provider.ts","../src/google-tool-code-context-transformer.ts"],"sourcesContent":["export { GoogleProvider, type GoogleProviderConfig } from \"./google-provider.ts\";\nexport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n","import crypto from \"node:crypto\";\n\nimport * as gemini from \"@google/genai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n EnumParameterType,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolDefinition,\n} from \"@simulacra-ai/core\";\nimport { deep_merge, peek_generator, undefined_if_empty } from \"@simulacra-ai/core\";\nimport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n\n/**\n * Configuration options for the Google Gemini provider.\n */\nexport interface GoogleProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gemini-2.0-flash-exp\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /** Configuration for extended thinking mode. */\n thinking?: {\n /** Whether to enable extended thinking. */\n enable: boolean;\n /** The token budget allocated for thinking. */\n budget_tokens?: number;\n };\n}\n\n/**\n * Model provider implementation for Google's Gemini models.\n *\n * This provider wraps the Google Generative AI SDK to provide streaming completions\n * with support for tool use, extended thinking, and multimodal content. It handles\n * message formatting, content streaming, and usage tracking according to the\n * ModelProvider interface.\n */\nexport class GoogleProvider implements ModelProvider {\n readonly #sdk: gemini.GoogleGenAI;\n readonly #config: GoogleProviderConfig;\n\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new Google Gemini provider instance.\n *\n * @param sdk - The initialized Google Generative AI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers. Defaults to GoogleToolCodeContextTransformer.\n */\n constructor(\n sdk: gemini.GoogleGenAI,\n config: GoogleProviderConfig,\n context_transformers: ProviderContextTransformer[] = [new GoogleToolCodeContextTransformer()],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, thinking, ...api_extras } = this.#config;\n const params: gemini.GenerateContentParameters = {\n model,\n\n config: {\n ...api_extras,\n systemInstruction: request.system,\n maxOutputTokens: max_tokens,\n thinkingConfig: {\n includeThoughts: thinking?.enable,\n thinkingBudget: thinking?.budget_tokens,\n },\n ...(request.tools.length > 0\n ? {\n tools: [\n {\n functionDeclarations: request.tools.map((t) => to_gemini_tool(t)),\n },\n ],\n }\n : {}),\n },\n contents: request.messages.map((m) => to_gemini_content(m)),\n };\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const response = await this.#sdk.models.generateContentStream(params);\n const { peeked_value: _peeked_value, generator } = (await peek_generator(response)) as {\n peeked_value: gemini.GenerateContentResponse;\n generator: AsyncGenerator<gemini.GenerateContentResponse>;\n };\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(generator, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new GoogleProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncGenerator<gemini.GenerateContentResponse>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: Partial<gemini.GenerateContentResponse> | undefined;\n const completed_parts = new Set<number>();\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { candidates: candidates_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n candidates: response?.candidates ?? [],\n };\n const candidates = response.candidates as gemini.Candidate[];\n\n for (const candidate_chunk of candidates_chunk ?? []) {\n if (!candidates[candidate_chunk.index ?? 0]) {\n candidates[candidate_chunk.index ?? 0] = candidate_chunk;\n const message = from_gemini_content(candidate_chunk.content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage });\n }\n receiver.start_message({ message, usage });\n continue;\n }\n const { content: content_chunk, ...rest } = candidate_chunk;\n const candidate = (candidates[candidate_chunk.index ?? 0] = {\n ...candidates[candidate_chunk.index ?? 0],\n ...rest,\n content: {\n ...candidates[candidate_chunk.index ?? 0]?.content,\n parts: candidates[candidate_chunk.index ?? 0]?.content?.parts ?? [],\n },\n });\n\n for (const part_chunk of content_chunk?.parts ?? []) {\n const [part] = candidate.content.parts.slice(-1);\n if (!part) {\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n } else {\n if (part_chunk.thought && part.thought) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (!part_chunk.thought && !part.thought && part_chunk.text && part.text) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (part_chunk.functionCall && part.functionCall) {\n part.functionCall = deep_merge(part.functionCall, part_chunk.functionCall);\n } else if (part_chunk.executableCode && part.executableCode) {\n if (part_chunk.executableCode.code && part.executableCode.code) {\n part.executableCode.code += part_chunk.executableCode.code;\n delete part_chunk.executableCode.code;\n }\n part.executableCode = deep_merge(part.executableCode, part_chunk.executableCode);\n } else if (part_chunk.videoMetadata && part.videoMetadata) {\n part.videoMetadata = deep_merge(part.videoMetadata, part_chunk.videoMetadata);\n } else if (part_chunk.fileData && part.fileData) {\n part.fileData = deep_merge(part.fileData, part_chunk.fileData);\n } else if (part_chunk.inlineData && part.inlineData) {\n part.inlineData = deep_merge(part.inlineData, part_chunk.inlineData);\n } else {\n receiver.complete_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n completed_parts.add(candidate.content.parts.length - 1);\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n continue;\n }\n receiver.update_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n }\n }\n }\n }\n if (!response || !response.candidates?.[0]) {\n throw new Error(\"no data\", { cause: JSON.stringify(response?.promptFeedback ?? response) });\n }\n receiver.response_raw({ ...response });\n\n const message = from_gemini_content(response.candidates[0].content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (let i = 0; i < message.content.length; i++) {\n if (!completed_parts.has(i)) {\n receiver.complete_content({ content: message.content[i], message, usage });\n }\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction to_gemini_tool(tool: ToolDefinition): gemini.FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: gemini.Type.OBJECT,\n properties: undefined_if_empty(\n Object.fromEntries(\n tool.parameters.map((p) => [p.name, to_gemini_tool_schema(p, p.description)]),\n ),\n ),\n required: undefined_if_empty(tool.parameters.filter((p) => p.required).map((p) => p.name)),\n },\n };\n}\n\nfunction from_gemini_content(content?: gemini.Content) {\n if (!content) {\n return;\n }\n return {\n role: content.role === \"model\" ? \"assistant\" : \"user\",\n content: content.parts?.map((p: gemini.Part) => from_gemini_part(p)).filter(Boolean),\n };\n}\n\nfunction from_gemini_part(part: gemini.Part) {\n if (!part) {\n return;\n }\n if (part.thought) {\n return {\n type: \"thinking\",\n thought: part.text ?? \"\",\n };\n }\n if (\"text\" in part) {\n return {\n type: \"text\",\n text: part.text ?? \"\",\n };\n }\n if (part.functionCall) {\n return {\n type: \"tool\",\n tool_request_id: part.functionCall.id ?? crypto.randomUUID(),\n tool: part.functionCall.name ?? \"\",\n params: part.functionCall.args ?? {},\n };\n }\n if (part.functionResponse) {\n return {\n type: \"tool_result\",\n tool_request_id: part.functionResponse.id ?? \"\",\n tool: part.functionResponse.name ?? \"\",\n result: part.functionResponse.response ?? {},\n };\n }\n return {\n type: \"raw\",\n model_kind: \"google\",\n data: JSON.stringify(part),\n };\n}\n\nfunction to_gemini_content(message: Message): gemini.Content {\n return {\n role: message.role === \"assistant\" ? \"model\" : \"user\",\n parts: message.content.map((c) => to_gemini_part(c)),\n };\n}\n\nfunction to_gemini_part(content: Readonly<Content>) {\n switch (content.type) {\n case \"text\":\n return {\n text: content.text,\n };\n case \"tool\":\n return {\n functionCall: {\n id: content.tool_request_id,\n name: content.tool,\n args: content.params,\n },\n };\n case \"raw\":\n if (content.model_kind === \"google\") {\n try {\n return {\n ...JSON.parse(content.data),\n };\n } catch {\n return {\n text: content.data,\n };\n }\n }\n return {\n text: content.data,\n };\n case \"tool_result\":\n return {\n functionResponse: {\n id: content.tool_request_id,\n name: content.tool,\n response: content.result,\n },\n };\n case \"thinking\":\n return {\n thought: true,\n text: content.thought,\n };\n default:\n throw new Error(\"unexpected content type\");\n }\n}\n\nfunction to_gemini_tool_schema(parameter_type: ParameterType, description?: string): gemini.Schema {\n switch (parameter_type.type) {\n case \"string\":\n return {\n type: gemini.Type.STRING,\n description,\n enum: (parameter_type as EnumParameterType).enum,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"number\":\n return {\n type: gemini.Type.NUMBER,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"boolean\":\n return {\n type: gemini.Type.BOOLEAN,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"object\":\n return {\n type: gemini.Type.OBJECT,\n description,\n properties: Object.fromEntries(\n Object.entries(parameter_type.properties).map(([name, p]) => [\n name,\n to_gemini_tool_schema(p, p.description),\n ]),\n ),\n required: undefined_if_empty(\n Object.entries(parameter_type.properties)\n .filter(([, p]) => p.required)\n .map(([name]) => name),\n ),\n };\n case \"array\":\n return {\n type: gemini.Type.ARRAY,\n description,\n items: to_gemini_tool_schema(parameter_type.items, parameter_type.items.description),\n };\n }\n}\n\nfunction from_gemini_usage(usage: gemini.GenerateContentResponseUsageMetadata | undefined) {\n return {\n cache_read_input_tokens: usage?.cachedContentTokenCount,\n input_tokens: usage?.promptTokenCount,\n output_tokens: usage?.candidatesTokenCount,\n };\n}\n\nfunction map_stop_reason(\n response: Partial<gemini.GenerateContentResponse>,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const { finishReason, finishMessage } of response?.candidates ?? []) {\n switch (finishReason) {\n case gemini.FinishReason.STOP:\n if (response.candidates?.[0].content?.parts?.some((p: gemini.Part) => !!p.functionCall)) {\n return {\n stop_reason: \"tool_use\",\n stop_details: finishMessage,\n };\n } else {\n return {\n stop_reason: \"end_turn\",\n stop_details: finishMessage,\n };\n }\n case gemini.FinishReason.MAX_TOKENS:\n return {\n stop_reason: \"max_tokens\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.MALFORMED_FUNCTION_CALL:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.SAFETY:\n case gemini.FinishReason.RECITATION:\n case gemini.FinishReason.LANGUAGE:\n case gemini.FinishReason.BLOCKLIST:\n case gemini.FinishReason.PROHIBITED_CONTENT:\n case gemini.FinishReason.SPII:\n case gemini.FinishReason.IMAGE_SAFETY:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n","import crypto from \"node:crypto\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n ProviderContextTransformer,\n TextContent,\n ToolContent,\n} from \"@simulacra-ai/core\";\n\n/**\n * Provider context transformer that extracts tool calls from Gemini's code execution blocks.\n *\n * Gemini models sometimes return tool calls as executable code in markdown code blocks\n * tagged with \"tool_code\". This transformer parses those blocks and converts them into\n * standard tool call content that the framework can execute.\n */\nexport class GoogleToolCodeContextTransformer implements ProviderContextTransformer {\n /**\n * Transforms completion messages by extracting tool calls from code blocks.\n *\n * Scans text content for code blocks tagged as \"tool_code\" and parses them into\n * proper tool call content. The original code blocks are replaced with newlines\n * in the text content.\n *\n * @param message - The completion message to transform.\n * @returns A promise resolving to the transformed message.\n */\n transform_completion(message: AssistantMessage) {\n if (message.role !== \"assistant\") {\n return Promise.resolve(message);\n }\n\n return Promise.resolve({\n ...message,\n content: message.content.flatMap((c) => {\n if (c.type !== \"text\") {\n return [c];\n }\n return this.extract_tool_calls(c);\n }),\n });\n }\n\n private extract_tool_calls(content: TextContent) {\n const tool_calls: ToolContent[] = [];\n const remaining_text = content.text.replaceAll(\n /```(?:tool_code)\\n(.*?)\\n```/gs,\n (_, tool_code) => {\n const tool_call = this.parse_tool_call(content, tool_code);\n if (tool_call) {\n tool_calls.push(tool_call);\n }\n return \"\\n\";\n },\n );\n\n return [{ ...content, text: remaining_text }, ...tool_calls] as AssistantContent[];\n }\n\n private parse_tool_call(content: AssistantContent, tool_code?: string) {\n const function_match = tool_code?.match(/^print\\((\\w+)\\((.*)\\)\\)$/);\n if (!function_match) {\n return;\n }\n const [_, name, params_text] = function_match;\n const params = Object.fromEntries(\n Array.from(\n params_text.matchAll(\n /(\\w+)\\s*=\\s*((\"(?:\\\\\"|[^\"])*\")|(-?[\\d.]+)|([Tt]rue|[Ff]alse))\\s*(,|$)/g,\n ),\n ).map(([_match, key, _full, str, num, bool]: string[]) => {\n if (bool !== undefined) {\n return [key, bool.toLocaleLowerCase() === \"true\"];\n }\n if (!isNaN(Number(num))) {\n return [key, Number(num)];\n }\n try {\n return [key, JSON.parse(str)];\n } catch {\n return [key, str];\n }\n }),\n );\n\n return {\n type: \"tool\",\n tool_request_id: content.id ?? crypto.randomUUID(),\n tool: name,\n params: params,\n } as ToolContent;\n }\n}\n"],"mappings":"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","names":["import_node_crypto","crypto","message","usage","rest","crypto"]}
|
package/dist/index.js
CHANGED
|
@@ -287,7 +287,7 @@ function from_gemini_part(part) {
|
|
|
287
287
|
thought: part.text ?? ""
|
|
288
288
|
};
|
|
289
289
|
}
|
|
290
|
-
if (part
|
|
290
|
+
if ("text" in part) {
|
|
291
291
|
return {
|
|
292
292
|
type: "text",
|
|
293
293
|
text: part.text ?? ""
|
|
@@ -442,7 +442,6 @@ function map_stop_reason(response) {
|
|
|
442
442
|
stop_reason: "error",
|
|
443
443
|
stop_details: finishMessage
|
|
444
444
|
};
|
|
445
|
-
case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:
|
|
446
445
|
case gemini.FinishReason.SAFETY:
|
|
447
446
|
case gemini.FinishReason.RECITATION:
|
|
448
447
|
case gemini.FinishReason.LANGUAGE:
|
|
@@ -450,6 +449,11 @@ function map_stop_reason(response) {
|
|
|
450
449
|
case gemini.FinishReason.PROHIBITED_CONTENT:
|
|
451
450
|
case gemini.FinishReason.SPII:
|
|
452
451
|
case gemini.FinishReason.IMAGE_SAFETY:
|
|
452
|
+
return {
|
|
453
|
+
stop_reason: "error",
|
|
454
|
+
stop_details: finishMessage
|
|
455
|
+
};
|
|
456
|
+
case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:
|
|
453
457
|
}
|
|
454
458
|
}
|
|
455
459
|
return {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/google-provider.ts","../src/google-tool-code-context-transformer.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport * as gemini from \"@google/genai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n EnumParameterType,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolDefinition,\n} from \"@simulacra-ai/core\";\nimport { deep_merge, peek_generator, undefined_if_empty } from \"@simulacra-ai/core\";\nimport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n\n/**\n * Configuration options for the Google Gemini provider.\n */\nexport interface GoogleProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gemini-2.0-flash-exp\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /** Configuration for extended thinking mode. */\n thinking?: {\n /** Whether to enable extended thinking. */\n enable: boolean;\n /** The token budget allocated for thinking. */\n budget_tokens?: number;\n };\n}\n\n/**\n * Model provider implementation for Google's Gemini models.\n *\n * This provider wraps the Google Generative AI SDK to provide streaming completions\n * with support for tool use, extended thinking, and multimodal content. It handles\n * message formatting, content streaming, and usage tracking according to the\n * ModelProvider interface.\n */\nexport class GoogleProvider implements ModelProvider {\n readonly #sdk: gemini.GoogleGenAI;\n readonly #config: GoogleProviderConfig;\n\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new Google Gemini provider instance.\n *\n * @param sdk - The initialized Google Generative AI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers. Defaults to GoogleToolCodeContextTransformer.\n */\n constructor(\n sdk: gemini.GoogleGenAI,\n config: GoogleProviderConfig,\n context_transformers: ProviderContextTransformer[] = [new GoogleToolCodeContextTransformer()],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, thinking, ...api_extras } = this.#config;\n const params: gemini.GenerateContentParameters = {\n model,\n\n config: {\n ...api_extras,\n systemInstruction: request.system,\n maxOutputTokens: max_tokens,\n thinkingConfig: {\n includeThoughts: thinking?.enable,\n thinkingBudget: thinking?.budget_tokens,\n },\n ...(request.tools.length > 0\n ? {\n tools: [\n {\n functionDeclarations: request.tools.map((t) => to_gemini_tool(t)),\n },\n ],\n }\n : {}),\n },\n contents: request.messages.map((m) => to_gemini_content(m)),\n };\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const response = await this.#sdk.models.generateContentStream(params);\n const { peeked_value: _peeked_value, generator } = (await peek_generator(response)) as {\n peeked_value: gemini.GenerateContentResponse;\n generator: AsyncGenerator<gemini.GenerateContentResponse>;\n };\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(generator, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new GoogleProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncGenerator<gemini.GenerateContentResponse>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: Partial<gemini.GenerateContentResponse> | undefined;\n const completed_parts = new Set<number>();\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { candidates: candidates_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n candidates: response?.candidates ?? [],\n };\n const candidates = response.candidates as gemini.Candidate[];\n\n for (const candidate_chunk of candidates_chunk ?? []) {\n if (!candidates[candidate_chunk.index ?? 0]) {\n candidates[candidate_chunk.index ?? 0] = candidate_chunk;\n const message = from_gemini_content(candidate_chunk.content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage });\n }\n receiver.start_message({ message, usage });\n continue;\n }\n const { content: content_chunk, ...rest } = candidate_chunk;\n const candidate = (candidates[candidate_chunk.index ?? 0] = {\n ...candidates[candidate_chunk.index ?? 0],\n ...rest,\n content: {\n ...candidates[candidate_chunk.index ?? 0]?.content,\n parts: candidates[candidate_chunk.index ?? 0]?.content?.parts ?? [],\n },\n });\n\n for (const part_chunk of content_chunk?.parts ?? []) {\n const [part] = candidate.content.parts.slice(-1);\n if (!part) {\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n } else {\n if (part_chunk.thought && part.thought) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (!part_chunk.thought && !part.thought && part_chunk.text && part.text) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (part_chunk.functionCall && part.functionCall) {\n part.functionCall = deep_merge(part.functionCall, part_chunk.functionCall);\n } else if (part_chunk.executableCode && part.executableCode) {\n if (part_chunk.executableCode.code && part.executableCode.code) {\n part.executableCode.code += part_chunk.executableCode.code;\n delete part_chunk.executableCode.code;\n }\n part.executableCode = deep_merge(part.executableCode, part_chunk.executableCode);\n } else if (part_chunk.videoMetadata && part.videoMetadata) {\n part.videoMetadata = deep_merge(part.videoMetadata, part_chunk.videoMetadata);\n } else if (part_chunk.fileData && part.fileData) {\n part.fileData = deep_merge(part.fileData, part_chunk.fileData);\n } else if (part_chunk.inlineData && part.inlineData) {\n part.inlineData = deep_merge(part.inlineData, part_chunk.inlineData);\n } else {\n receiver.complete_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n completed_parts.add(candidate.content.parts.length - 1);\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n continue;\n }\n receiver.update_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n }\n }\n }\n }\n if (!response || !response.candidates?.[0]) {\n throw new Error(\"no data\", { cause: JSON.stringify(response?.promptFeedback ?? response) });\n }\n receiver.response_raw({ ...response });\n\n const message = from_gemini_content(response.candidates[0].content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (let i = 0; i < message.content.length; i++) {\n if (!completed_parts.has(i)) {\n receiver.complete_content({ content: message.content[i], message, usage });\n }\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction to_gemini_tool(tool: ToolDefinition): gemini.FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: gemini.Type.OBJECT,\n properties: undefined_if_empty(\n Object.fromEntries(\n tool.parameters.map((p) => [p.name, to_gemini_tool_schema(p, p.description)]),\n ),\n ),\n required: undefined_if_empty(tool.parameters.filter((p) => p.required).map((p) => p.name)),\n },\n };\n}\n\nfunction from_gemini_content(content?: gemini.Content) {\n if (!content) {\n return;\n }\n return {\n role: content.role === \"model\" ? \"assistant\" : \"user\",\n content: content.parts?.map((p: gemini.Part) => from_gemini_part(p)).filter(Boolean),\n };\n}\n\nfunction from_gemini_part(part: gemini.Part) {\n if (!part) {\n return;\n }\n if (part.thought) {\n return {\n type: \"thinking\",\n thought: part.text ?? \"\",\n };\n }\n if (part.text) {\n return {\n type: \"text\",\n text: part.text ?? \"\",\n };\n }\n if (part.functionCall) {\n return {\n type: \"tool\",\n tool_request_id: part.functionCall.id ?? crypto.randomUUID(),\n tool: part.functionCall.name ?? \"\",\n params: part.functionCall.args ?? {},\n };\n }\n if (part.functionResponse) {\n return {\n type: \"tool_result\",\n tool_request_id: part.functionResponse.id ?? \"\",\n tool: part.functionResponse.name ?? \"\",\n result: part.functionResponse.response ?? {},\n };\n }\n return {\n type: \"raw\",\n model_kind: \"google\",\n data: JSON.stringify(part),\n };\n}\n\nfunction to_gemini_content(message: Message): gemini.Content {\n return {\n role: message.role === \"assistant\" ? \"model\" : \"user\",\n parts: message.content.map((c) => to_gemini_part(c)),\n };\n}\n\nfunction to_gemini_part(content: Readonly<Content>) {\n switch (content.type) {\n case \"text\":\n return {\n text: content.text,\n };\n case \"tool\":\n return {\n functionCall: {\n id: content.tool_request_id,\n name: content.tool,\n args: content.params,\n },\n };\n case \"raw\":\n if (content.model_kind === \"google\") {\n try {\n return {\n ...JSON.parse(content.data),\n };\n } catch {\n return {\n text: content.data,\n };\n }\n }\n return {\n text: content.data,\n };\n case \"tool_result\":\n return {\n functionResponse: {\n id: content.tool_request_id,\n name: content.tool,\n response: content.result,\n },\n };\n case \"thinking\":\n return {\n thought: true,\n text: content.thought,\n };\n default:\n throw new Error(\"unexpected content type\");\n }\n}\n\nfunction to_gemini_tool_schema(parameter_type: ParameterType, description?: string): gemini.Schema {\n switch (parameter_type.type) {\n case \"string\":\n return {\n type: gemini.Type.STRING,\n description,\n enum: (parameter_type as EnumParameterType).enum,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"number\":\n return {\n type: gemini.Type.NUMBER,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"boolean\":\n return {\n type: gemini.Type.BOOLEAN,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"object\":\n return {\n type: gemini.Type.OBJECT,\n description,\n properties: Object.fromEntries(\n Object.entries(parameter_type.properties).map(([name, p]) => [\n name,\n to_gemini_tool_schema(p, p.description),\n ]),\n ),\n required: undefined_if_empty(\n Object.entries(parameter_type.properties)\n .filter(([, p]) => p.required)\n .map(([name]) => name),\n ),\n };\n case \"array\":\n return {\n type: gemini.Type.ARRAY,\n description,\n items: to_gemini_tool_schema(parameter_type.items, parameter_type.items.description),\n };\n }\n}\n\nfunction from_gemini_usage(usage: gemini.GenerateContentResponseUsageMetadata | undefined) {\n return {\n cache_read_input_tokens: usage?.cachedContentTokenCount,\n input_tokens: usage?.promptTokenCount,\n output_tokens: usage?.candidatesTokenCount,\n };\n}\n\nfunction map_stop_reason(\n response: Partial<gemini.GenerateContentResponse>,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const { finishReason, finishMessage } of response?.candidates ?? []) {\n switch (finishReason) {\n case gemini.FinishReason.STOP:\n if (response.candidates?.[0].content?.parts?.some((p: gemini.Part) => !!p.functionCall)) {\n return {\n stop_reason: \"tool_use\",\n stop_details: finishMessage,\n };\n } else {\n return {\n stop_reason: \"end_turn\",\n stop_details: finishMessage,\n };\n }\n case gemini.FinishReason.MAX_TOKENS:\n return {\n stop_reason: \"max_tokens\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.MALFORMED_FUNCTION_CALL:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:\n case gemini.FinishReason.SAFETY:\n case gemini.FinishReason.RECITATION:\n case gemini.FinishReason.LANGUAGE:\n case gemini.FinishReason.BLOCKLIST:\n case gemini.FinishReason.PROHIBITED_CONTENT:\n case gemini.FinishReason.SPII:\n case gemini.FinishReason.IMAGE_SAFETY:\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n","import crypto from \"node:crypto\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n ProviderContextTransformer,\n TextContent,\n ToolContent,\n} from \"@simulacra-ai/core\";\n\n/**\n * Provider context transformer that extracts tool calls from Gemini's code execution blocks.\n *\n * Gemini models sometimes return tool calls as executable code in markdown code blocks\n * tagged with \"tool_code\". This transformer parses those blocks and converts them into\n * standard tool call content that the framework can execute.\n */\nexport class GoogleToolCodeContextTransformer implements ProviderContextTransformer {\n /**\n * Transforms completion messages by extracting tool calls from code blocks.\n *\n * Scans text content for code blocks tagged as \"tool_code\" and parses them into\n * proper tool call content. The original code blocks are replaced with newlines\n * in the text content.\n *\n * @param message - The completion message to transform.\n * @returns A promise resolving to the transformed message.\n */\n transform_completion(message: AssistantMessage) {\n if (message.role !== \"assistant\") {\n return Promise.resolve(message);\n }\n\n return Promise.resolve({\n ...message,\n content: message.content.flatMap((c) => {\n if (c.type !== \"text\") {\n return [c];\n }\n return this.extract_tool_calls(c);\n }),\n });\n }\n\n private extract_tool_calls(content: TextContent) {\n const tool_calls: ToolContent[] = [];\n const remaining_text = content.text.replaceAll(\n /```(?:tool_code)\\n(.*?)\\n```/gs,\n (_, tool_code) => {\n const tool_call = this.parse_tool_call(content, tool_code);\n if (tool_call) {\n tool_calls.push(tool_call);\n }\n return \"\\n\";\n },\n );\n\n return [{ ...content, text: remaining_text }, ...tool_calls] as AssistantContent[];\n }\n\n private parse_tool_call(content: AssistantContent, tool_code?: string) {\n const function_match = tool_code?.match(/^print\\((\\w+)\\((.*)\\)\\)$/);\n if (!function_match) {\n return;\n }\n const [_, name, params_text] = function_match;\n const params = Object.fromEntries(\n Array.from(\n params_text.matchAll(\n /(\\w+)\\s*=\\s*((\"(?:\\\\\"|[^\"])*\")|(-?[\\d.]+)|([Tt]rue|[Ff]alse))\\s*(,|$)/g,\n ),\n ).map(([_match, key, _full, str, num, bool]: string[]) => {\n if (bool !== undefined) {\n return [key, bool.toLocaleLowerCase() === \"true\"];\n }\n if (!isNaN(Number(num))) {\n return [key, Number(num)];\n }\n try {\n return [key, JSON.parse(str)];\n } catch {\n return [key, str];\n }\n }),\n );\n\n return {\n type: \"tool\",\n tool_request_id: content.id ?? crypto.randomUUID(),\n tool: name,\n params: params,\n } as ToolContent;\n }\n}\n"],"mappings":"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","names":["crypto","message","usage","rest","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/google-provider.ts","../src/google-tool-code-context-transformer.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport * as gemini from \"@google/genai\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n CancellationToken,\n CompletionResponseData,\n Content,\n EnumParameterType,\n Message,\n ModelProvider,\n ModelRequest,\n ParameterType,\n ProviderContextTransformer,\n StreamReceiver,\n ToolDefinition,\n} from \"@simulacra-ai/core\";\nimport { deep_merge, peek_generator, undefined_if_empty } from \"@simulacra-ai/core\";\nimport { GoogleToolCodeContextTransformer } from \"./google-tool-code-context-transformer.ts\";\n\n/**\n * Configuration options for the Google Gemini provider.\n */\nexport interface GoogleProviderConfig extends Record<string, unknown> {\n /** The model identifier to use (e.g., \"gemini-2.0-flash-exp\"). */\n model: string;\n /** The maximum number of tokens to generate in the response. */\n max_tokens?: number;\n /** Configuration for extended thinking mode. */\n thinking?: {\n /** Whether to enable extended thinking. */\n enable: boolean;\n /** The token budget allocated for thinking. */\n budget_tokens?: number;\n };\n}\n\n/**\n * Model provider implementation for Google's Gemini models.\n *\n * This provider wraps the Google Generative AI SDK to provide streaming completions\n * with support for tool use, extended thinking, and multimodal content. It handles\n * message formatting, content streaming, and usage tracking according to the\n * ModelProvider interface.\n */\nexport class GoogleProvider implements ModelProvider {\n readonly #sdk: gemini.GoogleGenAI;\n readonly #config: GoogleProviderConfig;\n\n readonly context_transformers: ProviderContextTransformer[];\n\n /**\n * Creates a new Google Gemini provider instance.\n *\n * @param sdk - The initialized Google Generative AI SDK client.\n * @param config - Configuration options for the provider.\n * @param context_transformers - Provider-level context transformers. Defaults to GoogleToolCodeContextTransformer.\n */\n constructor(\n sdk: gemini.GoogleGenAI,\n config: GoogleProviderConfig,\n context_transformers: ProviderContextTransformer[] = [new GoogleToolCodeContextTransformer()],\n ) {\n this.#sdk = sdk;\n this.#config = config;\n this.context_transformers = context_transformers;\n }\n\n /**\n * Executes a model request and streams the response through the provided receiver.\n *\n * @param request - The request containing messages, tools, and system prompt.\n * @param receiver - The receiver that handles streaming events.\n * @param cancellation - Token to signal cancellation of the request.\n * @returns A promise that resolves when the request completes.\n */\n async execute_request(\n request: ModelRequest,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ): Promise<void> {\n const { model, max_tokens, thinking, ...api_extras } = this.#config;\n const params: gemini.GenerateContentParameters = {\n model,\n\n config: {\n ...api_extras,\n systemInstruction: request.system,\n maxOutputTokens: max_tokens,\n thinkingConfig: {\n includeThoughts: thinking?.enable,\n thinkingBudget: thinking?.budget_tokens,\n },\n ...(request.tools.length > 0\n ? {\n tools: [\n {\n functionDeclarations: request.tools.map((t) => to_gemini_tool(t)),\n },\n ],\n }\n : {}),\n },\n contents: request.messages.map((m) => to_gemini_content(m)),\n };\n receiver.before_request({ params });\n receiver.request_raw(params);\n\n const response = await this.#sdk.models.generateContentStream(params);\n const { peeked_value: _peeked_value, generator } = (await peek_generator(response)) as {\n peeked_value: gemini.GenerateContentResponse;\n generator: AsyncGenerator<gemini.GenerateContentResponse>;\n };\n\n // Intentionally not awaited. Streaming is event-driven through the receiver.\n // The policy wraps only connection establishment; chunk processing flows\n // asynchronously via StreamListener events back to the conversation.\n this.#stream_response(generator, receiver, cancellation);\n }\n\n /**\n * Creates a clone of this provider with the same configuration.\n *\n * @returns A new provider instance with identical configuration.\n */\n clone(): ModelProvider {\n return new GoogleProvider(this.#sdk, this.#config, this.context_transformers);\n }\n\n async #stream_response(\n stream: AsyncGenerator<gemini.GenerateContentResponse>,\n receiver: StreamReceiver,\n cancellation: CancellationToken,\n ) {\n try {\n let response: Partial<gemini.GenerateContentResponse> | undefined;\n const completed_parts = new Set<number>();\n for await (const response_chunk of stream) {\n if (cancellation.is_cancellation_requested) {\n receiver.cancel();\n return;\n }\n receiver.stream_raw(response_chunk);\n\n const { candidates: candidates_chunk, ...rest } = response_chunk;\n response = {\n ...response,\n ...rest,\n candidates: response?.candidates ?? [],\n };\n const candidates = response.candidates as gemini.Candidate[];\n\n for (const candidate_chunk of candidates_chunk ?? []) {\n if (!candidates[candidate_chunk.index ?? 0]) {\n candidates[candidate_chunk.index ?? 0] = candidate_chunk;\n const message = from_gemini_content(candidate_chunk.content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (const content of message.content) {\n receiver.start_content({ content, message, usage });\n }\n receiver.start_message({ message, usage });\n continue;\n }\n const { content: content_chunk, ...rest } = candidate_chunk;\n const candidate = (candidates[candidate_chunk.index ?? 0] = {\n ...candidates[candidate_chunk.index ?? 0],\n ...rest,\n content: {\n ...candidates[candidate_chunk.index ?? 0]?.content,\n parts: candidates[candidate_chunk.index ?? 0]?.content?.parts ?? [],\n },\n });\n\n for (const part_chunk of content_chunk?.parts ?? []) {\n const [part] = candidate.content.parts.slice(-1);\n if (!part) {\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n } else {\n if (part_chunk.thought && part.thought) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (!part_chunk.thought && !part.thought && part_chunk.text && part.text) {\n part.text = (part.text ?? \"\") + (part_chunk.text ?? \"\");\n } else if (part_chunk.functionCall && part.functionCall) {\n part.functionCall = deep_merge(part.functionCall, part_chunk.functionCall);\n } else if (part_chunk.executableCode && part.executableCode) {\n if (part_chunk.executableCode.code && part.executableCode.code) {\n part.executableCode.code += part_chunk.executableCode.code;\n delete part_chunk.executableCode.code;\n }\n part.executableCode = deep_merge(part.executableCode, part_chunk.executableCode);\n } else if (part_chunk.videoMetadata && part.videoMetadata) {\n part.videoMetadata = deep_merge(part.videoMetadata, part_chunk.videoMetadata);\n } else if (part_chunk.fileData && part.fileData) {\n part.fileData = deep_merge(part.fileData, part_chunk.fileData);\n } else if (part_chunk.inlineData && part.inlineData) {\n part.inlineData = deep_merge(part.inlineData, part_chunk.inlineData);\n } else {\n receiver.complete_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n completed_parts.add(candidate.content.parts.length - 1);\n candidate.content.parts.push(part_chunk);\n receiver.start_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part_chunk) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n receiver.update_message({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n usage: from_gemini_usage(response?.usageMetadata),\n });\n continue;\n }\n receiver.update_content({\n message: from_gemini_content(candidate.content) as AssistantMessage,\n content: from_gemini_part(part) as AssistantContent,\n usage: from_gemini_usage(response.usageMetadata),\n });\n }\n }\n }\n }\n if (!response || !response.candidates?.[0]) {\n throw new Error(\"no data\", { cause: JSON.stringify(response?.promptFeedback ?? response) });\n }\n receiver.response_raw({ ...response });\n\n const message = from_gemini_content(response.candidates[0].content) as AssistantMessage;\n const usage = from_gemini_usage(response.usageMetadata);\n for (let i = 0; i < message.content.length; i++) {\n if (!completed_parts.has(i)) {\n receiver.complete_content({ content: message.content[i], message, usage });\n }\n }\n receiver.complete_message({ message, usage, ...map_stop_reason(response) });\n } catch (error) {\n receiver.error(error);\n }\n }\n}\n\nfunction to_gemini_tool(tool: ToolDefinition): gemini.FunctionDeclaration {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: gemini.Type.OBJECT,\n properties: undefined_if_empty(\n Object.fromEntries(\n tool.parameters.map((p) => [p.name, to_gemini_tool_schema(p, p.description)]),\n ),\n ),\n required: undefined_if_empty(tool.parameters.filter((p) => p.required).map((p) => p.name)),\n },\n };\n}\n\nfunction from_gemini_content(content?: gemini.Content) {\n if (!content) {\n return;\n }\n return {\n role: content.role === \"model\" ? \"assistant\" : \"user\",\n content: content.parts?.map((p: gemini.Part) => from_gemini_part(p)).filter(Boolean),\n };\n}\n\nfunction from_gemini_part(part: gemini.Part) {\n if (!part) {\n return;\n }\n if (part.thought) {\n return {\n type: \"thinking\",\n thought: part.text ?? \"\",\n };\n }\n if (\"text\" in part) {\n return {\n type: \"text\",\n text: part.text ?? \"\",\n };\n }\n if (part.functionCall) {\n return {\n type: \"tool\",\n tool_request_id: part.functionCall.id ?? crypto.randomUUID(),\n tool: part.functionCall.name ?? \"\",\n params: part.functionCall.args ?? {},\n };\n }\n if (part.functionResponse) {\n return {\n type: \"tool_result\",\n tool_request_id: part.functionResponse.id ?? \"\",\n tool: part.functionResponse.name ?? \"\",\n result: part.functionResponse.response ?? {},\n };\n }\n return {\n type: \"raw\",\n model_kind: \"google\",\n data: JSON.stringify(part),\n };\n}\n\nfunction to_gemini_content(message: Message): gemini.Content {\n return {\n role: message.role === \"assistant\" ? \"model\" : \"user\",\n parts: message.content.map((c) => to_gemini_part(c)),\n };\n}\n\nfunction to_gemini_part(content: Readonly<Content>) {\n switch (content.type) {\n case \"text\":\n return {\n text: content.text,\n };\n case \"tool\":\n return {\n functionCall: {\n id: content.tool_request_id,\n name: content.tool,\n args: content.params,\n },\n };\n case \"raw\":\n if (content.model_kind === \"google\") {\n try {\n return {\n ...JSON.parse(content.data),\n };\n } catch {\n return {\n text: content.data,\n };\n }\n }\n return {\n text: content.data,\n };\n case \"tool_result\":\n return {\n functionResponse: {\n id: content.tool_request_id,\n name: content.tool,\n response: content.result,\n },\n };\n case \"thinking\":\n return {\n thought: true,\n text: content.thought,\n };\n default:\n throw new Error(\"unexpected content type\");\n }\n}\n\nfunction to_gemini_tool_schema(parameter_type: ParameterType, description?: string): gemini.Schema {\n switch (parameter_type.type) {\n case \"string\":\n return {\n type: gemini.Type.STRING,\n description,\n enum: (parameter_type as EnumParameterType).enum,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"number\":\n return {\n type: gemini.Type.NUMBER,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"boolean\":\n return {\n type: gemini.Type.BOOLEAN,\n description,\n default: !parameter_type.required ? parameter_type.default : undefined,\n };\n case \"object\":\n return {\n type: gemini.Type.OBJECT,\n description,\n properties: Object.fromEntries(\n Object.entries(parameter_type.properties).map(([name, p]) => [\n name,\n to_gemini_tool_schema(p, p.description),\n ]),\n ),\n required: undefined_if_empty(\n Object.entries(parameter_type.properties)\n .filter(([, p]) => p.required)\n .map(([name]) => name),\n ),\n };\n case \"array\":\n return {\n type: gemini.Type.ARRAY,\n description,\n items: to_gemini_tool_schema(parameter_type.items, parameter_type.items.description),\n };\n }\n}\n\nfunction from_gemini_usage(usage: gemini.GenerateContentResponseUsageMetadata | undefined) {\n return {\n cache_read_input_tokens: usage?.cachedContentTokenCount,\n input_tokens: usage?.promptTokenCount,\n output_tokens: usage?.candidatesTokenCount,\n };\n}\n\nfunction map_stop_reason(\n response: Partial<gemini.GenerateContentResponse>,\n): Pick<CompletionResponseData, \"stop_reason\" | \"stop_details\"> {\n for (const { finishReason, finishMessage } of response?.candidates ?? []) {\n switch (finishReason) {\n case gemini.FinishReason.STOP:\n if (response.candidates?.[0].content?.parts?.some((p: gemini.Part) => !!p.functionCall)) {\n return {\n stop_reason: \"tool_use\",\n stop_details: finishMessage,\n };\n } else {\n return {\n stop_reason: \"end_turn\",\n stop_details: finishMessage,\n };\n }\n case gemini.FinishReason.MAX_TOKENS:\n return {\n stop_reason: \"max_tokens\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.MALFORMED_FUNCTION_CALL:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.SAFETY:\n case gemini.FinishReason.RECITATION:\n case gemini.FinishReason.LANGUAGE:\n case gemini.FinishReason.BLOCKLIST:\n case gemini.FinishReason.PROHIBITED_CONTENT:\n case gemini.FinishReason.SPII:\n case gemini.FinishReason.IMAGE_SAFETY:\n return {\n stop_reason: \"error\",\n stop_details: finishMessage,\n };\n case gemini.FinishReason.FINISH_REASON_UNSPECIFIED:\n }\n }\n return {\n stop_reason: \"other\",\n };\n}\n","import crypto from \"node:crypto\";\n\nimport type {\n AssistantContent,\n AssistantMessage,\n ProviderContextTransformer,\n TextContent,\n ToolContent,\n} from \"@simulacra-ai/core\";\n\n/**\n * Provider context transformer that extracts tool calls from Gemini's code execution blocks.\n *\n * Gemini models sometimes return tool calls as executable code in markdown code blocks\n * tagged with \"tool_code\". This transformer parses those blocks and converts them into\n * standard tool call content that the framework can execute.\n */\nexport class GoogleToolCodeContextTransformer implements ProviderContextTransformer {\n /**\n * Transforms completion messages by extracting tool calls from code blocks.\n *\n * Scans text content for code blocks tagged as \"tool_code\" and parses them into\n * proper tool call content. The original code blocks are replaced with newlines\n * in the text content.\n *\n * @param message - The completion message to transform.\n * @returns A promise resolving to the transformed message.\n */\n transform_completion(message: AssistantMessage) {\n if (message.role !== \"assistant\") {\n return Promise.resolve(message);\n }\n\n return Promise.resolve({\n ...message,\n content: message.content.flatMap((c) => {\n if (c.type !== \"text\") {\n return [c];\n }\n return this.extract_tool_calls(c);\n }),\n });\n }\n\n private extract_tool_calls(content: TextContent) {\n const tool_calls: ToolContent[] = [];\n const remaining_text = content.text.replaceAll(\n /```(?:tool_code)\\n(.*?)\\n```/gs,\n (_, tool_code) => {\n const tool_call = this.parse_tool_call(content, tool_code);\n if (tool_call) {\n tool_calls.push(tool_call);\n }\n return \"\\n\";\n },\n );\n\n return [{ ...content, text: remaining_text }, ...tool_calls] as AssistantContent[];\n }\n\n private parse_tool_call(content: AssistantContent, tool_code?: string) {\n const function_match = tool_code?.match(/^print\\((\\w+)\\((.*)\\)\\)$/);\n if (!function_match) {\n return;\n }\n const [_, name, params_text] = function_match;\n const params = Object.fromEntries(\n Array.from(\n params_text.matchAll(\n /(\\w+)\\s*=\\s*((\"(?:\\\\\"|[^\"])*\")|(-?[\\d.]+)|([Tt]rue|[Ff]alse))\\s*(,|$)/g,\n ),\n ).map(([_match, key, _full, str, num, bool]: string[]) => {\n if (bool !== undefined) {\n return [key, bool.toLocaleLowerCase() === \"true\"];\n }\n if (!isNaN(Number(num))) {\n return [key, Number(num)];\n }\n try {\n return [key, JSON.parse(str)];\n } catch {\n return [key, str];\n }\n }),\n );\n\n return {\n type: \"tool\",\n tool_request_id: content.id ?? crypto.randomUUID(),\n tool: name,\n params: params,\n } as ToolContent;\n }\n}\n"],"mappings":"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","names":["crypto","message","usage","rest","crypto"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simulacra-ai/google",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Google Gemini provider for the Simulacra conversation engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -20,12 +20,17 @@
|
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsup",
|
|
23
|
-
"clean": "rm -rf dist *.tsbuildinfo"
|
|
23
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest"
|
|
24
26
|
},
|
|
25
27
|
"peerDependencies": {
|
|
26
|
-
"@simulacra-ai/core": "0.0.
|
|
28
|
+
"@simulacra-ai/core": "0.0.8",
|
|
27
29
|
"@google/genai": ">=0.10.0 <2.0.0"
|
|
28
30
|
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"vitest": "^3.0.0"
|
|
33
|
+
},
|
|
29
34
|
"repository": {
|
|
30
35
|
"type": "git",
|
|
31
36
|
"url": "https://github.com/simulacra-ai/simulacra.git",
|