smoltalk 0.0.45 → 0.0.46
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/clients/anthropic.js +10 -4
- package/dist/clients/baseClient.js +28 -0
- package/dist/clients/google.js +6 -0
- package/dist/clients/ollama.js +4 -0
- package/dist/clients/openai.js +5 -0
- package/dist/clients/openaiResponses.js +4 -0
- package/dist/statelogClient.d.ts +2 -0
- package/dist/statelogClient.js +13 -1
- package/dist/strategies/baseStrategy.d.ts +2 -0
- package/dist/strategies/baseStrategy.js +8 -0
- package/dist/strategies/fallbackStrategy.js +13 -0
- package/dist/strategies/raceStrategy.js +4 -0
- package/package.json +1 -1
|
@@ -84,14 +84,16 @@ export class SmolAnthropic extends BaseClient {
|
|
|
84
84
|
}
|
|
85
85
|
async _textSync(config) {
|
|
86
86
|
const { system, messages, tools, thinking } = this.buildRequest(config);
|
|
87
|
-
|
|
87
|
+
let debugData = {
|
|
88
88
|
model: this.getModel(),
|
|
89
89
|
max_tokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
90
90
|
messages,
|
|
91
91
|
system,
|
|
92
92
|
tools,
|
|
93
93
|
thinking,
|
|
94
|
-
}
|
|
94
|
+
};
|
|
95
|
+
this.logger.debug("Sending request to Anthropic:", debugData);
|
|
96
|
+
this.statelogClient?.promptRequest(debugData);
|
|
95
97
|
const signal = this.getAbortSignal(config);
|
|
96
98
|
const response = await this.client.messages.create({
|
|
97
99
|
model: this.getModel(),
|
|
@@ -107,6 +109,7 @@ export class SmolAnthropic extends BaseClient {
|
|
|
107
109
|
stream: false,
|
|
108
110
|
}, { ...(signal && { signal }) });
|
|
109
111
|
this.logger.debug("Response from Anthropic:", response);
|
|
112
|
+
this.statelogClient?.promptResponse(response);
|
|
110
113
|
let output = null;
|
|
111
114
|
const toolCalls = [];
|
|
112
115
|
const thinkingBlocks = [];
|
|
@@ -134,14 +137,16 @@ export class SmolAnthropic extends BaseClient {
|
|
|
134
137
|
}
|
|
135
138
|
async *_textStream(config) {
|
|
136
139
|
const { system, messages, tools, thinking } = this.buildRequest(config);
|
|
137
|
-
|
|
140
|
+
const streamDebugData = {
|
|
138
141
|
model: this.model,
|
|
139
142
|
max_tokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
140
143
|
messages,
|
|
141
144
|
system,
|
|
142
145
|
tools,
|
|
143
146
|
thinking,
|
|
144
|
-
}
|
|
147
|
+
};
|
|
148
|
+
this.logger.debug("Sending streaming request to Anthropic:", streamDebugData);
|
|
149
|
+
this.statelogClient?.promptRequest(streamDebugData);
|
|
145
150
|
const signal = this.getAbortSignal(config);
|
|
146
151
|
const stream = await this.client.messages.create({
|
|
147
152
|
model: this.model,
|
|
@@ -219,6 +224,7 @@ export class SmolAnthropic extends BaseClient {
|
|
|
219
224
|
}
|
|
220
225
|
}
|
|
221
226
|
this.logger.debug("Streaming response completed from Anthropic");
|
|
227
|
+
this.statelogClient?.promptResponse({ content, usage: { inputTokens, outputTokens } });
|
|
222
228
|
const toolCalls = [];
|
|
223
229
|
for (const block of toolBlocks.values()) {
|
|
224
230
|
const toolCall = new ToolCall(block.id, block.name, block.arguments);
|
|
@@ -49,6 +49,10 @@ export class BaseClient {
|
|
|
49
49
|
promptConfig.messages.length > promptConfig.maxMessages) {
|
|
50
50
|
const logger = getLogger();
|
|
51
51
|
logger.warn(`Message limit exceeded: ${promptConfig.messages.length} messages sent, but maxMessages is set to ${promptConfig.maxMessages}. Aborting request.`);
|
|
52
|
+
this.statelogClient?.debug("Message limit exceeded", {
|
|
53
|
+
messageCount: promptConfig.messages.length,
|
|
54
|
+
maxMessages: promptConfig.maxMessages,
|
|
55
|
+
});
|
|
52
56
|
return {
|
|
53
57
|
success: false,
|
|
54
58
|
error: `Message limit exceeded: ${promptConfig.messages.length} messages exceeds the maxMessages limit of ${promptConfig.maxMessages}`,
|
|
@@ -71,6 +75,10 @@ export class BaseClient {
|
|
|
71
75
|
// Request budget check
|
|
72
76
|
if (budget.requestBudget !== undefined &&
|
|
73
77
|
requestsUsed >= budget.requestBudget) {
|
|
78
|
+
this.statelogClient?.debug("Request budget exhausted", {
|
|
79
|
+
requestsUsed,
|
|
80
|
+
requestBudget: budget.requestBudget,
|
|
81
|
+
});
|
|
74
82
|
return {
|
|
75
83
|
config,
|
|
76
84
|
failure: {
|
|
@@ -83,6 +91,10 @@ export class BaseClient {
|
|
|
83
91
|
if (budget.tokenBudget !== undefined) {
|
|
84
92
|
const remaining = budget.tokenBudget - tokensUsed;
|
|
85
93
|
if (remaining <= 0) {
|
|
94
|
+
this.statelogClient?.debug("Token budget exhausted", {
|
|
95
|
+
tokensUsed,
|
|
96
|
+
tokenBudget: budget.tokenBudget,
|
|
97
|
+
});
|
|
86
98
|
return {
|
|
87
99
|
config,
|
|
88
100
|
failure: {
|
|
@@ -97,6 +109,10 @@ export class BaseClient {
|
|
|
97
109
|
if (budget.costBudget !== undefined) {
|
|
98
110
|
const remainingUSD = budget.costBudget - costUsed;
|
|
99
111
|
if (remainingUSD <= 0) {
|
|
112
|
+
this.statelogClient?.debug("Cost budget exhausted", {
|
|
113
|
+
costUsed,
|
|
114
|
+
costBudget: budget.costBudget,
|
|
115
|
+
});
|
|
100
116
|
return {
|
|
101
117
|
config,
|
|
102
118
|
failure: {
|
|
@@ -138,6 +154,10 @@ export class BaseClient {
|
|
|
138
154
|
const message = timeBudgetMs
|
|
139
155
|
? `Request timed out after ${timeBudgetMs}ms`
|
|
140
156
|
: "Request was aborted";
|
|
157
|
+
this.statelogClient?.debug("Request aborted or timed out", {
|
|
158
|
+
reason: message,
|
|
159
|
+
timeBudgetMs,
|
|
160
|
+
});
|
|
141
161
|
return { success: false, error: message };
|
|
142
162
|
}
|
|
143
163
|
throw err;
|
|
@@ -282,6 +302,10 @@ export class BaseClient {
|
|
|
282
302
|
if (err instanceof z.ZodError) {
|
|
283
303
|
logger.warn("Zod error details:", z.prettifyError(err));
|
|
284
304
|
}
|
|
305
|
+
this.statelogClient?.debug("Response format validation failed", {
|
|
306
|
+
retriesLeft: retries,
|
|
307
|
+
error: errorMessage,
|
|
308
|
+
});
|
|
285
309
|
this.statelogClient?.diff({
|
|
286
310
|
message: "Response format validation failed",
|
|
287
311
|
itemA: promptConfig.responseFormat,
|
|
@@ -353,6 +377,10 @@ export class BaseClient {
|
|
|
353
377
|
const message = timeBudgetMs
|
|
354
378
|
? `Request timed out after ${timeBudgetMs}ms`
|
|
355
379
|
: "Request was aborted";
|
|
380
|
+
this.statelogClient?.debug("Streaming request aborted or timed out", {
|
|
381
|
+
reason: message,
|
|
382
|
+
timeBudgetMs,
|
|
383
|
+
});
|
|
356
384
|
yield { type: "timeout", error: message };
|
|
357
385
|
}
|
|
358
386
|
else {
|
package/dist/clients/google.js
CHANGED
|
@@ -103,6 +103,7 @@ export class SmolGoogle extends BaseClient {
|
|
|
103
103
|
// make two requests instead
|
|
104
104
|
/*********** TOOL CALL REQUEST ************/
|
|
105
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
|
+
this.statelogClient?.debug("Google Gemini: splitting tool calls and structured response into separate requests", {});
|
|
106
107
|
const toolRequest = {
|
|
107
108
|
...request,
|
|
108
109
|
config: {
|
|
@@ -154,9 +155,11 @@ export class SmolGoogle extends BaseClient {
|
|
|
154
155
|
}
|
|
155
156
|
async __textSync(request) {
|
|
156
157
|
this.logger.debug("Sending request to Google Gemini:", JSON.stringify(request, null, 2));
|
|
158
|
+
this.statelogClient?.promptRequest(request);
|
|
157
159
|
// Send the prompt as the latest message
|
|
158
160
|
const result = await this.client.models.generateContent(request);
|
|
159
161
|
this.logger.debug("Response from Google Gemini:", JSON.stringify(result, null, 2));
|
|
162
|
+
this.statelogClient?.promptResponse(result);
|
|
160
163
|
const output = result.text || null;
|
|
161
164
|
const toolCalls = [];
|
|
162
165
|
const thinkingBlocks = [];
|
|
@@ -199,10 +202,12 @@ export class SmolGoogle extends BaseClient {
|
|
|
199
202
|
const hasStructuredResponse = !!config.responseFormat;
|
|
200
203
|
if (hasTools && hasStructuredResponse) {
|
|
201
204
|
this.logger.debug("Gemini does not support streaming responses with both tool calls and structured response formats. Response format will be ignored.");
|
|
205
|
+
this.statelogClient?.debug("Google Gemini: streaming with tools + structured response not supported, ignoring response format", {});
|
|
202
206
|
request.config.responseMimeType = undefined;
|
|
203
207
|
request.config.responseJsonSchema = undefined;
|
|
204
208
|
}
|
|
205
209
|
this.logger.debug("Sending streaming request to Google Gemini:", JSON.stringify(request, null, 2));
|
|
210
|
+
this.statelogClient?.promptRequest(request);
|
|
206
211
|
const stream = await this.client.models.generateContentStream(request);
|
|
207
212
|
let content = "";
|
|
208
213
|
const toolCallsMap = new Map();
|
|
@@ -251,6 +256,7 @@ export class SmolGoogle extends BaseClient {
|
|
|
251
256
|
}
|
|
252
257
|
}
|
|
253
258
|
this.logger.debug("Streaming response completed from Google Gemini");
|
|
259
|
+
this.statelogClient?.promptResponse({ content, usage, cost });
|
|
254
260
|
// Yield tool calls
|
|
255
261
|
const toolCalls = [];
|
|
256
262
|
for (const tc of toolCallsMap.values()) {
|
package/dist/clients/ollama.js
CHANGED
|
@@ -70,6 +70,7 @@ export class SmolOllama extends BaseClient {
|
|
|
70
70
|
Object.assign(request, config.rawAttributes);
|
|
71
71
|
}
|
|
72
72
|
this.logger.debug("Sending request to Ollama:", JSON.stringify(request, null, 2));
|
|
73
|
+
this.statelogClient?.promptRequest(request);
|
|
73
74
|
const signal = this.getAbortSignal(config);
|
|
74
75
|
const abortHandler = signal ? () => this.client.abort() : undefined;
|
|
75
76
|
if (signal && abortHandler) {
|
|
@@ -81,6 +82,7 @@ export class SmolOllama extends BaseClient {
|
|
|
81
82
|
signal.removeEventListener("abort", abortHandler);
|
|
82
83
|
}
|
|
83
84
|
this.logger.debug("Response from Ollama:", JSON.stringify(result, null, 2));
|
|
85
|
+
this.statelogClient?.promptResponse(result);
|
|
84
86
|
const output = result.message?.content || null;
|
|
85
87
|
const toolCalls = [];
|
|
86
88
|
if (result.message?.tool_calls) {
|
|
@@ -116,6 +118,7 @@ export class SmolOllama extends BaseClient {
|
|
|
116
118
|
Object.assign(request, config.rawAttributes);
|
|
117
119
|
}
|
|
118
120
|
this.logger.debug("Sending streaming request to Ollama:", JSON.stringify(request, null, 2));
|
|
121
|
+
this.statelogClient?.promptRequest(request);
|
|
119
122
|
const signal = this.getAbortSignal(config);
|
|
120
123
|
const abortHandler = signal ? () => this.client.abort() : undefined;
|
|
121
124
|
if (signal && abortHandler) {
|
|
@@ -171,6 +174,7 @@ export class SmolOllama extends BaseClient {
|
|
|
171
174
|
usage = usageAndCost.usage;
|
|
172
175
|
cost = usageAndCost.cost;
|
|
173
176
|
}
|
|
177
|
+
this.statelogClient?.promptResponse({ content, usage, cost });
|
|
174
178
|
// Yield tool calls
|
|
175
179
|
const toolCalls = [];
|
|
176
180
|
for (const tc of toolCallsMap.values()) {
|
package/dist/clients/openai.js
CHANGED
|
@@ -71,12 +71,14 @@ export class SmolOpenAi extends BaseClient {
|
|
|
71
71
|
async _textSync(config) {
|
|
72
72
|
const request = this.buildRequest(config);
|
|
73
73
|
this.logger.debug("Sending request to OpenAI:", JSON.stringify(request, null, 2));
|
|
74
|
+
this.statelogClient?.promptRequest(request);
|
|
74
75
|
const signal = this.getAbortSignal(config);
|
|
75
76
|
const completion = await this.client.chat.completions.create({
|
|
76
77
|
...request,
|
|
77
78
|
stream: false,
|
|
78
79
|
}, { ...(signal && { signal }) });
|
|
79
80
|
this.logger.debug("Response from OpenAI:", JSON.stringify(completion, null, 2));
|
|
81
|
+
this.statelogClient?.promptResponse(completion);
|
|
80
82
|
const message = completion.choices[0].message;
|
|
81
83
|
const output = message.content;
|
|
82
84
|
const _toolCalls = message.tool_calls;
|
|
@@ -88,6 +90,7 @@ export class SmolOpenAi extends BaseClient {
|
|
|
88
90
|
}
|
|
89
91
|
else {
|
|
90
92
|
this.logger.warn(`Unsupported tool call type: ${tc.type} for tool call ID: ${tc.id}`);
|
|
93
|
+
this.statelogClient?.debug(`Unsupported tool call type: ${tc.type}`, { toolCallId: tc.id });
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
}
|
|
@@ -104,6 +107,7 @@ export class SmolOpenAi extends BaseClient {
|
|
|
104
107
|
async *_textStream(config) {
|
|
105
108
|
const request = this.buildRequest(config);
|
|
106
109
|
this.logger.debug("Sending streaming request to OpenAI:", JSON.stringify(request, null, 2));
|
|
110
|
+
this.statelogClient?.promptRequest(request);
|
|
107
111
|
const signal = this.getAbortSignal(config);
|
|
108
112
|
const completion = await this.client.chat.completions.create({
|
|
109
113
|
...request,
|
|
@@ -151,6 +155,7 @@ export class SmolOpenAi extends BaseClient {
|
|
|
151
155
|
}
|
|
152
156
|
}
|
|
153
157
|
this.logger.debug("Streaming response completed from OpenAI");
|
|
158
|
+
this.statelogClient?.promptResponse({ content, usage, cost });
|
|
154
159
|
const toolCalls = [];
|
|
155
160
|
for (const tc of toolCallsMap.values()) {
|
|
156
161
|
const toolCall = new ToolCall(tc.id, tc.name, tc.arguments);
|
|
@@ -105,12 +105,14 @@ export class SmolOpenAiResponses extends BaseClient {
|
|
|
105
105
|
async _textSync(config) {
|
|
106
106
|
const request = this.buildRequest(config);
|
|
107
107
|
this.logger.debug("Sending request to OpenAI Responses API:", JSON.stringify(request, null, 2));
|
|
108
|
+
this.statelogClient?.promptRequest(request);
|
|
108
109
|
const signal = this.getAbortSignal(config);
|
|
109
110
|
const response = await this.client.responses.create({
|
|
110
111
|
...request,
|
|
111
112
|
stream: false,
|
|
112
113
|
}, { ...(signal && { signal }) });
|
|
113
114
|
this.logger.debug("Response from OpenAI Responses API:", JSON.stringify(response, null, 2));
|
|
115
|
+
this.statelogClient?.promptResponse(response);
|
|
114
116
|
const output = response.output_text || null;
|
|
115
117
|
const toolCalls = [];
|
|
116
118
|
for (const item of response.output) {
|
|
@@ -130,6 +132,7 @@ export class SmolOpenAiResponses extends BaseClient {
|
|
|
130
132
|
async *_textStream(config) {
|
|
131
133
|
const request = this.buildRequest(config);
|
|
132
134
|
this.logger.debug("Sending streaming request to OpenAI Responses API:", JSON.stringify(request, null, 2));
|
|
135
|
+
this.statelogClient?.promptRequest(request);
|
|
133
136
|
const signal = this.getAbortSignal(config);
|
|
134
137
|
const stream = this.client.responses.stream(request, {
|
|
135
138
|
...(signal && { signal }),
|
|
@@ -200,6 +203,7 @@ export class SmolOpenAiResponses extends BaseClient {
|
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
this.logger.debug("Streaming response completed from OpenAI Responses API");
|
|
206
|
+
this.statelogClient?.promptResponse({ content, usage, cost });
|
|
203
207
|
const toolCalls = [];
|
|
204
208
|
for (const fc of functionCalls.values()) {
|
|
205
209
|
const toolCall = new ToolCall(fc.call_id, fc.name, fc.arguments);
|
package/dist/statelogClient.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ export declare class StatelogClient {
|
|
|
57
57
|
isConditionalEdge: boolean;
|
|
58
58
|
data: any;
|
|
59
59
|
}): Promise<void>;
|
|
60
|
+
promptRequest(data: Record<string, any>): Promise<void>;
|
|
61
|
+
promptResponse(data: Record<string, any>): Promise<void>;
|
|
60
62
|
promptCompletion({ messages, completion, model, timeTaken, tools, responseFormat, }: {
|
|
61
63
|
messages: any[];
|
|
62
64
|
completion: any;
|
package/dist/statelogClient.js
CHANGED
|
@@ -88,6 +88,18 @@ export class StatelogClient {
|
|
|
88
88
|
data,
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
+
async promptRequest(data) {
|
|
92
|
+
await this.post({
|
|
93
|
+
type: "promptRequest",
|
|
94
|
+
data,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async promptResponse(data) {
|
|
98
|
+
await this.post({
|
|
99
|
+
type: "promptResponse",
|
|
100
|
+
data,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
91
103
|
async promptCompletion({ messages, completion, model, timeTaken, tools, responseFormat, }) {
|
|
92
104
|
await this.post({
|
|
93
105
|
type: "promptCompletion",
|
|
@@ -286,7 +298,7 @@ export function getStatelogClient(config) {
|
|
|
286
298
|
const statelogConfig = {
|
|
287
299
|
host: config.host,
|
|
288
300
|
traceId: config.traceId || nanoid(),
|
|
289
|
-
apiKey: process.env.
|
|
301
|
+
apiKey: process.env.STATELOG_SMOLTALK_API_KEY || "",
|
|
290
302
|
projectId: config.projectId,
|
|
291
303
|
debugMode: config.debugMode || false,
|
|
292
304
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { StatelogClient } from "../statelogClient.js";
|
|
1
2
|
import { PromptResult, Result, SmolPromptConfig } from "../types.js";
|
|
2
3
|
import { Strategy, StrategyJSON } from "./types.js";
|
|
3
4
|
export declare class BaseStrategy implements Strategy {
|
|
5
|
+
statelogClient?: StatelogClient;
|
|
4
6
|
text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
5
7
|
textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
6
8
|
textStream(config: SmolPromptConfig): Promise<Result<AsyncIterable<PromptResult>>>;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
import { getStatelogClient } from "../statelogClient.js";
|
|
1
2
|
export class BaseStrategy {
|
|
3
|
+
statelogClient;
|
|
2
4
|
async text(config) {
|
|
5
|
+
this.statelogClient = config.statelog
|
|
6
|
+
? getStatelogClient(config.statelog)
|
|
7
|
+
: undefined;
|
|
3
8
|
if (config.hooks?.onStrategyStart) {
|
|
4
9
|
config.hooks.onStrategyStart(this, config);
|
|
5
10
|
}
|
|
6
11
|
return this._text({ ...config, strategy: undefined });
|
|
7
12
|
}
|
|
8
13
|
async textSync(config) {
|
|
14
|
+
this.statelogClient = config.statelog
|
|
15
|
+
? getStatelogClient(config.statelog)
|
|
16
|
+
: undefined;
|
|
9
17
|
return this._textSync({ ...config, strategy: undefined });
|
|
10
18
|
}
|
|
11
19
|
async textStream(config) {
|
|
@@ -30,15 +30,28 @@ export class FallbackStrategy extends BaseStrategy {
|
|
|
30
30
|
}
|
|
31
31
|
if (error instanceof SmolTimeoutError) {
|
|
32
32
|
if (this.config.fallbackOn.includes("timeout")) {
|
|
33
|
+
this.statelogClient?.debug("FallbackStrategy: falling back due to timeout", {
|
|
34
|
+
failedStrategy: strategy.toString(),
|
|
35
|
+
strategyIndex: i,
|
|
36
|
+
});
|
|
33
37
|
continue;
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
else if (error instanceof SmolStructuredOutputError) {
|
|
37
41
|
if (this.config.fallbackOn.includes("structuredOutputFailure")) {
|
|
42
|
+
this.statelogClient?.debug("FallbackStrategy: falling back due to structured output failure", {
|
|
43
|
+
failedStrategy: strategy.toString(),
|
|
44
|
+
strategyIndex: i,
|
|
45
|
+
});
|
|
38
46
|
continue;
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
if (this.config.fallbackOn.includes("error")) {
|
|
50
|
+
this.statelogClient?.debug("FallbackStrategy: falling back due to error", {
|
|
51
|
+
failedStrategy: strategy.toString(),
|
|
52
|
+
strategyIndex: i,
|
|
53
|
+
error: error.message,
|
|
54
|
+
});
|
|
42
55
|
continue;
|
|
43
56
|
}
|
|
44
57
|
throw error;
|
|
@@ -32,6 +32,10 @@ export class RaceStrategy extends BaseStrategy {
|
|
|
32
32
|
if (j !== i) {
|
|
33
33
|
const logger = getLogger();
|
|
34
34
|
logger.debug(`RaceStrategy: aborting strategy ${this.strategies[j]} because strategy ${this.strategies[i]} won the race.`);
|
|
35
|
+
this.statelogClient?.debug("RaceStrategy: aborting losing strategy", {
|
|
36
|
+
winner: this.strategies[i].toString(),
|
|
37
|
+
aborted: this.strategies[j].toString(),
|
|
38
|
+
});
|
|
35
39
|
controllers[j].abort();
|
|
36
40
|
}
|
|
37
41
|
}
|