@jaex/dstsx 0.1.0 → 0.1.2
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 +10 -0
- package/dist/index.cjs +265 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -10
- package/dist/index.d.ts +42 -10
- package/dist/index.js +264 -166
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -389,7 +389,7 @@ var LM = class {
|
|
|
389
389
|
#cache;
|
|
390
390
|
#diskCache;
|
|
391
391
|
#requestCount = 0;
|
|
392
|
-
#tokenUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
392
|
+
#tokenUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cachedPromptTokens: 0 };
|
|
393
393
|
constructor(model, cacheOptions = {}) {
|
|
394
394
|
this.model = model;
|
|
395
395
|
this.#cache = new LRUCache(cacheOptions.maxSize, cacheOptions.ttlMs);
|
|
@@ -423,6 +423,9 @@ var LM = class {
|
|
|
423
423
|
this.#tokenUsage.promptTokens += response.usage.promptTokens;
|
|
424
424
|
this.#tokenUsage.completionTokens += response.usage.completionTokens;
|
|
425
425
|
this.#tokenUsage.totalTokens += response.usage.totalTokens;
|
|
426
|
+
if (response.usage.cachedPromptTokens) {
|
|
427
|
+
this.#tokenUsage.cachedPromptTokens += response.usage.cachedPromptTokens;
|
|
428
|
+
}
|
|
426
429
|
}
|
|
427
430
|
return response;
|
|
428
431
|
}
|
|
@@ -469,21 +472,28 @@ var LM = class {
|
|
|
469
472
|
// src/lm/adapters/OpenAI.ts
|
|
470
473
|
var OpenAI = class extends LM {
|
|
471
474
|
#options;
|
|
475
|
+
#client;
|
|
472
476
|
constructor(options = {}) {
|
|
473
477
|
super(options.model ?? "gpt-4o");
|
|
474
478
|
this.#options = options;
|
|
475
479
|
}
|
|
480
|
+
async #getClient() {
|
|
481
|
+
if (!this.#client) {
|
|
482
|
+
const { default: Client } = await import("openai").catch(() => {
|
|
483
|
+
throw new Error(
|
|
484
|
+
"The `openai` package is required for the OpenAI adapter.\nInstall it with: npm install openai"
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
this.#client = new Client({
|
|
488
|
+
apiKey: this.#options.apiKey ?? process.env["OPENAI_API_KEY"],
|
|
489
|
+
baseURL: this.#options.baseURL,
|
|
490
|
+
maxRetries: this.#options.maxRetries ?? 3
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return this.#client;
|
|
494
|
+
}
|
|
476
495
|
async _call(prompt, config) {
|
|
477
|
-
const
|
|
478
|
-
throw new Error(
|
|
479
|
-
"The `openai` package is required for the OpenAI adapter.\nInstall it with: npm install openai"
|
|
480
|
-
);
|
|
481
|
-
});
|
|
482
|
-
const client = new OpenAIClient({
|
|
483
|
-
apiKey: this.#options.apiKey ?? process.env["OPENAI_API_KEY"],
|
|
484
|
-
baseURL: this.#options.baseURL,
|
|
485
|
-
maxRetries: this.#options.maxRetries ?? 3
|
|
486
|
-
});
|
|
496
|
+
const client = await this.#getClient();
|
|
487
497
|
const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
|
|
488
498
|
const response = await client.chat.completions.create({
|
|
489
499
|
model: config.model ?? this.model,
|
|
@@ -497,28 +507,21 @@ var OpenAI = class extends LM {
|
|
|
497
507
|
const texts = (response.choices ?? []).map(
|
|
498
508
|
(c) => c.message?.content ?? ""
|
|
499
509
|
);
|
|
510
|
+
const usageDetails = response.usage;
|
|
500
511
|
return {
|
|
501
512
|
text: texts[0] ?? "",
|
|
502
513
|
texts,
|
|
503
|
-
usage:
|
|
504
|
-
promptTokens:
|
|
505
|
-
completionTokens:
|
|
506
|
-
totalTokens:
|
|
514
|
+
usage: usageDetails ? {
|
|
515
|
+
promptTokens: usageDetails.prompt_tokens,
|
|
516
|
+
completionTokens: usageDetails.completion_tokens,
|
|
517
|
+
totalTokens: usageDetails.total_tokens,
|
|
518
|
+
...usageDetails.prompt_tokens_details?.cached_tokens ? { cachedPromptTokens: usageDetails.prompt_tokens_details.cached_tokens } : {}
|
|
507
519
|
} : null,
|
|
508
520
|
raw: response
|
|
509
521
|
};
|
|
510
522
|
}
|
|
511
523
|
async *stream(prompt, config = {}) {
|
|
512
|
-
const
|
|
513
|
-
throw new Error(
|
|
514
|
-
"The `openai` package is required for the OpenAI adapter.\nInstall it with: npm install openai"
|
|
515
|
-
);
|
|
516
|
-
});
|
|
517
|
-
const client = new OpenAIClient({
|
|
518
|
-
apiKey: this.#options.apiKey ?? process.env["OPENAI_API_KEY"],
|
|
519
|
-
baseURL: this.#options.baseURL,
|
|
520
|
-
maxRetries: this.#options.maxRetries ?? 3
|
|
521
|
-
});
|
|
524
|
+
const client = await this.#getClient();
|
|
522
525
|
const messages = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
|
|
523
526
|
const stream = await client.chat.completions.create({
|
|
524
527
|
model: config.model ?? this.model,
|
|
@@ -539,64 +542,164 @@ var OpenAI = class extends LM {
|
|
|
539
542
|
}
|
|
540
543
|
};
|
|
541
544
|
|
|
545
|
+
// src/settings/Settings.ts
|
|
546
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
547
|
+
var contextStore = new AsyncLocalStorage();
|
|
548
|
+
var Settings = class {
|
|
549
|
+
#global = {};
|
|
550
|
+
// ---------------------------------------------------------------------------
|
|
551
|
+
// Effective settings: async-context overrides take precedence over globals.
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
get #current() {
|
|
554
|
+
const ctx = contextStore.getStore();
|
|
555
|
+
return ctx !== void 0 ? { ...this.#global, ...ctx } : this.#global;
|
|
556
|
+
}
|
|
557
|
+
// ---------------------------------------------------------------------------
|
|
558
|
+
// Accessors
|
|
559
|
+
// ---------------------------------------------------------------------------
|
|
560
|
+
get lm() {
|
|
561
|
+
return this.#current.lm;
|
|
562
|
+
}
|
|
563
|
+
get rm() {
|
|
564
|
+
return this.#current.rm;
|
|
565
|
+
}
|
|
566
|
+
get lmConfig() {
|
|
567
|
+
return this.#current.lmConfig;
|
|
568
|
+
}
|
|
569
|
+
get logLevel() {
|
|
570
|
+
return this.#current.logLevel ?? "warn";
|
|
571
|
+
}
|
|
572
|
+
get cacheDir() {
|
|
573
|
+
return this.#current.cacheDir;
|
|
574
|
+
}
|
|
575
|
+
// ---------------------------------------------------------------------------
|
|
576
|
+
// Mutation
|
|
577
|
+
// ---------------------------------------------------------------------------
|
|
578
|
+
/**
|
|
579
|
+
* Merge `options` into the global settings. Existing keys are overwritten;
|
|
580
|
+
* omitted keys are unchanged. This does NOT affect currently running
|
|
581
|
+
* {@link Settings.context} scopes.
|
|
582
|
+
*/
|
|
583
|
+
configure(options) {
|
|
584
|
+
this.#global = { ...this.#global, ...options };
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Reset all global settings to their defaults.
|
|
588
|
+
*/
|
|
589
|
+
reset() {
|
|
590
|
+
this.#global = {};
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Return a deep-frozen snapshot of the currently effective settings
|
|
594
|
+
* (respects any active async-context overrides).
|
|
595
|
+
*/
|
|
596
|
+
inspect() {
|
|
597
|
+
return Object.freeze({ ...this.#current });
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Run `fn` inside an async-context-local settings scope.
|
|
601
|
+
*
|
|
602
|
+
* The `overrides` are merged on top of the current global settings and
|
|
603
|
+
* stored in an `AsyncLocalStorage` context. Concurrent calls each get
|
|
604
|
+
* their own isolated snapshot — they never overwrite each other's settings.
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```ts
|
|
608
|
+
* // In an Express/Fastify handler:
|
|
609
|
+
* await settings.context({ lm: perRequestLM }, () => program.forward(inputs));
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
async context(overrides, fn) {
|
|
613
|
+
const merged = { ...this.#global, ...overrides };
|
|
614
|
+
return contextStore.run(merged, fn);
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var settings = new Settings();
|
|
618
|
+
|
|
542
619
|
// src/lm/adapters/Anthropic.ts
|
|
543
620
|
var Anthropic = class extends LM {
|
|
544
621
|
#options;
|
|
622
|
+
#client;
|
|
545
623
|
constructor(options = {}) {
|
|
546
624
|
super(options.model ?? "claude-3-5-sonnet-20241022");
|
|
547
625
|
this.#options = options;
|
|
548
626
|
}
|
|
627
|
+
async #getClient() {
|
|
628
|
+
if (!this.#client) {
|
|
629
|
+
const { default: Client } = await import("@anthropic-ai/sdk").catch(() => {
|
|
630
|
+
throw new Error(
|
|
631
|
+
"The `@anthropic-ai/sdk` package is required for the Anthropic adapter.\nInstall it with: npm install @anthropic-ai/sdk"
|
|
632
|
+
);
|
|
633
|
+
});
|
|
634
|
+
this.#client = new Client({
|
|
635
|
+
apiKey: this.#options.apiKey ?? process.env["ANTHROPIC_API_KEY"],
|
|
636
|
+
maxRetries: this.#options.maxRetries ?? 3
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
return this.#client;
|
|
640
|
+
}
|
|
549
641
|
async _call(prompt, config) {
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
"The `@anthropic-ai/sdk` package is required for the Anthropic adapter.\nInstall it with: npm install @anthropic-ai/sdk"
|
|
553
|
-
);
|
|
554
|
-
});
|
|
555
|
-
const client = new Anthropic2({
|
|
556
|
-
apiKey: this.#options.apiKey ?? process.env["ANTHROPIC_API_KEY"],
|
|
557
|
-
maxRetries: this.#options.maxRetries ?? 3
|
|
558
|
-
});
|
|
642
|
+
const client = await this.#getClient();
|
|
643
|
+
const doCache = config.promptCaching ?? settings.lmConfig?.promptCaching ?? this.#options.promptCaching ?? false;
|
|
559
644
|
const msgs = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
|
|
560
645
|
const systemMsg = msgs.find((m) => m.role === "system");
|
|
561
646
|
const userMsgs = msgs.filter((m) => m.role !== "system");
|
|
647
|
+
let systemPayload;
|
|
648
|
+
if (systemMsg) {
|
|
649
|
+
systemPayload = doCache ? [{ type: "text", text: systemMsg.content, cache_control: { type: "ephemeral" } }] : systemMsg.content;
|
|
650
|
+
}
|
|
651
|
+
const messagesPayload = userMsgs.map((m, idx) => {
|
|
652
|
+
const isLast = idx === userMsgs.length - 1;
|
|
653
|
+
return {
|
|
654
|
+
role: m.role,
|
|
655
|
+
content: doCache && isLast ? [{ type: "text", text: m.content, cache_control: { type: "ephemeral" } }] : m.content
|
|
656
|
+
};
|
|
657
|
+
});
|
|
562
658
|
const response = await client.messages.create({
|
|
563
659
|
model: config.model ?? this.model,
|
|
564
660
|
max_tokens: config.maxTokens ?? 1024,
|
|
565
|
-
system:
|
|
566
|
-
messages:
|
|
661
|
+
system: systemPayload,
|
|
662
|
+
messages: messagesPayload,
|
|
567
663
|
temperature: config.temperature,
|
|
568
664
|
...config.extra ?? {}
|
|
569
665
|
});
|
|
570
666
|
const text = response.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("") ?? "";
|
|
667
|
+
const usage = response.usage;
|
|
668
|
+
const cachedInput = (usage.cache_read_input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0);
|
|
571
669
|
return {
|
|
572
670
|
text,
|
|
573
671
|
texts: [text],
|
|
574
|
-
usage:
|
|
575
|
-
promptTokens:
|
|
576
|
-
completionTokens:
|
|
577
|
-
totalTokens:
|
|
672
|
+
usage: usage ? {
|
|
673
|
+
promptTokens: usage.input_tokens,
|
|
674
|
+
completionTokens: usage.output_tokens,
|
|
675
|
+
totalTokens: usage.input_tokens + usage.output_tokens,
|
|
676
|
+
...cachedInput > 0 ? { cachedPromptTokens: cachedInput } : {}
|
|
578
677
|
} : null,
|
|
579
678
|
raw: response
|
|
580
679
|
};
|
|
581
680
|
}
|
|
582
681
|
async *stream(prompt, config = {}) {
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
"The `@anthropic-ai/sdk` package is required for the Anthropic adapter.\nInstall it with: npm install @anthropic-ai/sdk"
|
|
586
|
-
);
|
|
587
|
-
});
|
|
588
|
-
const client = new Anthropic2({
|
|
589
|
-
apiKey: this.#options.apiKey ?? process.env["ANTHROPIC_API_KEY"],
|
|
590
|
-
maxRetries: this.#options.maxRetries ?? 3
|
|
591
|
-
});
|
|
682
|
+
const client = await this.#getClient();
|
|
683
|
+
const doCache = config.promptCaching ?? settings.lmConfig?.promptCaching ?? this.#options.promptCaching ?? false;
|
|
592
684
|
const msgs = typeof prompt === "string" ? [{ role: "user", content: prompt }] : prompt;
|
|
593
685
|
const systemMsg = msgs.find((m) => m.role === "system");
|
|
594
686
|
const userMsgs = msgs.filter((m) => m.role !== "system");
|
|
687
|
+
let systemPayload;
|
|
688
|
+
if (systemMsg) {
|
|
689
|
+
systemPayload = doCache ? [{ type: "text", text: systemMsg.content, cache_control: { type: "ephemeral" } }] : systemMsg.content;
|
|
690
|
+
}
|
|
691
|
+
const messagesPayload = userMsgs.map((m, idx) => {
|
|
692
|
+
const isLast = idx === userMsgs.length - 1;
|
|
693
|
+
return {
|
|
694
|
+
role: m.role,
|
|
695
|
+
content: doCache && isLast ? [{ type: "text", text: m.content, cache_control: { type: "ephemeral" } }] : m.content
|
|
696
|
+
};
|
|
697
|
+
});
|
|
595
698
|
const stream = client.messages.stream({
|
|
596
699
|
model: config.model ?? this.model,
|
|
597
700
|
max_tokens: config.maxTokens ?? 1024,
|
|
598
|
-
system:
|
|
599
|
-
messages:
|
|
701
|
+
system: systemPayload,
|
|
702
|
+
messages: messagesPayload,
|
|
600
703
|
...config.extra ?? {}
|
|
601
704
|
});
|
|
602
705
|
for await (const event of stream) {
|
|
@@ -850,6 +953,9 @@ var MockLM = class extends LM {
|
|
|
850
953
|
};
|
|
851
954
|
|
|
852
955
|
// src/modules/Module.ts
|
|
956
|
+
function firstPrediction(result) {
|
|
957
|
+
return Array.isArray(result) ? result[0] ?? new Prediction({}) : result;
|
|
958
|
+
}
|
|
853
959
|
var Module = class _Module {
|
|
854
960
|
/**
|
|
855
961
|
* Recursively discover all {@link Predict} sub-modules by walking the own
|
|
@@ -913,80 +1019,6 @@ var Module = class _Module {
|
|
|
913
1019
|
}
|
|
914
1020
|
};
|
|
915
1021
|
|
|
916
|
-
// src/settings/Settings.ts
|
|
917
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
918
|
-
var contextStore = new AsyncLocalStorage();
|
|
919
|
-
var Settings = class {
|
|
920
|
-
#global = {};
|
|
921
|
-
// ---------------------------------------------------------------------------
|
|
922
|
-
// Effective settings: async-context overrides take precedence over globals.
|
|
923
|
-
// ---------------------------------------------------------------------------
|
|
924
|
-
get #current() {
|
|
925
|
-
const ctx = contextStore.getStore();
|
|
926
|
-
return ctx !== void 0 ? { ...this.#global, ...ctx } : this.#global;
|
|
927
|
-
}
|
|
928
|
-
// ---------------------------------------------------------------------------
|
|
929
|
-
// Accessors
|
|
930
|
-
// ---------------------------------------------------------------------------
|
|
931
|
-
get lm() {
|
|
932
|
-
return this.#current.lm;
|
|
933
|
-
}
|
|
934
|
-
get rm() {
|
|
935
|
-
return this.#current.rm;
|
|
936
|
-
}
|
|
937
|
-
get lmConfig() {
|
|
938
|
-
return this.#current.lmConfig;
|
|
939
|
-
}
|
|
940
|
-
get logLevel() {
|
|
941
|
-
return this.#current.logLevel ?? "warn";
|
|
942
|
-
}
|
|
943
|
-
get cacheDir() {
|
|
944
|
-
return this.#current.cacheDir;
|
|
945
|
-
}
|
|
946
|
-
// ---------------------------------------------------------------------------
|
|
947
|
-
// Mutation
|
|
948
|
-
// ---------------------------------------------------------------------------
|
|
949
|
-
/**
|
|
950
|
-
* Merge `options` into the global settings. Existing keys are overwritten;
|
|
951
|
-
* omitted keys are unchanged. This does NOT affect currently running
|
|
952
|
-
* {@link Settings.context} scopes.
|
|
953
|
-
*/
|
|
954
|
-
configure(options) {
|
|
955
|
-
this.#global = { ...this.#global, ...options };
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Reset all global settings to their defaults.
|
|
959
|
-
*/
|
|
960
|
-
reset() {
|
|
961
|
-
this.#global = {};
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* Return a deep-frozen snapshot of the currently effective settings
|
|
965
|
-
* (respects any active async-context overrides).
|
|
966
|
-
*/
|
|
967
|
-
inspect() {
|
|
968
|
-
return Object.freeze({ ...this.#current });
|
|
969
|
-
}
|
|
970
|
-
/**
|
|
971
|
-
* Run `fn` inside an async-context-local settings scope.
|
|
972
|
-
*
|
|
973
|
-
* The `overrides` are merged on top of the current global settings and
|
|
974
|
-
* stored in an `AsyncLocalStorage` context. Concurrent calls each get
|
|
975
|
-
* their own isolated snapshot — they never overwrite each other's settings.
|
|
976
|
-
*
|
|
977
|
-
* @example
|
|
978
|
-
* ```ts
|
|
979
|
-
* // In an Express/Fastify handler:
|
|
980
|
-
* await settings.context({ lm: perRequestLM }, () => program.forward(inputs));
|
|
981
|
-
* ```
|
|
982
|
-
*/
|
|
983
|
-
async context(overrides, fn) {
|
|
984
|
-
const merged = { ...this.#global, ...overrides };
|
|
985
|
-
return contextStore.run(merged, fn);
|
|
986
|
-
}
|
|
987
|
-
};
|
|
988
|
-
var settings = new Settings();
|
|
989
|
-
|
|
990
1022
|
// src/modules/Predict.ts
|
|
991
1023
|
var Predict = class extends Module {
|
|
992
1024
|
signature;
|
|
@@ -1006,9 +1038,7 @@ var Predict = class extends Module {
|
|
|
1006
1038
|
async forward(inputs) {
|
|
1007
1039
|
const lm = settings.lm;
|
|
1008
1040
|
if (!lm) {
|
|
1009
|
-
throw new Error(
|
|
1010
|
-
"No LM configured. Call settings.configure({ lm }) before using Predict."
|
|
1011
|
-
);
|
|
1041
|
+
throw new Error("No LM configured. Call settings.configure({ lm }) before using Predict.");
|
|
1012
1042
|
}
|
|
1013
1043
|
const prompt = this.#buildPrompt(inputs);
|
|
1014
1044
|
const config = settings.lmConfig ?? {};
|
|
@@ -1023,7 +1053,8 @@ var Predict = class extends Module {
|
|
|
1023
1053
|
*/
|
|
1024
1054
|
async *stream(inputs) {
|
|
1025
1055
|
const lm = settings.lm;
|
|
1026
|
-
if (!lm)
|
|
1056
|
+
if (!lm)
|
|
1057
|
+
throw new Error("No LM configured. Call settings.configure({ lm }) before using Predict.");
|
|
1027
1058
|
const prompt = this.#buildPrompt(inputs);
|
|
1028
1059
|
const config = settings.lmConfig ?? {};
|
|
1029
1060
|
yield* lm.stream(prompt, config);
|
|
@@ -1040,9 +1071,7 @@ var Predict = class extends Module {
|
|
|
1040
1071
|
}
|
|
1041
1072
|
load(state) {
|
|
1042
1073
|
if (Array.isArray(state["demos"])) {
|
|
1043
|
-
this.demos = state["demos"].map(
|
|
1044
|
-
(d) => new Example(d)
|
|
1045
|
-
);
|
|
1074
|
+
this.demos = state["demos"].map((d) => new Example(d));
|
|
1046
1075
|
}
|
|
1047
1076
|
if (typeof state["instructions"] === "string") {
|
|
1048
1077
|
this.instructions = state["instructions"];
|
|
@@ -1063,32 +1092,80 @@ var Predict = class extends Module {
|
|
|
1063
1092
|
}
|
|
1064
1093
|
}
|
|
1065
1094
|
lines.push(this.#formatInputs(inputs));
|
|
1066
|
-
for (const [name] of this.signature.outputs) {
|
|
1067
|
-
|
|
1095
|
+
for (const [name, meta] of this.signature.outputs) {
|
|
1096
|
+
const label = meta.prefix ?? `${name}:`;
|
|
1097
|
+
lines.push(label.endsWith(":") ? label : `${label}:`);
|
|
1068
1098
|
}
|
|
1069
1099
|
return lines.join("\n");
|
|
1070
1100
|
}
|
|
1071
1101
|
#formatExample(data) {
|
|
1072
|
-
|
|
1102
|
+
const formatField = (name, meta) => {
|
|
1103
|
+
const label = meta?.prefix ?? `${name}:`;
|
|
1104
|
+
const prefix = label.endsWith(":") ? label : `${label}:`;
|
|
1105
|
+
return `${prefix} ${String(data[name] ?? "")}`;
|
|
1106
|
+
};
|
|
1107
|
+
return [
|
|
1108
|
+
...[...this.signature.inputs].map(([name, meta]) => formatField(name, meta)),
|
|
1109
|
+
...[...this.signature.outputs].map(([name, meta]) => formatField(name, meta))
|
|
1110
|
+
].join("\n");
|
|
1073
1111
|
}
|
|
1074
1112
|
#formatInputs(inputs) {
|
|
1075
|
-
return [...this.signature.inputs].map(([name]) =>
|
|
1113
|
+
return [...this.signature.inputs].map(([name, meta]) => {
|
|
1114
|
+
const label = meta.prefix ?? `${name}:`;
|
|
1115
|
+
const prefix = label.endsWith(":") ? label : `${label}:`;
|
|
1116
|
+
return `${prefix} ${String(inputs[name] ?? "")}`;
|
|
1117
|
+
}).join("\n");
|
|
1076
1118
|
}
|
|
1077
1119
|
/**
|
|
1078
1120
|
* Parse a raw completion string into a map of field name → value.
|
|
1079
1121
|
*
|
|
1080
|
-
* Looks for `fieldName: <value>`
|
|
1122
|
+
* Looks for `fieldName: <value>` or `prefix: <value>` patterns in the completion.
|
|
1123
|
+
* Handles common LLM formatting like **bold**, *italic*, etc.
|
|
1124
|
+
* Supports multi-line values by extracting content between field markers.
|
|
1081
1125
|
*/
|
|
1082
1126
|
#parseCompletion(text) {
|
|
1083
1127
|
const result = {};
|
|
1084
|
-
const
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1128
|
+
const outputs = [...this.signature.outputs.entries()];
|
|
1129
|
+
const fieldLabels = [];
|
|
1130
|
+
for (const [key, meta] of outputs) {
|
|
1131
|
+
const prefixBase = (meta.prefix ?? "").replace(/:$/, "").trim();
|
|
1132
|
+
const patterns = [key];
|
|
1133
|
+
if (prefixBase && prefixBase.toLowerCase() !== key.toLowerCase()) {
|
|
1134
|
+
patterns.push(prefixBase);
|
|
1135
|
+
}
|
|
1136
|
+
fieldLabels.push({ key, patterns });
|
|
1137
|
+
}
|
|
1138
|
+
const allPatterns = fieldLabels.flatMap((f) => f.patterns);
|
|
1139
|
+
const allPatternsEscaped = allPatterns.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
1140
|
+
const markerPattern = `(?:\\*\\*|\\*|_)?(${allPatternsEscaped.join("|")})(?:\\*\\*|\\*|_)?:`;
|
|
1141
|
+
const markerRegex = new RegExp(markerPattern, "gi");
|
|
1142
|
+
const markers = [];
|
|
1143
|
+
let markerMatch;
|
|
1144
|
+
while ((markerMatch = markerRegex.exec(text)) !== null) {
|
|
1145
|
+
const matchedLabel = markerMatch[1].toLowerCase();
|
|
1146
|
+
for (const { key, patterns } of fieldLabels) {
|
|
1147
|
+
if (patterns.some((p) => p.toLowerCase() === matchedLabel)) {
|
|
1148
|
+
markers.push({
|
|
1149
|
+
key,
|
|
1150
|
+
start: markerMatch.index,
|
|
1151
|
+
end: markerMatch.index + markerMatch[0].length
|
|
1152
|
+
});
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1090
1155
|
}
|
|
1091
1156
|
}
|
|
1157
|
+
for (let i = 0; i < markers.length; i++) {
|
|
1158
|
+
const marker = markers[i];
|
|
1159
|
+
const contentStart = marker.end;
|
|
1160
|
+
const contentEnd = i + 1 < markers.length ? markers[i + 1].start : text.length;
|
|
1161
|
+
let content = text.slice(contentStart, contentEnd).trim();
|
|
1162
|
+
content = content.replace(/^(\*\*|\*|_)+\s*/, "");
|
|
1163
|
+
content = content.replace(/\s*(\*\*|\*|_)+$/, "");
|
|
1164
|
+
if (!(marker.key in result)) {
|
|
1165
|
+
result[marker.key] = content;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
const outputKeys = outputs.map(([k]) => k);
|
|
1092
1169
|
if (outputKeys.length === 1 && !(outputKeys[0] in result)) {
|
|
1093
1170
|
result[outputKeys[0]] = text.trim();
|
|
1094
1171
|
}
|
|
@@ -1134,9 +1211,6 @@ var ChainOfThoughtWithHint = class extends ChainOfThought {
|
|
|
1134
1211
|
});
|
|
1135
1212
|
Object.assign(this, { signature: extendedSig });
|
|
1136
1213
|
}
|
|
1137
|
-
async forward(inputs) {
|
|
1138
|
-
return super.forward(inputs);
|
|
1139
|
-
}
|
|
1140
1214
|
};
|
|
1141
1215
|
|
|
1142
1216
|
// src/modules/MultiChainComparison.ts
|
|
@@ -1154,14 +1228,23 @@ var MultiChainComparison = class extends Module {
|
|
|
1154
1228
|
}
|
|
1155
1229
|
async forward(inputs) {
|
|
1156
1230
|
const completions = [];
|
|
1231
|
+
const outputKey = [...this.#cot.signature.outputs.keys()].find((k) => k !== "rationale") ?? "answer";
|
|
1157
1232
|
for (let i = 0; i < this.M; i++) {
|
|
1158
1233
|
const result = await this.#cot.forward(inputs);
|
|
1159
|
-
|
|
1160
|
-
completions.push(String(result.get(outputKey ?? "answer") ?? ""));
|
|
1234
|
+
completions.push(String(result.get(outputKey) ?? ""));
|
|
1161
1235
|
}
|
|
1162
|
-
|
|
1236
|
+
const aggregated = await this.#aggregator.forward({
|
|
1163
1237
|
completions: completions.map((c, i) => `Option ${i + 1}: ${c}`).join("\n")
|
|
1164
1238
|
});
|
|
1239
|
+
const rawAnswer = String(aggregated.get("answer") ?? "");
|
|
1240
|
+
const optionMatch = /^Option\s*(\d+)/i.exec(rawAnswer);
|
|
1241
|
+
if (optionMatch) {
|
|
1242
|
+
const optionIdx = parseInt(optionMatch[1], 10) - 1;
|
|
1243
|
+
if (optionIdx >= 0 && optionIdx < completions.length) {
|
|
1244
|
+
return new Prediction({ answer: completions[optionIdx] ?? rawAnswer });
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return new Prediction({ answer: rawAnswer });
|
|
1165
1248
|
}
|
|
1166
1249
|
};
|
|
1167
1250
|
|
|
@@ -1175,7 +1258,6 @@ var ReAct = class extends Module {
|
|
|
1175
1258
|
this.tools = new Map(tools.map((t) => [t.name, t]));
|
|
1176
1259
|
this.maxIter = maxIter;
|
|
1177
1260
|
const toolDescriptions = tools.map((t) => `${t.name}: ${t.description}`).join("\n");
|
|
1178
|
-
const base = typeof signature === "string" ? signature : signature;
|
|
1179
1261
|
const instructions = `You are an agent. Use the following tools:
|
|
1180
1262
|
${toolDescriptions}
|
|
1181
1263
|
|
|
@@ -1185,9 +1267,12 @@ Action: <tool>[<args>]
|
|
|
1185
1267
|
Observation: <result>
|
|
1186
1268
|
...
|
|
1187
1269
|
Finish[<answer>]`;
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1270
|
+
let baseSig = typeof signature === "string" ? Signature.from(signature) : signature;
|
|
1271
|
+
baseSig = baseSig.withInput("trajectory", {
|
|
1272
|
+
description: "Interleaved reasoning steps so far",
|
|
1273
|
+
optional: true
|
|
1274
|
+
});
|
|
1275
|
+
this.#predictor = new Predict(baseSig);
|
|
1191
1276
|
this.#predictor.instructions = instructions;
|
|
1192
1277
|
}
|
|
1193
1278
|
async forward(inputs) {
|
|
@@ -1270,10 +1355,11 @@ var ProgramOfThought = class extends Module {
|
|
|
1270
1355
|
for (let attempt = 0; attempt < this.maxAttempts; attempt++) {
|
|
1271
1356
|
const genInputs = attempt === 0 ? {
|
|
1272
1357
|
...inputs,
|
|
1273
|
-
instructions: "Write JavaScript code to compute the answer. Use a `return` statement for the final value."
|
|
1358
|
+
instructions: "Write JavaScript code to compute the answer. IMPORTANT: Use a `return` statement (not console.log) for the final value. Do not include markdown code fences."
|
|
1274
1359
|
} : { code, error: lastError };
|
|
1275
1360
|
const generated = attempt === 0 ? await this.#codeGenerator.forward(genInputs) : await this.#corrector.forward(genInputs);
|
|
1276
1361
|
code = String(generated.get("code") ?? generated.get("fixed_code") ?? "");
|
|
1362
|
+
code = code.replace(/^```(?:\w+)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
|
|
1277
1363
|
try {
|
|
1278
1364
|
if (this.sandbox === "worker") {
|
|
1279
1365
|
result = await this.#executeInWorker(code, this.timeoutMs);
|
|
@@ -1412,7 +1498,9 @@ var Retry = class extends Module {
|
|
|
1412
1498
|
let lastError;
|
|
1413
1499
|
for (let attempt = 0; attempt < this.maxAttempts; attempt++) {
|
|
1414
1500
|
try {
|
|
1415
|
-
return
|
|
1501
|
+
return firstPrediction(
|
|
1502
|
+
await this.#inner.forward(...args)
|
|
1503
|
+
);
|
|
1416
1504
|
} catch (err) {
|
|
1417
1505
|
if (err instanceof AssertionError) {
|
|
1418
1506
|
lastError = err;
|
|
@@ -1447,7 +1535,7 @@ var BestOfN = class extends Module {
|
|
|
1447
1535
|
() => this.#inner.forward(...args)
|
|
1448
1536
|
)
|
|
1449
1537
|
);
|
|
1450
|
-
return this.#reduce(results);
|
|
1538
|
+
return this.#reduce(results.map(firstPrediction));
|
|
1451
1539
|
}
|
|
1452
1540
|
};
|
|
1453
1541
|
|
|
@@ -1466,7 +1554,7 @@ var Ensemble = class extends Module {
|
|
|
1466
1554
|
(m) => m.forward(...args)
|
|
1467
1555
|
)
|
|
1468
1556
|
);
|
|
1469
|
-
return this.#reduce(results);
|
|
1557
|
+
return this.#reduce(results.map(firstPrediction));
|
|
1470
1558
|
}
|
|
1471
1559
|
};
|
|
1472
1560
|
|
|
@@ -1575,6 +1663,7 @@ var TypedChainOfThought = class extends TypedPredictor {
|
|
|
1575
1663
|
};
|
|
1576
1664
|
|
|
1577
1665
|
// src/modules/Parallel.ts
|
|
1666
|
+
import { setTimeout as setTimeout2 } from "timers";
|
|
1578
1667
|
var Parallel = class extends Module {
|
|
1579
1668
|
#modules;
|
|
1580
1669
|
#timeoutMs;
|
|
@@ -1583,29 +1672,37 @@ var Parallel = class extends Module {
|
|
|
1583
1672
|
this.#modules = modules;
|
|
1584
1673
|
this.#timeoutMs = options.timeoutMs;
|
|
1585
1674
|
}
|
|
1586
|
-
/**
|
|
1675
|
+
/**
|
|
1676
|
+
* Run all modules in parallel and return one {@link Prediction} per module.
|
|
1677
|
+
* If a module's `forward()` returns multiple predictions, the first is used.
|
|
1678
|
+
*/
|
|
1587
1679
|
async run(...args) {
|
|
1588
1680
|
const tasks = this.#modules.map(
|
|
1589
1681
|
(m) => m.forward(...args)
|
|
1590
1682
|
);
|
|
1683
|
+
let settled;
|
|
1591
1684
|
if (this.#timeoutMs !== void 0) {
|
|
1592
1685
|
const timeoutMs = this.#timeoutMs;
|
|
1593
1686
|
const withTimeout = tasks.map(
|
|
1594
1687
|
(t) => Promise.race([
|
|
1595
1688
|
t,
|
|
1596
1689
|
new Promise(
|
|
1597
|
-
(_, reject) =>
|
|
1690
|
+
(_, reject) => setTimeout2(() => reject(new Error("Parallel: timeout")), timeoutMs)
|
|
1598
1691
|
)
|
|
1599
1692
|
])
|
|
1600
1693
|
);
|
|
1601
|
-
|
|
1694
|
+
settled = Promise.all(withTimeout);
|
|
1695
|
+
} else {
|
|
1696
|
+
settled = Promise.all(tasks);
|
|
1602
1697
|
}
|
|
1603
|
-
return
|
|
1698
|
+
return (await settled).map(firstPrediction);
|
|
1604
1699
|
}
|
|
1605
|
-
/**
|
|
1700
|
+
/**
|
|
1701
|
+
* Execute all modules in parallel and return all predictions as an array
|
|
1702
|
+
* (one entry per module).
|
|
1703
|
+
*/
|
|
1606
1704
|
async forward(...args) {
|
|
1607
|
-
|
|
1608
|
-
return results[0];
|
|
1705
|
+
return this.run(...args);
|
|
1609
1706
|
}
|
|
1610
1707
|
};
|
|
1611
1708
|
|
|
@@ -1626,7 +1723,7 @@ var Refine = class extends Module {
|
|
|
1626
1723
|
}
|
|
1627
1724
|
async forward(...args) {
|
|
1628
1725
|
const innerForward = this.#inner.forward.bind(this.#inner);
|
|
1629
|
-
let prediction = await innerForward(...args);
|
|
1726
|
+
let prediction = firstPrediction(await innerForward(...args));
|
|
1630
1727
|
for (let i = 0; i < this.#maxRefinements; i++) {
|
|
1631
1728
|
if (this.#stopCondition?.(prediction)) break;
|
|
1632
1729
|
const outputStr = JSON.stringify(prediction.toDict());
|
|
@@ -1649,7 +1746,7 @@ var Refine = class extends Module {
|
|
|
1649
1746
|
};
|
|
1650
1747
|
}
|
|
1651
1748
|
try {
|
|
1652
|
-
prediction = await innerForward(...newArgs);
|
|
1749
|
+
prediction = firstPrediction(await innerForward(...newArgs));
|
|
1653
1750
|
} catch {
|
|
1654
1751
|
break;
|
|
1655
1752
|
}
|
|
@@ -2773,6 +2870,7 @@ export {
|
|
|
2773
2870
|
evaluate,
|
|
2774
2871
|
exactMatch,
|
|
2775
2872
|
f1,
|
|
2873
|
+
firstPrediction,
|
|
2776
2874
|
majority,
|
|
2777
2875
|
passAtK,
|
|
2778
2876
|
rouge,
|