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.
- package/package.json +5 -2
- package/src/app.ts +16 -8
- package/src/backend/claude-sdk/handler.ts +428 -415
- package/src/backend/claude-sdk/stream.ts +76 -53
- package/src/backend/codex/handler/message.ts +275 -366
- package/src/backend/codex/handler/rollout-accounting.ts +137 -0
- package/src/backend/openai-agents/handler/message.ts +282 -356
- package/src/backend/remote-server/chat-turn.ts +66 -122
- package/src/backend/remote-server/index.ts +4 -0
- package/src/backend/remote-server/mcp.ts +73 -9
- package/src/backend/remote-server/model-catalog/presentation.ts +269 -228
- package/src/backend/remote-server/sessions.ts +2 -2
- package/src/backend/remote-server/turn.ts +58 -55
- package/src/backend/shared/cache-telemetry.ts +17 -1
- package/src/backend/shared/handler-to-events.ts +11 -16
- package/src/backend/shared/index.ts +14 -15
- package/src/backend/shared/result-events.ts +30 -0
- package/src/backend/shared/turn-phases.ts +277 -0
- package/src/bootstrap.ts +120 -79
- package/src/cli/setup.ts +375 -349
- package/src/core/background/cron-spec.ts +273 -0
- package/src/core/background/heartbeat/agent.ts +167 -104
- package/src/core/background/triggers/exit.ts +19 -2
- package/src/core/background/triggers/resume.ts +14 -7
- package/src/core/background/triggers/state.ts +9 -0
- package/src/core/engine/backend-controller/pool.ts +2 -0
- package/src/core/engine/backend-controller/state.ts +25 -12
- package/src/core/engine/gateway-actions/cron.ts +28 -292
- package/src/core/engine/gateway-routes.ts +239 -0
- package/src/core/engine/gateway.ts +66 -238
- package/src/core/mcp-hub/child-transport.ts +215 -0
- package/src/core/mcp-hub/children.ts +72 -13
- package/src/core/mcp-hub/index.ts +32 -13
- package/src/core/models/active-model.ts +29 -6
- package/src/core/vfs/mounts/files.ts +128 -115
- package/src/core/weaver/shuttle.ts +33 -2
- package/src/core/weaver/weaver.ts +37 -6
- package/src/frontend/discord/callbacks/components/agent-buttons.ts +82 -0
- package/src/frontend/discord/callbacks/components/backend-select.ts +149 -0
- package/src/frontend/discord/callbacks/components/effort.ts +72 -0
- package/src/frontend/discord/callbacks/components/index.ts +120 -0
- package/src/frontend/discord/callbacks/components/metrics.ts +24 -0
- package/src/frontend/discord/callbacks/components/model-nav.ts +93 -0
- package/src/frontend/discord/callbacks/components/model-select.ts +118 -0
- package/src/frontend/discord/callbacks/components/model.ts +33 -0
- package/src/frontend/discord/callbacks/components/pulse.ts +93 -0
- package/src/frontend/discord/callbacks/components/settings.ts +243 -0
- package/src/frontend/discord/callbacks/components/types.ts +34 -0
- package/src/frontend/discord/callbacks/index.ts +4 -4
- package/src/frontend/discord/connection.ts +36 -0
- package/src/frontend/discord/diagnostics.ts +62 -0
- package/src/frontend/discord/guild-policy.ts +89 -0
- package/src/frontend/discord/index.ts +44 -305
- package/src/frontend/discord/outbound.ts +61 -0
- package/src/frontend/discord/ready.ts +73 -0
- package/src/frontend/discord/runtime.ts +55 -0
- package/src/frontend/native/chat-lifecycle.ts +39 -0
- package/src/frontend/native/chat-wire.ts +69 -0
- package/src/frontend/native/context.ts +106 -0
- package/src/frontend/native/control.ts +78 -0
- package/src/frontend/native/emit.ts +167 -0
- package/src/frontend/native/empty-chat-sweep.ts +50 -0
- package/src/frontend/native/handlers.ts +121 -0
- package/src/frontend/native/history.ts +101 -0
- package/src/frontend/native/index.ts +90 -1293
- package/src/frontend/native/media.ts +43 -0
- package/src/frontend/native/models.ts +221 -0
- package/src/frontend/native/queue.ts +47 -0
- package/src/frontend/native/reset.ts +50 -0
- package/src/frontend/native/routes/chats.ts +115 -0
- package/src/frontend/native/routes/daemon.ts +70 -0
- package/src/frontend/native/routes/host.ts +151 -0
- package/src/frontend/native/routes/index.ts +22 -0
- package/src/frontend/native/routes/mesh.ts +72 -0
- package/src/frontend/native/routes/models.ts +54 -0
- package/src/frontend/native/routes/params.ts +29 -0
- package/src/frontend/native/routes/pre-auth.ts +94 -0
- package/src/frontend/native/routes/table.ts +92 -0
- package/src/frontend/native/runtime.ts +109 -0
- package/src/frontend/native/server.ts +30 -555
- package/src/frontend/native/status.ts +26 -0
- package/src/frontend/native/tool-result.ts +48 -0
- package/src/frontend/native/turn.ts +341 -0
- package/src/frontend/telegram/admin.ts +75 -52
- package/src/frontend/whatsapp/access.ts +67 -0
- package/src/frontend/whatsapp/connection.ts +280 -0
- package/src/frontend/whatsapp/inbound.ts +327 -0
- package/src/frontend/whatsapp/index.ts +28 -599
- package/src/frontend/whatsapp/runtime.ts +74 -0
- package/src/storage/metrics.ts +18 -0
- package/src/storage/session-record.ts +29 -0
- package/src/storage/sessions.ts +24 -0
- package/src/storage/trigger-store.ts +8 -0
- package/src/util/boot-timer.ts +31 -0
- package/src/util/concurrency.ts +28 -0
- package/src/util/watchdog.ts +32 -7
- package/src/frontend/discord/callbacks/components.ts +0 -793
- 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
|
+
}
|