@coreplane/switchboard 1.224.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-BXwWQRJt.js → ResidentDetailPage-Cu4Ve2j4.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-CwVN-3tl.js → ResidentsIndexPage-_QIDVyOj.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-C0-RUb8o.js → RunRoutePage-DxgcHX-0.js} +5 -5
- package/dist/assets/web/dist/assets/{RunsIndexPage-Tx5P767G.js → RunsIndexPage-JQvnDmo0.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-C80zFu3G.js → ScheduledPage-DEVRWqZi.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-BaGkjYs1.js → StatusDot-BDAKF1Bp.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-BL-Cwe59.js → Tooltip-BFncyNUQ.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-DZgVjemt.js → dist-DJfQXPjH.js} +1 -1
- package/dist/assets/web/dist/assets/{main-BB6FMkeU.js → main-BjhiJxQq.js} +2 -2
- package/dist/assets/web/dist/assets/main-DymOuq2l.css +1 -0
- package/dist/cli.js +313 -55
- package/package.json +2 -1
- package/dist/assets/web/dist/assets/CostsPage-C-ximW1N.js +0 -2
- package/dist/assets/web/dist/assets/main-43n8Y5qO.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();
|
|
@@ -34006,7 +34022,7 @@ var init_runLoop = __esm({
|
|
|
34006
34022
|
"use strict";
|
|
34007
34023
|
init_profile();
|
|
34008
34024
|
init_runner();
|
|
34009
|
-
|
|
34025
|
+
init_types2();
|
|
34010
34026
|
init_workspace();
|
|
34011
34027
|
init_select();
|
|
34012
34028
|
init_botHostContainer();
|
|
@@ -37567,7 +37583,7 @@ var OpenAICompatProvider;
|
|
|
37567
37583
|
var init_openaiCompat = __esm({
|
|
37568
37584
|
"../../src/providers/openaiCompat.ts"() {
|
|
37569
37585
|
"use strict";
|
|
37570
|
-
|
|
37586
|
+
init_types2();
|
|
37571
37587
|
init_secrets2();
|
|
37572
37588
|
OpenAICompatProvider = class {
|
|
37573
37589
|
name;
|
|
@@ -37675,6 +37691,241 @@ var init_registry3 = __esm({
|
|
|
37675
37691
|
}
|
|
37676
37692
|
});
|
|
37677
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
|
+
|
|
37678
37929
|
// ../../src/mcp/secretStore.ts
|
|
37679
37930
|
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
37680
37931
|
import { dirname as dirname10, resolve as resolve10 } from "node:path";
|
|
@@ -37863,7 +38114,7 @@ var init_mcp2 = __esm({
|
|
|
37863
38114
|
init_sealed();
|
|
37864
38115
|
init_secretStore();
|
|
37865
38116
|
init_service();
|
|
37866
|
-
|
|
38117
|
+
init_types3();
|
|
37867
38118
|
init_registry2();
|
|
37868
38119
|
init_client();
|
|
37869
38120
|
init_fake();
|
|
@@ -40038,7 +40289,7 @@ var init_webShell = __esm({
|
|
|
40038
40289
|
init_favicon();
|
|
40039
40290
|
init_residentsModel();
|
|
40040
40291
|
init_webSeed();
|
|
40041
|
-
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'";
|
|
40042
40293
|
FORM_PAGE_CSP = PAGE_CSP.replace("form-action 'none'", "form-action 'self'");
|
|
40043
40294
|
WEB_HTML_HEADERS = {
|
|
40044
40295
|
"content-type": "text/html; charset=utf-8",
|
|
@@ -42771,6 +43022,7 @@ var init_modelProxy = __esm({
|
|
|
42771
43022
|
"use strict";
|
|
42772
43023
|
init_anthropic();
|
|
42773
43024
|
init_openaiCompat();
|
|
43025
|
+
init_types2();
|
|
42774
43026
|
init_http();
|
|
42775
43027
|
ANTHROPIC_MESSAGES_PATH = "/v1/messages";
|
|
42776
43028
|
OPENAI_CHAT_COMPLETIONS_PATH = "/v1/chat/completions";
|
|
@@ -43133,7 +43385,7 @@ var init_relay = __esm({
|
|
|
43133
43385
|
"../../src/core/harness/pi/relay.ts"() {
|
|
43134
43386
|
"use strict";
|
|
43135
43387
|
init_tracingExecutor();
|
|
43136
|
-
|
|
43388
|
+
init_types2();
|
|
43137
43389
|
init_awaitChildren();
|
|
43138
43390
|
init_runEvents();
|
|
43139
43391
|
init_toolRules();
|
|
@@ -44732,6 +44984,7 @@ async function runBot() {
|
|
|
44732
44984
|
});
|
|
44733
44985
|
console.log(`[capabilities] ${JSON.stringify(capabilities)}`);
|
|
44734
44986
|
const providers = new ProviderRegistry(config.config.providers);
|
|
44987
|
+
const completions = new PiAiProviders(config.config.providers);
|
|
44735
44988
|
const skills = new BundledSkillStore(DEFAULT_SKILLS_DIR);
|
|
44736
44989
|
let slackEmailLookup;
|
|
44737
44990
|
const mcpWiring = buildMcp(config, processSecrets, {
|
|
@@ -44839,6 +45092,7 @@ async function runBot() {
|
|
|
44839
45092
|
const deps = {
|
|
44840
45093
|
config,
|
|
44841
45094
|
providers,
|
|
45095
|
+
completions,
|
|
44842
45096
|
spanLog,
|
|
44843
45097
|
runBearers,
|
|
44844
45098
|
harness: {
|
|
@@ -45309,6 +45563,7 @@ var init_index = __esm({
|
|
|
45309
45563
|
init_config2();
|
|
45310
45564
|
init_capabilities();
|
|
45311
45565
|
init_registry3();
|
|
45566
|
+
init_piAi();
|
|
45312
45567
|
init_slack();
|
|
45313
45568
|
init_slackChannelDirectory();
|
|
45314
45569
|
init_http();
|
|
@@ -45427,6 +45682,7 @@ init_memory();
|
|
|
45427
45682
|
init_residentAdmin();
|
|
45428
45683
|
init_residentFleet();
|
|
45429
45684
|
init_registry3();
|
|
45685
|
+
init_piAi();
|
|
45430
45686
|
init_skills2();
|
|
45431
45687
|
init_mcp2();
|
|
45432
45688
|
init_source();
|
|
@@ -45754,6 +46010,7 @@ async function main() {
|
|
|
45754
46010
|
globalThis.console = new Console({ stdout: process.stderr, stderr: process.stderr });
|
|
45755
46011
|
const { config, runStore } = await bot();
|
|
45756
46012
|
const providers = new ProviderRegistry(config.config.providers);
|
|
46013
|
+
const completions = new PiAiProviders(config.config.providers);
|
|
45757
46014
|
const skills = new BundledSkillStore(DEFAULT_SKILLS_DIR);
|
|
45758
46015
|
const capabilities = capabilitiesFrom(config.config, publicEnv(), processSecrets, {
|
|
45759
46016
|
meatBinary: meatOnPath(publicEnv())
|
|
@@ -45770,6 +46027,7 @@ async function main() {
|
|
|
45770
46027
|
const deps = {
|
|
45771
46028
|
config,
|
|
45772
46029
|
providers,
|
|
46030
|
+
completions,
|
|
45773
46031
|
capabilities,
|
|
45774
46032
|
residentFleet,
|
|
45775
46033
|
...artifacts ? { artifacts } : {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.225.0",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@anthropic-ai/sdk": "^0.124.0",
|
|
38
|
+
"@earendil-works/pi-ai": "0.85.1",
|
|
38
39
|
"@slack/bolt": "^5.1.0",
|
|
39
40
|
"aws4fetch": "^1.0.20",
|
|
40
41
|
"e2b": "^2.46.1",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./AppShell-lYVcj-k7.js";import{Ci as t,Lr as n,Xt as r,_n as i,cn as a,gn as o,ir as s,ln as c,on as l,r as u,sn as d,un as f,ur as p,vi as m,wi as h,xi as g,yn as _}from"./seed-DeKSHrt2.js";var v=`Durable Objects`,y=`Workers · storage · R2`,b=`LLM (Anthropic)`,x=(e,t=2)=>`$${e.toFixed(t)}`,S=e=>e.workersUsd+e.doRowsUsd+e.doStorageUsd+e.r2Usd+e.workflowsUsd;function ee(e){let t=[];for(let n of e.days)for(let e of Object.keys(n.containers))t.includes(e)||t.push(e);return e.days.some(e=>Object.keys(e.durableObjects).length>0)&&t.push(v),e.days.some(e=>S(e)>0)&&t.push(y),e.llmAvailable&&t.push(b),t}function C(e,t){return t===`Durable Objects`?Object.values(e.durableObjects).reduce((e,t)=>e+t,0)+e.doRequestsUsd:t===`Workers · storage · R2`?S(e):t===`LLM (Anthropic)`?e.llmUsd:e.containers[t]?.total??0}function te(e){let t=e.range.partialLastDay?e.days.slice(0,-1):e.days,n=e.range.partialLastDay?e.days[e.days.length-1]:void 0,r=t[t.length-1],i=t.slice(-7),a=i.length?i.reduce((e,t)=>e+t.total,0)/i.length:0,o=e.account.cloudUsd>0?Math.round(e.totals.cloudUsd/e.account.cloudUsd*100):0;return{...r?{yesterday:{date:r.date,total:r.total}}:{},...n?{today:{date:n.date,total:n.total}}:{},avg7:a,projectedMonth:a*30.4,llm:{range:e.totals.llmUsd,...r?{yesterday:r.llmUsd}:{},...n?{today:{usd:n.llmUsd,estimated:n.llmEstimated}}:{}},accountShare:o}}function w(e,t,n){let r=[`${e.date} · total ${x(e.total)}${n?` (partial day)`:``}`];for(let n of t){let t=C(e,n);t<=0||r.push(`${n} ${x(t)}${n===`LLM (Anthropic)`&&e.llmEstimated?` (estimate)`:``}`)}return r.join(`
|
|
2
|
-
`)}function T(e,t){let n={t:12,r:12,b:30,l:48},r=960-n.l-n.r,i=260-n.t-n.b,a=e.days,o=Math.max(1e-9,...a.map(e=>e.total))*1.08,s=r/Math.max(1,a.length),c=Math.min(10,s*.28),l=e=>n.t+i-e/o*i,u=Array.from({length:5},(e,t)=>{let n=o/4*t;return{y:Number(l(n).toFixed(1)),label:x(n)}}),d=[],f=[],p=[];return a.forEach((r,o)=>{let u=0,m=n.l+o*s+c/2,h=s-c;f.push({x:Number((n.l+o*s).toFixed(1)),y:n.t,width:Number(s.toFixed(1)),height:i,title:w(r,t,e.range.partialLastDay&&o===a.length-1)}),t.forEach((e,t)=>{let n=C(r,e);if(n<=0)return;let i=l(u+n),a=l(u),o=Math.max(0,a-i-2);d.push({seriesIndex:t,x:Number(m.toFixed(1)),y:Number(i.toFixed(1)),width:Number(h.toFixed(1)),height:Number(o.toFixed(1))}),u+=n}),(a.length<=16||o%Math.ceil(a.length/16)===0)&&p.push({x:Number((m+h/2).toFixed(1)),label:r.date.slice(5)})}),{width:960,height:260,gridLines:u,segments:d,dayHovers:f,dayLabels:p,axisY:Number(l(0).toFixed(1)),marginLeft:n.l,marginRight:n.r}}function E(e){let t=e.totals.byResource,n=[[`Memory (provisioned while awake)`,t.memory],[`vCPU (active use only)`,t.cpu],[`Durable Object duration + requests`,t.durableObjects],[`Disk (provisioned while awake)`,t.disk],[`Workers requests + CPU`,t.workers],[`Durable Object SQLite rows`,t.doRows],[`Durable Object SQLite storage`,t.doStorage],[`R2 storage + operations`,t.r2],[`Workflow steps + state`,t.workflows]],r=n.reduce((e,t)=>e+t[1],0)||1;return n.map(([e,t])=>({label:e,usd:t,percent:t/r*100}))}var D=[`fill-[#4478b8] dark:fill-[#7aa7e0]`,`fill-[#c8823b] dark:fill-[#e0a95a]`,`fill-[#4c8c57] dark:fill-[#6fae7a]`,`fill-[#b8963e] dark:fill-[#d4b45a]`,`fill-[#b0568c] dark:fill-[#d489b8]`,`fill-[#6b7bcc] dark:fill-[#98a5e6]`,`fill-[#d05252] dark:fill-[#e07a74]`,`fill-[#3e8e96] dark:fill-[#6fb9c0]`],O=[`bg-[#4478b8] dark:bg-[#7aa7e0]`,`bg-[#c8823b] dark:bg-[#e0a95a]`,`bg-[#4c8c57] dark:bg-[#6fae7a]`,`bg-[#b8963e] dark:bg-[#d4b45a]`,`bg-[#b0568c] dark:bg-[#d489b8]`,`bg-[#6b7bcc] dark:bg-[#98a5e6]`,`bg-[#d05252] dark:bg-[#e07a74]`,`bg-[#3e8e96] dark:bg-[#6fb9c0]`],k={class:`overflow-x-auto`},A=[`viewBox`],j=[`x1`,`x2`,`y1`,`y2`],M=[`x`,`y`],N=[`x`,`y`,`width`,`height`],P=[`x`,`y`,`width`,`height`],F=[`x`,`y`],I=[`x1`,`x2`,`y1`,`y2`],L=_({__name:`CostChart`,props:{report:{},series:{}},setup(e){let t=e,n=l(()=>T(t.report,t.series));return(e,t)=>(s(),f(`div`,k,[(s(),f(`svg`,{class:`block h-auto w-full font-mono`,viewBox:`0 0 ${n.value.width} ${n.value.height}`,role:`img`,"aria-label":`Daily cost, stacked by component`},[(s(!0),f(r,null,p(n.value.gridLines,(e,t)=>(s(),f(r,{key:`g${t}`},[d(`line`,{class:`stroke-(--ui-border-muted)`,x1:n.value.marginLeft,x2:n.value.width-n.value.marginRight,y1:e.y,y2:e.y},null,8,j),d(`text`,{class:`fill-(--ui-text-dimmed) text-[11px] tabular-nums`,x:n.value.marginLeft-8,y:e.y+4,"text-anchor":`end`},h(e.label),9,M)],64))),128)),(s(!0),f(r,null,p(n.value.segments,(e,t)=>(s(),f(`rect`,{key:`s${t}`,class:g([`seg hover:opacity-85`,m(D)[e.seriesIndex%m(D).length]]),x:e.x,y:e.y,width:e.width,height:e.height},null,10,N))),128)),(s(!0),f(r,null,p(n.value.dayHovers,(e,t)=>(s(),f(`rect`,{key:`h${t}`,class:`day fill-transparent`,x:e.x,y:e.y,width:e.width,height:e.height},[d(`title`,null,h(e.title),1)],8,P))),128)),(s(!0),f(r,null,p(n.value.dayLabels,(e,t)=>(s(),f(`text`,{key:`d${t}`,class:`fill-(--ui-text-dimmed) text-[11px]`,x:e.x,y:n.value.height-10,"text-anchor":`middle`},h(e.label),9,F))),128)),d(`line`,{class:`stroke-(--ui-border)`,x1:n.value.marginLeft,x2:n.value.width-n.value.marginRight,y1:n.value.axisY,y2:n.value.axisY},null,8,I)],8,A))]))}}),R={class:`mb-4 flex flex-wrap items-center gap-x-4 gap-y-2`},z={class:`flex items-center gap-1`,"aria-label":`Range`},B={key:0,class:`rounded-md bg-accented px-2.5 py-1 font-mono text-xs font-medium tabular-nums text-highlighted`,"aria-current":`page`},V=[`href`],H={key:0,class:`flex items-center gap-1`,"aria-label":`Cost groups`},U={key:0,class:`rounded-md bg-accented px-2.5 py-1 text-xs font-medium text-highlighted`,"aria-current":`page`},W=[`href`],G={class:`font-mono text-sm tabular-nums text-muted`},K={class:`mb-5 grid grid-cols-[repeat(auto-fit,minmax(190px,1fr))] gap-3`},q={key:0,class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},J={class:`font-mono text-2xl font-medium tabular-nums`},Y={class:`text-xs text-muted`},X={key:1,class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},Z={class:`font-mono text-2xl font-medium tabular-nums`},Q={class:`text-xs text-muted`},ne={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},re={class:`font-mono text-2xl font-medium tabular-nums`},ie={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},ae={class:`font-mono text-2xl font-medium tabular-nums`},oe={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},se={class:`font-mono text-2xl font-medium tabular-nums`},ce={class:`text-xs text-muted`},le={class:`grid gap-0.5 rounded-lg border border-default bg-elevated px-4 py-3.5`},ue={class:`font-mono text-2xl font-medium tabular-nums`},de={class:`text-xs text-muted`},fe={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},pe={class:`flex flex-wrap items-baseline justify-between gap-x-4 gap-y-2`},me={class:`legend flex flex-wrap gap-x-4 gap-y-1.5 text-xs text-muted`},he={key:0,class:`text-xs text-warn`},ge={key:1,class:`text-xs text-muted`},_e={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},ve={class:`w-full border-collapse font-mono text-[0.8125rem] tabular-nums`},ye={class:`px-2.5 py-1.5`},be={class:`px-2.5 py-1.5 text-right`},xe={class:`px-2.5 py-1.5 text-right`},Se={class:`w-2/5 px-2.5 py-1.5`},Ce={class:`mb-5 grid gap-3 rounded-lg border border-default bg-elevated px-5 py-4`},we={open:``},Te={class:`mt-2.5 overflow-x-auto`},Ee={class:`data w-full min-w-[38rem] border-collapse whitespace-nowrap font-mono text-[0.8125rem] tabular-nums`},De=[`title`],$={key:0,class:`text-xs text-dimmed`},Oe={key:1,class:`text-xs text-dimmed`},ke={class:`border-b border-muted px-2.5 py-1.5 text-right font-medium`},Ae={class:`text-xs text-muted`},je={class:`rounded bg-accented px-1 py-0.5`},Me={class:`border-t border-default pt-3.5 text-xs text-dimmed`},Ne={class:`mt-2 grid gap-1.5`},Pe=_({__name:`CostsPage`,setup(_){let v=u(`costs`),y=l(()=>v?.report??null),b=l(()=>v?.groups??[]),S=l(()=>y.value?ee(y.value):[]),w=l(()=>y.value?te(y.value):null),T=l(()=>y.value?E(y.value):[]),D=l(()=>y.value?[...y.value.days].reverse():[]),k=[1,7,30,90],A=e=>e===1?`today`:`${e}d`,j=l(()=>{let e=y.value,t=w.value;if(!e||!t)return``;if(!e.llmAvailable)return`LLM spend not configured`;let n=[];return t.llm.yesterday!==void 0&&n.push(`yesterday ${x(t.llm.yesterday)}`),t.llm.today&&n.push(`today ${x(t.llm.today.usd)}${t.llm.today.estimated?` (estimate)`:``}`),n.length?n.join(` · `):`in range`});function M(e){let t=new Date(`${e}T00:00:00Z`);return Number.isNaN(t.getTime())?e:`${[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`][t.getUTCMonth()]} ${t.getUTCDate()}`}return(l,u)=>y.value&&w.value?(s(),a(e,{key:0,title:`${y.value.label} spend`,nav:`costs`},{default:n(()=>[d(`div`,R,[d(`nav`,z,[(s(),f(r,null,p(k,e=>(s(),f(r,{key:e},[e===y.value.range.days?(s(),f(`span`,B,h(A(e)),1)):(s(),f(`a`,{key:1,class:`rounded-md px-2.5 py-1 font-mono text-xs tabular-nums text-muted no-underline hover:bg-elevated hover:text-highlighted`,href:`/costs/${y.value.group}?days=${e}`},h(A(e)),9,V))],64))),64))]),b.value.length>1?(s(),f(`nav`,H,[(s(!0),f(r,null,p(b.value,e=>(s(),f(r,{key:e},[e===y.value.group?(s(),f(`span`,U,h(e),1)):(s(),f(`a`,{key:1,class:`rounded-md px-2.5 py-1 text-xs text-muted no-underline hover:bg-elevated hover:text-highlighted`,href:`/costs/${e}`},h(e),9,W))],64))),128))])):c(``,!0),d(`p`,G,[o(h(M(y.value.range.from))+` → `+h(M(y.value.range.to))+` · `+h(y.value.range.days)+`d`,1),y.value.range.partialLastDay?(s(),f(r,{key:0},[o(` · today partial`)],64)):c(``,!0)])]),d(`section`,K,[w.value.yesterday?(s(),f(`div`,q,[u[0]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Yesterday`,-1),d(`span`,J,h(m(x)(w.value.yesterday.total)),1),d(`span`,Y,h(w.value.yesterday.date)+` · last full day`,1)])):(s(),f(`div`,X,[u[1]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Today so far`,-1),d(`span`,Z,h(w.value.today?m(x)(w.value.today.total):`—`),1),d(`span`,Q,h(w.value.today?`${w.value.today.date} · partial day, UTC`:`no day in range`),1)])),d(`div`,ne,[u[2]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`7-day average`,-1),d(`span`,re,h(m(x)(w.value.avg7)),1),u[3]||=d(`span`,{class:`text-xs text-muted`},`per day, full days only`,-1)]),d(`div`,ie,[u[4]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Projected month`,-1),d(`span`,ae,h(m(x)(w.value.projectedMonth,0)),1),u[5]||=d(`span`,{class:`text-xs text-muted`},`7-day rate × 30.4, before plan fees and included allowances`,-1)]),d(`div`,oe,[u[6]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`LLM spend`,-1),d(`span`,se,h(y.value.llmAvailable?m(x)(w.value.llm.range):`—`),1),d(`span`,ce,h(j.value),1)]),d(`div`,le,[u[7]||=d(`span`,{class:`font-mono text-[0.6875rem] font-medium uppercase tracking-widest text-dimmed`},`Share of account`,-1),d(`span`,ue,h(w.value.accountShare)+`%`,1),d(`span`,de,h(m(x)(y.value.totals.cloudUsd))+` of `+h(m(x)(y.value.account.cloudUsd))+` Cloudflare spend in range`,1)])]),d(`section`,fe,[d(`div`,pe,[u[8]||=d(`div`,null,[d(`h2`,{class:`text-[0.9375rem] font-medium`},`Daily cost`),d(`p`,{class:`text-sm text-muted`},`Stacked by component · USD list price`)],-1),d(`div`,me,[(s(!0),f(r,null,p(S.value,(e,t)=>(s(),f(`span`,{key:e,class:`inline-flex items-center gap-1.5`},[d(`i`,{class:g([`inline-block size-2.5 rounded-xs`,m(O)[t%m(O).length]])},null,2),o(h(e),1)]))),128))])]),i(L,{report:y.value,series:S.value},null,8,[`report`,`series`]),y.value.llmAvailable?y.value.days.some(e=>e.llmEstimated)?(s(),f(`p`,ge,[u[10]||=o(` A day the Anthropic cost report has not closed yet (today, and yesterday until a few hours after midnight UTC) shows its LLM figure as an estimate: the hourly usage report priced at list. The closed days are the cost report itself. `,-1),y.value.days.some(e=>e.llmUnpricedTokens>0)?(s(),f(r,{key:0},[o(` Some tokens ran under a model this page has no price for and are not in the estimate. `)],64)):c(``,!0)])):c(``,!0):(s(),f(`p`,he,[...u[9]||=[o(` LLM spend not configured — set `,-1),d(`code`,null,`ANTHROPIC_ADMIN_KEY`,-1),o(` and the group's `,-1),d(`code`,null,`anthropicWorkspaceId`,-1),o(` to layer it in. `,-1)]]))]),d(`section`,_e,[u[11]||=d(`div`,null,[d(`h2`,{class:`text-[0.9375rem] font-medium`},`What each cloud dollar buys`)],-1),d(`table`,ve,[d(`tbody`,null,[(s(!0),f(r,null,p(T.value,e=>(s(),f(`tr`,{key:e.label,class:`border-b border-muted`},[d(`td`,ye,h(e.label),1),d(`td`,be,h(m(x)(e.usd)),1),d(`td`,xe,h(Math.round(e.percent))+`%`,1),d(`td`,Se,[d(`i`,{class:`block h-2.5 rounded-xs bg-primary opacity-75`,style:t({width:`${e.percent.toFixed(1)}%`})},null,4)])]))),128))])])]),d(`section`,Ce,[d(`details`,we,[u[14]||=d(`summary`,{class:`cursor-pointer text-sm text-muted`},`Table view — daily cost by component (USD)`,-1),d(`div`,Te,[d(`table`,Ee,[d(`thead`,null,[d(`tr`,null,[u[12]||=d(`th`,{class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-left text-xs font-medium text-muted`},` Date `,-1),(s(!0),f(r,null,p(S.value,e=>(s(),f(`th`,{key:e,class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-right text-xs font-medium text-muted`},h(e),1))),128)),u[13]||=d(`th`,{class:`border-b border-muted bg-(--ui-bg-muted) px-2.5 py-1.5 text-right text-xs font-medium text-muted`},` Total `,-1)])]),d(`tbody`,null,[(s(!0),f(r,null,p(D.value,e=>(s(),f(`tr`,{key:e.date},[d(`td`,{class:`border-b border-muted px-2.5 py-1.5`,title:e.date},[o(h(M(e.date))+` `,1),y.value.range.partialLastDay&&e.date===y.value.range.to?(s(),f(`span`,$,`(partial day`+h(e.llmEstimated?` · LLM estimated`:``)+`)`,1)):e.llmEstimated?(s(),f(`span`,Oe,`(LLM estimated)`)):c(``,!0)],8,De),(s(!0),f(r,null,p(S.value,t=>(s(),f(`td`,{key:t,class:`border-b border-muted px-2.5 py-1.5 text-right`},h(m(x)(m(C)(e,t),3)),1))),128)),d(`td`,ke,h(m(x)(e.total,3)),1)]))),128))])])])]),d(`p`,Ae,[u[15]||=o(` Machine-readable twin: `,-1),d(`code`,je,`GET /costs/`+h(y.value.group)+`.json`,1),u[16]||=o(` (same Access gate). `,-1)])]),d(`footer`,Me,[d(`details`,null,[u[21]||=d(`summary`,{class:`cursor-pointer text-muted`},`How these numbers are computed`,-1),d(`div`,Ne,[u[19]||=d(`div`,null,[d(`b`,null,`Live.`),o(` Both billing sources are read live from this page — nothing cached, nothing stored. Cloudflare bills vCPU on active use only; memory and disk bill on the provisioned size for every second a container is awake. LLM spend is the Anthropic Admin API cost report for this group's workspace (gross, USD); a day the cost report has not closed is the Admin API usage report, hourly, priced at Anthropic list per model (input, output, cache writes, cache reads) and marked as an estimate. `)],-1),u[20]||=d(`div`,null,[d(`b`,null,`Method.`),o(` Cloudflare GraphQL Analytics, every meter a Workers deployment is billed on: `),d(`code`,null,`containersUsageAdaptiveGroups`),o(` (cpuTimeSec, allocatedMemory, allocatedDisk per app per UTC day), `),d(`code`,null,`durableObjectsPeriodicGroups`),o(` (billable `),d(`code`,null,`duration`),o(` GB-s and SQLite rows read and written per namespace), `),d(`code`,null,`durableObjectsInvocationsAdaptiveGroups`),o(` (requests per namespace), `),d(`code`,null,`durableObjectsSqlStorageGroups`),o(` (bytes stored), `),d(`code`,null,`workersInvocationsAdaptive`),o(` (requests, CPU time), `),d(`code`,null,`r2StorageAdaptiveGroups`),o(` and `),d(`code`,null,`r2OperationsAdaptiveGroups`),o(` (bytes stored, class A/B operations). Prices: vCPU $0.000020/s, memory $0.0000025/GiB-s, disk $0.00000007/GB-s, DO duration $12.50 per million GB-s, DO requests $0.15/M, SQLite rows $0.001/M read and $1.00/M written, DO storage $0.20/GB-month, Workers $0.30/M requests and $0.02/M CPU-ms, R2 $0.015/GB-month, $4.50/M class A and $0.36/M class B (deletes free). Storage is the day's peak, prorated over a 30.44-day month. Gross list price — plan fees and included allowances are not subtracted; Workers Logs volume has no analytics dataset and is not priced. `)],-1),d(`div`,null,[u[17]||=d(`b`,null,`Scope.`,-1),u[18]||=o(` Attributed to this group: the Workers `,-1),d(`code`,null,h(y.value.attribution.workers.join(`, `)),1),o(`, every Durable Object namespace they host (`+h(Object.keys(y.value.attribution.durableObjectNamespaces).length)+`), the R2 buckets named after them (`+h(Object.keys(y.value.attribution.r2Buckets).length)+`), and the container apps mapped in `,1),d(`code`,null,`costs.groups.`+h(y.value.group),1),o(` (`+h(Object.keys(y.value.attribution.containerApps).length)+`). Everything else in the account is priced the same way into the account total, which is what "share of account" divides by. `,1)])])])])]),_:1},8,[`title`])):c(``,!0)}});export{Pe as default};
|