negotium 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/agent-helpers.js +220 -32
  2. package/dist/agent-helpers.js.map +12 -12
  3. package/dist/background-bash.js.map +1 -1
  4. package/dist/browser-runtime.js.map +1 -1
  5. package/dist/{chunk-5g5a63vv.js → chunk-5cpdbbeh.js} +56 -6
  6. package/dist/{chunk-5g5a63vv.js.map → chunk-5cpdbbeh.js.map} +5 -5
  7. package/dist/hosted-agent.js +119 -9
  8. package/dist/hosted-agent.js.map +8 -8
  9. package/dist/main.js +931 -419
  10. package/dist/main.js.map +25 -24
  11. package/dist/mcp-factories.js +289 -42
  12. package/dist/mcp-factories.js.map +13 -13
  13. package/dist/prompts.js.map +1 -1
  14. package/dist/query-runtime.js.map +1 -1
  15. package/dist/registry.js +3 -3
  16. package/dist/registry.js.map +2 -2
  17. package/dist/rollout.js +1 -1
  18. package/dist/runtime/src/agents/codex-provider.ts +53 -2
  19. package/dist/runtime/src/agents/compaction-support.ts +1 -1
  20. package/dist/runtime/src/agents/maestro-provider.ts +3 -0
  21. package/dist/runtime/src/agents/rollout/codex.ts +62 -0
  22. package/dist/runtime/src/index.ts +1 -0
  23. package/dist/runtime/src/mcp/factories/token-stats.ts +33 -11
  24. package/dist/runtime/src/mcp/runtime-spec.ts +58 -1
  25. package/dist/runtime/src/node-host.ts +1 -0
  26. package/dist/runtime/src/runtime/turn-event-stream.ts +43 -2
  27. package/dist/runtime/src/runtime/turn-runner.ts +20 -9
  28. package/dist/runtime/src/storage/token-stats.ts +200 -19
  29. package/dist/runtime/src/types.ts +6 -0
  30. package/dist/runtime/src/version.ts +1 -1
  31. package/dist/runtime-helpers.js.map +1 -1
  32. package/dist/storage.js +112 -11
  33. package/dist/storage.js.map +4 -4
  34. package/dist/types/packages/core/src/agents/codex-provider.d.ts +13 -0
  35. package/dist/types/packages/core/src/agents/compaction-support.d.ts +1 -0
  36. package/dist/types/packages/core/src/agents/rollout/codex.d.ts +9 -0
  37. package/dist/types/packages/core/src/mcp/factories/token-stats.d.ts +4 -2
  38. package/dist/types/packages/core/src/runtime/turn-runner.d.ts +4 -0
  39. package/dist/types/packages/core/src/storage/token-stats.d.ts +35 -6
  40. package/dist/types/packages/core/src/types.d.ts +6 -0
  41. package/dist/types/packages/core/src/version.d.ts +1 -1
  42. package/dist/vault.js.map +1 -1
  43. package/package.json +2 -2
@@ -474,7 +474,7 @@ var init_canonical_bridge_config = __esm(() => {
474
474
  });
475
475
 
476
476
  // ../../packages/core/src/mcp/runtime-spec.ts
477
- import { createHmac, timingSafeEqual } from "crypto";
477
+ import { createHash, createHmac, timingSafeEqual } from "crypto";
478
478
  function encodeTokenPart(value) {
479
479
  return Buffer.from(JSON.stringify(value), "utf-8").toString("base64url");
480
480
  }
@@ -507,19 +507,69 @@ function buildRuntimeMcpSpec(agent, ctx) {
507
507
  return {
508
508
  type: "sse",
509
509
  url: `${base}/sse?${query}`,
510
- timeout: CLAUDE_MCP_TOOL_TIMEOUT_MS
510
+ timeout: CLAUDE_MCP_TOOL_TIMEOUT_MS,
511
+ ...agent === "maestro" ? { lifecycle: "turn" } : {}
511
512
  };
512
513
  }
514
+ function hostedMcpCacheIdentity(surface, ctx) {
515
+ let semanticContext;
516
+ switch (surface) {
517
+ case "system-health":
518
+ semanticContext = {};
519
+ break;
520
+ case "token-stats":
521
+ case "agent-health":
522
+ semanticContext = { userId: ctx.userId };
523
+ break;
524
+ case "task":
525
+ semanticContext = {
526
+ userId: ctx.userId,
527
+ topicTitle: ctx.topicTitle,
528
+ topicId: ctx.topicId ?? null
529
+ };
530
+ break;
531
+ case "wiki":
532
+ case "skills":
533
+ semanticContext = {
534
+ userId: ctx.userId,
535
+ topicId: ctx.wikiTopicId ?? ctx.topicId ?? null
536
+ };
537
+ break;
538
+ case "vault":
539
+ semanticContext = { userId: ctx.userId, cwd: ctx.cwd, agent: ctx.agent };
540
+ break;
541
+ case "session-comm":
542
+ semanticContext = {
543
+ userId: ctx.userId,
544
+ topicTitle: ctx.topicTitle,
545
+ topicId: ctx.topicId ?? null,
546
+ subagentParentTopicId: ctx.subagentParentTopicId ?? null,
547
+ depth: ctx.depth ?? 0,
548
+ silent: ctx.silent ?? false,
549
+ agent: ctx.agent,
550
+ peerBridge: ctx.peerBridge ?? null
551
+ };
552
+ break;
553
+ }
554
+ const digest = createHash("sha256").update(JSON.stringify([surface, semanticContext])).digest("hex").slice(0, 24);
555
+ return `hosted:${surface}:${digest}`;
556
+ }
513
557
  function buildHostedMcpSpec(agent, surface, ctx) {
514
558
  const token = issueHostedMcpToken(surface, ctx);
515
559
  const base = `http://127.0.0.1:${runtimePort}${RUNTIME_MCP_BASE_PATH}/${surface}`;
516
560
  const query = `token=${encodeURIComponent(token)}`;
517
561
  if (agent === "codex")
518
562
  return { url: `${base}/mcp?${query}` };
563
+ const queryBound = surface === "session-comm" && (ctx.silent === true || ctx.peerBridge !== undefined);
564
+ const lifecycle = queryBound ? "turn" : surface === "session-comm" ? "session" : "process";
519
565
  return {
520
566
  type: "sse",
521
567
  url: `${base}/sse?${query}`,
522
- timeout: CLAUDE_MCP_TOOL_TIMEOUT_MS
568
+ timeout: CLAUDE_MCP_TOOL_TIMEOUT_MS,
569
+ ...agent === "maestro" ? {
570
+ lifecycle,
571
+ cacheKey: hostedMcpCacheIdentity(surface, ctx)
572
+ } : {}
523
573
  };
524
574
  }
525
575
  var RUNTIME_MCP_KEY = "runtime", RUNTIME_MCP_BASE_PATH = "/mcp/runtime", TOKEN_TTL_MS, CLAUDE_MCP_TOOL_TIMEOUT_MS = 600000, runtimePort;
@@ -1372,9 +1422,9 @@ var init_sqlite = __esm(async () => {
1372
1422
  });
1373
1423
 
1374
1424
  // ../../packages/core/src/storage/vault-crypto-core.ts
1375
- import { createCipheriv, createDecipheriv, createHash, randomBytes as randomBytes3 } from "crypto";
1425
+ import { createCipheriv, createDecipheriv, createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
1376
1426
  function encryptionKey(masterKey) {
1377
- return createHash("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
1427
+ return createHash2("sha256").update("otium-vault-value-v1\x00", "utf8").update(masterKey, "utf8").digest().subarray(0, KEY_BYTES);
1378
1428
  }
1379
1429
  function aad(userId, key) {
1380
1430
  return Buffer.from(`${userId}\x00${key.toUpperCase()}`, "utf8");
@@ -2173,7 +2223,7 @@ var init_claude_registry = __esm(() => {
2173
2223
  });
2174
2224
 
2175
2225
  // ../../packages/core/src/version.ts
2176
- var NEGOTIUM_VERSION = "0.2.15";
2226
+ var NEGOTIUM_VERSION = "0.2.17";
2177
2227
 
2178
2228
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2179
2229
  import { spawn as spawn2 } from "child_process";
@@ -2631,6 +2681,36 @@ function extractLatestCodexContextUsage(jsonl) {
2631
2681
  }
2632
2682
  return;
2633
2683
  }
2684
+ function extractLatestCodexTokenTotals(jsonl) {
2685
+ const lines = jsonl.trimEnd().split(`
2686
+ `);
2687
+ for (let index = lines.length - 1;index >= 0; index -= 1) {
2688
+ try {
2689
+ const entry = JSON.parse(lines[index] ?? "");
2690
+ if (entry.type !== "event_msg" || entry.payload?.type !== "token_count")
2691
+ continue;
2692
+ const usage = entry.payload.info?.total_token_usage;
2693
+ if (!usage)
2694
+ continue;
2695
+ const values = [
2696
+ usage.input_tokens,
2697
+ usage.output_tokens,
2698
+ usage.cached_input_tokens,
2699
+ usage.cache_write_input_tokens
2700
+ ];
2701
+ if (values.some((value) => value !== undefined && (!Number.isFinite(value) || value < 0))) {
2702
+ continue;
2703
+ }
2704
+ return {
2705
+ inputTokens: usage.input_tokens ?? 0,
2706
+ outputTokens: usage.output_tokens ?? 0,
2707
+ cachedInputTokens: usage.cached_input_tokens ?? 0,
2708
+ cacheWriteInputTokens: usage.cache_write_input_tokens ?? 0
2709
+ };
2710
+ } catch {}
2711
+ }
2712
+ return;
2713
+ }
2634
2714
  function readLatestCodexContextUsage(threadId) {
2635
2715
  const path = latestCodexRolloutPath(threadId);
2636
2716
  if (!path)
@@ -2642,6 +2722,17 @@ function readLatestCodexContextUsage(threadId) {
2642
2722
  return;
2643
2723
  }
2644
2724
  }
2725
+ function readLatestCodexTokenTotals(threadId) {
2726
+ const path = latestCodexRolloutPath(threadId);
2727
+ if (!path)
2728
+ return;
2729
+ try {
2730
+ return extractLatestCodexTokenTotals(readFileSync5(path, "utf8"));
2731
+ } catch (error) {
2732
+ logger.debug({ error, threadId }, "codex token totals: rollout read failed");
2733
+ return;
2734
+ }
2735
+ }
2645
2736
  function migrateCodexRolloutNativeMultiAgentMetadata(threadId) {
2646
2737
  const path = latestCodexRolloutPath(threadId);
2647
2738
  if (!path)
@@ -4956,6 +5047,7 @@ var init_tool_format = __esm(() => {
4956
5047
  var exports_codex_provider = {};
4957
5048
  __export(exports_codex_provider, {
4958
5049
  toCodexMcpServers: () => toCodexMcpServers,
5050
+ normalizeCodexTurnUsage: () => normalizeCodexTurnUsage,
4959
5051
  codexProvider: () => codexProvider
4960
5052
  });
4961
5053
  import { execFileSync as execFileSync4 } from "child_process";
@@ -4963,6 +5055,20 @@ import { existsSync as existsSync11, readFileSync as readFileSync11, realpathSyn
4963
5055
  import { homedir as homedir6 } from "os";
4964
5056
  import { dirname as dirname9, isAbsolute as isAbsolute2, join as join12, relative, resolve as resolve8 } from "path";
4965
5057
  import { Codex } from "@openai/codex-sdk";
5058
+ function sameCodexUsage(usage, total) {
5059
+ return usage.input_tokens === total.inputTokens && usage.output_tokens === total.outputTokens && (usage.cached_input_tokens ?? 0) === total.cachedInputTokens && (usage.cache_write_input_tokens ?? 0) === total.cacheWriteInputTokens;
5060
+ }
5061
+ function normalizeCodexTurnUsage(usage, baseline, rolloutTotal) {
5062
+ if (!baseline || !rolloutTotal || !sameCodexUsage(usage, rolloutTotal))
5063
+ return usage;
5064
+ const delta = (current, previous) => current >= previous ? current - previous : current;
5065
+ return {
5066
+ input_tokens: delta(rolloutTotal.inputTokens, baseline.inputTokens),
5067
+ output_tokens: delta(rolloutTotal.outputTokens, baseline.outputTokens),
5068
+ cached_input_tokens: delta(rolloutTotal.cachedInputTokens, baseline.cachedInputTokens),
5069
+ cache_write_input_tokens: delta(rolloutTotal.cacheWriteInputTokens, baseline.cacheWriteInputTokens)
5070
+ };
5071
+ }
4966
5072
  function mapEffort(effort) {
4967
5073
  if (!effort)
4968
5074
  return;
@@ -5362,6 +5468,7 @@ async function* codexProvider(opts) {
5362
5468
  ...opts.effort ? { modelReasoningEffort: mapEffort(opts.effort) } : {}
5363
5469
  };
5364
5470
  let currentSessionId = opts.sessionId;
5471
+ let usageBaseline = currentSessionId ? readLatestCodexTokenTotals(currentSessionId) : undefined;
5365
5472
  let thread = currentSessionId ? codex.resumeThread(currentSessionId, threadOptions) : codex.startThread(threadOptions);
5366
5473
  let prompt = promptForThread(opts, true);
5367
5474
  let agentTextSoFar = "";
@@ -5420,6 +5527,7 @@ async function* codexProvider(opts) {
5420
5527
  thread = codex.startThread(threadOptions);
5421
5528
  prompt = promptForThread(opts, true);
5422
5529
  currentSessionId = undefined;
5530
+ usageBaseline = undefined;
5423
5531
  startResult = await startStreamedWithTracking(thread, prompt, attemptAbort.signal, trackedPids);
5424
5532
  }
5425
5533
  if (attemptAbort.signal.aborted) {
@@ -5520,10 +5628,11 @@ async function* codexProvider(opts) {
5520
5628
  break;
5521
5629
  }
5522
5630
  case "turn.completed": {
5523
- const usage = event.usage;
5524
- if (!usage)
5631
+ const rawUsage = event.usage;
5632
+ if (!rawUsage)
5525
5633
  break;
5526
5634
  attemptCompleted = true;
5635
+ const usage = normalizeCodexTurnUsage(rawUsage, usageBaseline, currentSessionId ? readLatestCodexTokenTotals(currentSessionId) : undefined);
5527
5636
  const contextUsage = currentSessionId ? readLatestCodexContextUsage(currentSessionId) : undefined;
5528
5637
  yield {
5529
5638
  type: "result",
@@ -5532,6 +5641,7 @@ async function* codexProvider(opts) {
5532
5641
  usage: {
5533
5642
  inputTokens: usage.input_tokens,
5534
5643
  outputTokens: usage.output_tokens,
5644
+ cacheCreationInputTokens: usage.cache_write_input_tokens,
5535
5645
  cacheReadInputTokens: usage.cached_input_tokens,
5536
5646
  ...contextUsage
5537
5647
  }
@@ -5724,6 +5834,7 @@ function maestroProvider(opts) {
5724
5834
  ...opts,
5725
5835
  enableToolSearch: !opts.toolPolicy && opts.enableToolSearch !== false,
5726
5836
  toolResultTruncation: buildMaestroToolResultTruncation(opts),
5837
+ ephemeralSystemPrompt: opts.ephemeralSystemPrompt,
5727
5838
  apiKeyOverrides: resolveMaestroApiKeyOverrides(userId),
5728
5839
  agent: "maestro",
5729
5840
  disallowedTools: buildMaestroDisallowedTools(callerDisallowedTools, opts.toolPolicy),
@@ -9750,7 +9861,7 @@ var init_runtime_process_leases = __esm(async () => {
9750
9861
  });
9751
9862
 
9752
9863
  // ../../packages/core/src/agents/mcp-tools/ask-user.ts
9753
- import { createHash as createHash2, randomUUID as randomUUID9 } from "crypto";
9864
+ import { createHash as createHash3, randomUUID as randomUUID9 } from "crypto";
9754
9865
  import { z } from "zod";
9755
9866
  function normalizeAskText(value, maxChars) {
9756
9867
  if (typeof value !== "string")
@@ -9787,7 +9898,7 @@ function normalizeAskUserQuestionInput(input) {
9787
9898
  return { question, choices };
9788
9899
  }
9789
9900
  function askBodyHash(question, choices) {
9790
- return createHash2("sha256").update(JSON.stringify({ question, choices })).digest("hex");
9901
+ return createHash3("sha256").update(JSON.stringify({ question, choices })).digest("hex");
9791
9902
  }
9792
9903
  function answerToolResult(answer) {
9793
9904
  if (!answer.userId)
@@ -10807,7 +10918,7 @@ var init_browser_profiles = __esm(async () => {
10807
10918
 
10808
10919
  // ../../packages/core/src/platform/playwright/manager.ts
10809
10920
  import { execFileSync as execFileSync7, spawn as spawn5 } from "child_process";
10810
- import { createHash as createHash3, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
10921
+ import { createHash as createHash4, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
10811
10922
  import {
10812
10923
  cpSync,
10813
10924
  existsSync as existsSync17,
@@ -10902,7 +11013,7 @@ function parseInstanceKey(instanceKey) {
10902
11013
  };
10903
11014
  }
10904
11015
  function portFileName(instanceKey) {
10905
- return createHash3("sha256").update(instanceKey).digest("hex").slice(0, 24);
11016
+ return createHash4("sha256").update(instanceKey).digest("hex").slice(0, 24);
10906
11017
  }
10907
11018
  function writePortFile(instanceKey, port) {
10908
11019
  try {
@@ -12495,7 +12606,7 @@ __export(exports_derive, {
12495
12606
  TopicForkCompactionError: () => TopicForkCompactionError,
12496
12607
  TopicDeriveBusyError: () => TopicDeriveBusyError
12497
12608
  });
12498
- import { createHash as createHash4, randomUUID as randomUUID12 } from "crypto";
12609
+ import { createHash as createHash5, randomUUID as randomUUID12 } from "crypto";
12499
12610
  import { mkdirSync as mkdirSync13, rmSync as rmSync5, unlinkSync as unlinkSync13 } from "fs";
12500
12611
  function getTopics() {
12501
12612
  return listTopics().filter((topic) => !isLegacySharedGeneral(topic.id));
@@ -12561,7 +12672,7 @@ function captureForkSnapshot(sourceTopicId, userId, topicTitle) {
12561
12672
  maxRowid: messageRows.at(-1)?.rowid ?? 0
12562
12673
  },
12563
12674
  active: isTopicRunning(sourceTopicId),
12564
- canonicalDigest: createHash4("sha256").update(entries.map((entry) => JSON.stringify(entry)).join(`
12675
+ canonicalDigest: createHash5("sha256").update(entries.map((entry) => JSON.stringify(entry)).join(`
12565
12676
  `)).digest("hex")
12566
12677
  };
12567
12678
  }
@@ -13054,7 +13165,7 @@ __export(exports_session_asks, {
13054
13165
  clearPendingAsk: () => clearPendingAsk,
13055
13166
  PENDING_ASK_TTL_MS: () => PENDING_ASK_TTL_MS
13056
13167
  });
13057
- import { createHash as createHash5 } from "crypto";
13168
+ import { createHash as createHash6 } from "crypto";
13058
13169
  import {
13059
13170
  closeSync as closeSync2,
13060
13171
  mkdirSync as mkdirSync15,
@@ -13068,14 +13179,14 @@ import {
13068
13179
  import { dirname as dirname13, join as join24 } from "path";
13069
13180
  function pendingAskDir(userId) {
13070
13181
  const rawUserId = String(userId);
13071
- const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash5("sha256").update(rawUserId).digest("hex")}`;
13182
+ const safeUserId = /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
13072
13183
  return join24(resolveStorageSessionAsksDir(), safeUserId);
13073
13184
  }
13074
13185
  function encodeAskKey(key) {
13075
13186
  return JSON.stringify([key.from, key.to]);
13076
13187
  }
13077
13188
  function pendingAskPath(key) {
13078
- const digest = createHash5("sha256").update(encodeAskKey(key)).digest("hex");
13189
+ const digest = createHash6("sha256").update(encodeAskKey(key)).digest("hex");
13079
13190
  return join24(pendingAskDir(key.userId), `${ASK_FILENAME_PREFIX}${digest}.pending`);
13080
13191
  }
13081
13192
  function v2PendingAskPath(key) {
@@ -14654,12 +14765,12 @@ var init_visuals = __esm(async () => {
14654
14765
  });
14655
14766
 
14656
14767
  // ../../packages/core/src/storage/token-stats.ts
14657
- import { createHash as createHash6 } from "crypto";
14768
+ import { createHash as createHash7 } from "crypto";
14658
14769
  import { mkdirSync as mkdirSync17 } from "fs";
14659
14770
  import { join as join26 } from "path";
14660
14771
  function tokenStatsFileId(userId) {
14661
14772
  const rawUserId = String(userId);
14662
- return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash6("sha256").update(rawUserId).digest("hex")}`;
14773
+ return /^[A-Za-z0-9][A-Za-z0-9_.@-]{0,255}$/.test(rawUserId) && !rawUserId.includes("..") ? rawUserId : `sha256-${createHash7("sha256").update(rawUserId).digest("hex")}`;
14663
14774
  }
14664
14775
  function queriesPath(userId) {
14665
14776
  const fileId = tokenStatsFileId(userId);
@@ -14667,14 +14778,33 @@ function queriesPath(userId) {
14667
14778
  mkdirSync17(logDir, { recursive: true });
14668
14779
  return join26(logDir, `token-queries-${fileId}.jsonl`);
14669
14780
  }
14670
- function recordUsage(userId, session, usage) {
14781
+ function estimateUsageCost(agent, model, usage) {
14782
+ const prices = TOKEN_PRICES[`${agent}:${model}`];
14783
+ if (!prices)
14784
+ return 0;
14785
+ return (usage.inputTokens * prices.input + usage.outputTokens * prices.output + (agent === "claude" ? usage.cacheCreationInputTokens * (prices.cacheWrite ?? prices.input) : 0) + usage.cacheReadInputTokens * prices.cacheRead) / 1e6;
14786
+ }
14787
+ function recordUsage(userId, session, usage, context) {
14788
+ const cacheReadInputTokens = usage.cacheReadInputTokens ?? 0;
14789
+ const inputTokens = context.agent === "claude" ? usage.inputTokens : Math.max(0, usage.inputTokens - cacheReadInputTokens);
14790
+ const normalized = {
14791
+ inputTokens,
14792
+ outputTokens: usage.outputTokens,
14793
+ cacheCreationInputTokens: usage.cacheCreationInputTokens ?? 0,
14794
+ cacheReadInputTokens
14795
+ };
14671
14796
  const record = {
14797
+ schemaVersion: 2,
14672
14798
  timestamp: new Date().toISOString(),
14673
14799
  session,
14674
- inputTokens: usage.inputTokens,
14675
- outputTokens: usage.outputTokens,
14676
- cacheCreationInputTokens: usage.cacheCreationInputTokens ?? 0,
14677
- cacheReadInputTokens: usage.cacheReadInputTokens ?? 0
14800
+ topicId: context.topicId,
14801
+ ...context.providerSessionId ? { providerSessionId: context.providerSessionId } : {},
14802
+ agent: context.agent,
14803
+ model: context.model,
14804
+ ...normalized,
14805
+ ...usage.contextTokens !== undefined ? { contextTokens: usage.contextTokens } : {},
14806
+ ...usage.contextWindow !== undefined ? { contextWindow: usage.contextWindow } : {},
14807
+ estimatedCostUsd: usage.costUsd ?? estimateUsageCost(context.agent, context.model, normalized)
14678
14808
  };
14679
14809
  try {
14680
14810
  appendJsonlEntry(queriesPath(userId), record);
@@ -14682,10 +14812,23 @@ function recordUsage(userId, session, usage) {
14682
14812
  logger.warn({ err: e, userId }, "token-stats: Failed to record");
14683
14813
  }
14684
14814
  }
14815
+ var TOKEN_PRICES;
14685
14816
  var init_token_stats = __esm(async () => {
14686
14817
  init_jsonl();
14687
14818
  init_logger();
14688
14819
  await init_storage_host();
14820
+ TOKEN_PRICES = {
14821
+ "codex:gpt-5.6-sol": { input: 5, cacheRead: 0.5, output: 30 },
14822
+ "codex:gpt-5.6-terra": { input: 2.5, cacheRead: 0.25, output: 15 },
14823
+ "codex:gpt-5.6-luna": { input: 1, cacheRead: 0.1, output: 6 },
14824
+ "claude:fable": { input: 10, cacheWrite: 12.5, cacheRead: 1, output: 50 },
14825
+ "claude:opus": { input: 5, cacheWrite: 6.25, cacheRead: 0.5, output: 25 },
14826
+ "claude:sonnet": { input: 2, cacheWrite: 2.5, cacheRead: 0.2, output: 10 },
14827
+ "maestro:kimi-k3": { input: 3, cacheRead: 0.3, output: 15 },
14828
+ "maestro:kimi-k2.7-code": { input: 0.95, cacheRead: 0.19, output: 4 },
14829
+ "maestro:deepseek-pro": { input: 0.435, cacheRead: 0.003625, output: 0.87 },
14830
+ "maestro:deepseek-flash": { input: 0.14, cacheRead: 0.0028, output: 0.28 }
14831
+ };
14689
14832
  });
14690
14833
 
14691
14834
  // ../../packages/core/src/runtime/turn-event-stream.ts
@@ -14714,6 +14857,9 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14714
14857
  let pendingSawDelta = false;
14715
14858
  let accumulatedText = "";
14716
14859
  let pendingText = "";
14860
+ let assistantContextTokens = 0;
14861
+ let toolContextTokens = 0;
14862
+ let lastContextProgressAt = 0;
14717
14863
  let lastVisibleMessageId = null;
14718
14864
  const visibleMessageIds = [];
14719
14865
  let lastTaskPanelText = null;
@@ -14724,6 +14870,28 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14724
14870
  const toolSummaryOptions = {
14725
14871
  cwd: control.injectParams?.cwd ?? workspaceCwdFor(topicId)
14726
14872
  };
14873
+ const recordEventUsage = (usage) => {
14874
+ recordUsage(userId, topicTitle, usage, {
14875
+ topicId,
14876
+ ...control.sessionId ? { providerSessionId: control.sessionId } : {},
14877
+ agent: agentType,
14878
+ model
14879
+ });
14880
+ };
14881
+ const broadcastContextProgress = (force = false) => {
14882
+ if (silent)
14883
+ return;
14884
+ const now = Date.now();
14885
+ if (!force && lastContextProgressAt > 0 && now - lastContextProgressAt < 250)
14886
+ return;
14887
+ lastContextProgressAt = now;
14888
+ hub.broadcastAiStatus(topicId, {
14889
+ kind: "context_progress",
14890
+ queryId,
14891
+ assistantTokens: assistantContextTokens,
14892
+ toolTokens: toolContextTokens
14893
+ });
14894
+ };
14727
14895
  const nextSyntheticToolUseId = () => `tool-${queryId}-${++syntheticToolCounter}`;
14728
14896
  const bindToolUseId = (providerToolUseId, fallback) => {
14729
14897
  const providerId = normalizeToolUseId(providerToolUseId);
@@ -14833,6 +15001,8 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14833
15001
  const incoming = event.content;
14834
15002
  accumulatedText += incoming;
14835
15003
  pendingText += incoming;
15004
+ assistantContextTokens = estimateTextTokens(accumulatedText);
15005
+ broadcastContextProgress();
14836
15006
  break;
14837
15007
  }
14838
15008
  case "text":
@@ -14840,10 +15010,15 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14840
15010
  const incoming = event.content;
14841
15011
  accumulatedText += incoming;
14842
15012
  pendingText += incoming;
15013
+ assistantContextTokens = estimateTextTokens(accumulatedText);
15014
+ broadcastContextProgress();
14843
15015
  }
14844
15016
  break;
14845
15017
  case "tool_use":
14846
15018
  emitPendingAssistantMessage();
15019
+ toolContextTokens += estimateTextTokens(`${event.name}
15020
+ ${JSON.stringify(event.input ?? {})}`);
15021
+ broadcastContextProgress(true);
14847
15022
  if (isVisualsShowHtmlTool(event.name)) {
14848
15023
  const input = event.input;
14849
15024
  if (typeof input.html !== "string" || input.html.trim().length === 0) {
@@ -14997,6 +15172,8 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14997
15172
  }
14998
15173
  break;
14999
15174
  case "tool_result":
15175
+ toolContextTokens += estimateTextTokens(event.content);
15176
+ broadcastContextProgress(true);
15000
15177
  if (isVisualToolResultHandled(event.toolUseId))
15001
15178
  break;
15002
15179
  if (!silent) {
@@ -15042,7 +15219,7 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
15042
15219
  break;
15043
15220
  case "result":
15044
15221
  if (event.usage)
15045
- recordUsage(userId, topicTitle, event.usage);
15222
+ recordEventUsage(event.usage);
15046
15223
  {
15047
15224
  const usage = event.usage ? {
15048
15225
  input: event.usage.inputTokens,
@@ -15092,6 +15269,8 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
15092
15269
  }
15093
15270
  break;
15094
15271
  case "error":
15272
+ if (event.usage)
15273
+ recordEventUsage(event.usage);
15095
15274
  logger.warn({ topicId, queryId, agentType, model, silent, error: event.content }, "ai: provider returned error");
15096
15275
  terminalEmitted = true;
15097
15276
  errorOccurred = true;
@@ -15380,6 +15559,7 @@ __export(exports_turn_runner, {
15380
15559
  channelTranscriptSpeaker: () => channelTranscriptSpeaker,
15381
15560
  canonicalModelId: () => canonicalModelId,
15382
15561
  buildVideoHtml: () => buildVideoHtml,
15562
+ buildTurnReminderQuery: () => buildTurnReminderQuery,
15383
15563
  buildMermaidHtml: () => buildMermaidHtml,
15384
15564
  buildMentionOnlyChannelPrompt: () => buildMentionOnlyChannelPrompt,
15385
15565
  buildImageHtml: () => buildImageHtml,
@@ -15405,6 +15585,18 @@ function withDefaultPlaywright(configuredMcp, isManager) {
15405
15585
  enabled.add("background-bash");
15406
15586
  return [...enabled];
15407
15587
  }
15588
+ function buildTurnReminderQuery(agent, prompt, reminders) {
15589
+ const reminderPrompt = reminders.join(`
15590
+
15591
+ `);
15592
+ if (!reminderPrompt)
15593
+ return { prompt };
15594
+ if (agent === "maestro")
15595
+ return { prompt, ephemeralSystemPrompt: reminderPrompt };
15596
+ return { prompt: `${prompt}
15597
+
15598
+ ${reminderPrompt}` };
15599
+ }
15408
15600
  function appendSystemMessage(topicId, text2) {
15409
15601
  const message = {
15410
15602
  id: randomUUID16(),
@@ -16352,15 +16544,11 @@ function startAiTurn(params) {
16352
16544
  if (consumePlaywrightUnavailable(userId, topic.title)) {
16353
16545
  turnReminders.push("<system-reminder>Playwright browser tools are UNAVAILABLE this turn. The `mcp__playwright__*` tools have been removed from this turn's catalog because the long-lived browser MCP could not be prepared. Do not attempt to call browser tools. If browser interaction is required, ask the user to retry shortly or use a non-browser alternative.</system-reminder>");
16354
16546
  }
16355
- const effectivePrompt = turnReminders.length > 0 ? `${agentPrompt}
16356
-
16357
- ${turnReminders.join(`
16358
-
16359
- `)}` : agentPrompt;
16547
+ const reminderQuery = buildTurnReminderQuery(agentKind, agentPrompt, turnReminders);
16360
16548
  try {
16361
16549
  yield* runAgent({
16362
16550
  agent: agentKind,
16363
- prompt: effectivePrompt,
16551
+ ...reminderQuery,
16364
16552
  attachments: promptAttachments,
16365
16553
  cwd: workspaceCwd,
16366
16554
  systemPrompt,
@@ -18579,4 +18767,4 @@ export {
18579
18767
  DEFAULT_SELF_CONFIG_PRODUCT
18580
18768
  };
18581
18769
 
18582
- //# debugId=C80646F5B5A065DA64756E2164756E21
18770
+ //# debugId=814F0B0C425F56EA64756E2164756E21