@iinm/plain-agent 1.10.11 → 1.10.13
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/sandbox/bin/plain-sandbox +2 -1
- package/src/agent.d.ts +1 -1
- package/src/agentLoop.mjs +1 -4
- package/src/cli/formatter.mjs +16 -18
- package/src/cli/interactive.mjs +5 -5
- package/src/tools/compactContext.mjs +1 -1
- package/src/tools/execCommand.mjs +29 -7
- package/src/tools/tmuxCommand.mjs +1 -1
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}")
|
|
|
7
7
|
|
|
8
8
|
MOUNTABLE_SCRIPT_PATH="$HOME/.cache/$SCRIPT_NAME/$SCRIPT_NAME"
|
|
9
9
|
CONTAINER_SCRIPT_PATH="/sandbox/bin/$SCRIPT_NAME"
|
|
10
|
+
PRESET_BASE_IMAGE="public.ecr.aws/docker/library/debian:stable-20260505-slim"
|
|
10
11
|
|
|
11
12
|
help() {
|
|
12
13
|
cat << HELP
|
|
@@ -851,8 +852,8 @@ setup_container_user() {
|
|
|
851
852
|
}
|
|
852
853
|
|
|
853
854
|
print_preset_dockerfile() {
|
|
855
|
+
echo "FROM $PRESET_BASE_IMAGE"
|
|
854
856
|
cat << 'EOF'
|
|
855
|
-
FROM public.ecr.aws/docker/library/debian:stable-slim
|
|
856
857
|
|
|
857
858
|
RUN apt update \
|
|
858
859
|
&& apt install -y \
|
package/src/agent.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ type AgentEventMap = {
|
|
|
37
37
|
message: [Message];
|
|
38
38
|
partialMessageContent: [PartialMessageContent];
|
|
39
39
|
error: [Error];
|
|
40
|
-
toolUseRequest: [];
|
|
40
|
+
toolUseRequest: [number];
|
|
41
41
|
turnEnd: [];
|
|
42
42
|
providerTokenUsage: [ProviderTokenUsage];
|
|
43
43
|
subagentSwitched: [{ name: string } | null];
|
package/src/agentLoop.mjs
CHANGED
|
@@ -172,9 +172,6 @@ export function createAgentLoop({
|
|
|
172
172
|
content: validation.toolResults,
|
|
173
173
|
},
|
|
174
174
|
]);
|
|
175
|
-
if (validation.errorMessage) {
|
|
176
|
-
console.error(styleText("yellow", validation.errorMessage));
|
|
177
|
-
}
|
|
178
175
|
continue;
|
|
179
176
|
}
|
|
180
177
|
|
|
@@ -205,7 +202,7 @@ export function createAgentLoop({
|
|
|
205
202
|
|
|
206
203
|
const isAllToolUseApproved = decisions.every((d) => d.action === "allow");
|
|
207
204
|
if (!isAllToolUseApproved) {
|
|
208
|
-
agentEventEmitter.emit("toolUseRequest");
|
|
205
|
+
agentEventEmitter.emit("toolUseRequest", toolUseParts.length);
|
|
209
206
|
break;
|
|
210
207
|
}
|
|
211
208
|
|
package/src/cli/formatter.mjs
CHANGED
|
@@ -70,7 +70,7 @@ export async function formatToolUse(toolUse) {
|
|
|
70
70
|
/** @type {Partial<ExecCommandInput>} */
|
|
71
71
|
const execCommandInput = input;
|
|
72
72
|
return [
|
|
73
|
-
|
|
73
|
+
`${toolName}`,
|
|
74
74
|
`command: ${JSON.stringify(execCommandInput.command)}`,
|
|
75
75
|
formatArgs(execCommandInput.args),
|
|
76
76
|
].join("\n");
|
|
@@ -80,7 +80,7 @@ export async function formatToolUse(toolUse) {
|
|
|
80
80
|
/** @type {Partial<WriteFileInput>} */
|
|
81
81
|
const writeFileInput = input;
|
|
82
82
|
return [
|
|
83
|
-
|
|
83
|
+
`${toolName}`,
|
|
84
84
|
`filePath: ${writeFileInput.filePath}`,
|
|
85
85
|
`content:\n${writeFileInput.content}`,
|
|
86
86
|
].join("\n");
|
|
@@ -92,18 +92,16 @@ export async function formatToolUse(toolUse) {
|
|
|
92
92
|
const filePath = patchFileInput.filePath ?? "";
|
|
93
93
|
const patch = patchFileInput.patch || "";
|
|
94
94
|
const rendered = await renderPatch(filePath, patch);
|
|
95
|
-
return [
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`patch:\n${rendered}`,
|
|
99
|
-
].join("\n");
|
|
95
|
+
return [`${toolName}`, `path: ${filePath}`, `patch:\n${rendered}`].join(
|
|
96
|
+
"\n",
|
|
97
|
+
);
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
if (toolName === "read_file") {
|
|
103
101
|
/** @type {Partial<ReadFileInput>} */
|
|
104
102
|
const readFileInput = input;
|
|
105
103
|
/** @type {string[]} */
|
|
106
|
-
const lines = [
|
|
104
|
+
const lines = [`${toolName}`, `filePath: ${readFileInput.filePath}`];
|
|
107
105
|
if (readFileInput.offset !== undefined) {
|
|
108
106
|
lines.push(`offset: ${readFileInput.offset}`);
|
|
109
107
|
}
|
|
@@ -117,7 +115,7 @@ export async function formatToolUse(toolUse) {
|
|
|
117
115
|
/** @type {Partial<TmuxCommandInput>} */
|
|
118
116
|
const tmuxCommandInput = input;
|
|
119
117
|
return [
|
|
120
|
-
|
|
118
|
+
`${toolName}`,
|
|
121
119
|
`command: ${tmuxCommandInput.command}`,
|
|
122
120
|
formatArgs(tmuxCommandInput.args),
|
|
123
121
|
].join("\n");
|
|
@@ -127,7 +125,7 @@ export async function formatToolUse(toolUse) {
|
|
|
127
125
|
/** @type {Partial<SwitchToSubagentInput>} */
|
|
128
126
|
const switchToSubagentInput = input;
|
|
129
127
|
return [
|
|
130
|
-
|
|
128
|
+
`${toolName}`,
|
|
131
129
|
`name: ${switchToSubagentInput.name}`,
|
|
132
130
|
`goal: ${switchToSubagentInput.goal}`,
|
|
133
131
|
].join("\n");
|
|
@@ -137,7 +135,7 @@ export async function formatToolUse(toolUse) {
|
|
|
137
135
|
/** @type {Partial<CompactContextInput>} */
|
|
138
136
|
const compactContextInput = input;
|
|
139
137
|
return [
|
|
140
|
-
|
|
138
|
+
`${toolName}`,
|
|
141
139
|
`memoryPath: ${compactContextInput.memoryPath}`,
|
|
142
140
|
`reason: ${compactContextInput.reason}`,
|
|
143
141
|
].join("\n");
|
|
@@ -147,7 +145,7 @@ export async function formatToolUse(toolUse) {
|
|
|
147
145
|
/** @type {Partial<import("../tools/switchToMainAgent").SwitchToMainAgentInput>} */
|
|
148
146
|
const switchToMainAgentInput = input;
|
|
149
147
|
return [
|
|
150
|
-
|
|
148
|
+
`${toolName}`,
|
|
151
149
|
`memoryPath: ${switchToMainAgentInput.memoryPath}`,
|
|
152
150
|
].join("\n");
|
|
153
151
|
}
|
|
@@ -159,7 +157,7 @@ export async function formatToolUse(toolUse) {
|
|
|
159
157
|
? webSearchInput.searches.map((s) => s.keywords.join(" ")).join(" | ")
|
|
160
158
|
: "";
|
|
161
159
|
return [
|
|
162
|
-
|
|
160
|
+
`${toolName}`,
|
|
163
161
|
`searches: ${searchesLine}`,
|
|
164
162
|
`question: ${webSearchInput.question}`,
|
|
165
163
|
].join("\n");
|
|
@@ -169,7 +167,7 @@ export async function formatToolUse(toolUse) {
|
|
|
169
167
|
/** @type {Partial<import("../tools/webFetch.mjs").WebFetchInput>} */
|
|
170
168
|
const webFetchInput = input;
|
|
171
169
|
return [
|
|
172
|
-
|
|
170
|
+
`${toolName}`,
|
|
173
171
|
`url: ${webFetchInput.url}`,
|
|
174
172
|
`question: ${webFetchInput.question}`,
|
|
175
173
|
].join("\n");
|
|
@@ -212,7 +210,7 @@ export function formatToolResult(toolResult) {
|
|
|
212
210
|
const contentString = contentStringParts.join("\n\n");
|
|
213
211
|
|
|
214
212
|
if (isError) {
|
|
215
|
-
return styleText("
|
|
213
|
+
return styleText("magenta", contentString);
|
|
216
214
|
}
|
|
217
215
|
|
|
218
216
|
if (toolResult.toolName === "exec_command") {
|
|
@@ -223,7 +221,7 @@ export function formatToolResult(toolResult) {
|
|
|
223
221
|
styleText("yellow", "$1"),
|
|
224
222
|
)
|
|
225
223
|
.replace(/(^<stderr>|<\/stderr>$)/gm, styleText("magenta", "$1"))
|
|
226
|
-
.replace(/(^<error
|
|
224
|
+
.replace(/(^<error code=.+?>|<\/error>$)/gm, styleText("magenta", "$1"));
|
|
227
225
|
}
|
|
228
226
|
|
|
229
227
|
if (toolResult.toolName === "read_file") {
|
|
@@ -237,7 +235,7 @@ export function formatToolResult(toolResult) {
|
|
|
237
235
|
return contentString
|
|
238
236
|
.replace(/(^<stdout>|<\/stdout>$)/gm, styleText("blue", "$1"))
|
|
239
237
|
.replace(/(^<stderr>|<\/stderr>$)/gm, styleText("magenta", "$1"))
|
|
240
|
-
.replace(/(^<error>|<\/error>$)/gm, styleText("
|
|
238
|
+
.replace(/(^<error>|<\/error>$)/gm, styleText("magenta", "$1"))
|
|
241
239
|
.replace(/(^<tmux:.*?>|<\/tmux:.*?>$)/gm, styleText("green", "$1"));
|
|
242
240
|
}
|
|
243
241
|
|
|
@@ -858,7 +856,7 @@ function renderPatchBlock(block, originalLines, nonce) {
|
|
|
858
856
|
// "+ ".
|
|
859
857
|
for (const op of diffLines(oldSlice, block.body)) {
|
|
860
858
|
if (op.type === "-") {
|
|
861
|
-
out.push(styleText("
|
|
859
|
+
out.push(styleText("magenta", `- ${op.line}`));
|
|
862
860
|
} else if (op.type === "+") {
|
|
863
861
|
out.push(styleText("green", `+ ${op.line}`));
|
|
864
862
|
} else {
|
package/src/cli/interactive.mjs
CHANGED
|
@@ -501,9 +501,8 @@ export function startInteractiveSession({
|
|
|
501
501
|
}
|
|
502
502
|
if (partialContent.position === "stop") {
|
|
503
503
|
if (partialContent.type === "tool_use") {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
);
|
|
504
|
+
// Clear current line, move up one line, and clear that line too
|
|
505
|
+
process.stdout.write("\x1b[2K\x1b[1F\x1b[2K");
|
|
507
506
|
} else {
|
|
508
507
|
// Flush any buffered text before printing the closing tag
|
|
509
508
|
streamBuffer.forceFlush();
|
|
@@ -524,13 +523,14 @@ export function startInteractiveSession({
|
|
|
524
523
|
);
|
|
525
524
|
});
|
|
526
525
|
|
|
527
|
-
agentEventEmitter.on("toolUseRequest", () => {
|
|
526
|
+
agentEventEmitter.on("toolUseRequest", (toolCount) => {
|
|
527
|
+
const toolText = toolCount === 1 ? "tool call" : "tool calls";
|
|
528
528
|
cli.setPrompt(
|
|
529
529
|
getCliPrompt(
|
|
530
530
|
state.subagentName,
|
|
531
531
|
styleText(
|
|
532
532
|
"yellow",
|
|
533
|
-
|
|
533
|
+
`Approve ${toolCount} ${toolText}? (y = allow once, Y = allow in this session, or feedback)`,
|
|
534
534
|
),
|
|
535
535
|
),
|
|
536
536
|
);
|
|
@@ -140,19 +140,41 @@ export function createExecCommandTool(config) {
|
|
|
140
140
|
: "<stderr></stderr>",
|
|
141
141
|
];
|
|
142
142
|
|
|
143
|
-
if (err) {
|
|
144
|
-
// rg:
|
|
145
|
-
const ignoreError = [
|
|
143
|
+
if (!stderr && err) {
|
|
144
|
+
// rg: exit status != 0 when no matches are found.
|
|
145
|
+
const ignoreError = ["rg"].includes(input.command);
|
|
146
146
|
if (!ignoreError) {
|
|
147
|
-
//
|
|
148
|
-
const
|
|
147
|
+
// mask sandbox details
|
|
148
|
+
const originalCommand = [
|
|
149
|
+
input.command,
|
|
150
|
+
...(input.args ?? []),
|
|
151
|
+
];
|
|
152
|
+
const sandboxedCommand = [command, ...(args ?? [])];
|
|
153
|
+
const sandboxStr = [
|
|
154
|
+
...sandboxedCommand.slice(
|
|
155
|
+
0,
|
|
156
|
+
sandboxedCommand.length - originalCommand.length,
|
|
157
|
+
),
|
|
158
|
+
"",
|
|
159
|
+
].join(" ");
|
|
160
|
+
|
|
161
|
+
const errMessageMasked = sandboxStr
|
|
162
|
+
? err.message.replaceAll(sandboxStr, "")
|
|
163
|
+
: err.message;
|
|
164
|
+
|
|
165
|
+
const errMessageTruncated = errMessageMasked.slice(
|
|
149
166
|
0,
|
|
150
167
|
OUTPUT_TRUNCATED_LENGTH,
|
|
151
168
|
);
|
|
152
169
|
const isErrMessageTruncated =
|
|
153
|
-
|
|
170
|
+
errMessageMasked.length > OUTPUT_TRUNCATED_LENGTH;
|
|
171
|
+
|
|
154
172
|
result.push(
|
|
155
|
-
|
|
173
|
+
[
|
|
174
|
+
"",
|
|
175
|
+
`<error code="${err.code}" killed="${err.killed}" signal="${err.signal}">`,
|
|
176
|
+
`${err.name}: ${errMessageTruncated}${isErrMessageTruncated ? "... (Message truncated)" : ""}</error>`,
|
|
177
|
+
].join("\n"),
|
|
156
178
|
);
|
|
157
179
|
}
|
|
158
180
|
}
|
|
@@ -108,7 +108,7 @@ export function createTmuxCommandTool(config) {
|
|
|
108
108
|
? `<stderr>\n${isStderrTruncated ? "(Output truncated) ..." : ""}${stderrTruncated}\n</stderr>`
|
|
109
109
|
: "<stderr></stderr>",
|
|
110
110
|
];
|
|
111
|
-
if (err) {
|
|
111
|
+
if (!stderr && err) {
|
|
112
112
|
const errMessageTruncated = err.message.slice(
|
|
113
113
|
0,
|
|
114
114
|
OUTPUT_MAX_LENGTH,
|