talon-agent 3.33.4 → 3.34.1

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 (98) hide show
  1. package/package.json +5 -2
  2. package/src/app.ts +16 -8
  3. package/src/backend/claude-sdk/handler.ts +428 -415
  4. package/src/backend/claude-sdk/stream.ts +76 -53
  5. package/src/backend/codex/handler/message.ts +275 -366
  6. package/src/backend/codex/handler/rollout-accounting.ts +137 -0
  7. package/src/backend/openai-agents/handler/message.ts +282 -356
  8. package/src/backend/remote-server/chat-turn.ts +66 -122
  9. package/src/backend/remote-server/index.ts +4 -0
  10. package/src/backend/remote-server/mcp.ts +73 -9
  11. package/src/backend/remote-server/model-catalog/presentation.ts +269 -228
  12. package/src/backend/remote-server/sessions.ts +2 -2
  13. package/src/backend/remote-server/turn.ts +58 -55
  14. package/src/backend/shared/cache-telemetry.ts +17 -1
  15. package/src/backend/shared/handler-to-events.ts +11 -16
  16. package/src/backend/shared/index.ts +14 -15
  17. package/src/backend/shared/result-events.ts +30 -0
  18. package/src/backend/shared/turn-phases.ts +277 -0
  19. package/src/bootstrap.ts +120 -79
  20. package/src/cli/setup.ts +375 -349
  21. package/src/core/background/cron-spec.ts +273 -0
  22. package/src/core/background/heartbeat/agent.ts +167 -104
  23. package/src/core/background/triggers/exit.ts +19 -2
  24. package/src/core/background/triggers/resume.ts +14 -7
  25. package/src/core/background/triggers/state.ts +9 -0
  26. package/src/core/engine/backend-controller/pool.ts +2 -0
  27. package/src/core/engine/backend-controller/state.ts +25 -12
  28. package/src/core/engine/gateway-actions/cron.ts +28 -292
  29. package/src/core/engine/gateway-routes.ts +239 -0
  30. package/src/core/engine/gateway.ts +66 -238
  31. package/src/core/mcp-hub/child-transport.ts +215 -0
  32. package/src/core/mcp-hub/children.ts +72 -13
  33. package/src/core/mcp-hub/index.ts +32 -13
  34. package/src/core/models/active-model.ts +29 -6
  35. package/src/core/vfs/mounts/files.ts +128 -115
  36. package/src/core/weaver/shuttle.ts +33 -2
  37. package/src/core/weaver/weaver.ts +37 -6
  38. package/src/frontend/discord/callbacks/components/agent-buttons.ts +82 -0
  39. package/src/frontend/discord/callbacks/components/backend-select.ts +149 -0
  40. package/src/frontend/discord/callbacks/components/effort.ts +72 -0
  41. package/src/frontend/discord/callbacks/components/index.ts +120 -0
  42. package/src/frontend/discord/callbacks/components/metrics.ts +24 -0
  43. package/src/frontend/discord/callbacks/components/model-nav.ts +93 -0
  44. package/src/frontend/discord/callbacks/components/model-select.ts +118 -0
  45. package/src/frontend/discord/callbacks/components/model.ts +33 -0
  46. package/src/frontend/discord/callbacks/components/pulse.ts +93 -0
  47. package/src/frontend/discord/callbacks/components/settings.ts +243 -0
  48. package/src/frontend/discord/callbacks/components/types.ts +34 -0
  49. package/src/frontend/discord/callbacks/index.ts +4 -4
  50. package/src/frontend/discord/connection.ts +36 -0
  51. package/src/frontend/discord/diagnostics.ts +62 -0
  52. package/src/frontend/discord/guild-policy.ts +89 -0
  53. package/src/frontend/discord/index.ts +44 -305
  54. package/src/frontend/discord/outbound.ts +61 -0
  55. package/src/frontend/discord/ready.ts +73 -0
  56. package/src/frontend/discord/runtime.ts +55 -0
  57. package/src/frontend/native/chat-lifecycle.ts +39 -0
  58. package/src/frontend/native/chat-wire.ts +69 -0
  59. package/src/frontend/native/context.ts +106 -0
  60. package/src/frontend/native/control.ts +78 -0
  61. package/src/frontend/native/emit.ts +167 -0
  62. package/src/frontend/native/empty-chat-sweep.ts +50 -0
  63. package/src/frontend/native/handlers.ts +121 -0
  64. package/src/frontend/native/history.ts +101 -0
  65. package/src/frontend/native/index.ts +90 -1293
  66. package/src/frontend/native/media.ts +43 -0
  67. package/src/frontend/native/models.ts +221 -0
  68. package/src/frontend/native/queue.ts +47 -0
  69. package/src/frontend/native/reset.ts +50 -0
  70. package/src/frontend/native/routes/chats.ts +115 -0
  71. package/src/frontend/native/routes/daemon.ts +70 -0
  72. package/src/frontend/native/routes/host.ts +151 -0
  73. package/src/frontend/native/routes/index.ts +22 -0
  74. package/src/frontend/native/routes/mesh.ts +72 -0
  75. package/src/frontend/native/routes/models.ts +54 -0
  76. package/src/frontend/native/routes/params.ts +29 -0
  77. package/src/frontend/native/routes/pre-auth.ts +94 -0
  78. package/src/frontend/native/routes/table.ts +92 -0
  79. package/src/frontend/native/runtime.ts +109 -0
  80. package/src/frontend/native/server.ts +30 -555
  81. package/src/frontend/native/status.ts +26 -0
  82. package/src/frontend/native/tool-result.ts +48 -0
  83. package/src/frontend/native/turn.ts +341 -0
  84. package/src/frontend/telegram/admin.ts +75 -52
  85. package/src/frontend/whatsapp/access.ts +67 -0
  86. package/src/frontend/whatsapp/connection.ts +280 -0
  87. package/src/frontend/whatsapp/inbound.ts +327 -0
  88. package/src/frontend/whatsapp/index.ts +28 -599
  89. package/src/frontend/whatsapp/runtime.ts +74 -0
  90. package/src/storage/metrics.ts +18 -0
  91. package/src/storage/session-record.ts +29 -0
  92. package/src/storage/sessions.ts +24 -0
  93. package/src/storage/trigger-store.ts +8 -0
  94. package/src/util/boot-timer.ts +31 -0
  95. package/src/util/concurrency.ts +28 -0
  96. package/src/util/watchdog.ts +32 -7
  97. package/src/frontend/discord/callbacks/components.ts +0 -793
  98. package/src/frontend/discord/callbacks/shared.ts +0 -22
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Rollout-JSONL usage accounting for one Codex turn.
3
+ *
4
+ * Codex's `turn.completed.usage` is CUMULATIVE across every API call in
5
+ * the turn — never in the per-turn units the shared stream state (and
6
+ * everything downstream: /status, the companion's per-message counts)
7
+ * speaks. The rollout JSONL's totals diffed against the pre-turn baseline
8
+ * are this turn's real usage; that is the ONLY authoritative source. The
9
+ * SDK figure is a last-resort fallback when the rollout can't be read,
10
+ * and it overstates multi-call turns.
11
+ *
12
+ * The same baseline serves the throttled mid-turn poll (live /status) and
13
+ * the final settlement, which the success path and the terminal-failure
14
+ * path both run so failed turns account for the tokens they burned.
15
+ */
16
+
17
+ import type { Usage } from "@openai/codex-sdk";
18
+ import {
19
+ pushLiveUsage,
20
+ recordTokens,
21
+ type StreamState,
22
+ } from "../../shared/index.js";
23
+ import { CODEX_LIVE_POLL_INTERVAL_MS } from "../constants.js";
24
+ import {
25
+ readLastRolloutSnapshot,
26
+ type CodexRolloutSnapshot,
27
+ } from "../token-usage.js";
28
+
29
+ type RolloutTotals = NonNullable<CodexRolloutSnapshot["totals"]>;
30
+
31
+ export type RolloutAccounting = {
32
+ /** Thread id once `thread.started` lands; polls are no-ops before it. */
33
+ threadId: string | undefined;
34
+ /** Throttled mid-turn rollout tail — fire-and-forget, never throws. */
35
+ pollLive(): void;
36
+ /** Final authoritative settlement; `usage` is the SDK's fallback figure. */
37
+ settle(usage: Usage | null): Promise<void>;
38
+ };
39
+
40
+ /**
41
+ * Capture the cumulative token totals BEFORE the turn runs.
42
+ * `total_token_usage` accumulates across the whole session file, so this
43
+ * turn's usage = post-turn totals minus this baseline. Fresh threads have
44
+ * no rollout yet → zero baseline. `null` = resumed thread whose baseline
45
+ * couldn't be read.
46
+ */
47
+ export async function createRolloutAccounting(inputs: {
48
+ state: StreamState;
49
+ sessionId: string | undefined;
50
+ }): Promise<RolloutAccounting> {
51
+ const { state } = inputs;
52
+ const baseline: RolloutTotals | null = inputs.sessionId
53
+ ? ((await readLastRolloutSnapshot(inputs.sessionId).catch(() => null))
54
+ ?.totals ?? null)
55
+ : { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0 };
56
+
57
+ let pollInFlight = false;
58
+ let lastPollAt = 0;
59
+
60
+ const accounting: RolloutAccounting = {
61
+ threadId: undefined,
62
+
63
+ // The Codex CLI appends a `token_count` event to the rollout JSONL
64
+ // after every API call, so tailing it during the turn gives live
65
+ // context-fill / token / API-call stats long before `turn.completed`.
66
+ // In-flight guard — never blocks the event loop.
67
+ pollLive() {
68
+ if (!accounting.threadId || pollInFlight) return;
69
+ const now = Date.now();
70
+ if (now - lastPollAt < CODEX_LIVE_POLL_INTERVAL_MS) return;
71
+ pollInFlight = true;
72
+ lastPollAt = now;
73
+ readLastRolloutSnapshot(accounting.threadId)
74
+ .then((snap) => {
75
+ if (!snap) return;
76
+ applyContext(state, snap);
77
+ // Same delta-vs-baseline math as the final settlement, which
78
+ // recomputes and overwrites — a torn mid-turn read can't
79
+ // corrupt the committed numbers.
80
+ if (snap.totals && baseline) {
81
+ state.sdkInputTokens = Math.max(
82
+ 0,
83
+ snap.totals.inputTokens - baseline.inputTokens,
84
+ );
85
+ state.sdkOutputTokens = Math.max(
86
+ 0,
87
+ snap.totals.outputTokens - baseline.outputTokens,
88
+ );
89
+ state.sdkCacheRead = Math.max(
90
+ 0,
91
+ snap.totals.cachedInputTokens - baseline.cachedInputTokens,
92
+ );
93
+ }
94
+ pushLiveUsage(state);
95
+ })
96
+ .catch(() => {})
97
+ .finally(() => {
98
+ pollInFlight = false;
99
+ });
100
+ },
101
+
102
+ async settle(usage) {
103
+ const last = accounting.threadId
104
+ ? await readLastRolloutSnapshot(accounting.threadId).catch(() => null)
105
+ : null;
106
+ if (last) applyContext(state, last);
107
+ if (last?.totals && baseline) {
108
+ recordTokens(state, {
109
+ inputTokens: last.totals.inputTokens - baseline.inputTokens,
110
+ outputTokens: last.totals.outputTokens - baseline.outputTokens,
111
+ cacheRead: last.totals.cachedInputTokens - baseline.cachedInputTokens,
112
+ cacheWrite: 0, // Codex doesn't report cache writes
113
+ });
114
+ } else if (usage) {
115
+ recordTokens(state, {
116
+ inputTokens: usage.input_tokens,
117
+ outputTokens: usage.output_tokens,
118
+ cacheRead: usage.cached_input_tokens,
119
+ cacheWrite: 0, // Codex doesn't report cache writes
120
+ });
121
+ }
122
+ },
123
+ };
124
+ return accounting;
125
+ }
126
+
127
+ function applyContext(state: StreamState, snap: CodexRolloutSnapshot): void {
128
+ if (snap.usage) {
129
+ state.contextTokens = snap.usage.contextTokens;
130
+ if (snap.usage.contextWindow) {
131
+ state.contextWindow = snap.usage.contextWindow;
132
+ }
133
+ }
134
+ if (typeof snap.numApiCalls === "number") {
135
+ state.numApiCalls = snap.numApiCalls;
136
+ }
137
+ }