@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.
Files changed (23) hide show
  1. package/dist/assets/config/config.example.yaml +5 -1
  2. package/dist/assets/deploy/cloudflare-resident/Dockerfile +47 -12
  3. package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +28 -9
  4. package/dist/assets/package-lock.json +980 -4
  5. package/dist/assets/package.json +2 -1
  6. package/dist/assets/source.json +3 -3
  7. package/dist/assets/src/providers/types.ts +3 -0
  8. package/dist/assets/web/dist/.vite/manifest.json +20 -20
  9. package/dist/assets/web/dist/assets/CostsPage-BlPwsI2T.js +3 -0
  10. package/dist/assets/web/dist/assets/{ResidentDetailPage-BXwWQRJt.js → ResidentDetailPage-Cu4Ve2j4.js} +1 -1
  11. package/dist/assets/web/dist/assets/{ResidentsIndexPage-CwVN-3tl.js → ResidentsIndexPage-_QIDVyOj.js} +1 -1
  12. package/dist/assets/web/dist/assets/{RunRoutePage-C0-RUb8o.js → RunRoutePage-DxgcHX-0.js} +5 -5
  13. package/dist/assets/web/dist/assets/{RunsIndexPage-Tx5P767G.js → RunsIndexPage-JQvnDmo0.js} +1 -1
  14. package/dist/assets/web/dist/assets/{ScheduledPage-C80zFu3G.js → ScheduledPage-DEVRWqZi.js} +1 -1
  15. package/dist/assets/web/dist/assets/{StatusDot-BaGkjYs1.js → StatusDot-BDAKF1Bp.js} +1 -1
  16. package/dist/assets/web/dist/assets/{Tooltip-BL-Cwe59.js → Tooltip-BFncyNUQ.js} +1 -1
  17. package/dist/assets/web/dist/assets/{dist-DZgVjemt.js → dist-DJfQXPjH.js} +1 -1
  18. package/dist/assets/web/dist/assets/{main-BB6FMkeU.js → main-BjhiJxQq.js} +2 -2
  19. package/dist/assets/web/dist/assets/main-DymOuq2l.css +1 -0
  20. package/dist/cli.js +313 -55
  21. package/package.json +2 -1
  22. package/dist/assets/web/dist/assets/CostsPage-C-ximW1N.js +0 -2
  23. 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 ANTHROPIC_API_KEY_ENV, AnthropicProvider, EPHEMERAL, CACHEABLE_BLOCKS;
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
- ANTHROPIC_API_KEY_ENV = "ANTHROPIC_API_KEY";
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
- account: { cloudUsd: accountCloudUsd },
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 range = resolveRange(daysParam, now());
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 init_types2 = __esm({
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
- init_types2();
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
- init_types2();
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
- init_types3();
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
- providers: deps.providers,
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
- init_types3();
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.providers.get(ref.provider), ref.model, {
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
- init_types3();
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
- init_types3();
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
- init_types3();
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
- init_types3();
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
- init_types3();
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
- init_types2();
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
- init_types3();
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.224.0",
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};