@coreplane/switchboard 1.223.0 → 1.225.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/config/config.example.yaml +5 -1
- package/dist/assets/deploy/cloudflare-resident/Dockerfile +47 -12
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +28 -9
- package/dist/assets/package-lock.json +980 -4
- package/dist/assets/package.json +2 -1
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/providers/types.ts +3 -0
- package/dist/assets/web/dist/.vite/manifest.json +20 -20
- package/dist/assets/web/dist/assets/CostsPage-BlPwsI2T.js +3 -0
- package/dist/assets/web/dist/assets/{ResidentDetailPage-BTg4oFcn.js → ResidentDetailPage-Cu4Ve2j4.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-Dr2qkjKI.js → ResidentsIndexPage-_QIDVyOj.js} +1 -1
- package/dist/assets/web/dist/assets/RunRoutePage-DxgcHX-0.js +12 -0
- package/dist/assets/web/dist/assets/{RunsIndexPage-DEkZXNnw.js → RunsIndexPage-JQvnDmo0.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-wA7HE6UW.js → ScheduledPage-DEVRWqZi.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-7ojvQlTS.js → StatusDot-BDAKF1Bp.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-Cx88lWUW.js → Tooltip-BFncyNUQ.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-B85zXO-d.js → dist-DJfQXPjH.js} +1 -1
- package/dist/assets/web/dist/assets/{main-BdoqEBpN.js → main-BjhiJxQq.js} +2 -2
- package/dist/assets/web/dist/assets/main-DymOuq2l.css +1 -0
- package/dist/cli.js +404 -89
- package/package.json +2 -1
- package/dist/assets/web/dist/assets/CostsPage-C-ximW1N.js +0 -2
- package/dist/assets/web/dist/assets/RunRoutePage-CTbnfyBQ.js +0 -12
- package/dist/assets/web/dist/assets/main-C1tNx19B.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -11448,6 +11448,41 @@ var init_config3 = __esm({
|
|
|
11448
11448
|
}
|
|
11449
11449
|
});
|
|
11450
11450
|
|
|
11451
|
+
// ../../src/providers/types.ts
|
|
11452
|
+
function toolResultText(content) {
|
|
11453
|
+
if (typeof content === "string") return content;
|
|
11454
|
+
return content.map((p) => {
|
|
11455
|
+
if (p.type === "text") return p.text;
|
|
11456
|
+
if (p.type === "image") return `[image ${p.mediaType}, ${base64Bytes(p.data)} bytes]`;
|
|
11457
|
+
return `[document ${p.name ?? "document"} (${p.mediaType}), ${base64Bytes(p.data)} bytes]`;
|
|
11458
|
+
}).join("\n");
|
|
11459
|
+
}
|
|
11460
|
+
function capToolResultContent(content, cap = MAX_TOOL_RESULT_CHARS) {
|
|
11461
|
+
const capText = (text) => text.length > cap ? `${text.slice(0, cap)}
|
|
11462
|
+
\u2026[tool result truncated: ${text.length - cap} of ${text.length} characters cut \u2014 ask for a narrower slice]` : text;
|
|
11463
|
+
if (typeof content === "string") return capText(content);
|
|
11464
|
+
return content.map((p) => p.type === "text" ? { ...p, text: capText(p.text) } : p);
|
|
11465
|
+
}
|
|
11466
|
+
function base64Bytes(b64) {
|
|
11467
|
+
const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
|
|
11468
|
+
return Math.floor(b64.length * 3 / 4) - padding;
|
|
11469
|
+
}
|
|
11470
|
+
function parseModelRef(ref) {
|
|
11471
|
+
const i = ref.indexOf("/");
|
|
11472
|
+
if (i === -1) {
|
|
11473
|
+
throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>", e.g. "anthropic/claude-opus-5"`);
|
|
11474
|
+
}
|
|
11475
|
+
return { provider: ref.slice(0, i), model: ref.slice(i + 1) };
|
|
11476
|
+
}
|
|
11477
|
+
var MAX_TOOL_RESULT_CHARS, ANTHROPIC_API_KEY_ENV;
|
|
11478
|
+
var init_types2 = __esm({
|
|
11479
|
+
"../../src/providers/types.ts"() {
|
|
11480
|
+
"use strict";
|
|
11481
|
+
MAX_TOOL_RESULT_CHARS = 12e4;
|
|
11482
|
+
ANTHROPIC_API_KEY_ENV = "ANTHROPIC_API_KEY";
|
|
11483
|
+
}
|
|
11484
|
+
});
|
|
11485
|
+
|
|
11451
11486
|
// ../../src/providers/anthropic.ts
|
|
11452
11487
|
import Anthropic from "@anthropic-ai/sdk";
|
|
11453
11488
|
function anthropicApiKey(providers, secrets) {
|
|
@@ -11568,12 +11603,12 @@ function usageFromAnthropic(u) {
|
|
|
11568
11603
|
if (typeof o.cache_creation_input_tokens === "number") usage.cacheWriteTokens = o.cache_creation_input_tokens;
|
|
11569
11604
|
return usage;
|
|
11570
11605
|
}
|
|
11571
|
-
var
|
|
11606
|
+
var AnthropicProvider, EPHEMERAL, CACHEABLE_BLOCKS;
|
|
11572
11607
|
var init_anthropic = __esm({
|
|
11573
11608
|
"../../src/providers/anthropic.ts"() {
|
|
11574
11609
|
"use strict";
|
|
11575
11610
|
init_secrets2();
|
|
11576
|
-
|
|
11611
|
+
init_types2();
|
|
11577
11612
|
AnthropicProvider = class {
|
|
11578
11613
|
name;
|
|
11579
11614
|
client;
|
|
@@ -11671,6 +11706,8 @@ function parseCostsConfig(raw) {
|
|
|
11671
11706
|
const r = raw;
|
|
11672
11707
|
if (typeof r.cloudflareAccountId !== "string" || !r.cloudflareAccountId)
|
|
11673
11708
|
throw new Error("costs.cloudflareAccountId is required");
|
|
11709
|
+
if (r.cloudflareAccountName !== void 0 && typeof r.cloudflareAccountName !== "string")
|
|
11710
|
+
throw new Error("costs.cloudflareAccountName must be a string when given");
|
|
11674
11711
|
if (!r.groups || typeof r.groups !== "object")
|
|
11675
11712
|
throw new Error("costs.groups must be a mapping of group \u2192 { workers, containerApps }");
|
|
11676
11713
|
const groups = {};
|
|
@@ -11693,6 +11730,7 @@ function parseCostsConfig(raw) {
|
|
|
11693
11730
|
}
|
|
11694
11731
|
return {
|
|
11695
11732
|
cloudflareAccountId: r.cloudflareAccountId,
|
|
11733
|
+
...typeof r.cloudflareAccountName === "string" && r.cloudflareAccountName ? { cloudflareAccountName: r.cloudflareAccountName } : {},
|
|
11696
11734
|
cloudflareTokenEnv: typeof r.cloudflareTokenEnv === "string" ? r.cloudflareTokenEnv : DEFAULT_CF_TOKEN_ENV,
|
|
11697
11735
|
anthropicAdminKeyEnv: typeof r.anthropicAdminKeyEnv === "string" ? r.anthropicAdminKeyEnv : DEFAULT_ANTHROPIC_ADMIN_ENV,
|
|
11698
11736
|
groups
|
|
@@ -11772,7 +11810,7 @@ function eachDay(range) {
|
|
|
11772
11810
|
for (let d = range.from; d <= range.to; d = addDays2(d, 1)) out.push(d);
|
|
11773
11811
|
return out;
|
|
11774
11812
|
}
|
|
11775
|
-
function buildCostReport(group, cfg, usage, llm, range) {
|
|
11813
|
+
function buildCostReport(group, cfg, usage, llm, range, meta) {
|
|
11776
11814
|
const attribution = attributionOf(cfg, usage);
|
|
11777
11815
|
const workers = new Set(cfg.workers);
|
|
11778
11816
|
const namespaces = attribution.durableObjectNamespaces;
|
|
@@ -11890,7 +11928,12 @@ function buildCostReport(group, cfg, usage, llm, range) {
|
|
|
11890
11928
|
llmAvailable: llm !== null && !!cfg.anthropicWorkspaceId,
|
|
11891
11929
|
days,
|
|
11892
11930
|
totals: { cloudUsd, llmUsd, total: cloudUsd + llmUsd, byResource },
|
|
11893
|
-
|
|
11931
|
+
generatedAt: meta.generatedAt ?? systemClock(),
|
|
11932
|
+
account: {
|
|
11933
|
+
id: meta.accountId,
|
|
11934
|
+
...meta.accountName ? { name: meta.accountName } : {},
|
|
11935
|
+
cloudUsd: accountCloudUsd
|
|
11936
|
+
},
|
|
11894
11937
|
attribution
|
|
11895
11938
|
};
|
|
11896
11939
|
}
|
|
@@ -11931,9 +11974,14 @@ function createCostsService(cfg, cloudflare, llm, now = () => new Date(systemClo
|
|
|
11931
11974
|
async report(group, daysParam) {
|
|
11932
11975
|
const g = cfg.groups[group];
|
|
11933
11976
|
if (!g) throw new Error(`unknown cost group ${group}`);
|
|
11934
|
-
const
|
|
11977
|
+
const at = now();
|
|
11978
|
+
const range = resolveRange(daysParam, at);
|
|
11935
11979
|
const [usage, llmRows] = await Promise.all([cloudflare.fetchUsage(range), llm.fetchDailyCost(range)]);
|
|
11936
|
-
return buildCostReport(group, g, usage, llmRows, range
|
|
11980
|
+
return buildCostReport(group, g, usage, llmRows, range, {
|
|
11981
|
+
accountId: cfg.cloudflareAccountId,
|
|
11982
|
+
accountName: cfg.cloudflareAccountName,
|
|
11983
|
+
generatedAt: at.getTime()
|
|
11984
|
+
});
|
|
11937
11985
|
}
|
|
11938
11986
|
};
|
|
11939
11987
|
}
|
|
@@ -16685,7 +16733,7 @@ var init_connect = __esm({
|
|
|
16685
16733
|
|
|
16686
16734
|
// ../../src/mcp/types.ts
|
|
16687
16735
|
var McpError;
|
|
16688
|
-
var
|
|
16736
|
+
var init_types3 = __esm({
|
|
16689
16737
|
"../../src/mcp/types.ts"() {
|
|
16690
16738
|
"use strict";
|
|
16691
16739
|
McpError = class extends Error {
|
|
@@ -16780,7 +16828,7 @@ var MCP_PROTOCOL_VERSION, MCP_REQUEST_TIMEOUT_MS, MCP_MAX_RESPONSE_BYTES, MCP_MA
|
|
|
16780
16828
|
var init_client = __esm({
|
|
16781
16829
|
"../../src/mcp/client.ts"() {
|
|
16782
16830
|
"use strict";
|
|
16783
|
-
|
|
16831
|
+
init_types3();
|
|
16784
16832
|
MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
16785
16833
|
MCP_REQUEST_TIMEOUT_MS = 3e4;
|
|
16786
16834
|
MCP_MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
@@ -17495,7 +17543,7 @@ var init_bridge = __esm({
|
|
|
17495
17543
|
"../../src/mcp/bridge.ts"() {
|
|
17496
17544
|
"use strict";
|
|
17497
17545
|
init_commandRegistry();
|
|
17498
|
-
|
|
17546
|
+
init_types3();
|
|
17499
17547
|
init_classify();
|
|
17500
17548
|
MCP_TOOL_NAME_MAX = 64;
|
|
17501
17549
|
MCP_TOOL_PREFIX = "mcp__";
|
|
@@ -18527,40 +18575,6 @@ var init_mcp = __esm({
|
|
|
18527
18575
|
}
|
|
18528
18576
|
});
|
|
18529
18577
|
|
|
18530
|
-
// ../../src/providers/types.ts
|
|
18531
|
-
function toolResultText(content) {
|
|
18532
|
-
if (typeof content === "string") return content;
|
|
18533
|
-
return content.map((p) => {
|
|
18534
|
-
if (p.type === "text") return p.text;
|
|
18535
|
-
if (p.type === "image") return `[image ${p.mediaType}, ${base64Bytes(p.data)} bytes]`;
|
|
18536
|
-
return `[document ${p.name ?? "document"} (${p.mediaType}), ${base64Bytes(p.data)} bytes]`;
|
|
18537
|
-
}).join("\n");
|
|
18538
|
-
}
|
|
18539
|
-
function capToolResultContent(content, cap = MAX_TOOL_RESULT_CHARS) {
|
|
18540
|
-
const capText = (text) => text.length > cap ? `${text.slice(0, cap)}
|
|
18541
|
-
\u2026[tool result truncated: ${text.length - cap} of ${text.length} characters cut \u2014 ask for a narrower slice]` : text;
|
|
18542
|
-
if (typeof content === "string") return capText(content);
|
|
18543
|
-
return content.map((p) => p.type === "text" ? { ...p, text: capText(p.text) } : p);
|
|
18544
|
-
}
|
|
18545
|
-
function base64Bytes(b64) {
|
|
18546
|
-
const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
|
|
18547
|
-
return Math.floor(b64.length * 3 / 4) - padding;
|
|
18548
|
-
}
|
|
18549
|
-
function parseModelRef(ref) {
|
|
18550
|
-
const i = ref.indexOf("/");
|
|
18551
|
-
if (i === -1) {
|
|
18552
|
-
throw new Error(`Model "${ref}" must be qualified as "<provider>/<model>", e.g. "anthropic/claude-opus-5"`);
|
|
18553
|
-
}
|
|
18554
|
-
return { provider: ref.slice(0, i), model: ref.slice(i + 1) };
|
|
18555
|
-
}
|
|
18556
|
-
var MAX_TOOL_RESULT_CHARS;
|
|
18557
|
-
var init_types3 = __esm({
|
|
18558
|
-
"../../src/providers/types.ts"() {
|
|
18559
|
-
"use strict";
|
|
18560
|
-
MAX_TOOL_RESULT_CHARS = 12e4;
|
|
18561
|
-
}
|
|
18562
|
-
});
|
|
18563
|
-
|
|
18564
18578
|
// ../../src/core/memory/scorer.ts
|
|
18565
18579
|
function tokenize2(text) {
|
|
18566
18580
|
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
@@ -19383,7 +19397,7 @@ async function memoryContextBlock(organization, cfg, injected, query, userId, sc
|
|
|
19383
19397
|
var init_memory = __esm({
|
|
19384
19398
|
"../../src/core/memory/index.ts"() {
|
|
19385
19399
|
"use strict";
|
|
19386
|
-
|
|
19400
|
+
init_types2();
|
|
19387
19401
|
init_scorer();
|
|
19388
19402
|
init_scope();
|
|
19389
19403
|
init_stores();
|
|
@@ -22578,7 +22592,9 @@ function afterReply(deps, ctx) {
|
|
|
22578
22592
|
scheduleReflection({
|
|
22579
22593
|
cfg: deps.config.config.memory,
|
|
22580
22594
|
store: deps.memory,
|
|
22581
|
-
|
|
22595
|
+
// The extractor's one call goes through pi's model library
|
|
22596
|
+
// (harness-pi.md item 13), never the loop's own provider adapters.
|
|
22597
|
+
providers: deps.completions,
|
|
22582
22598
|
runModelRef: resolved.modelRef,
|
|
22583
22599
|
gate: { toolCalls, historyTurns: history.length, agentName: resolved.agentName },
|
|
22584
22600
|
threadKey: msg.threadKey,
|
|
@@ -25123,7 +25139,7 @@ var init_resolve = __esm({
|
|
|
25123
25139
|
init_registry();
|
|
25124
25140
|
init_profile();
|
|
25125
25141
|
init_directives();
|
|
25126
|
-
|
|
25142
|
+
init_types2();
|
|
25127
25143
|
init_factory();
|
|
25128
25144
|
init_githubRepoProbe();
|
|
25129
25145
|
init_repoContext();
|
|
@@ -28206,7 +28222,7 @@ async function routeRequest(deps, ctx) {
|
|
|
28206
28222
|
if (deps.routeModel) model = deps.routeModel;
|
|
28207
28223
|
else {
|
|
28208
28224
|
const ref = parseModelRef(modelRef2);
|
|
28209
|
-
model = providerRouteModel(deps.
|
|
28225
|
+
model = providerRouteModel(deps.completions.get(ref.provider), ref.model, {
|
|
28210
28226
|
...cfg.routing?.answer ? { answer: cfg.routing.answer } : {}
|
|
28211
28227
|
});
|
|
28212
28228
|
}
|
|
@@ -28276,7 +28292,7 @@ var init_route = __esm({
|
|
|
28276
28292
|
init_registry();
|
|
28277
28293
|
init_workspace();
|
|
28278
28294
|
init_config2();
|
|
28279
|
-
|
|
28295
|
+
init_types2();
|
|
28280
28296
|
init_redact();
|
|
28281
28297
|
init_statusCardFrame();
|
|
28282
28298
|
init_spawn();
|
|
@@ -28883,7 +28899,7 @@ var MAX_CONSECUTIVE_INFRA_FAILURES, HardStopError, HARD_STOP_MESSAGE, wrapUpNote
|
|
|
28883
28899
|
var init_runner = __esm({
|
|
28884
28900
|
"../../src/runner.ts"() {
|
|
28885
28901
|
"use strict";
|
|
28886
|
-
|
|
28902
|
+
init_types2();
|
|
28887
28903
|
init_runEvents();
|
|
28888
28904
|
init_threadAdmission();
|
|
28889
28905
|
init_executor();
|
|
@@ -30673,7 +30689,7 @@ var init_provision = __esm({
|
|
|
30673
30689
|
init_resident();
|
|
30674
30690
|
init_memory();
|
|
30675
30691
|
init_runBearers();
|
|
30676
|
-
|
|
30692
|
+
init_types2();
|
|
30677
30693
|
init_skills2();
|
|
30678
30694
|
init_source();
|
|
30679
30695
|
init_configAwareness();
|
|
@@ -31681,7 +31697,7 @@ var init_bridge2 = __esm({
|
|
|
31681
31697
|
return this.answerText ?? this.heldAnswer;
|
|
31682
31698
|
}
|
|
31683
31699
|
observe(event) {
|
|
31684
|
-
const out = { replies: [], settled: false
|
|
31700
|
+
const out = { replies: [], settled: false };
|
|
31685
31701
|
const disposition = PI_EVENT_DISPOSITION[event.type];
|
|
31686
31702
|
if (disposition === void 0) {
|
|
31687
31703
|
this.note("harness_error", `pi emitted an event kind this build does not know: ${redactAndCap(event.type, 80)}`);
|
|
@@ -31698,9 +31714,6 @@ var init_bridge2 = __esm({
|
|
|
31698
31714
|
case "agent_settled":
|
|
31699
31715
|
out.settled = true;
|
|
31700
31716
|
break;
|
|
31701
|
-
case "turn_end":
|
|
31702
|
-
out.turnEnded = true;
|
|
31703
|
-
break;
|
|
31704
31717
|
case "message_start":
|
|
31705
31718
|
if (isRecord3(event.message) && event.message.role === "assistant") this.assistantStartedAt = this.deps.clock();
|
|
31706
31719
|
break;
|
|
@@ -31893,6 +31906,7 @@ var init_bridge2 = __esm({
|
|
|
31893
31906
|
});
|
|
31894
31907
|
|
|
31895
31908
|
// ../../src/core/harness/pi/mirror.ts
|
|
31909
|
+
import { isDeepStrictEqual } from "node:util";
|
|
31896
31910
|
function partsOf2(content) {
|
|
31897
31911
|
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
31898
31912
|
if (!Array.isArray(content)) return [];
|
|
@@ -32042,11 +32056,14 @@ var init_mirror = __esm({
|
|
|
32042
32056
|
constructor(deps) {
|
|
32043
32057
|
this.deps = deps;
|
|
32044
32058
|
this.idx = deps.seedLength;
|
|
32059
|
+
this.mirroredTail = deps.mirroredTail;
|
|
32045
32060
|
}
|
|
32046
32061
|
deps;
|
|
32047
32062
|
idx;
|
|
32048
32063
|
pendingUser = [];
|
|
32049
|
-
|
|
32064
|
+
/** pi is about to echo the seed's prompt as a user message (see `expectSeedEcho`). */
|
|
32065
|
+
seedEchoPending = false;
|
|
32066
|
+
mirroredTail;
|
|
32050
32067
|
iteration = 0;
|
|
32051
32068
|
/** The highest ledger inbox seq folded in so far (run-history item 40). */
|
|
32052
32069
|
inboxConsumedSeq = 0;
|
|
@@ -32054,19 +32071,43 @@ var init_mirror = __esm({
|
|
|
32054
32071
|
get wired() {
|
|
32055
32072
|
return this.deps.onStep !== void 0;
|
|
32056
32073
|
}
|
|
32074
|
+
/** pi answered the seed's prompt: the first user message without results
|
|
32075
|
+
* that follows is its echo — the seed, on the ledger already — and is not
|
|
32076
|
+
* written twice. A continue prompt (harness-pi item 8) expects none: its
|
|
32077
|
+
* echo is a turn the model was told, folded in like a steer's text. */
|
|
32078
|
+
expectSeedEcho() {
|
|
32079
|
+
this.seedEchoPending = true;
|
|
32080
|
+
}
|
|
32081
|
+
/** The row about to be written, against the transcript's tail — compared
|
|
32082
|
+
* once, with the first row the mirror meets: equal means the ledger holds
|
|
32083
|
+
* it already (read again, harness-pi item 8), together with the results
|
|
32084
|
+
* pending before it, which were its step's user turn. */
|
|
32085
|
+
alreadyHeld(row) {
|
|
32086
|
+
const tail = this.mirroredTail;
|
|
32087
|
+
if (tail === void 0) return false;
|
|
32088
|
+
this.mirroredTail = void 0;
|
|
32089
|
+
if (!isDeepStrictEqual(row, tail)) return false;
|
|
32090
|
+
this.pendingUser = [];
|
|
32091
|
+
return true;
|
|
32092
|
+
}
|
|
32093
|
+
/** Feeds one finished message; answers whether the ledger now holds
|
|
32094
|
+
* everything up to it — a step written, or an assistant turn found already
|
|
32095
|
+
* there — so the harness can move the row's offset past it. A result or a
|
|
32096
|
+
* steer's text waits in memory for the next step, and the answer is no. */
|
|
32057
32097
|
async onMessage(message3, turn) {
|
|
32058
|
-
if (!this.deps.onStep) return;
|
|
32098
|
+
if (!this.deps.onStep) return false;
|
|
32059
32099
|
const chat = chatMessageOf(message3);
|
|
32060
|
-
if (!chat) return;
|
|
32061
|
-
if (chat.content.length === 0) return;
|
|
32100
|
+
if (!chat) return false;
|
|
32101
|
+
if (chat.content.length === 0) return false;
|
|
32062
32102
|
if (chat.role === "user") {
|
|
32063
|
-
if (
|
|
32064
|
-
this.
|
|
32065
|
-
return;
|
|
32103
|
+
if (this.seedEchoPending && !chat.content.some((p) => p.type === "tool_result")) {
|
|
32104
|
+
this.seedEchoPending = false;
|
|
32105
|
+
return false;
|
|
32066
32106
|
}
|
|
32067
32107
|
this.pendingUser.push(...chat.content);
|
|
32068
|
-
return;
|
|
32108
|
+
return false;
|
|
32069
32109
|
}
|
|
32110
|
+
if (this.alreadyHeld({ turn: chat })) return true;
|
|
32070
32111
|
const turns = [];
|
|
32071
32112
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32072
32113
|
this.pendingUser = [];
|
|
@@ -32083,13 +32124,16 @@ var init_mirror = __esm({
|
|
|
32083
32124
|
};
|
|
32084
32125
|
this.idx += turns.length;
|
|
32085
32126
|
await this.deps.onStep(report2);
|
|
32127
|
+
return true;
|
|
32086
32128
|
}
|
|
32087
32129
|
/** pi compacted (session-log item 6): the results pending since the last
|
|
32088
32130
|
* assistant turn go as the user turn they would have been, the entry as the
|
|
32089
32131
|
* row after them — its own step with nothing in flight, so the log holds
|
|
32090
|
-
* the summary where pi wrote it and the index moves past it.
|
|
32132
|
+
* the summary where pi wrote it and the index moves past it. Answers as
|
|
32133
|
+
* `onMessage` does: the ledger holds everything up to the entry. */
|
|
32091
32134
|
async onCompaction(entry, turn) {
|
|
32092
|
-
if (!this.deps.onStep) return;
|
|
32135
|
+
if (!this.deps.onStep) return false;
|
|
32136
|
+
if (this.alreadyHeld({ compaction: entry })) return true;
|
|
32093
32137
|
const turns = [];
|
|
32094
32138
|
if (this.pendingUser.length > 0) turns.push({ role: "user", content: this.pendingUser });
|
|
32095
32139
|
this.pendingUser = [];
|
|
@@ -32105,6 +32149,7 @@ var init_mirror = __esm({
|
|
|
32105
32149
|
};
|
|
32106
32150
|
this.idx += turns.length + 1;
|
|
32107
32151
|
await this.deps.onStep(report2);
|
|
32152
|
+
return true;
|
|
32108
32153
|
}
|
|
32109
32154
|
};
|
|
32110
32155
|
}
|
|
@@ -32121,11 +32166,16 @@ var init_transport = __esm({
|
|
|
32121
32166
|
constructor(deps) {
|
|
32122
32167
|
this.deps = deps;
|
|
32123
32168
|
this.offset = deps.offset ?? 0;
|
|
32169
|
+
this.consumedOffset = this.offset;
|
|
32124
32170
|
this.lines = this.read();
|
|
32125
32171
|
}
|
|
32126
32172
|
deps;
|
|
32127
|
-
/** The byte the next read starts at
|
|
32173
|
+
/** The byte the next read starts at: the read position, moved by whole chunks. */
|
|
32128
32174
|
offset;
|
|
32175
|
+
/** The boundary after the record last handed out, moved by records: where a
|
|
32176
|
+
* reader that has seen everything so far continues from — the harness's
|
|
32177
|
+
* re-attach fact, taken when nothing handed out is left unwritten. */
|
|
32178
|
+
consumedOffset;
|
|
32129
32179
|
/** pi was found dead while the harness still listened. */
|
|
32130
32180
|
exited = false;
|
|
32131
32181
|
closed = false;
|
|
@@ -32178,11 +32228,15 @@ var init_transport = __esm({
|
|
|
32178
32228
|
/** Complete lines out of the buffered bytes; the partial tail waits for more. */
|
|
32179
32229
|
*split(chunk) {
|
|
32180
32230
|
this.buffer = Buffer.concat([this.buffer, Buffer.from(chunk)]);
|
|
32231
|
+
const base = this.offset - this.buffer.length;
|
|
32181
32232
|
let start3 = 0;
|
|
32182
32233
|
for (let i = this.buffer.indexOf(NEWLINE, start3); i >= 0; i = this.buffer.indexOf(NEWLINE, start3)) {
|
|
32183
32234
|
let line3 = this.buffer.subarray(start3, i).toString("utf8");
|
|
32184
32235
|
if (line3.endsWith("\r")) line3 = line3.slice(0, -1);
|
|
32185
|
-
if (line3.length > 0)
|
|
32236
|
+
if (line3.length > 0) {
|
|
32237
|
+
this.consumedOffset = base + i + 1;
|
|
32238
|
+
yield line3;
|
|
32239
|
+
}
|
|
32186
32240
|
start3 = i + 1;
|
|
32187
32241
|
}
|
|
32188
32242
|
this.buffer = this.buffer.subarray(start3);
|
|
@@ -32192,6 +32246,7 @@ var init_transport = __esm({
|
|
|
32192
32246
|
});
|
|
32193
32247
|
|
|
32194
32248
|
// ../../src/core/harness/pi/harness.ts
|
|
32249
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
32195
32250
|
function piHarnessFactsOf(value) {
|
|
32196
32251
|
if (typeof value !== "object" || value === null) return void 0;
|
|
32197
32252
|
const v = value;
|
|
@@ -32252,6 +32307,13 @@ function settlementResults(settlements) {
|
|
|
32252
32307
|
}))
|
|
32253
32308
|
};
|
|
32254
32309
|
}
|
|
32310
|
+
function ledgerTailOf(resume) {
|
|
32311
|
+
if (!resume) return void 0;
|
|
32312
|
+
const closing = resume.compactions?.filter((c) => c.before === resume.messages.length).at(-1);
|
|
32313
|
+
if (closing) return { compaction: closing.entry };
|
|
32314
|
+
const last = resume.messages.at(-1);
|
|
32315
|
+
return last?.role === "assistant" ? { turn: last } : void 0;
|
|
32316
|
+
}
|
|
32255
32317
|
function settlementAnswer(s) {
|
|
32256
32318
|
return { content: [{ type: "text", text: settlementText(s) }], isError: true };
|
|
32257
32319
|
}
|
|
@@ -32296,10 +32358,12 @@ async function runPiHarness(deps, run2) {
|
|
|
32296
32358
|
};
|
|
32297
32359
|
}
|
|
32298
32360
|
bridge.turns = run2.resume?.turn ?? 0;
|
|
32361
|
+
const tail = ledgerTailOf(run2.resume);
|
|
32299
32362
|
const mirror = new PiMirror({
|
|
32300
32363
|
onStep: run2.onStep,
|
|
32301
|
-
seedLength: run2.resume
|
|
32302
|
-
remainingMs: () => deadline - now()
|
|
32364
|
+
seedLength: run2.resume ? run2.resume.messages.length + (run2.resume.compactions?.length ?? 0) : run2.messages.length,
|
|
32365
|
+
remainingMs: () => deadline - now(),
|
|
32366
|
+
...tail ? { mirroredTail: tail } : {}
|
|
32303
32367
|
});
|
|
32304
32368
|
mirror.inboxConsumedSeq = run2.resume?.inboxConsumedSeq ?? 0;
|
|
32305
32369
|
let writeUp;
|
|
@@ -32336,12 +32400,17 @@ async function runPiHarness(deps, run2) {
|
|
|
32336
32400
|
let pid;
|
|
32337
32401
|
let transport;
|
|
32338
32402
|
let facts2;
|
|
32403
|
+
let mirrored = 0;
|
|
32339
32404
|
const save = () => {
|
|
32340
32405
|
if (facts2) {
|
|
32341
|
-
|
|
32406
|
+
facts2 = { ...facts2, logOffset: mirrored };
|
|
32342
32407
|
run2.saveFacts?.(facts2);
|
|
32343
32408
|
}
|
|
32344
32409
|
};
|
|
32410
|
+
const held = () => {
|
|
32411
|
+
if (transport) mirrored = transport.consumedOffset;
|
|
32412
|
+
save();
|
|
32413
|
+
};
|
|
32345
32414
|
let catchingUp = false;
|
|
32346
32415
|
try {
|
|
32347
32416
|
const recorded = run2.resume?.facts;
|
|
@@ -32368,13 +32437,14 @@ async function runPiHarness(deps, run2) {
|
|
|
32368
32437
|
if (reattached && recorded && paths !== void 0) {
|
|
32369
32438
|
pid = recorded.pid;
|
|
32370
32439
|
facts2 = { ...recorded, ...recorded.container === void 0 && here !== void 0 ? { container: here } : {} };
|
|
32440
|
+
mirrored = recorded.logOffset;
|
|
32371
32441
|
transport = new PiRpcTransport({
|
|
32372
32442
|
container,
|
|
32373
32443
|
paths,
|
|
32374
32444
|
pid,
|
|
32375
32445
|
pollMs: deps.pollMs ?? 750,
|
|
32376
32446
|
sleep: deps.sleep,
|
|
32377
|
-
offset:
|
|
32447
|
+
offset: mirrored
|
|
32378
32448
|
});
|
|
32379
32449
|
catchingUp = true;
|
|
32380
32450
|
const inFlight = run2.resume?.settlements.length ?? 0;
|
|
@@ -32452,12 +32522,15 @@ async function runPiHarness(deps, run2) {
|
|
|
32452
32522
|
save();
|
|
32453
32523
|
transport = new PiRpcTransport({ container, paths, pid, pollMs: deps.pollMs ?? 750, sleep: deps.sleep });
|
|
32454
32524
|
}
|
|
32455
|
-
|
|
32456
|
-
|
|
32525
|
+
const stamp = `${now()}-${randomUUID2().slice(0, 8)}`;
|
|
32526
|
+
const ids = { retry: `retry:${stamp}`, state: `state:${stamp}`, prompt: `prompt:${stamp}` };
|
|
32527
|
+
const continuing = reattached || run2.resume !== void 0;
|
|
32528
|
+
transport.send({ id: ids.retry, type: "set_auto_retry", enabled: false });
|
|
32529
|
+
transport.send({ id: ids.state, type: "get_state" });
|
|
32457
32530
|
if (reattached)
|
|
32458
|
-
transport.send({ id:
|
|
32459
|
-
else if (run2.resume) transport.send({ id:
|
|
32460
|
-
else transport.send({ id:
|
|
32531
|
+
transport.send({ id: ids.prompt, type: "prompt", message: CONTINUE_PROMPT, streamingBehavior: "steer" });
|
|
32532
|
+
else if (run2.resume) transport.send({ id: ids.prompt, type: "prompt", message: CONTINUE_PROMPT });
|
|
32533
|
+
else transport.send({ id: ids.prompt, type: "prompt", ...promptOf(run2.messages) });
|
|
32461
32534
|
let warned = false;
|
|
32462
32535
|
let settled = false;
|
|
32463
32536
|
let stopMode;
|
|
@@ -32575,19 +32648,20 @@ ${stagedLine}` : prompt,
|
|
|
32575
32648
|
}
|
|
32576
32649
|
if (obs.response) {
|
|
32577
32650
|
const r = obs.response;
|
|
32578
|
-
if (r.id ===
|
|
32651
|
+
if (r.id === ids.state && r.success === true && typeof r.data?.sessionFile === "string") {
|
|
32579
32652
|
const data = r.data;
|
|
32580
32653
|
facts2 = { ...facts2 ?? { pid, logOffset: 0, root: paths.dir }, sessionFile: String(data.sessionFile) };
|
|
32581
32654
|
save();
|
|
32582
32655
|
}
|
|
32583
|
-
if (r.id ===
|
|
32656
|
+
if (r.id === ids.prompt) {
|
|
32584
32657
|
catchingUp = false;
|
|
32585
32658
|
if (r.success === false) throw new PromptRefused(String(r.error ?? "no reason"));
|
|
32659
|
+
if (!continuing) mirror.expectSeedEcho();
|
|
32586
32660
|
}
|
|
32587
32661
|
}
|
|
32588
|
-
if (obs.message
|
|
32662
|
+
if (obs.message && await mirror.onMessage(obs.message, bridge.turns)) held();
|
|
32589
32663
|
if (obs.compaction) {
|
|
32590
|
-
await mirror.onCompaction(obs.compaction, bridge.turns);
|
|
32664
|
+
if (await mirror.onCompaction(obs.compaction, bridge.turns)) held();
|
|
32591
32665
|
if (!writeUp && !hardStopped && !catchingUp) {
|
|
32592
32666
|
let notepad;
|
|
32593
32667
|
let unavailable = false;
|
|
@@ -32608,7 +32682,6 @@ ${stagedLine}` : prompt,
|
|
|
32608
32682
|
note("harness_error", `a model call failed while the bot was away (${obs.providerError}); continuing`);
|
|
32609
32683
|
else providerError = obs.providerError;
|
|
32610
32684
|
}
|
|
32611
|
-
if (obs.turnEnded) save();
|
|
32612
32685
|
if (obs.settled && !catchingUp) {
|
|
32613
32686
|
settled = true;
|
|
32614
32687
|
break;
|
|
@@ -32622,8 +32695,8 @@ ${stagedLine}` : prompt,
|
|
|
32622
32695
|
}
|
|
32623
32696
|
if (bypass) throw bypass;
|
|
32624
32697
|
if (!settled) {
|
|
32625
|
-
const
|
|
32626
|
-
throw new Error(`pi exited before the run settled${
|
|
32698
|
+
const tail2 = await container.tail(paths.errLog, 2e3);
|
|
32699
|
+
throw new Error(`pi exited before the run settled${tail2.trim() ? `: ${redactAndCap(tail2.trim(), 400)}` : ""}`);
|
|
32627
32700
|
}
|
|
32628
32701
|
if (providerError !== void 0) throw new Error(`the model call failed: ${providerError}`);
|
|
32629
32702
|
const text = bridge.answer() ?? "";
|
|
@@ -33949,7 +34022,7 @@ var init_runLoop = __esm({
|
|
|
33949
34022
|
"use strict";
|
|
33950
34023
|
init_profile();
|
|
33951
34024
|
init_runner();
|
|
33952
|
-
|
|
34025
|
+
init_types2();
|
|
33953
34026
|
init_workspace();
|
|
33954
34027
|
init_select();
|
|
33955
34028
|
init_botHostContainer();
|
|
@@ -36787,8 +36860,8 @@ var init_types5 = __esm({
|
|
|
36787
36860
|
});
|
|
36788
36861
|
|
|
36789
36862
|
// ../../src/core/runLedger/writeThrough.ts
|
|
36790
|
-
import { randomUUID as
|
|
36791
|
-
function mintGeneration(now = Date.now, random =
|
|
36863
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
36864
|
+
function mintGeneration(now = Date.now, random = randomUUID3) {
|
|
36792
36865
|
const stamp = new Date(now()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
36793
36866
|
const gen = `${stamp}-${random().replace(/-/g, "").slice(0, 8)}`;
|
|
36794
36867
|
if (!GEN_PATTERN.test(gen)) throw new Error(`minted generation ${gen} does not match GEN_PATTERN`);
|
|
@@ -37510,7 +37583,7 @@ var OpenAICompatProvider;
|
|
|
37510
37583
|
var init_openaiCompat = __esm({
|
|
37511
37584
|
"../../src/providers/openaiCompat.ts"() {
|
|
37512
37585
|
"use strict";
|
|
37513
|
-
|
|
37586
|
+
init_types2();
|
|
37514
37587
|
init_secrets2();
|
|
37515
37588
|
OpenAICompatProvider = class {
|
|
37516
37589
|
name;
|
|
@@ -37618,6 +37691,241 @@ var init_registry3 = __esm({
|
|
|
37618
37691
|
}
|
|
37619
37692
|
});
|
|
37620
37693
|
|
|
37694
|
+
// ../../src/core/harness/piAi.ts
|
|
37695
|
+
import { anthropicMessagesApi } from "@earendil-works/pi-ai/api/anthropic-messages.lazy";
|
|
37696
|
+
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
37697
|
+
function piApiFor(type) {
|
|
37698
|
+
return type === "anthropic" ? "anthropic-messages" : "openai-completions";
|
|
37699
|
+
}
|
|
37700
|
+
function piStreamOptions(api, req, key) {
|
|
37701
|
+
const shared = {
|
|
37702
|
+
...key !== void 0 ? { apiKey: key } : { apiKey: "unused", headers: { Authorization: null } },
|
|
37703
|
+
maxTokens: req.maxTokens,
|
|
37704
|
+
...req.signal ? { signal: req.signal } : {},
|
|
37705
|
+
cacheRetention: req.cacheTtl === "1h" ? "long" : "short"
|
|
37706
|
+
};
|
|
37707
|
+
if (!req.toolChoice) return shared;
|
|
37708
|
+
return api === "anthropic-messages" ? { ...shared, toolChoice: { type: "tool", name: req.toolChoice.name } } : { ...shared, toolChoice: { type: "function", function: { name: req.toolChoice.name } } };
|
|
37709
|
+
}
|
|
37710
|
+
function toPiContext(req, model, clock3) {
|
|
37711
|
+
const callNames = /* @__PURE__ */ new Map();
|
|
37712
|
+
const messages = [];
|
|
37713
|
+
for (const turn of req.messages) {
|
|
37714
|
+
if (turn.role === "assistant") {
|
|
37715
|
+
for (const part of turn.content) if (part.type === "tool_use") callNames.set(part.id, part.name);
|
|
37716
|
+
messages.push(assistantMessage(turn, model, clock3()));
|
|
37717
|
+
} else {
|
|
37718
|
+
messages.push(...userMessages(turn, callNames, clock3()));
|
|
37719
|
+
}
|
|
37720
|
+
}
|
|
37721
|
+
const tools = req.tools?.map((t) => ({
|
|
37722
|
+
name: t.name,
|
|
37723
|
+
description: t.description,
|
|
37724
|
+
parameters: t.inputSchema
|
|
37725
|
+
}));
|
|
37726
|
+
return {
|
|
37727
|
+
...req.system !== void 0 ? { systemPrompt: req.system } : {},
|
|
37728
|
+
messages,
|
|
37729
|
+
...tools && tools.length > 0 ? { tools } : {}
|
|
37730
|
+
};
|
|
37731
|
+
}
|
|
37732
|
+
function assistantMessage(turn, model, timestamp) {
|
|
37733
|
+
const content = [];
|
|
37734
|
+
for (const part of turn.content) {
|
|
37735
|
+
if (part.type === "text") content.push({ type: "text", text: part.text });
|
|
37736
|
+
else if (part.type === "tool_use")
|
|
37737
|
+
content.push({ type: "toolCall", id: part.id, name: part.name, arguments: argumentsOf(part.input) });
|
|
37738
|
+
else if (part.type === "thinking")
|
|
37739
|
+
content.push({ type: "thinking", thinking: part.thinking, thinkingSignature: part.signature });
|
|
37740
|
+
else if (part.type === "redacted_thinking")
|
|
37741
|
+
content.push({ type: "thinking", thinking: "", thinkingSignature: part.data, redacted: true });
|
|
37742
|
+
}
|
|
37743
|
+
return {
|
|
37744
|
+
role: "assistant",
|
|
37745
|
+
content,
|
|
37746
|
+
api: model.api,
|
|
37747
|
+
provider: model.provider,
|
|
37748
|
+
model: model.id,
|
|
37749
|
+
usage: { ...ZERO_USAGE, cost: { ...ZERO_USAGE.cost } },
|
|
37750
|
+
stopReason: content.some((p) => p.type === "toolCall") ? "toolUse" : "stop",
|
|
37751
|
+
timestamp
|
|
37752
|
+
};
|
|
37753
|
+
}
|
|
37754
|
+
function argumentsOf(input) {
|
|
37755
|
+
return typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
37756
|
+
}
|
|
37757
|
+
function userMessages(turn, callNames, timestamp) {
|
|
37758
|
+
const out = [];
|
|
37759
|
+
const rest = [];
|
|
37760
|
+
for (const part of turn.content) {
|
|
37761
|
+
if (part.type === "tool_result") {
|
|
37762
|
+
const result = {
|
|
37763
|
+
role: "toolResult",
|
|
37764
|
+
toolCallId: part.toolUseId,
|
|
37765
|
+
toolName: callNames.get(part.toolUseId) ?? part.toolUseId,
|
|
37766
|
+
content: toolResultParts(part.content),
|
|
37767
|
+
isError: part.isError === true,
|
|
37768
|
+
timestamp
|
|
37769
|
+
};
|
|
37770
|
+
out.push(result);
|
|
37771
|
+
} else {
|
|
37772
|
+
const visible = visiblePart(part);
|
|
37773
|
+
if (visible) rest.push(visible);
|
|
37774
|
+
}
|
|
37775
|
+
}
|
|
37776
|
+
if (rest.length > 0) out.push({ role: "user", content: rest, timestamp });
|
|
37777
|
+
return out;
|
|
37778
|
+
}
|
|
37779
|
+
function toolResultParts(content) {
|
|
37780
|
+
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
37781
|
+
return content.map((part) => visiblePart(part)).filter((p) => p !== void 0);
|
|
37782
|
+
}
|
|
37783
|
+
function visiblePart(part) {
|
|
37784
|
+
switch (part.type) {
|
|
37785
|
+
case "text":
|
|
37786
|
+
return { type: "text", text: part.text };
|
|
37787
|
+
case "image":
|
|
37788
|
+
return { type: "image", data: part.data, mimeType: part.mediaType };
|
|
37789
|
+
case "document":
|
|
37790
|
+
return {
|
|
37791
|
+
type: "text",
|
|
37792
|
+
text: `
|
|
37793
|
+
|
|
37794
|
+
[attached file: ${part.name ?? "document"} (${part.mediaType}); not supported by this provider]
|
|
37795
|
+
`
|
|
37796
|
+
};
|
|
37797
|
+
default:
|
|
37798
|
+
return void 0;
|
|
37799
|
+
}
|
|
37800
|
+
}
|
|
37801
|
+
function fromPiMessage(message3, provider) {
|
|
37802
|
+
if (message3.stopReason === "error" || message3.stopReason === "aborted") {
|
|
37803
|
+
throw new Error(`Provider "${provider}" (${message3.model}): ${message3.errorMessage ?? "the model call failed"}`);
|
|
37804
|
+
}
|
|
37805
|
+
const content = [];
|
|
37806
|
+
for (const part of message3.content) {
|
|
37807
|
+
if (part.type === "text") content.push({ type: "text", text: part.text });
|
|
37808
|
+
else if (part.type === "toolCall")
|
|
37809
|
+
content.push({ type: "tool_use", id: part.id, name: part.name, input: part.arguments });
|
|
37810
|
+
else if (part.type === "thinking") {
|
|
37811
|
+
content.push(
|
|
37812
|
+
part.redacted ? { type: "redacted_thinking", data: part.thinkingSignature ?? "" } : { type: "thinking", thinking: part.thinking, signature: part.thinkingSignature ?? "" }
|
|
37813
|
+
);
|
|
37814
|
+
}
|
|
37815
|
+
}
|
|
37816
|
+
return { content, stopReason: STOP_REASONS[message3.stopReason] ?? "other", usage: usageOf(message3.usage) };
|
|
37817
|
+
}
|
|
37818
|
+
function usageOf(usage) {
|
|
37819
|
+
return {
|
|
37820
|
+
inputTokens: usage.input,
|
|
37821
|
+
outputTokens: usage.output,
|
|
37822
|
+
cacheReadTokens: usage.cacheRead,
|
|
37823
|
+
cacheWriteTokens: usage.cacheWrite
|
|
37824
|
+
};
|
|
37825
|
+
}
|
|
37826
|
+
var ANTHROPIC_BASE_URL, ZERO_RATES, ZERO_USAGE, CONTEXT_WINDOW, PiAiProviders, PiAiProvider, STOP_REASONS;
|
|
37827
|
+
var init_piAi = __esm({
|
|
37828
|
+
"../../src/core/harness/piAi.ts"() {
|
|
37829
|
+
"use strict";
|
|
37830
|
+
init_types2();
|
|
37831
|
+
init_secrets2();
|
|
37832
|
+
init_clock();
|
|
37833
|
+
ANTHROPIC_BASE_URL = "https://api.anthropic.com";
|
|
37834
|
+
ZERO_RATES = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
37835
|
+
ZERO_USAGE = { ...ZERO_RATES, totalTokens: 0, cost: { ...ZERO_RATES, total: 0 } };
|
|
37836
|
+
CONTEXT_WINDOW = 2e5;
|
|
37837
|
+
PiAiProviders = class {
|
|
37838
|
+
providers = /* @__PURE__ */ new Map();
|
|
37839
|
+
constructor(configs, opts = {}) {
|
|
37840
|
+
for (const [name, cfg] of Object.entries(configs)) this.providers.set(name, new PiAiProvider(name, cfg, opts));
|
|
37841
|
+
}
|
|
37842
|
+
get(name) {
|
|
37843
|
+
const provider = this.providers.get(name);
|
|
37844
|
+
if (!provider) {
|
|
37845
|
+
throw new Error(`Unknown provider "${name}". Configured providers: ${[...this.providers.keys()].join(", ")}`);
|
|
37846
|
+
}
|
|
37847
|
+
return provider;
|
|
37848
|
+
}
|
|
37849
|
+
names() {
|
|
37850
|
+
return [...this.providers.keys()];
|
|
37851
|
+
}
|
|
37852
|
+
};
|
|
37853
|
+
PiAiProvider = class {
|
|
37854
|
+
name;
|
|
37855
|
+
api;
|
|
37856
|
+
baseUrl;
|
|
37857
|
+
keyEnv;
|
|
37858
|
+
secrets;
|
|
37859
|
+
clock;
|
|
37860
|
+
scripted;
|
|
37861
|
+
fetchImpl;
|
|
37862
|
+
streams;
|
|
37863
|
+
constructor(name, cfg, opts = {}) {
|
|
37864
|
+
this.name = name;
|
|
37865
|
+
this.api = piApiFor(cfg.type);
|
|
37866
|
+
if (cfg.type === "openai-compatible" && !cfg.baseUrl) {
|
|
37867
|
+
throw new Error(`Provider "${name}": openai-compatible providers require baseUrl`);
|
|
37868
|
+
}
|
|
37869
|
+
this.baseUrl = (cfg.baseUrl ?? ANTHROPIC_BASE_URL).replace(/\/+$/, "");
|
|
37870
|
+
this.keyEnv = cfg.apiKeyEnv ?? (cfg.type === "anthropic" ? ANTHROPIC_API_KEY_ENV : void 0);
|
|
37871
|
+
this.secrets = opts.secrets ?? processSecrets;
|
|
37872
|
+
this.clock = opts.clock ?? systemClock;
|
|
37873
|
+
this.scripted = opts.apis?.[this.api];
|
|
37874
|
+
this.fetchImpl = opts.fetch;
|
|
37875
|
+
}
|
|
37876
|
+
/** The model pi is handed for one request: the block as its provider, the
|
|
37877
|
+
* request's output cap as its own, no thinking (neither caller asks for
|
|
37878
|
+
* any), text and images in, the zero rate card. */
|
|
37879
|
+
model(id, maxTokens) {
|
|
37880
|
+
return {
|
|
37881
|
+
id,
|
|
37882
|
+
name: id,
|
|
37883
|
+
api: this.api,
|
|
37884
|
+
provider: this.name,
|
|
37885
|
+
baseUrl: this.baseUrl,
|
|
37886
|
+
reasoning: false,
|
|
37887
|
+
input: ["text", "image"],
|
|
37888
|
+
cost: { ...ZERO_RATES },
|
|
37889
|
+
contextWindow: CONTEXT_WINDOW,
|
|
37890
|
+
maxTokens
|
|
37891
|
+
};
|
|
37892
|
+
}
|
|
37893
|
+
/** One completion: the key revealed into pi's request options and nowhere
|
|
37894
|
+
* else, the request in pi's shape, pi's adapter on the wire, its final
|
|
37895
|
+
* message back in the vocabulary. A missing key fails here, by variable
|
|
37896
|
+
* name, before any request; a provider error or an abort is thrown with
|
|
37897
|
+
* pi's message — `route()` and `reflect()` catch either as they catch a
|
|
37898
|
+
* native adapter's throw. */
|
|
37899
|
+
async complete(req) {
|
|
37900
|
+
let key;
|
|
37901
|
+
if (this.keyEnv !== void 0) {
|
|
37902
|
+
const secret2 = this.secrets.named(this.keyEnv);
|
|
37903
|
+
if (!secret2) throw new Error(`Provider "${this.name}": ${this.keyEnv} is not set`);
|
|
37904
|
+
key = secret2.reveal();
|
|
37905
|
+
}
|
|
37906
|
+
const model = this.model(req.model, req.maxTokens);
|
|
37907
|
+
const options = {
|
|
37908
|
+
...piStreamOptions(this.api, req, key),
|
|
37909
|
+
...this.fetchImpl ? { fetch: this.fetchImpl } : {}
|
|
37910
|
+
};
|
|
37911
|
+
const message3 = await this.api$().stream(model, toPiContext(req, model, this.clock), options).result();
|
|
37912
|
+
return fromPiMessage(message3, this.name);
|
|
37913
|
+
}
|
|
37914
|
+
/** pi's implementation of this provider's API, loaded on the first call and
|
|
37915
|
+
* kept; a scripted one stands in for it in tests. */
|
|
37916
|
+
api$() {
|
|
37917
|
+
this.streams ??= this.scripted ?? (this.api === "anthropic-messages" ? anthropicMessagesApi() : openAICompletionsApi());
|
|
37918
|
+
return this.streams;
|
|
37919
|
+
}
|
|
37920
|
+
};
|
|
37921
|
+
STOP_REASONS = {
|
|
37922
|
+
stop: "end_turn",
|
|
37923
|
+
toolUse: "tool_use",
|
|
37924
|
+
length: "max_tokens"
|
|
37925
|
+
};
|
|
37926
|
+
}
|
|
37927
|
+
});
|
|
37928
|
+
|
|
37621
37929
|
// ../../src/mcp/secretStore.ts
|
|
37622
37930
|
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
37623
37931
|
import { dirname as dirname10, resolve as resolve10 } from "node:path";
|
|
@@ -37806,7 +38114,7 @@ var init_mcp2 = __esm({
|
|
|
37806
38114
|
init_sealed();
|
|
37807
38115
|
init_secretStore();
|
|
37808
38116
|
init_service();
|
|
37809
|
-
|
|
38117
|
+
init_types3();
|
|
37810
38118
|
init_registry2();
|
|
37811
38119
|
init_client();
|
|
37812
38120
|
init_fake();
|
|
@@ -39981,7 +40289,7 @@ var init_webShell = __esm({
|
|
|
39981
40289
|
init_favicon();
|
|
39982
40290
|
init_residentsModel();
|
|
39983
40291
|
init_webSeed();
|
|
39984
|
-
PAGE_CSP = "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'";
|
|
40292
|
+
PAGE_CSP = "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; media-src 'self'; font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'";
|
|
39985
40293
|
FORM_PAGE_CSP = PAGE_CSP.replace("form-action 'none'", "form-action 'self'");
|
|
39986
40294
|
WEB_HTML_HEADERS = {
|
|
39987
40295
|
"content-type": "text/html; charset=utf-8",
|
|
@@ -42714,6 +43022,7 @@ var init_modelProxy = __esm({
|
|
|
42714
43022
|
"use strict";
|
|
42715
43023
|
init_anthropic();
|
|
42716
43024
|
init_openaiCompat();
|
|
43025
|
+
init_types2();
|
|
42717
43026
|
init_http();
|
|
42718
43027
|
ANTHROPIC_MESSAGES_PATH = "/v1/messages";
|
|
42719
43028
|
OPENAI_CHAT_COMPLETIONS_PATH = "/v1/chat/completions";
|
|
@@ -43076,7 +43385,7 @@ var init_relay = __esm({
|
|
|
43076
43385
|
"../../src/core/harness/pi/relay.ts"() {
|
|
43077
43386
|
"use strict";
|
|
43078
43387
|
init_tracingExecutor();
|
|
43079
|
-
|
|
43388
|
+
init_types2();
|
|
43080
43389
|
init_awaitChildren();
|
|
43081
43390
|
init_runEvents();
|
|
43082
43391
|
init_toolRules();
|
|
@@ -44675,6 +44984,7 @@ async function runBot() {
|
|
|
44675
44984
|
});
|
|
44676
44985
|
console.log(`[capabilities] ${JSON.stringify(capabilities)}`);
|
|
44677
44986
|
const providers = new ProviderRegistry(config.config.providers);
|
|
44987
|
+
const completions = new PiAiProviders(config.config.providers);
|
|
44678
44988
|
const skills = new BundledSkillStore(DEFAULT_SKILLS_DIR);
|
|
44679
44989
|
let slackEmailLookup;
|
|
44680
44990
|
const mcpWiring = buildMcp(config, processSecrets, {
|
|
@@ -44782,6 +45092,7 @@ async function runBot() {
|
|
|
44782
45092
|
const deps = {
|
|
44783
45093
|
config,
|
|
44784
45094
|
providers,
|
|
45095
|
+
completions,
|
|
44785
45096
|
spanLog,
|
|
44786
45097
|
runBearers,
|
|
44787
45098
|
harness: {
|
|
@@ -45252,6 +45563,7 @@ var init_index = __esm({
|
|
|
45252
45563
|
init_config2();
|
|
45253
45564
|
init_capabilities();
|
|
45254
45565
|
init_registry3();
|
|
45566
|
+
init_piAi();
|
|
45255
45567
|
init_slack();
|
|
45256
45568
|
init_slackChannelDirectory();
|
|
45257
45569
|
init_http();
|
|
@@ -45370,6 +45682,7 @@ init_memory();
|
|
|
45370
45682
|
init_residentAdmin();
|
|
45371
45683
|
init_residentFleet();
|
|
45372
45684
|
init_registry3();
|
|
45685
|
+
init_piAi();
|
|
45373
45686
|
init_skills2();
|
|
45374
45687
|
init_mcp2();
|
|
45375
45688
|
init_source();
|
|
@@ -45697,6 +46010,7 @@ async function main() {
|
|
|
45697
46010
|
globalThis.console = new Console({ stdout: process.stderr, stderr: process.stderr });
|
|
45698
46011
|
const { config, runStore } = await bot();
|
|
45699
46012
|
const providers = new ProviderRegistry(config.config.providers);
|
|
46013
|
+
const completions = new PiAiProviders(config.config.providers);
|
|
45700
46014
|
const skills = new BundledSkillStore(DEFAULT_SKILLS_DIR);
|
|
45701
46015
|
const capabilities = capabilitiesFrom(config.config, publicEnv(), processSecrets, {
|
|
45702
46016
|
meatBinary: meatOnPath(publicEnv())
|
|
@@ -45713,6 +46027,7 @@ async function main() {
|
|
|
45713
46027
|
const deps = {
|
|
45714
46028
|
config,
|
|
45715
46029
|
providers,
|
|
46030
|
+
completions,
|
|
45716
46031
|
capabilities,
|
|
45717
46032
|
residentFleet,
|
|
45718
46033
|
...artifacts ? { artifacts } : {},
|