smoltalk 0.0.42 → 0.0.44

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.
@@ -1,8 +1,13 @@
1
- import { GoogleGenAI } from "@google/genai";
1
+ import { Content, GenerateContentConfig, GoogleGenAI } from "@google/genai";
2
2
  import { BaseClientConfig, PromptConfig, PromptResult, Result, SmolClient, StreamChunk } from "../types.js";
3
3
  import { BaseClient } from "./baseClient.js";
4
4
  import { ModelName } from "../models.js";
5
5
  export type SmolGoogleConfig = BaseClientConfig;
6
+ type GeneratedRequest = {
7
+ contents: Content[];
8
+ model: ModelName;
9
+ config: GenerateContentConfig;
10
+ };
6
11
  export declare class SmolGoogle extends BaseClient implements SmolClient {
7
12
  private client;
8
13
  private logger;
@@ -13,5 +18,7 @@ export declare class SmolGoogle extends BaseClient implements SmolClient {
13
18
  private calculateUsageAndCost;
14
19
  private buildRequest;
15
20
  _textSync(config: PromptConfig): Promise<Result<PromptResult>>;
21
+ __textSync(request: GeneratedRequest): Promise<Result<PromptResult>>;
16
22
  _textStream(config: PromptConfig): AsyncGenerator<StreamChunk>;
17
23
  }
24
+ export {};
@@ -1,10 +1,11 @@
1
1
  import { GoogleGenAI } from "@google/genai";
2
2
  import { ToolCall } from "../classes/ToolCall.js";
3
3
  import { getLogger } from "../logger.js";
4
- import { success, } from "../types.js";
4
+ import { addCosts, addTokenUsage, success, } from "../types.js";
5
5
  import { zodToGoogleTool } from "../util/tool.js";
6
6
  import { BaseClient } from "./baseClient.js";
7
7
  import { Model } from "../model.js";
8
+ import { userMessage } from "../classes/message/index.js";
8
9
  export class SmolGoogle extends BaseClient {
9
10
  client;
10
11
  logger;
@@ -65,10 +66,7 @@ export class SmolGoogle extends BaseClient {
65
66
  if (tools.length > 0) {
66
67
  genConfig.tools = [{ functionDeclarations: tools }];
67
68
  }
68
- if (config.responseFormat && tools.length > 0) {
69
- console.error("Warning: Both responseFormat and tools are specified in the prompt config. Google Gemini does not support enforcing a response format when tools are included, so the responseFormat will be ignored.");
70
- }
71
- else if (config.responseFormat && tools.length === 0) {
69
+ if (config.responseFormat) {
72
70
  genConfig.responseMimeType = "application/json";
73
71
  genConfig.responseJsonSchema = config.responseFormat.toJSONSchema();
74
72
  }
@@ -94,6 +92,67 @@ export class SmolGoogle extends BaseClient {
94
92
  if (signal) {
95
93
  request.config = { ...request.config, abortSignal: signal };
96
94
  }
95
+ const hasTools = config.tools && config.tools.length > 0;
96
+ const hasStructuredResponse = !!config.responseFormat;
97
+ if (!hasTools && !hasStructuredResponse) {
98
+ // If there are no tools or structured response, we can make a single request and return immediately
99
+ return this.__textSync(request);
100
+ }
101
+ // Google Gemini does not support combining function calling with
102
+ // responseMimeType 'application/json'. When tools are present, we
103
+ // make two requests instead
104
+ /*********** TOOL CALL REQUEST ************/
105
+ this.logger.debug("Detected both tool calls and structured response in call to Google Gemini. Making separate request to Google Gemini for tool calls.");
106
+ const toolRequest = {
107
+ ...request,
108
+ config: {
109
+ ...request.config,
110
+ responseMimeType: undefined,
111
+ responseJsonSchema: undefined,
112
+ },
113
+ };
114
+ const toolResult = await this.__textSync(toolRequest);
115
+ if (!toolResult.success) {
116
+ return toolResult;
117
+ }
118
+ if (toolResult.value.toolCalls.length > 0) {
119
+ this.logger.debug("Tool calls detected. Returning tool calls without making second request for structured response.");
120
+ return toolResult;
121
+ }
122
+ if (!toolResult.value.output) {
123
+ throw new Error("No output or tool calls detected in Google Gemini response. This should not happen.");
124
+ }
125
+ this.logger.debug("No tool calls detected. Making second request to Google Gemini for structured response.");
126
+ /*********** STRUCTURED OUTPUT REQUEST ************/
127
+ const message = userMessage(`Please return this output in the specified structured format. Output: ${toolResult.value.output}`);
128
+ const messages = [message.toGoogleMessage()];
129
+ const responseRequest = {
130
+ ...request,
131
+ config: {
132
+ ...request.config,
133
+ tools: undefined,
134
+ },
135
+ messages,
136
+ };
137
+ const responseResult = await this.__textSync(responseRequest);
138
+ if (!responseResult.success) {
139
+ return responseResult;
140
+ }
141
+ const thinkingBlocks = [
142
+ ...(toolResult.value.thinkingBlocks || []),
143
+ ...(responseResult.value.thinkingBlocks || []),
144
+ ];
145
+ return success({
146
+ output: responseResult.value.output,
147
+ // if there were tool calls, we would have returned already, so we know these are empty
148
+ toolCalls: [],
149
+ ...(thinkingBlocks.length > 0 && { thinkingBlocks }),
150
+ usage: addTokenUsage(toolResult.value.usage, responseResult.value.usage),
151
+ cost: addCosts(toolResult.value.cost, responseResult.value.cost),
152
+ model: request.model,
153
+ });
154
+ }
155
+ async __textSync(request) {
97
156
  this.logger.debug("Sending request to Google Gemini:", JSON.stringify(request, null, 2));
98
157
  // Send the prompt as the latest message
99
158
  const result = await this.client.models.generateContent(request);
@@ -136,6 +195,13 @@ export class SmolGoogle extends BaseClient {
136
195
  if (signal) {
137
196
  request.config = { ...request.config, abortSignal: signal };
138
197
  }
198
+ const hasTools = config.tools && config.tools.length > 0;
199
+ const hasStructuredResponse = !!config.responseFormat;
200
+ if (hasTools && hasStructuredResponse) {
201
+ this.logger.debug("Gemini does not support streaming responses with both tool calls and structured response formats. Response format will be ignored.");
202
+ request.config.responseMimeType = undefined;
203
+ request.config.responseJsonSchema = undefined;
204
+ }
139
205
  this.logger.debug("Sending streaming request to Google Gemini:", JSON.stringify(request, null, 2));
140
206
  const stream = await this.client.models.generateContentStream(request);
141
207
  let content = "";
package/dist/model.js CHANGED
@@ -109,12 +109,12 @@ export class Model {
109
109
  if (!model || !isTextModel(model)) {
110
110
  return null;
111
111
  }
112
- const inputCost = round((usage.inputTokens * (model.inputTokenCost || 0)) / 1_000_000, 2);
113
- const outputCost = round((usage.outputTokens * (model.outputTokenCost || 0)) / 1_000_000, 2);
112
+ const inputCost = round((usage.inputTokens * (model.inputTokenCost || 0)) / 1_000_000, 6);
113
+ const outputCost = round((usage.outputTokens * (model.outputTokenCost || 0)) / 1_000_000, 6);
114
114
  const cachedInputCost = usage.cachedInputTokens && model.cachedInputTokenCost
115
- ? round((usage.cachedInputTokens * model.cachedInputTokenCost) / 1_000_000, 2)
115
+ ? round((usage.cachedInputTokens * model.cachedInputTokenCost) / 1_000_000, 6)
116
116
  : undefined;
117
- const totalCost = round(inputCost + outputCost + (cachedInputCost || 0), 2);
117
+ const totalCost = round(inputCost + outputCost + (cachedInputCost || 0), 6);
118
118
  return {
119
119
  inputCost,
120
120
  outputCost,