talon-agent 4.6.1 → 5.0.0
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 +19 -4
- package/src/backend/claude-sdk/handler.ts +28 -7
- 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 +1 -1
- 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 +1 -1
- 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 +32 -23
- 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 +2 -2
- 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 +4 -19
- package/src/cli.ts +1 -1
- 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 +1 -1
- package/src/core/config/index.ts +15 -11
- package/src/core/daemon/resource-sampler.ts +121 -0
- package/src/core/engine/dispatcher.ts +16 -0
- package/src/core/engine/gateway-actions/cron.ts +2 -2
- package/src/core/engine/gateway-actions/index.ts +3 -0
- package/src/core/engine/gateway-actions/memory.ts +335 -0
- package/src/core/engine/gateway.ts +0 -6
- 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/prompt/assemble.ts +2 -12
- package/src/core/prompt/index.ts +2 -2
- package/src/core/prompt/invalidation.ts +1 -1
- package/src/core/tasks/index.ts +1 -1
- package/src/core/tools/index.ts +2 -0
- package/src/core/tools/memory.ts +128 -0
- package/src/core/tools/types.ts +1 -0
- 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/pulse.ts +1 -1
- package/src/frontend/discord/callbacks/components/settings.ts +1 -1
- package/src/frontend/discord/callbacks/modals.ts +4 -1
- package/src/frontend/discord/commands/admin.ts +1 -35
- package/src/frontend/discord/commands/definitions.ts +0 -11
- package/src/frontend/discord/commands/router.ts +0 -3
- package/src/frontend/discord/commands/session.ts +6 -0
- package/src/frontend/discord/commands/settings.ts +1 -1
- package/src/frontend/discord/middleware.ts +1 -25
- 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/model-commands.ts +1 -1
- package/src/frontend/shared/session-status.ts +35 -8
- package/src/frontend/shared/status-context.ts +101 -2
- package/src/frontend/telegram/admin/background.ts +1 -1
- package/src/frontend/telegram/callbacks/model/backend.ts +1 -1
- package/src/frontend/telegram/callbacks/pulse.ts +1 -1
- package/src/frontend/telegram/callbacks/settings.ts +1 -1
- package/src/frontend/telegram/commands/admin.ts +2 -37
- package/src/frontend/telegram/commands/index.ts +1 -1
- package/src/frontend/telegram/commands/session.ts +6 -0
- package/src/frontend/telegram/commands/settings.ts +1 -1
- package/src/frontend/telegram/handlers/messages.ts +0 -10
- package/src/frontend/telegram/index.ts +1 -5
- package/src/frontend/telegram/middleware.ts +1 -15
- 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 +8 -2
- 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 +1 -1
- package/src/frontend/whatsapp/runtime.ts +1 -1
- package/src/index.ts +1 -1
- 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/boot-timer.ts +15 -1
- package/src/util/chat-id.ts +30 -0
- package/src/util/log.ts +1 -1
- package/src/util/paths.ts +0 -2
- 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/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/core/{scripting/lua-runner.ts → scripts/lua.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/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
|
@@ -19,14 +19,34 @@
|
|
|
19
19
|
import {
|
|
20
20
|
type AgentEvent,
|
|
21
21
|
classifiedToAgentError,
|
|
22
|
-
} from "
|
|
23
|
-
import { classify } from "
|
|
24
|
-
import type { ChatRunParams } from "
|
|
22
|
+
} from "../../../core/agent-runtime/events.js";
|
|
23
|
+
import { classify } from "../../../core/errors.js";
|
|
24
|
+
import type { ChatRunParams } from "../../../core/agent-runtime/capabilities.js";
|
|
25
25
|
import type { QueryParams, QueryResult } from "./handler-types.js";
|
|
26
26
|
import { buildResultEvents } from "./result-events.js";
|
|
27
27
|
|
|
28
28
|
const SENTINEL = Symbol("handler-to-events:sentinel");
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* The DATA half of `QueryParams`, carried verbatim from the canonical
|
|
32
|
+
* `ChatRunParams` (only `ModelRef` flattens to `model.id`). The
|
|
33
|
+
* callback half is the queue's and is built per run below. Keeping the
|
|
34
|
+
* carry in one place is what stops a field — `retrievedMemory` being
|
|
35
|
+
* the one #639 lost — from reaching some handlers and not others.
|
|
36
|
+
*/
|
|
37
|
+
function turnFields(params: ChatRunParams) {
|
|
38
|
+
return {
|
|
39
|
+
chatId: params.chatId,
|
|
40
|
+
model: params.model.id,
|
|
41
|
+
text: params.text,
|
|
42
|
+
senderName: params.senderName,
|
|
43
|
+
senderHandle: params.senderHandle,
|
|
44
|
+
isGroup: params.isGroup,
|
|
45
|
+
messageId: params.messageId,
|
|
46
|
+
retrievedMemory: params.retrievedMemory,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
30
50
|
type QueueEvent = AgentEvent | typeof SENTINEL;
|
|
31
51
|
|
|
32
52
|
/**
|
|
@@ -79,13 +99,7 @@ export async function* handlerToEvents(
|
|
|
79
99
|
let lastAccumulated = "";
|
|
80
100
|
|
|
81
101
|
const handlerParams: QueryParams = {
|
|
82
|
-
|
|
83
|
-
model: params.model.id,
|
|
84
|
-
text: params.text,
|
|
85
|
-
senderName: params.senderName,
|
|
86
|
-
senderHandle: params.senderHandle,
|
|
87
|
-
isGroup: params.isGroup,
|
|
88
|
-
messageId: params.messageId,
|
|
102
|
+
...turnFields(params),
|
|
89
103
|
onStreamDelta: (accumulated) => {
|
|
90
104
|
if (typeof accumulated !== "string" || accumulated.length === 0) {
|
|
91
105
|
return;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* stream loop that `handler-to-events.ts` adapts onto the native
|
|
11
11
|
* `AsyncIterable<AgentEvent>` shape at the factory boundary.
|
|
12
12
|
*
|
|
13
|
-
* Living in `backend/
|
|
13
|
+
* Living in `backend/runtime/turn/` keeps `core/types.ts` clean of any
|
|
14
14
|
* implementation-detail shapes, so the dispatcher / cron / triggers /
|
|
15
15
|
* frontends never accidentally couple to the callback contract.
|
|
16
16
|
*/
|
|
@@ -35,6 +35,12 @@ export type QueryParams = {
|
|
|
35
35
|
* Provider message ID. Telegram is numeric; Discord snowflakes are strings.
|
|
36
36
|
*/
|
|
37
37
|
messageId?: number | string;
|
|
38
|
+
/**
|
|
39
|
+
* Per-turn retrieved memory, carried verbatim from `ChatRunParams`.
|
|
40
|
+
* The handler passes it to `formatUserPrompt` and does nothing else
|
|
41
|
+
* with it — see `backend/runtime/prompt/prompt-format.ts`.
|
|
42
|
+
*/
|
|
43
|
+
retrievedMemory?: string;
|
|
38
44
|
onStreamDelta?: (accumulated: string, phase?: "thinking" | "text") => void;
|
|
39
45
|
onTextBlock?: (text: string) => Promise<void>;
|
|
40
46
|
/**
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* model swap) because those touch backend-specific storage.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import type { TalonError } from "
|
|
25
|
-
import { getFallbackModel } from "
|
|
24
|
+
import type { TalonError } from "../../../core/errors.js";
|
|
25
|
+
import { getFallbackModel } from "../../../core/models/catalog.js";
|
|
26
26
|
|
|
27
27
|
// ── Public API ──────────────────────────────────────────────────────────────
|
|
28
28
|
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* logging imports so the adapter stays a pure event translator.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { AgentEvent } from "
|
|
9
|
-
import type { TokenUsageSnapshot } from "
|
|
8
|
+
import type { AgentEvent } from "../../../core/agent-runtime/events.js";
|
|
9
|
+
import type { TokenUsageSnapshot } from "../usage.js";
|
|
10
10
|
|
|
11
11
|
export function buildResultEvents(inputs: {
|
|
12
12
|
text: string;
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { captureDeliveredText } from "./delivered-text.js";
|
|
23
|
-
import { isTurnTerminator, stripMcpPrefix } from "
|
|
24
|
-
import { updateLiveTurn } from "
|
|
23
|
+
import { isTurnTerminator, stripMcpPrefix } from "../../../core/tools/index.js";
|
|
24
|
+
import { updateLiveTurn } from "../../../storage/sessions.js";
|
|
25
25
|
|
|
26
26
|
// ── State shape ─────────────────────────────────────────────────────────────
|
|
27
27
|
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* partial text and real usage — never as an error, never as a retry.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { log, logWarn } from "
|
|
21
|
-
import { incrementCounter } from "
|
|
20
|
+
import { log, logWarn } from "../../../util/log.js";
|
|
21
|
+
import { incrementCounter } from "../../../storage/metrics.js";
|
|
22
22
|
|
|
23
23
|
const interrupts = new Map<string, () => void | Promise<void>>();
|
|
24
24
|
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
recordUsage,
|
|
24
24
|
setSessionId,
|
|
25
25
|
setSessionName,
|
|
26
|
-
} from "
|
|
27
|
-
import { log } from "
|
|
28
|
-
import { extractSessionName } from "
|
|
29
|
-
import { traceMessage } from "
|
|
26
|
+
} from "../../../storage/sessions.js";
|
|
27
|
+
import { log } from "../../../util/log.js";
|
|
28
|
+
import { extractSessionName } from "../../../util/session-name.js";
|
|
29
|
+
import { traceMessage } from "../../../util/trace.js";
|
|
30
30
|
import {
|
|
31
31
|
FLOW_VIOLATION_MAX_RETRIES,
|
|
32
32
|
detectFlowViolation,
|
|
@@ -37,9 +37,9 @@ import {
|
|
|
37
37
|
recordFailedTurnAccounting,
|
|
38
38
|
recordFlowViolation,
|
|
39
39
|
recordTurnMetrics,
|
|
40
|
-
} from "
|
|
40
|
+
} from "../metrics.js";
|
|
41
41
|
import type { StreamState } from "./stream-state.js";
|
|
42
|
-
import { summarizeUsage, type TokenUsageSnapshot } from "
|
|
42
|
+
import { summarizeUsage, type TokenUsageSnapshot } from "../usage.js";
|
|
43
43
|
|
|
44
44
|
// ── Usage snapshot ──────────────────────────────────────────────────────────
|
|
45
45
|
|
package/src/bootstrap.ts
CHANGED
|
@@ -24,16 +24,16 @@ import {
|
|
|
24
24
|
} from "./core/engine/dispatcher.js";
|
|
25
25
|
import { bus } from "./core/bus/index.js";
|
|
26
26
|
import { appendToJournal } from "./storage/journal.js";
|
|
27
|
-
import { initPulse, resetPulseTimer } from "./core/background/pulse.js";
|
|
28
|
-
import { initCron } from "./core/background/cron.js";
|
|
29
|
-
import { initPlanAlerts } from "./core/background/plan-alerts.js";
|
|
27
|
+
import { initPulse, resetPulseTimer } from "./core/background/pulse/pulse.js";
|
|
28
|
+
import { initCron } from "./core/background/cron/scheduler.js";
|
|
29
|
+
import { initPlanAlerts } from "./core/background/pulse/plan-alerts.js";
|
|
30
30
|
import { setAdminNotifier } from "./core/frontend-runtime/admin-notify.js";
|
|
31
31
|
import { startAuthExpiryMonitor } from "./core/auth/expiry-monitor.js";
|
|
32
32
|
import {
|
|
33
33
|
initTriggers,
|
|
34
34
|
resumeAfterRestart as resumeTriggersAfterRestart,
|
|
35
35
|
} from "./core/background/triggers/index.js";
|
|
36
|
-
import { initDream, maybeStartDream } from "./core/background/dream.js";
|
|
36
|
+
import { initDream, maybeStartDream } from "./core/background/dream/index.js";
|
|
37
37
|
import { initHeartbeat } from "./core/background/heartbeat/index.js";
|
|
38
38
|
import { log, logWarn, logDebug } from "./util/log.js";
|
|
39
39
|
import { bootPhase } from "./util/boot-timer.js";
|
|
@@ -489,21 +489,6 @@ export async function initBackendAndDispatcher(
|
|
|
489
489
|
// alerts above.
|
|
490
490
|
wireAdminNotifier(config, frontends);
|
|
491
491
|
|
|
492
|
-
// Soul — initialize the identity kernel singleton from config so the prompt
|
|
493
|
-
// injection / dream hooks see the right enabled state. Off by default; a
|
|
494
|
-
// failure here must never block startup.
|
|
495
|
-
try {
|
|
496
|
-
const { SoulService, setSoul } = await import("./core/soul/service.js");
|
|
497
|
-
setSoul(
|
|
498
|
-
SoulService.create({
|
|
499
|
-
enabled: config.soul?.enabled ?? false,
|
|
500
|
-
...(config.soul?.path ? { path: config.soul.path } : {}),
|
|
501
|
-
}),
|
|
502
|
-
);
|
|
503
|
-
} catch (err) {
|
|
504
|
-
log("soul", `init skipped: ${String(err)}`);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
492
|
// Only enable mempalace dream integration if the plugin actually registered
|
|
508
493
|
let mempalaceCfg: { pythonPath: string; palacePath: string } | undefined;
|
|
509
494
|
if (config.mempalace?.enabled) {
|
package/src/cli.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { MCP_LAUNCH_SUBCOMMAND, runSupervisor } from "./util/mcp-launcher.js";
|
|
20
|
-
import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/
|
|
20
|
+
import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/scripts/lua.js";
|
|
21
21
|
|
|
22
22
|
// Hidden subcommand dispatch — must run before anything else. Talon
|
|
23
23
|
// supervises MCP stdio children (`_mcp-launch`) and runs WASM-sandboxed
|
|
@@ -56,6 +56,17 @@ export interface ChatRunParams {
|
|
|
56
56
|
isGroup?: boolean;
|
|
57
57
|
/** Provider message ID. Telegram is numeric; Discord snowflakes are strings. */
|
|
58
58
|
messageId?: number | string;
|
|
59
|
+
/**
|
|
60
|
+
* Memory retrieved for this turn by `core/memory/turn-retrieval.ts`,
|
|
61
|
+
* already ranked, trust-filtered and budgeted. The Weaver resolves it
|
|
62
|
+
* before the call; a backend's only job is to hand it to
|
|
63
|
+
* `formatUserPrompt`, which owns the rendering.
|
|
64
|
+
*
|
|
65
|
+
* Turn-scoped and user-turn-only: it must never reach
|
|
66
|
+
* `prepareSystemPrompt()` or a backend `system` field, or the
|
|
67
|
+
* per-session frozen prompt stops being frozen (plan §3.6).
|
|
68
|
+
*/
|
|
69
|
+
retrievedMemory?: string;
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
// ── Catalog types ───────────────────────────────────────────────────────────
|
|
@@ -199,6 +199,80 @@ export async function assertCompletedUsageMatchesUsageEvent(
|
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* `ChatRunParams.retrievedMemory` must reach the prompt the backend
|
|
204
|
+
* sends, in the USER turn, after the message text.
|
|
205
|
+
*
|
|
206
|
+
* This is the clause #639 was written in the absence of: the old
|
|
207
|
+
* pre-retrieval field was honoured by two backends and dropped in
|
|
208
|
+
* silence by the other four, a divergence that would have become a
|
|
209
|
+
* real bug the day a retriever existed. Now there is one renderer
|
|
210
|
+
* (`backend/runtime/prompt/prompt-format.ts`) that every backend already calls
|
|
211
|
+
* for its time tag and `msg_id` framing — and this assertion is what
|
|
212
|
+
* stops a backend from quietly building its prompt some other way.
|
|
213
|
+
*
|
|
214
|
+
* The caller supplies `capturePrompt`, returning the prompt the
|
|
215
|
+
* backend built for the last run: `core/` cannot import `backend/`, so
|
|
216
|
+
* the rendering itself is asserted by the caller, which can. `marker`
|
|
217
|
+
* is the retrieved text; it must appear after the user's own text, and
|
|
218
|
+
* must not appear at all when the field is absent.
|
|
219
|
+
*/
|
|
220
|
+
export async function assertChatBackendCarriesRetrievedMemory(
|
|
221
|
+
backend: Backend,
|
|
222
|
+
capturePrompt: () => string | undefined,
|
|
223
|
+
options: { text?: string; chatId?: string; marker?: string } = {},
|
|
224
|
+
): Promise<void> {
|
|
225
|
+
const chat = backend.chat;
|
|
226
|
+
if (!chat) return;
|
|
227
|
+
const text = options.text ?? "ping";
|
|
228
|
+
const marker = options.marker ?? "#1 [fact] contract: remembered thing";
|
|
229
|
+
const run = async (retrievedMemory?: string): Promise<string> => {
|
|
230
|
+
await drain(
|
|
231
|
+
chat.runChatTurn({
|
|
232
|
+
chatId: options.chatId ?? "contract-test-chat",
|
|
233
|
+
model: makeBareModelRef(backend.id, "contract-test-model"),
|
|
234
|
+
text,
|
|
235
|
+
senderName: "ContractTest",
|
|
236
|
+
...(retrievedMemory !== undefined ? { retrievedMemory } : {}),
|
|
237
|
+
}),
|
|
238
|
+
);
|
|
239
|
+
const prompt = capturePrompt();
|
|
240
|
+
if (prompt === undefined) {
|
|
241
|
+
throw new ContractViolation(
|
|
242
|
+
backend.id,
|
|
243
|
+
"ChatBackend.carriesRetrievedMemory",
|
|
244
|
+
"the backend built no prompt for the turn",
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
return prompt;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const withMemory = await run(marker);
|
|
251
|
+
if (!withMemory.includes(marker)) {
|
|
252
|
+
throw new ContractViolation(
|
|
253
|
+
backend.id,
|
|
254
|
+
"ChatBackend.carriesRetrievedMemory",
|
|
255
|
+
`retrievedMemory never reached the prompt: ${JSON.stringify(withMemory)}`,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
if (withMemory.indexOf(marker) < withMemory.indexOf(text)) {
|
|
259
|
+
throw new ContractViolation(
|
|
260
|
+
backend.id,
|
|
261
|
+
"ChatBackend.carriesRetrievedMemory",
|
|
262
|
+
"the memory block precedes the user text; it must be appended after it",
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const without = await run();
|
|
267
|
+
if (without.includes(marker)) {
|
|
268
|
+
throw new ContractViolation(
|
|
269
|
+
backend.id,
|
|
270
|
+
"ChatBackend.carriesRetrievedMemory",
|
|
271
|
+
"the memory block appeared in a turn that carried no retrievedMemory",
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
202
276
|
/**
|
|
203
277
|
* Backends that expose a `BackgroundRunner` must terminate with
|
|
204
278
|
* `completed` or `error` and must emit `run_started` first — same
|
|
@@ -323,7 +397,16 @@ export async function assertUsageTelemetryShape(
|
|
|
323
397
|
*/
|
|
324
398
|
export async function assertBackendContract(
|
|
325
399
|
backend: Backend,
|
|
326
|
-
options: {
|
|
400
|
+
options: {
|
|
401
|
+
text?: string;
|
|
402
|
+
chatId?: string;
|
|
403
|
+
/**
|
|
404
|
+
* The prompt the backend built for the last run, when the fixture
|
|
405
|
+
* can capture it. Supplying it opts the turn-retrieval clause into
|
|
406
|
+
* the suite; omitting it skips that clause only.
|
|
407
|
+
*/
|
|
408
|
+
capturePrompt?: () => string | undefined;
|
|
409
|
+
} = {},
|
|
327
410
|
): Promise<string[]> {
|
|
328
411
|
const checked: string[] = [];
|
|
329
412
|
|
|
@@ -336,6 +419,14 @@ export async function assertBackendContract(
|
|
|
336
419
|
checked.push("ChatBackend.singleUsage");
|
|
337
420
|
await assertCompletedUsageMatchesUsageEvent(backend, options);
|
|
338
421
|
checked.push("ChatBackend.completedUsageMatches");
|
|
422
|
+
if (options.capturePrompt) {
|
|
423
|
+
await assertChatBackendCarriesRetrievedMemory(
|
|
424
|
+
backend,
|
|
425
|
+
options.capturePrompt,
|
|
426
|
+
options,
|
|
427
|
+
);
|
|
428
|
+
checked.push("ChatBackend.carriesRetrievedMemory");
|
|
429
|
+
}
|
|
339
430
|
}
|
|
340
431
|
if (backend.background) {
|
|
341
432
|
await assertBackgroundRunnerLifecycle(backend);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* longer render markdown logs themselves and core no longer parses
|
|
10
10
|
* backend-specific output.
|
|
11
11
|
*
|
|
12
|
-
* The shared wrapper `backend/
|
|
12
|
+
* The shared wrapper `backend/runtime/turn/handler-to-events.ts` converts
|
|
13
13
|
* each backend's existing callback-driven `handleMessage` into the
|
|
14
14
|
* canonical sequence: `run_started → text_delta* →
|
|
15
15
|
* assistant_message* → tool_call* → usage → completed`. Backends
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* unset to avoid sweeping the other context's subprocesses.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { BackgroundRunner } from "
|
|
18
|
-
import type { OneShotAgentParams, OneShotUsage } from "
|
|
19
|
-
import { logWarn, logError } from "
|
|
17
|
+
import type { BackgroundRunner } from "../../agent-runtime/capabilities.js";
|
|
18
|
+
import type { OneShotAgentParams, OneShotUsage } from "../../types.js";
|
|
19
|
+
import { logWarn, logError } from "../../../util/log.js";
|
|
20
20
|
|
|
21
21
|
/** Default bounded grace after an abort before giving up on the backend. */
|
|
22
22
|
const DEFAULT_ABORT_GRACE_MS = 30 * 1000;
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { mkdir, appendFile } from "node:fs/promises";
|
|
17
|
-
import { dirs } from "
|
|
18
|
-
import { log, logWarn } from "
|
|
17
|
+
import { dirs } from "../../../util/paths.js";
|
|
18
|
+
import { log, logWarn } from "../../../util/log.js";
|
|
19
19
|
import {
|
|
20
20
|
acquireBackendInstance,
|
|
21
21
|
isModelValidForBackend,
|
|
22
|
-
} from "
|
|
23
|
-
import { taskTable } from "
|
|
24
|
-
import type { OneShotAgentParams } from "
|
|
22
|
+
} from "../../engine/backend-controller/index.js";
|
|
23
|
+
import { taskTable } from "../../tasks/index.js";
|
|
24
|
+
import type { OneShotAgentParams } from "../../types.js";
|
|
25
25
|
import { runIsolatedAgent } from "./isolated-agent.js";
|
|
26
26
|
import {
|
|
27
27
|
buildJobSystemPrompt,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { Cron } from "croner";
|
|
23
|
-
import { getActiveCount } from "
|
|
23
|
+
import { getActiveCount } from "../../engine/dispatcher.js";
|
|
24
24
|
import {
|
|
25
25
|
getAllCronJobs,
|
|
26
26
|
getCronJob,
|
|
@@ -31,10 +31,10 @@ import {
|
|
|
31
31
|
describeSchedule,
|
|
32
32
|
type CronJob,
|
|
33
33
|
type CronRunOutcome,
|
|
34
|
-
} from "
|
|
35
|
-
import { appendDailyLog } from "
|
|
36
|
-
import { log, logError, logWarn } from "
|
|
37
|
-
import { numericChatIdFor } from "
|
|
34
|
+
} from "../../../storage/cron.js";
|
|
35
|
+
import { appendDailyLog } from "../../../storage/daily-log.js";
|
|
36
|
+
import { log, logError, logWarn } from "../../../util/log.js";
|
|
37
|
+
import { numericChatIdFor } from "../../../util/chat-id.js";
|
|
38
38
|
import { runJobOneShot } from "./job-oneshot.js";
|
|
39
39
|
import {
|
|
40
40
|
jobAllowsRun,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
import {
|
|
47
47
|
catchupRunCount,
|
|
48
48
|
missedRunCount,
|
|
49
|
-
} from "
|
|
49
|
+
} from "../../../native/scheduler-core.js";
|
|
50
50
|
|
|
51
51
|
// ── Dependencies (injected at startup) ──────────────────────────────────────
|
|
52
52
|
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
type CatchupPolicy,
|
|
19
19
|
type CronJob,
|
|
20
20
|
type CronJobType,
|
|
21
|
-
} from "
|
|
21
|
+
} from "../../../storage/cron.js";
|
|
22
22
|
|
|
23
23
|
/** The scheduler ticks once a minute, so sub-minute intervals are meaningless. */
|
|
24
24
|
const MIN_INTERVAL_SECONDS = 60;
|
|
@@ -13,18 +13,17 @@
|
|
|
13
13
|
|
|
14
14
|
import { existsSync, mkdirSync, appendFileSync } from "node:fs";
|
|
15
15
|
import { resolve } from "node:path";
|
|
16
|
-
import { files as pathFiles, dirs } from "
|
|
17
|
-
import { kvGet, kvSet } from "
|
|
18
|
-
import { importLegacyJson } from "
|
|
16
|
+
import { files as pathFiles, dirs } from "../../../util/paths.js";
|
|
17
|
+
import { kvGet, kvSet } from "../../../storage/kv.js";
|
|
18
|
+
import { importLegacyJson } from "../../../storage/legacy-import.js";
|
|
19
19
|
import { readPromptAsset } from "#prompt-assets";
|
|
20
|
-
import { log, logError, logWarn } from "
|
|
21
|
-
import { getDefaultModel } from "
|
|
22
|
-
import type { OneShotAgentParams, ReasoningEffortLevel } from "
|
|
23
|
-
import type { Backend } from "
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { FailureBackoff } from "./failure-backoff.js";
|
|
20
|
+
import { log, logError, logWarn } from "../../../util/log.js";
|
|
21
|
+
import { getDefaultModel } from "../../models/catalog.js";
|
|
22
|
+
import type { OneShotAgentParams, ReasoningEffortLevel } from "../../types.js";
|
|
23
|
+
import type { Backend } from "../../agent-runtime/capabilities.js";
|
|
24
|
+
import { taskTable } from "../../tasks/index.js";
|
|
25
|
+
import { resolveBackgroundEffort } from "../effort.js";
|
|
26
|
+
import { FailureBackoff } from "../failure-backoff.js";
|
|
28
27
|
|
|
29
28
|
// ── Types ────────────────────────────────────────────────────────────────────
|
|
30
29
|
|
|
@@ -160,10 +159,6 @@ async function executeDream(trigger: "auto" | "forced"): Promise<void> {
|
|
|
160
159
|
"dream",
|
|
161
160
|
`Memory consolidation complete (${trigger}), log: ${dreamLogPath}`,
|
|
162
161
|
);
|
|
163
|
-
// The soul's organic maintenance shares the dream cadence. Inert (no-op)
|
|
164
|
-
// unless the soul is enabled, and isolated so a soul failure never breaks
|
|
165
|
-
// memory consolidation.
|
|
166
|
-
await getSoul().dream();
|
|
167
162
|
} catch (err) {
|
|
168
163
|
logError("dream", `Memory consolidation failed (${trigger})`, err);
|
|
169
164
|
writeDreamState({ last_run: state?.last_run ?? 0, status: "idle" });
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* also what covers windows the plan reports no reset for).
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { getPooledBackend } from "
|
|
15
|
-
import { log, logWarn } from "
|
|
16
|
-
import { formatSmartTimestamp } from "
|
|
14
|
+
import { getPooledBackend } from "../../engine/backend-controller/index.js";
|
|
15
|
+
import { log, logWarn } from "../../../util/log.js";
|
|
16
|
+
import { formatSmartTimestamp } from "../../../util/time.js";
|
|
17
17
|
|
|
18
18
|
const CHECK_INTERVAL_MS = 5 * 60_000;
|
|
19
19
|
|
|
@@ -8,16 +8,19 @@
|
|
|
8
8
|
* Knows nothing about the backend or frontend — uses the dispatcher.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { execute, getActiveCount } from "
|
|
11
|
+
import { execute, getActiveCount } from "../../engine/dispatcher.js";
|
|
12
12
|
import {
|
|
13
13
|
setChatPulse,
|
|
14
14
|
getRegisteredPulseChats,
|
|
15
15
|
getChatSettings,
|
|
16
16
|
setPulseLastCheckMsgId,
|
|
17
|
-
} from "
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
} from "../../../storage/chat-settings.js";
|
|
18
|
+
import {
|
|
19
|
+
getRecentHistory,
|
|
20
|
+
getLatestMessageId,
|
|
21
|
+
} from "../../../storage/history.js";
|
|
22
|
+
import { log, logError } from "../../../util/log.js";
|
|
23
|
+
import { formatSmartTimestamp } from "../../../util/time.js";
|
|
21
24
|
|
|
22
25
|
// ── State ────────────────────────────────────────────────────────────────────
|
|
23
26
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
8
|
import type { Trigger } from "../../../storage/triggers.js";
|
|
9
9
|
import { selfInvocation } from "../../../util/mcp-launcher.js";
|
|
10
|
-
import { LUA_RUN_SUBCOMMAND } from "../../
|
|
10
|
+
import { LUA_RUN_SUBCOMMAND } from "../../scripts/lua.js";
|
|
11
11
|
|
|
12
12
|
export function commandForLanguage(
|
|
13
13
|
lang: Trigger["language"],
|
package/src/core/config/index.ts
CHANGED
|
@@ -557,16 +557,11 @@ const configSchema = z.object({
|
|
|
557
557
|
// Playwright — headless browser automation via MCP
|
|
558
558
|
playwright: playwrightConfigSchema.optional(),
|
|
559
559
|
|
|
560
|
-
// Soul — compiled
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
enabled: z.boolean().default(false),
|
|
566
|
-
/** Kernel persistence path (default: ~/.talon/data/soul.json) */
|
|
567
|
-
path: z.string().min(1).optional(),
|
|
568
|
-
})
|
|
569
|
-
.optional(),
|
|
560
|
+
// Soul — the compiled identity kernel, removed in #953. The root schema
|
|
561
|
+
// is `.strict()`, so a key that simply disappeared would make every
|
|
562
|
+
// existing config.json fail to parse; accepted and ignored instead, with
|
|
563
|
+
// one warning at load so the operator knows to drop it.
|
|
564
|
+
soul: z.unknown().optional(),
|
|
570
565
|
|
|
571
566
|
// Discord — discord.js v14-based frontend
|
|
572
567
|
discord: discordConfigSchema.optional(),
|
|
@@ -741,6 +736,15 @@ export function loadConfig(): TalonConfig {
|
|
|
741
736
|
|
|
742
737
|
const parsed = configSchema.parse(fileConfig);
|
|
743
738
|
|
|
739
|
+
// The soul kernel is gone (#953). Its config block still parses so an
|
|
740
|
+
// existing config.json keeps loading, but it no longer does anything —
|
|
741
|
+
// say so once rather than silently ignoring it.
|
|
742
|
+
if (parsed.soul !== undefined) {
|
|
743
|
+
console.warn(
|
|
744
|
+
`Ignoring "soul" in ${CONFIG_FILE}: the soul kernel was removed; its message taps now write to the memory store. Remove the key.`,
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
744
748
|
// Unified memory section: mirror the selected backend onto the per-plugin
|
|
745
749
|
// section the loaders consume (builtins.ts reads config.mempalace /
|
|
746
750
|
// config.mem0). The memory section wins over a legacy section when both
|
|
@@ -827,7 +831,7 @@ export function primaryFrontend(config: TalonConfig): string {
|
|
|
827
831
|
* the config. Multi-frontend deployments need per-chat prompt
|
|
828
832
|
* flavours (a native-app chat must get native.md guidance, not the
|
|
829
833
|
* telegram.md that `frontends[0]` happens to be) — the per-session
|
|
830
|
-
* snapshot layer (backend/
|
|
834
|
+
* snapshot layer (backend/runtime/prompt/system-prompt.ts) calls this with the
|
|
831
835
|
* chat's owning frontend and freezes the result per session.
|
|
832
836
|
*/
|
|
833
837
|
export function buildSystemPromptPartsFor(
|