talon-agent 4.6.1 → 5.0.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/README.md +3 -3
- package/package.json +2 -1
- package/prompts/README.md +2 -2
- package/prompts/system/memory-recall.md +16 -0
- package/src/app.ts +22 -7
- package/src/backend/claude-sdk/factory.ts +21 -41
- package/src/backend/claude-sdk/handler.ts +28 -7
- package/src/backend/claude-sdk/host/in-process.ts +147 -0
- package/src/backend/claude-sdk/one-shot.ts +1 -1
- package/src/backend/claude-sdk/options.ts +7 -6
- package/src/backend/claude-sdk/stream.ts +30 -3
- package/src/backend/claude-sdk/warm.ts +1 -1
- package/src/backend/codex/constants.ts +1 -1
- package/src/backend/codex/factory.ts +2 -2
- package/src/backend/codex/handler/events.ts +1 -1
- package/src/backend/codex/handler/message.ts +26 -12
- package/src/backend/codex/handler/rollout-accounting.ts +1 -1
- package/src/backend/codex/init.ts +1 -1
- package/src/backend/codex/mcp-config.ts +2 -2
- package/src/backend/codex/one-shot.ts +1 -1
- package/src/backend/kilo/handler/message.ts +4 -1
- package/src/backend/openai-agents/constants.ts +1 -1
- package/src/backend/openai-agents/factory.ts +2 -2
- package/src/backend/openai-agents/handler/events.ts +1 -1
- package/src/backend/openai-agents/handler/message.ts +8 -4
- package/src/backend/openai-agents/init.ts +1 -1
- package/src/backend/openai-agents/mcp-pool.ts +2 -2
- package/src/backend/opencode/handler/message.ts +4 -1
- package/src/backend/remote-server/chat-turn.ts +31 -23
- package/src/backend/remote-server/events.ts +3 -3
- package/src/backend/remote-server/factory.ts +6 -3
- package/src/backend/remote-server/index.ts +1 -1
- package/src/backend/remote-server/mcp.ts +1 -1
- package/src/backend/remote-server/one-shot.ts +1 -1
- package/src/backend/remote-server/server-bindings.ts +1 -1
- package/src/backend/remote-server/turn.ts +1 -1
- package/src/backend/runtime/cache/cache-metrics.ts +126 -0
- package/src/backend/{shared → runtime/cache}/cache-telemetry.ts +22 -2
- package/src/backend/{shared → runtime}/index.ts +34 -25
- package/src/backend/{shared → runtime/prompt}/delivery-contract.ts +1 -1
- package/src/backend/{shared → runtime/prompt}/prompt-format.ts +46 -2
- package/src/backend/{shared → runtime/prompt}/system-prompt.ts +4 -4
- package/src/backend/{shared → runtime/turn}/delivered-text.ts +1 -1
- package/src/backend/{shared → runtime/turn}/delivery.ts +3 -3
- package/src/backend/{shared → runtime/turn}/handle-retry.ts +5 -5
- package/src/backend/{shared → runtime/turn}/handler-to-events.ts +24 -10
- package/src/backend/{shared → runtime/turn}/handler-types.ts +7 -1
- package/src/backend/{shared → runtime/turn}/model-retry.ts +2 -2
- package/src/backend/{shared → runtime/turn}/result-events.ts +2 -2
- package/src/backend/{shared → runtime/turn}/stream-state.ts +2 -2
- package/src/backend/{shared → runtime/turn}/turn-interrupt.ts +2 -2
- package/src/backend/{shared → runtime/turn}/turn-phases.ts +6 -6
- package/src/bootstrap.ts +6 -21
- package/src/cli.ts +6 -3
- package/src/core/agent-runtime/README.md +15 -0
- package/src/core/agent-runtime/agent-host.ts +387 -0
- package/src/core/agent-runtime/capabilities.ts +11 -0
- package/src/core/agent-runtime/contract-tests.ts +92 -1
- package/src/core/agent-runtime/events.ts +1 -1
- package/src/core/background/{isolated-agent.ts → cron/isolated-agent.ts} +3 -3
- package/src/core/background/{job-health.ts → cron/job-health.ts} +1 -1
- package/src/core/background/{job-oneshot.ts → cron/job-oneshot.ts} +5 -5
- package/src/core/background/{job-prompt.ts → cron/job-prompt.ts} +1 -1
- package/src/core/background/{cron.ts → cron/scheduler.ts} +6 -6
- package/src/core/background/{cron-spec.ts → cron/spec.ts} +1 -1
- package/src/core/background/{dream.ts → dream/index.ts} +10 -15
- package/src/core/background/{plan-alerts.ts → pulse/plan-alerts.ts} +3 -3
- package/src/core/background/{pulse.ts → pulse/pulse.ts} +8 -5
- package/src/core/background/triggers/command.ts +2 -2
- package/src/{util → core/config}/harden.ts +1 -1
- package/src/core/config/index.ts +16 -12
- package/src/{util → core/daemon}/boot-timer.ts +15 -1
- package/src/core/daemon/pidfile.ts +1 -1
- package/src/core/daemon/resource-sampler.ts +121 -0
- package/src/{util → core/daemon}/respawn.ts +1 -1
- package/src/core/doctor/index.ts +1 -1
- package/src/core/engine/dispatcher.ts +16 -0
- package/src/core/engine/gateway-actions/cron.ts +2 -2
- package/src/core/engine/gateway-actions/fetch-url.ts +1 -1
- package/src/core/engine/gateway-actions/index.ts +4 -1
- package/src/core/engine/gateway-actions/memory.ts +335 -0
- package/src/core/engine/gateway-actions/native/exec-background.ts +129 -0
- package/src/core/engine/gateway-actions/native/exec-remote.ts +85 -0
- package/src/core/engine/gateway-actions/native/exec.ts +182 -0
- package/src/core/engine/gateway-actions/native/index.ts +46 -0
- package/src/core/engine/gateway-actions/native/params.ts +46 -0
- package/src/core/engine/gateway-actions/native/read.ts +182 -0
- package/src/core/engine/gateway-actions/native/results.ts +34 -0
- package/src/core/engine/gateway-actions/native/search.ts +212 -0
- package/src/core/engine/gateway-actions/native/shell.ts +39 -0
- package/src/core/engine/gateway-actions/native/teleport.ts +55 -0
- package/src/core/engine/gateway-actions/native/write.ts +170 -0
- package/src/core/engine/gateway.ts +0 -6
- package/src/core/frontend-runtime/builtins.ts +2 -2
- package/src/{util → core/frontend-runtime}/chat-id.ts +30 -0
- package/src/core/mcp-hub/index.ts +1 -1
- package/src/core/mcp-hub/talon-server.ts +1 -1
- package/src/core/memory/import.ts +3 -2
- package/src/core/memory/taps.ts +199 -0
- package/src/core/memory/turn-retrieval.ts +222 -0
- package/src/core/plugin/mcp.ts +1 -1
- package/src/core/prompt/assemble.ts +2 -12
- package/src/core/prompt/index.ts +2 -2
- package/src/core/prompt/invalidation.ts +1 -1
- package/src/core/{scripting/lua-runner.ts → scripts/lua.ts} +1 -1
- package/src/core/tasks/index.ts +1 -1
- package/src/core/tools/{chat.ts → chat/chat.ts} +1 -1
- package/src/core/tools/{cross-send.ts → chat/cross-send.ts} +1 -1
- package/src/core/tools/{history.ts → chat/history.ts} +2 -2
- package/src/core/tools/{media.ts → chat/media.ts} +1 -1
- package/src/core/tools/{members.ts → chat/members.ts} +2 -2
- package/src/core/tools/{messaging.ts → chat/messaging.ts} +2 -2
- package/src/core/tools/{moderation.ts → chat/moderation.ts} +2 -2
- package/src/core/tools/{stickers.ts → chat/stickers.ts} +2 -2
- package/src/core/tools/{whatsapp.ts → chat/whatsapp.ts} +1 -1
- package/src/core/tools/content/memory.ts +128 -0
- package/src/core/tools/{web.ts → content/web.ts} +1 -1
- package/src/core/tools/index.ts +21 -19
- package/src/core/tools/{admin.ts → ops/admin.ts} +1 -1
- package/src/core/tools/{bridge.ts → ops/bridge.ts} +2 -2
- package/src/core/tools/{goals.ts → ops/goals.ts} +2 -2
- package/src/core/tools/{mesh.ts → ops/mesh.ts} +1 -1
- package/src/core/tools/{models.ts → ops/models.ts} +1 -1
- package/src/core/tools/{native.ts → ops/native.ts} +1 -1
- package/src/core/tools/{scheduling.ts → ops/scheduling.ts} +1 -1
- package/src/core/tools/{scripts.ts → ops/scripts.ts} +1 -1
- package/src/core/tools/{skills.ts → ops/skills.ts} +1 -1
- package/src/core/tools/{triggers.ts → ops/triggers.ts} +1 -1
- package/src/core/tools/types.ts +1 -0
- package/src/{util → core/vfs}/workspace.ts +2 -2
- package/src/core/weaver/turn-cpu.ts +32 -0
- package/src/core/weaver/weaver.ts +36 -0
- package/src/frontend/discord/admin.ts +1 -1
- package/src/frontend/discord/callbacks/components/backend-select.ts +1 -1
- package/src/frontend/discord/callbacks/components/effort.ts +1 -1
- package/src/frontend/discord/callbacks/components/index.ts +1 -1
- package/src/frontend/discord/callbacks/components/pulse.ts +1 -1
- package/src/frontend/discord/callbacks/components/settings.ts +2 -2
- package/src/frontend/discord/callbacks/modals.ts +4 -1
- package/src/frontend/discord/commands/admin.ts +2 -36
- package/src/frontend/discord/commands/definitions.ts +0 -11
- package/src/frontend/discord/commands/info.ts +1 -1
- package/src/frontend/discord/commands/interaction.ts +1 -1
- package/src/frontend/discord/commands/router.ts +0 -3
- package/src/frontend/discord/commands/session.ts +8 -2
- package/src/frontend/discord/commands/settings.ts +2 -2
- package/src/frontend/discord/handlers/messages.ts +1 -1
- package/src/frontend/discord/handlers/state.ts +1 -1
- package/src/frontend/discord/middleware.ts +2 -26
- package/src/frontend/discord/ready.ts +1 -1
- package/src/frontend/discord/render.ts +41 -259
- package/src/frontend/discord/runtime.ts +1 -2
- package/src/frontend/native/{auth.ts → bridge/auth.ts} +2 -2
- package/src/frontend/native/{discovery.ts → bridge/discovery.ts} +3 -3
- package/src/frontend/native/{routes → bridge/routes}/chats.ts +1 -1
- package/src/frontend/native/{routes → bridge/routes}/daemon.ts +1 -1
- package/src/frontend/native/{routes → bridge/routes}/host.ts +6 -3
- package/src/frontend/native/{routes → bridge/routes}/pre-auth.ts +1 -1
- package/src/frontend/native/{server.ts → bridge/server.ts} +3 -3
- package/src/frontend/native/{tls.ts → bridge/tls.ts} +2 -2
- package/src/frontend/native/{chat-lifecycle.ts → chats/chat-lifecycle.ts} +3 -3
- package/src/frontend/native/{chat-wire.ts → chats/chat-wire.ts} +4 -4
- package/src/frontend/native/{chats.ts → chats/chats.ts} +4 -4
- package/src/frontend/native/{empty-chat-sweep.ts → chats/empty-chat-sweep.ts} +4 -4
- package/src/frontend/native/{history.ts → chats/history.ts} +7 -7
- package/src/frontend/native/{reset.ts → chats/reset.ts} +7 -7
- package/src/frontend/native/index.ts +13 -10
- package/src/frontend/native/{media.ts → media/media.ts} +3 -3
- package/src/frontend/native/runtime.ts +1 -1
- package/src/frontend/native/{control.ts → surface/control.ts} +4 -4
- package/src/frontend/native/{extensions.ts → surface/extensions.ts} +12 -9
- package/src/frontend/native/{handlers.ts → surface/handlers.ts} +19 -14
- package/src/frontend/native/{logs.ts → surface/logs.ts} +2 -2
- package/src/frontend/native/{memory.ts → surface/memory.ts} +2 -2
- package/src/frontend/native/{models.ts → surface/models.ts} +17 -10
- package/src/frontend/native/{settings.ts → surface/settings.ts} +9 -9
- package/src/frontend/native/{status.ts → surface/status.ts} +3 -3
- package/src/frontend/native/{actions.ts → turn/actions.ts} +7 -4
- package/src/frontend/native/{context.ts → turn/context.ts} +8 -8
- package/src/frontend/native/{emit.ts → turn/emit.ts} +7 -7
- package/src/frontend/native/{queue.ts → turn/queue.ts} +3 -3
- package/src/frontend/native/{turn-meta.ts → turn/turn-meta.ts} +2 -2
- package/src/frontend/native/{turn.ts → turn/turn.ts} +9 -9
- package/src/frontend/{shared → presentation}/format.ts +4 -3
- package/src/frontend/{shared → presentation}/model-commands.ts +1 -1
- package/src/frontend/{shared → presentation}/reasoning-levels.ts +12 -0
- package/src/frontend/presentation/reports.ts +493 -0
- package/src/frontend/{shared → presentation}/session-status.ts +36 -9
- package/src/frontend/{shared → presentation}/status-context.ts +101 -2
- package/src/frontend/teams/commands.ts +2 -2
- package/src/frontend/teams/turn.ts +1 -1
- package/src/frontend/telegram/admin/background.ts +1 -1
- package/src/frontend/telegram/admin/health.ts +1 -1
- package/src/frontend/telegram/admin/sessions.ts +1 -1
- package/src/frontend/telegram/callbacks/effort.ts +2 -2
- package/src/frontend/telegram/callbacks/metrics.ts +1 -1
- package/src/frontend/telegram/callbacks/model/backend.ts +1 -1
- package/src/frontend/telegram/callbacks/model/views.ts +1 -1
- package/src/frontend/telegram/callbacks/pulse.ts +1 -1
- package/src/frontend/telegram/callbacks/query.ts +1 -1
- package/src/frontend/telegram/callbacks/settings.ts +3 -3
- package/src/frontend/telegram/commands/admin.ts +6 -41
- package/src/frontend/telegram/commands/index.ts +1 -1
- package/src/frontend/telegram/commands/info.ts +2 -2
- package/src/frontend/telegram/commands/session.ts +9 -3
- package/src/frontend/telegram/commands/settings.ts +5 -3
- package/src/frontend/telegram/handlers/messages.ts +0 -10
- package/src/frontend/telegram/handlers/state.ts +1 -1
- package/src/frontend/telegram/index.ts +1 -5
- package/src/frontend/telegram/middleware.ts +1 -15
- package/src/frontend/telegram/model-menu.ts +1 -1
- package/src/frontend/telegram/render/html.ts +30 -0
- package/src/frontend/telegram/{helpers → render}/menu.ts +46 -19
- package/src/frontend/telegram/render/reports.ts +182 -0
- package/src/frontend/terminal/builtins/context.ts +2 -2
- package/src/frontend/terminal/builtins/session.ts +1 -1
- package/src/frontend/terminal/builtins/status.ts +2 -2
- package/src/frontend/terminal/index.ts +2 -2
- package/src/frontend/terminal/renderer.ts +1 -1
- package/src/frontend/whatsapp/access.ts +2 -2
- package/src/frontend/whatsapp/actions/history.ts +2 -2
- package/src/frontend/whatsapp/actions/messaging.ts +2 -2
- package/src/frontend/whatsapp/actions/moderation.ts +1 -1
- package/src/frontend/whatsapp/actions/send.ts +1 -1
- package/src/frontend/whatsapp/commands.ts +12 -6
- package/src/frontend/whatsapp/{connection.ts → connection/connection.ts} +5 -5
- package/src/frontend/whatsapp/{pairing-service.ts → connection/pairing-service.ts} +3 -3
- package/src/frontend/whatsapp/{wa-logger.ts → connection/wa-logger.ts} +2 -2
- package/src/frontend/whatsapp/index.ts +4 -4
- package/src/frontend/whatsapp/{inbound.ts → messages/inbound.ts} +15 -15
- package/src/frontend/whatsapp/{media-store.ts → messages/media-store.ts} +4 -4
- package/src/frontend/whatsapp/{message-store.ts → messages/message-store.ts} +1 -1
- package/src/frontend/whatsapp/{turn-recovery.ts → messages/turn-recovery.ts} +4 -4
- package/src/frontend/whatsapp/registry.ts +2 -2
- package/src/frontend/whatsapp/runtime.ts +1 -1
- package/src/index.ts +6 -3
- package/src/storage/db.ts +6 -1
- package/src/storage/memory.ts +59 -8
- package/src/storage/metrics.ts +38 -0
- package/src/storage/repositories/sessions-repo.ts +6 -0
- package/src/storage/session-record.ts +13 -2
- package/src/storage/sessions.ts +12 -0
- package/src/storage/sql/db.sql +5 -0
- package/src/storage/sql/schema.sql +4 -0
- package/src/storage/sql/sessions.sql +3 -3
- package/src/storage/sql/statements.generated.ts +10 -3
- package/src/storage/sql/turn-meta.sql +1 -1
- package/src/util/log.ts +1 -1
- package/src/util/paths.ts +0 -2
- package/src/util/runtime.ts +1 -1
- package/src/core/engine/gateway-actions/native.ts +0 -1035
- package/src/core/soul/README.md +0 -110
- package/src/core/soul/RESEARCH.md +0 -98
- package/src/core/soul/associative.ts +0 -98
- package/src/core/soul/centrality.ts +0 -98
- package/src/core/soul/cluster.ts +0 -83
- package/src/core/soul/compiler.ts +0 -207
- package/src/core/soul/consolidate.ts +0 -179
- package/src/core/soul/critic.ts +0 -162
- package/src/core/soul/dag.ts +0 -265
- package/src/core/soul/delta.ts +0 -123
- package/src/core/soul/drift.ts +0 -99
- package/src/core/soul/embedder.ts +0 -129
- package/src/core/soul/emergent-critic.ts +0 -96
- package/src/core/soul/forgetting.ts +0 -131
- package/src/core/soul/governance.ts +0 -93
- package/src/core/soul/hash.ts +0 -97
- package/src/core/soul/hdc.ts +0 -154
- package/src/core/soul/kernel.ts +0 -540
- package/src/core/soul/lattice.ts +0 -103
- package/src/core/soul/lens.ts +0 -110
- package/src/core/soul/projector.ts +0 -240
- package/src/core/soul/reflect.ts +0 -170
- package/src/core/soul/reflex.ts +0 -164
- package/src/core/soul/retrieve.ts +0 -146
- package/src/core/soul/salience.ts +0 -146
- package/src/core/soul/service.ts +0 -204
- package/src/core/soul/settings.ts +0 -47
- package/src/core/soul/signals.ts +0 -117
- package/src/core/soul/talon-embedder.ts +0 -80
- package/src/core/soul/taps.ts +0 -199
- package/src/core/soul/types.ts +0 -298
- package/src/core/soul/valence.ts +0 -83
- package/src/frontend/telegram/helpers/diagnostics.ts +0 -428
- package/src/frontend/telegram/helpers/format.ts +0 -42
- package/src/frontend/telegram/helpers/index.ts +0 -13
- package/src/util/cleanup-registry.ts +0 -36
- /package/src/backend/{shared → runtime}/frontends.ts +0 -0
- /package/src/backend/{shared → runtime}/metrics.ts +0 -0
- /package/src/backend/{shared → runtime}/sleep.ts +0 -0
- /package/src/backend/{shared → runtime/turn}/flow-violation.ts +0 -0
- /package/src/backend/{shared → runtime}/usage.ts +0 -0
- /package/src/{util/mcp-launcher.ts → core/mcp-hub/launcher.ts} +0 -0
- /package/src/{util → core/tools/content}/web-content.ts +0 -0
- /package/src/core/tools/{mcp-env.ts → ops/mcp-env.ts} +0 -0
- /package/src/{util → core/weaver}/session-name.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/index.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/memory.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/mesh.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/models.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/params.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/table.ts +0 -0
- /package/src/frontend/native/{tool-result.ts → turn/tool-result.ts} +0 -0
- /package/src/frontend/{shared → presentation}/access.ts +0 -0
- /package/src/frontend/{shared → presentation}/plan-usage-report.ts +0 -0
- /package/src/frontend/whatsapp/{auth-state.ts → connection/auth-state.ts} +0 -0
- /package/src/frontend/whatsapp/{identity.ts → connection/identity.ts} +0 -0
- /package/src/frontend/whatsapp/{pairing-lock.ts → connection/pairing-lock.ts} +0 -0
- /package/src/frontend/whatsapp/{pairing.ts → connection/pairing.ts} +0 -0
- /package/src/frontend/whatsapp/{pins.ts → messages/pins.ts} +0 -0
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
* `codex.resumeThread(id)`, the rollout-JSONL live/settle usage accounting
|
|
8
8
|
* (`rollout-accounting.ts`), and the ChatGPT-OAuth model-mismatch recovery
|
|
9
9
|
* ladder. The post-stream phases are the shared ones in
|
|
10
|
-
* `backend/
|
|
10
|
+
* `backend/runtime/turn/turn-phases.ts`.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { Thread, Usage } from "@openai/codex-sdk";
|
|
14
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
QueryParams,
|
|
16
|
+
QueryResult,
|
|
17
|
+
} from "../../runtime/turn/handler-types.js";
|
|
15
18
|
import {
|
|
16
19
|
getSession,
|
|
17
20
|
incrementTurns,
|
|
@@ -37,7 +40,7 @@ import {
|
|
|
37
40
|
nameSessionFromFirstMessage,
|
|
38
41
|
finishCallbackTurn,
|
|
39
42
|
type StreamState,
|
|
40
|
-
} from "../../
|
|
43
|
+
} from "../../runtime/index.js";
|
|
41
44
|
|
|
42
45
|
import {
|
|
43
46
|
codexSystemPromptSuffix,
|
|
@@ -48,7 +51,7 @@ import {
|
|
|
48
51
|
import {
|
|
49
52
|
frontendsForChat,
|
|
50
53
|
nonTerminalFrontends,
|
|
51
|
-
} from "../../
|
|
54
|
+
} from "../../runtime/frontends.js";
|
|
52
55
|
import { getState } from "../state.js";
|
|
53
56
|
import { ensureCodex, getCodexAuthInfo } from "../init.js";
|
|
54
57
|
import {
|
|
@@ -213,6 +216,23 @@ async function maybeFallbackForChatGptMismatch(
|
|
|
213
216
|
* ChatGPT-OAuth account is swapped pre-emptively rather than letting the
|
|
214
217
|
* first turn fail.
|
|
215
218
|
*/
|
|
219
|
+
/**
|
|
220
|
+
* The turn's user prompt: the shared framing every backend emits, plus
|
|
221
|
+
* whatever this turn's memory retrieval produced. `formatUserPrompt` is
|
|
222
|
+
* the one place `retrievedMemory` is rendered — see
|
|
223
|
+
* `backend/runtime/prompt/prompt-format.ts`.
|
|
224
|
+
*/
|
|
225
|
+
function buildTurnPrompt(params: QueryParams): string {
|
|
226
|
+
return formatUserPrompt({
|
|
227
|
+
text: params.text,
|
|
228
|
+
senderName: params.senderName ?? "user",
|
|
229
|
+
senderHandle: params.senderHandle,
|
|
230
|
+
isGroup: params.isGroup,
|
|
231
|
+
messageId: params.messageId,
|
|
232
|
+
retrievedMemory: params.retrievedMemory,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
216
236
|
function resolveCodexModel(chatId: string, requested: string | undefined) {
|
|
217
237
|
const authInfo = getCodexAuthInfo();
|
|
218
238
|
const authAwareDefault =
|
|
@@ -409,7 +429,7 @@ export async function handleMessage(
|
|
|
409
429
|
}
|
|
410
430
|
const codex = ensureCodex(params.chatId);
|
|
411
431
|
|
|
412
|
-
const { chatId, text, senderName,
|
|
432
|
+
const { chatId, text, senderName, isGroup } = params;
|
|
413
433
|
const t0 = Date.now();
|
|
414
434
|
const session = getSession(chatId);
|
|
415
435
|
const previousTurns = session.turns;
|
|
@@ -432,13 +452,7 @@ export async function handleMessage(
|
|
|
432
452
|
sessionEpoch: session.createdAt,
|
|
433
453
|
});
|
|
434
454
|
|
|
435
|
-
const prompt =
|
|
436
|
-
text,
|
|
437
|
-
senderName: senderName ?? "user",
|
|
438
|
-
senderHandle,
|
|
439
|
-
isGroup,
|
|
440
|
-
messageId,
|
|
441
|
-
});
|
|
455
|
+
const prompt = buildTurnPrompt(params);
|
|
442
456
|
|
|
443
457
|
log("agent", `[${chatId}] <- (${text.length} chars)`);
|
|
444
458
|
traceMessage(chatId, "in", text, { senderName, isGroup });
|
|
@@ -25,7 +25,7 @@ import { Codex } from "@openai/codex-sdk";
|
|
|
25
25
|
import type { TalonConfig } from "../../core/config/index.js";
|
|
26
26
|
import type { FrontendName } from "../../core/agent-runtime/backend-registry.js";
|
|
27
27
|
import { log, logWarn } from "../../util/log.js";
|
|
28
|
-
import { nonTerminalFrontends } from "../
|
|
28
|
+
import { nonTerminalFrontends } from "../runtime/frontends.js";
|
|
29
29
|
import { getState } from "./state.js";
|
|
30
30
|
import { asCodexConfig, buildCodexMcpServers } from "./mcp-config.js";
|
|
31
31
|
import { detectCodexAuth, type CodexAuthInfo } from "./auth.js";
|
|
@@ -29,8 +29,8 @@ import {
|
|
|
29
29
|
pluginHubUrl,
|
|
30
30
|
hubPluginServerNames,
|
|
31
31
|
} from "../../core/mcp-hub/index.js";
|
|
32
|
-
import type { ToolExclusionConfig } from "../../core/tools/mcp-env.js";
|
|
33
|
-
import { frontendsForChat } from "../
|
|
32
|
+
import type { ToolExclusionConfig } from "../../core/tools/ops/mcp-env.js";
|
|
33
|
+
import { frontendsForChat } from "../runtime/frontends.js";
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* AppToolApproval values accepted by Codex's `mcp_servers.<name>` table.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import type { OneShotAgentParams, OneShotUsage } from "../../core/types.js";
|
|
21
21
|
import { log, logWarn } from "../../util/log.js";
|
|
22
|
-
import { appendBackendSuffix } from "../
|
|
22
|
+
import { appendBackendSuffix } from "../runtime/index.js";
|
|
23
23
|
import { ensureCodex, getCodexAuthInfo } from "./init.js";
|
|
24
24
|
import {
|
|
25
25
|
CODEX_SYSTEM_PROMPT_SUFFIX,
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* Kilo's server bindings.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
QueryParams,
|
|
8
|
+
QueryResult,
|
|
9
|
+
} from "../../runtime/turn/handler-types.js";
|
|
7
10
|
import { runRemoteChatTurn } from "../../remote-server/chat-turn.js";
|
|
8
11
|
import {
|
|
9
12
|
ensureServer,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* orchestration) with MCP servers wired from the plugin system.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { buildDeliveryContract } from "../
|
|
13
|
+
import { buildDeliveryContract } from "../runtime/prompt/delivery-contract.js";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Agents-specific addendum to the shared tool-only delivery contract:
|
|
@@ -13,8 +13,8 @@ import { registerBackend } from "../../core/agent-runtime/backend-registry.js";
|
|
|
13
13
|
import { openAIAgentsDoctorChecks } from "./doctor.js";
|
|
14
14
|
import type { BackendFactory } from "../../core/agent-runtime/backend-registry.js";
|
|
15
15
|
import { log } from "../../util/log.js";
|
|
16
|
-
import { handlerToEvents } from "../
|
|
17
|
-
import { interruptChatTurn } from "../
|
|
16
|
+
import { handlerToEvents } from "../runtime/turn/handler-to-events.js";
|
|
17
|
+
import { interruptChatTurn } from "../runtime/turn/turn-interrupt.js";
|
|
18
18
|
import {
|
|
19
19
|
composeBackend,
|
|
20
20
|
type ChatBackend,
|
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
* MCP bundle, iterating the `StreamedRunResult` (see `events.ts`), and
|
|
7
7
|
* `.cancel()` on terminator. The post-stream phases — accounting, the
|
|
8
8
|
* trailing-prose flow-violation retry, the result — are the shared ones in
|
|
9
|
-
* `backend/
|
|
9
|
+
* `backend/runtime/turn/turn-phases.ts`.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { Agent, run } from "@openai/agents";
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
QueryParams,
|
|
15
|
+
QueryResult,
|
|
16
|
+
} from "../../runtime/turn/handler-types.js";
|
|
14
17
|
import { getSession, incrementTurns } from "../../../storage/sessions.js";
|
|
15
18
|
import { getChatSettings } from "../../../storage/chat-settings.js";
|
|
16
19
|
import { log, logError, logWarn } from "../../../util/log.js";
|
|
@@ -33,7 +36,7 @@ import {
|
|
|
33
36
|
enforceTrailingProse,
|
|
34
37
|
finishCallbackTurn,
|
|
35
38
|
type StreamState,
|
|
36
|
-
} from "../../
|
|
39
|
+
} from "../../runtime/index.js";
|
|
37
40
|
|
|
38
41
|
import {
|
|
39
42
|
buildOpenAiAgentsSuffix,
|
|
@@ -43,7 +46,7 @@ import {
|
|
|
43
46
|
} from "../constants.js";
|
|
44
47
|
import { getState, getOrCreateSession } from "../state.js";
|
|
45
48
|
import { getActiveFrontends } from "../init.js";
|
|
46
|
-
import { frontendsForChat } from "../../
|
|
49
|
+
import { frontendsForChat } from "../../runtime/frontends.js";
|
|
47
50
|
import { getOrCreateBundle } from "../mcp-pool.js";
|
|
48
51
|
import { OPENAI_AGENTS_BUILTIN_TOOLS } from "../builtins.js";
|
|
49
52
|
import { activeAborts } from "./state.js";
|
|
@@ -105,6 +108,7 @@ function buildTurnPrompt(
|
|
|
105
108
|
senderHandle: params.senderHandle,
|
|
106
109
|
isGroup: params.isGroup,
|
|
107
110
|
messageId: params.messageId,
|
|
111
|
+
retrievedMemory: params.retrievedMemory,
|
|
108
112
|
});
|
|
109
113
|
if (frontend && previousTurns === 0 && !isRetry) {
|
|
110
114
|
prompt += `\n\n${buildFirstTurnReminder(frontend)}`;
|
|
@@ -46,7 +46,7 @@ import { setDefaultOpenAIClient, setOpenAIAPI } from "@openai/agents";
|
|
|
46
46
|
import type { TalonConfig } from "../../core/config/index.js";
|
|
47
47
|
import type { FrontendName } from "../../core/agent-runtime/backend-registry.js";
|
|
48
48
|
import { log, logWarn } from "../../util/log.js";
|
|
49
|
-
import { nonTerminalFrontends } from "../
|
|
49
|
+
import { nonTerminalFrontends } from "../runtime/frontends.js";
|
|
50
50
|
import { getState } from "./state.js";
|
|
51
51
|
import { startDiscovery } from "./discovery.js";
|
|
52
52
|
|
|
@@ -30,8 +30,8 @@ import {
|
|
|
30
30
|
pluginHubUrl,
|
|
31
31
|
hubPluginServerNames,
|
|
32
32
|
} from "../../core/mcp-hub/index.js";
|
|
33
|
-
import type { ToolExclusionConfig } from "../../core/tools/mcp-env.js";
|
|
34
|
-
import { frontendsForChat } from "../
|
|
33
|
+
import type { ToolExclusionConfig } from "../../core/tools/ops/mcp-env.js";
|
|
34
|
+
import { frontendsForChat } from "../runtime/frontends.js";
|
|
35
35
|
import { log, logWarn } from "../../util/log.js";
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* bound to OpenCode's server bindings.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
QueryParams,
|
|
8
|
+
QueryResult,
|
|
9
|
+
} from "../../runtime/turn/handler-types.js";
|
|
7
10
|
import { runRemoteChatTurn } from "../../remote-server/chat-turn.js";
|
|
8
11
|
import {
|
|
9
12
|
ensureServer,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Resolves the active model against the server's catalog, makes sure the
|
|
6
6
|
* server, session, and this chat's MCP servers exist, builds the prompt
|
|
7
7
|
* pair, drives the turn (`./turn.ts`), then runs the shared post-turn
|
|
8
|
-
* phases (`backend/
|
|
8
|
+
* phases (`backend/runtime/turn/turn-phases.ts`) with the one family-specific
|
|
9
9
|
* step in between: the usage fallback from the session summary.
|
|
10
10
|
*
|
|
11
11
|
* Kilo and OpenCode ran byte-for-byte copies of this (modulo the backend
|
|
@@ -18,8 +18,14 @@ import { getSession, incrementTurns } from "../../storage/sessions.js";
|
|
|
18
18
|
import { getChatSettings } from "../../storage/chat-settings.js";
|
|
19
19
|
import { log, logError } from "../../util/log.js";
|
|
20
20
|
import { traceMessage } from "../../util/trace.js";
|
|
21
|
-
import type {
|
|
22
|
-
|
|
21
|
+
import type {
|
|
22
|
+
QueryParams,
|
|
23
|
+
QueryResult,
|
|
24
|
+
} from "../runtime/turn/handler-types.js";
|
|
25
|
+
import {
|
|
26
|
+
frontendsForChat,
|
|
27
|
+
nonTerminalFrontends,
|
|
28
|
+
} from "../runtime/frontends.js";
|
|
23
29
|
import {
|
|
24
30
|
createStreamState,
|
|
25
31
|
recordTokens,
|
|
@@ -33,7 +39,7 @@ import {
|
|
|
33
39
|
accountFailedTurn,
|
|
34
40
|
nameSessionFromFirstMessage,
|
|
35
41
|
finishCallbackTurn,
|
|
36
|
-
} from "../
|
|
42
|
+
} from "../runtime/index.js";
|
|
37
43
|
import type { RemoteAgentClient } from "./client.js";
|
|
38
44
|
import type { RemoteServerBindings } from "./server-bindings.js";
|
|
39
45
|
import { getTurnSummary, type RemoteSessionClient } from "./session-helpers.js";
|
|
@@ -68,16 +74,7 @@ export async function runRemoteChatTurn<TClient extends RemoteAgentClient>(
|
|
|
68
74
|
const config = bindings.getConfig();
|
|
69
75
|
if (!config) throw new Error(`${label} agent not initialized`);
|
|
70
76
|
|
|
71
|
-
const {
|
|
72
|
-
chatId,
|
|
73
|
-
text,
|
|
74
|
-
senderName,
|
|
75
|
-
senderHandle,
|
|
76
|
-
isGroup,
|
|
77
|
-
messageId,
|
|
78
|
-
onTextBlock,
|
|
79
|
-
onToolUse,
|
|
80
|
-
} = params;
|
|
77
|
+
const { chatId, text, senderName, onTextBlock, onToolUse } = params;
|
|
81
78
|
const t0 = Date.now();
|
|
82
79
|
const session = getSession(chatId);
|
|
83
80
|
const previousTurns = session.turns;
|
|
@@ -108,14 +105,8 @@ export async function runRemoteChatTurn<TClient extends RemoteAgentClient>(
|
|
|
108
105
|
pluginMcpServerNames,
|
|
109
106
|
);
|
|
110
107
|
|
|
111
|
-
// Build the prompt (time tag + sender + msg_id
|
|
112
|
-
const prompt =
|
|
113
|
-
text,
|
|
114
|
-
senderName: senderName ?? "user",
|
|
115
|
-
senderHandle,
|
|
116
|
-
isGroup,
|
|
117
|
-
messageId,
|
|
118
|
-
});
|
|
108
|
+
// Build the prompt (time tag + sender + msg_id + recalled memory).
|
|
109
|
+
const prompt = buildTurnPrompt(params);
|
|
119
110
|
|
|
120
111
|
// Per-session frozen prompt + this backend's delivery suffix.
|
|
121
112
|
const { text: systemPrompt } = prepareSystemPrompt({
|
|
@@ -130,7 +121,7 @@ export async function runRemoteChatTurn<TClient extends RemoteAgentClient>(
|
|
|
130
121
|
});
|
|
131
122
|
|
|
132
123
|
log("agent", `[${chatId}] <- (${text.length} chars)`);
|
|
133
|
-
traceMessage(chatId, "in", text, { senderName, isGroup });
|
|
124
|
+
traceMessage(chatId, "in", text, { senderName, isGroup: params.isGroup });
|
|
134
125
|
|
|
135
126
|
// Bind the stream state to the chat so token mutators mirror counts
|
|
136
127
|
// into the live-turn overlay — /status updates while the turn runs.
|
|
@@ -268,6 +259,23 @@ export async function runRemoteChatTurn<TClient extends RemoteAgentClient>(
|
|
|
268
259
|
* session summaries can race on cancellation, so a failure leaves the
|
|
269
260
|
* counts at zero.
|
|
270
261
|
*/
|
|
262
|
+
/**
|
|
263
|
+
* The turn's user prompt: the shared framing every backend emits, plus
|
|
264
|
+
* whatever this turn's memory retrieval produced. `formatUserPrompt` is
|
|
265
|
+
* the one place `retrievedMemory` is rendered — see
|
|
266
|
+
* `backend/runtime/prompt/prompt-format.ts`.
|
|
267
|
+
*/
|
|
268
|
+
function buildTurnPrompt(params: QueryParams): string {
|
|
269
|
+
return formatUserPrompt({
|
|
270
|
+
text: params.text,
|
|
271
|
+
senderName: params.senderName ?? "user",
|
|
272
|
+
senderHandle: params.senderHandle,
|
|
273
|
+
isGroup: params.isGroup,
|
|
274
|
+
messageId: params.messageId,
|
|
275
|
+
retrievedMemory: params.retrievedMemory,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
271
279
|
async function fillUsageFromSummary(
|
|
272
280
|
oc: RemoteSessionClient,
|
|
273
281
|
sessionId: string,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
recordToolUse,
|
|
34
34
|
recordToolCall,
|
|
35
35
|
type StreamState,
|
|
36
|
-
} from "../
|
|
36
|
+
} from "../runtime/index.js";
|
|
37
37
|
import {
|
|
38
38
|
extractAssistantUsage,
|
|
39
39
|
type RemoteAssistantInfo,
|
|
@@ -68,7 +68,7 @@ export interface EventProcessingContext {
|
|
|
68
68
|
chatId: string;
|
|
69
69
|
/** Session id we're scoped to — events for other sessions are dropped. */
|
|
70
70
|
sessionId: string;
|
|
71
|
-
/** Stream state accumulator (
|
|
71
|
+
/** Stream state accumulator (runtime/turn/). */
|
|
72
72
|
state: StreamState;
|
|
73
73
|
/** Tool-call ids we've already fired callbacks for. */
|
|
74
74
|
seenToolCallIds: Set<string>;
|
|
@@ -164,7 +164,7 @@ export async function processStreamEvent(
|
|
|
164
164
|
* lands so token/context stats are live mid-turn instead of appearing
|
|
165
165
|
* only at the post-loop accounting. `recordTokens` also mirrors the
|
|
166
166
|
* counts into the chat's live-turn overlay when the state is bound to a
|
|
167
|
-
* chat (see `
|
|
167
|
+
* chat (see `runtime/turn/stream-state.ts: pushLiveUsage`).
|
|
168
168
|
*
|
|
169
169
|
* Values are the message's totals (not deltas), matching what the
|
|
170
170
|
* post-loop `extractAssistantUsage(lastAssistant.info)` reads — so the
|
|
@@ -28,9 +28,12 @@ import type { OneShotAgentParams, OneShotUsage } from "../../core/types.js";
|
|
|
28
28
|
import type { TalonConfig } from "../../core/config/index.js";
|
|
29
29
|
import { binaryOnPath } from "../../util/binary-on-path.js";
|
|
30
30
|
import { log } from "../../util/log.js";
|
|
31
|
-
import { handlerToEvents } from "../
|
|
32
|
-
import type {
|
|
33
|
-
|
|
31
|
+
import { handlerToEvents } from "../runtime/turn/handler-to-events.js";
|
|
32
|
+
import type {
|
|
33
|
+
QueryParams,
|
|
34
|
+
QueryResult,
|
|
35
|
+
} from "../runtime/turn/handler-types.js";
|
|
36
|
+
import { interruptChatTurn } from "../runtime/turn/turn-interrupt.js";
|
|
34
37
|
import type { RemoteModelProvider } from "./model-catalog/provider.js";
|
|
35
38
|
import type { RemoteSessionSnapshot } from "./session-helpers.js";
|
|
36
39
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* What's NOT here (intentionally):
|
|
29
29
|
*
|
|
30
30
|
* - Tool definitions, frontend prompt format — those are backend-
|
|
31
|
-
* agnostic and live in `core/` and `backend/
|
|
31
|
+
* agnostic and live in `core/` and `backend/runtime/`.
|
|
32
32
|
*
|
|
33
33
|
* This barrel exposes the helper layer for tests and the conformance
|
|
34
34
|
* suite; the bindings modules import from the concrete files directly.
|
|
@@ -50,7 +50,7 @@ import { ALL_TOOLS, nativeTools } from "../../core/tools/index.js";
|
|
|
50
50
|
import {
|
|
51
51
|
frontendForChatId,
|
|
52
52
|
nonTerminalFrontends,
|
|
53
|
-
} from "../
|
|
53
|
+
} from "../runtime/frontends.js";
|
|
54
54
|
|
|
55
55
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
56
56
|
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
type RemoteSessionClient,
|
|
42
42
|
type RemoteAssistantInfo,
|
|
43
43
|
} from "./session-helpers.js";
|
|
44
|
-
import { appendBackendSuffix, sleep } from "../
|
|
44
|
+
import { appendBackendSuffix, sleep } from "../runtime/index.js";
|
|
45
45
|
import { buildPermissionRuleset } from "./sessions.js";
|
|
46
46
|
|
|
47
47
|
// ── Client surface ──────────────────────────────────────────────────────────
|
|
@@ -25,7 +25,7 @@ import type { FrontendName } from "../../core/agent-runtime/backend-registry.js"
|
|
|
25
25
|
import {
|
|
26
26
|
buildDeliveryContract,
|
|
27
27
|
type DeliveryMode,
|
|
28
|
-
} from "../
|
|
28
|
+
} from "../runtime/prompt/delivery-contract.js";
|
|
29
29
|
import type { RemoteAgentClient } from "./client.js";
|
|
30
30
|
import { createRemoteServerState, errMsg } from "./state.js";
|
|
31
31
|
import { ensureRemoteServer, stopRemoteServer } from "./lifecycle.js";
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { logWarn } from "../../util/log.js";
|
|
16
|
-
import { createStreamState, recordTokens, sleep } from "../
|
|
16
|
+
import { createStreamState, recordTokens, sleep } from "../runtime/index.js";
|
|
17
17
|
import { processStreamEvent, finalizePartsIntoState } from "./events.js";
|
|
18
18
|
import { findLastAssistantMessage } from "./messages.js";
|
|
19
19
|
import {
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt-cache rollups — the per-turn verdict, the tool fingerprint and the
|
|
3
|
+
* SDK's compaction boundaries, folded into counters an operator can read.
|
|
4
|
+
*
|
|
5
|
+
* `cache-telemetry.ts` next door decides WHAT a turn did (verdict,
|
|
6
|
+
* fingerprint, lookback risk) and is pure apart from its own per-chat maps.
|
|
7
|
+
* This module is the side-effecting half: it writes to the metrics store and
|
|
8
|
+
* logs, so the telemetry stays testable without a store.
|
|
9
|
+
*
|
|
10
|
+
* Why these numbers exist (docs/cache-economics.md, PR A): every decision in
|
|
11
|
+
* PR B ("one prefix per frontend") and PR C ("compact when the cache has gone
|
|
12
|
+
* cold") needs a before/after figure, and nothing here changes a prompt byte
|
|
13
|
+
* or a turn's behaviour — measurement only.
|
|
14
|
+
*
|
|
15
|
+
* - `cache.first_request.{hit,miss,none}` — did the previous turn's prefix
|
|
16
|
+
* survive? The turn's first request is the only one that can say, and it
|
|
17
|
+
* is the number that tracks cost.
|
|
18
|
+
* - `cache.first_request.{read,write}_tokens` — how big the prefix is, so a
|
|
19
|
+
* miss can be priced.
|
|
20
|
+
* - `cache.session_start.{hit,miss,none}` — the same verdict restricted to a
|
|
21
|
+
* chat's FIRST turn. A hit there means another chat had already warmed an
|
|
22
|
+
* identical prefix: the cross-chat sharing signal PR B is aiming at.
|
|
23
|
+
* - `cache.tool_fingerprint.changed` — tools render before the system
|
|
24
|
+
* prompt, so a change invalidates everything after it.
|
|
25
|
+
* - `session.compacted.{manual,auto}` + `session.compact.{pre,post}_tokens`
|
|
26
|
+
* — how often the SDK compacts and how much it reclaims, the baseline
|
|
27
|
+
* PR C's idle-compaction policy is measured against.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { log } from "../../../util/log.js";
|
|
31
|
+
import {
|
|
32
|
+
incrementCounter,
|
|
33
|
+
noteCacheVerdict,
|
|
34
|
+
recordHistogram,
|
|
35
|
+
} from "../../../storage/metrics.js";
|
|
36
|
+
import {
|
|
37
|
+
crossTurnVerdict,
|
|
38
|
+
fingerprintHash,
|
|
39
|
+
hasToolFingerprint,
|
|
40
|
+
noteToolFingerprint,
|
|
41
|
+
type CrossTurnVerdict,
|
|
42
|
+
type TurnCacheStats,
|
|
43
|
+
} from "./cache-telemetry.js";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Roll one finished turn's cache behaviour up into the metrics store and
|
|
47
|
+
* remember the verdict for `/status`.
|
|
48
|
+
*
|
|
49
|
+
* `turnsIncludingThis` is the chat's turn count with this turn already
|
|
50
|
+
* counted, so 1 means the turn was the session's first — the only turn whose
|
|
51
|
+
* verdict says anything about cross-chat prefix sharing.
|
|
52
|
+
*/
|
|
53
|
+
export function rollUpTurnCache(
|
|
54
|
+
chatId: string,
|
|
55
|
+
stats: TurnCacheStats,
|
|
56
|
+
turnsIncludingThis: number,
|
|
57
|
+
): CrossTurnVerdict {
|
|
58
|
+
const verdict = crossTurnVerdict(stats);
|
|
59
|
+
incrementCounter(`cache.first_request.${verdict}`);
|
|
60
|
+
// Recorded on every turn, zeros included: the average is then "tokens per
|
|
61
|
+
// turn", which is what a miss costs, rather than an average over the
|
|
62
|
+
// turns that happened to be interesting.
|
|
63
|
+
recordHistogram("cache.first_request.read_tokens", stats.firstRead);
|
|
64
|
+
recordHistogram("cache.first_request.write_tokens", stats.firstWrite);
|
|
65
|
+
if (turnsIncludingThis <= 1) {
|
|
66
|
+
incrementCounter(`cache.session_start.${verdict}`);
|
|
67
|
+
}
|
|
68
|
+
noteCacheVerdict(chatId, verdict);
|
|
69
|
+
return verdict;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Record a chat's tool set: one info line the first time a chat is seen (so
|
|
74
|
+
* two chats on the same frontend can be compared by eye — identical hash +
|
|
75
|
+
* identical static prompt ⇒ shared cache), and a counter whenever it changes
|
|
76
|
+
* mid-process. `noteToolFingerprint` still owns the warning it already logs
|
|
77
|
+
* for a mid-session change.
|
|
78
|
+
*/
|
|
79
|
+
export function reportToolFingerprint(
|
|
80
|
+
chatId: string,
|
|
81
|
+
fingerprint: readonly string[],
|
|
82
|
+
): void {
|
|
83
|
+
const seen = hasToolFingerprint(chatId);
|
|
84
|
+
const changed = noteToolFingerprint(chatId, fingerprint);
|
|
85
|
+
if (!seen) {
|
|
86
|
+
log(
|
|
87
|
+
"agent",
|
|
88
|
+
`[${chatId}] tool fingerprint ${fingerprintHash(fingerprint)} ` +
|
|
89
|
+
`(${fingerprint.length} tools)`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (changed) incrementCounter("cache.tool_fingerprint.changed");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The SDK's compaction metadata, narrowed to the fields that are measured. */
|
|
96
|
+
export type CompactBoundary = {
|
|
97
|
+
trigger: "manual" | "auto";
|
|
98
|
+
pre_tokens: number;
|
|
99
|
+
post_tokens?: number;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Record a compaction boundary the SDK reported mid-stream. Purely
|
|
104
|
+
* observational — the turn carries on exactly as it did before, this just
|
|
105
|
+
* stops the event being dropped on the floor.
|
|
106
|
+
*/
|
|
107
|
+
export function recordCompactBoundary(
|
|
108
|
+
chatId: string,
|
|
109
|
+
meta: CompactBoundary,
|
|
110
|
+
): void {
|
|
111
|
+
const trigger = meta.trigger === "manual" ? "manual" : "auto";
|
|
112
|
+
incrementCounter(`session.compacted.${trigger}`);
|
|
113
|
+
const pre = Number.isFinite(meta.pre_tokens) ? meta.pre_tokens : 0;
|
|
114
|
+
const post =
|
|
115
|
+
typeof meta.post_tokens === "number" && Number.isFinite(meta.post_tokens)
|
|
116
|
+
? meta.post_tokens
|
|
117
|
+
: undefined;
|
|
118
|
+
recordHistogram("session.compact.pre_tokens", pre);
|
|
119
|
+
if (post !== undefined) recordHistogram("session.compact.post_tokens", post);
|
|
120
|
+
log(
|
|
121
|
+
"agent",
|
|
122
|
+
`[${chatId}] context compacted (${trigger}): ${pre} tokens` +
|
|
123
|
+
(post !== undefined ? ` -> ${post}` : "") +
|
|
124
|
+
` — the prefix after the boundary is new, so the next turn re-writes it`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
* did.
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
|
-
import {
|
|
39
|
+
import { createHash } from "node:crypto";
|
|
40
|
+
|
|
41
|
+
import { logWarn } from "../../../util/log.js";
|
|
40
42
|
|
|
41
43
|
// ── Per-turn cache stats ────────────────────────────────────────────────────
|
|
42
44
|
|
|
@@ -244,7 +246,7 @@ export function cacheMinimumTokens(model: string): number | undefined {
|
|
|
244
246
|
return best?.min;
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
/** Cheap tokenizer-free estimate (~4 chars/token),
|
|
249
|
+
/** Cheap tokenizer-free estimate (~4 chars/token), the house heuristic. */
|
|
248
250
|
function estimateTokens(text: string): number {
|
|
249
251
|
return Math.ceil(text.length / 4);
|
|
250
252
|
}
|
|
@@ -307,6 +309,24 @@ export function toolFingerprint(
|
|
|
307
309
|
].sort();
|
|
308
310
|
}
|
|
309
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Short, stable digest of a tool set — the thing to compare between two
|
|
314
|
+
* chats. Two chats whose fingerprints (and static prompt) match render a
|
|
315
|
+
* byte-identical prefix and therefore share the cache; two that don't,
|
|
316
|
+
* can't, however similar they look (docs/cache-economics.md, PR B).
|
|
317
|
+
*/
|
|
318
|
+
export function fingerprintHash(fingerprint: readonly string[]): string {
|
|
319
|
+
return createHash("sha256")
|
|
320
|
+
.update(fingerprint.join("\n"))
|
|
321
|
+
.digest("hex")
|
|
322
|
+
.slice(0, 12);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** True once a fingerprint has been recorded for this chat in this process. */
|
|
326
|
+
export function hasToolFingerprint(chatId: string): boolean {
|
|
327
|
+
return lastToolSets.has(chatId);
|
|
328
|
+
}
|
|
329
|
+
|
|
310
330
|
/**
|
|
311
331
|
* Record this turn's tool set for a chat and warn when it differs from the
|
|
312
332
|
* previous turn's. Returns true when a change was detected.
|