talon-agent 5.0.0 → 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/package.json +1 -1
- package/src/app.ts +3 -3
- package/src/backend/claude-sdk/factory.ts +21 -41
- package/src/backend/claude-sdk/host/in-process.ts +147 -0
- package/src/backend/codex/mcp-config.ts +1 -1
- package/src/backend/openai-agents/mcp-pool.ts +1 -1
- package/src/backend/runtime/index.ts +2 -2
- package/src/backend/runtime/turn/delivery.ts +1 -1
- package/src/backend/runtime/turn/turn-phases.ts +1 -1
- package/src/bootstrap.ts +2 -2
- package/src/cli.ts +5 -2
- package/src/core/agent-runtime/README.md +15 -0
- package/src/core/agent-runtime/agent-host.ts +387 -0
- package/src/core/background/cron/scheduler.ts +1 -1
- package/src/core/background/triggers/command.ts +1 -1
- package/src/{util → core/config}/harden.ts +1 -1
- package/src/core/config/index.ts +1 -1
- package/src/core/daemon/pidfile.ts +1 -1
- package/src/core/daemon/resource-sampler.ts +2 -2
- package/src/{util → core/daemon}/respawn.ts +1 -1
- package/src/core/doctor/index.ts +1 -1
- package/src/core/engine/gateway-actions/fetch-url.ts +1 -1
- package/src/core/engine/gateway-actions/index.ts +1 -1
- package/src/core/engine/gateway-actions/memory.ts +2 -2
- 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/frontend-runtime/builtins.ts +2 -2
- package/src/core/mcp-hub/index.ts +1 -1
- package/src/core/mcp-hub/talon-server.ts +1 -1
- package/src/core/memory/taps.ts +1 -1
- package/src/core/plugin/mcp.ts +1 -1
- package/src/core/scripts/lua.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/{memory.ts → content/memory.ts} +2 -2
- package/src/core/tools/{web.ts → content/web.ts} +1 -1
- package/src/core/tools/index.ts +20 -20
- 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/{util → core/vfs}/workspace.ts +2 -2
- 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/settings.ts +1 -1
- package/src/frontend/discord/commands/admin.ts +1 -1
- package/src/frontend/discord/commands/info.ts +1 -1
- package/src/frontend/discord/commands/interaction.ts +1 -1
- package/src/frontend/discord/commands/session.ts +3 -3
- package/src/frontend/discord/commands/settings.ts +1 -1
- package/src/frontend/discord/handlers/messages.ts +1 -1
- package/src/frontend/discord/handlers/state.ts +1 -1
- package/src/frontend/discord/middleware.ts +1 -1
- package/src/frontend/discord/ready.ts +1 -1
- package/src/frontend/discord/render.ts +41 -259
- package/src/frontend/native/chats/chats.ts +1 -1
- package/src/frontend/native/surface/models.ts +1 -1
- package/src/frontend/native/turn/context.ts +1 -1
- package/src/frontend/native/turn/emit.ts +1 -1
- package/src/frontend/{shared → presentation}/format.ts +4 -3
- 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 +1 -1
- package/src/frontend/teams/commands.ts +2 -2
- package/src/frontend/teams/turn.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/views.ts +1 -1
- package/src/frontend/telegram/callbacks/query.ts +1 -1
- package/src/frontend/telegram/callbacks/settings.ts +2 -2
- package/src/frontend/telegram/commands/admin.ts +4 -4
- package/src/frontend/telegram/commands/info.ts +2 -2
- package/src/frontend/telegram/commands/session.ts +4 -4
- package/src/frontend/telegram/commands/settings.ts +4 -2
- package/src/frontend/telegram/handlers/state.ts +1 -1
- 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/commands.ts +5 -5
- package/src/frontend/whatsapp/registry.ts +1 -1
- package/src/index.ts +5 -2
- package/src/util/runtime.ts +1 -1
- package/src/core/engine/gateway-actions/native.ts +0 -1035
- 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/{util → core/daemon}/boot-timer.ts +0 -0
- /package/src/{util → core/frontend-runtime}/chat-id.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/{shared → presentation}/access.ts +0 -0
- /package/src/frontend/{shared → presentation}/model-commands.ts +0 -0
- /package/src/frontend/{shared → presentation}/plan-usage-report.ts +0 -0
- /package/src/frontend/{shared → presentation}/status-context.ts +0 -0
|
@@ -20,14 +20,14 @@ 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(
|
|
@@ -8,7 +8,7 @@
|
|
|
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,
|
|
@@ -17,14 +17,14 @@ import {
|
|
|
17
17
|
import { forceDream } from "../../../core/background/dream/index.js";
|
|
18
18
|
import { escapeHtml } from "../formatting.js";
|
|
19
19
|
import { closestMatch } from "../../../native/strsim.js";
|
|
20
|
+
import { formatDuration } from "../../presentation/format.js";
|
|
20
21
|
import {
|
|
21
|
-
formatDuration,
|
|
22
22
|
renderDoctorMessage,
|
|
23
23
|
renderMetricsKeyboard,
|
|
24
24
|
renderMetricsPanel,
|
|
25
25
|
renderUsageMessage,
|
|
26
|
-
} from "../
|
|
27
|
-
import { collectPlanUsage } from "../../
|
|
26
|
+
} from "../render/reports.js";
|
|
27
|
+
import { collectPlanUsage } from "../../presentation/plan-usage-report.js";
|
|
28
28
|
import { collectDoctorReport } from "../../../core/doctor/index.js";
|
|
29
29
|
import { handleAdminCommand } from "../admin.js";
|
|
30
30
|
import { getTodayMetrics } from "../../../storage/metrics.js";
|
|
@@ -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,17 +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
23
|
import {
|
|
24
24
|
formatCacheTempLine,
|
|
25
25
|
formatDaemonLine,
|
|
26
|
-
} from "../../
|
|
26
|
+
} from "../../presentation/status-context.js";
|
|
27
27
|
import { stopCurrentTurn } from "../../../core/engine/dispatcher.js";
|
|
28
28
|
import type { RegisterDeps } from "./state.js";
|
|
29
29
|
|
|
@@ -23,13 +23,15 @@ 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
|
|
@@ -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
|
+
};
|
|
@@ -1,19 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settings + model-picker UI: settings text, the `/model` main/browse/backend
|
|
3
|
-
* keyboards, effort rows, and the menu-state builder.
|
|
3
|
+
* keyboards, effort rows, the model-option list, and the menu-state builder.
|
|
4
|
+
* All pure rendering.
|
|
5
|
+
*
|
|
6
|
+
* The settings body itself is `frontend/presentation/reports.ts`, rendered
|
|
7
|
+
* with Telegram's dialect; everything below it is inline-keyboard shape,
|
|
8
|
+
* which has no counterpart on Discord (Components, not keyboards).
|
|
4
9
|
*/
|
|
5
10
|
|
|
6
11
|
import { escapeHtml } from "../formatting.js";
|
|
7
12
|
import type { ReasoningEffortLevel } from "../../../core/types.js";
|
|
8
13
|
import { REASONING_LEVEL_LABELS } from "../../../core/models/reasoning-levels.js";
|
|
9
|
-
import { resolveModel, resolveModelId } from "../../../core/models/catalog.js";
|
|
10
14
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "
|
|
15
|
+
getModels,
|
|
16
|
+
resolveModel,
|
|
17
|
+
resolveModelId,
|
|
18
|
+
type ModelInfo,
|
|
19
|
+
} from "../../../core/models/catalog.js";
|
|
20
|
+
import { renderSettingsText as renderSettingsTextWith } from "../../presentation/reports.js";
|
|
21
|
+
import { TELEGRAM_REPORTS } from "./html.js";
|
|
22
|
+
|
|
23
|
+
/** Display name for a known ModelInfo. */
|
|
24
|
+
export function formatModelOptionLabel(model: ModelInfo): string {
|
|
25
|
+
return model.displayName;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Compact display name for a known ModelInfo. */
|
|
29
|
+
export function formatCompactModelLabel(model: ModelInfo): string {
|
|
30
|
+
return model.displayName;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** One option per distinct display name, in catalog order. */
|
|
34
|
+
export function getTelegramModelOptions(): ModelInfo[] {
|
|
35
|
+
const options: ModelInfo[] = [];
|
|
36
|
+
const seenKeys = new Set<string>();
|
|
37
|
+
|
|
38
|
+
for (const model of getModels()) {
|
|
39
|
+
const key = model.displayName.toLowerCase();
|
|
40
|
+
if (seenKeys.has(key)) continue;
|
|
41
|
+
seenKeys.add(key);
|
|
42
|
+
options.push(model);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return options;
|
|
46
|
+
}
|
|
17
47
|
|
|
18
48
|
export function renderSettingsText(
|
|
19
49
|
model: string,
|
|
@@ -22,17 +52,14 @@ export function renderSettingsText(
|
|
|
22
52
|
pulseIntervalMs?: number,
|
|
23
53
|
modelDetails?: Array<string>,
|
|
24
54
|
): string {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
`<b>Effort:</b> ${effort}`,
|
|
34
|
-
`<b>Pulse:</b> ${proactive ? "on" : "off"} (every ${intervalStr})`,
|
|
35
|
-
].join("\n");
|
|
55
|
+
return renderSettingsTextWith(
|
|
56
|
+
TELEGRAM_REPORTS,
|
|
57
|
+
model,
|
|
58
|
+
effort,
|
|
59
|
+
proactive,
|
|
60
|
+
pulseIntervalMs,
|
|
61
|
+
modelDetails,
|
|
62
|
+
);
|
|
36
63
|
}
|
|
37
64
|
|
|
38
65
|
export function isSelectedModel(
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics, doctor, mesh and usage reports for Telegram (HTML messages).
|
|
3
|
+
*
|
|
4
|
+
* The reports themselves live in `frontend/presentation/reports.ts` and
|
|
5
|
+
* the HTML dialect in `./html.ts`; this file is the wrappers that keep
|
|
6
|
+
* each command to a single import, plus the two Telegram-only pieces:
|
|
7
|
+
* the /metrics grain keyboard and the `/mesh` bridge footer.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { escapeHtml } from "../formatting.js";
|
|
11
|
+
import type { DoctorReport } from "../../../core/doctor/index.js";
|
|
12
|
+
import type { MeshPingResult } from "../../../core/mesh/service.js";
|
|
13
|
+
import type { BackendUsageEntry } from "../../presentation/plan-usage-report.js";
|
|
14
|
+
import type { SettingsButton } from "./menu.js";
|
|
15
|
+
import {
|
|
16
|
+
renderDoctorReport,
|
|
17
|
+
renderMeshReport as renderMeshReportWith,
|
|
18
|
+
renderMetricsPanel as renderMetricsPanelWith,
|
|
19
|
+
renderUsageMessage as renderUsageMessageWith,
|
|
20
|
+
type MetricsSnapshot,
|
|
21
|
+
} from "../../presentation/reports.js";
|
|
22
|
+
import { TELEGRAM_MESSAGE_MAX, TELEGRAM_REPORTS } from "./html.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Rows shown in the `tool_calls` leaderboard before the tail collapses
|
|
26
|
+
* into a "…and N more" line. A long-lived bot accumulates a lifetime
|
|
27
|
+
* tool-call entry per distinct tool name (easily 100+ once plugin and
|
|
28
|
+
* MCP tools are counted), which is what used to push /metrics past
|
|
29
|
+
* Telegram's message limit and split it across messages.
|
|
30
|
+
*/
|
|
31
|
+
const TOOL_CALLS_TOP_N = 12;
|
|
32
|
+
|
|
33
|
+
/** Which grain the /metrics panel is currently showing. */
|
|
34
|
+
export type MetricsView = "today" | "all";
|
|
35
|
+
|
|
36
|
+
const VIEW_TITLES: Record<MetricsView, string> = {
|
|
37
|
+
today: "Metrics — today (UTC)",
|
|
38
|
+
all: "Metrics — all time",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Render the /metrics panel for one grain as a SINGLE Telegram message.
|
|
43
|
+
* Pair it with `renderMetricsKeyboard(view)` — the Today / All time
|
|
44
|
+
* buttons swap grains by editing this message in place.
|
|
45
|
+
*/
|
|
46
|
+
export function renderMetricsPanel(
|
|
47
|
+
metrics: MetricsSnapshot,
|
|
48
|
+
view: MetricsView,
|
|
49
|
+
maxLen = TELEGRAM_MESSAGE_MAX,
|
|
50
|
+
): string {
|
|
51
|
+
return renderMetricsPanelWith(
|
|
52
|
+
metrics,
|
|
53
|
+
TELEGRAM_REPORTS,
|
|
54
|
+
VIEW_TITLES[view],
|
|
55
|
+
maxLen,
|
|
56
|
+
TOOL_CALLS_TOP_N,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Grain-switch buttons for the /metrics panel. */
|
|
61
|
+
export function renderMetricsKeyboard(
|
|
62
|
+
view: MetricsView,
|
|
63
|
+
): Array<Array<SettingsButton>> {
|
|
64
|
+
return [
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
text: view === "today" ? "✓ Today" : "Today",
|
|
68
|
+
callback_data: "metrics:today",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
text: view === "all" ? "✓ All time" : "All time",
|
|
72
|
+
callback_data: "metrics:all",
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Render the `/usage` report — one block per exposed backend. */
|
|
79
|
+
export function renderUsageMessage(entries: BackendUsageEntry[]): string {
|
|
80
|
+
return renderUsageMessageWith(entries, TELEGRAM_REPORTS);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Render a DoctorReport as one Telegram HTML message. Same data as
|
|
85
|
+
* `talon doctor` (src/core/doctor/) plus in-process runtime info — when
|
|
86
|
+
* this renders, the bot is by definition running, so the CLI's "is the
|
|
87
|
+
* bot up" probe becomes an uptime line instead.
|
|
88
|
+
*/
|
|
89
|
+
export function renderDoctorMessage(report: DoctorReport): string {
|
|
90
|
+
return renderDoctorReport(report, TELEGRAM_REPORTS);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── /mesh ───────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Render the `/mesh` fleet report as one HTML message, with the bridge
|
|
97
|
+
* footer appended when the caller supplies reachability.
|
|
98
|
+
*/
|
|
99
|
+
export function renderMeshReport(
|
|
100
|
+
results: MeshPingResult[],
|
|
101
|
+
now = Date.now(),
|
|
102
|
+
bridge?: MeshReachability,
|
|
103
|
+
): string {
|
|
104
|
+
// An empty fleet is the one case where "what do I point a device at?" is
|
|
105
|
+
// the only useful thing to say, so the bridge line carries the answer
|
|
106
|
+
// instead of leaving the operator to hunt for host and port.
|
|
107
|
+
return renderMeshReportWith(
|
|
108
|
+
results,
|
|
109
|
+
TELEGRAM_REPORTS,
|
|
110
|
+
now,
|
|
111
|
+
bridgeLines(bridge),
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** What `/mesh` says about the bridge a new device would dial. */
|
|
116
|
+
export type MeshReachability =
|
|
117
|
+
| {
|
|
118
|
+
ok: true;
|
|
119
|
+
url: string;
|
|
120
|
+
authRequired: boolean;
|
|
121
|
+
token?: string;
|
|
122
|
+
fingerprint?: string;
|
|
123
|
+
}
|
|
124
|
+
| { ok: false; text: string };
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The bridge footer.
|
|
128
|
+
*
|
|
129
|
+
* The bearer token and certificate appear when the caller passed them, which
|
|
130
|
+
* `/mesh` does for the configured admin and not for anyone else: an operator
|
|
131
|
+
* asking their own daemon how to reach itself should get the answer, while a
|
|
132
|
+
* group member reading the fleet has no business holding the key to it.
|
|
133
|
+
*/
|
|
134
|
+
function bridgeLines(bridge?: MeshReachability): string[] {
|
|
135
|
+
if (!bridge) return [];
|
|
136
|
+
if (!bridge.ok) return ["", `<b>Bridge</b> — ${escapeHtml(bridge.text)}`];
|
|
137
|
+
const auth = bridge.authRequired ? "token required" : "no token";
|
|
138
|
+
return [
|
|
139
|
+
"",
|
|
140
|
+
`<b>Bridge</b> <code>${escapeHtml(bridge.url)}</code> · ${auth}`,
|
|
141
|
+
...(bridge.token ? [`Token <code>${escapeHtml(bridge.token)}</code>`] : []),
|
|
142
|
+
...(bridge.fingerprint
|
|
143
|
+
? [`Certificate <code>${escapeHtml(bridge.fingerprint)}</code>`]
|
|
144
|
+
: []),
|
|
145
|
+
"Run <code>/mesh link</code> for a one-tap pairing link.",
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Render a minted pairing link, or why one couldn't be minted.
|
|
151
|
+
*
|
|
152
|
+
* The values are printed alongside the link because the link's whole payoff
|
|
153
|
+
* — the phone configuring itself — depends on the companion already being
|
|
154
|
+
* installed, and the fallback needs to be right there when it isn't.
|
|
155
|
+
*/
|
|
156
|
+
export function renderMeshPairLink(
|
|
157
|
+
minted:
|
|
158
|
+
| {
|
|
159
|
+
ok: true;
|
|
160
|
+
link: string;
|
|
161
|
+
url: string;
|
|
162
|
+
token: string;
|
|
163
|
+
fingerprint?: string;
|
|
164
|
+
}
|
|
165
|
+
| { ok: false; text: string },
|
|
166
|
+
): string {
|
|
167
|
+
if (!minted.ok) {
|
|
168
|
+
return `<b>Pairing</b>\n\n${escapeHtml(minted.text)}`;
|
|
169
|
+
}
|
|
170
|
+
return [
|
|
171
|
+
"<b>Pair a device</b>",
|
|
172
|
+
"",
|
|
173
|
+
`Open on the phone: ${escapeHtml(minted.link)}`,
|
|
174
|
+
"",
|
|
175
|
+
"Single-use, expires in 10 minutes. If the companion isn't installed yet:",
|
|
176
|
+
` Bridge <code>${escapeHtml(minted.url)}</code>`,
|
|
177
|
+
` Token <code>${escapeHtml(minted.token)}</code>`,
|
|
178
|
+
...(minted.fingerprint
|
|
179
|
+
? [` Certificate <code>${escapeHtml(minted.fingerprint)}</code>`]
|
|
180
|
+
: []),
|
|
181
|
+
].join("\n");
|
|
182
|
+
}
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
apportionCells,
|
|
8
8
|
type ContextBreakdown,
|
|
9
9
|
type ContextSegmentKey,
|
|
10
|
-
} from "../../
|
|
10
|
+
} from "../../presentation/status-context.js";
|
|
11
11
|
import { getRecentHistory } from "../../../storage/history.js";
|
|
12
|
-
import { formatTokenCount } from "../../
|
|
12
|
+
import { formatTokenCount } from "../../presentation/format.js";
|
|
13
13
|
import { getChatSettings } from "../../../storage/chat-settings.js";
|
|
14
14
|
import { resolveModelId as resolveModelName } from "../../../core/models/catalog.js";
|
|
15
15
|
import { getSessionInfo } from "../../../storage/sessions.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
import { formatTimeAgo } from "../renderer.js";
|
|
5
|
-
import { isTerminalChatId } from "../../../
|
|
5
|
+
import { isTerminalChatId } from "../../../core/frontend-runtime/chat-id.js";
|
|
6
6
|
import { resolveModel as coreResolveModel } from "../../../core/models/catalog.js";
|
|
7
7
|
import {
|
|
8
8
|
getAllSessions,
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
buildCacheDisplay,
|
|
6
6
|
buildContextDisplay,
|
|
7
7
|
buildPlanDisplay,
|
|
8
|
-
} from "../../
|
|
8
|
+
} from "../../presentation/status-context.js";
|
|
9
9
|
import {
|
|
10
10
|
formatDuration,
|
|
11
11
|
formatTokenCount,
|
|
12
12
|
formatUsd,
|
|
13
|
-
} from "../../
|
|
13
|
+
} from "../../presentation/format.js";
|
|
14
14
|
import { getChatSettings } from "../../../storage/chat-settings.js";
|
|
15
15
|
import { getSessionInfo } from "../../../storage/sessions.js";
|
|
16
16
|
import { getLoadedPlugins } from "../../../core/plugin/index.js";
|
|
@@ -16,7 +16,7 @@ import { log } from "../../util/log.js";
|
|
|
16
16
|
import {
|
|
17
17
|
deriveNumericChatId,
|
|
18
18
|
generateTerminalChatId,
|
|
19
|
-
} from "../../
|
|
19
|
+
} from "../../core/frontend-runtime/chat-id.js";
|
|
20
20
|
import { resolveModel } from "../../core/models/catalog.js";
|
|
21
21
|
import { toolInputToRecord } from "../../core/agent-runtime/events.js";
|
|
22
22
|
import { createRenderer } from "./renderer.js";
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
clearCommands,
|
|
28
28
|
type CommandContext,
|
|
29
29
|
} from "./commands.js";
|
|
30
|
-
import { buildCacheDisplay } from "../
|
|
30
|
+
import { buildCacheDisplay } from "../presentation/status-context.js";
|
|
31
31
|
|
|
32
32
|
// ── State ────────────────────────────────────────────────────────────────────
|
|
33
33
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* WhatsApp has no inline buttons, so everything Telegram does with a
|
|
6
6
|
* picker is done here with typed arguments: `/model` prints a numbered
|
|
7
7
|
* catalog, `/model 3` (or `/model <id>`, `/model <backend>`) picks from
|
|
8
|
-
* it. The state changes come from frontend/
|
|
8
|
+
* it. The state changes come from frontend/presentation/model-commands.ts;
|
|
9
9
|
* this module only parses, authorises, and renders.
|
|
10
10
|
*
|
|
11
11
|
* Replies are written in Markdown — `sendText` translates them into
|
|
@@ -23,16 +23,16 @@ import {
|
|
|
23
23
|
formatModelLabel,
|
|
24
24
|
formatTokenCount,
|
|
25
25
|
formatUsd,
|
|
26
|
-
} from "../
|
|
26
|
+
} from "../presentation/format.js";
|
|
27
27
|
import {
|
|
28
28
|
collectSessionStatus,
|
|
29
29
|
performSessionReset,
|
|
30
30
|
type SessionStatusData,
|
|
31
|
-
} from "../
|
|
31
|
+
} from "../presentation/session-status.js";
|
|
32
32
|
import {
|
|
33
33
|
formatCacheTempLine,
|
|
34
34
|
formatDaemonLine,
|
|
35
|
-
} from "../
|
|
35
|
+
} from "../presentation/status-context.js";
|
|
36
36
|
import {
|
|
37
37
|
describeChatEffort,
|
|
38
38
|
describeChatModels,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
switchChatBackend,
|
|
46
46
|
type ModelCommandDeps,
|
|
47
47
|
type ModelOverview,
|
|
48
|
-
} from "../
|
|
48
|
+
} from "../presentation/model-commands.js";
|
|
49
49
|
import { sendText } from "./actions/send.js";
|
|
50
50
|
import { identityAllowed, type Identity } from "./connection/identity.js";
|
|
51
51
|
import type { WhatsAppChatInfo } from "./registry.js";
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { isJidGroup, jidNormalizedUser } from "baileys";
|
|
12
|
-
import { deriveNumericChatId } from "../../
|
|
12
|
+
import { deriveNumericChatId } from "../../core/frontend-runtime/chat-id.js";
|
|
13
13
|
import { bareId } from "./connection/identity.js";
|
|
14
14
|
|
|
15
15
|
export type WhatsAppChatInfo = {
|
package/src/index.ts
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
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 {
|
|
11
|
+
import {
|
|
12
|
+
MCP_LAUNCH_SUBCOMMAND,
|
|
13
|
+
runSupervisor,
|
|
14
|
+
} from "./core/mcp-hub/launcher.js";
|
|
12
15
|
import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/scripts/lua.js";
|
|
13
16
|
|
|
14
17
|
if (process.argv[2] === MCP_LAUNCH_SUBCOMMAND) {
|
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. */
|