smoltalk 0.0.60 → 0.0.62
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/baseClient.js +5 -1
- package/dist/functions.js +16 -4
- package/dist/strategies/baseStrategy.d.ts +11 -3
- package/dist/strategies/baseStrategy.js +25 -3
- package/dist/strategies/fastestStrategy.d.ts +3 -1
- package/dist/strategies/fastestStrategy.js +32 -26
- package/dist/strategies/idStrategy.d.ts +3 -1
- package/dist/strategies/idStrategy.js +12 -4
- package/dist/strategies/raceStrategy.d.ts +2 -2
- package/dist/strategies/randomStrategy.d.ts +2 -1
- package/dist/strategies/randomStrategy.js +8 -0
- package/dist/strategies/types.d.ts +4 -3
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { userMessage, assistantMessage
|
|
1
|
+
import { userMessage, assistantMessage } from "../classes/message/index.js";
|
|
2
2
|
import { latencyTracker } from "../latencyTracker.js";
|
|
3
3
|
import { getLogger } from "../util/logger.js";
|
|
4
4
|
import { SmolStructuredOutputError } from "../smolError.js";
|
|
@@ -149,6 +149,10 @@ export class BaseClient {
|
|
|
149
149
|
return rawValue;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
// 1.5 Look for { type: "object", properties: { response: { ... } } } pattern
|
|
153
|
+
if (rawValue.type === "object" && rawValue.properties) {
|
|
154
|
+
return this.extractResponse(promptConfig, rawValue.properties, schema, depth + 1);
|
|
155
|
+
}
|
|
152
156
|
// 2. String → try JSON.parse, then recurse
|
|
153
157
|
if (typeof rawValue === "string") {
|
|
154
158
|
const stripped = rawValue
|
package/dist/functions.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseMessage, messageFromJSON, } from "./classes/message/index.js";
|
|
2
2
|
import { Model } from "./model.js";
|
|
3
3
|
import { BaseStrategy } from "./strategies/baseStrategy.js";
|
|
4
4
|
import { fromJSON } from "./strategies/index.js";
|
|
5
|
+
import { getLogger } from "./util/logger.js";
|
|
5
6
|
function getStrategy(model) {
|
|
6
7
|
if (model instanceof BaseStrategy)
|
|
7
8
|
return model;
|
|
@@ -29,16 +30,27 @@ export function splitConfig(config) {
|
|
|
29
30
|
promptConfig,
|
|
30
31
|
};
|
|
31
32
|
}
|
|
33
|
+
function fixMessagesIfNecessary(messages) {
|
|
34
|
+
if (messages && messages.length > 0) {
|
|
35
|
+
if (!(messages[0] instanceof BaseMessage)) {
|
|
36
|
+
getLogger().warn("Messages are not instances of smoltalk.BaseMessage");
|
|
37
|
+
return messages.map((m) => messageFromJSON(m));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return messages;
|
|
41
|
+
}
|
|
32
42
|
export function text(config) {
|
|
33
43
|
const strategy = getStrategy(config.model);
|
|
44
|
+
config.messages = fixMessagesIfNecessary(config.messages);
|
|
34
45
|
return strategy.text(config);
|
|
35
46
|
}
|
|
36
47
|
export function textSync(config) {
|
|
37
48
|
const strategy = getStrategy(config.model);
|
|
49
|
+
config.messages = fixMessagesIfNecessary(config.messages);
|
|
38
50
|
return strategy.textSync(config);
|
|
39
51
|
}
|
|
40
52
|
export function textStream(config) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
return
|
|
53
|
+
const strategy = getStrategy(config.model);
|
|
54
|
+
config.messages = fixMessagesIfNecessary(config.messages);
|
|
55
|
+
return strategy.textStream(config);
|
|
44
56
|
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { StatelogClient } from "../statelogClient.js";
|
|
2
|
-
import { PromptResult, Result, SmolPromptConfig } from "../types.js";
|
|
2
|
+
import { PromptResult, Result, SmolPromptConfig, StreamChunk } from "../types.js";
|
|
3
3
|
import { Strategy, StrategyJSON } from "./types.js";
|
|
4
4
|
export declare class BaseStrategy implements Strategy {
|
|
5
5
|
statelogClient?: StatelogClient;
|
|
6
|
-
text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
6
|
+
text(config: Omit<SmolPromptConfig, "stream">): Promise<Result<PromptResult>>;
|
|
7
|
+
text(config: Omit<SmolPromptConfig, "stream"> & {
|
|
8
|
+
stream: false;
|
|
9
|
+
}): Promise<Result<PromptResult>>;
|
|
10
|
+
text(config: Omit<SmolPromptConfig, "stream"> & {
|
|
11
|
+
stream: true;
|
|
12
|
+
}): AsyncGenerator<StreamChunk>;
|
|
13
|
+
text(config: SmolPromptConfig): Promise<Result<PromptResult>> | AsyncGenerator<StreamChunk>;
|
|
7
14
|
textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
8
|
-
textStream(config: SmolPromptConfig):
|
|
15
|
+
textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
9
16
|
_text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
10
17
|
_textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
18
|
+
_textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
11
19
|
toJSON(): StrategyJSON;
|
|
12
20
|
toString(): string;
|
|
13
21
|
toShortString(): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getStatelogClient } from "../statelogClient.js";
|
|
2
2
|
export class BaseStrategy {
|
|
3
3
|
statelogClient;
|
|
4
|
-
|
|
4
|
+
text(config) {
|
|
5
5
|
this.statelogClient = config.statelog
|
|
6
6
|
? getStatelogClient(config.statelog)
|
|
7
7
|
: undefined;
|
|
@@ -10,6 +10,9 @@ export class BaseStrategy {
|
|
|
10
10
|
this.statelogClient?.debug(`Calling onStrategyStart hook for strategy ${this.toString()}`);
|
|
11
11
|
config.hooks.onStrategyStart(this, config);
|
|
12
12
|
}
|
|
13
|
+
if (config.stream) {
|
|
14
|
+
return this.textStream(config);
|
|
15
|
+
}
|
|
13
16
|
return this._text(config);
|
|
14
17
|
}
|
|
15
18
|
async textSync(config) {
|
|
@@ -19,8 +22,12 @@ export class BaseStrategy {
|
|
|
19
22
|
this.statelogClient?.debug(`Starting strategy (sync) ${this.toString()}`);
|
|
20
23
|
return this._textSync(config);
|
|
21
24
|
}
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
textStream(config) {
|
|
26
|
+
this.statelogClient = config.statelog
|
|
27
|
+
? getStatelogClient(config.statelog)
|
|
28
|
+
: undefined;
|
|
29
|
+
this.statelogClient?.debug(`Starting strategy (stream) ${this.toString()}`);
|
|
30
|
+
return this._textStream(config);
|
|
24
31
|
}
|
|
25
32
|
async _text(config) {
|
|
26
33
|
throw new Error("_text method not implemented.");
|
|
@@ -28,6 +35,21 @@ export class BaseStrategy {
|
|
|
28
35
|
async _textSync(config) {
|
|
29
36
|
throw new Error("_textSync method not implemented.");
|
|
30
37
|
}
|
|
38
|
+
async *_textStream(config) {
|
|
39
|
+
const result = await this._textSync(config);
|
|
40
|
+
if (result.success) {
|
|
41
|
+
if (result.value.output) {
|
|
42
|
+
yield { type: "text", text: result.value.output };
|
|
43
|
+
}
|
|
44
|
+
for (const tc of result.value.toolCalls) {
|
|
45
|
+
yield { type: "tool_call", toolCall: tc };
|
|
46
|
+
}
|
|
47
|
+
yield { type: "done", result: result.value };
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
yield { type: "error", error: result.error };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
31
53
|
toJSON() {
|
|
32
54
|
throw new Error("toJSON method not implemented.");
|
|
33
55
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Model } from "../model.js";
|
|
2
|
-
import { PromptResult, Result, SmolPromptConfig } from "../types.js";
|
|
2
|
+
import { PromptResult, Result, SmolPromptConfig, StreamChunk } from "../types.js";
|
|
3
3
|
import { BaseStrategy } from "./baseStrategy.js";
|
|
4
4
|
import { StrategyJSON } from "./types.js";
|
|
5
5
|
export declare class FastestStrategy extends BaseStrategy {
|
|
@@ -8,7 +8,9 @@ export declare class FastestStrategy extends BaseStrategy {
|
|
|
8
8
|
constructor(models: (string | Model)[], epsilon?: number);
|
|
9
9
|
toString(): string;
|
|
10
10
|
toShortString(): string;
|
|
11
|
+
private chooseModel;
|
|
11
12
|
_text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
13
|
+
_textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
12
14
|
private pickFastest;
|
|
13
15
|
/** Get tokens/sec for a model: tracked latency first, then static estimate, then 0. */
|
|
14
16
|
private getSpeed;
|
|
@@ -20,47 +20,53 @@ export class FastestStrategy extends BaseStrategy {
|
|
|
20
20
|
toShortString() {
|
|
21
21
|
return `fastest([${this.models.map((s) => s.toString()).join(", ")}])`;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
chooseModel(config) {
|
|
24
24
|
const resolved = this.models.map((model) => Model.create(model));
|
|
25
|
-
let chosen = null;
|
|
26
25
|
const logger = getLogger(config.logLevel);
|
|
27
26
|
if (Math.random() < this.epsilon) {
|
|
28
27
|
// Explore: pick a random model
|
|
29
|
-
chosen = resolved[Math.floor(Math.random() * resolved.length)];
|
|
28
|
+
const chosen = resolved[Math.floor(Math.random() * resolved.length)];
|
|
30
29
|
logger.debug("fastest strategy - exploring random model", {
|
|
31
30
|
model: chosen.getResolvedModel(),
|
|
32
31
|
});
|
|
33
32
|
this.statelogClient?.debug("fastest strategy - picking random model", {
|
|
34
33
|
model: chosen.getResolvedModel(),
|
|
35
34
|
});
|
|
35
|
+
return chosen;
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
// we don't have latency data for any model, so just pick randomly
|
|
50
|
-
chosen = resolved[Math.floor(Math.random() * resolved.length)];
|
|
51
|
-
logger.debug("fastest strategy - no latency data, picking random model", {
|
|
52
|
-
models: resolved.map((m) => m.getResolvedModel()),
|
|
53
|
-
chosen: chosen.getResolvedModel(),
|
|
54
|
-
});
|
|
55
|
-
this.statelogClient?.debug("fastest strategy - no latency data, picking random model", {
|
|
56
|
-
models: resolved.map((m) => m.getResolvedModel()),
|
|
57
|
-
chosen,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
37
|
+
// Exploit: pick the fastest model by tracked latency
|
|
38
|
+
const fastest = this.pickFastest(resolved);
|
|
39
|
+
if (fastest) {
|
|
40
|
+
logger.debug("fastest strategy - exploiting fastest model", {
|
|
41
|
+
model: fastest.getResolvedModel(),
|
|
42
|
+
});
|
|
43
|
+
this.statelogClient?.debug("fastest strategy - using fastest model", {
|
|
44
|
+
model: fastest.getResolvedModel(),
|
|
45
|
+
});
|
|
46
|
+
return fastest;
|
|
60
47
|
}
|
|
48
|
+
// we don't have latency data for any model, so just pick randomly
|
|
49
|
+
const chosen = resolved[Math.floor(Math.random() * resolved.length)];
|
|
50
|
+
logger.debug("fastest strategy - no latency data, picking random model", {
|
|
51
|
+
models: resolved.map((m) => m.getResolvedModel()),
|
|
52
|
+
chosen: chosen.getResolvedModel(),
|
|
53
|
+
});
|
|
54
|
+
this.statelogClient?.debug("fastest strategy - no latency data, picking random model", {
|
|
55
|
+
models: resolved.map((m) => m.getResolvedModel()),
|
|
56
|
+
chosen,
|
|
57
|
+
});
|
|
58
|
+
return chosen;
|
|
59
|
+
}
|
|
60
|
+
async _text(config) {
|
|
61
|
+
const chosen = this.chooseModel(config);
|
|
61
62
|
const strategy = new IDStrategy(chosen);
|
|
62
63
|
return strategy.text(config);
|
|
63
64
|
}
|
|
65
|
+
async *_textStream(config) {
|
|
66
|
+
const chosen = this.chooseModel(config);
|
|
67
|
+
const strategy = new IDStrategy(chosen);
|
|
68
|
+
yield* strategy.textStream(config);
|
|
69
|
+
}
|
|
64
70
|
pickFastest(models) {
|
|
65
71
|
let best = null;
|
|
66
72
|
let bestSpeed = 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Model } from "../model.js";
|
|
2
|
-
import { ModelLike, PromptResult, Result, SmolPromptConfig } from "../types.js";
|
|
2
|
+
import { ModelLike, PromptResult, Result, SmolPromptConfig, StreamChunk } from "../types.js";
|
|
3
3
|
import { BaseStrategy } from "./baseStrategy.js";
|
|
4
4
|
import { StrategyJSON } from "./types.js";
|
|
5
5
|
export declare class IDStrategy extends BaseStrategy {
|
|
@@ -7,8 +7,10 @@ export declare class IDStrategy extends BaseStrategy {
|
|
|
7
7
|
constructor(model: ModelLike, provider?: string);
|
|
8
8
|
toString(): string;
|
|
9
9
|
toShortString(): string;
|
|
10
|
+
private _getClientAndConfig;
|
|
10
11
|
_text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
11
12
|
_textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
13
|
+
_textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
12
14
|
toJSON(): StrategyJSON;
|
|
13
15
|
static fromJSON(json: unknown): IDStrategy;
|
|
14
16
|
}
|
|
@@ -15,10 +15,7 @@ export class IDStrategy extends BaseStrategy {
|
|
|
15
15
|
toShortString() {
|
|
16
16
|
return `id(${this.model.toString()})`;
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
return this._textSync(config);
|
|
20
|
-
}
|
|
21
|
-
async _textSync(config) {
|
|
18
|
+
_getClientAndConfig(config) {
|
|
22
19
|
const configOverrides = {
|
|
23
20
|
model: this.model.getResolvedModel(),
|
|
24
21
|
provider: this.model.getProvider(),
|
|
@@ -31,8 +28,19 @@ export class IDStrategy extends BaseStrategy {
|
|
|
31
28
|
...smolConfig,
|
|
32
29
|
...configOverrides,
|
|
33
30
|
});
|
|
31
|
+
return { client, promptConfig };
|
|
32
|
+
}
|
|
33
|
+
async _text(config) {
|
|
34
|
+
return this._textSync(config);
|
|
35
|
+
}
|
|
36
|
+
async _textSync(config) {
|
|
37
|
+
const { client, promptConfig } = this._getClientAndConfig(config);
|
|
34
38
|
return client.textSync(promptConfig);
|
|
35
39
|
}
|
|
40
|
+
async *_textStream(config) {
|
|
41
|
+
const { client, promptConfig } = this._getClientAndConfig(config);
|
|
42
|
+
yield* client.textStream(promptConfig);
|
|
43
|
+
}
|
|
36
44
|
// todo: this toJSON isn't fully accurate as it resolves the model,
|
|
37
45
|
// so strategy vs strategy.fromJSON(strategy.toJSON()) won't be the same
|
|
38
46
|
toJSON() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModelParam, SmolPromptConfig } from "../types.js";
|
|
1
|
+
import { ModelParam, PromptResult, SmolPromptConfig } from "../types.js";
|
|
2
2
|
import { BaseStrategy } from "./baseStrategy.js";
|
|
3
3
|
import { Strategy, StrategyJSON } from "./types.js";
|
|
4
4
|
export declare class RaceStrategy extends BaseStrategy {
|
|
@@ -6,7 +6,7 @@ export declare class RaceStrategy extends BaseStrategy {
|
|
|
6
6
|
constructor(strategies: ModelParam[]);
|
|
7
7
|
toString(): string;
|
|
8
8
|
toShortString(): string;
|
|
9
|
-
_text(config: SmolPromptConfig): Promise<import("../types.js").Failure | import("../types.js").Success<
|
|
9
|
+
_text(config: SmolPromptConfig): Promise<import("../types.js").Failure | import("../types.js").Success<PromptResult>>;
|
|
10
10
|
toJSON(): StrategyJSON;
|
|
11
11
|
static fromJSON(json: unknown): RaceStrategy;
|
|
12
12
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ModelParam, PromptResult, Result, SmolPromptConfig } from "../types.js";
|
|
1
|
+
import { ModelParam, PromptResult, Result, SmolPromptConfig, StreamChunk } from "../types.js";
|
|
2
2
|
import { BaseStrategy } from "./baseStrategy.js";
|
|
3
3
|
import { Strategy, StrategyJSON } from "./types.js";
|
|
4
4
|
export declare class RandomStrategy extends BaseStrategy {
|
|
@@ -7,6 +7,7 @@ export declare class RandomStrategy extends BaseStrategy {
|
|
|
7
7
|
toString(): string;
|
|
8
8
|
toShortString(): string;
|
|
9
9
|
_text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
10
|
+
_textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
10
11
|
toJSON(): StrategyJSON;
|
|
11
12
|
static fromJSON(json: unknown): RandomStrategy;
|
|
12
13
|
}
|
|
@@ -23,6 +23,14 @@ export class RandomStrategy extends BaseStrategy {
|
|
|
23
23
|
const result = await strategy.text(config);
|
|
24
24
|
return result;
|
|
25
25
|
}
|
|
26
|
+
async *_textStream(config) {
|
|
27
|
+
const randomIndex = Math.floor(Math.random() * this.strategies.length);
|
|
28
|
+
const strategy = this.strategies[randomIndex];
|
|
29
|
+
this.statelogClient?.debug("random strategy chosen (stream)", {
|
|
30
|
+
strategy,
|
|
31
|
+
});
|
|
32
|
+
yield* strategy.textStream(config);
|
|
33
|
+
}
|
|
26
34
|
toJSON() {
|
|
27
35
|
return {
|
|
28
36
|
type: "random",
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { SmolPromptConfig, Result, PromptResult } from "../types.js";
|
|
2
|
+
import { SmolPromptConfig, Result, PromptResult, StreamChunk } from "../types.js";
|
|
3
3
|
export interface Strategy {
|
|
4
|
-
text(config: SmolPromptConfig): Promise<Result<PromptResult
|
|
4
|
+
text(config: SmolPromptConfig): Promise<Result<PromptResult>> | AsyncGenerator<StreamChunk>;
|
|
5
5
|
_text(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
6
6
|
textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
7
7
|
_textSync(config: SmolPromptConfig): Promise<Result<PromptResult>>;
|
|
8
|
-
textStream(config: SmolPromptConfig):
|
|
8
|
+
textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
9
|
+
_textStream(config: SmolPromptConfig): AsyncGenerator<StreamChunk>;
|
|
9
10
|
toJSON(): StrategyJSON;
|
|
10
11
|
toString(): string;
|
|
11
12
|
toShortString(): string;
|