@livx.cc/agentx 0.99.30 → 0.99.32
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/dist/{Agent-DC7FEEjF.d.ts → Agent-USp7SIao.d.ts} +4 -3
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +29 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +27 -12
- package/dist/index.js.map +1 -1
- package/dist/{mcp-Cnq0pS95.d.ts → mcp-Bd19NiCL.d.ts} +1 -1
- package/dist/mcp.client.d.ts +2 -2
- package/dist/{tools-BZVppx-6.d.ts → tools-Byyh_bae.d.ts} +4 -3
- package/dist/tools.shell.d.ts +4 -1
- package/dist/tools.shell.js +7 -4
- package/dist/tools.shell.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
2
|
-
import { M as Message, H as HostBridge, A as AgentTool, C as ChatLike, g as MessageContent, U as UserQuestion } from './tools-
|
|
2
|
+
import { M as Message, H as HostBridge, A as AgentTool, C as ChatLike, g as MessageContent, U as UserQuestion } from './tools-Byyh_bae.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Hooks — deterministic interception points around tool execution, run by the
|
|
@@ -325,8 +325,9 @@ declare class AgentOptions {
|
|
|
325
325
|
traceDir?: string;
|
|
326
326
|
/** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */
|
|
327
327
|
stream: boolean;
|
|
328
|
-
/** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn
|
|
329
|
-
* no assistant text after
|
|
328
|
+
/** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn runs tools but never
|
|
329
|
+
* closes — no assistant text after the last tool, or text that trails off on an action it announced
|
|
330
|
+
* and never took ("Also checking for X.") — nudge ONE more step to ANSWER the user
|
|
330
331
|
* from the tool results already in the transcript — so the turn delivers a reply instead of trailing off
|
|
331
332
|
* mid-narration. Deliberately not a "summarize what you did" nudge: that produced process reports and
|
|
332
333
|
* permission-asking instead of answers (see the nudge text in runLoop).
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { H as Hooks, i as RunResult, R as ReasoningEffort, A as Agent } from './Agent-
|
|
2
|
+
import { H as Hooks, i as RunResult, R as ReasoningEffort, A as Agent } from './Agent-USp7SIao.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
|
-
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, g as MessageContent } from './tools-
|
|
4
|
+
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, g as MessageContent } from './tools-Byyh_bae.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
|
@@ -258,7 +258,13 @@ function stripContent(content, stub) {
|
|
|
258
258
|
});
|
|
259
259
|
return changed ? out : content;
|
|
260
260
|
}
|
|
261
|
-
|
|
261
|
+
function endsOnAnnouncedAction(text) {
|
|
262
|
+
const sentences = text.split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter(Boolean);
|
|
263
|
+
const last = sentences[sentences.length - 1];
|
|
264
|
+
if (!last || NEXT_STEP.test(last)) return false;
|
|
265
|
+
return ANNOUNCED_ACTION.test(last);
|
|
266
|
+
}
|
|
267
|
+
var log2, p_sep, IMAGE_ELIDE_STUB, IMAGE_REF_SCHEME, REF_REGISTRY_MAX, refRegistry, isImageRefUrl, bearsImage, ANNOUNCED_ACTION, NEXT_STEP;
|
|
262
268
|
var init_llm = __esm({
|
|
263
269
|
"src/llm.ts"() {
|
|
264
270
|
"use strict";
|
|
@@ -271,6 +277,8 @@ var init_llm = __esm({
|
|
|
271
277
|
refRegistry = /* @__PURE__ */ new Map();
|
|
272
278
|
isImageRefUrl = (url) => !!url && url.startsWith(IMAGE_REF_SCHEME);
|
|
273
279
|
bearsImage = (m) => messageHasImage(m.content) || toolImageRef(m.content) != null;
|
|
280
|
+
ANNOUNCED_ACTION = /^(?:also\s+|now\s+|then\s+)*(?:let me\b|i'?ll\b|i will\b|i'?m going to\b|(?:re-?)?(?:check|search|scan|read|verify|run|inspect|expand|look|examin|continu|proceed|try|fetch|load|open|test|build|grep|find|review|trac|dig|explor)\w*ing\b)/i;
|
|
281
|
+
NEXT_STEP = /^next (?:step|run|up)\b/i;
|
|
274
282
|
}
|
|
275
283
|
});
|
|
276
284
|
|
|
@@ -2033,20 +2041,23 @@ async function nodeSpawn() {
|
|
|
2033
2041
|
return _spawn;
|
|
2034
2042
|
}
|
|
2035
2043
|
function makeRealShellTool(options) {
|
|
2036
|
-
const
|
|
2044
|
+
const defaultTimeoutMs = options.timeoutMs ?? 12e4;
|
|
2045
|
+
const maxTimeoutMs = Math.max(options.maxTimeoutMs ?? 6e5, defaultTimeoutMs);
|
|
2037
2046
|
return {
|
|
2038
2047
|
name: "Shell",
|
|
2039
|
-
description:
|
|
2048
|
+
description: `Run a shell command via /bin/sh in the working directory. Executes any installed binary \u2014 ls, cat, grep, git, bun, node, curl, scripts, etc. Returns combined stdout+stderr; non-zero exits are prefixed \`[exit N]\`. Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input fail fast rather than hang \u2014 for privileged actions use a non-interactive flag (e.g. \`sudo -n\`), or ask the user to run the command themselves. Each command is killed after ${defaultTimeoutMs}ms (result \`[exit 124]\` with whatever output it produced) \u2014 pass \`timeoutMs\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \`curl -m 10\`). Set \`background:true\` for long-running processes (servers, watchers) \u2014 returns a job id immediately; poll with ShellOutput, stop with ShellKill.`,
|
|
2040
2049
|
parameters: {
|
|
2041
2050
|
type: "object",
|
|
2042
2051
|
required: ["command"],
|
|
2043
2052
|
properties: {
|
|
2044
2053
|
command: { type: "string", description: "the shell command line to execute" },
|
|
2045
|
-
background: { type: "boolean", description: "run detached and return a job id immediately (for servers/watchers/long builds)" }
|
|
2054
|
+
background: { type: "boolean", description: "run detached and return a job id immediately (for servers/watchers/long builds)" },
|
|
2055
|
+
timeoutMs: { type: "number", description: "wall-clock cap for THIS command, overriding the default (clamped to the tool max)" }
|
|
2046
2056
|
}
|
|
2047
2057
|
},
|
|
2048
|
-
async run({ command, background }, ctx) {
|
|
2058
|
+
async run({ command, background, timeoutMs: askedTimeoutMs }, ctx) {
|
|
2049
2059
|
const cmd = String(command ?? "");
|
|
2060
|
+
const timeoutMs = Number.isFinite(askedTimeoutMs) && Number(askedTimeoutMs) > 0 ? Math.min(Number(askedTimeoutMs), maxTimeoutMs) : defaultTimeoutMs;
|
|
2050
2061
|
if (!cmd.trim()) return "[exit 1] empty command";
|
|
2051
2062
|
if (background) {
|
|
2052
2063
|
if (!options.registry) return "Error: background execution is not enabled in this host (no job registry).";
|
|
@@ -3614,8 +3625,9 @@ var AgentOptions = class {
|
|
|
3614
3625
|
traceDir;
|
|
3615
3626
|
/** Stream tokens from the model. Takes effect only with a `host.notify`; off => current (non-stream) behavior. */
|
|
3616
3627
|
stream = false;
|
|
3617
|
-
/** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn
|
|
3618
|
-
* no assistant text after
|
|
3628
|
+
/** Closure reflex for delegated runtimes (cursor/claude-code): when such a turn runs tools but never
|
|
3629
|
+
* closes — no assistant text after the last tool, or text that trails off on an action it announced
|
|
3630
|
+
* and never took ("Also checking for X.") — nudge ONE more step to ANSWER the user
|
|
3619
3631
|
* from the tool results already in the transcript — so the turn delivers a reply instead of trailing off
|
|
3620
3632
|
* mid-narration. Deliberately not a "summarize what you did" nudge: that produced process reports and
|
|
3621
3633
|
* permission-asking instead of answers (see the nudge text in runLoop).
|
|
@@ -4118,7 +4130,7 @@ var Agent = class _Agent {
|
|
|
4118
4130
|
}
|
|
4119
4131
|
if (toolCalls.length === 0) {
|
|
4120
4132
|
if (this.drainInjections()) continue;
|
|
4121
|
-
if (o.closeDelegatedTurns && res.
|
|
4133
|
+
if (o.closeDelegatedTurns && res.endedWithoutClosing && !closureNudged && steps < o.maxSteps) {
|
|
4122
4134
|
closureNudged = true;
|
|
4123
4135
|
log6.verbose("delegated turn went silent after a tool \u2014 nudging a closing answer");
|
|
4124
4136
|
this.transcript.push({
|
|
@@ -4225,7 +4237,8 @@ var Agent = class _Agent {
|
|
|
4225
4237
|
let usage;
|
|
4226
4238
|
const delegated = /* @__PURE__ */ new Map();
|
|
4227
4239
|
const delegatedOrder = [];
|
|
4228
|
-
let
|
|
4240
|
+
let sawTool = false;
|
|
4241
|
+
let trailing = "";
|
|
4229
4242
|
for await (const chunk of stream) {
|
|
4230
4243
|
poke?.();
|
|
4231
4244
|
if (this.options.signal?.aborted) break;
|
|
@@ -4245,11 +4258,12 @@ var Agent = class _Agent {
|
|
|
4245
4258
|
if (a.output !== void 0) prev.output = a.output;
|
|
4246
4259
|
prev.status = a.status;
|
|
4247
4260
|
}
|
|
4248
|
-
|
|
4261
|
+
sawTool = true;
|
|
4262
|
+
trailing = "";
|
|
4249
4263
|
}
|
|
4250
4264
|
if (chunk.content) {
|
|
4251
4265
|
content += chunk.content;
|
|
4252
|
-
|
|
4266
|
+
trailing += chunk.content;
|
|
4253
4267
|
this.options.host.notify({ kind: "text_delta", message: chunk.content });
|
|
4254
4268
|
}
|
|
4255
4269
|
if (chunk.finishReason) finishReason = chunk.finishReason;
|
|
@@ -4257,7 +4271,8 @@ var Agent = class _Agent {
|
|
|
4257
4271
|
if (chunk.usage) usage = chunk.usage;
|
|
4258
4272
|
}
|
|
4259
4273
|
const delegatedTools = delegatedOrder.map((k) => delegated.get(k));
|
|
4260
|
-
|
|
4274
|
+
const endedWithoutClosing = sawTool && (!trailing.trim() || endsOnAnnouncedAction(trailing));
|
|
4275
|
+
return { content, ...finishReason ? { finishReason } : {}, ...toolCalls ? { toolCalls } : {}, ...usage ? { usage } : {}, ...delegatedTools.length ? { delegatedTools } : {}, ...endedWithoutClosing ? { endedWithoutClosing: true } : {} };
|
|
4261
4276
|
}
|
|
4262
4277
|
async dispatch(tc) {
|
|
4263
4278
|
const tool = this.activeTools.find((t) => t.name === tc.function.name);
|
|
@@ -9038,7 +9053,8 @@ The filesystem root '/' is the real machine root \u2014 you have full filesystem
|
|
|
9038
9053
|
const list = [...names];
|
|
9039
9054
|
return `You are agentx (an agent runtime) \u2014 NOT Claude Code or Claude Desktop, which are separate agents with their own config. Your MCP servers are configured in .agent/settings.json or .agent/config.* (this project's .agent/ or ~/.agent/), and their tools are already in your tool list as \`mcp__<server>__<tool>\`.${list.length ? ` Configured MCP servers: ${list.join(", ")}.` : " No MCP servers are currently configured."} When asked which MCPs/tools you have, answer from your own tool list \u2014 never read Claude Code/Desktop config (e.g. ~/.claude.json, claude_desktop_config.json) to answer; those belong to a different agent.`;
|
|
9040
9055
|
})();
|
|
9041
|
-
const
|
|
9056
|
+
const closureNote = isDelegated ? "Never end your turn on an action you only announced. If you say you are about to search, read, check or run something, DO it in the same turn before you stop. Your last message must be the ANSWER \u2014 the result and what it means \u2014 or an explicit statement that you are blocked and why. Narration of what you are about to do is not an ending." : "";
|
|
9057
|
+
const extra = [o.appendSystemPrompt, envNote, cwdNote, shellNote, toneNote, mountNote, mcpNote, closureNote].filter(Boolean).join("\n\n");
|
|
9042
9058
|
const basePrompt = (() => {
|
|
9043
9059
|
let p = new AgentOptions().systemPrompt;
|
|
9044
9060
|
if (!virtual) p = p.replace("operating on a virtual filesystem", "operating on the host filesystem");
|