pi-advisor-flow 0.8.1-dev.1 → 0.8.1-dev.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/CHANGELOG.md +3 -5
- package/README.md +8 -0
- package/dist/index.js +41 -606
- package/package.json +1 -1
- package/src/commands/activation.ts +3 -10
- package/src/commands/lifecycle.ts +1 -6
- package/src/scout.ts +7 -16
- package/src/child-session.ts +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -4,13 +4,11 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
|
|
5
5
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Unreleased
|
|
8
8
|
|
|
9
|
-
###
|
|
9
|
+
### Added
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
- Keep marked child model selections out of the persisted parent Executor configuration.
|
|
13
|
-
- Run Advisor Scout with the marked child's active model and thinking level instead of replacing them with the configured parent Executor.
|
|
11
|
+
- Published validated npm development previews for package changes on `main` under the `dev` dist-tag; stable installs continue to use `latest`.
|
|
14
12
|
|
|
15
13
|
## 0.8.0 - 2026-09-22
|
|
16
14
|
|
package/README.md
CHANGED
|
@@ -46,6 +46,14 @@ Requires Pi 0.84.1 or later. Pi 0.85.0 is not supported (broken upstream release
|
|
|
46
46
|
pi install npm:pi-advisor-flow
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
For npm consumers who want to test the latest development preview:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install pi-advisor-flow@dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Preview builds use the next patch prerelease version (for example, `0.8.1-dev.1` after stable `0.8.0`) and are published only when a file included in the npm package changes. Each preview advances the `dev.N` sequence. Regular installs continue to use the stable `latest` version.
|
|
56
|
+
|
|
49
57
|
You can also install from GitHub:
|
|
50
58
|
|
|
51
59
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -272,16 +272,6 @@ var splitRef = (ref) => {
|
|
|
272
272
|
return i === -1 ? ["openai-codex", ref] : [ref.slice(0, i), ref.slice(i + 1)];
|
|
273
273
|
};
|
|
274
274
|
|
|
275
|
-
// src/child-session.ts
|
|
276
|
-
var isMarkedSubagent = () => process.env.PI_SUBAGENT_CHILD === "1";
|
|
277
|
-
var effectiveExecutorRef = (ctx) => {
|
|
278
|
-
if (isMarkedSubagent() && ctx.model) {
|
|
279
|
-
return `${ctx.model.provider}/${ctx.model.id}`;
|
|
280
|
-
}
|
|
281
|
-
return executorRef;
|
|
282
|
-
};
|
|
283
|
-
var effectiveExecutorEffort = (ctx) => isMarkedSubagent() ? ctx.thinkingLevel : executorEffortRef;
|
|
284
|
-
|
|
285
275
|
// src/content-utils.ts
|
|
286
276
|
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
287
277
|
var isRecordOf = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -2077,8 +2067,8 @@ var toolResultEntry = (message, toolResultMaxLines, toolResultMaxBytes, policies
|
|
|
2077
2067
|
return `[Tool Result for ${toolName}] (excluded by Advisor tool policy)`;
|
|
2078
2068
|
}
|
|
2079
2069
|
if (policy === "summary") {
|
|
2080
|
-
const
|
|
2081
|
-
return `[Tool Result for ${toolName}] (output omitted by Advisor tool policy: summary; status: ${status}; ${
|
|
2070
|
+
const capped = capToolResult(source, toolResultMaxLines, toolResultMaxBytes);
|
|
2071
|
+
return `[Tool Result for ${toolName}] (output omitted by Advisor tool policy: summary; status: ${status}; ${capped.totalLines} lines, ${capped.totalBytes} bytes; source output was${capped.truncated ? "" : " not"} truncated)`;
|
|
2082
2072
|
}
|
|
2083
2073
|
const disclosed = redact ? redactSecrets(source) : source;
|
|
2084
2074
|
const capped = capToolResult(disclosed, toolResultMaxLines, toolResultMaxBytes);
|
|
@@ -2118,17 +2108,17 @@ var selectRecentEntries = (entries, maxChars) => {
|
|
|
2118
2108
|
}
|
|
2119
2109
|
const newestTruncated = "[Newest entry truncated]";
|
|
2120
2110
|
if (entries.length === 1) {
|
|
2121
|
-
const
|
|
2122
|
-
return `${
|
|
2111
|
+
const prefix = `${newestTruncated}${separator}`;
|
|
2112
|
+
return `${prefix}${entries[0].slice(0, Math.max(0, maxChars - prefix.length))}`.slice(0, maxChars);
|
|
2123
2113
|
}
|
|
2124
2114
|
const selected = [];
|
|
2125
2115
|
let selectedLength = 0;
|
|
2126
2116
|
for (let index = entries.length - 1;index >= 0; index -= 1) {
|
|
2127
2117
|
const entry = entries[index];
|
|
2128
2118
|
const candidateCount = selected.length + 1;
|
|
2129
|
-
const
|
|
2119
|
+
const omitted = entries.length - candidateCount;
|
|
2130
2120
|
const candidateLength = selectedLength + entry.length + (selected.length > 0 ? separator.length : 0);
|
|
2131
|
-
if (omissionMarker(
|
|
2121
|
+
if (omissionMarker(omitted).length + separator.length + candidateLength > maxChars) {
|
|
2132
2122
|
break;
|
|
2133
2123
|
}
|
|
2134
2124
|
selected.unshift(entry);
|
|
@@ -2824,17 +2814,17 @@ var setupAbortWatch = (parentSignal, timeoutMs) => {
|
|
|
2824
2814
|
wasTimedOut: () => timedOut
|
|
2825
2815
|
};
|
|
2826
2816
|
};
|
|
2827
|
-
var streamScoutResponse = async (dependencies, resolved,
|
|
2817
|
+
var streamScoutResponse = async (dependencies, resolved, manifest, parentSignal, timeoutMs, publish) => {
|
|
2828
2818
|
const { abortPromise, controller, teardown, wasTimedOut } = setupAbortWatch(parentSignal, timeoutMs);
|
|
2829
2819
|
try {
|
|
2830
2820
|
const collection = dependencies.collect(resolved, {
|
|
2831
2821
|
messages: [manifestMessage(manifest)],
|
|
2832
2822
|
onChunk: (thinking, text) => {
|
|
2833
2823
|
if (!controller.signal.aborted) {
|
|
2834
|
-
publish({ model:
|
|
2824
|
+
publish({ model: executorRef, text, thinking, type: "chunk" });
|
|
2835
2825
|
}
|
|
2836
2826
|
},
|
|
2837
|
-
reasoning:
|
|
2827
|
+
reasoning: executorEffortRef,
|
|
2838
2828
|
signal: controller.signal,
|
|
2839
2829
|
systemPrompt: SCOUT_SYSTEM
|
|
2840
2830
|
});
|
|
@@ -2863,24 +2853,22 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
|
|
|
2863
2853
|
return { cancelled: true, ok: false };
|
|
2864
2854
|
};
|
|
2865
2855
|
const fallback = (category, message, usage) => {
|
|
2866
|
-
const
|
|
2856
|
+
const outcome = {
|
|
2867
2857
|
category,
|
|
2868
2858
|
message,
|
|
2869
2859
|
metrics: usage === undefined ? baseMetrics(manifest, startedAt) : { ...baseMetrics(manifest, startedAt), usage },
|
|
2870
|
-
model:
|
|
2860
|
+
model: executorRef,
|
|
2871
2861
|
ok: false
|
|
2872
2862
|
};
|
|
2873
|
-
publish({ outcome
|
|
2874
|
-
return
|
|
2863
|
+
publish({ outcome, type: "fallback" });
|
|
2864
|
+
return outcome;
|
|
2875
2865
|
};
|
|
2876
2866
|
if (parentSignal?.aborted) {
|
|
2877
2867
|
return cancelled();
|
|
2878
2868
|
}
|
|
2879
|
-
const executorModel = effectiveExecutorRef(ctx);
|
|
2880
|
-
const executorEffort = effectiveExecutorEffort(ctx);
|
|
2881
2869
|
let resolved;
|
|
2882
2870
|
try {
|
|
2883
|
-
resolved = await dependencies.resolve(ctx,
|
|
2871
|
+
resolved = await dependencies.resolve(ctx, executorRef, "Scout");
|
|
2884
2872
|
} catch (error) {
|
|
2885
2873
|
if (parentSignal?.aborted) {
|
|
2886
2874
|
return cancelled();
|
|
@@ -2891,8 +2879,8 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
|
|
|
2891
2879
|
if (parentSignal?.aborted) {
|
|
2892
2880
|
return cancelled();
|
|
2893
2881
|
}
|
|
2894
|
-
publish({ model:
|
|
2895
|
-
const streamed = await streamScoutResponse(dependencies, resolved,
|
|
2882
|
+
publish({ model: executorRef, type: "call" });
|
|
2883
|
+
const streamed = await streamScoutResponse(dependencies, resolved, manifest, parentSignal, timeoutMs, publish);
|
|
2896
2884
|
if (!streamed.ok) {
|
|
2897
2885
|
if (parentSignal?.aborted) {
|
|
2898
2886
|
return cancelled();
|
|
@@ -2919,7 +2907,7 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
|
|
|
2919
2907
|
]).size,
|
|
2920
2908
|
usage: snapshotAdvisorUsage(streamed.streamed.usage)
|
|
2921
2909
|
},
|
|
2922
|
-
model:
|
|
2910
|
+
model: executorRef,
|
|
2923
2911
|
ok: true,
|
|
2924
2912
|
selectedLabels: manifest.groups.filter((group) => group.required || selection.selectedIds.includes(group.id)).map((group) => group.label),
|
|
2925
2913
|
selection
|
|
@@ -2970,12 +2958,12 @@ var curateAdvisorConversation = async (ctx, legacyConversation, signal, onScout,
|
|
|
2970
2958
|
};
|
|
2971
2959
|
|
|
2972
2960
|
// src/tools/prompts.ts
|
|
2973
|
-
var advisorMessageText = (conversation, question, changes, draft, preferences,
|
|
2961
|
+
var advisorMessageText = (conversation, question, changes, draft, preferences, untracked, tracked) => {
|
|
2974
2962
|
const safeConversation = escapeRepositoryText(conversation);
|
|
2975
2963
|
const safeDraft = draft ? escapeRepositoryText(draft) : undefined;
|
|
2976
2964
|
const safePreferences = preferences ? escapeRepositoryText(preferences) : undefined;
|
|
2977
|
-
const safeUntracked = (
|
|
2978
|
-
const safeTracked = (
|
|
2965
|
+
const safeUntracked = (untracked ?? []).map(escapeRepositoryText);
|
|
2966
|
+
const safeTracked = (tracked ?? []).map(escapeRepositoryText);
|
|
2979
2967
|
const text = `${safeConversation ? `<conversation>
|
|
2980
2968
|
${safeConversation}
|
|
2981
2969
|
</conversation>` : ""}${changes ? `
|
|
@@ -3088,16 +3076,16 @@ var assembleConsultationContext = async (options) => {
|
|
|
3088
3076
|
const curated = await curateAdvisorConversation(ctx, legacyConversation, options.signal, options.onScout, advisorScoutEnabledRef, runAdvisorScout, options.currentInvocationId, conversationBudget);
|
|
3089
3077
|
const preferences = await readProjectPreferences(ctx, ATTACHMENT_TEXT_MAX_BYTES, advisorRedactSecretsRef);
|
|
3090
3078
|
const draftText = options.draft ? redactAndCapText(options.draft, ATTACHMENT_TEXT_MAX_BYTES, advisorRedactSecretsRef) : undefined;
|
|
3091
|
-
const
|
|
3092
|
-
const
|
|
3079
|
+
const untracked = await readUntrackedFiles(ctx.cwd, options.includeUntracked ?? [], advisorUntrackedContentRef, advisorRedactSecretsRef);
|
|
3080
|
+
const tracked = await readTrackedFiles(ctx.cwd, options.includeTracked ?? [], advisorTrackedFileContentRef, advisorRedactSecretsRef, Math.max(0, ATTACHMENTS_TOTAL_MAX_BYTES - untracked.reduce((sum, item) => sum + item.bytes, 0)));
|
|
3093
3081
|
return {
|
|
3094
3082
|
changeText,
|
|
3095
3083
|
conversation: curated.conversation,
|
|
3096
3084
|
draftText,
|
|
3097
3085
|
preferences,
|
|
3098
3086
|
scout: curated.scout,
|
|
3099
|
-
tracked
|
|
3100
|
-
untracked
|
|
3087
|
+
tracked,
|
|
3088
|
+
untracked
|
|
3101
3089
|
};
|
|
3102
3090
|
};
|
|
3103
3091
|
|
|
@@ -3161,11 +3149,11 @@ var parseAutomaticDecision = (text) => {
|
|
|
3161
3149
|
if (!subsequent) {
|
|
3162
3150
|
continue;
|
|
3163
3151
|
}
|
|
3164
|
-
const
|
|
3152
|
+
const repeated = namedGroups(subsequent).decision.trim().toLowerCase();
|
|
3165
3153
|
if (openingFence) {
|
|
3166
|
-
pendingFencedDecisions.push(
|
|
3154
|
+
pendingFencedDecisions.push(repeated);
|
|
3167
3155
|
} else {
|
|
3168
|
-
decisions.push(
|
|
3156
|
+
decisions.push(repeated);
|
|
3169
3157
|
}
|
|
3170
3158
|
}
|
|
3171
3159
|
if (openingFence) {
|
|
@@ -4185,7 +4173,7 @@ var resolveActivationModels = async (runtime, ctx) => {
|
|
|
4185
4173
|
if (!(advisorAuth.ok && advisorAuth.apiKey)) {
|
|
4186
4174
|
return { error: `No API key for Advisor ${advisorRef}` };
|
|
4187
4175
|
}
|
|
4188
|
-
if (!
|
|
4176
|
+
if (!await runtime.setExecutorModel(executor)) {
|
|
4189
4177
|
return { error: `No API key for Executor ${executorRef}` };
|
|
4190
4178
|
}
|
|
4191
4179
|
return {};
|
|
@@ -4231,7 +4219,7 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
|
|
|
4231
4219
|
saveConfig(ctx, { persistAdvisor: true, persistExecutor: true });
|
|
4232
4220
|
}
|
|
4233
4221
|
runtime.pendingExecutorModelRef = undefined;
|
|
4234
|
-
if (executorEffortRef
|
|
4222
|
+
if (executorEffortRef) {
|
|
4235
4223
|
runtime.pi.setThinkingLevel(executorEffortRef);
|
|
4236
4224
|
}
|
|
4237
4225
|
if (!runtime.flowEnabled()) {
|
|
@@ -4242,22 +4230,20 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
|
|
|
4242
4230
|
]);
|
|
4243
4231
|
}
|
|
4244
4232
|
if (announce) {
|
|
4245
|
-
const activeExecutorRef = effectiveExecutorRef(ctx);
|
|
4246
|
-
const activeExecutorEffort = effectiveExecutorEffort(ctx);
|
|
4247
4233
|
notify(ctx, `${ADVISOR_ACTIVATION_EXPLANATION}
|
|
4248
4234
|
|
|
4249
|
-
Advisor flow ready — Executor: ${
|
|
4235
|
+
Advisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`, "info");
|
|
4250
4236
|
}
|
|
4251
4237
|
};
|
|
4252
4238
|
|
|
4253
4239
|
// src/commands/lifecycle.ts
|
|
4254
|
-
var registerCommandLifecycle = (runtime,
|
|
4240
|
+
var registerCommandLifecycle = (runtime, activateAdvisor) => {
|
|
4255
4241
|
runtime.pi.on("session_start", async (_event, ctx) => {
|
|
4256
4242
|
runtime.pendingExecutorModelRef = undefined;
|
|
4257
4243
|
try {
|
|
4258
4244
|
loadConfig(ctx);
|
|
4259
4245
|
if (alwaysOnRef) {
|
|
4260
|
-
await
|
|
4246
|
+
await activateAdvisor("", ctx, false);
|
|
4261
4247
|
}
|
|
4262
4248
|
} catch (error) {
|
|
4263
4249
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -4265,7 +4251,7 @@ var registerCommandLifecycle = (runtime, activateAdvisor2) => {
|
|
|
4265
4251
|
}
|
|
4266
4252
|
});
|
|
4267
4253
|
runtime.pi.on("model_select", (event, ctx) => {
|
|
4268
|
-
if (event.source !== "set" || runtime.suppressModelSelectionSync
|
|
4254
|
+
if (event.source !== "set" || runtime.suppressModelSelectionSync) {
|
|
4269
4255
|
return;
|
|
4270
4256
|
}
|
|
4271
4257
|
const selected = `${event.model.provider}/${event.model.id}`;
|
|
@@ -4652,12 +4638,12 @@ var connectionFailure = (error) => {
|
|
|
4652
4638
|
failure: new JevFailureError("network", `Jev connection failed: ${message}`)
|
|
4653
4639
|
};
|
|
4654
4640
|
};
|
|
4655
|
-
var sleepWithAbort = (signal, ms) => new Promise((
|
|
4656
|
-
const timer = setTimeout(
|
|
4641
|
+
var sleepWithAbort = (signal, ms) => new Promise((resolve) => {
|
|
4642
|
+
const timer = setTimeout(resolve, ms);
|
|
4657
4643
|
timer.unref?.();
|
|
4658
4644
|
signal.addEventListener("abort", () => {
|
|
4659
4645
|
clearTimeout(timer);
|
|
4660
|
-
|
|
4646
|
+
resolve();
|
|
4661
4647
|
}, { once: true });
|
|
4662
4648
|
});
|
|
4663
4649
|
|
|
@@ -5644,56 +5630,6 @@ import { getKeybindings } from "@earendil-works/pi-tui";
|
|
|
5644
5630
|
import { Key as Key2, matchesKey as matchesKey2, truncateToWidth as truncateToWidth5 } from "@earendil-works/pi-tui";
|
|
5645
5631
|
|
|
5646
5632
|
// node_modules/@typesafe-ai/sdk/dist/index.mjs
|
|
5647
|
-
var requestIdFrom = (headers) => headers.get("x-typesafe-request-id") ?? undefined;
|
|
5648
|
-
var APIPromise = class APIPromise2 extends Promise {
|
|
5649
|
-
#responsePromise;
|
|
5650
|
-
#parseResponse;
|
|
5651
|
-
#parsed;
|
|
5652
|
-
constructor(responsePromise, parseResponse) {
|
|
5653
|
-
super((resolve2) => resolve2(undefined));
|
|
5654
|
-
this.#responsePromise = responsePromise;
|
|
5655
|
-
this.#parseResponse = parseResponse;
|
|
5656
|
-
}
|
|
5657
|
-
asResponse() {
|
|
5658
|
-
return this.#responsePromise;
|
|
5659
|
-
}
|
|
5660
|
-
async withResponse() {
|
|
5661
|
-
const [data, response] = await Promise.all([this.#parse(), this.#responsePromise]);
|
|
5662
|
-
return {
|
|
5663
|
-
data,
|
|
5664
|
-
response,
|
|
5665
|
-
requestId: requestIdFrom(response.headers)
|
|
5666
|
-
};
|
|
5667
|
-
}
|
|
5668
|
-
map(fn) {
|
|
5669
|
-
return new APIPromise2(this.#responsePromise, () => this.#parse().then(fn));
|
|
5670
|
-
}
|
|
5671
|
-
#parse() {
|
|
5672
|
-
this.#parsed ??= this.#responsePromise.then(this.#parseResponse);
|
|
5673
|
-
return this.#parsed;
|
|
5674
|
-
}
|
|
5675
|
-
then(onfulfilled, onrejected) {
|
|
5676
|
-
return this.#parse().then(onfulfilled, onrejected);
|
|
5677
|
-
}
|
|
5678
|
-
catch(onrejected) {
|
|
5679
|
-
return this.#parse().catch(onrejected);
|
|
5680
|
-
}
|
|
5681
|
-
finally(onfinally) {
|
|
5682
|
-
return this.#parse().finally(onfinally);
|
|
5683
|
-
}
|
|
5684
|
-
};
|
|
5685
|
-
var ENV = {
|
|
5686
|
-
apiKey: "TYPESAFE_API_KEY",
|
|
5687
|
-
baseURL: "TYPESAFE_BASE_URL",
|
|
5688
|
-
defaultModel: "TYPESAFE_DEFAULT_MODEL",
|
|
5689
|
-
logLevel: "TYPESAFE_LOG_LEVEL"
|
|
5690
|
-
};
|
|
5691
|
-
var readEnv = (name) => {
|
|
5692
|
-
if (typeof process === "undefined" || !process.env)
|
|
5693
|
-
return;
|
|
5694
|
-
return process.env[name]?.trim() || undefined;
|
|
5695
|
-
};
|
|
5696
|
-
var fromCodeOrEnv = (fromCode, envVar) => fromCode ?? readEnv(envVar);
|
|
5697
5633
|
var range2 = (from, to) => Array.from({ length: to - from }, (_, i) => from + i);
|
|
5698
5634
|
var DEFAULT_RETRY_POLICY = {
|
|
5699
5635
|
maxRetries: 2,
|
|
@@ -5711,239 +5647,11 @@ var DEFAULT_RETRY_POLICY = {
|
|
|
5711
5647
|
apiTimeoutError: true
|
|
5712
5648
|
};
|
|
5713
5649
|
DEFAULT_RETRY_POLICY.maxRetries;
|
|
5714
|
-
var isRetryableStatus = (status, policy = DEFAULT_RETRY_POLICY) => policy.httpStatuses.has(status);
|
|
5715
|
-
var parseRetryAfter = (headers, now = Date.now()) => {
|
|
5716
|
-
const ms = Number(headers.get("retry-after-ms"));
|
|
5717
|
-
if (headers.has("retry-after-ms") && Number.isFinite(ms) && ms >= 0)
|
|
5718
|
-
return ms;
|
|
5719
|
-
const raw = headers.get("retry-after");
|
|
5720
|
-
if (raw === null)
|
|
5721
|
-
return;
|
|
5722
|
-
const seconds = Number(raw);
|
|
5723
|
-
if (Number.isFinite(seconds))
|
|
5724
|
-
return seconds >= 0 ? seconds * 1000 : undefined;
|
|
5725
|
-
const date = Date.parse(raw);
|
|
5726
|
-
if (!Number.isNaN(date))
|
|
5727
|
-
return Math.max(0, date - now);
|
|
5728
|
-
};
|
|
5729
|
-
var retryDelayMs = (attempt, headers, policy = DEFAULT_RETRY_POLICY, random = Math.random) => {
|
|
5730
|
-
if (policy.respectRetryAfter && headers !== undefined) {
|
|
5731
|
-
const retryAfter = parseRetryAfter(headers);
|
|
5732
|
-
if (retryAfter !== undefined && retryAfter <= policy.maxRetryAfterMs)
|
|
5733
|
-
return retryAfter;
|
|
5734
|
-
}
|
|
5735
|
-
const exponential = Math.min(policy.backoffInitialMs * 2 ** attempt, policy.backoffMaxMs);
|
|
5736
|
-
return Math.round(exponential * (1 - random() * policy.backoffJitter));
|
|
5737
|
-
};
|
|
5738
|
-
var sleep = (ms, signal) => new Promise((resolve2, reject) => {
|
|
5739
|
-
if (signal?.aborted)
|
|
5740
|
-
return reject(signal.reason);
|
|
5741
|
-
const onAbort = () => {
|
|
5742
|
-
clearTimeout(timer);
|
|
5743
|
-
reject(signal?.reason);
|
|
5744
|
-
};
|
|
5745
|
-
const timer = setTimeout(() => {
|
|
5746
|
-
signal?.removeEventListener("abort", onAbort);
|
|
5747
|
-
resolve2();
|
|
5748
|
-
}, ms);
|
|
5749
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5750
|
-
});
|
|
5751
|
-
var TypeSafeError = class extends Error {
|
|
5752
|
-
constructor(message, options) {
|
|
5753
|
-
super(message, options);
|
|
5754
|
-
this.name = new.target.name;
|
|
5755
|
-
}
|
|
5756
|
-
};
|
|
5757
|
-
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
5758
|
-
var extractMessage = (body) => {
|
|
5759
|
-
if (typeof body === "string")
|
|
5760
|
-
return body || undefined;
|
|
5761
|
-
if (!isRecord2(body))
|
|
5762
|
-
return;
|
|
5763
|
-
const { error, message, detail } = body;
|
|
5764
|
-
if (typeof error === "string")
|
|
5765
|
-
return error;
|
|
5766
|
-
if (isRecord2(error) && typeof error.message === "string")
|
|
5767
|
-
return error.message;
|
|
5768
|
-
if (typeof message === "string")
|
|
5769
|
-
return message;
|
|
5770
|
-
if (typeof detail === "string")
|
|
5771
|
-
return detail;
|
|
5772
|
-
if (isRecord2(detail) && typeof detail.message === "string")
|
|
5773
|
-
return detail.message;
|
|
5774
|
-
if (Array.isArray(detail))
|
|
5775
|
-
return describeValidationErrors(detail);
|
|
5776
|
-
};
|
|
5777
|
-
var describeValidationErrors = (errors) => {
|
|
5778
|
-
const parts = errors.flatMap((e) => {
|
|
5779
|
-
if (!isRecord2(e) || typeof e.msg !== "string")
|
|
5780
|
-
return [];
|
|
5781
|
-
const loc = Array.isArray(e.loc) ? e.loc.filter((x) => x !== "body").join(".") : "";
|
|
5782
|
-
return [loc ? `${loc}: ${e.msg}` : e.msg];
|
|
5783
|
-
});
|
|
5784
|
-
return parts.length > 0 ? parts.join("; ") : undefined;
|
|
5785
|
-
};
|
|
5786
|
-
var MAX_RAW_BODY_IN_MESSAGE = 200;
|
|
5787
|
-
var APIError = class APIError2 extends TypeSafeError {
|
|
5788
|
-
status;
|
|
5789
|
-
headers;
|
|
5790
|
-
body;
|
|
5791
|
-
requestId;
|
|
5792
|
-
constructor(status, body, headers, message) {
|
|
5793
|
-
super(message ?? APIError2.describe(status, body));
|
|
5794
|
-
this.status = status;
|
|
5795
|
-
this.body = body;
|
|
5796
|
-
this.headers = headers;
|
|
5797
|
-
this.requestId = requestIdFrom(headers);
|
|
5798
|
-
}
|
|
5799
|
-
static describe(status, body) {
|
|
5800
|
-
const detail = extractMessage(body);
|
|
5801
|
-
if (detail)
|
|
5802
|
-
return `${status} ${detail}`;
|
|
5803
|
-
if (body === undefined)
|
|
5804
|
-
return `${status} status code (no body)`;
|
|
5805
|
-
const raw = typeof body === "string" ? body : JSON.stringify(body);
|
|
5806
|
-
return `${status} ${raw.length > MAX_RAW_BODY_IN_MESSAGE ? `${raw.slice(0, MAX_RAW_BODY_IN_MESSAGE)}…` : raw}`;
|
|
5807
|
-
}
|
|
5808
|
-
static fromResponse(status, body, headers) {
|
|
5809
|
-
if (status === 400)
|
|
5810
|
-
return new BadRequestError(status, body, headers);
|
|
5811
|
-
if (status === 401)
|
|
5812
|
-
return new AuthenticationError(status, body, headers);
|
|
5813
|
-
if (status === 403)
|
|
5814
|
-
return new PermissionDeniedError(status, body, headers);
|
|
5815
|
-
if (status === 404)
|
|
5816
|
-
return new NotFoundError(status, body, headers);
|
|
5817
|
-
if (status === 422)
|
|
5818
|
-
return new UnprocessableEntityError(status, body, headers);
|
|
5819
|
-
if (status === 429)
|
|
5820
|
-
return new RateLimitError(status, body, headers);
|
|
5821
|
-
if (status >= 500)
|
|
5822
|
-
return new InternalServerError(status, body, headers);
|
|
5823
|
-
return new APIError2(status, body, headers);
|
|
5824
|
-
}
|
|
5825
|
-
};
|
|
5826
|
-
var BadRequestError = class extends APIError {
|
|
5827
|
-
};
|
|
5828
|
-
var AuthenticationError = class extends APIError {
|
|
5829
|
-
};
|
|
5830
|
-
var PermissionDeniedError = class extends APIError {
|
|
5831
|
-
};
|
|
5832
|
-
var NotFoundError = class extends APIError {
|
|
5833
|
-
};
|
|
5834
|
-
var UnprocessableEntityError = class extends APIError {
|
|
5835
|
-
};
|
|
5836
|
-
var RateLimitError = class extends APIError {
|
|
5837
|
-
retryAfterMs = parseRetryAfter(this.headers);
|
|
5838
|
-
};
|
|
5839
|
-
var InternalServerError = class extends APIError {
|
|
5840
|
-
};
|
|
5841
|
-
var APIConnectionError = class extends TypeSafeError {
|
|
5842
|
-
constructor(message = "Connection error.", options) {
|
|
5843
|
-
super(message, options);
|
|
5844
|
-
}
|
|
5845
|
-
};
|
|
5846
|
-
var APITimeoutError = class extends APIConnectionError {
|
|
5847
|
-
timeoutMs;
|
|
5848
|
-
constructor(timeoutMs, options) {
|
|
5849
|
-
super(`Request timed out after ${timeoutMs}ms.`, options);
|
|
5850
|
-
this.timeoutMs = timeoutMs;
|
|
5851
|
-
}
|
|
5852
|
-
};
|
|
5853
|
-
var APIUserAbortError = class extends TypeSafeError {
|
|
5854
|
-
constructor(message = "Request was aborted.", options) {
|
|
5855
|
-
super(message, options);
|
|
5856
|
-
}
|
|
5857
|
-
};
|
|
5858
|
-
var LOG_LEVELS = [
|
|
5859
|
-
"debug",
|
|
5860
|
-
"info",
|
|
5861
|
-
"warn",
|
|
5862
|
-
"error",
|
|
5863
|
-
"off"
|
|
5864
|
-
];
|
|
5865
|
-
var DEFAULT_LOG_LEVEL = "warn";
|
|
5866
|
-
var isLogLevel = (value) => LOG_LEVELS.includes(value);
|
|
5867
|
-
var parseLogLevel = (value, source) => {
|
|
5868
|
-
if (isLogLevel(value))
|
|
5869
|
-
return value;
|
|
5870
|
-
throw new TypeSafeError(`Invalid log level "${value}" from ${source}. Expected one of: ${LOG_LEVELS.join(", ")}.`);
|
|
5871
|
-
};
|
|
5872
|
-
var PREFIX = "[typesafe-sdk]";
|
|
5873
|
-
var consoleLogger = {
|
|
5874
|
-
debug: (message, ...args) => console.debug(`${PREFIX} ${message}`, ...args),
|
|
5875
|
-
info: (message, ...args) => console.info(`${PREFIX} ${message}`, ...args),
|
|
5876
|
-
warn: (message, ...args) => console.warn(`${PREFIX} ${message}`, ...args),
|
|
5877
|
-
error: (message, ...args) => console.error(`${PREFIX} ${message}`, ...args)
|
|
5878
|
-
};
|
|
5879
|
-
var RANK = {
|
|
5880
|
-
debug: 0,
|
|
5881
|
-
info: 1,
|
|
5882
|
-
warn: 2,
|
|
5883
|
-
error: 3,
|
|
5884
|
-
off: 4
|
|
5885
|
-
};
|
|
5886
|
-
var drop = () => {};
|
|
5887
|
-
var withLevel = (sink, level) => {
|
|
5888
|
-
const enabled = (at) => RANK[at] >= RANK[level];
|
|
5889
|
-
return {
|
|
5890
|
-
debug: enabled("debug") ? (message, ...args) => sink.debug(message, ...args) : drop,
|
|
5891
|
-
info: enabled("info") ? (message, ...args) => sink.info(message, ...args) : drop,
|
|
5892
|
-
warn: enabled("warn") ? (message, ...args) => sink.warn(message, ...args) : drop,
|
|
5893
|
-
error: enabled("error") ? (message, ...args) => sink.error(message, ...args) : drop
|
|
5894
|
-
};
|
|
5895
|
-
};
|
|
5896
|
-
var KEY_HEADERS = /* @__PURE__ */ new Set([
|
|
5897
|
-
"authorization",
|
|
5898
|
-
"proxy-authorization",
|
|
5899
|
-
"x-api-key"
|
|
5900
|
-
]);
|
|
5901
|
-
var OPAQUE_HEADERS = /* @__PURE__ */ new Set(["cookie", "set-cookie"]);
|
|
5902
|
-
var redactKey = (value) => {
|
|
5903
|
-
const [scheme, secret] = value.includes(" ") ? value.split(/\s+/, 2) : [undefined, value];
|
|
5904
|
-
const tail = secret && secret.length > 8 ? secret.slice(-4) : "";
|
|
5905
|
-
return `${scheme ? `${scheme} ` : ""}***${tail}`;
|
|
5906
|
-
};
|
|
5907
|
-
var redact = (name, value) => {
|
|
5908
|
-
const lower = name.toLowerCase();
|
|
5909
|
-
if (KEY_HEADERS.has(lower))
|
|
5910
|
-
return redactKey(value);
|
|
5911
|
-
if (OPAQUE_HEADERS.has(lower))
|
|
5912
|
-
return "***";
|
|
5913
|
-
return value;
|
|
5914
|
-
};
|
|
5915
|
-
var redactHeaders = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [name, redact(name, value)]));
|
|
5916
5650
|
var noul = (instructions = null, criteria) => ({
|
|
5917
5651
|
type: "noul",
|
|
5918
5652
|
instructions,
|
|
5919
5653
|
criteria
|
|
5920
5654
|
});
|
|
5921
|
-
var validateQuestions = (questions) => {
|
|
5922
|
-
if (Object.keys(questions).length === 0)
|
|
5923
|
-
throw new TypeSafeError("At least one question is required.");
|
|
5924
|
-
for (const [name, question] of Object.entries(questions)) {
|
|
5925
|
-
if (question.type !== "score")
|
|
5926
|
-
continue;
|
|
5927
|
-
if (!Array.isArray(question.criteria))
|
|
5928
|
-
throw new TypeSafeError(`Score question "${name}" has criteria that are not a list; score criteria must be a list of descriptions indexed by score from zero.`);
|
|
5929
|
-
if (question.criteria.length < 2)
|
|
5930
|
-
throw new TypeSafeError(`Score question "${name}" has ${question.criteria.length} criteria; at least two scores are required.`);
|
|
5931
|
-
}
|
|
5932
|
-
};
|
|
5933
|
-
var Models = class {
|
|
5934
|
-
#transport;
|
|
5935
|
-
constructor(transport) {
|
|
5936
|
-
this.#transport = transport;
|
|
5937
|
-
}
|
|
5938
|
-
list(options = {}) {
|
|
5939
|
-
return this.#transport.request("GET", "/v1/models", options).map(unwrapModels);
|
|
5940
|
-
}
|
|
5941
|
-
};
|
|
5942
|
-
var unwrapModels = (wire) => {
|
|
5943
|
-
if (Array.isArray(wire?.models))
|
|
5944
|
-
return wire.models;
|
|
5945
|
-
throw new TypeSafeError("Unexpected response shape from GET /v1/models; expected { models: [...] }.");
|
|
5946
|
-
};
|
|
5947
5655
|
var g = globalThis;
|
|
5948
5656
|
var isBrowser = () => typeof g.window !== "undefined" && typeof g.window.document !== "undefined" && typeof g.navigator !== "undefined";
|
|
5949
5657
|
var describeRuntime = () => {
|
|
@@ -5962,280 +5670,7 @@ var describeRuntime = () => {
|
|
|
5962
5670
|
return "browser";
|
|
5963
5671
|
return "unknown";
|
|
5964
5672
|
};
|
|
5965
|
-
var VERSION = "0.6.0";
|
|
5966
|
-
var missingApiKey = () => {
|
|
5967
|
-
throw new TypeSafeError(`No API key was provided. Pass \`apiKey\` to the TypeSafeClient constructor or set the ${ENV.apiKey} environment variable.`);
|
|
5968
|
-
};
|
|
5969
|
-
var missingFetch = () => {
|
|
5970
|
-
throw new TypeSafeError("No global `fetch` is available in this runtime. Pass a `fetch` implementation to the TypeSafeClient constructor.");
|
|
5971
|
-
};
|
|
5972
|
-
var refuseBrowser = () => {
|
|
5973
|
-
throw new TypeSafeError("TypeSafeClient is running in a browser, which would expose your API key to anyone using the page. Call the API from a server instead, or pass `dangerouslyAllowBrowser: true` if you understand the risk.");
|
|
5974
|
-
};
|
|
5975
|
-
var defaultFetch = (input, init) => globalThis.fetch(input, init);
|
|
5976
|
-
var assertNonNegativeInteger = (name, value) => {
|
|
5977
|
-
if (!Number.isInteger(value) || value < 0)
|
|
5978
|
-
throw new TypeSafeError(`\`${name}\` must be a non-negative integer, got ${String(value)}.`);
|
|
5979
|
-
return value;
|
|
5980
|
-
};
|
|
5981
|
-
var assertPositiveMs = (name, value) => {
|
|
5982
|
-
if (!Number.isFinite(value) || value <= 0)
|
|
5983
|
-
throw new TypeSafeError(`\`${name}\` must be a positive number of milliseconds, got ${String(value)}.`);
|
|
5984
|
-
return value;
|
|
5985
|
-
};
|
|
5986
|
-
var assertNonNegativeMs = (name, value) => {
|
|
5987
|
-
if (!Number.isFinite(value) || value < 0)
|
|
5988
|
-
throw new TypeSafeError(`\`${name}\` must be a non-negative number of milliseconds, got ${String(value)}.`);
|
|
5989
|
-
return value;
|
|
5990
|
-
};
|
|
5991
|
-
var assertFraction = (name, value) => {
|
|
5992
|
-
if (!Number.isFinite(value) || value < 0 || value > 1)
|
|
5993
|
-
throw new TypeSafeError(`\`${name}\` must be between 0 and 1, got ${String(value)}.`);
|
|
5994
|
-
return value;
|
|
5995
|
-
};
|
|
5996
|
-
var assertStatusSet = (name, statuses) => {
|
|
5997
|
-
for (const status of statuses)
|
|
5998
|
-
if (!Number.isInteger(status) || status < 100 || status > 999)
|
|
5999
|
-
throw new TypeSafeError(`\`${name}\` must contain HTTP status codes, got ${String(status)}.`);
|
|
6000
|
-
return statuses;
|
|
6001
|
-
};
|
|
6002
|
-
var resolveRetryPolicy = (base, overrides) => {
|
|
6003
|
-
const o = overrides ?? {};
|
|
6004
|
-
return {
|
|
6005
|
-
maxRetries: o.maxRetries === undefined ? base.maxRetries : assertNonNegativeInteger("retry.maxRetries", o.maxRetries),
|
|
6006
|
-
backoffInitialMs: o.backoffInitialMs === undefined ? base.backoffInitialMs : assertNonNegativeMs("retry.backoffInitialMs", o.backoffInitialMs),
|
|
6007
|
-
backoffMaxMs: o.backoffMaxMs === undefined ? base.backoffMaxMs : assertNonNegativeMs("retry.backoffMaxMs", o.backoffMaxMs),
|
|
6008
|
-
backoffJitter: o.backoffJitter === undefined ? base.backoffJitter : assertFraction("retry.backoffJitter", o.backoffJitter),
|
|
6009
|
-
httpStatuses: new Set(o.httpStatuses === undefined ? base.httpStatuses : assertStatusSet("retry.httpStatuses", o.httpStatuses)),
|
|
6010
|
-
respectRetryAfter: o.respectRetryAfter ?? base.respectRetryAfter,
|
|
6011
|
-
maxRetryAfterMs: o.maxRetryAfterMs === undefined ? base.maxRetryAfterMs : assertNonNegativeMs("retry.maxRetryAfterMs", o.maxRetryAfterMs),
|
|
6012
|
-
apiConnectionError: o.apiConnectionError ?? base.apiConnectionError,
|
|
6013
|
-
apiTimeoutError: o.apiTimeoutError ?? base.apiTimeoutError
|
|
6014
|
-
};
|
|
6015
|
-
};
|
|
6016
|
-
var isRetryableError = (err, policy) => {
|
|
6017
|
-
if (err instanceof APITimeoutError)
|
|
6018
|
-
return policy.apiTimeoutError;
|
|
6019
|
-
if (err instanceof APIConnectionError)
|
|
6020
|
-
return policy.apiConnectionError;
|
|
6021
|
-
return false;
|
|
6022
|
-
};
|
|
6023
|
-
var resolveLogLevel = (fromCode) => {
|
|
6024
|
-
if (fromCode !== undefined)
|
|
6025
|
-
return parseLogLevel(fromCode, "the `logLevel` option");
|
|
6026
|
-
const fromEnv = readEnv(ENV.logLevel);
|
|
6027
|
-
if (fromEnv !== undefined)
|
|
6028
|
-
return parseLogLevel(fromEnv, ENV.logLevel);
|
|
6029
|
-
return DEFAULT_LOG_LEVEL;
|
|
6030
|
-
};
|
|
6031
|
-
var stripTrailingSlashes = (url) => url.replace(/\/+$/, "");
|
|
6032
|
-
var mergeHeaders = (...sources) => {
|
|
6033
|
-
const entries = /* @__PURE__ */ new Map;
|
|
6034
|
-
for (const source of sources)
|
|
6035
|
-
for (const [name, value] of Object.entries(source))
|
|
6036
|
-
if (value === undefined)
|
|
6037
|
-
entries.delete(name.toLowerCase());
|
|
6038
|
-
else
|
|
6039
|
-
entries.set(name.toLowerCase(), [name, value]);
|
|
6040
|
-
return Object.fromEntries(entries.values());
|
|
6041
|
-
};
|
|
6042
|
-
var bufferResponse = async (response, signal) => {
|
|
6043
|
-
const reader = response.clone().body?.getReader();
|
|
6044
|
-
if (!reader)
|
|
6045
|
-
return;
|
|
6046
|
-
const cancel = () => {
|
|
6047
|
-
reader.cancel(signal.reason).catch(() => {});
|
|
6048
|
-
response.body?.cancel(signal.reason).catch(() => {});
|
|
6049
|
-
};
|
|
6050
|
-
signal.addEventListener("abort", cancel, { once: true });
|
|
6051
|
-
try {
|
|
6052
|
-
if (signal.aborted)
|
|
6053
|
-
cancel();
|
|
6054
|
-
signal.throwIfAborted();
|
|
6055
|
-
while (!(await reader.read()).done)
|
|
6056
|
-
signal.throwIfAborted();
|
|
6057
|
-
signal.throwIfAborted();
|
|
6058
|
-
} finally {
|
|
6059
|
-
signal.removeEventListener("abort", cancel);
|
|
6060
|
-
reader.releaseLock();
|
|
6061
|
-
}
|
|
6062
|
-
};
|
|
6063
5673
|
var RUNTIME = describeRuntime();
|
|
6064
|
-
var TypeSafeClient = class {
|
|
6065
|
-
#apiKey;
|
|
6066
|
-
baseURL;
|
|
6067
|
-
defaultModel;
|
|
6068
|
-
logLevel;
|
|
6069
|
-
logger;
|
|
6070
|
-
retry;
|
|
6071
|
-
timeout;
|
|
6072
|
-
defaultHeaders;
|
|
6073
|
-
fetch;
|
|
6074
|
-
models;
|
|
6075
|
-
#requestCount = 0;
|
|
6076
|
-
constructor(config = {}) {
|
|
6077
|
-
if (isBrowser() && !config.dangerouslyAllowBrowser)
|
|
6078
|
-
refuseBrowser();
|
|
6079
|
-
this.#apiKey = fromCodeOrEnv(config.apiKey, ENV.apiKey) ?? missingApiKey();
|
|
6080
|
-
this.baseURL = stripTrailingSlashes(fromCodeOrEnv(config.baseURL, ENV.baseURL) ?? "https://api.typesafe.ai");
|
|
6081
|
-
this.defaultModel = fromCodeOrEnv(config.defaultModel, ENV.defaultModel) ?? "jev-latest";
|
|
6082
|
-
this.logLevel = resolveLogLevel(config.logLevel);
|
|
6083
|
-
this.logger = withLevel(config.logger ?? consoleLogger, this.logLevel);
|
|
6084
|
-
this.retry = resolveRetryPolicy(DEFAULT_RETRY_POLICY, config.retry);
|
|
6085
|
-
this.timeout = assertPositiveMs("timeout", config.timeout ?? 1e4);
|
|
6086
|
-
this.defaultHeaders = { ...config.defaultHeaders };
|
|
6087
|
-
if (config.fetch === undefined && typeof globalThis.fetch !== "function")
|
|
6088
|
-
missingFetch();
|
|
6089
|
-
this.fetch = config.fetch ?? defaultFetch;
|
|
6090
|
-
const transport = {
|
|
6091
|
-
request: (method, path, options) => this.#request(method, path, options),
|
|
6092
|
-
defaultModel: this.defaultModel
|
|
6093
|
-
};
|
|
6094
|
-
this.models = new Models(transport);
|
|
6095
|
-
}
|
|
6096
|
-
systemOne(request, options = {}) {
|
|
6097
|
-
validateQuestions(request.questions);
|
|
6098
|
-
const body = {
|
|
6099
|
-
...request,
|
|
6100
|
-
model: request.model ?? this.defaultModel
|
|
6101
|
-
};
|
|
6102
|
-
return this.#request("POST", "/v1/systemone", {
|
|
6103
|
-
...options,
|
|
6104
|
-
body
|
|
6105
|
-
});
|
|
6106
|
-
}
|
|
6107
|
-
#request(method, path, options = {}) {
|
|
6108
|
-
const resolved = {
|
|
6109
|
-
method,
|
|
6110
|
-
path,
|
|
6111
|
-
body: options.body,
|
|
6112
|
-
headers: mergeHeaders(this.defaultHeaders, options.headers ?? {}),
|
|
6113
|
-
signal: options.signal,
|
|
6114
|
-
timeout: options.timeout === undefined ? this.timeout : assertPositiveMs("timeout", options.timeout),
|
|
6115
|
-
retry: resolveRetryPolicy(this.retry, options.retry)
|
|
6116
|
-
};
|
|
6117
|
-
const tag = `#${++this.#requestCount} ${method} ${path}`;
|
|
6118
|
-
return new APIPromise(this.fetchWithRetries(tag, resolved), async (res) => {
|
|
6119
|
-
const parsed = await parseBody(res);
|
|
6120
|
-
this.logger.debug(`${tag} <- body`, parsed);
|
|
6121
|
-
return parsed;
|
|
6122
|
-
});
|
|
6123
|
-
}
|
|
6124
|
-
async fetchWithRetries(tag, req) {
|
|
6125
|
-
const url = `${this.baseURL}${req.path}`;
|
|
6126
|
-
const headers = mergeHeaders(req.headers, {
|
|
6127
|
-
Authorization: `Bearer ${this.#apiKey}`,
|
|
6128
|
-
Accept: "application/json",
|
|
6129
|
-
"User-Agent": `typesafe-sdk/${VERSION}`,
|
|
6130
|
-
"X-TypeSafe-SDK": `typesafe-sdk/${VERSION}`,
|
|
6131
|
-
"X-TypeSafe-Runtime": RUNTIME,
|
|
6132
|
-
"Content-Type": req.body === undefined ? undefined : "application/json",
|
|
6133
|
-
"X-TypeSafe-Retry-Count": undefined
|
|
6134
|
-
});
|
|
6135
|
-
const body = req.body === undefined ? undefined : JSON.stringify(req.body);
|
|
6136
|
-
for (let attempt = 0;; attempt++) {
|
|
6137
|
-
const retriesLeft = req.retry.maxRetries - attempt;
|
|
6138
|
-
const attemptHeaders = attempt === 0 ? headers : {
|
|
6139
|
-
...headers,
|
|
6140
|
-
"X-TypeSafe-Retry-Count": String(attempt)
|
|
6141
|
-
};
|
|
6142
|
-
this.logger.debug(`${tag} -> ${url}`, {
|
|
6143
|
-
headers: redactHeaders(attemptHeaders),
|
|
6144
|
-
body: req.body
|
|
6145
|
-
});
|
|
6146
|
-
const started = Date.now();
|
|
6147
|
-
let res;
|
|
6148
|
-
try {
|
|
6149
|
-
res = await this.attempt(tag, url, {
|
|
6150
|
-
method: req.method,
|
|
6151
|
-
headers: attemptHeaders,
|
|
6152
|
-
body
|
|
6153
|
-
}, req);
|
|
6154
|
-
} catch (err) {
|
|
6155
|
-
if (err instanceof APIUserAbortError || retriesLeft <= 0)
|
|
6156
|
-
throw err;
|
|
6157
|
-
if (!isRetryableError(err, req.retry))
|
|
6158
|
-
throw err;
|
|
6159
|
-
await this.backOff(tag, attempt, retriesLeft, err.message, undefined, req);
|
|
6160
|
-
continue;
|
|
6161
|
-
}
|
|
6162
|
-
const requestId = requestIdFrom(res.headers);
|
|
6163
|
-
this.logger.info(`${tag} <- ${res.status} in ${Date.now() - started}ms${requestId ? ` (request ${requestId})` : ""}`);
|
|
6164
|
-
if (res.ok)
|
|
6165
|
-
return res;
|
|
6166
|
-
const errorBody = await parseBody(res);
|
|
6167
|
-
this.logger.debug(`${tag} <- error body`, errorBody);
|
|
6168
|
-
const error = APIError.fromResponse(res.status, errorBody, res.headers);
|
|
6169
|
-
if (retriesLeft <= 0 || !isRetryableStatus(res.status, req.retry))
|
|
6170
|
-
throw error;
|
|
6171
|
-
await this.backOff(tag, attempt, retriesLeft, `${res.status}`, res.headers, req);
|
|
6172
|
-
}
|
|
6173
|
-
}
|
|
6174
|
-
async attempt(tag, url, init, { signal, timeout }) {
|
|
6175
|
-
const controller = new AbortController;
|
|
6176
|
-
const abortFromCaller = () => controller.abort(signal?.reason);
|
|
6177
|
-
if (signal?.aborted)
|
|
6178
|
-
abortFromCaller();
|
|
6179
|
-
signal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
6180
|
-
let timedOut = false;
|
|
6181
|
-
const timer = setTimeout(() => {
|
|
6182
|
-
timedOut = true;
|
|
6183
|
-
controller.abort();
|
|
6184
|
-
}, timeout);
|
|
6185
|
-
const started = Date.now();
|
|
6186
|
-
const elapsed = () => `${Date.now() - started}ms`;
|
|
6187
|
-
try {
|
|
6188
|
-
const response = await this.fetch(url, {
|
|
6189
|
-
...init,
|
|
6190
|
-
signal: controller.signal
|
|
6191
|
-
});
|
|
6192
|
-
await bufferResponse(response, controller.signal);
|
|
6193
|
-
return response;
|
|
6194
|
-
} catch (err) {
|
|
6195
|
-
if (signal?.aborted) {
|
|
6196
|
-
this.logger.info(`${tag} aborted by caller after ${elapsed()}`);
|
|
6197
|
-
throw new APIUserAbortError(undefined, { cause: err });
|
|
6198
|
-
}
|
|
6199
|
-
if (timedOut) {
|
|
6200
|
-
this.logger.info(`${tag} timed out after ${elapsed()}`);
|
|
6201
|
-
throw new APITimeoutError(timeout, { cause: err });
|
|
6202
|
-
}
|
|
6203
|
-
this.logger.info(`${tag} connection error after ${elapsed()}`, err);
|
|
6204
|
-
throw new APIConnectionError(err instanceof Error ? `Connection error: ${err.message}` : undefined, { cause: err });
|
|
6205
|
-
} finally {
|
|
6206
|
-
clearTimeout(timer);
|
|
6207
|
-
signal?.removeEventListener("abort", abortFromCaller);
|
|
6208
|
-
}
|
|
6209
|
-
}
|
|
6210
|
-
async backOff(tag, attempt, retriesLeft, reason, headers, { retry, signal }) {
|
|
6211
|
-
const delay = retryDelayMs(attempt, headers, retry);
|
|
6212
|
-
const nth = attempt + 1;
|
|
6213
|
-
const total = attempt + retriesLeft;
|
|
6214
|
-
this.logger.info(`${tag} retrying in ${delay}ms (retry ${nth}/${total}) after ${reason}`);
|
|
6215
|
-
try {
|
|
6216
|
-
await sleep(delay, signal);
|
|
6217
|
-
} catch (err) {
|
|
6218
|
-
this.logger.info(`${tag} aborted by caller while waiting to retry`);
|
|
6219
|
-
throw new APIUserAbortError(undefined, { cause: err });
|
|
6220
|
-
}
|
|
6221
|
-
}
|
|
6222
|
-
};
|
|
6223
|
-
var parseBody = async (res) => {
|
|
6224
|
-
const text = await res.text();
|
|
6225
|
-
if (text.length === 0)
|
|
6226
|
-
return;
|
|
6227
|
-
if ((res.headers.get("content-type") ?? "").includes("application/json"))
|
|
6228
|
-
try {
|
|
6229
|
-
return JSON.parse(text);
|
|
6230
|
-
} catch {
|
|
6231
|
-
return text;
|
|
6232
|
-
}
|
|
6233
|
-
try {
|
|
6234
|
-
return JSON.parse(text);
|
|
6235
|
-
} catch {
|
|
6236
|
-
return text;
|
|
6237
|
-
}
|
|
6238
|
-
};
|
|
6239
5674
|
|
|
6240
5675
|
// src/ui/masked-input.ts
|
|
6241
5676
|
import { Input as Input2, truncateToWidth as truncateToWidth4 } from "@earendil-works/pi-tui";
|
|
@@ -7338,7 +6773,7 @@ import {
|
|
|
7338
6773
|
writeFile
|
|
7339
6774
|
} from "node:fs/promises";
|
|
7340
6775
|
import { join as join5 } from "node:path";
|
|
7341
|
-
import { setTimeout as
|
|
6776
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
7342
6777
|
import { getAgentDir as getAgentDir4 } from "@earendil-works/pi-coding-agent";
|
|
7343
6778
|
var ADOPTIONS = [
|
|
7344
6779
|
"followed",
|
|
@@ -7426,7 +6861,7 @@ var withOutcomeLock = async (run) => {
|
|
|
7426
6861
|
}
|
|
7427
6862
|
continue;
|
|
7428
6863
|
}
|
|
7429
|
-
await
|
|
6864
|
+
await sleep(5);
|
|
7430
6865
|
}
|
|
7431
6866
|
}
|
|
7432
6867
|
throw new Error("Timed out waiting to append an Advisor outcome.");
|
|
@@ -8328,8 +7763,8 @@ function registerPiAdvisor(pi) {
|
|
|
8328
7763
|
});
|
|
8329
7764
|
}
|
|
8330
7765
|
export {
|
|
8331
|
-
|
|
8332
|
-
parseAutomaticDecision2 as parseAutomaticDecision,
|
|
7766
|
+
consultAdvisor2 as consultAdvisor,
|
|
8333
7767
|
registerPiAdvisor as default,
|
|
8334
|
-
|
|
7768
|
+
parseAutomaticDecision2 as parseAutomaticDecision,
|
|
7769
|
+
runAdvisorGate2 as runAdvisorGate
|
|
8335
7770
|
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
effectiveExecutorEffort,
|
|
5
|
-
effectiveExecutorRef,
|
|
6
|
-
isMarkedSubagent,
|
|
7
|
-
} from "../child-session.ts";
|
|
8
3
|
import { parseArgs } from "../config/args.ts";
|
|
9
4
|
import {
|
|
10
5
|
advisorEffortRef,
|
|
@@ -56,7 +51,7 @@ const resolveActivationModels = async (
|
|
|
56
51
|
if (!(advisorAuth.ok && advisorAuth.apiKey)) {
|
|
57
52
|
return { error: `No API key for Advisor ${advisorRef}` };
|
|
58
53
|
}
|
|
59
|
-
if (!
|
|
54
|
+
if (!(await runtime.setExecutorModel(executor))) {
|
|
60
55
|
return { error: `No API key for Executor ${executorRef}` };
|
|
61
56
|
}
|
|
62
57
|
return {};
|
|
@@ -121,7 +116,7 @@ export const activateAdvisor = async (
|
|
|
121
116
|
// an older inactive selection override an explicit activation argument on a
|
|
122
117
|
// later attempt.
|
|
123
118
|
runtime.pendingExecutorModelRef = undefined;
|
|
124
|
-
if (executorEffortRef
|
|
119
|
+
if (executorEffortRef) {
|
|
125
120
|
// SAFETY: executorEffortRef is operator-configured and trusted to name a ThinkingLevel.
|
|
126
121
|
runtime.pi.setThinkingLevel(executorEffortRef as ThinkingLevel);
|
|
127
122
|
}
|
|
@@ -133,11 +128,9 @@ export const activateAdvisor = async (
|
|
|
133
128
|
]);
|
|
134
129
|
}
|
|
135
130
|
if (announce) {
|
|
136
|
-
const activeExecutorRef = effectiveExecutorRef(ctx);
|
|
137
|
-
const activeExecutorEffort = effectiveExecutorEffort(ctx);
|
|
138
131
|
notify(
|
|
139
132
|
ctx,
|
|
140
|
-
`${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${
|
|
133
|
+
`${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
|
|
141
134
|
"info"
|
|
142
135
|
);
|
|
143
136
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
|
-
import { isMarkedSubagent } from "../child-session.ts";
|
|
4
3
|
import {
|
|
5
4
|
alwaysOnRef,
|
|
6
5
|
executorRef,
|
|
@@ -41,11 +40,7 @@ export const registerCommandLifecycle = (
|
|
|
41
40
|
// "restore" replays a stored session model and "cycle" changes the active
|
|
42
41
|
// model without an explicit `/model` choice. Neither should redefine the
|
|
43
42
|
// configured Executor.
|
|
44
|
-
if (
|
|
45
|
-
event.source !== "set" ||
|
|
46
|
-
runtime.suppressModelSelectionSync ||
|
|
47
|
-
isMarkedSubagent()
|
|
48
|
-
) {
|
|
43
|
+
if (event.source !== "set" || runtime.suppressModelSelectionSync) {
|
|
49
44
|
return;
|
|
50
45
|
}
|
|
51
46
|
const selected = `${event.model.provider}/${event.model.id}`;
|
package/src/scout.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { Message } from "@earendil-works/pi-ai/compat";
|
|
2
2
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
effectiveExecutorEffort,
|
|
6
|
-
effectiveExecutorRef,
|
|
7
|
-
} from "./child-session.ts";
|
|
4
|
+
import { executorEffortRef, executorRef } from "./config/state.ts";
|
|
8
5
|
import { isRecord, isString } from "./content-utils.ts";
|
|
9
6
|
import { collectTextStream, resolveConfiguredModel } from "./model-stream.ts";
|
|
10
7
|
import type {
|
|
@@ -253,8 +250,6 @@ type ScoutStreamResult =
|
|
|
253
250
|
const streamScoutResponse = async (
|
|
254
251
|
dependencies: ScoutDependencies,
|
|
255
252
|
resolved: ResolvedConfiguredModel,
|
|
256
|
-
executorModel: string,
|
|
257
|
-
executorEffort: string | undefined,
|
|
258
253
|
manifest: ScoutManifest,
|
|
259
254
|
parentSignal: AbortSignal | undefined,
|
|
260
255
|
timeoutMs: number,
|
|
@@ -269,10 +264,10 @@ const streamScoutResponse = async (
|
|
|
269
264
|
messages: [manifestMessage(manifest)],
|
|
270
265
|
onChunk: (thinking, text) => {
|
|
271
266
|
if (!controller.signal.aborted) {
|
|
272
|
-
publish({ model:
|
|
267
|
+
publish({ model: executorRef, text, thinking, type: "chunk" });
|
|
273
268
|
}
|
|
274
269
|
},
|
|
275
|
-
reasoning:
|
|
270
|
+
reasoning: executorEffortRef,
|
|
276
271
|
signal: controller.signal,
|
|
277
272
|
systemPrompt: SCOUT_SYSTEM,
|
|
278
273
|
});
|
|
@@ -322,7 +317,7 @@ export const runAdvisorScout = async (
|
|
|
322
317
|
usage === undefined
|
|
323
318
|
? baseMetrics(manifest, startedAt)
|
|
324
319
|
: { ...baseMetrics(manifest, startedAt), usage },
|
|
325
|
-
model:
|
|
320
|
+
model: executorRef,
|
|
326
321
|
ok: false as const,
|
|
327
322
|
};
|
|
328
323
|
publish({ outcome, type: "fallback" });
|
|
@@ -333,11 +328,9 @@ export const runAdvisorScout = async (
|
|
|
333
328
|
return cancelled();
|
|
334
329
|
}
|
|
335
330
|
|
|
336
|
-
const executorModel = effectiveExecutorRef(ctx);
|
|
337
|
-
const executorEffort = effectiveExecutorEffort(ctx);
|
|
338
331
|
let resolved: ResolvedConfiguredModel;
|
|
339
332
|
try {
|
|
340
|
-
resolved = await dependencies.resolve(ctx,
|
|
333
|
+
resolved = await dependencies.resolve(ctx, executorRef, "Scout");
|
|
341
334
|
} catch (error) {
|
|
342
335
|
if (parentSignal?.aborted) {
|
|
343
336
|
return cancelled();
|
|
@@ -349,13 +342,11 @@ export const runAdvisorScout = async (
|
|
|
349
342
|
if (parentSignal?.aborted) {
|
|
350
343
|
return cancelled();
|
|
351
344
|
}
|
|
352
|
-
publish({ model:
|
|
345
|
+
publish({ model: executorRef, type: "call" });
|
|
353
346
|
|
|
354
347
|
const streamed = await streamScoutResponse(
|
|
355
348
|
dependencies,
|
|
356
349
|
resolved,
|
|
357
|
-
executorModel,
|
|
358
|
-
executorEffort,
|
|
359
350
|
manifest,
|
|
360
351
|
parentSignal,
|
|
361
352
|
timeoutMs,
|
|
@@ -399,7 +390,7 @@ export const runAdvisorScout = async (
|
|
|
399
390
|
]).size,
|
|
400
391
|
usage: snapshotAdvisorUsage(streamed.streamed.usage),
|
|
401
392
|
},
|
|
402
|
-
model:
|
|
393
|
+
model: executorRef,
|
|
403
394
|
ok: true as const,
|
|
404
395
|
selectedLabels: manifest.groups
|
|
405
396
|
.filter(
|
package/src/child-session.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
import { executorEffortRef, executorRef } from "./config/state.ts";
|
|
4
|
-
|
|
5
|
-
export const isMarkedSubagent = () => process.env.PI_SUBAGENT_CHILD === "1";
|
|
6
|
-
|
|
7
|
-
export const effectiveExecutorRef = (ctx: ExtensionContext) => {
|
|
8
|
-
if (isMarkedSubagent() && ctx.model) {
|
|
9
|
-
return `${ctx.model.provider}/${ctx.model.id}`;
|
|
10
|
-
}
|
|
11
|
-
return executorRef;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const effectiveExecutorEffort = (ctx: ExtensionContext) =>
|
|
15
|
-
isMarkedSubagent() ? ctx.thinkingLevel : executorEffortRef;
|