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
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { CacheMetricsSupport } from "../../core/types.js";
|
|
2
2
|
import type { PlanUsage } from "../../core/agent-runtime/capabilities.js";
|
|
3
|
+
import type { CacheVerdict } from "../../storage/metrics.js";
|
|
3
4
|
import { formatSmartTimestamp, formatRelativeAge } from "../../util/time.js";
|
|
5
|
+
import { formatDuration } from "./format.js";
|
|
4
6
|
|
|
5
7
|
// ── /context breakdown ────────────────────────────────────────────────────────
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Rough token estimate — ~4 chars/token, the house heuristic used everywhere
|
|
9
|
-
* (
|
|
11
|
+
* (cache-telemetry, and the prompt budgets). No real tokenizer is wired, so every
|
|
10
12
|
* measured figure in the breakdown below is an estimate at this fidelity.
|
|
11
13
|
*/
|
|
12
14
|
export function estimateContextTokens(text: string): number {
|
|
@@ -271,7 +273,7 @@ export function buildCacheDisplay(input: {
|
|
|
271
273
|
? input.cacheWrite
|
|
272
274
|
: 0;
|
|
273
275
|
|
|
274
|
-
// Match the canonical formula in `src/backend/
|
|
276
|
+
// Match the canonical formula in `src/backend/runtime/usage.ts:cacheHitPercent`:
|
|
275
277
|
// cache_write is tokens being *written to* cache on this call, not served
|
|
276
278
|
// from it, so it must not dilute the hit ratio. The denominator is
|
|
277
279
|
// `input + read` ("effective input"), regardless of whether the backend
|
|
@@ -287,6 +289,103 @@ export function buildCacheDisplay(input: {
|
|
|
287
289
|
};
|
|
288
290
|
}
|
|
289
291
|
|
|
292
|
+
// ── Cache temperature ───────────────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
export interface CacheTempDisplay {
|
|
295
|
+
/** Last cross-turn verdict, or "unknown" when this process saw no turn. */
|
|
296
|
+
verdict: CacheVerdict | "unknown";
|
|
297
|
+
/** Time since the last turn ended, or "—" when no turn has finished. */
|
|
298
|
+
idle: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Resolve the "is this chat's prompt prefix still warm?" line.
|
|
303
|
+
*
|
|
304
|
+
* The aggregate `Cache: NN% hit` above it answers a different question — it
|
|
305
|
+
* folds in every request of every turn, and an agentic turn's later requests
|
|
306
|
+
* always read the prefix the first one paid for. What costs money is whether
|
|
307
|
+
* the NEXT turn will find the prefix still cached, and the two inputs to that
|
|
308
|
+
* are the last turn's cross-turn verdict and how long ago that turn ended
|
|
309
|
+
* (docs/cache-economics.md).
|
|
310
|
+
*
|
|
311
|
+
* Returns null when neither is known — a chat that has not completed a turn
|
|
312
|
+
* in this process has nothing to say, and a fabricated "none / 0s" would read
|
|
313
|
+
* as a measurement.
|
|
314
|
+
*/
|
|
315
|
+
export function buildCacheTempDisplay(input: {
|
|
316
|
+
verdict?: CacheVerdict;
|
|
317
|
+
lastTurnEndedAt?: number;
|
|
318
|
+
now?: number;
|
|
319
|
+
}): CacheTempDisplay | null {
|
|
320
|
+
const endedAt =
|
|
321
|
+
typeof input.lastTurnEndedAt === "number" &&
|
|
322
|
+
Number.isFinite(input.lastTurnEndedAt) &&
|
|
323
|
+
input.lastTurnEndedAt > 0
|
|
324
|
+
? input.lastTurnEndedAt
|
|
325
|
+
: undefined;
|
|
326
|
+
if (!input.verdict && endedAt === undefined) return null;
|
|
327
|
+
const now = input.now ?? Date.now();
|
|
328
|
+
return {
|
|
329
|
+
verdict: input.verdict ?? "unknown",
|
|
330
|
+
idle:
|
|
331
|
+
endedAt === undefined ? "—" : formatDuration(Math.max(0, now - endedAt)),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** The one-line rendering every frontend's /status shares. */
|
|
336
|
+
export function formatCacheTempLine(temp: CacheTempDisplay): string {
|
|
337
|
+
return `Cache: ${temp.verdict} last turn · idle ${temp.idle}`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ── Daemon resources ────────────────────────────────────────────────────────
|
|
341
|
+
|
|
342
|
+
export interface DaemonDisplay {
|
|
343
|
+
rssMb: number;
|
|
344
|
+
heapMb: number;
|
|
345
|
+
/**
|
|
346
|
+
* Mean daemon CPU per turn, in ms, or undefined before any turn has been
|
|
347
|
+
* measured. The metrics store's histograms expose count/avg/min/max only
|
|
348
|
+
* (`storage/metrics.ts`) — there is no percentile to read, so the line
|
|
349
|
+
* says "avg" rather than implying a p50 it cannot compute.
|
|
350
|
+
*/
|
|
351
|
+
cpuPerTurnMs: number | undefined;
|
|
352
|
+
/** How many turns the average is over. */
|
|
353
|
+
cpuSamples: number;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Resolve the "what does the daemon itself cost?" line — resident memory
|
|
358
|
+
* now, and the CPU a turn spends inside Talon rather than waiting on a
|
|
359
|
+
* model (docs/ts-migration-plan.md, Phase 0). Pure: the caller reads
|
|
360
|
+
* `process.memoryUsage()` and the `turn.cpu_ms` histogram.
|
|
361
|
+
*/
|
|
362
|
+
export function buildDaemonDisplay(input: {
|
|
363
|
+
rssBytes: number;
|
|
364
|
+
heapBytes: number;
|
|
365
|
+
cpuPerTurn?: { count: number; avg: number };
|
|
366
|
+
}): DaemonDisplay {
|
|
367
|
+
const toMb = (bytes: number): number =>
|
|
368
|
+
Number.isFinite(bytes) && bytes > 0 ? Math.round(bytes / (1024 * 1024)) : 0;
|
|
369
|
+
const cpu = input.cpuPerTurn;
|
|
370
|
+
const measured =
|
|
371
|
+
cpu !== undefined && cpu.count > 0 && Number.isFinite(cpu.avg);
|
|
372
|
+
return {
|
|
373
|
+
rssMb: toMb(input.rssBytes),
|
|
374
|
+
heapMb: toMb(input.heapBytes),
|
|
375
|
+
cpuPerTurnMs: measured ? Math.round(cpu.avg) : undefined,
|
|
376
|
+
cpuSamples: measured ? cpu.count : 0,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** The one-line rendering every frontend's /status shares. */
|
|
381
|
+
export function formatDaemonLine(daemon: DaemonDisplay): string {
|
|
382
|
+
const cpu =
|
|
383
|
+
daemon.cpuPerTurnMs === undefined
|
|
384
|
+
? "cpu/turn —"
|
|
385
|
+
: `cpu/turn avg ${daemon.cpuPerTurnMs} ms (n=${daemon.cpuSamples})`;
|
|
386
|
+
return `Daemon: rss ${daemon.rssMb} MB · heap ${daemon.heapMb} MB · ${cpu}`;
|
|
387
|
+
}
|
|
388
|
+
|
|
290
389
|
// ── Plan limits ─────────────────────────────────────────────────────────────
|
|
291
390
|
|
|
292
391
|
/** Figures older than this are labelled with their age in /status. */
|
|
@@ -9,8 +9,8 @@ import { resolveModel } from "../../core/models/catalog.js";
|
|
|
9
9
|
import { resolveChatBackend } from "../../core/engine/backend-controller/index.js";
|
|
10
10
|
import { getSessionInfo } from "../../storage/sessions.js";
|
|
11
11
|
import { getChatSettings } from "../../storage/chat-settings.js";
|
|
12
|
-
import { performSessionReset } from "../
|
|
13
|
-
import { buildCacheDisplay } from "../
|
|
12
|
+
import { performSessionReset } from "../presentation/session-status.js";
|
|
13
|
+
import { buildCacheDisplay } from "../presentation/status-context.js";
|
|
14
14
|
import { buildAdaptiveCard } from "./formatting.js";
|
|
15
15
|
import type { ChatMessage } from "./graph.js";
|
|
16
16
|
import { postCard } from "./outbound.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
describeSchedule,
|
|
10
10
|
nextRunAt,
|
|
11
11
|
} from "../../../storage/cron.js";
|
|
12
|
-
import { getPulseStatus } from "../../../core/background/pulse.js";
|
|
12
|
+
import { getPulseStatus } from "../../../core/background/pulse/pulse.js";
|
|
13
13
|
import { replyHtmlChunked } from "./chunked-reply.js";
|
|
14
14
|
|
|
15
15
|
export async function replyCronJobs(ctx: Context): Promise<void> {
|
|
@@ -12,7 +12,7 @@ import { getAllSessions } from "../../../storage/sessions.js";
|
|
|
12
12
|
import { todayLogDate } from "../../../storage/daily-log.js";
|
|
13
13
|
import { getActiveCount } from "../../../core/engine/dispatcher.js";
|
|
14
14
|
import { getHealthStatus, getRecentErrors } from "../../../util/watchdog.js";
|
|
15
|
-
import { formatDuration } from "
|
|
15
|
+
import { formatDuration } from "../../presentation/format.js";
|
|
16
16
|
|
|
17
17
|
export async function replyStats(ctx: Context): Promise<void> {
|
|
18
18
|
const h = getHealthStatus();
|
|
@@ -8,7 +8,7 @@ import { escapeHtml } from "../formatting.js";
|
|
|
8
8
|
import { resetSession, getAllSessions } from "../../../storage/sessions.js";
|
|
9
9
|
import { clearHistory } from "../../../storage/history.js";
|
|
10
10
|
import { getChatSettings } from "../../../storage/chat-settings.js";
|
|
11
|
-
import { formatModelLabel } from "
|
|
11
|
+
import { formatModelLabel } from "../../presentation/format.js";
|
|
12
12
|
import { replyHtmlChunked } from "./chunked-reply.js";
|
|
13
13
|
|
|
14
14
|
/** `/admin chats` — every active session, newest first, titled via getChat. */
|
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
type EffortLevel,
|
|
10
10
|
} from "../../../storage/chat-settings.js";
|
|
11
11
|
import { getBackendIdForChat } from "../../../core/engine/backend-controller/index.js";
|
|
12
|
-
import { renderEffortRows } from "../
|
|
12
|
+
import { renderEffortRows } from "../render/menu.js";
|
|
13
13
|
import { resolveBackendForChat } from "../model-menu.js";
|
|
14
14
|
import {
|
|
15
15
|
displayReasoningEffort,
|
|
16
16
|
getActiveReasoningLevels,
|
|
17
17
|
supportsReasoningLevel,
|
|
18
|
-
} from "../../
|
|
18
|
+
} from "../../presentation/reasoning-levels.js";
|
|
19
19
|
import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
|
|
20
20
|
|
|
21
21
|
export async function handleEffortCallback(
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
renderMetricsKeyboard,
|
|
13
13
|
renderMetricsPanel,
|
|
14
14
|
type MetricsView,
|
|
15
|
-
} from "../
|
|
15
|
+
} from "../render/reports.js";
|
|
16
16
|
import { isAuthorizedAdmin } from "../commands/state.js";
|
|
17
17
|
import { answerCallbackQuerySafe, editOrIgnoreSame } from "./query.js";
|
|
18
18
|
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
rebindChat,
|
|
15
15
|
releaseChat,
|
|
16
16
|
} from "../../../../core/engine/backend-controller/index.js";
|
|
17
|
-
import { resetPulseCheckpoint } from "../../../../core/background/pulse.js";
|
|
17
|
+
import { resetPulseCheckpoint } from "../../../../core/background/pulse/pulse.js";
|
|
18
18
|
import { resolveActiveModelForChat } from "../../../../core/models/active-model.js";
|
|
19
19
|
import { logWarn } from "../../../../util/log.js";
|
|
20
20
|
import type { ModelCallback } from "../../model-callbacks.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
disablePulse,
|
|
9
9
|
enablePulse,
|
|
10
10
|
isPulseEnabled,
|
|
11
|
-
} from "../../../core/background/pulse.js";
|
|
11
|
+
} from "../../../core/background/pulse/pulse.js";
|
|
12
12
|
import { answerCallbackQuerySafe } from "./query.js";
|
|
13
13
|
|
|
14
14
|
export async function handlePulseCallback(
|
|
@@ -7,7 +7,7 @@ import type { Context } from "grammy";
|
|
|
7
7
|
import type { TalonConfig } from "../../../core/config/index.js";
|
|
8
8
|
import type { Backend } from "../../../core/agent-runtime/capabilities.js";
|
|
9
9
|
import { logWarn } from "../../../util/log.js";
|
|
10
|
-
import type { SettingsButton } from "../
|
|
10
|
+
import type { SettingsButton } from "../render/menu.js";
|
|
11
11
|
|
|
12
12
|
export type CallbackDeps = {
|
|
13
13
|
config: TalonConfig;
|
|
@@ -14,20 +14,20 @@ import {
|
|
|
14
14
|
disablePulse,
|
|
15
15
|
enablePulse,
|
|
16
16
|
isPulseEnabled,
|
|
17
|
-
} from "../../../core/background/pulse.js";
|
|
17
|
+
} from "../../../core/background/pulse/pulse.js";
|
|
18
18
|
import { getBackendIdForChat } from "../../../core/engine/backend-controller/index.js";
|
|
19
19
|
import {
|
|
20
20
|
renderSettingsText,
|
|
21
21
|
renderSettingsKeyboard,
|
|
22
22
|
type SettingsButton,
|
|
23
|
-
} from "../
|
|
23
|
+
} from "../render/menu.js";
|
|
24
24
|
import { resolveBackendForChat } from "../model-menu.js";
|
|
25
25
|
import { resolveActiveModelForChat } from "../../../core/models/active-model.js";
|
|
26
26
|
import {
|
|
27
27
|
displayReasoningEffort,
|
|
28
28
|
getActiveReasoningLevels,
|
|
29
29
|
supportsReasoningLevel,
|
|
30
|
-
} from "../../
|
|
30
|
+
} from "../../presentation/reasoning-levels.js";
|
|
31
31
|
import { answerCallbackQuerySafe, type CallbackDeps } from "./query.js";
|
|
32
32
|
|
|
33
33
|
export async function handleSettingsCallback(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Admin + maintenance commands — /admin, /metrics, /doctor, /dream,
|
|
2
|
+
* Admin + maintenance commands — /admin, /metrics, /doctor, /dream,
|
|
3
3
|
* /restart, /update — plus the unknown-command "did you mean…?" suggester.
|
|
4
4
|
*
|
|
5
5
|
* Most commands here gate on the configured admin user id via
|
|
@@ -8,24 +8,23 @@
|
|
|
8
8
|
|
|
9
9
|
import type { Bot } from "grammy";
|
|
10
10
|
import type { TalonConfig } from "../../../core/config/index.js";
|
|
11
|
-
import { respawnSelf } from "../../../
|
|
11
|
+
import { respawnSelf } from "../../../core/daemon/respawn.js";
|
|
12
12
|
import { isStaleCommand } from "../stale-command.js";
|
|
13
13
|
import {
|
|
14
14
|
getRepoRoot,
|
|
15
15
|
runSelfUpdate,
|
|
16
16
|
} from "../../../core/update/self-update.js";
|
|
17
|
-
import { forceDream } from "../../../core/background/dream.js";
|
|
18
|
-
import { getSoul } from "../../../core/soul/service.js";
|
|
17
|
+
import { forceDream } from "../../../core/background/dream/index.js";
|
|
19
18
|
import { escapeHtml } from "../formatting.js";
|
|
20
19
|
import { closestMatch } from "../../../native/strsim.js";
|
|
20
|
+
import { formatDuration } from "../../presentation/format.js";
|
|
21
21
|
import {
|
|
22
|
-
formatDuration,
|
|
23
22
|
renderDoctorMessage,
|
|
24
23
|
renderMetricsKeyboard,
|
|
25
24
|
renderMetricsPanel,
|
|
26
25
|
renderUsageMessage,
|
|
27
|
-
} from "../
|
|
28
|
-
import { collectPlanUsage } from "../../
|
|
26
|
+
} from "../render/reports.js";
|
|
27
|
+
import { collectPlanUsage } from "../../presentation/plan-usage-report.js";
|
|
29
28
|
import { collectDoctorReport } from "../../../core/doctor/index.js";
|
|
30
29
|
import { handleAdminCommand } from "../admin.js";
|
|
31
30
|
import { getTodayMetrics } from "../../../storage/metrics.js";
|
|
@@ -126,39 +125,6 @@ function registerDreamCommand(bot: Bot): void {
|
|
|
126
125
|
});
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
// /soul — introspect the compiled identity (read-only). `/soul dream`
|
|
130
|
-
// (admin) runs the organic maintenance pass. Inert when the soul is
|
|
131
|
-
// disabled (TALON_SOUL_ENABLED), so it's safe to ship dormant.
|
|
132
|
-
function registerSoulCommand(bot: Bot): void {
|
|
133
|
-
bot.command("soul", async (ctx) => {
|
|
134
|
-
const soul = getSoul();
|
|
135
|
-
if (!soul.enabled) {
|
|
136
|
-
await ctx.reply("Soul is disabled (set TALON_SOUL_ENABLED to enable).");
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
const arg = (ctx.match ?? "").trim().toLowerCase();
|
|
140
|
-
if (arg === "dream") {
|
|
141
|
-
if (!isAuthorizedAdmin(ctx)) {
|
|
142
|
-
await ctx.reply("Not authorized.");
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
const sent = await ctx.reply("🧠 Soul dreaming...");
|
|
146
|
-
void soul
|
|
147
|
-
.dream()
|
|
148
|
-
.then(() =>
|
|
149
|
-
bot.api.editMessageText(
|
|
150
|
-
ctx.chat.id,
|
|
151
|
-
sent.message_id,
|
|
152
|
-
"🧠 Soul dream complete.",
|
|
153
|
-
),
|
|
154
|
-
)
|
|
155
|
-
.catch(() => undefined);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
await ctx.reply(soul.introspect());
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
|
|
162
128
|
function registerRestartCommand(bot: Bot): void {
|
|
163
129
|
bot.command("restart", async (ctx) => {
|
|
164
130
|
if (!isAuthorizedAdmin(ctx)) {
|
|
@@ -275,7 +241,6 @@ export function registerAdminCommands(
|
|
|
275
241
|
registerUsageCommand(bot, config);
|
|
276
242
|
registerDoctorCommand(bot, config);
|
|
277
243
|
registerDreamCommand(bot);
|
|
278
|
-
registerSoulCommand(bot);
|
|
279
244
|
registerRestartCommand(bot);
|
|
280
245
|
const updateRepoRoot = config.devBuild ? getRepoRoot() : null;
|
|
281
246
|
if (updateRepoRoot) registerUpdateCommand(bot, config, updateRepoRoot);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - `memory` — /memory (read-only view of the typed memory store)
|
|
9
9
|
* - `session` — /reset /status
|
|
10
10
|
* - `settings` — /model /effort /pulse /settings
|
|
11
|
-
* - `admin` — /admin /metrics /doctor /dream /
|
|
11
|
+
* - `admin` — /admin /metrics /doctor /dream /restart /update
|
|
12
12
|
* + the unknown-command suggester
|
|
13
13
|
*
|
|
14
14
|
* `registerCommands` wires every group onto the bot in an order that ends
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import type { Bot, Context } from "grammy";
|
|
6
6
|
import { isUserClientReady } from "../userbot.js";
|
|
7
7
|
import { escapeHtml } from "../formatting.js";
|
|
8
|
+
import { formatDuration } from "../../presentation/format.js";
|
|
8
9
|
import {
|
|
9
|
-
formatDuration,
|
|
10
10
|
renderMeshPairLink,
|
|
11
11
|
renderMeshReport,
|
|
12
12
|
type MeshReachability,
|
|
13
|
-
} from "../
|
|
13
|
+
} from "../render/reports.js";
|
|
14
14
|
import { isAuthorizedAdmin } from "./state.js";
|
|
15
15
|
import { getLoadedPlugins } from "../../../core/plugin/index.js";
|
|
16
16
|
import { getMeshService } from "../../../core/mesh/index.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Session commands — /reset and /status.
|
|
3
3
|
*
|
|
4
4
|
* Data gathering and the reset sequence live in
|
|
5
|
-
* frontend/
|
|
5
|
+
* frontend/presentation/session-status.ts; this file only renders Telegram HTML.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Bot } from "grammy";
|
|
@@ -13,13 +13,17 @@ import {
|
|
|
13
13
|
formatTokenCount,
|
|
14
14
|
formatBytes,
|
|
15
15
|
formatUsd,
|
|
16
|
-
} from "
|
|
16
|
+
} from "../../presentation/format.js";
|
|
17
17
|
import { resolveBackendForChat } from "../model-menu.js";
|
|
18
18
|
import { getBackendIdForChat } from "../../../core/engine/backend-controller/index.js";
|
|
19
19
|
import {
|
|
20
20
|
performSessionReset,
|
|
21
21
|
collectSessionStatus,
|
|
22
|
-
} from "../../
|
|
22
|
+
} from "../../presentation/session-status.js";
|
|
23
|
+
import {
|
|
24
|
+
formatCacheTempLine,
|
|
25
|
+
formatDaemonLine,
|
|
26
|
+
} from "../../presentation/status-context.js";
|
|
23
27
|
import { stopCurrentTurn } from "../../../core/engine/dispatcher.js";
|
|
24
28
|
import type { RegisterDeps } from "./state.js";
|
|
25
29
|
|
|
@@ -74,6 +78,7 @@ export function registerSessionCommands(
|
|
|
74
78
|
` Read ${formatTokenCount(s.cache.read)}${s.cache.showsWrite ? ` Write ${formatTokenCount(s.cache.write)}` : ""}`,
|
|
75
79
|
]
|
|
76
80
|
: []),
|
|
81
|
+
...(s.cacheTemp ? [` ${formatCacheTempLine(s.cacheTemp)}`] : []),
|
|
77
82
|
` Input ${formatTokenCount(s.inputTokens)} Output ${formatTokenCount(s.outputTokens)}${s.costUsd > 0 ? ` Cost ${formatUsd(s.costUsd)}` : ""}`,
|
|
78
83
|
"",
|
|
79
84
|
...(s.plan
|
|
@@ -91,6 +96,7 @@ export function registerSessionCommands(
|
|
|
91
96
|
`<b>Session</b> ${s.sessionName ? `"${escapeHtml(s.sessionName)}" ` : ""}${s.sessionId ? "<code>" + escapeHtml(s.sessionId.slice(0, 8)) + "...</code>" : "<i>(new)</i>"} · ${s.sessionAge} old`,
|
|
92
97
|
`<b>Uptime</b> ${s.uptime} · ${s.activeSessionCount} active session${s.activeSessionCount === 1 ? "" : "s"}`,
|
|
93
98
|
`<b>Runtime</b> ${escapeHtml(s.runtime)} · ${formatBytes(s.rssBytes)} RSS`,
|
|
99
|
+
escapeHtml(formatDaemonLine(s.daemon)),
|
|
94
100
|
];
|
|
95
101
|
await ctx.reply(lines.join("\n"), { parse_mode: "HTML" });
|
|
96
102
|
});
|
|
@@ -17,19 +17,21 @@ import {
|
|
|
17
17
|
disablePulse,
|
|
18
18
|
enablePulse,
|
|
19
19
|
isPulseEnabled,
|
|
20
|
-
} from "../../../core/background/pulse.js";
|
|
20
|
+
} from "../../../core/background/pulse/pulse.js";
|
|
21
21
|
import { escapeHtml } from "../formatting.js";
|
|
22
22
|
import {
|
|
23
23
|
formatModelLabel,
|
|
24
24
|
formatDuration,
|
|
25
25
|
parseInterval,
|
|
26
|
+
} from "../../presentation/format.js";
|
|
27
|
+
import {
|
|
26
28
|
renderSettingsText,
|
|
27
29
|
renderSettingsKeyboard,
|
|
28
30
|
renderEffortRows,
|
|
29
31
|
renderModelMenuText,
|
|
30
32
|
renderModelMenuKeyboard,
|
|
31
33
|
type SettingsButton,
|
|
32
|
-
} from "../
|
|
34
|
+
} from "../render/menu.js";
|
|
33
35
|
import {
|
|
34
36
|
buildModelMenuViewForChat,
|
|
35
37
|
resolveBackendForChat,
|
|
@@ -40,7 +42,7 @@ import {
|
|
|
40
42
|
displayReasoningEffort,
|
|
41
43
|
getActiveReasoningLevels,
|
|
42
44
|
supportsReasoningLevel,
|
|
43
|
-
} from "../../
|
|
45
|
+
} from "../../presentation/reasoning-levels.js";
|
|
44
46
|
import type { RegisterDeps } from "./state.js";
|
|
45
47
|
|
|
46
48
|
/** `/model <query>` — resolve the query against the per-chat backend and
|
|
@@ -13,7 +13,6 @@ import { setMessageFilePath } from "../../../storage/history.js";
|
|
|
13
13
|
import { addMedia } from "../../../storage/media-index.js";
|
|
14
14
|
import { appendDailyLog } from "../../../storage/daily-log.js";
|
|
15
15
|
import { logError } from "../../../util/log.js";
|
|
16
|
-
import { recordMessageSignal } from "../../../core/soul/taps.js";
|
|
17
16
|
import {
|
|
18
17
|
getSenderName,
|
|
19
18
|
getReplyContext,
|
|
@@ -178,15 +177,6 @@ export async function handleTextMessage(
|
|
|
178
177
|
);
|
|
179
178
|
const prompt = fwdCtx + replyCtx + replyPhotoCtx + (ctx.message.text ?? "");
|
|
180
179
|
|
|
181
|
-
// Soul tap: a message reaching here is addressed to Talon (DM, mention, or
|
|
182
|
-
// reply). If it reads as a standing directive or a correction, record it as
|
|
183
|
-
// evidence. No-op unless the soul is enabled.
|
|
184
|
-
recordMessageSignal({
|
|
185
|
-
text: ctx.message.text ?? "",
|
|
186
|
-
actor: sender,
|
|
187
|
-
addressedToBot: true,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
180
|
enqueueMessage(bot, config, chatId, ctx.chat.id, {
|
|
191
181
|
prompt,
|
|
192
182
|
replyToId: ctx.message.message_id,
|
|
@@ -10,7 +10,6 @@ import { Bot, InputFile, API_CONSTANTS } from "grammy";
|
|
|
10
10
|
import { autoRetry } from "@grammyjs/auto-retry";
|
|
11
11
|
import { apiThrottler } from "@grammyjs/transformer-throttler";
|
|
12
12
|
import type { TalonConfig } from "../../core/config/index.js";
|
|
13
|
-
import { soulEnabled } from "../../core/soul/settings.js";
|
|
14
13
|
import type { ContextManager } from "../../core/types.js";
|
|
15
14
|
import type { Gateway } from "../../core/engine/gateway.js";
|
|
16
15
|
import { createTelegramActionHandler, sendText } from "./actions/index.js";
|
|
@@ -127,13 +126,10 @@ export function createTelegramFrontend(
|
|
|
127
126
|
});
|
|
128
127
|
// Beyond grammY's defaults: `chat_join_request` feeds the moderation
|
|
129
128
|
// tool's pending-join cache (inert unless the bot admins an
|
|
130
|
-
// approval-gated chat)
|
|
131
|
-
// reaction tap — subscribed only when the soul is enabled, so a
|
|
132
|
-
// soulless deployment's reaction behaviour is unchanged.
|
|
129
|
+
// approval-gated chat).
|
|
133
130
|
const allowedUpdates = [
|
|
134
131
|
...API_CONSTANTS.DEFAULT_UPDATE_TYPES,
|
|
135
132
|
"chat_join_request" as const,
|
|
136
|
-
...(soulEnabled(config.soul) ? ["message_reaction" as const] : []),
|
|
137
133
|
];
|
|
138
134
|
await bot.start({
|
|
139
135
|
allowed_updates: allowedUpdates,
|
|
@@ -12,13 +12,12 @@ import type { TalonConfig } from "../../core/config/index.js";
|
|
|
12
12
|
import { pushMessage } from "../../storage/history.js";
|
|
13
13
|
import type { HistoryMessage } from "../../storage/repositories/history-repo.js";
|
|
14
14
|
import { allowChat, revokeChat } from "./userbot.js";
|
|
15
|
-
import { registerChat } from "../../core/background/pulse.js";
|
|
15
|
+
import { registerChat } from "../../core/background/pulse/pulse.js";
|
|
16
16
|
import { log } from "../../util/log.js";
|
|
17
17
|
import { getSenderName } from "./handlers/index.js";
|
|
18
18
|
import { noteUpdateId } from "./update-offset.js";
|
|
19
19
|
import { noteInboundThread } from "./topics.js";
|
|
20
20
|
import { recordJoinRequest } from "./join-requests.js";
|
|
21
|
-
import { newlyAddedEmojis, recordReactionToBot } from "../../core/soul/taps.js";
|
|
22
21
|
import {
|
|
23
22
|
handleTextMessage,
|
|
24
23
|
handlePhotoMessage,
|
|
@@ -147,18 +146,6 @@ function captureHistory(
|
|
|
147
146
|
return next();
|
|
148
147
|
}
|
|
149
148
|
|
|
150
|
-
// ── Reaction tap — feed reactions on Talon's own messages to the soul ────
|
|
151
|
-
// Telegram only delivers `message_reaction` updates when subscribed via
|
|
152
|
-
// allowed_updates (see index.ts) and, in groups, when the bot is an admin.
|
|
153
|
-
// The handler is inert unless the soul is enabled.
|
|
154
|
-
function tapReaction(ctx: Filter<Context, "message_reaction">): void {
|
|
155
|
-
const mr = ctx.messageReaction;
|
|
156
|
-
// Ignore the bot reacting to messages itself.
|
|
157
|
-
if (mr.user?.id === ctx.me.id) return;
|
|
158
|
-
const added = newlyAddedEmojis(mr.old_reaction, mr.new_reaction);
|
|
159
|
-
recordReactionToBot(mr.chat.id, mr.message_id, added);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
149
|
// ── Join requests — cache for moderate(op="list_join_requests") ─────────
|
|
163
150
|
// Delivered only when subscribed via allowed_updates (see index.ts) and
|
|
164
151
|
// the bot admins a chat whose invite link requires approval. Stored, not
|
|
@@ -208,7 +195,6 @@ function registerMessageHandlers(bot: Bot, config: TalonConfig): void {
|
|
|
208
195
|
export function registerMiddleware(bot: Bot, config: TalonConfig): void {
|
|
209
196
|
bot.use(trackUpdateOffset);
|
|
210
197
|
bot.on("message", captureHistory);
|
|
211
|
-
bot.on("message_reaction", tapReaction);
|
|
212
198
|
bot.on("chat_join_request", cacheJoinRequest);
|
|
213
199
|
bot.on("my_chat_member", revokeOnRemoval);
|
|
214
200
|
registerMessageHandlers(bot, config);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram's dialect of the shared chat reports.
|
|
3
|
+
*
|
|
4
|
+
* `frontend/presentation/reports.ts` writes each report once and takes
|
|
5
|
+
* the markup spelling from a `ReportFormatter`; this is Telegram's.
|
|
6
|
+
* `escape` is `escapeHtml` because sends use `parse_mode: HTML`, so a
|
|
7
|
+
* literal `<` in a device name, a model id, a metric key or a backend
|
|
8
|
+
* note would be read as a tag and 400 the entire message.
|
|
9
|
+
*
|
|
10
|
+
* Its own module so both `reports.ts` (the report wrappers) and
|
|
11
|
+
* `menu.ts` (the settings body) can read it without a cycle.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { escapeHtml } from "../formatting.js";
|
|
15
|
+
import type { ReportFormatter } from "../../presentation/reports.js";
|
|
16
|
+
|
|
17
|
+
/** Telegram hard-caps a message at 4096 characters; this leaves headroom. */
|
|
18
|
+
export const TELEGRAM_MESSAGE_MAX = 3800;
|
|
19
|
+
|
|
20
|
+
export const TELEGRAM_REPORTS: ReportFormatter = {
|
|
21
|
+
bold: (s) => `<b>${s}</b>`,
|
|
22
|
+
italic: (s) => `<i>${s}</i>`,
|
|
23
|
+
// Telegram has one italic tag; Discord spells this one `*…*`.
|
|
24
|
+
emphasis: (s) => `<i>${s}</i>`,
|
|
25
|
+
code: (s) => `<code>${s}</code>`,
|
|
26
|
+
escape: escapeHtml,
|
|
27
|
+
lineLimit: TELEGRAM_MESSAGE_MAX,
|
|
28
|
+
metricLabelMax: 80,
|
|
29
|
+
pulseLabel: "Pulse:",
|
|
30
|
+
};
|