@hicaru/pi-rlm 0.3.15 → 0.3.17
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 +96 -70
- package/README.ru.md +86 -59
- package/README.zh-CN.md +95 -65
- package/package.json +5 -5
- package/src/bridge/add-context.ts +1 -1
- package/src/bridge/handlers/await.ts +13 -22
- package/src/bridge/handlers/completion.ts +27 -5
- package/src/bridge/handlers/emitting.ts +2 -2
- package/src/bridge/handlers/llm-query.ts +46 -68
- package/src/bridge/handlers/rlm-query.ts +14 -84
- package/src/bridge/handlers/task-registry.ts +22 -17
- package/src/bridge/handlers/types.ts +8 -6
- package/src/bridge/model.ts +21 -4
- package/src/commands/rlm-llm.ts +1 -10
- package/src/commands/rlm-rlm.ts +1 -8
- package/src/config/defaults.ts +31 -12
- package/src/config/settings.ts +47 -33
- package/src/config/skillstate.ts +465 -0
- package/src/context/md-cache.ts +1 -1
- package/src/context/merge.ts +1 -1
- package/src/context/namespace.ts +2 -2
- package/src/context/refresh.ts +1 -1
- package/src/context/source-dir.ts +21 -11
- package/src/context/source-doc.ts +1 -1
- package/src/context/source-git.ts +3 -15
- package/src/context/source-text.ts +1 -1
- package/src/context/walk.ts +6 -14
- package/src/core/budget.ts +107 -21
- package/src/core/compaction.ts +44 -1
- package/src/core/engine.ts +192 -94
- package/src/core/iteration.ts +1 -1
- package/src/core/ledger.ts +10 -13
- package/src/core/limits.ts +1 -1
- package/src/core/model-registry.ts +1 -1
- package/src/core/resource-limits.ts +1 -1
- package/src/core/root-context.ts +126 -0
- package/src/core/root-digest.ts +213 -0
- package/src/core/root-state.ts +240 -0
- package/src/core/run-state.ts +577 -0
- package/src/core/types.ts +56 -12
- package/src/index.ts +167 -36
- package/src/mode/llm-model.ts +13 -1
- package/src/mode/native-guards.ts +0 -6
- package/src/mode/rlm-mode.ts +34 -11
- package/src/mode/subagent.ts +5 -5
- package/src/prompts/glossary.ts +41 -25
- package/src/prompts/native.ts +1 -3
- package/src/prompts/system.ts +12 -4
- package/src/prompts/user.ts +17 -0
- package/src/sandbox/context-file.ts +1 -1
- package/src/sandbox/interrupts.ts +25 -31
- package/src/sandbox/protocol.ts +14 -20
- package/src/sandbox/py/__pycache__/guards.cpython-314.pyc +0 -0
- package/src/sandbox/py/__pycache__/retrieval.cpython-314.pyc +0 -0
- package/src/sandbox/py/__pycache__/scaffold.cpython-314.pyc +0 -0
- package/src/sandbox/py/__pycache__/worker.cpython-314.pyc +0 -0
- package/src/sandbox/py/guards.py +1 -1
- package/src/sandbox/py/retrieval.py +4 -1
- package/src/sandbox/py/scaffold.py +24 -31
- package/src/sandbox/py/worker.py +3 -1
- package/src/sandbox/sandbox-manager.ts +2 -2
- package/src/sandbox/sandbox.ts +35 -5
- package/src/text/agent-text.ts +58 -0
- package/src/text/parsing.ts +35 -3
- package/src/text/preview.ts +3 -0
- package/src/text/repl-output.ts +1 -1
- package/src/tool/background-tasks.ts +1 -1
- package/src/tool/repl-render.ts +1 -1
- package/src/tool/repl-result.ts +1 -1
- package/src/tool/repl-tool.ts +50 -26
- package/src/tool/rlm-tool.ts +4 -5
- package/src/tool/subcall-render.ts +1 -1
- package/src/tool/subcall-store.ts +2 -2
- package/src/tool/tool-utils.ts +5 -5
- package/src/ui/config-panel.ts +39 -0
- package/src/ui/intro.ts +1 -1
- package/src/ui/modal/timeline-store.ts +1 -1
- package/src/ui/model-picker/drilldown.ts +1 -1
- package/src/ui/model-picker/levels.ts +1 -1
- package/src/ui/panel/run-registry.ts +1 -1
- package/src/ui/tree/tree-rows.ts +1 -1
- package/src/ui/tree/tree-widget.ts +1 -1
- package/src/util/bm25.ts +97 -0
- package/src/util/concurrency.ts +1 -1
- package/src/util/errors.ts +1 -1
- package/src/util/retry.ts +22 -7
- package/src/util/state-merge.ts +34 -0
- package/src/util/throttle.ts +1 -1
- package/src/util/type-guards.ts +6 -0
- package/src/core/memory.ts +0 -589
package/src/bridge/model.ts
CHANGED
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* RLM root (full history).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { clampThinkingLevel } from "@earendil-works/pi-ai";
|
|
12
13
|
import { type Api, completeSimple, type Message, type Model, type ThinkingLevel, type Usage } from "@earendil-works/pi-ai/compat";
|
|
13
14
|
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
14
15
|
import { completeWithRetry, DEFAULT_RETRY_POLICY, type RetryPolicy } from "../util/retry.ts";
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
type Role = "system" | "user" | "assistant";
|
|
17
18
|
export interface ChatMsg {
|
|
18
19
|
readonly role: Role;
|
|
19
20
|
readonly content: string;
|
|
@@ -54,20 +55,36 @@ function assistantMessage(text: string, model: Model<Api>): Message {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
function toPiMessages(messages: readonly ChatMsg[], model: Model<Api>): { readonly systemPrompt?: string; readonly messages: Message[] } {
|
|
57
|
-
|
|
58
|
+
// System segments joined once below — no quadratic re-copy of the accumulated prompt (rule:
|
|
59
|
+
// never build large text with `+`/template concat inside a loop).
|
|
60
|
+
const systemParts: string[] = [];
|
|
58
61
|
const out: Message[] = [];
|
|
59
62
|
for (const m of messages) {
|
|
60
63
|
if (m.role === "system") {
|
|
61
|
-
|
|
64
|
+
systemParts.push(m.content);
|
|
62
65
|
} else if (m.role === "user") {
|
|
63
66
|
out.push({ role: "user", content: m.content, timestamp: Date.now() });
|
|
64
67
|
} else {
|
|
65
68
|
out.push(assistantMessage(m.content, model));
|
|
66
69
|
}
|
|
67
70
|
}
|
|
71
|
+
const systemPrompt = systemParts.length > 0 ? systemParts.join("\n\n") : undefined;
|
|
68
72
|
return { systemPrompt, messages: out };
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Explicit reasoning gate. pi-ai clamps unsupported levels too (a model with `reasoning:
|
|
77
|
+
* false` supports only "off", so any requested level clamps to it and nothing goes out on
|
|
78
|
+
* the wire) — owning the gate here makes the behavior engine policy, testable without a
|
|
79
|
+
* provider, and drops the option outright instead of forwarding a level the model cannot
|
|
80
|
+
* honor. Capability comes from the registry entry, never from config.
|
|
81
|
+
*/
|
|
82
|
+
export function effectiveReasoning(model: Model<Api>, level: ThinkingLevel | undefined): ThinkingLevel | undefined {
|
|
83
|
+
if (level === undefined) return undefined;
|
|
84
|
+
const clamped = clampThinkingLevel(model, level);
|
|
85
|
+
return clamped === "off" ? undefined : clamped;
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
/** Extract the assistant's plain text from a completion. */
|
|
72
89
|
function extractText(content: readonly { readonly type: string; readonly text?: string }[]): string {
|
|
73
90
|
return content
|
|
@@ -97,7 +114,7 @@ export async function modelComplete(messages: readonly ChatMsg[], opts: Complete
|
|
|
97
114
|
headers: auth.headers,
|
|
98
115
|
maxTokens: opts.maxTokens,
|
|
99
116
|
temperature: opts.temperature,
|
|
100
|
-
reasoning: opts.reasoning,
|
|
117
|
+
reasoning: effectiveReasoning(opts.model, opts.reasoning),
|
|
101
118
|
signal: opts.signal,
|
|
102
119
|
onResponse: (res) => { note(res.status, res.headers); },
|
|
103
120
|
},
|
package/src/commands/rlm-llm.ts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
/** `/rlm-llm` — pin the leaf-LLM model (llm_query / llm_batch / map_files). */
|
|
2
2
|
|
|
3
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
4
3
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
5
4
|
import { modelRef } from "../config/settings.ts";
|
|
6
|
-
import { cheapestModel } from "../mode/llm-model.ts";
|
|
5
|
+
import { cheapestModel, sessionScopedModels } from "../mode/llm-model.ts";
|
|
7
6
|
import type { RlmController } from "../mode/rlm-mode.ts";
|
|
8
7
|
import { pickableModels, selectModel } from "../ui/model-picker.ts";
|
|
9
8
|
import { setRlmModeStatus } from "../ui/status.ts";
|
|
10
9
|
import { applyLlmSelection } from "./pins.ts";
|
|
11
10
|
|
|
12
|
-
/** Newer Pi hosts expose session-scoped models; 0.79 peers do not — duck-type safely. */
|
|
13
|
-
function sessionScopedModels(
|
|
14
|
-
ctx: ExtensionContext,
|
|
15
|
-
): readonly { readonly model: Model<Api> }[] | undefined {
|
|
16
|
-
const scoped: unknown = Reflect.get(ctx, "scopedModels");
|
|
17
|
-
return Array.isArray(scoped) ? scoped as readonly { readonly model: Model<Api> }[] : undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
11
|
async function runRlmLlm(controller: RlmController, ctx: ExtensionContext): Promise<void> {
|
|
21
12
|
try {
|
|
22
13
|
await ctx.modelRegistry.refresh();
|
package/src/commands/rlm-rlm.ts
CHANGED
|
@@ -4,21 +4,14 @@
|
|
|
4
4
|
* the pre-pin behavior, now an explicit picker row.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
8
7
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
8
|
import { modelRef } from "../config/settings.ts";
|
|
9
|
+
import { sessionScopedModels } from "../mode/llm-model.ts";
|
|
10
10
|
import type { RlmController } from "../mode/rlm-mode.ts";
|
|
11
11
|
import { pickableModels, selectModel } from "../ui/model-picker.ts";
|
|
12
12
|
import { setRlmModeStatus } from "../ui/status.ts";
|
|
13
13
|
import { applyRlmSelection } from "./pins.ts";
|
|
14
14
|
|
|
15
|
-
function sessionScopedModels(
|
|
16
|
-
ctx: ExtensionContext,
|
|
17
|
-
): readonly { readonly model: Model<Api> }[] | undefined {
|
|
18
|
-
const scoped: unknown = Reflect.get(ctx, "scopedModels");
|
|
19
|
-
return Array.isArray(scoped) ? scoped as readonly { readonly model: Model<Api> }[] : undefined;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
15
|
async function runRlmRlm(controller: RlmController, ctx: ExtensionContext): Promise<void> {
|
|
23
16
|
try {
|
|
24
17
|
await ctx.modelRegistry.refresh();
|
package/src/config/defaults.ts
CHANGED
|
@@ -20,11 +20,12 @@ export const DEFAULT_CONFIG: Readonly<RlmConfig> = Object.freeze({
|
|
|
20
20
|
// of the context it inherited, where a leaf is one HTTP request. Worst case is
|
|
21
21
|
// (maxDepth - 1) × this many concurrent child engines. Default 4.
|
|
22
22
|
maxConcurrentChildren: 4,
|
|
23
|
-
// v5.1 rate-limit resilience (util/retry.ts):
|
|
24
|
-
// 2s→60s adaptive per-provider cooldown.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
// v5.1 rate-limit resilience (util/retry.ts): 15 total attempts on the SAME model —
|
|
24
|
+
// 500ms→15s backoff, 2s→60s adaptive per-provider cooldown. DOCTRINE: NO fallback —
|
|
25
|
+
// when the attempts are exhausted the call fails loudly; model/provider never switch.
|
|
26
|
+
retryMaxAttempts: 15,
|
|
27
|
+
// 429s park on the cooldown instead of dying — up to 15 windows (2s→4s→…≤60s).
|
|
28
|
+
rateLimitMaxAttempts: 15,
|
|
28
29
|
retryBaseDelayMs: 500,
|
|
29
30
|
retryMaxDelayMs: 15_000,
|
|
30
31
|
throttleBaseMs: 2_000,
|
|
@@ -51,11 +52,29 @@ export const DEFAULT_CONFIG: Readonly<RlmConfig> = Object.freeze({
|
|
|
51
52
|
// v5 TaskLedger blackboard
|
|
52
53
|
enableLedger: true,
|
|
53
54
|
rlmBudget: 8,
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
// Verification-discipline nudge — deliberately OFF (plan guardrail): when on, an early
|
|
56
|
+
// bare-number finalize gets one coached redo instead of being accepted. Opt-in via rlm.json.
|
|
57
|
+
enableVerificationNudge: false,
|
|
58
|
+
// SKILL.state integration: Σ_t execution state + cross-session distilled knowledge.
|
|
59
|
+
enableRunState: true,
|
|
60
|
+
runStateRetryMax: 2,
|
|
61
|
+
enableSkillState: true,
|
|
62
|
+
// Default ON (bench rec #3): deterministic harvest — one cheap distill leaf per finalize
|
|
63
|
+
// replaces the stochastic fence-emission harvest (0 vs 4 notes across identical ON arms).
|
|
64
|
+
enableSkillStateDistill: true,
|
|
65
|
+
skillStateMaxTokens: 1_200,
|
|
66
|
+
skillStateLeafTokens: 200,
|
|
67
|
+
skillStateMinScore: 4.0,
|
|
68
|
+
skillStateNotesPerProject: 128,
|
|
69
|
+
// Root Σ integration (WS-2..WS-4): digest compaction ON (it only swaps the summarizer for
|
|
70
|
+
// a deterministic digest — zero tokens, strictly less latency); the context transform and
|
|
71
|
+
// model-proposed fences soak with flags OFF until the A/B says otherwise.
|
|
72
|
+
enableRootDigestCompaction: true,
|
|
73
|
+
rootDigestKeepRecentChars: 12_000,
|
|
74
|
+
rootDigestMaxChars: 8_000,
|
|
75
|
+
enableRootContextTransform: false,
|
|
76
|
+
rootContextKeepTurns: 2,
|
|
77
|
+
rootContextElideChars: 1_500,
|
|
78
|
+
rootContextSnapshot: true,
|
|
79
|
+
enableRootStateFences: false,
|
|
61
80
|
});
|
package/src/config/settings.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { Api, Model, ThinkingLevel } from "@earendil-works/pi-ai";
|
|
|
7
7
|
import type { RlmConfig } from "../core/types.ts";
|
|
8
8
|
import { DEFAULT_CONFIG } from "./defaults.ts";
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
interface PersistedSettings {
|
|
11
11
|
readonly config: Partial<RlmConfig>;
|
|
12
12
|
/** "provider/id" of the pinned sub-LLM, or undefined for "cheapest (auto)".
|
|
13
13
|
* `null` = explicit "cheapest" clear (omit key on disk). */
|
|
@@ -38,9 +38,10 @@ function validateString(v: unknown): string | undefined {
|
|
|
38
38
|
/**
|
|
39
39
|
* Every value pi-ai accepts for `reasoning`. Keyed by the union so a new level added upstream
|
|
40
40
|
* is a compile error here rather than a silently-rejected setting. Note `off` is NOT a
|
|
41
|
-
* ThinkingLevel — a hand-edited rlm.json carrying one is dropped, not forwarded.
|
|
41
|
+
* ThinkingLevel — a hand-edited rlm.json carrying one is dropped, not forwarded. Exported so
|
|
42
|
+
* the config panel derives its choices from the same source of truth.
|
|
42
43
|
*/
|
|
43
|
-
const THINKING_LEVELS: Readonly<Record<ThinkingLevel, true>> = Object.freeze({
|
|
44
|
+
export const THINKING_LEVELS: Readonly<Record<ThinkingLevel, true>> = Object.freeze({
|
|
44
45
|
minimal: true, low: true, medium: true, high: true, xhigh: true, max: true,
|
|
45
46
|
});
|
|
46
47
|
|
|
@@ -103,8 +104,7 @@ export function validateConfig(raw: unknown): Partial<RlmConfig> {
|
|
|
103
104
|
if (subSystemPrompt !== undefined) out.subSystemPrompt = subSystemPrompt;
|
|
104
105
|
const sandboxInitTimeoutMs = validateNumber(r.sandboxInitTimeoutMs, 100);
|
|
105
106
|
if (sandboxInitTimeoutMs !== undefined) out.sandboxInitTimeoutMs = sandboxInitTimeoutMs;
|
|
106
|
-
|
|
107
|
-
const contextLoader = validateBoolean(r.contextLoader) ?? validateBoolean(r.libraryLoader);
|
|
107
|
+
const contextLoader = validateBoolean(r.contextLoader);
|
|
108
108
|
if (contextLoader !== undefined) out.contextLoader = contextLoader;
|
|
109
109
|
const autoSeedCwd = validateBoolean(r.autoSeedCwd);
|
|
110
110
|
if (autoSeedCwd !== undefined) out.autoSeedCwd = autoSeedCwd;
|
|
@@ -126,18 +126,6 @@ export function validateConfig(raw: unknown): Partial<RlmConfig> {
|
|
|
126
126
|
if (enableLedger !== undefined) out.enableLedger = enableLedger;
|
|
127
127
|
const rlmBudget = validateNumber(r.rlmBudget, 0);
|
|
128
128
|
if (rlmBudget !== undefined) out.rlmBudget = rlmBudget;
|
|
129
|
-
// v5 durable memory
|
|
130
|
-
const enableMemory = validateBoolean(r.enableMemory);
|
|
131
|
-
if (enableMemory !== undefined) out.enableMemory = enableMemory;
|
|
132
|
-
const injectNoteTokens = validateNumber(r.injectNoteTokens, 100);
|
|
133
|
-
if (injectNoteTokens !== undefined) out.injectNoteTokens = injectNoteTokens;
|
|
134
|
-
const evolveEvery = validateNumber(r.evolveEvery, 0);
|
|
135
|
-
if (evolveEvery !== undefined) out.evolveEvery = evolveEvery;
|
|
136
|
-
if (r.memoryDir === null) out.memoryDir = null;
|
|
137
|
-
else {
|
|
138
|
-
const memoryDir = validateString(r.memoryDir);
|
|
139
|
-
if (memoryDir !== undefined) out.memoryDir = memoryDir;
|
|
140
|
-
}
|
|
141
129
|
// v5 provider concurrency caps: { provider: minConcurrent }
|
|
142
130
|
if (typeof r.providerMaxConcurrent === "object" && r.providerMaxConcurrent !== null) {
|
|
143
131
|
const caps: Record<string, number> = {};
|
|
@@ -147,8 +135,43 @@ export function validateConfig(raw: unknown): Partial<RlmConfig> {
|
|
|
147
135
|
}
|
|
148
136
|
if (Object.keys(caps).length > 0) out.providerMaxConcurrent = Object.freeze(caps);
|
|
149
137
|
}
|
|
150
|
-
//
|
|
151
|
-
|
|
138
|
+
// Verification-discipline nudge (default OFF).
|
|
139
|
+
const enableVerificationNudge = validateBoolean(r.enableVerificationNudge);
|
|
140
|
+
if (enableVerificationNudge !== undefined) out.enableVerificationNudge = enableVerificationNudge;
|
|
141
|
+
// SKILL.state integration (Workstreams A–F)
|
|
142
|
+
const enableRunState = validateBoolean(r.enableRunState);
|
|
143
|
+
if (enableRunState !== undefined) out.enableRunState = enableRunState;
|
|
144
|
+
const runStateRetryMax = validateNumber(r.runStateRetryMax, 0);
|
|
145
|
+
if (runStateRetryMax !== undefined) out.runStateRetryMax = runStateRetryMax;
|
|
146
|
+
const enableSkillState = validateBoolean(r.enableSkillState);
|
|
147
|
+
if (enableSkillState !== undefined) out.enableSkillState = enableSkillState;
|
|
148
|
+
const enableSkillStateDistill = validateBoolean(r.enableSkillStateDistill);
|
|
149
|
+
if (enableSkillStateDistill !== undefined) out.enableSkillStateDistill = enableSkillStateDistill;
|
|
150
|
+
const skillStateMaxTokens = validateNumber(r.skillStateMaxTokens, 50);
|
|
151
|
+
if (skillStateMaxTokens !== undefined) out.skillStateMaxTokens = skillStateMaxTokens;
|
|
152
|
+
const skillStateLeafTokens = validateNumber(r.skillStateLeafTokens, 0);
|
|
153
|
+
if (skillStateLeafTokens !== undefined) out.skillStateLeafTokens = skillStateLeafTokens;
|
|
154
|
+
const skillStateMinScore = validateNumber(r.skillStateMinScore, 0);
|
|
155
|
+
if (skillStateMinScore !== undefined) out.skillStateMinScore = skillStateMinScore;
|
|
156
|
+
const skillStateNotesPerProject = validateNumber(r.skillStateNotesPerProject, 1);
|
|
157
|
+
if (skillStateNotesPerProject !== undefined) out.skillStateNotesPerProject = skillStateNotesPerProject;
|
|
158
|
+
// Root Σ integration (WS-2..WS-4)
|
|
159
|
+
const enableRootDigestCompaction = validateBoolean(r.enableRootDigestCompaction);
|
|
160
|
+
if (enableRootDigestCompaction !== undefined) out.enableRootDigestCompaction = enableRootDigestCompaction;
|
|
161
|
+
const rootDigestKeepRecentChars = validateNumber(r.rootDigestKeepRecentChars, 200);
|
|
162
|
+
if (rootDigestKeepRecentChars !== undefined) out.rootDigestKeepRecentChars = rootDigestKeepRecentChars;
|
|
163
|
+
const rootDigestMaxChars = validateNumber(r.rootDigestMaxChars, 200);
|
|
164
|
+
if (rootDigestMaxChars !== undefined) out.rootDigestMaxChars = rootDigestMaxChars;
|
|
165
|
+
const enableRootContextTransform = validateBoolean(r.enableRootContextTransform);
|
|
166
|
+
if (enableRootContextTransform !== undefined) out.enableRootContextTransform = enableRootContextTransform;
|
|
167
|
+
const rootContextKeepTurns = validateNumber(r.rootContextKeepTurns, 0);
|
|
168
|
+
if (rootContextKeepTurns !== undefined) out.rootContextKeepTurns = rootContextKeepTurns;
|
|
169
|
+
const rootContextElideChars = validateNumber(r.rootContextElideChars, 100);
|
|
170
|
+
if (rootContextElideChars !== undefined) out.rootContextElideChars = rootContextElideChars;
|
|
171
|
+
const rootContextSnapshot = validateBoolean(r.rootContextSnapshot);
|
|
172
|
+
if (rootContextSnapshot !== undefined) out.rootContextSnapshot = rootContextSnapshot;
|
|
173
|
+
const enableRootStateFences = validateBoolean(r.enableRootStateFences);
|
|
174
|
+
if (enableRootStateFences !== undefined) out.enableRootStateFences = enableRootStateFences;
|
|
152
175
|
if (typeof r.subSampling === "object" && r.subSampling !== null) {
|
|
153
176
|
const ss = r.subSampling as Record<string, unknown>;
|
|
154
177
|
const sampling: { maxTokens?: number; temperature?: number; reasoning?: ThinkingLevel } = {};
|
|
@@ -181,8 +204,7 @@ export async function loadSettings(): Promise<PersistedSettings> {
|
|
|
181
204
|
const r = raw as Record<string, unknown>;
|
|
182
205
|
return {
|
|
183
206
|
config: validateConfig(r.config),
|
|
184
|
-
|
|
185
|
-
llm: validateString(r.llm) ?? validateString(r.worker),
|
|
207
|
+
llm: validateString(r.llm),
|
|
186
208
|
rlm: validateString(r.rlm),
|
|
187
209
|
};
|
|
188
210
|
} catch {
|
|
@@ -238,16 +260,8 @@ export function modelRef(model: Model<Api> | undefined): string | undefined {
|
|
|
238
260
|
return model ? `${model.provider}/${model.id}` : undefined;
|
|
239
261
|
}
|
|
240
262
|
|
|
241
|
-
/**
|
|
242
|
-
*
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
*/
|
|
246
|
-
export function displayModelRef(
|
|
247
|
-
registry: ModelRegistry,
|
|
248
|
-
override: string | null,
|
|
249
|
-
fallback: Model<Api>,
|
|
250
|
-
): string {
|
|
251
|
-
const resolved = override ? (resolveModelId(registry, override) ?? fallback) : fallback;
|
|
252
|
-
return modelRef(resolved) ?? fallback.id;
|
|
263
|
+
/** Single "provider/id" projection for sub-call node labels — shared by the llm and rlm
|
|
264
|
+
* bridges so sub-call trees label their nodes identically. */
|
|
265
|
+
export function modelLabelOf(model: Model<Api>): string {
|
|
266
|
+
return modelRef(model) ?? model.id;
|
|
253
267
|
}
|