talon-agent 1.2.0 → 1.4.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.
Files changed (46) hide show
  1. package/package.json +7 -6
  2. package/prompts/dream.md +6 -2
  3. package/prompts/mempalace.md +57 -0
  4. package/src/__tests__/compose-tools.test.ts +216 -0
  5. package/src/__tests__/cron-store-extended.test.ts +1 -1
  6. package/src/__tests__/dream.test.ts +118 -1
  7. package/src/__tests__/fuzz.test.ts +1 -3
  8. package/src/__tests__/gateway-actions.test.ts +1 -423
  9. package/src/__tests__/gateway-retry.test.ts +0 -4
  10. package/src/__tests__/handlers.test.ts +0 -4
  11. package/src/__tests__/heartbeat.test.ts +3 -0
  12. package/src/__tests__/mempalace-plugin.test.ts +295 -0
  13. package/src/__tests__/plugin.test.ts +169 -0
  14. package/src/__tests__/storage-save-errors.test.ts +1 -1
  15. package/src/__tests__/time.test.ts +1 -1
  16. package/src/__tests__/watchdog.test.ts +1 -3
  17. package/src/__tests__/workspace.test.ts +0 -1
  18. package/src/backend/claude-sdk/index.ts +39 -54
  19. package/src/backend/opencode/index.ts +5 -20
  20. package/src/bootstrap.ts +140 -11
  21. package/src/core/dream.ts +40 -6
  22. package/src/core/gateway-actions.ts +0 -87
  23. package/src/core/plugin.ts +103 -16
  24. package/src/core/tools/bridge.ts +40 -0
  25. package/src/core/tools/chat.ts +52 -0
  26. package/src/core/tools/history.ts +80 -0
  27. package/src/core/tools/index.ts +82 -0
  28. package/src/core/tools/mcp-server.ts +64 -0
  29. package/src/core/tools/media.ts +23 -0
  30. package/src/core/tools/members.ts +46 -0
  31. package/src/core/tools/messaging.ts +300 -0
  32. package/src/core/tools/scheduling.ts +89 -0
  33. package/src/core/tools/stickers.ts +143 -0
  34. package/src/core/tools/types.ts +60 -0
  35. package/src/core/tools/web.ts +26 -0
  36. package/src/frontend/telegram/actions.ts +10 -1
  37. package/src/frontend/telegram/handlers.ts +5 -17
  38. package/src/plugins/github/index.ts +106 -0
  39. package/src/plugins/mempalace/index.ts +147 -0
  40. package/src/plugins/playwright/index.ts +82 -0
  41. package/src/storage/sessions.ts +0 -10
  42. package/src/util/config.ts +31 -1
  43. package/src/util/log.ts +4 -1
  44. package/src/util/paths.ts +9 -0
  45. package/src/backend/claude-sdk/tools.ts +0 -651
  46. package/src/frontend/teams/tools.ts +0 -175
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Playwright plugin — browser automation via the official Playwright MCP server.
3
+ *
4
+ * Gives the agent headless Chromium for web scraping, screenshots, PDF generation,
5
+ * and general browser automation.
6
+ *
7
+ * Configuration in ~/.talon/config.json:
8
+ * "playwright": {
9
+ * "enabled": true,
10
+ * "browser": "chromium", // optional, default "chromium"
11
+ * "headless": true // optional, default true
12
+ * }
13
+ */
14
+
15
+ import { existsSync } from "node:fs";
16
+ import { resolve } from "node:path";
17
+ import type { TalonPlugin } from "../../core/plugin.js";
18
+ import { log } from "../../util/log.js";
19
+
20
+ export function createPlaywrightPlugin(config: {
21
+ browser?: string;
22
+ headless?: boolean;
23
+ }): TalonPlugin {
24
+ const browser = config.browser ?? "chromium";
25
+ const headless = config.headless !== false; // default true
26
+
27
+ // Resolve path from Talon's node_modules
28
+ const mcpBin = resolve(
29
+ import.meta.dirname ?? ".",
30
+ "../../../node_modules/@playwright/mcp/cli.js",
31
+ );
32
+
33
+ const args = ["--no-sandbox"];
34
+
35
+ if (headless) {
36
+ args.push("--headless");
37
+ }
38
+
39
+ if (browser !== "chromium") {
40
+ args.push("--browser", browser);
41
+ }
42
+
43
+ return {
44
+ name: "playwright",
45
+ description: "Browser automation via Playwright MCP (headless Chromium)",
46
+ version: "1.0.0",
47
+
48
+ mcpServer: {
49
+ command: "node",
50
+ args: [mcpBin, ...args],
51
+ },
52
+
53
+ validateConfig() {
54
+ const errors: string[] = [];
55
+
56
+ const validBrowsers = [
57
+ "chromium",
58
+ "chrome",
59
+ "firefox",
60
+ "webkit",
61
+ "msedge",
62
+ ];
63
+ if (!validBrowsers.includes(browser)) {
64
+ errors.push(
65
+ `Invalid browser "${browser}". Valid options: ${validBrowsers.join(", ")}`,
66
+ );
67
+ }
68
+
69
+ if (!existsSync(mcpBin)) {
70
+ errors.push(
71
+ `@playwright/mcp not found at ${mcpBin} — run "npm install @playwright/mcp"`,
72
+ );
73
+ }
74
+
75
+ return errors.length > 0 ? errors : undefined;
76
+ },
77
+
78
+ async init() {
79
+ log("playwright", `Ready (${browser}, headless=${headless})`);
80
+ },
81
+ };
82
+ }
@@ -82,16 +82,6 @@ export function loadSessions(): void {
82
82
  );
83
83
  store = {};
84
84
  }
85
- // SDK sessions don't survive process restarts — the embedded Claude Code
86
- // subprocess is gone. Clear stale session IDs so we don't try to resume
87
- // a dead session (which causes the SDK to hang silently on Windows).
88
- // Keep turns/usage intact — they're historical data used by /resume.
89
- for (const session of Object.values(store)) {
90
- if (session.sessionId) {
91
- session.sessionId = undefined;
92
- dirty = true;
93
- }
94
- }
95
85
  }
96
86
 
97
87
  function saveSessions(): void {
@@ -40,10 +40,40 @@ const configSchema = z.object({
40
40
  heartbeatIntervalMinutes: z.number().int().min(5).default(60),
41
41
  heartbeatModel: z.string().optional(), // Model for heartbeat agent (defaults to main model)
42
42
  braveApiKey: z.string().optional(),
43
- searxngUrl: z.string().default("http://localhost:8080"),
44
43
  timezone: z.string().optional(),
45
44
  plugins: z.array(pluginEntrySchema).default([]),
46
45
 
46
+ // GitHub — GitHub API access via official MCP server
47
+ github: z
48
+ .object({
49
+ enabled: z.boolean().default(false),
50
+ /** GitHub personal access token (default: from `gh auth token`) */
51
+ token: z.string().min(1).optional(),
52
+ })
53
+ .optional(),
54
+
55
+ // MemPalace — structured long-term memory with vector search
56
+ mempalace: z
57
+ .object({
58
+ enabled: z.boolean().default(false),
59
+ /** Palace directory path (default: ~/.talon/workspace/palace/) */
60
+ palacePath: z.string().min(1).optional(),
61
+ /** Python binary path (default: ~/.talon/mempalace-venv/bin/python) */
62
+ pythonPath: z.string().min(1).optional(),
63
+ })
64
+ .optional(),
65
+
66
+ // Playwright — headless browser automation via MCP
67
+ playwright: z
68
+ .object({
69
+ enabled: z.boolean().default(false),
70
+ /** Browser engine: chromium (default), chrome, firefox, webkit, msedge */
71
+ browser: z.string().optional(),
72
+ /** Run headless (default: true) */
73
+ headless: z.boolean().default(true),
74
+ })
75
+ .optional(),
76
+
47
77
  // Display name shown in terminal UI (defaults to "Talon")
48
78
  botDisplayName: z.string().default("Talon"),
49
79
 
package/src/util/log.ts CHANGED
@@ -41,7 +41,10 @@ export type LogComponent =
41
41
  | "plugin"
42
42
  | "teams"
43
43
  | "config"
44
- | "access";
44
+ | "access"
45
+ | "github"
46
+ | "mempalace"
47
+ | "playwright";
45
48
 
46
49
  const LOG_FILE = files.log;
47
50
 
package/src/util/paths.ts CHANGED
@@ -51,6 +51,8 @@ export const dirs = {
51
51
  prompts: resolve(TALON_ROOT, "prompts"),
52
52
  /** Per-chat message traces: ~/.talon/data/traces/ */
53
53
  traces: resolve(TALON_ROOT, "data", "traces"),
54
+ /** MemPalace palace: ~/.talon/workspace/palace/ */
55
+ palace: resolve(TALON_ROOT, "workspace", "palace"),
54
56
  } as const;
55
57
 
56
58
  // ── Files ──────────────────────────────────────────────────────────────────
@@ -78,6 +80,13 @@ export const files = {
78
80
  userSession: resolve(TALON_ROOT, ".user-session"),
79
81
  /** PID file for daemon mode: ~/.talon/talon.pid */
80
82
  pid: resolve(TALON_ROOT, "talon.pid"),
83
+ /** MemPalace venv python binary (platform-dependent: bin/python on Unix, Scripts/python.exe on Windows) */
84
+ mempalacePython: resolve(
85
+ TALON_ROOT,
86
+ "mempalace-venv",
87
+ process.platform === "win32" ? "Scripts" : "bin",
88
+ process.platform === "win32" ? "python.exe" : "python",
89
+ ),
81
90
  /** Dream mode state: ~/.talon/workspace/memory/dream_state.json */
82
91
  dreamState: resolve(TALON_ROOT, "workspace", "memory", "dream_state.json"),
83
92
  /** Heartbeat state: ~/.talon/workspace/memory/heartbeat_state.json */