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
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import type { WASocket } from "baileys";
|
|
12
12
|
import type { TalonConfig } from "../../core/config/index.js";
|
|
13
13
|
import type { Gateway } from "../../core/engine/gateway.js";
|
|
14
|
-
import { bareId } from "./identity.js";
|
|
14
|
+
import { bareId } from "./connection/identity.js";
|
|
15
15
|
|
|
16
16
|
type WhatsAppSettings = {
|
|
17
17
|
allowedJids: string[];
|
package/src/index.ts
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Dispatches the hidden `_mcp-launch` (MCP supervisor) and `_lua-run`
|
|
5
5
|
* (WASM Lua trigger runner) subcommands BEFORE the app graph loads —
|
|
6
|
-
* both are Talon re-invoking itself (see
|
|
6
|
+
* both are Talon re-invoking itself (see core/mcp-hub/launcher.ts). The
|
|
7
7
|
* dynamic import keeps these helper processes light: they evaluate this
|
|
8
8
|
* shim and their own module, never the backends/frontends/plugins.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
MCP_LAUNCH_SUBCOMMAND,
|
|
13
|
+
runSupervisor,
|
|
14
|
+
} from "./core/mcp-hub/launcher.js";
|
|
15
|
+
import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/scripts/lua.js";
|
|
13
16
|
|
|
14
17
|
if (process.argv[2] === MCP_LAUNCH_SUBCOMMAND) {
|
|
15
18
|
await runSupervisor(process.argv.slice(3));
|
package/src/storage/db.ts
CHANGED
|
@@ -69,7 +69,7 @@ let db: SqlDatabase | null = null;
|
|
|
69
69
|
* Column reconciliation runs first: `ALTER TABLE … ADD COLUMN` has no
|
|
70
70
|
* IF NOT EXISTS form, so columns added to already-shipped tables
|
|
71
71
|
* (media_index.content_hash, sessions.metrics,
|
|
72
|
-
* history_messages.attachments) are ensured by attempting the ALTER and
|
|
72
|
+
* history_messages.attachments, sessions.last_turn_ended_at) are ensured by attempting the ALTER and
|
|
73
73
|
* swallowing the two expected failures — "duplicate column name"
|
|
74
74
|
* (column already there) and "no such table" (fresh database; the
|
|
75
75
|
* CREATE TABLE in schema.sql includes the column).
|
|
@@ -100,6 +100,11 @@ function ensureSchema(database: SqlDatabase): void {
|
|
|
100
100
|
} catch {
|
|
101
101
|
/* duplicate column or no such table — both mean nothing to do */
|
|
102
102
|
}
|
|
103
|
+
try {
|
|
104
|
+
database.exec(dbSql.addSessionsLastTurnEndedAtColumn);
|
|
105
|
+
} catch {
|
|
106
|
+
/* duplicate column or no such table — both mean nothing to do */
|
|
107
|
+
}
|
|
103
108
|
database.exec("BEGIN");
|
|
104
109
|
try {
|
|
105
110
|
database.exec(SCHEMA);
|
package/src/storage/memory.ts
CHANGED
|
@@ -206,6 +206,25 @@ function similarityQuery(text: string): string {
|
|
|
206
206
|
.join(" OR ");
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* The near-duplicate probe, in one place: live rows of the same
|
|
211
|
+
* kind + subject whose text best matches `text` (bm25 order), with
|
|
212
|
+
* `excludeId` left out. `assertMemory` excludes the row it just wrote;
|
|
213
|
+
* a caller probing *before* writing has nothing to exclude and passes
|
|
214
|
+
* `0`, which is not a valid rowid.
|
|
215
|
+
*/
|
|
216
|
+
function similarRows(
|
|
217
|
+
kind: MemoryKind,
|
|
218
|
+
subject: string,
|
|
219
|
+
text: string,
|
|
220
|
+
excludeId: number,
|
|
221
|
+
limit: number,
|
|
222
|
+
): MemoryRow[] {
|
|
223
|
+
const match = similarityQuery(text);
|
|
224
|
+
if (!match) return [];
|
|
225
|
+
return repo.similar(match, kind, subject, excludeId, limit);
|
|
226
|
+
}
|
|
227
|
+
|
|
209
228
|
/**
|
|
210
229
|
* Load a row that a mutation is about to change, or explain why it
|
|
211
230
|
* can't. Only a live row is mutable: a dropped one is in the graveyard
|
|
@@ -280,10 +299,13 @@ export function assertMemory(input: MemoryInput): {
|
|
|
280
299
|
const row = normalize(input);
|
|
281
300
|
return inTransaction(() => {
|
|
282
301
|
const id = insertWithHistory(row, "assert");
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
302
|
+
const similar = similarRows(
|
|
303
|
+
row.kind,
|
|
304
|
+
row.subject,
|
|
305
|
+
row.text,
|
|
306
|
+
id,
|
|
307
|
+
SIMILAR_LIMIT,
|
|
308
|
+
);
|
|
287
309
|
return { id, similar };
|
|
288
310
|
});
|
|
289
311
|
}
|
|
@@ -478,14 +500,43 @@ export function listMemories(opts: MemoryListOptions = {}): MemoryRow[] {
|
|
|
478
500
|
* input is quoted into a literal FTS5 expression by the shared
|
|
479
501
|
* `ftsQuote` core, so operators and punctuation in a query are matched
|
|
480
502
|
* as text rather than parsed as syntax.
|
|
503
|
+
*
|
|
504
|
+
* `match` picks how the query's terms combine:
|
|
505
|
+
*
|
|
506
|
+
* - `"all"` (default) — every term must appear. Right for a search
|
|
507
|
+
* someone typed on purpose (`talon memory search`, `/memory`).
|
|
508
|
+
* - `"any"` — terms are OR-ed and bm25 ranks, the same expression
|
|
509
|
+
* near-duplicate detection already uses. Right for a query that is
|
|
510
|
+
* a whole sentence nobody wrote as a query — a chat turn's inbound
|
|
511
|
+
* message (`core/memory/turn-retrieval.ts`), where AND-ing every
|
|
512
|
+
* word means matching nothing.
|
|
481
513
|
*/
|
|
482
514
|
export function searchMemories(
|
|
483
515
|
query: string,
|
|
484
|
-
opts: { kind?: MemoryKind; limit?: number } = {},
|
|
516
|
+
opts: { kind?: MemoryKind; limit?: number; match?: "all" | "any" } = {},
|
|
485
517
|
): MemoryRow[] {
|
|
486
|
-
const
|
|
487
|
-
if (!
|
|
488
|
-
return repo.searchFts(
|
|
518
|
+
const expr = opts.match === "any" ? similarityQuery(query) : ftsQuote(query);
|
|
519
|
+
if (!expr) return [];
|
|
520
|
+
return repo.searchFts(expr, opts.kind, opts.limit ?? DEFAULT_SEARCH_LIMIT);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* The near-duplicate candidates a claim *would* report if it were
|
|
525
|
+
* asserted now — the same FTS probe `assertMemory` runs, without
|
|
526
|
+
* writing anything.
|
|
527
|
+
*
|
|
528
|
+
* This is what lets the write path offer supersede-instead-of-append
|
|
529
|
+
* before a second row exists (plan §3.2): `remember` probes first, and
|
|
530
|
+
* only inserts once the caller has either picked a row to supersede or
|
|
531
|
+
* said the claim really is separate.
|
|
532
|
+
*/
|
|
533
|
+
export function findSimilarMemories(
|
|
534
|
+
kind: MemoryKind,
|
|
535
|
+
subject: string,
|
|
536
|
+
text: string,
|
|
537
|
+
limit: number = SIMILAR_LIMIT,
|
|
538
|
+
): MemoryRow[] {
|
|
539
|
+
return similarRows(kind, subject, text, 0, limit);
|
|
489
540
|
}
|
|
490
541
|
|
|
491
542
|
/** The audit trail for one row, oldest entry first. */
|
package/src/storage/metrics.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { emptyPhases, TURN_PHASES, type TurnPhase } from "./session-record.js";
|
|
|
15
15
|
const PHASE_HISTOGRAM: Record<TurnPhase, string> = {
|
|
16
16
|
queueWait: "turn.queue_wait_ms",
|
|
17
17
|
warpResolve: "turn.warp_resolve_ms",
|
|
18
|
+
memory: "turn.memory_ms",
|
|
18
19
|
firstToken: "turn.first_token_ms",
|
|
19
20
|
stream: "turn.stream_ms",
|
|
20
21
|
delivery: "turn.delivery_ms",
|
|
@@ -30,6 +31,42 @@ const legacyCounters = new Map<string, number>();
|
|
|
30
31
|
*/
|
|
31
32
|
const processHistograms = new Map<string, MetricsLatencyAgg>();
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* A chat's last cross-turn cache verdict — did the turn's FIRST request
|
|
36
|
+
* read the previous turn's prefix (`hit`), pay to re-write it (`miss`), or
|
|
37
|
+
* was nothing cacheable at all (`none`)? Mirrors `CrossTurnVerdict` in
|
|
38
|
+
* backend/runtime/cache/cache-telemetry.ts, which owns the classification; the
|
|
39
|
+
* union is restated here because `/status` renders it and frontends may
|
|
40
|
+
* not import backend/ (.dependency-cruiser.cjs: frontend-not-to-backend).
|
|
41
|
+
*/
|
|
42
|
+
export type CacheVerdict = "hit" | "miss" | "none";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Per-chat last verdict. Process-local and deliberately unpersisted: it
|
|
46
|
+
* describes the live prefix, which dies with the process anyway, and
|
|
47
|
+
* `/status` is the only reader. Bounded like the per-chat maps in
|
|
48
|
+
* cache-telemetry.ts, insertion-ordered eviction.
|
|
49
|
+
*/
|
|
50
|
+
const MAX_TRACKED_CHATS = 256;
|
|
51
|
+
const lastCacheVerdicts = new Map<string, CacheVerdict>();
|
|
52
|
+
|
|
53
|
+
/** Record the chat's newest cross-turn cache verdict. */
|
|
54
|
+
export function noteCacheVerdict(chatId: string, verdict: CacheVerdict): void {
|
|
55
|
+
if (
|
|
56
|
+
lastCacheVerdicts.size >= MAX_TRACKED_CHATS &&
|
|
57
|
+
!lastCacheVerdicts.has(chatId)
|
|
58
|
+
) {
|
|
59
|
+
const oldest = lastCacheVerdicts.keys().next().value;
|
|
60
|
+
if (oldest !== undefined) lastCacheVerdicts.delete(oldest);
|
|
61
|
+
}
|
|
62
|
+
lastCacheVerdicts.set(chatId, verdict);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The chat's last cross-turn verdict, or undefined if none was recorded. */
|
|
66
|
+
export function getCacheVerdict(chatId: string): CacheVerdict | undefined {
|
|
67
|
+
return lastCacheVerdicts.get(chatId);
|
|
68
|
+
}
|
|
69
|
+
|
|
33
70
|
export type MetricsSnapshot = {
|
|
34
71
|
counters: Record<string, number>;
|
|
35
72
|
histograms: Record<
|
|
@@ -202,5 +239,6 @@ export function getTodayMetrics(): MetricsSnapshot {
|
|
|
202
239
|
export function resetMetrics(): void {
|
|
203
240
|
legacyCounters.clear();
|
|
204
241
|
processHistograms.clear();
|
|
242
|
+
lastCacheVerdicts.clear();
|
|
205
243
|
resetAllSessionMetrics();
|
|
206
244
|
}
|
|
@@ -42,6 +42,7 @@ type Row = {
|
|
|
42
42
|
total_response_ms: number;
|
|
43
43
|
last_response_ms: number;
|
|
44
44
|
fastest_response_ms: number | null;
|
|
45
|
+
last_turn_ended_at: number | null;
|
|
45
46
|
metrics: string | null;
|
|
46
47
|
};
|
|
47
48
|
|
|
@@ -81,6 +82,7 @@ function rowToSession(row: Row): SessionState {
|
|
|
81
82
|
lastBotMessageId: row.last_bot_message_id ?? undefined,
|
|
82
83
|
sessionName: row.session_name ?? undefined,
|
|
83
84
|
lastModel: row.last_model ?? undefined,
|
|
85
|
+
lastTurnEndedAt: row.last_turn_ended_at ?? undefined,
|
|
84
86
|
};
|
|
85
87
|
}
|
|
86
88
|
|
|
@@ -120,6 +122,10 @@ export function upsert(chatId: string, session: SessionState): void {
|
|
|
120
122
|
num(usage?.totalResponseMs),
|
|
121
123
|
num(usage?.lastResponseMs),
|
|
122
124
|
typeof fastest === "number" && Number.isFinite(fastest) ? fastest : null,
|
|
125
|
+
typeof session.lastTurnEndedAt === "number" &&
|
|
126
|
+
Number.isFinite(session.lastTurnEndedAt)
|
|
127
|
+
? session.lastTurnEndedAt
|
|
128
|
+
: null,
|
|
123
129
|
JSON.stringify(session.metrics ?? emptyMetrics()),
|
|
124
130
|
);
|
|
125
131
|
}
|
|
@@ -56,12 +56,14 @@ export type MetricsLatencyAgg = {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Where a turn's wall-clock went, as seen from the Weaver: waiting in the
|
|
59
|
-
* chat's FIFO, resolving the warp,
|
|
60
|
-
* whole stream, and the slice of it spent
|
|
59
|
+
* chat's FIFO, resolving the warp, retrieving this turn's memory, until
|
|
60
|
+
* the backend's first event, the whole stream, and the slice of it spent
|
|
61
|
+
* inside frontend delivery.
|
|
61
62
|
*/
|
|
62
63
|
export const TURN_PHASES = [
|
|
63
64
|
"queueWait",
|
|
64
65
|
"warpResolve",
|
|
66
|
+
"memory",
|
|
65
67
|
"firstToken",
|
|
66
68
|
"stream",
|
|
67
69
|
"delivery",
|
|
@@ -104,6 +106,14 @@ export type SessionState = {
|
|
|
104
106
|
sessionName?: string;
|
|
105
107
|
/** Model used for this session's cost tracking. */
|
|
106
108
|
lastModel?: string;
|
|
109
|
+
/**
|
|
110
|
+
* When the last turn of this chat finished (ms epoch), or undefined when
|
|
111
|
+
* no turn has completed yet. Distinct from `lastActive`, which any
|
|
112
|
+
* session write moves: this one only ever means "the transcript stopped
|
|
113
|
+
* growing here", which is what the prompt cache's TTL runs against —
|
|
114
|
+
* warm iff `now - lastTurnEndedAt < ttl` (docs/cache-economics.md).
|
|
115
|
+
*/
|
|
116
|
+
lastTurnEndedAt?: number;
|
|
107
117
|
};
|
|
108
118
|
|
|
109
119
|
export const emptyUsage = (): SessionUsage => ({
|
|
@@ -146,6 +156,7 @@ export const emptyLatency = (): MetricsLatencyAgg => ({
|
|
|
146
156
|
export const emptyPhases = (): MetricsPhaseAggs => ({
|
|
147
157
|
queueWait: emptyLatency(),
|
|
148
158
|
warpResolve: emptyLatency(),
|
|
159
|
+
memory: emptyLatency(),
|
|
149
160
|
firstToken: emptyLatency(),
|
|
150
161
|
stream: emptyLatency(),
|
|
151
162
|
delivery: emptyLatency(),
|
package/src/storage/sessions.ts
CHANGED
|
@@ -480,6 +480,10 @@ export function recordUsage(
|
|
|
480
480
|
session.usage.estimatedCostUsd += turn.costUsd;
|
|
481
481
|
}
|
|
482
482
|
if (turn.model) session.lastModel = turn.model;
|
|
483
|
+
// A turn just ended — this is the timestamp the prompt cache ages
|
|
484
|
+
// against (docs/cache-economics.md). Set on the one seam every backend
|
|
485
|
+
// funnels a finished turn through, failed-but-billed turns included.
|
|
486
|
+
session.lastTurnEndedAt = Date.now();
|
|
483
487
|
if (turn.durationMs && turn.durationMs > 0) {
|
|
484
488
|
session.usage.totalResponseMs =
|
|
485
489
|
(session.usage.totalResponseMs || 0) + turn.durationMs;
|
|
@@ -580,6 +584,12 @@ export type SessionInfo = {
|
|
|
580
584
|
lastModel?: string;
|
|
581
585
|
/** True when a turn is currently streaming and `usage` includes its live so-far counts. */
|
|
582
586
|
turnInProgress?: boolean;
|
|
587
|
+
/**
|
|
588
|
+
* When this chat's last turn finished (ms epoch), or undefined when none
|
|
589
|
+
* has. `/status` reports the idle gap from it; `lastActive` can't stand in
|
|
590
|
+
* because any session write moves that.
|
|
591
|
+
*/
|
|
592
|
+
lastTurnEndedAt?: number;
|
|
583
593
|
};
|
|
584
594
|
|
|
585
595
|
export function getSessionInfo(chatId: string): SessionInfo {
|
|
@@ -594,6 +604,7 @@ export function getSessionInfo(chatId: string): SessionInfo {
|
|
|
594
604
|
sessionName: session?.sessionName,
|
|
595
605
|
lastModel: session?.lastModel,
|
|
596
606
|
turnInProgress: liveTurns.has(chatId),
|
|
607
|
+
lastTurnEndedAt: session?.lastTurnEndedAt,
|
|
597
608
|
};
|
|
598
609
|
}
|
|
599
610
|
|
|
@@ -615,6 +626,7 @@ export function getAllSessions(): Array<{ chatId: string; info: SessionInfo }> {
|
|
|
615
626
|
sessionName: session.sessionName,
|
|
616
627
|
lastModel: session.lastModel,
|
|
617
628
|
turnInProgress: liveTurns.has(chatId),
|
|
629
|
+
lastTurnEndedAt: session.lastTurnEndedAt,
|
|
618
630
|
},
|
|
619
631
|
}));
|
|
620
632
|
}
|
package/src/storage/sql/db.sql
CHANGED
|
@@ -25,3 +25,8 @@ ALTER TABLE sessions ADD COLUMN metrics TEXT NOT NULL DEFAULT '{"lifetime":{"cou
|
|
|
25
25
|
-- carry more than one attachment. Fresh databases get the column via
|
|
26
26
|
-- schema.sql.
|
|
27
27
|
ALTER TABLE history_messages ADD COLUMN attachments TEXT
|
|
28
|
+
|
|
29
|
+
-- name: addSessionsLastTurnEndedAtColumn
|
|
30
|
+
-- Column reconciliation for databases that shipped before the cache-age
|
|
31
|
+
-- signal existed. Fresh databases get the column via schema.sql.
|
|
32
|
+
ALTER TABLE sessions ADD COLUMN last_turn_ended_at INTEGER
|
|
@@ -161,6 +161,10 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
161
161
|
total_response_ms REAL NOT NULL DEFAULT 0,
|
|
162
162
|
last_response_ms REAL NOT NULL DEFAULT 0,
|
|
163
163
|
fastest_response_ms REAL,
|
|
164
|
+
-- When the chat's last turn finished; NULL until one has. Read as the
|
|
165
|
+
-- prompt cache's age signal (docs/cache-economics.md), which is why it
|
|
166
|
+
-- is separate from last_active (moved by any session write).
|
|
167
|
+
last_turn_ended_at INTEGER,
|
|
164
168
|
metrics TEXT NOT NULL DEFAULT '{"lifetime":{"counters":{"queries":0,"toolCalls":0,"turnsWithTools":0,"apiCalls":0,"inputTokens":0,"outputTokens":0,"cacheReadTokens":0,"cacheWriteTokens":0,"failedTurns":0,"flowViolationRetries":0,"flowViolationCapExhausted":0,"trailingTextDropped":0},"latency":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"toolCallsByName":{},"backend":{},"cacheHitPercent":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"toolCallsPerTurn":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"apiCallsPerTurn":{"count":0,"sumMs":0,"minMs":null,"maxMs":0}},"buckets":{}}'
|
|
165
169
|
);
|
|
166
170
|
|
|
@@ -7,15 +7,15 @@ INSERT OR REPLACE INTO sessions
|
|
|
7
7
|
created_at, last_bot_message_id, total_input_tokens, total_output_tokens,
|
|
8
8
|
total_cache_read, total_cache_write, last_prompt_tokens, context_tokens,
|
|
9
9
|
context_window, num_api_calls, estimated_cost_usd, total_response_ms,
|
|
10
|
-
last_response_ms, fastest_response_ms, metrics)
|
|
11
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
10
|
+
last_response_ms, fastest_response_ms, last_turn_ended_at, metrics)
|
|
11
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
12
12
|
|
|
13
13
|
-- name: all
|
|
14
14
|
SELECT chat_id, session_id, session_name, last_model, turns, last_active,
|
|
15
15
|
created_at, last_bot_message_id, total_input_tokens, total_output_tokens,
|
|
16
16
|
total_cache_read, total_cache_write, last_prompt_tokens, context_tokens,
|
|
17
17
|
context_window, num_api_calls, estimated_cost_usd, total_response_ms,
|
|
18
|
-
last_response_ms, fastest_response_ms, metrics
|
|
18
|
+
last_response_ms, fastest_response_ms, last_turn_ended_at, metrics
|
|
19
19
|
FROM sessions
|
|
20
20
|
|
|
21
21
|
-- name: remove
|
|
@@ -166,6 +166,10 @@ CREATE TABLE IF NOT EXISTS sessions (
|
|
|
166
166
|
total_response_ms REAL NOT NULL DEFAULT 0,
|
|
167
167
|
last_response_ms REAL NOT NULL DEFAULT 0,
|
|
168
168
|
fastest_response_ms REAL,
|
|
169
|
+
-- When the chat's last turn finished; NULL until one has. Read as the
|
|
170
|
+
-- prompt cache's age signal (docs/cache-economics.md), which is why it
|
|
171
|
+
-- is separate from last_active (moved by any session write).
|
|
172
|
+
last_turn_ended_at INTEGER,
|
|
169
173
|
metrics TEXT NOT NULL DEFAULT '{"lifetime":{"counters":{"queries":0,"toolCalls":0,"turnsWithTools":0,"apiCalls":0,"inputTokens":0,"outputTokens":0,"cacheReadTokens":0,"cacheWriteTokens":0,"failedTurns":0,"flowViolationRetries":0,"flowViolationCapExhausted":0,"trailingTextDropped":0},"latency":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"toolCallsByName":{},"backend":{},"cacheHitPercent":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"toolCallsPerTurn":{"count":0,"sumMs":0,"minMs":null,"maxMs":0},"apiCallsPerTurn":{"count":0,"sumMs":0,"minMs":null,"maxMs":0}},"buckets":{}}'
|
|
170
174
|
);
|
|
171
175
|
|
|
@@ -414,6 +418,9 @@ ALTER TABLE sessions ADD COLUMN metrics TEXT NOT NULL DEFAULT '{"lifetime":{"cou
|
|
|
414
418
|
-- carry more than one attachment. Fresh databases get the column via
|
|
415
419
|
-- schema.sql.
|
|
416
420
|
ALTER TABLE history_messages ADD COLUMN attachments TEXT`,
|
|
421
|
+
addSessionsLastTurnEndedAtColumn: `-- Column reconciliation for databases that shipped before the cache-age
|
|
422
|
+
-- signal existed. Fresh databases get the column via schema.sql.
|
|
423
|
+
ALTER TABLE sessions ADD COLUMN last_turn_ended_at INTEGER`,
|
|
417
424
|
} as const;
|
|
418
425
|
|
|
419
426
|
export const goalsSql = {
|
|
@@ -657,13 +664,13 @@ export const sessionsSql = {
|
|
|
657
664
|
created_at, last_bot_message_id, total_input_tokens, total_output_tokens,
|
|
658
665
|
total_cache_read, total_cache_write, last_prompt_tokens, context_tokens,
|
|
659
666
|
context_window, num_api_calls, estimated_cost_usd, total_response_ms,
|
|
660
|
-
last_response_ms, fastest_response_ms, metrics)
|
|
661
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
667
|
+
last_response_ms, fastest_response_ms, last_turn_ended_at, metrics)
|
|
668
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
662
669
|
all: `SELECT chat_id, session_id, session_name, last_model, turns, last_active,
|
|
663
670
|
created_at, last_bot_message_id, total_input_tokens, total_output_tokens,
|
|
664
671
|
total_cache_read, total_cache_write, last_prompt_tokens, context_tokens,
|
|
665
672
|
context_window, num_api_calls, estimated_cost_usd, total_response_ms,
|
|
666
|
-
last_response_ms, fastest_response_ms, metrics
|
|
673
|
+
last_response_ms, fastest_response_ms, last_turn_ended_at, metrics
|
|
667
674
|
FROM sessions`,
|
|
668
675
|
remove: `DELETE FROM sessions WHERE chat_id = ?`,
|
|
669
676
|
} as const;
|
package/src/util/log.ts
CHANGED
package/src/util/paths.ts
CHANGED
|
@@ -116,8 +116,6 @@ export const files = {
|
|
|
116
116
|
triggers: resolve(TALON_ROOT, "data", "triggers.json"),
|
|
117
117
|
/** Legacy JSON native turn meta (imported into talon.db on first boot) */
|
|
118
118
|
nativeTurnMeta: resolve(TALON_ROOT, "data", "native-turn-meta.json"),
|
|
119
|
-
/** Soul kernel state: ~/.talon/data/soul.json (overridable via config.soul.path) */
|
|
120
|
-
soul: resolve(TALON_ROOT, "data", "soul.json"),
|
|
121
119
|
/** Legacy JSON media index (imported into talon.db on first boot) */
|
|
122
120
|
mediaIndex: resolve(TALON_ROOT, "data", "media-index.json"),
|
|
123
121
|
/** Persistent memory: ~/.talon/workspace/memory/memory.md */
|
package/src/util/runtime.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Bun-COMPILED binaries are a third shape detected separately (argv[1]
|
|
13
13
|
* points into the embedded virtual fs) — see the existing `$bunfs`
|
|
14
|
-
* checks at the spawn sites and in `
|
|
14
|
+
* checks at the spawn sites and in `core/mcp-hub/launcher.ts`.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/** True when the current process is executing under the Bun runtime. */
|