smoltalk 0.0.67 → 0.2.1
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/README.md +51 -154
- package/dist/client.d.ts +3 -3
- package/dist/client.js +9 -5
- package/dist/clients/anthropic.d.ts +4 -4
- package/dist/clients/anthropic.js +1 -1
- package/dist/clients/baseClient.d.ts +17 -20
- package/dist/clients/baseClient.js +21 -43
- package/dist/clients/google.d.ts +4 -4
- package/dist/clients/google.js +1 -1
- package/dist/clients/ollama.d.ts +4 -4
- package/dist/clients/ollama.js +1 -1
- package/dist/clients/openai.d.ts +4 -4
- package/dist/clients/openai.js +2 -1
- package/dist/clients/openaiResponses.d.ts +4 -4
- package/dist/clients/openaiResponses.js +2 -1
- package/dist/functions.d.ts +13 -10
- package/dist/functions.js +4 -55
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -2
- package/dist/model.d.ts +2 -5
- package/dist/model.js +11 -27
- package/dist/models.d.ts +2 -2
- package/dist/models.js +3 -1
- package/dist/testing/index.d.ts +9 -0
- package/dist/testing/index.js +41 -0
- package/dist/types.d.ts +52 -160
- package/dist/types.js +1 -1
- package/dist/util/logger.d.ts +17 -1
- package/dist/util/logger.js +68 -5
- package/package.json +15 -19
- package/dist/clients/llamaCpp.d.ts +0 -28
- package/dist/clients/llamaCpp.js +0 -316
- package/dist/latencyTracker.d.ts +0 -32
- package/dist/latencyTracker.js +0 -73
- package/dist/middleware.d.ts +0 -54
- package/dist/middleware.js +0 -321
- package/dist/strategies/baseStrategy.d.ts +0 -22
- package/dist/strategies/baseStrategy.js +0 -62
- package/dist/strategies/fallbackStrategy.d.ts +0 -14
- package/dist/strategies/fallbackStrategy.js +0 -122
- package/dist/strategies/fastestStrategy.d.ts +0 -19
- package/dist/strategies/fastestStrategy.js +0 -108
- package/dist/strategies/idStrategy.d.ts +0 -16
- package/dist/strategies/idStrategy.js +0 -62
- package/dist/strategies/index.d.ts +0 -17
- package/dist/strategies/index.js +0 -68
- package/dist/strategies/raceStrategy.d.ts +0 -12
- package/dist/strategies/raceStrategy.js +0 -72
- package/dist/strategies/randomStrategy.d.ts +0 -13
- package/dist/strategies/randomStrategy.js +0 -54
- package/dist/strategies/timeoutStrategy.d.ts +0 -13
- package/dist/strategies/timeoutStrategy.js +0 -65
- package/dist/strategies/types.d.ts +0 -78
- package/dist/strategies/types.js +0 -58
package/dist/clients/openai.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
-
import {
|
|
2
|
+
import { PromptResult, Result, SmolClient, SmolConfig, StreamChunk } from "../types.js";
|
|
3
3
|
import { BaseClient } from "./baseClient.js";
|
|
4
4
|
import { ModelName } from "../models.js";
|
|
5
|
-
export type SmolOpenAiConfig =
|
|
5
|
+
export type SmolOpenAiConfig = SmolConfig;
|
|
6
6
|
export declare class SmolOpenAi extends BaseClient implements SmolClient {
|
|
7
7
|
private client;
|
|
8
8
|
private logger;
|
|
@@ -13,6 +13,6 @@ export declare class SmolOpenAi extends BaseClient implements SmolClient {
|
|
|
13
13
|
private calculateUsageAndCost;
|
|
14
14
|
private buildRequest;
|
|
15
15
|
private rethrowAsSmolError;
|
|
16
|
-
_textSync(config:
|
|
17
|
-
_textStream(config:
|
|
16
|
+
_textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
17
|
+
_textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
|
18
18
|
}
|
package/dist/clients/openai.js
CHANGED
|
@@ -24,7 +24,7 @@ export class SmolOpenAi extends BaseClient {
|
|
|
24
24
|
return this.client;
|
|
25
25
|
}
|
|
26
26
|
getModel() {
|
|
27
|
-
return this.model.
|
|
27
|
+
return this.model.getModel();
|
|
28
28
|
}
|
|
29
29
|
calculateUsageAndCost(usageData) {
|
|
30
30
|
let usage;
|
|
@@ -64,6 +64,7 @@ export class SmolOpenAi extends BaseClient {
|
|
|
64
64
|
json_schema: {
|
|
65
65
|
name: config.responseFormatOptions?.name || "response",
|
|
66
66
|
schema: config.responseFormat.toJSONSchema(),
|
|
67
|
+
strict: !!config.responseFormatOptions?.strict,
|
|
67
68
|
},
|
|
68
69
|
};
|
|
69
70
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
-
import {
|
|
2
|
+
import { PromptResult, Result, SmolClient, SmolConfig, StreamChunk } from "../types.js";
|
|
3
3
|
import { BaseClient } from "./baseClient.js";
|
|
4
4
|
import { ModelName } from "../models.js";
|
|
5
|
-
export type SmolOpenAiResponsesConfig =
|
|
5
|
+
export type SmolOpenAiResponsesConfig = SmolConfig;
|
|
6
6
|
export declare class SmolOpenAiResponses extends BaseClient implements SmolClient {
|
|
7
7
|
private client;
|
|
8
8
|
private logger;
|
|
@@ -14,6 +14,6 @@ export declare class SmolOpenAiResponses extends BaseClient implements SmolClien
|
|
|
14
14
|
private buildRequest;
|
|
15
15
|
private calculateUsageAndCost;
|
|
16
16
|
private rethrowAsSmolError;
|
|
17
|
-
_textSync(config:
|
|
18
|
-
_textStream(config:
|
|
17
|
+
_textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
18
|
+
_textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
|
19
19
|
}
|
|
@@ -24,7 +24,7 @@ export class SmolOpenAiResponses extends BaseClient {
|
|
|
24
24
|
return this.client;
|
|
25
25
|
}
|
|
26
26
|
getModel() {
|
|
27
|
-
return this.model.
|
|
27
|
+
return this.model.getModel();
|
|
28
28
|
}
|
|
29
29
|
convertMessages(config) {
|
|
30
30
|
const systemParts = [];
|
|
@@ -76,6 +76,7 @@ export class SmolOpenAiResponses extends BaseClient {
|
|
|
76
76
|
type: "json_schema",
|
|
77
77
|
name: config.responseFormatOptions?.name || "response",
|
|
78
78
|
schema: config.responseFormat.toJSONSchema(),
|
|
79
|
+
strict: !!config.responseFormatOptions?.strict,
|
|
79
80
|
},
|
|
80
81
|
};
|
|
81
82
|
}
|
package/dist/functions.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PromptConfig, PromptResult, SmolPromptConfig, StreamChunk } from "./types.js";
|
|
1
|
+
import { PromptResult, SmolConfig, StreamChunk } from "./types.js";
|
|
3
2
|
import { Result } from "./types/result.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
promptConfig: PromptConfig;
|
|
7
|
-
};
|
|
8
|
-
export declare function text(config: SmolPromptConfig & {
|
|
3
|
+
import type { z, ZodType } from "zod";
|
|
4
|
+
export declare function text(config: SmolConfig & {
|
|
9
5
|
stream: true;
|
|
10
6
|
}): AsyncGenerator<StreamChunk>;
|
|
11
|
-
export declare function text(config:
|
|
7
|
+
export declare function text<S extends ZodType>(config: Omit<SmolConfig, "responseFormat"> & {
|
|
8
|
+
responseFormat: S;
|
|
9
|
+
stream?: false;
|
|
10
|
+
}): Promise<Result<PromptResult<z.infer<S>>>>;
|
|
11
|
+
export declare function text(config: SmolConfig & {
|
|
12
12
|
stream?: false;
|
|
13
13
|
}): Promise<Result<PromptResult>>;
|
|
14
|
-
export declare function textSync(config:
|
|
15
|
-
|
|
14
|
+
export declare function textSync<S extends ZodType>(config: Omit<SmolConfig, "responseFormat"> & {
|
|
15
|
+
responseFormat: S;
|
|
16
|
+
}): Promise<Result<PromptResult<z.infer<S>>>>;
|
|
17
|
+
export declare function textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
18
|
+
export declare function textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
package/dist/functions.js
CHANGED
|
@@ -1,42 +1,6 @@
|
|
|
1
1
|
import { BaseMessage, messageFromJSON, } from "./classes/message/index.js";
|
|
2
|
-
import {
|
|
3
|
-
import { Model } from "./model.js";
|
|
4
|
-
import { BaseStrategy } from "./strategies/baseStrategy.js";
|
|
5
|
-
import { fromJSON } from "./strategies/index.js";
|
|
2
|
+
import { getClient } from "./client.js";
|
|
6
3
|
import { getLogger } from "./util/logger.js";
|
|
7
|
-
function getStrategy(model) {
|
|
8
|
-
if (model instanceof BaseStrategy)
|
|
9
|
-
return model;
|
|
10
|
-
return fromJSON(model);
|
|
11
|
-
}
|
|
12
|
-
/** Always creates a fresh strategy instance (safe for concurrent use). */
|
|
13
|
-
function getFreshStrategy(model) {
|
|
14
|
-
if (model instanceof BaseStrategy)
|
|
15
|
-
return fromJSON(model.toJSON());
|
|
16
|
-
return fromJSON(model);
|
|
17
|
-
}
|
|
18
|
-
export function splitConfig(config) {
|
|
19
|
-
const { openAiApiKey, googleApiKey, ollamaApiKey, anthropicApiKey, ollamaHost, model: rawModel, provider, logLevel, statelog, metadata, hooks, llamaCppModelDir, middleware, ...promptConfig } = config;
|
|
20
|
-
const _model = new Model(rawModel);
|
|
21
|
-
const model = _model.getResolvedModel();
|
|
22
|
-
return {
|
|
23
|
-
smolConfig: {
|
|
24
|
-
openAiApiKey,
|
|
25
|
-
googleApiKey,
|
|
26
|
-
ollamaApiKey,
|
|
27
|
-
anthropicApiKey,
|
|
28
|
-
ollamaHost,
|
|
29
|
-
model,
|
|
30
|
-
provider,
|
|
31
|
-
logLevel,
|
|
32
|
-
statelog,
|
|
33
|
-
metadata,
|
|
34
|
-
hooks,
|
|
35
|
-
llamaCppModelDir,
|
|
36
|
-
},
|
|
37
|
-
promptConfig,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
4
|
function fixMessagesIfNecessary(messages) {
|
|
41
5
|
if (messages && messages.length > 0) {
|
|
42
6
|
if (!(messages[0] instanceof BaseMessage)) {
|
|
@@ -47,30 +11,15 @@ function fixMessagesIfNecessary(messages) {
|
|
|
47
11
|
return messages;
|
|
48
12
|
}
|
|
49
13
|
export function text(config) {
|
|
50
|
-
if (config.stream)
|
|
14
|
+
if (config.stream)
|
|
51
15
|
return textStream(config);
|
|
52
|
-
}
|
|
53
16
|
return textSync(config);
|
|
54
17
|
}
|
|
55
18
|
export async function textSync(config) {
|
|
56
19
|
config.messages = fixMessagesIfNecessary(config.messages);
|
|
57
|
-
|
|
58
|
-
const runMain = (cfg) => { const s = getFreshStrategy(cfg.model); return s.textSync(cfg); };
|
|
59
|
-
const middlewareResult = await executeMiddlewareSync(config, runMain, runMain);
|
|
60
|
-
if (middlewareResult)
|
|
61
|
-
return middlewareResult;
|
|
62
|
-
}
|
|
63
|
-
const strategy = getStrategy(config.model);
|
|
64
|
-
const { middleware: _, ...configWithoutMiddleware } = config;
|
|
65
|
-
return strategy.textSync(configWithoutMiddleware);
|
|
20
|
+
return getClient(config).textSync(config);
|
|
66
21
|
}
|
|
67
22
|
export async function* textStream(config) {
|
|
68
23
|
config.messages = fixMessagesIfNecessary(config.messages);
|
|
69
|
-
|
|
70
|
-
yield* executeMiddlewareStream(config, (cfg) => { const s = getFreshStrategy(cfg.model); return s.textStream(cfg); }, (cfg) => { const s = getFreshStrategy(cfg.model); return s.textSync(cfg); });
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const strategy = getStrategy(config.model);
|
|
74
|
-
const { middleware: _, ...configWithoutMiddleware } = config;
|
|
75
|
-
yield* strategy.textStream(configWithoutMiddleware);
|
|
24
|
+
yield* getClient(config).textStream(config);
|
|
76
25
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,5 @@ export * from "./util/util.js";
|
|
|
7
7
|
export * from "./classes/message/index.js";
|
|
8
8
|
export * from "./functions.js";
|
|
9
9
|
export * from "./classes/ToolCall.js";
|
|
10
|
-
export
|
|
11
|
-
export {
|
|
12
|
-
export type { LatencySample } from "./latencyTracker.js";
|
|
13
|
-
export type { MiddlewareCheck, MiddlewareConfig, MiddlewareResult } from "./middleware.js";
|
|
10
|
+
export { getLogger, EgonLog } from "./util/logger.js";
|
|
11
|
+
export type { LogLevel } from "./util/logger.js";
|
package/dist/index.js
CHANGED
|
@@ -7,5 +7,4 @@ export * from "./util/util.js";
|
|
|
7
7
|
export * from "./classes/message/index.js";
|
|
8
8
|
export * from "./functions.js";
|
|
9
9
|
export * from "./classes/ToolCall.js";
|
|
10
|
-
export
|
|
11
|
-
export { latencyTracker } from "./latencyTracker.js";
|
|
10
|
+
export { getLogger, EgonLog } from "./util/logger.js";
|
package/dist/model.d.ts
CHANGED
|
@@ -2,14 +2,11 @@ import { ModelName, Provider } from "./models.js";
|
|
|
2
2
|
import { ModelLike } from "./types.js";
|
|
3
3
|
export declare class Model {
|
|
4
4
|
private model;
|
|
5
|
-
private resolvedModel;
|
|
6
5
|
private provider?;
|
|
7
6
|
constructor(model: ModelName, provider?: Provider);
|
|
8
|
-
getModel():
|
|
9
|
-
getResolvedModel(): string;
|
|
7
|
+
getModel(): ModelName;
|
|
10
8
|
getProvider(): Provider | undefined;
|
|
11
|
-
|
|
12
|
-
resolveModel(): ModelName;
|
|
9
|
+
private lookupProvider;
|
|
13
10
|
calculateCost(usage: {
|
|
14
11
|
inputTokens: number;
|
|
15
12
|
outputTokens: number;
|
package/dist/model.js
CHANGED
|
@@ -1,44 +1,28 @@
|
|
|
1
|
-
import { getModel, isTextModel } from "./models.js";
|
|
1
|
+
import { getModel, isTextModel, ModelNameSchema } from "./models.js";
|
|
2
2
|
import { SmolError } from "./smolError.js";
|
|
3
|
-
import { ModelNameSchema } from "./strategies/types.js";
|
|
4
3
|
import { round } from "./util/util.js";
|
|
5
4
|
export class Model {
|
|
6
5
|
model;
|
|
7
|
-
resolvedModel;
|
|
8
6
|
provider;
|
|
9
7
|
constructor(model, provider) {
|
|
8
|
+
if (!ModelNameSchema.safeParse(model).success) {
|
|
9
|
+
throw new SmolError(`Model ${JSON.stringify(model)} is not recognized. Please specify a known model name.`);
|
|
10
|
+
}
|
|
10
11
|
this.model = model;
|
|
11
|
-
this.
|
|
12
|
-
this.provider = provider || this.setProvider();
|
|
12
|
+
this.provider = provider || this.lookupProvider();
|
|
13
13
|
}
|
|
14
14
|
getModel() {
|
|
15
15
|
return this.model;
|
|
16
16
|
}
|
|
17
|
-
getResolvedModel() {
|
|
18
|
-
return this.resolvedModel;
|
|
19
|
-
}
|
|
20
17
|
getProvider() {
|
|
21
|
-
|
|
22
|
-
return this.provider;
|
|
23
|
-
}
|
|
24
|
-
return undefined;
|
|
18
|
+
return this.provider;
|
|
25
19
|
}
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
if (modelInfo) {
|
|
30
|
-
return modelInfo.provider;
|
|
31
|
-
}
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
resolveModel() {
|
|
35
|
-
if (ModelNameSchema.safeParse(this.model).success) {
|
|
36
|
-
return this.model;
|
|
37
|
-
}
|
|
38
|
-
throw new SmolError(`Model ${JSON.stringify(this.model)} is not recognized. Please specify a known model name.`);
|
|
20
|
+
lookupProvider() {
|
|
21
|
+
const modelInfo = getModel(this.model);
|
|
22
|
+
return modelInfo ? modelInfo.provider : undefined;
|
|
39
23
|
}
|
|
40
24
|
calculateCost(usage) {
|
|
41
|
-
const model = getModel(this.
|
|
25
|
+
const model = getModel(this.model);
|
|
42
26
|
if (!model || !isTextModel(model)) {
|
|
43
27
|
return null;
|
|
44
28
|
}
|
|
@@ -60,7 +44,7 @@ export class Model {
|
|
|
60
44
|
return `Model(${JSON.stringify(this.model)})`;
|
|
61
45
|
}
|
|
62
46
|
toJSON() {
|
|
63
|
-
return this.
|
|
47
|
+
return this.model;
|
|
64
48
|
}
|
|
65
49
|
static create(model, provider) {
|
|
66
50
|
if (model instanceof Model) {
|
package/dist/models.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const providers: readonly ["ollama", "
|
|
2
|
+
export declare const providers: readonly ["ollama", "openai", "openai-responses", "anthropic", "google", "replicate", "modal"];
|
|
3
3
|
export declare const ProviderSchema: z.ZodEnum<{
|
|
4
4
|
ollama: "ollama";
|
|
5
|
-
"llama-cpp": "llama-cpp";
|
|
6
5
|
openai: "openai";
|
|
7
6
|
"openai-responses": "openai-responses";
|
|
8
7
|
anthropic: "anthropic";
|
|
@@ -1226,3 +1225,4 @@ export declare function isImageModel(model: ModelType): model is ImageModel;
|
|
|
1226
1225
|
export declare function isTextModel(model: ModelType): model is TextModel;
|
|
1227
1226
|
export declare function isSpeechToTextModel(model: ModelType): model is SpeechToTextModel;
|
|
1228
1227
|
export declare function isEmbeddingsModel(model: ModelType): model is EmbeddingsModel;
|
|
1228
|
+
export declare const ModelNameSchema: z.ZodString;
|
package/dist/models.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export const providers = [
|
|
3
3
|
"ollama",
|
|
4
|
-
"llama-cpp",
|
|
5
4
|
"openai",
|
|
6
5
|
"openai-responses",
|
|
7
6
|
"anthropic",
|
|
@@ -673,3 +672,6 @@ export function isSpeechToTextModel(model) {
|
|
|
673
672
|
export function isEmbeddingsModel(model) {
|
|
674
673
|
return model.type === "embeddings";
|
|
675
674
|
}
|
|
675
|
+
export const ModelNameSchema = z
|
|
676
|
+
.string()
|
|
677
|
+
.regex(/^[a-zA-Z0-9._:-]+$/, "Model name must only contain letters, numbers, dots, underscores, hyphens, and colons");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseClient } from "../clients/baseClient.js";
|
|
2
|
+
import type { PromptResult, Result, SmolConfig, StreamChunk } from "../types.js";
|
|
3
|
+
export declare class TestProvider extends BaseClient {
|
|
4
|
+
private callIndex;
|
|
5
|
+
private nextResponse;
|
|
6
|
+
private cannedUsage;
|
|
7
|
+
_textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
8
|
+
_textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BaseClient } from "../clients/baseClient.js";
|
|
2
|
+
import { promptResult, success } from "../types.js";
|
|
3
|
+
const DEFAULT_RESPONSE = "test response";
|
|
4
|
+
export class TestProvider extends BaseClient {
|
|
5
|
+
callIndex = 0;
|
|
6
|
+
nextResponse(config) {
|
|
7
|
+
const responses = config.metadata?.testResponses;
|
|
8
|
+
if (Array.isArray(responses) && responses.length > 0) {
|
|
9
|
+
const response = responses[this.callIndex % responses.length];
|
|
10
|
+
this.callIndex += 1;
|
|
11
|
+
return response;
|
|
12
|
+
}
|
|
13
|
+
const single = config.metadata?.testResponse;
|
|
14
|
+
return single ?? DEFAULT_RESPONSE;
|
|
15
|
+
}
|
|
16
|
+
cannedUsage(config) {
|
|
17
|
+
return config.metadata?.testUsage;
|
|
18
|
+
}
|
|
19
|
+
async _textSync(config) {
|
|
20
|
+
const output = this.nextResponse(config);
|
|
21
|
+
return success(promptResult({
|
|
22
|
+
output,
|
|
23
|
+
toolCalls: [],
|
|
24
|
+
model: config.model,
|
|
25
|
+
usage: this.cannedUsage(config),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
async *_textStream(config) {
|
|
29
|
+
const output = this.nextResponse(config);
|
|
30
|
+
yield { type: "text", text: output };
|
|
31
|
+
yield {
|
|
32
|
+
type: "done",
|
|
33
|
+
result: promptResult({
|
|
34
|
+
output,
|
|
35
|
+
toolCalls: [],
|
|
36
|
+
model: config.model,
|
|
37
|
+
usage: this.cannedUsage(config),
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,21 +1,52 @@
|
|
|
1
1
|
export * from "./types/result.js";
|
|
2
|
-
import { LogLevel } from "
|
|
3
|
-
import type { MiddlewareConfig } from "./middleware.js";
|
|
2
|
+
import { LogLevel } from "./util/logger.js";
|
|
4
3
|
import z, { ZodType } from "zod";
|
|
5
4
|
import { Message } from "./classes/message/index.js";
|
|
6
5
|
import { ToolCall } from "./classes/ToolCall.js";
|
|
7
6
|
import { Model } from "./model.js";
|
|
8
7
|
import { ModelName } from "./models.js";
|
|
9
|
-
import { Strategy, StrategyJSON } from "./strategies/types.js";
|
|
10
8
|
import { Result } from "./types/result.js";
|
|
11
9
|
import { TokenUsage } from "./types/tokenUsage.js";
|
|
12
10
|
import { CostEstimate } from "./types/costEstimate.js";
|
|
13
11
|
export * from "./types/costEstimate.js";
|
|
14
12
|
export * from "./types/tokenUsage.js";
|
|
15
|
-
export type
|
|
13
|
+
export type SmolConfig = {
|
|
14
|
+
/** The model to use. */
|
|
15
|
+
model: ModelName;
|
|
16
|
+
/** Override the provider for the given model (e.g., use a custom endpoint for an OpenAI-compatible model). */
|
|
17
|
+
provider?: string;
|
|
18
|
+
/** API key for OpenAI. Required when using OpenAI models. */
|
|
19
|
+
openAiApiKey?: string;
|
|
20
|
+
/** API key for Google Gemini. Required when using Google models. */
|
|
21
|
+
googleApiKey?: string;
|
|
22
|
+
/** API key for Anthropic. Required when using Anthropic/Claude models. */
|
|
23
|
+
anthropicApiKey?: string;
|
|
24
|
+
/** API key for Ollama. Only needed when connecting to a cloud-hosted Ollama instance. */
|
|
25
|
+
ollamaApiKey?: string;
|
|
26
|
+
/** Base URL for the Ollama server. Defaults to localhost if not set. (Ollama only) */
|
|
27
|
+
ollamaHost?: string;
|
|
28
|
+
/** Log level for internal debug logging. */
|
|
29
|
+
logLevel?: LogLevel;
|
|
30
|
+
/** Configuration for Statelog observability/tracing integration. */
|
|
31
|
+
statelog?: Partial<{
|
|
32
|
+
host: string;
|
|
33
|
+
projectId: string;
|
|
34
|
+
traceId: string;
|
|
35
|
+
debugMode: boolean;
|
|
36
|
+
apiKey: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Lifecycle hooks called at various points during execution. */
|
|
39
|
+
hooks?: Partial<{
|
|
40
|
+
onStart: (config: SmolConfig) => void;
|
|
41
|
+
onToolCall: (toolCall: ToolCall) => void;
|
|
42
|
+
onEnd: (result: PromptResult) => void;
|
|
43
|
+
onError: (error: Error) => void;
|
|
44
|
+
}>;
|
|
45
|
+
/** Arbitrary metadata passed to custom model providers. */
|
|
46
|
+
metadata?: Record<string, any>;
|
|
16
47
|
/** The conversation messages to send to the model. */
|
|
17
48
|
messages: Message[];
|
|
18
|
-
/** Tools (functions) the model can call.
|
|
49
|
+
/** Tools (functions) the model can call. */
|
|
19
50
|
tools?: {
|
|
20
51
|
name: string;
|
|
21
52
|
description?: string;
|
|
@@ -23,9 +54,9 @@ export type PromptConfig = {
|
|
|
23
54
|
}[];
|
|
24
55
|
/** Maximum number of tokens the model can generate in its response. */
|
|
25
56
|
maxTokens?: number;
|
|
26
|
-
/** Sampling temperature (0-2).
|
|
57
|
+
/** Sampling temperature (0-2). (OpenAI only) */
|
|
27
58
|
temperature?: number;
|
|
28
|
-
/** Number of alternative completions to generate.
|
|
59
|
+
/** Number of alternative completions to generate. */
|
|
29
60
|
numSuggestions?: number;
|
|
30
61
|
/** Whether the model can call multiple tools in a single turn. (OpenAI Responses API only) */
|
|
31
62
|
parallelToolCalls?: boolean;
|
|
@@ -33,40 +64,17 @@ export type PromptConfig = {
|
|
|
33
64
|
responseFormat?: ZodType;
|
|
34
65
|
/** If true, returns an AsyncGenerator of StreamChunks instead of a single result. */
|
|
35
66
|
stream?: boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Enable extended thinking / thought signatures.
|
|
38
|
-
* When enabled, the model returns its reasoning process alongside the response.
|
|
39
|
-
* (Anthropic and Google only — OpenAI reasoning tokens are not exposed)
|
|
40
|
-
*/
|
|
67
|
+
/** Enable extended thinking / thought signatures. (Anthropic and Google only) */
|
|
41
68
|
thinking?: {
|
|
42
|
-
/** Whether to enable extended thinking. */
|
|
43
69
|
enabled: boolean;
|
|
44
|
-
/** Token budget for the thinking process. Defaults to 5000. (Anthropic only) */
|
|
45
70
|
budgetTokens?: number;
|
|
46
71
|
};
|
|
47
|
-
/**
|
|
48
|
-
* Provider-agnostic reasoning effort level.
|
|
49
|
-
* - OpenAI: passed as reasoning_effort / reasoning.effort
|
|
50
|
-
* - Anthropic: mapped to thinking budget (low=2048, medium=5000, high=10000)
|
|
51
|
-
* - Google: mapped to thinkingBudget (low=2048, medium=8192, high=16384)
|
|
52
|
-
* If `thinking` is also set, it takes precedence for Anthropic/Google.
|
|
53
|
-
*/
|
|
72
|
+
/** Provider-agnostic reasoning effort level. */
|
|
54
73
|
reasoningEffort?: "low" | "medium" | "high";
|
|
55
74
|
responseFormatOptions?: Partial<{
|
|
56
|
-
/**
|
|
57
|
-
* Identifier for the JSON schema sent to OpenAI's structured output API
|
|
58
|
-
* (e.g. "math_response"). Defaults to "response".
|
|
59
|
-
* OpenAI's json_schema response format *requires* a name field. The name helps
|
|
60
|
-
* OpenAI identify and cache the schema. Smoltalk defaults it to "response"
|
|
61
|
-
* so users don't have to think about it, but the option is there if someone
|
|
62
|
-
* wants to set a more descriptive name (OpenAI recommends it for clarity in their docs).
|
|
63
|
-
*/
|
|
64
75
|
name: string;
|
|
65
|
-
/** Whether to enforce strict schema adherence. */
|
|
66
76
|
strict: boolean;
|
|
67
|
-
/** Number of retries if validation fails. Defaults to 2 when strict is true. */
|
|
68
77
|
numRetries: number;
|
|
69
|
-
/** If true, strip extra keys from the response instead of failing validation. */
|
|
70
78
|
allowExtraKeys: boolean;
|
|
71
79
|
}>;
|
|
72
80
|
/** Arbitrary provider-specific attributes passed directly to the underlying API call. */
|
|
@@ -78,139 +86,21 @@ export type PromptConfig = {
|
|
|
78
86
|
/** Define behavior if too many repeated tool calls are detected (loop prevention). */
|
|
79
87
|
toolLoopDetection?: ToolLoopDetection;
|
|
80
88
|
};
|
|
81
|
-
export type SmolConfig = {
|
|
82
|
-
/** API key for OpenAI. Required when using OpenAI models. */
|
|
83
|
-
openAiApiKey?: string;
|
|
84
|
-
/** API key for Google Gemini. Required when using Google models. */
|
|
85
|
-
googleApiKey?: string;
|
|
86
|
-
/** API key for Anthropic. Required when using Anthropic/Claude models. */
|
|
87
|
-
anthropicApiKey?: string;
|
|
88
|
-
/** API key for Ollama. Only needed when connecting to a cloud-hosted Ollama instance. */
|
|
89
|
-
ollamaApiKey?: string;
|
|
90
|
-
/** Base URL for the Ollama server. Defaults to localhost if not set. (Ollama only) */
|
|
91
|
-
ollamaHost?: string;
|
|
92
|
-
/** Directory path for Llama.cpp models. Required when using the Llama.cpp client. */
|
|
93
|
-
llamaCppModelDir?: string;
|
|
94
|
-
/**
|
|
95
|
-
The given model determines both
|
|
96
|
-
- what client is used
|
|
97
|
-
- what strategy is executed.
|
|
98
|
-
|
|
99
|
-
## 1. Specifying a model directly
|
|
100
|
-
The simplest case is to specify the name of a model from lib/models.ts.
|
|
101
|
-
Example:
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
model: "claude-sonnet-4-6"
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## 2. Specifying a strategy
|
|
108
|
-
You can instead specify a strategy to execute. For example:
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
model: {
|
|
112
|
-
type: "race",
|
|
113
|
-
params: {
|
|
114
|
-
strategies: ["gemini-2.5-flash-lite", "gemini-2.5-pro"],
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
In this case, Smoltalk will run your request over using both LLMs simultaneously,
|
|
120
|
-
and take the response that finishes first.
|
|
121
|
-
|
|
122
|
-
You can also choose to specify fallbacks in case the first model
|
|
123
|
-
returns an error for some reason. This can be a good way to try something
|
|
124
|
-
with a fast model and then use a slower but more powerful model if the first one fails.
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
model: {
|
|
128
|
-
type: "fallback",
|
|
129
|
-
params: {
|
|
130
|
-
primaryStrategy: "gemini-2.5-flash-lite",
|
|
131
|
-
config: {
|
|
132
|
-
error: ["gemini-2.5-pro"],
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
You can of course combine strategies together to create more complex behavior:
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
const geminiLiteWithFallback = {
|
|
142
|
-
type: "fallback",
|
|
143
|
-
params: {
|
|
144
|
-
primaryStrategy: "gemini-2.5-flash-lite",
|
|
145
|
-
config: {
|
|
146
|
-
error: ["gemini-2.5-pro"],
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
model: {
|
|
152
|
-
type: "race",
|
|
153
|
-
params: {
|
|
154
|
-
strategies: ["gemini-2.5-pro", geminiLiteWithFallback],
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
*/
|
|
159
|
-
model: ModelParam;
|
|
160
|
-
/** Override the provider for the given model (e.g., use a custom endpoint for an OpenAI-compatible model). */
|
|
161
|
-
provider?: string;
|
|
162
|
-
/** Log level for internal debug logging. */
|
|
163
|
-
logLevel?: LogLevel;
|
|
164
|
-
/** Configuration for Statelog observability/tracing integration. */
|
|
165
|
-
statelog?: Partial<{
|
|
166
|
-
/** Statelog server host URL. */
|
|
167
|
-
host: string;
|
|
168
|
-
/** Project identifier for grouping traces. */
|
|
169
|
-
projectId: string;
|
|
170
|
-
/** Trace identifier for correlating related requests. */
|
|
171
|
-
traceId: string;
|
|
172
|
-
/** Enable debug mode for verbose Statelog output. */
|
|
173
|
-
debugMode: boolean;
|
|
174
|
-
/** API key for authenticating with the Statelog server. */
|
|
175
|
-
apiKey: string;
|
|
176
|
-
}>;
|
|
177
|
-
/** Lifecycle hooks called at various points during execution. */
|
|
178
|
-
hooks?: Partial<{
|
|
179
|
-
/** Called when the prompt execution starts. */
|
|
180
|
-
onStart: (config: PromptConfig) => void;
|
|
181
|
-
/** Called each time the model invokes a tool. */
|
|
182
|
-
onToolCall: (toolCall: ToolCall) => void;
|
|
183
|
-
/** Called when the prompt execution completes successfully. */
|
|
184
|
-
onEnd: (result: PromptResult) => void;
|
|
185
|
-
/** Called when an error occurs during execution. */
|
|
186
|
-
onError: (error: Error) => void;
|
|
187
|
-
/** Called when a strategy begins execution. */
|
|
188
|
-
onStrategyStart: (strategy: Strategy, config: SmolPromptConfig) => void;
|
|
189
|
-
}>;
|
|
190
|
-
/** Arbitrary metadata passed to custom model providers. */
|
|
191
|
-
metadata?: Record<string, any>;
|
|
192
|
-
/** Middleware checks that run LLM-based validation on the prompt before or alongside the main call. */
|
|
193
|
-
middleware?: MiddlewareConfig;
|
|
194
|
-
};
|
|
195
89
|
export type ToolLoopDetection = {
|
|
196
90
|
enabled: boolean;
|
|
197
91
|
maxCalls: number;
|
|
198
92
|
intervention?: "remove-tool" | "remove-all-tools" | "throw-error" | "halt-execution";
|
|
199
93
|
excludeTools?: string[];
|
|
200
94
|
};
|
|
201
|
-
export type
|
|
202
|
-
|
|
203
|
-
};
|
|
204
|
-
export type BaseClientConfig = ResolvedSmolConfig;
|
|
205
|
-
export type PromptResult = {
|
|
206
|
-
output: string | null;
|
|
95
|
+
export type PromptResult<T = string> = {
|
|
96
|
+
output: T | null;
|
|
207
97
|
toolCalls: ToolCall[];
|
|
208
98
|
thinkingBlocks?: ThinkingBlock[];
|
|
209
99
|
usage?: TokenUsage;
|
|
210
100
|
cost?: CostEstimate;
|
|
211
101
|
model?: ModelName;
|
|
212
102
|
};
|
|
213
|
-
export declare function promptResult({ output, toolCalls, thinkingBlocks, usage, cost, model, }: Partial<PromptResult
|
|
103
|
+
export declare function promptResult<T = string>({ output, toolCalls, thinkingBlocks, usage, cost, model, }: Partial<PromptResult<T>>): PromptResult<T>;
|
|
214
104
|
export type StreamChunk = {
|
|
215
105
|
type: "text";
|
|
216
106
|
text: string;
|
|
@@ -232,19 +122,21 @@ export type StreamChunk = {
|
|
|
232
122
|
error: string;
|
|
233
123
|
};
|
|
234
124
|
export interface SmolClient {
|
|
235
|
-
text(
|
|
236
|
-
textSync(config:
|
|
237
|
-
_textSync(config:
|
|
238
|
-
textStream(config:
|
|
239
|
-
_textStream(config:
|
|
125
|
+
text(config: SmolConfig): Promise<Result<PromptResult>> | AsyncGenerator<StreamChunk>;
|
|
126
|
+
textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
127
|
+
_textSync(config: SmolConfig): Promise<Result<PromptResult>>;
|
|
128
|
+
textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
|
129
|
+
_textStream(config: SmolConfig): AsyncGenerator<StreamChunk>;
|
|
240
130
|
}
|
|
241
|
-
export type SmolPromptConfig = PromptConfig & SmolConfig;
|
|
242
131
|
export type TextPart = {
|
|
243
132
|
type: "text";
|
|
244
133
|
text: string;
|
|
245
134
|
};
|
|
135
|
+
/** Loose variant of SmolConfig for `getClient()` — messages are not required at construction time. */
|
|
136
|
+
export type SmolClientConfig = Omit<SmolConfig, "messages"> & {
|
|
137
|
+
messages?: Message[];
|
|
138
|
+
};
|
|
246
139
|
export type ModelLike = ModelName | Model;
|
|
247
|
-
export type ModelParam = ModelName | Strategy | StrategyJSON;
|
|
248
140
|
export type ThinkingBlock = {
|
|
249
141
|
text: string;
|
|
250
142
|
signature: string;
|
package/dist/types.js
CHANGED
|
@@ -4,7 +4,7 @@ export * from "./types/costEstimate.js";
|
|
|
4
4
|
export * from "./types/tokenUsage.js";
|
|
5
5
|
export function promptResult({ output, toolCalls, thinkingBlocks, usage, cost, model, }) {
|
|
6
6
|
return {
|
|
7
|
-
output: output
|
|
7
|
+
output: (output ?? null),
|
|
8
8
|
toolCalls: toolCalls || [],
|
|
9
9
|
thinkingBlocks: thinkingBlocks,
|
|
10
10
|
usage,
|