talon-agent 1.35.0 → 1.36.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "talon-agent",
3
- "version": "1.35.0",
3
+ "version": "1.36.0",
4
4
  "description": "Multi-frontend AI agent with full tool access, streaming, cron jobs, and plugin system",
5
5
  "author": "Dylan Neve",
6
6
  "license": "MIT",
@@ -101,7 +101,7 @@
101
101
  "@kilocode/sdk": "^7.2.22",
102
102
  "@modelcontextprotocol/sdk": "^1.29.0",
103
103
  "@openai/agents": "^0.13.0",
104
- "@openai/codex-sdk": "^0.143.0",
104
+ "@openai/codex-sdk": "^0.144.0",
105
105
  "@opencode-ai/sdk": "^1.17.4",
106
106
  "@playwright/mcp": "^0.0.77",
107
107
  "@types/cross-spawn": "^6.0.6",
@@ -133,7 +133,7 @@
133
133
  "knip": "^6.3.1",
134
134
  "oxlint": "^1.59.0",
135
135
  "prettier": "^3.8.1",
136
- "typescript": "^6.0.2",
136
+ "typescript": "^7.0.2",
137
137
  "vitest": "^4.1.3"
138
138
  },
139
139
  "overrides": {
@@ -30,6 +30,23 @@ import { log, logError } from "../../util/log.js";
30
30
  import { getConfig, getBridgePort } from "./state.js";
31
31
  import { ALLOWED_TOOLS_CHAT, EFFORT_MAP } from "./constants.js";
32
32
 
33
+ /**
34
+ * Built-in SDK tools that Talon's native tool set replaces when
35
+ * `config.nativeTools` is on. The shell/filesystem built-ins map 1:1 to
36
+ * bash/read/write/edit/glob/search; `Agent` (sub-agent dispatch) is dropped
37
+ * alongside them per the owner's preference for the native surface.
38
+ */
39
+ const NATIVE_REPLACED_BUILTINS = new Set<string>([
40
+ "Read",
41
+ "Write",
42
+ "Edit",
43
+ "NotebookEdit",
44
+ "Bash",
45
+ "Glob",
46
+ "Grep",
47
+ "Agent",
48
+ ]);
49
+
33
50
  // ── Types ────────────────────────────────────────────────────────────────────
34
51
 
35
52
  export type BuildSdkOptionsResult = {
@@ -61,8 +78,19 @@ export type HubMcpEntry = {
61
78
  type: "http";
62
79
  url: string;
63
80
  alwaysLoad?: boolean;
81
+ /** Per-server tool-call timeout in ms (overrides MCP_TOOL_TIMEOUT). */
82
+ timeout?: number;
64
83
  };
65
84
 
85
+ /**
86
+ * Tool-call timeout for the Talon frontend tool servers. Must sit ABOVE the
87
+ * bridge's largest per-action budget (1h for uncapped device file transfers)
88
+ * so the layer that times out is the bridge — whose error names the action,
89
+ * the budget, and warns the operation may still be running — rather than the
90
+ * SDK's generic MCP timeout, which tells the model nothing actionable.
91
+ */
92
+ const FRONTEND_TOOL_CALL_TIMEOUT_MS = 3_900_000; // 65 min
93
+
66
94
  /**
67
95
  * Build the MCP servers map for a chat query.
68
96
  * Includes frontend-specific tool servers and Brave Search, if configured.
@@ -102,6 +130,8 @@ export function buildMcpServers(chatId: string): Record<string, HubMcpEntry> {
102
130
  // lever here. Cost: ~50 frontend tool schemas loaded every turn (~10k
103
131
  // tokens, cached, negligible on the 1M-context models Talon runs).
104
132
  alwaysLoad: true,
133
+ // Outlast the bridge's 1h transfer budget — see the constant's doc.
134
+ timeout: FRONTEND_TOOL_CALL_TIMEOUT_MS,
105
135
  };
106
136
  }
107
137
 
@@ -388,7 +418,17 @@ export function buildSdkOptions(
388
418
  // WebFetch, Monitor, PushNotification, RemoteTrigger, Plan/Worktree/Todo
389
419
  // helpers, AskUserQuestion, ScheduleWakeup) is unavailable to the model.
390
420
  // MCP tools are governed independently via `mcpServers` below.
391
- tools: [...ALLOWED_TOOLS_CHAT],
421
+ //
422
+ // When `config.nativeTools` is on, the SDK's built-in shell/filesystem
423
+ // tools are dropped in favour of Talon's own native tools (which also
424
+ // teleport onto companion devices), and Agent (sub-agent dispatch) is
425
+ // removed too — the owner prefers the native surface without nested
426
+ // agents. Flip the flag back off to restore the built-ins instantly.
427
+ tools: config.nativeTools
428
+ ? ALLOWED_TOOLS_CHAT.filter(
429
+ (t) => !NATIVE_REPLACED_BUILTINS.has(t as string),
430
+ )
431
+ : [...ALLOWED_TOOLS_CHAT],
392
432
  ...thinkingConfig,
393
433
  mcpServers: {
394
434
  ...buildMcpServers(chatId),
package/src/bootstrap.ts CHANGED
@@ -167,6 +167,7 @@ export async function bootstrap(
167
167
  disabledTools: config.disabledTools,
168
168
  disabledToolTags: config.disabledToolTags,
169
169
  braveApiKey: config.braveApiKey,
170
+ nativeTools: config.nativeTools,
170
171
  });
171
172
 
172
173
  initWorkspace(config.workspace);
@@ -32,6 +32,7 @@ import { skillHandlers } from "./skills.js";
32
32
  import { pluginHandlers } from "./plugins.js";
33
33
  import { modelHandlers } from "./models.js";
34
34
  import { meshHandlers } from "./mesh.js";
35
+ import { nativeHandlers } from "./native.js";
35
36
 
36
37
  // Null-prototype so a request `action` of "toString" / "constructor" / etc.
37
38
  // can't resolve an inherited Object.prototype method — `handlers[action]` only
@@ -47,6 +48,7 @@ const handlers: SharedActionHandlers = Object.assign(Object.create(null), {
47
48
  ...pluginHandlers,
48
49
  ...modelHandlers,
49
50
  ...meshHandlers,
51
+ ...nativeHandlers,
50
52
  });
51
53
 
52
54
  export async function handleSharedAction(
@@ -19,4 +19,31 @@ export const meshHandlers: SharedActionHandlers = {
19
19
  getMeshService().deviceHistory(body.device, body.hours),
20
20
  ring_device: (body) => getMeshService().ringDevice(body.device, body.message),
21
21
  get_device_status: (body) => getMeshService().getDeviceStatus(body.device),
22
+ // Exec + filesystem surface — the substrate teleport routes through.
23
+ device_exec: (body) =>
24
+ getMeshService().execOnDevice(
25
+ body.device,
26
+ body.cmd,
27
+ body.cwd,
28
+ body.timeout_sec,
29
+ ),
30
+ device_list_dir: (body) =>
31
+ getMeshService().listDirOnDevice(body.device, body.path),
32
+ device_stat: (body) => getMeshService().statOnDevice(body.device, body.path),
33
+ device_read_file: (body) =>
34
+ getMeshService().readFileFromDevice(body.device, body.path),
35
+ device_write_file: (body) =>
36
+ getMeshService().writeFileToDevice(body.device, body.path, body.content),
37
+ device_pull_file: (body) =>
38
+ getMeshService().pullFileFromDevice(
39
+ body.device,
40
+ body.remote_path,
41
+ body.local_path,
42
+ ),
43
+ device_push_file: (body) =>
44
+ getMeshService().pushFileToDevice(
45
+ body.device,
46
+ body.local_path,
47
+ body.remote_path,
48
+ ),
22
49
  };