@livx.cc/agentx 0.99.122 → 0.99.123
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 +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +42 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +36 -9
- package/dist/index.js.map +1 -1
- package/dist/{mcp-CUo-9LUe.d.ts → mcp-DZhcLur2.d.ts} +1 -1
- package/dist/mcp.client.d.ts +2 -2
- package/dist/{secondChannel-BddfVzTp.d.ts → secondChannel-DES_VIeN.d.ts} +25 -2
- package/dist/{tools-DZHZIyxh.d.ts → tools-DwfeF8VQ.d.ts} +3 -0
- package/dist/tools.shell.d.ts +1 -1
- package/dist/tools.shell.js +1 -0
- package/dist/tools.shell.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ Beyond file tools, the runtime ships the higher-altitude pieces too — each an
|
|
|
87
87
|
- **Skills + memory** — VFS-backed (`skillsDir`/`memoryDir`); persistence is just the backend choice.
|
|
88
88
|
- **Subagents** (`subagents`; **typed agents** via `agentsDir` — `<dir>/<name>.md` defines a persona + model + scoped tools, selected with the `Task` `agentType`), **hooks** (`hooks`: preToolUse/postToolUse/onStop — block or audit any tool call), **slash-commands** (`commandsDir`), **TodoWrite**, **MCP** (`mcpToolsToAgentTools`).
|
|
89
89
|
- **A delegated child is a full agent**: it inherits the parent's **tools** (incl. host-injected/MCP ones), **system prompt**, and **providerOptions** (only when it stays on the same provider — cursor's `cwd`/`cursorSession` never leak onto an anthropic child; override with `providerOptionsFor(model)`). `Task({ model })` (and a `TaskBatch` task's `model`) runs one sub-task on another model — alias or full id, precedence **explicit `model` > `agentType` def's `model` > parent's**. A def's frontmatter `tools:` allowlist narrows the inherited set and may name a host-injected tool by name; its body still overrides the persona. The host's `preToolUse` gate is inherited too, so delegation is not a way around it (the observer/lifecycle hooks stay parent-only). Inherited tools that escape the VFS are re-bound per child (`AgentTool.withCwd`): a `isolation:"worktree"` child's real `Shell` runs in the WORKTREE, keeping any host rename (`Shell` -> `Bash`) (background shell jobs are off there, and the parent-bound `ShellOutput`/`ShellStatus`/`ShellKill` are dropped rather than pointed at the parent's jobs); an overlay child's shell writes straight to the working tree — an overlay isolates the VFS, not a process.
|
|
90
|
-
- **Two-model modes** (`src/modes.ts`) — **delegate** (`delegate: { worker }`): the agent's model PLANS and may not write (Write/Edit/MultiEdit/ApplyEdits/bash/Shell are refused at execution, keyed on `ToolContext.model`), `Task`/`TaskBatch` go on (depth 1, children default to the worker, and get the host's `postToolUse` so their writes are observed). **advisor** (`advisor: { model, limit?, snapshot? }`): the agent's model does the work and an `Advise` tool asks the stronger model (≤3 calls; it sees only the request, the host's optional `snapshot()` and the question); the first write waits for one consult. Both are off when the models are equal or either is `cursor/*`; the second model's usage comes back as `RunResult.workerUsage` / `workerModel` (not in `usage`). Prompt directives switch them: `[opus->haiku] task` (delegate), `[haiku<-opus] task` (advisor), `[off]`; keyed forms `delegate:x`, `advisor:x`, `mode:off`. A host passing its own `keys` to `parseDirectives` must list `delegate` / `advisor` / `mode`.
|
|
90
|
+
- **Two-model modes** (`src/modes.ts`) — **delegate** (`delegate: { worker }`): the agent's model PLANS and may not write (Write/Edit/MultiEdit/ApplyEdits/bash/Shell are refused at execution, keyed on `ToolContext.model`), `Task`/`TaskBatch` go on (depth 1, children default to the worker, and get the host's `postToolUse` so their writes are observed). **advisor** (`advisor: { model, limit?, snapshot? }`): the agent's model does the work and an `Advise` tool asks the stronger model (≤3 calls; it sees only the request, the host's optional `snapshot()` and the question); the first write waits for one consult. A `claude-code/*` agent gets the same modes as SDK options (`ccModeOptions`): a planner's native Write/Edit/MultiEdit/NotebookEdit/Bash/Task/Agent are `disallowedTools` and agentx's Task/TaskBatch reach it over the in-process bridge; an advised worker gets `Advise` bridged and a PreToolUse hook that denies native writes until one consult. Mixed pairs (anthropic ↔ claude-code) work. Both are off when the models are equal or either is `cursor/*`; the second model's usage comes back as `RunResult.workerUsage` / `workerModel` (not in `usage`). Prompt directives switch them: `[opus->haiku] task` (delegate), `[haiku<-opus] task` (advisor), `[off]`; keyed forms `delegate:x`, `advisor:x`, `mode:off`. A host passing its own `keys` to `parseDirectives` must list `delegate` / `advisor` / `mode`.
|
|
91
91
|
- **Streaming** (`stream: true` → `text_delta` via `HostBridge.notify`) and **context compaction** (`compaction: { maxMessages }` → edge-safe summarize-and-boundary). Defaults preserve the original non-stream, drop-oldest behavior.
|
|
92
92
|
- **Multi-turn + project context** — `Agent.send()` continues a conversation across turns (vs `run()`, which starts fresh); **project instructions** (`instructionFiles`: `AGENTS.md`/`CLAUDE.md` at the FS root) inject into the system prompt.
|
|
93
93
|
- **DuplexAgent** (`src/duplex.ts`) — voice-optimized three-tier engine (reflex/act/think): a fast reflex agent streams instant replies and self-selects escalation — `Act` for standard tool work (Sonnet-class), `Think` for deep reasoning (Opus-class, configurable, default on). Results are pushed back and re-voiced by the reflex (turn mutex, coalesced completions, `TaskStatus`/`CancelTask`). See [`mind/10`](./mind/10-duplex.md).
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import {
|
|
2
|
+
import { v as RouterState, H as Hooks, c as AgentOptions, w as RunResult, f as ChatUsage, R as ReasoningEffort, d as ChannelMode, b as Agent } from './secondChannel-DES_VIeN.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
|
-
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-
|
|
4
|
+
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-DwfeF8VQ.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* On-disk session store for the CLI: each conversation is one JSON file at
|
package/dist/cli.js
CHANGED
|
@@ -825,6 +825,7 @@ var init_tools_structured = __esm({
|
|
|
825
825
|
};
|
|
826
826
|
writeTool = {
|
|
827
827
|
name: "Write",
|
|
828
|
+
writes: true,
|
|
828
829
|
description: "Create or overwrite a file with the given contents, creating parent directories as needed. Use for new files instead of `bash echo >`. To replace an EXISTING file you must Read it first \u2014 overwriting an un-Read file is refused (it would destroy unseen content).",
|
|
829
830
|
parameters: {
|
|
830
831
|
type: "object",
|
|
@@ -850,6 +851,7 @@ var init_tools_structured = __esm({
|
|
|
850
851
|
};
|
|
851
852
|
multiEditTool = {
|
|
852
853
|
name: "MultiEdit",
|
|
854
|
+
writes: true,
|
|
853
855
|
description: "Apply several exact-substring replacements to one file in order, in a single call. Requires a prior Read. Each `old_string` must be unique at the time it is applied. All-or-nothing: if any edit fails, none are written.",
|
|
854
856
|
parameters: {
|
|
855
857
|
type: "object",
|
|
@@ -891,6 +893,7 @@ var init_tools_structured = __esm({
|
|
|
891
893
|
};
|
|
892
894
|
applyEditsTool = {
|
|
893
895
|
name: "ApplyEdits",
|
|
896
|
+
writes: true,
|
|
894
897
|
description: "Apply edits across one or MORE files in a single call \u2014 for cross-file refactors (rename/extract/move). edits=[{path, old_string?, new_string}]. WITH old_string: replace that exact substring (must be UNIQUE in the file \u2014 add surrounding context; read fresh + verified, no prior Read needed). WITHOUT old_string: write new_string as the whole file (creates it + parent dirs; but to OVERWRITE a file that already exists you must Read it first, else use old_string to edit part of it). Locate sites first with Grep (its output shows the exact text). Atomic: validated across all files before any write.",
|
|
895
898
|
parameters: {
|
|
896
899
|
type: "object",
|
|
@@ -1584,6 +1587,7 @@ var init_tools = __esm({
|
|
|
1584
1587
|
};
|
|
1585
1588
|
bashTool = {
|
|
1586
1589
|
name: "bash",
|
|
1590
|
+
writes: true,
|
|
1587
1591
|
description: "Run a shell command. Supports ls, cat, grep, find, head, tail, echo, mkdir, rm, mv, cp, wc, pipes (|), redirects (>, >>), and chaining (&&, ||, ;). Best for: running tests/builds, file operations (mkdir/mv/rm), and piped workflows. For searching file contents, prefer `Grep` (structured results, no re-parse). For finding files by name, prefer `Glob`.",
|
|
1588
1592
|
parameters: {
|
|
1589
1593
|
type: "object",
|
|
@@ -1661,6 +1665,7 @@ var init_tools = __esm({
|
|
|
1661
1665
|
};
|
|
1662
1666
|
editTool = {
|
|
1663
1667
|
name: "Edit",
|
|
1668
|
+
writes: true,
|
|
1664
1669
|
description: "Replace an exact substring in a file. Requires a prior Read of the same file. `old_string` must occur exactly once \u2014 include surrounding context to disambiguate.",
|
|
1665
1670
|
parameters: {
|
|
1666
1671
|
type: "object",
|
|
@@ -2992,6 +2997,7 @@ function makeRealShellTool(options) {
|
|
|
2992
2997
|
};
|
|
2993
2998
|
return {
|
|
2994
2999
|
name: "Shell",
|
|
3000
|
+
writes: true,
|
|
2995
3001
|
// Rebind for an isolated child agent (git worktree): same policy/env/timeouts, new cwd. The
|
|
2996
3002
|
// `registry` is deliberately dropped — it is bound to the PARENT's cwd (and, in hosts like
|
|
2997
3003
|
// shraga-ee, to the parent's session), so a background job started from the child would run
|
|
@@ -3967,8 +3973,8 @@ function memorySearchTool(fs, dirs) {
|
|
|
3967
3973
|
return `Error: invalid regex: ${e}`;
|
|
3968
3974
|
}
|
|
3969
3975
|
} else {
|
|
3970
|
-
const
|
|
3971
|
-
matcher = (l) => l.toLowerCase().includes(
|
|
3976
|
+
const lower2 = q2.toLowerCase();
|
|
3977
|
+
matcher = (l) => l.toLowerCase().includes(lower2);
|
|
3972
3978
|
}
|
|
3973
3979
|
const loaded = [];
|
|
3974
3980
|
for (const slug2 of slugs) {
|
|
@@ -4618,6 +4624,11 @@ init_logging();
|
|
|
4618
4624
|
var log8 = forComponent("modes");
|
|
4619
4625
|
var WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "ApplyEdits"]);
|
|
4620
4626
|
var PLANNER_BLOCKED = /* @__PURE__ */ new Set([...WRITE_TOOLS, "bash", "Shell"]);
|
|
4627
|
+
var lower = (xs) => new Set([...xs].map((x) => x.toLowerCase()));
|
|
4628
|
+
var PLANNER_BLOCKED_LC = lower(PLANNER_BLOCKED);
|
|
4629
|
+
var WRITE_TOOLS_LC = lower(WRITE_TOOLS);
|
|
4630
|
+
var plannerBlocks = (t) => !!t.writes || PLANNER_BLOCKED_LC.has(t.name.toLowerCase());
|
|
4631
|
+
var isFileWrite = (t) => WRITE_TOOLS_LC.has(t.name.toLowerCase());
|
|
4621
4632
|
var PLANNER_REFUSAL = "Refused: you are the planner and do not write files. Delegate the change with Task/TaskBatch (model set to the worker) and give the worker a full spec.";
|
|
4622
4633
|
var PLAN_FIRST = "Refused: check your plan with `Advise` before the first write (files, data shape, the hard parts). Then write.";
|
|
4623
4634
|
var ADVISE_LIMIT = 3;
|
|
@@ -4640,7 +4651,7 @@ function advisorFor(worker, advisor) {
|
|
|
4640
4651
|
return advisor && pairOk("advisor", worker, advisor) ? advisor : void 0;
|
|
4641
4652
|
}
|
|
4642
4653
|
function delegateTools(tools, planner) {
|
|
4643
|
-
return tools.map((t) => !
|
|
4654
|
+
return tools.map((t) => !plannerBlocks(t) ? t : {
|
|
4644
4655
|
...t,
|
|
4645
4656
|
run: async (...a) => a[1]?.model === planner ? PLANNER_REFUSAL : t.run(...a)
|
|
4646
4657
|
});
|
|
@@ -4710,7 +4721,7 @@ ${question}` }
|
|
|
4710
4721
|
}
|
|
4711
4722
|
}
|
|
4712
4723
|
};
|
|
4713
|
-
const gate = (tools) => tools.map((t) => !
|
|
4724
|
+
const gate = (tools) => tools.map((t) => !isFileWrite(t) ? t : { ...t, run: async (...a) => used ? t.run(...a) : PLAN_FIRST });
|
|
4714
4725
|
return { tool, gate, used: () => used };
|
|
4715
4726
|
}
|
|
4716
4727
|
function meterWorkers(ai, main2) {
|
|
@@ -4753,6 +4764,13 @@ function meterWorkers(ai, main2) {
|
|
|
4753
4764
|
resolved = void 0;
|
|
4754
4765
|
} };
|
|
4755
4766
|
}
|
|
4767
|
+
var CC_WRITE_TOOLS = ["Write", "Edit", "MultiEdit", "NotebookEdit"];
|
|
4768
|
+
function ccModeOptions(kind, hostHooks, used) {
|
|
4769
|
+
if (kind === "delegate") return { bridge: /* @__PURE__ */ new Set(["Task", "TaskBatch"]), disallow: [...CC_WRITE_TOOLS, "Bash", "Task", "Agent"] };
|
|
4770
|
+
if (kind !== "advisor") return { bridge: /* @__PURE__ */ new Set(), disallow: [] };
|
|
4771
|
+
const gate = { matcher: CC_WRITE_TOOLS.join("|"), hooks: [async () => used() ? {} : { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: PLAN_FIRST.replace("`Advise`", "`mcp__agentx__Advise`") } }] };
|
|
4772
|
+
return { bridge: /* @__PURE__ */ new Set(["Advise"]), disallow: [], hooks: { ...hostHooks, PreToolUse: [...hostHooks?.PreToolUse ?? [], gate] } };
|
|
4773
|
+
}
|
|
4756
4774
|
|
|
4757
4775
|
// src/lint.ts
|
|
4758
4776
|
var CODE_RE = /\.(ts|tsx|js|jsx|mjs|cjs)$/;
|
|
@@ -5080,6 +5098,8 @@ var Agent = class _Agent {
|
|
|
5080
5098
|
meter;
|
|
5081
5099
|
// delegate/advisor: meters the second model's calls
|
|
5082
5100
|
modeModel;
|
|
5101
|
+
modeKind;
|
|
5102
|
+
adv;
|
|
5083
5103
|
lastTask = "";
|
|
5084
5104
|
// the current turn's text — what the advisor reads as the request
|
|
5085
5105
|
/** claude-code bridge for agentx-only tools (ccBridge.ts) + the current step's executor it calls. */
|
|
@@ -5184,12 +5204,15 @@ var Agent = class _Agent {
|
|
|
5184
5204
|
const o = this.options;
|
|
5185
5205
|
if (!o.model.startsWith("claude-code/")) return void 0;
|
|
5186
5206
|
const po = { steer: () => this.drainPendingSteers() };
|
|
5187
|
-
const
|
|
5207
|
+
const mode = ccModeOptions(this.modeKind, o.providerOptions?.hooks, () => this.adv?.used() ?? 0);
|
|
5208
|
+
const bridged = (t) => o.ccBridge === "all" || CC_BRIDGED.has(t.name) || mode.bridge.has(t.name);
|
|
5188
5209
|
if (o.providerOptions?.claudeCodeSession && this.activeTools.some(bridged)) {
|
|
5189
5210
|
this.ccServer ??= ccToolServer("agentx", () => this.activeTools.filter(bridged), (n, a) => this.ccExec(n, a));
|
|
5190
5211
|
po.mcpServers = { ...o.providerOptions?.mcpServers, agentx: this.ccServer };
|
|
5191
5212
|
}
|
|
5192
|
-
const denyTools = claudeCodeDisallowedTools(o.permissions);
|
|
5213
|
+
const denyTools = [...claudeCodeDisallowedTools(o.permissions), ...mode.disallow];
|
|
5214
|
+
if (mode.hooks) po.hooks = mode.hooks;
|
|
5215
|
+
if (this.modeKind && o.providerOptions?.claudeCodeSession) po.claudeCodeSession = `${o.providerOptions.claudeCodeSession}:${this.modeKind}`;
|
|
5193
5216
|
if (denyTools.length) {
|
|
5194
5217
|
const prior = o.providerOptions?.disallowedTools ?? [];
|
|
5195
5218
|
po.disallowedTools = [.../* @__PURE__ */ new Set([...prior, ...denyTools])];
|
|
@@ -5287,7 +5310,8 @@ var Agent = class _Agent {
|
|
|
5287
5310
|
const advisor = !worker && o.advisor ? advisorFor(o.model, o.advisor.model) : void 0;
|
|
5288
5311
|
this.meter = worker || advisor ? meterWorkers(o.ai, o.model) : void 0;
|
|
5289
5312
|
const ai = this.meter?.ai ?? o.ai;
|
|
5290
|
-
|
|
5313
|
+
this.modeKind = worker ? "delegate" : advisor ? "advisor" : void 0;
|
|
5314
|
+
const adv = this.adv = advisor ? makeAdvisor({ ai, advisor, request: () => this.lastTask, snapshot: o.advisor.snapshot, limit: o.advisor.limit }) : void 0;
|
|
5291
5315
|
if (o.instructionFiles !== false) {
|
|
5292
5316
|
const names = Array.isArray(o.instructionFiles) ? o.instructionFiles : void 0;
|
|
5293
5317
|
const ins = await loadInstructions(fs, names);
|
|
@@ -7389,8 +7413,8 @@ function isTranscriptComplete(text) {
|
|
|
7389
7413
|
const lastWord = words4[words4.length - 1];
|
|
7390
7414
|
if (COMPLETE_ENDINGS.has(lastWord)) return true;
|
|
7391
7415
|
if (INCOMPLETE_ENDINGS.has(lastWord)) return false;
|
|
7392
|
-
const
|
|
7393
|
-
for (const marker of CONTINUATION_MARKERS) if (
|
|
7416
|
+
const lower2 = trimmed.toLowerCase();
|
|
7417
|
+
for (const marker of CONTINUATION_MARKERS) if (lower2.endsWith(marker)) return false;
|
|
7394
7418
|
if (words4.length <= 2) return false;
|
|
7395
7419
|
return true;
|
|
7396
7420
|
}
|
|
@@ -14986,6 +15010,7 @@ function readJsonFile(path, fallback) {
|
|
|
14986
15010
|
}
|
|
14987
15011
|
|
|
14988
15012
|
// cli/core.ts
|
|
15013
|
+
init_models();
|
|
14989
15014
|
init_hostPath();
|
|
14990
15015
|
init_platform();
|
|
14991
15016
|
var DEFAULT_TOOLS = ["bash", "Read", "Edit", "Write", "Grep", "Glob", "MultiEdit", "ApplyEdits", "RepoMap", "TodoWrite"];
|
|
@@ -15182,6 +15207,14 @@ Reference files in them by their mount path (the left side).`;
|
|
|
15182
15207
|
const po = providerOptionsFor(o.model, cwd, o.mcpServers, o.hostMcpServers);
|
|
15183
15208
|
return po ? { providerOptions: o.lean && isClaudeCode ? { ...po, settingSources: [] } : po } : {};
|
|
15184
15209
|
})(),
|
|
15210
|
+
// A child on ANOTHER provider (delegate mode's anthropic planner → claude-code/* worker, or back) gets that
|
|
15211
|
+
// runtime's own options (cwd, env, MCP) — the Agent default inherits only same-provider options, so a claude-code
|
|
15212
|
+
// worker under an anthropic planner ran with none. Same provider: the Agent default (parent's, minus its resume).
|
|
15213
|
+
providerOptionsFor: (m) => {
|
|
15214
|
+
const a = agentRef.agent, po = a?.options.providerOptions;
|
|
15215
|
+
if (modelProvider(m) === modelProvider(a?.options.model ?? "")) return po ? { ...po, resume: void 0, onClaudeCodeSession: void 0 } : void 0;
|
|
15216
|
+
return providerOptionsFor(m, cwd, o.mcpServers, o.hostMcpServers);
|
|
15217
|
+
},
|
|
15185
15218
|
...(() => {
|
|
15186
15219
|
const now4 = /* @__PURE__ */ new Date();
|
|
15187
15220
|
const platformNames = { darwin: "macOS", linux: "Linux", win32: "Windows" };
|