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
package/README.md
CHANGED
|
@@ -119,9 +119,9 @@ index.ts Composition root
|
|
|
119
119
|
| +-- bus/ Typed pub-sub spine + event journal
|
|
120
120
|
| +-- vfs/ The talon:// namespace (~/.talon/ns), FUSE-backed
|
|
121
121
|
| +-- mesh/ Device mesh: presence, exec/fs channel, teleport
|
|
122
|
-
| +--
|
|
123
|
-
| +-- scripts/ Run-to-completion execution of saved scripts
|
|
124
|
-
|
|
|
122
|
+
| +-- memory/ Typed memory store policy: core view, import, taps
|
|
123
|
+
| +-- scripts/ Run-to-completion execution of saved scripts +
|
|
124
|
+
| | the WASM-sandboxed Lua runner for trigger scripts
|
|
125
125
|
| +-- daemon/ Start / stop / restart, pidfile, discovery
|
|
126
126
|
| +-- plugin/ Plugin loader, registry, hot-reload
|
|
127
127
|
| +-- update/ Self-update for git-checkout deployments
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "talon-agent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "Multi-frontend AI agent with full tool access, streaming, cron jobs, and plugin system",
|
|
5
5
|
"author": "Dylan Neve",
|
|
6
6
|
"license": "MIT",
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
"depcruise": "node scripts/check-architecture.mjs",
|
|
85
85
|
"ratchets": "node scripts/check-ratchets.mjs",
|
|
86
86
|
"function-size": "node scripts/check-function-size.mjs",
|
|
87
|
+
"tree": "node scripts/check-tree.mjs",
|
|
87
88
|
"knip": "knip",
|
|
88
89
|
"format": "prettier --write src/ prompts/",
|
|
89
90
|
"format:check": "prettier --check src/ prompts/",
|
package/prompts/README.md
CHANGED
|
@@ -95,7 +95,7 @@ frontend, so it never belongs in the frontend `.md` files:
|
|
|
95
95
|
The delivery TOOL NAMES are per-frontend (`end_turn`/`send`/`react` on
|
|
96
96
|
telegram & discord, `end_turn`/`send_message`/`react` on native,
|
|
97
97
|
`end_turn`/`send_message` on teams) and are injected into the templates
|
|
98
|
-
by `src/backend/
|
|
98
|
+
by `src/backend/runtime/prompt/delivery-contract.ts`, which is also where the
|
|
99
99
|
frontend-aware `[FLOW VIOLATION]` reminder and the first-turn nudge
|
|
100
100
|
(appended to the turn-0 user message) are built.
|
|
101
101
|
|
|
@@ -109,7 +109,7 @@ contradictions between backends.
|
|
|
109
109
|
`heartbeat.md` and `dream.md` are not part of the chat system prompt — they
|
|
110
110
|
are standalone prompts for the background heartbeat and memory-consolidation
|
|
111
111
|
(dream) agents, loaded by `src/core/background/heartbeat.ts` /
|
|
112
|
-
`src/core/background/dream.ts`.
|
|
112
|
+
`src/core/background/dream/index.ts`.
|
|
113
113
|
|
|
114
114
|
## Token budget
|
|
115
115
|
|
|
@@ -59,3 +59,19 @@ memory instead is what crowds a memory file with snapshots that were true for
|
|
|
59
59
|
an hour.
|
|
60
60
|
|
|
61
61
|
Memory updates should usually be quiet unless the user asks about them.
|
|
62
|
+
|
|
63
|
+
### Remembering
|
|
64
|
+
|
|
65
|
+
When the `remember`, `recall`, and `forget` tools are available, they are the
|
|
66
|
+
canonical store — use them in preference to editing memory files by hand.
|
|
67
|
+
|
|
68
|
+
Call `remember` as you learn something durable: a stated preference, a
|
|
69
|
+
correction to something you had wrong, a fact about a person or a project the
|
|
70
|
+
user would expect you to still know next week. One claim per call.
|
|
71
|
+
|
|
72
|
+
Never store secrets or credentials, live operational status, or anything the
|
|
73
|
+
user asked you to keep off the record — and never store a claim as fact when
|
|
74
|
+
you are only guessing.
|
|
75
|
+
|
|
76
|
+
If a claim is already on file in a different wording, replace it rather than
|
|
77
|
+
adding a second copy; `forget` needs a reason, and drops are recoverable.
|
package/src/app.ts
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { getFrontends } from "./core/config/index.js";
|
|
10
|
-
import { startUploadCleanup, stopUploadCleanup } from "./
|
|
10
|
+
import { startUploadCleanup, stopUploadCleanup } from "./core/vfs/workspace.js";
|
|
11
11
|
import { flushDatabase } from "./storage/db.js";
|
|
12
12
|
import { getActiveCount, stopAllTurns } from "./core/engine/dispatcher.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import {
|
|
14
|
+
startPulseTimer,
|
|
15
|
+
stopPulseTimer,
|
|
16
|
+
} from "./core/background/pulse/pulse.js";
|
|
17
|
+
import { stopPlanAlerts } from "./core/background/pulse/plan-alerts.js";
|
|
15
18
|
import {
|
|
16
19
|
startHeartbeatTimer,
|
|
17
20
|
stopHeartbeatTimer,
|
|
@@ -21,13 +24,13 @@ import {
|
|
|
21
24
|
startCronTimer,
|
|
22
25
|
stopCronTimer,
|
|
23
26
|
runStartupCatchup,
|
|
24
|
-
} from "./core/background/cron.js";
|
|
27
|
+
} from "./core/background/cron/scheduler.js";
|
|
25
28
|
import { shutdownTriggers } from "./core/background/triggers/index.js";
|
|
26
29
|
import { pruneSettledTriggers } from "./storage/triggers.js";
|
|
27
30
|
import { startWatchdog, stopWatchdog } from "./util/watchdog.js";
|
|
28
|
-
import { spawnSuccessor } from "./
|
|
31
|
+
import { spawnSuccessor } from "./core/daemon/respawn.js";
|
|
29
32
|
import { log, logError, logWarn } from "./util/log.js";
|
|
30
|
-
import { bootPhase, bootReport } from "./
|
|
33
|
+
import { bootPhase, bootReport } from "./core/daemon/boot-timer.js";
|
|
31
34
|
import {
|
|
32
35
|
getVfs,
|
|
33
36
|
mountNamespaceFs,
|
|
@@ -51,6 +54,11 @@ import {
|
|
|
51
54
|
writePidRecord,
|
|
52
55
|
removePidRecordIfOwnedBy,
|
|
53
56
|
} from "./core/daemon/pidfile.js";
|
|
57
|
+
import {
|
|
58
|
+
recordBootMetrics,
|
|
59
|
+
startResourceSampler,
|
|
60
|
+
stopResourceSampler,
|
|
61
|
+
} from "./core/daemon/resource-sampler.js";
|
|
54
62
|
|
|
55
63
|
const { config } = await bootPhase("bootstrap", () => bootstrap());
|
|
56
64
|
|
|
@@ -202,6 +210,7 @@ async function gracefulShutdown(signal: string): Promise<void> {
|
|
|
202
210
|
});
|
|
203
211
|
await shutdownStep("triggers", shutdownTriggers);
|
|
204
212
|
await shutdownStep("watchdog", stopWatchdog);
|
|
213
|
+
await shutdownStep("resource sampler", stopResourceSampler);
|
|
205
214
|
await shutdownStep("upload cleanup", stopUploadCleanup);
|
|
206
215
|
await shutdownStep("mcp hub", async () => {
|
|
207
216
|
const { shutdownHub } = await import("./core/mcp-hub/index.js");
|
|
@@ -311,7 +320,13 @@ async function main(): Promise<void> {
|
|
|
311
320
|
await bootPhase("frontends start", () =>
|
|
312
321
|
Promise.all(blockingFrontends.map((frontend) => frontend.start())),
|
|
313
322
|
);
|
|
314
|
-
|
|
323
|
+
// Phase 0 accounting (docs/ts-migration-plan.md): the boot is over the
|
|
324
|
+
// moment the frontends are listening, so the totals are folded into the
|
|
325
|
+
// metrics store here, from the same uptime figure the log line prints.
|
|
326
|
+
const bootMs = Math.round(process.uptime() * 1000);
|
|
327
|
+
recordBootMetrics(bootMs);
|
|
328
|
+
startResourceSampler();
|
|
329
|
+
log("bot", `Ready in ${bootReport(bootMs)}`);
|
|
315
330
|
for (const frontend of stdinFrontends) {
|
|
316
331
|
void frontend
|
|
317
332
|
.start()
|
|
@@ -24,23 +24,12 @@ import {
|
|
|
24
24
|
type ToolRuntime,
|
|
25
25
|
type UsageTelemetry,
|
|
26
26
|
} from "../../core/agent-runtime/capabilities.js";
|
|
27
|
-
import { getPlanUsage } from "./plan-usage.js";
|
|
28
27
|
|
|
29
28
|
import {
|
|
30
|
-
initAgent as initClaudeAgent,
|
|
31
29
|
updateSystemPrompt as claudeUpdateSystemPrompt,
|
|
32
|
-
warmSession as claudeWarmSession,
|
|
33
|
-
getActiveQuery,
|
|
34
|
-
buildMcpServers,
|
|
35
|
-
buildPluginMcpServers,
|
|
36
|
-
runOneShotAgent as claudeRunOneShotAgent,
|
|
37
30
|
evictOrphanSubprocesses as claudeEvictOrphanSubprocesses,
|
|
38
31
|
} from "./index.js";
|
|
39
|
-
import {
|
|
40
|
-
runChatTurn as claudeRunChatTurn,
|
|
41
|
-
interruptChatTurn as claudeInterruptChatTurn,
|
|
42
|
-
} from "./handler.js";
|
|
43
|
-
import { waitForMcpServersReady } from "./mcp-ready.js";
|
|
32
|
+
import { createInProcessAgentHost } from "./host/in-process.js";
|
|
44
33
|
|
|
45
34
|
import * as modelProvider from "./model-provider.js";
|
|
46
35
|
import { claudeDoctorChecks } from "./doctor.js";
|
|
@@ -54,16 +43,25 @@ const claudeSdkFactory: BackendFactory = {
|
|
|
54
43
|
doctor: (config, isActive) => claudeDoctorChecks(config, isActive),
|
|
55
44
|
|
|
56
45
|
async init(config, ctx) {
|
|
57
|
-
|
|
46
|
+
// Everything SDK-side goes through the agent-host seam
|
|
47
|
+
// (docs/agent-host-sidecar.md). Phase 1 binds the in-process client,
|
|
48
|
+
// which calls the same functions this factory used to call inline;
|
|
49
|
+
// Phase 2 swaps in a process-backed client behind the same interface.
|
|
50
|
+
const host = createInProcessAgentHost(config, ctx.getBridgePort);
|
|
51
|
+
await host.hello();
|
|
58
52
|
log("bot", "Backend: Claude SDK (@anthropic-ai/claude-agent-sdk)");
|
|
59
53
|
|
|
60
54
|
const chat: ChatBackend = {
|
|
61
|
-
runChatTurn: (params) =>
|
|
62
|
-
interruptChatTurn: (chatId) =>
|
|
55
|
+
runChatTurn: (params) => host.runTurn(params),
|
|
56
|
+
interruptChatTurn: (chatId) => host.interrupt(chatId),
|
|
63
57
|
};
|
|
64
58
|
|
|
65
59
|
const background: BackgroundRunner = {
|
|
66
|
-
runOneShotAgent: (p) =>
|
|
60
|
+
runOneShotAgent: (p) => host.runOneShot(p),
|
|
61
|
+
// Not a protocol-table row yet: subprocess eviction reaches into
|
|
62
|
+
// the SDK's own children, so it belongs to the host — but the
|
|
63
|
+
// design's message table has no request for it. Tracked as an open
|
|
64
|
+
// question against Phase 2; bound directly until it gains one.
|
|
67
65
|
evictOrphanSubprocesses: (label) => claudeEvictOrphanSubprocesses(label),
|
|
68
66
|
};
|
|
69
67
|
|
|
@@ -81,7 +79,10 @@ const claudeSdkFactory: BackendFactory = {
|
|
|
81
79
|
getProviderModels: (p, pg, ps) =>
|
|
82
80
|
modelProvider.getProviderModels(p, pg, ps),
|
|
83
81
|
formatModelError: (q, r) => modelProvider.formatModelError(q, r),
|
|
84
|
-
|
|
82
|
+
// The one catalog member that asks the host: `list_models` is the
|
|
83
|
+
// protocol's model row. The seven above are daemon-side formatting
|
|
84
|
+
// over `core/models/catalog.ts`, which `hello` populates.
|
|
85
|
+
listModels: (f) => host.listModels(f),
|
|
85
86
|
};
|
|
86
87
|
|
|
87
88
|
// Claude SDK's per-turn subprocess model has no shared session
|
|
@@ -89,32 +90,11 @@ const claudeSdkFactory: BackendFactory = {
|
|
|
89
90
|
// dispatcher's `/reset` clears Talon's stored session id via
|
|
90
91
|
// `storage/sessions.ts:resetSession` regardless.
|
|
91
92
|
const sessions: SessionBackend = {
|
|
92
|
-
warmSession: (chatId) =>
|
|
93
|
+
warmSession: (chatId) => host.warmSession(chatId),
|
|
93
94
|
};
|
|
94
95
|
|
|
95
96
|
const tools: ToolRuntime = {
|
|
96
|
-
refreshTools:
|
|
97
|
-
const qi = getActiveQuery(chatId);
|
|
98
|
-
if (!qi) return null;
|
|
99
|
-
// Two-phase teardown: remove all MCP servers first so each
|
|
100
|
-
// subprocess receives an OS-agnostic shutdown via stdio, then
|
|
101
|
-
// install the fresh set.
|
|
102
|
-
await qi.setMcpServers({});
|
|
103
|
-
const freshServers = {
|
|
104
|
-
...buildMcpServers(chatId),
|
|
105
|
-
...buildPluginMcpServers(chatId),
|
|
106
|
-
};
|
|
107
|
-
const result = await qi.setMcpServers(freshServers);
|
|
108
|
-
// setMcpServers resolves on REGISTER, not CONNECT — MCP startup is
|
|
109
|
-
// non-blocking. A stdio server that dials a slow remote (e.g. the
|
|
110
|
-
// playwright plugin connecting to the Camoufox websocket) is still
|
|
111
|
-
// 'pending' at this point and its tools are absent from the live
|
|
112
|
-
// registry, so the turn would proceed with mcp__playwright-tools__*
|
|
113
|
-
// stuck "connecting" until the next refresh. Wait (bounded) for the
|
|
114
|
-
// newly-added servers to finish connecting before returning.
|
|
115
|
-
await waitForMcpServersReady(qi, result.added);
|
|
116
|
-
return result;
|
|
117
|
-
},
|
|
97
|
+
refreshTools: (chatId) => host.refreshTools(chatId),
|
|
118
98
|
};
|
|
119
99
|
|
|
120
100
|
const control: SystemControl = {
|
|
@@ -124,7 +104,7 @@ const claudeSdkFactory: BackendFactory = {
|
|
|
124
104
|
// No per-session snapshot to offer (each turn is a fresh subprocess),
|
|
125
105
|
// but the subscription's rate-limit windows are readable.
|
|
126
106
|
const usage: UsageTelemetry = {
|
|
127
|
-
getPlanUsage: () =>
|
|
107
|
+
getPlanUsage: () => host.planUsage(),
|
|
128
108
|
};
|
|
129
109
|
|
|
130
110
|
const backend = composeBackend({
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (session expired / context overflow / model fallback via
|
|
7
7
|
* `applyRetryDecisionStream`) and the post-result watchdog. The phases
|
|
8
8
|
* after the stream — accounting, the trailing-prose contract, the result
|
|
9
|
-
* events — are the shared ones in `backend/
|
|
9
|
+
* events — are the shared ones in `backend/runtime/turn/turn-phases.ts`.
|
|
10
10
|
*
|
|
11
11
|
* The exported async generator `runChatTurn` is what the factory wires
|
|
12
12
|
* onto `ChatBackend.runChatTurn` — no wrapper, no callback shim.
|
|
@@ -34,12 +34,13 @@ import {
|
|
|
34
34
|
} from "../../core/agent-runtime/events.js";
|
|
35
35
|
import type { ChatRunParams } from "../../core/agent-runtime/capabilities.js";
|
|
36
36
|
import { makeBareModelRef } from "../../core/agent-runtime/model-ref.js";
|
|
37
|
-
import { applyRetryDecisionStream } from "../
|
|
37
|
+
import { applyRetryDecisionStream } from "../runtime/turn/handle-retry.js";
|
|
38
38
|
import { getConfig } from "./state.js";
|
|
39
39
|
import { buildSdkOptions, getActiveFrontends } from "./options.js";
|
|
40
40
|
import { waitForMcpServersReady } from "./mcp-ready.js";
|
|
41
41
|
import { invalidatePlanUsage } from "./plan-usage.js";
|
|
42
|
-
import { frontendsForChat } from "../
|
|
42
|
+
import { frontendsForChat } from "../runtime/frontends.js";
|
|
43
|
+
import { rollUpTurnCache } from "../runtime/cache/cache-metrics.js";
|
|
43
44
|
import {
|
|
44
45
|
createStreamState,
|
|
45
46
|
isSystemInit,
|
|
@@ -47,10 +48,12 @@ import {
|
|
|
47
48
|
isAssistant,
|
|
48
49
|
isResult,
|
|
49
50
|
isRateLimitEvent,
|
|
51
|
+
isCompactBoundary,
|
|
50
52
|
isUserMessage,
|
|
51
53
|
extractToolResults,
|
|
52
54
|
processStreamDelta,
|
|
53
55
|
processAssistantMessage,
|
|
56
|
+
processCompactBoundary,
|
|
54
57
|
processResultMessage,
|
|
55
58
|
type StreamState,
|
|
56
59
|
} from "./stream.js";
|
|
@@ -74,7 +77,7 @@ import {
|
|
|
74
77
|
enforceTrailingProse,
|
|
75
78
|
buildResultEvents,
|
|
76
79
|
turnUsageSnapshot,
|
|
77
|
-
} from "../
|
|
80
|
+
} from "../runtime/index.js";
|
|
78
81
|
|
|
79
82
|
// ── Post-result watchdog ────────────────────────────────────────────────────
|
|
80
83
|
// The SDK's PostToolBatch hook is the canonical loop-terminator — it returns
|
|
@@ -334,6 +337,12 @@ async function* consumeSdkStream(
|
|
|
334
337
|
yield* translateToolResults(ctx, message);
|
|
335
338
|
continue;
|
|
336
339
|
}
|
|
340
|
+
// The SDK compacted the session mid-turn. Measured, not acted on: the
|
|
341
|
+
// turn carries on exactly as before.
|
|
342
|
+
if (isCompactBoundary(message)) {
|
|
343
|
+
processCompactBoundary(message, ctx.chatId);
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
337
346
|
// The turn just moved the plan's usage — drop the cached windows so
|
|
338
347
|
// the next /status reads them again instead of showing pre-turn
|
|
339
348
|
// figures.
|
|
@@ -399,6 +408,7 @@ function buildTurnPrompt(
|
|
|
399
408
|
senderHandle: params.senderHandle,
|
|
400
409
|
isGroup: params.isGroup,
|
|
401
410
|
messageId: params.messageId,
|
|
411
|
+
retrievedMemory: params.retrievedMemory,
|
|
402
412
|
});
|
|
403
413
|
if (frontend && previousTurns === 0 && !internal.flowRetries) {
|
|
404
414
|
prompt += `\n\n${buildFirstTurnReminder(frontend)}`;
|
|
@@ -445,12 +455,23 @@ function accountFailedClaudeTurn(
|
|
|
445
455
|
/**
|
|
446
456
|
* The aggregate `cache=NN%` can't distinguish a turn that reused the
|
|
447
457
|
* previous turn's prefix from one that re-wrote it — see
|
|
448
|
-
*
|
|
458
|
+
* runtime/cache/cache-telemetry.ts. A lookback overflow only *predicts* a miss,
|
|
449
459
|
* so warn when this turn's verdict proves the previous turn's overflow
|
|
450
460
|
* cost a prefix re-write, then record this turn's overflow for the next.
|
|
461
|
+
*
|
|
462
|
+
* Also the rollup seam: the verdict goes into `cache.first_request.*` (and
|
|
463
|
+
* `cache.session_start.*` on a chat's first turn) here rather than in
|
|
464
|
+
* `runChatTurn`, which is at its size limit. `turnsIncludingThis` is the
|
|
465
|
+
* session's turn count with this turn already counted — `incrementTurns`
|
|
466
|
+
* has run by the time this is called, so 1 means "this was the first".
|
|
451
467
|
*/
|
|
452
|
-
function reportCacheVerdict(
|
|
468
|
+
function reportCacheVerdict(
|
|
469
|
+
chatId: string,
|
|
470
|
+
state: StreamState,
|
|
471
|
+
turnsIncludingThis: number,
|
|
472
|
+
): void {
|
|
453
473
|
if (state.cacheStats) {
|
|
474
|
+
rollUpTurnCache(chatId, state.cacheStats, turnsIncludingThis);
|
|
454
475
|
const overflow = priorLookbackOverflow(chatId);
|
|
455
476
|
if (
|
|
456
477
|
overflow !== undefined &&
|
|
@@ -647,7 +668,7 @@ export async function* runChatTurn(
|
|
|
647
668
|
incrementTurns(chatId);
|
|
648
669
|
|
|
649
670
|
state.allResponseText += state.currentBlockText;
|
|
650
|
-
reportCacheVerdict(chatId, state);
|
|
671
|
+
reportCacheVerdict(chatId, state, session.turns);
|
|
651
672
|
|
|
652
673
|
const usage = turnUsageSnapshot(state);
|
|
653
674
|
log(
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-process agent host — `AgentHostClient` implemented as direct
|
|
3
|
+
* calls into `backend/claude-sdk/`.
|
|
4
|
+
*
|
|
5
|
+
* `docs/agent-host-sidecar.md` Phase 1. This is the implementation that
|
|
6
|
+
* keeps today's behaviour exactly: every method is a call-through to the
|
|
7
|
+
* function the claude-sdk `BackendFactory` used to call itself. There is
|
|
8
|
+
* no process, no framing and no logic of its own — the only code that
|
|
9
|
+
* moved here is `refreshTools`' two-phase MCP teardown, which had to,
|
|
10
|
+
* because it drives a `Query` handle and handles do not cross a process
|
|
11
|
+
* boundary.
|
|
12
|
+
*
|
|
13
|
+
* Phase 2 adds a sibling that speaks the same interface over a child
|
|
14
|
+
* process's stdio. Nothing above this file changes when it does.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
AgentHostClient,
|
|
19
|
+
HostReadyInfo,
|
|
20
|
+
HostSessionInfo,
|
|
21
|
+
HostToolRefresh,
|
|
22
|
+
} from "../../../core/agent-runtime/agent-host.js";
|
|
23
|
+
import { AGENT_HOST_PROTOCOL_VERSION } from "../../../core/agent-runtime/agent-host.js";
|
|
24
|
+
import type { TalonConfig } from "../../../core/config/index.js";
|
|
25
|
+
import { getSession } from "../../../storage/sessions.js";
|
|
26
|
+
import { talonVersion } from "../../../util/version.js";
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
initAgent as claudeInitAgent,
|
|
30
|
+
warmSession as claudeWarmSession,
|
|
31
|
+
getActiveQuery,
|
|
32
|
+
buildMcpServers,
|
|
33
|
+
buildPluginMcpServers,
|
|
34
|
+
runOneShotAgent as claudeRunOneShotAgent,
|
|
35
|
+
} from "../index.js";
|
|
36
|
+
import {
|
|
37
|
+
runChatTurn as claudeRunChatTurn,
|
|
38
|
+
interruptChatTurn as claudeInterruptChatTurn,
|
|
39
|
+
} from "../handler.js";
|
|
40
|
+
import { waitForMcpServersReady } from "../mcp-ready.js";
|
|
41
|
+
import { listModels as claudeListModels } from "../model-provider.js";
|
|
42
|
+
import { getPlanUsage } from "../plan-usage.js";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Install an MCP server set on the chat's live query. `null` when the
|
|
46
|
+
* chat has no query in flight — the same "nothing to refresh" answer
|
|
47
|
+
* `ToolRuntime.refreshTools` has always given.
|
|
48
|
+
*/
|
|
49
|
+
async function setMcpServers(
|
|
50
|
+
chatId: string,
|
|
51
|
+
servers: Record<string, unknown>,
|
|
52
|
+
): Promise<HostToolRefresh | null> {
|
|
53
|
+
const qi = getActiveQuery(chatId);
|
|
54
|
+
if (!qi) return null;
|
|
55
|
+
return qi.setMcpServers(servers as Parameters<typeof qi.setMcpServers>[0]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Re-derive the chat's MCP config from the live plugin registry. Body
|
|
60
|
+
* lifted verbatim from the claude-sdk factory's `tools.refreshTools`,
|
|
61
|
+
* comments included — the ordering is load-bearing.
|
|
62
|
+
*/
|
|
63
|
+
async function refreshTools(chatId: string): Promise<HostToolRefresh | null> {
|
|
64
|
+
const qi = getActiveQuery(chatId);
|
|
65
|
+
if (!qi) return null;
|
|
66
|
+
// Two-phase teardown: remove all MCP servers first so each
|
|
67
|
+
// subprocess receives an OS-agnostic shutdown via stdio, then
|
|
68
|
+
// install the fresh set.
|
|
69
|
+
await qi.setMcpServers({});
|
|
70
|
+
const freshServers = {
|
|
71
|
+
...buildMcpServers(chatId),
|
|
72
|
+
...buildPluginMcpServers(chatId),
|
|
73
|
+
};
|
|
74
|
+
const result = await qi.setMcpServers(freshServers);
|
|
75
|
+
// setMcpServers resolves on REGISTER, not CONNECT — MCP startup is
|
|
76
|
+
// non-blocking. A stdio server that dials a slow remote (e.g. the
|
|
77
|
+
// playwright plugin connecting to the Camoufox websocket) is still
|
|
78
|
+
// 'pending' at this point and its tools are absent from the live
|
|
79
|
+
// registry, so the turn would proceed with mcp__playwright-tools__*
|
|
80
|
+
// stuck "connecting" until the next refresh. Wait (bounded) for the
|
|
81
|
+
// newly-added servers to finish connecting before returning.
|
|
82
|
+
await waitForMcpServersReady(qi, result.added);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The context figures `warm_session` populates, read back out of the
|
|
88
|
+
* daemon's session store. In-process the host and the store share a
|
|
89
|
+
* process, so this is a lookup; in Phase 2 it is the reply that carries
|
|
90
|
+
* those numbers home.
|
|
91
|
+
*/
|
|
92
|
+
async function sessionInfo(chatId: string): Promise<HostSessionInfo> {
|
|
93
|
+
const session = getSession(chatId);
|
|
94
|
+
return {
|
|
95
|
+
chatId,
|
|
96
|
+
sessionId: session.sessionId,
|
|
97
|
+
turns: session.turns,
|
|
98
|
+
contextTokens: session.usage.contextTokens,
|
|
99
|
+
contextWindow: session.usage.contextWindow,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The Claude SDK backend keeps no conversation memory of its own — each
|
|
105
|
+
* turn is a fresh subprocess — so the only per-chat state the host holds
|
|
106
|
+
* is the in-flight query handle. Dropping it is interrupting it.
|
|
107
|
+
*
|
|
108
|
+
* Not bound into the `Backend` object: claude-sdk has no `resetChat`
|
|
109
|
+
* slot today and Phase 1 does not add one. `/reset` still clears the
|
|
110
|
+
* stored session id through `storage/sessions.ts`, as it always has.
|
|
111
|
+
*/
|
|
112
|
+
async function resetSession(chatId: string): Promise<boolean> {
|
|
113
|
+
return claudeInterruptChatTurn(chatId);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build the in-process host. `config` and `getBridgePort` are held only
|
|
118
|
+
* for `hello()`, which performs the same `initAgent(config,
|
|
119
|
+
* getBridgePort)` the factory used to call inline.
|
|
120
|
+
*/
|
|
121
|
+
export function createInProcessAgentHost(
|
|
122
|
+
config: TalonConfig,
|
|
123
|
+
getBridgePort?: () => number,
|
|
124
|
+
): AgentHostClient {
|
|
125
|
+
return {
|
|
126
|
+
async hello(): Promise<HostReadyInfo> {
|
|
127
|
+
await claudeInitAgent(config, getBridgePort);
|
|
128
|
+
// `sdk` is omitted: in-process there is no separately-pinned SDK
|
|
129
|
+
// build to name — the daemon's own lockfile is the answer, and
|
|
130
|
+
// Phase 4 gives the host a `package.json` of its own to report.
|
|
131
|
+
return { protocol: AGENT_HOST_PROTOCOL_VERSION, host: talonVersion() };
|
|
132
|
+
},
|
|
133
|
+
runTurn: (params) => claudeRunChatTurn(params),
|
|
134
|
+
interrupt: (chatId) => claudeInterruptChatTurn(chatId),
|
|
135
|
+
runOneShot: (params) => claudeRunOneShotAgent(params),
|
|
136
|
+
warmSession: (chatId) => claudeWarmSession(chatId),
|
|
137
|
+
setMcpServers,
|
|
138
|
+
refreshTools,
|
|
139
|
+
listModels: (filter) => claudeListModels(filter),
|
|
140
|
+
planUsage: () => getPlanUsage(),
|
|
141
|
+
sessionInfo,
|
|
142
|
+
resetSession,
|
|
143
|
+
// Nothing to drain while the host is this process: the daemon's own
|
|
144
|
+
// shutdown path already aborts in-flight turns.
|
|
145
|
+
shutdown: async () => undefined,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -19,7 +19,7 @@ import { log, logWarn } from "../../util/log.js";
|
|
|
19
19
|
import { ALLOWED_TOOLS_BACKGROUND } from "../../core/constants.js";
|
|
20
20
|
import { EFFORT_MAP } from "./constants.js";
|
|
21
21
|
import { buildMcpServers, buildPluginMcpServers } from "./options.js";
|
|
22
|
-
import { warnIfBelowCacheMinimum } from "../
|
|
22
|
+
import { warnIfBelowCacheMinimum } from "../runtime/cache/cache-telemetry.js";
|
|
23
23
|
|
|
24
24
|
const DEFAULT_SUBPROCESS_KILL_GRACE_MS = 5 * 1000;
|
|
25
25
|
|
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
HookCallback,
|
|
16
16
|
HookJSONOutput,
|
|
17
17
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
18
|
-
import type { PreparedSystemPrompt } from "../
|
|
18
|
+
import type { PreparedSystemPrompt } from "../runtime/prompt/system-prompt.js";
|
|
19
19
|
import { getSession } from "../../storage/sessions.js";
|
|
20
20
|
import { getChatSettings } from "../../storage/chat-settings.js";
|
|
21
21
|
import { resolveModelId } from "../../core/models/catalog.js";
|
|
@@ -25,11 +25,12 @@ import {
|
|
|
25
25
|
pluginHubUrl,
|
|
26
26
|
hubPluginServerNames,
|
|
27
27
|
} from "../../core/mcp-hub/index.js";
|
|
28
|
-
import { nonTerminalFrontends, frontendsForChat } from "../shared/frontends.js";
|
|
29
28
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "../
|
|
29
|
+
nonTerminalFrontends,
|
|
30
|
+
frontendsForChat,
|
|
31
|
+
} from "../runtime/frontends.js";
|
|
32
|
+
import { toolFingerprint } from "../runtime/cache/cache-telemetry.js";
|
|
33
|
+
import { reportToolFingerprint } from "../runtime/cache/cache-metrics.js";
|
|
33
34
|
import { log, logError } from "../../util/log.js";
|
|
34
35
|
import { getConfig, getBridgePort } from "./state.js";
|
|
35
36
|
import { ALLOWED_TOOLS_CHAT, EFFORT_MAP } from "./constants.js";
|
|
@@ -395,7 +396,7 @@ export function buildSdkOptions(
|
|
|
395
396
|
// mid-session invalidates the system prompt and every cached message after
|
|
396
397
|
// it — the most expensive cache event there is, and one the aggregate
|
|
397
398
|
// hit-rate can't show. Plugin-provided MCP servers are the mutable part.
|
|
398
|
-
|
|
399
|
+
reportToolFingerprint(
|
|
399
400
|
chatId,
|
|
400
401
|
toolFingerprint(builtinTools, Object.keys(mcpServers)),
|
|
401
402
|
);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type {
|
|
10
|
+
SDKCompactBoundaryMessage,
|
|
10
11
|
SDKMessage,
|
|
11
12
|
SDKSystemMessage,
|
|
12
13
|
SDKPartialAssistantMessage,
|
|
@@ -22,7 +23,8 @@ import { checkModelDrift } from "./model-drift.js";
|
|
|
22
23
|
import {
|
|
23
24
|
turnCacheStats,
|
|
24
25
|
type TurnCacheStats,
|
|
25
|
-
} from "../
|
|
26
|
+
} from "../runtime/cache/cache-telemetry.js";
|
|
27
|
+
import { recordCompactBoundary } from "../runtime/cache/cache-metrics.js";
|
|
26
28
|
|
|
27
29
|
// ── Stream state accumulator ────────────────────────────────────────────────
|
|
28
30
|
|
|
@@ -46,7 +48,7 @@ export type StreamState = {
|
|
|
46
48
|
* `usage.iterations`. Undefined when the provider reported none — the
|
|
47
49
|
* aggregate totals above cannot distinguish a turn that read the previous
|
|
48
50
|
* turn's prefix from one that re-wrote it, and that distinction is the
|
|
49
|
-
* whole cost signal (see
|
|
51
|
+
* whole cost signal (see runtime/cache/cache-telemetry.ts).
|
|
50
52
|
*/
|
|
51
53
|
cacheStats: TurnCacheStats | undefined;
|
|
52
54
|
lastStreamUpdate: number;
|
|
@@ -156,6 +158,18 @@ export function isRateLimitEvent(msg: SDKMessage): boolean {
|
|
|
156
158
|
return msg.type === "rate_limit_event";
|
|
157
159
|
}
|
|
158
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Emitted when the SDK compacts the session — the transcript before the
|
|
163
|
+
* boundary is replaced by a summary, so every cached block after the system
|
|
164
|
+
* prompt is gone and the next turn re-writes it. Shares `type: 'system'`
|
|
165
|
+
* with the init message, so the subtype is what tells them apart.
|
|
166
|
+
*/
|
|
167
|
+
export function isCompactBoundary(
|
|
168
|
+
msg: SDKMessage,
|
|
169
|
+
): msg is SDKCompactBoundaryMessage {
|
|
170
|
+
return msg.type === "system" && msg.subtype === "compact_boundary";
|
|
171
|
+
}
|
|
172
|
+
|
|
159
173
|
// ── Message processors ──────────────────────────────────────────────────────
|
|
160
174
|
|
|
161
175
|
/** Output of `processStreamDelta` when the throttle interval has elapsed. */
|
|
@@ -334,6 +348,19 @@ export function extractToolResults(msg: SDKUserMessage): ToolResultInfo[] {
|
|
|
334
348
|
return results;
|
|
335
349
|
}
|
|
336
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Record a compaction boundary. Observational only: the turn proceeds
|
|
353
|
+
* exactly as it did before this message was recognised — what changes is
|
|
354
|
+
* that `session.compacted.*` now says how often the SDK compacts and how
|
|
355
|
+
* much it reclaims (docs/cache-economics.md, PR A step 3).
|
|
356
|
+
*/
|
|
357
|
+
export function processCompactBoundary(
|
|
358
|
+
msg: SDKCompactBoundaryMessage,
|
|
359
|
+
chatId: string,
|
|
360
|
+
): void {
|
|
361
|
+
recordCompactBoundary(chatId, msg.compact_metadata);
|
|
362
|
+
}
|
|
363
|
+
|
|
337
364
|
/** Context fill of the last API iteration + whether the turn's first request hit the cache. */
|
|
338
365
|
function readContextFill(
|
|
339
366
|
state: StreamState,
|
|
@@ -450,4 +477,4 @@ export function processResultMessage(
|
|
|
450
477
|
export {
|
|
451
478
|
normalizeForDedupe,
|
|
452
479
|
isDuplicateOfDelivered,
|
|
453
|
-
} from "../
|
|
480
|
+
} from "../runtime/turn/delivered-text.js";
|
|
@@ -11,7 +11,7 @@ import { getSession } from "../../storage/sessions.js";
|
|
|
11
11
|
import { log, logWarn } from "../../util/log.js";
|
|
12
12
|
import { getConfig } from "./state.js";
|
|
13
13
|
import { buildSdkOptions } from "./options.js";
|
|
14
|
-
import { prepareSystemPrompt } from "../
|
|
14
|
+
import { prepareSystemPrompt } from "../runtime/index.js";
|
|
15
15
|
|
|
16
16
|
export async function warmSession(chatId: string): Promise<void> {
|
|
17
17
|
// Guard against being called before initAgent()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Codex backend constants.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { buildDeliveryContract } from "../
|
|
5
|
+
import { buildDeliveryContract } from "../runtime/prompt/delivery-contract.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* System-prompt suffix appended to the user-configured system prompt.
|
|
@@ -10,8 +10,8 @@ import { registerBackend } from "../../core/agent-runtime/backend-registry.js";
|
|
|
10
10
|
import { codexDoctorChecks } from "./doctor.js";
|
|
11
11
|
import type { BackendFactory } from "../../core/agent-runtime/backend-registry.js";
|
|
12
12
|
import { log } from "../../util/log.js";
|
|
13
|
-
import { handlerToEvents } from "../
|
|
14
|
-
import { interruptChatTurn } from "../
|
|
13
|
+
import { handlerToEvents } from "../runtime/turn/handler-to-events.js";
|
|
14
|
+
import { interruptChatTurn } from "../runtime/turn/turn-interrupt.js";
|
|
15
15
|
import {
|
|
16
16
|
composeBackend,
|
|
17
17
|
type ChatBackend,
|