@iinm/plain-agent 1.14.1 → 1.14.3
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 +17 -1
- package/package.json +1 -1
- package/src/agentLoop.mjs +26 -0
- package/src/config.mjs +14 -0
- package/src/main.mjs +16 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Plain Agent
|
|
2
2
|
|
|
3
3
|
[](https://github.com/iinm/plain-agent/actions/workflows/github-code-scanning/codeql)
|
|
4
|
-
[](https://socket.dev/npm/package/@iinm/plain-agent)
|
|
5
5
|
[](https://packagephobia.com/result?p=@iinm/plain-agent)
|
|
6
6
|
|
|
7
7
|
A lightweight terminal-based coding agent focused on safety and low token cost
|
|
@@ -455,6 +455,14 @@ Create a configuration file.
|
|
|
455
455
|
"cache_read_input_tokens": 0.11,
|
|
456
456
|
"cache_creation_input_tokens": 1.375
|
|
457
457
|
}
|
|
458
|
+
},
|
|
459
|
+
// Required for soft limit (auto-compact) to work
|
|
460
|
+
"autoCompact": {
|
|
461
|
+
"inputTokensKeys": [
|
|
462
|
+
"input_tokens",
|
|
463
|
+
"cache_read_input_tokens",
|
|
464
|
+
"cache_creation_input_tokens"
|
|
465
|
+
]
|
|
458
466
|
}
|
|
459
467
|
},
|
|
460
468
|
{
|
|
@@ -482,6 +490,14 @@ Create a configuration file.
|
|
|
482
490
|
"cache_read_input_tokens": 0.33,
|
|
483
491
|
"cache_creation_input_tokens": 4.125
|
|
484
492
|
}
|
|
493
|
+
},
|
|
494
|
+
// Required for soft limit (auto-compact) to work
|
|
495
|
+
"autoCompact": {
|
|
496
|
+
"inputTokensKeys": [
|
|
497
|
+
"input_tokens",
|
|
498
|
+
"cache_read_input_tokens",
|
|
499
|
+
"cache_creation_input_tokens"
|
|
500
|
+
]
|
|
485
501
|
}
|
|
486
502
|
}
|
|
487
503
|
]
|
package/package.json
CHANGED
package/src/agentLoop.mjs
CHANGED
|
@@ -109,6 +109,7 @@ export function createAgentLoop({
|
|
|
109
109
|
let thinkingLoops = 0;
|
|
110
110
|
const maxThinkingLoops = 5;
|
|
111
111
|
let turnsAfterCompactPrompt = -1;
|
|
112
|
+
let turnsSinceSubagentReminder = 0;
|
|
112
113
|
while (true) {
|
|
113
114
|
// Check if auto-approve was paused by Ctrl-C during tool execution
|
|
114
115
|
if (pauseSignal.isPaused()) {
|
|
@@ -262,6 +263,9 @@ export function createAgentLoop({
|
|
|
262
263
|
stateManager.appendMessages([{ role: "user", content: toolResults }]);
|
|
263
264
|
}
|
|
264
265
|
|
|
266
|
+
// Subagent reminder: every 5 turns, remind the model of its subagent role
|
|
267
|
+
let autoCompactFired = false;
|
|
268
|
+
|
|
265
269
|
// Auto-compact: insert prompt if context exceeds soft limit
|
|
266
270
|
if (contextSoftLimit && inputTokensKeys && providerTokenUsage) {
|
|
267
271
|
const inputTokens = extractInputTokenCount(
|
|
@@ -286,6 +290,7 @@ export function createAgentLoop({
|
|
|
286
290
|
},
|
|
287
291
|
]);
|
|
288
292
|
turnsAfterCompactPrompt = 0;
|
|
293
|
+
autoCompactFired = true;
|
|
289
294
|
console.error(
|
|
290
295
|
styleText(
|
|
291
296
|
"yellow",
|
|
@@ -295,6 +300,27 @@ export function createAgentLoop({
|
|
|
295
300
|
}
|
|
296
301
|
}
|
|
297
302
|
}
|
|
303
|
+
|
|
304
|
+
if (!subagentManager.isSubagentActive()) {
|
|
305
|
+
turnsSinceSubagentReminder = 0;
|
|
306
|
+
} else if (!autoCompactFired) {
|
|
307
|
+
turnsSinceSubagentReminder += 1;
|
|
308
|
+
// Inject reminder every 5 turns (fires when counter reaches 5, 10, 15, ...)
|
|
309
|
+
if (turnsSinceSubagentReminder % 5 === 0) {
|
|
310
|
+
const activeSubagent = subagentManager.getActiveSubagent();
|
|
311
|
+
stateManager.appendMessages([
|
|
312
|
+
{
|
|
313
|
+
role: "user",
|
|
314
|
+
content: [
|
|
315
|
+
{
|
|
316
|
+
type: "text",
|
|
317
|
+
text: `System: You are subagent "${activeSubagent?.name}". Call "switch_to_main_agent" when your goal is done.`,
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
]);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
298
324
|
}
|
|
299
325
|
}
|
|
300
326
|
|
package/src/config.mjs
CHANGED
|
@@ -234,6 +234,20 @@ async function trustConfigHash(hash) {
|
|
|
234
234
|
await fs.writeFile(path.join(TRUSTED_CONFIG_HASHES_DIR, hash), "");
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Check whether auto-compact is effectively disabled because the model
|
|
239
|
+
* definition lacks `autoCompact.inputTokensKeys`.
|
|
240
|
+
*
|
|
241
|
+
* @param {number | undefined} contextSoftLimit
|
|
242
|
+
* @param {string[] | undefined} inputTokensKeys
|
|
243
|
+
* @returns {boolean}
|
|
244
|
+
*/
|
|
245
|
+
export function isAutoCompactMisconfigured(contextSoftLimit, inputTokensKeys) {
|
|
246
|
+
return Boolean(
|
|
247
|
+
contextSoftLimit && (!inputTokensKeys || inputTokensKeys.length === 0),
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
237
251
|
/**
|
|
238
252
|
* Resolve the effective context soft limit for the given model.
|
|
239
253
|
*
|
package/src/main.mjs
CHANGED
|
@@ -16,7 +16,11 @@ import { startBatchSession } from "./cli/batch.mjs";
|
|
|
16
16
|
import { runCostCommand } from "./cli/cost.mjs";
|
|
17
17
|
import { startInteractiveSession } from "./cli/interactive.mjs";
|
|
18
18
|
import { runTestApprovalCommand } from "./cli/testApproval.mjs";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
isAutoCompactMisconfigured,
|
|
21
|
+
loadAppConfig,
|
|
22
|
+
resolveContextSoftLimit,
|
|
23
|
+
} from "./config.mjs";
|
|
20
24
|
import { loadAgentRoles } from "./context/loadAgentRoles.mjs";
|
|
21
25
|
import { loadPrompts } from "./context/loadPrompts.mjs";
|
|
22
26
|
import { AGENT_PROJECT_METADATA_DIR, USER_NAME } from "./env.mjs";
|
|
@@ -434,6 +438,16 @@ export async function main(argv = process.argv) {
|
|
|
434
438
|
modelNameWithVariant,
|
|
435
439
|
);
|
|
436
440
|
|
|
441
|
+
const inputTokensKeys = modelDef.autoCompact?.inputTokensKeys;
|
|
442
|
+
if (isAutoCompactMisconfigured(contextSoftLimit, inputTokensKeys)) {
|
|
443
|
+
console.error(
|
|
444
|
+
styleText(
|
|
445
|
+
"yellow",
|
|
446
|
+
`⚠️ autoCompact.softLimit is set but model "${modelNameWithVariant}" has no autoCompact.inputTokensKeys.`,
|
|
447
|
+
),
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
437
451
|
const { userEventEmitter, agentEventEmitter, agentCommands } = createAgent({
|
|
438
452
|
callModel: agentCallModel,
|
|
439
453
|
prompt,
|
|
@@ -449,7 +463,7 @@ export async function main(argv = process.argv) {
|
|
|
449
463
|
},
|
|
450
464
|
initialState: resumedState,
|
|
451
465
|
contextSoftLimit,
|
|
452
|
-
inputTokensKeys
|
|
466
|
+
inputTokensKeys,
|
|
453
467
|
});
|
|
454
468
|
|
|
455
469
|
const sessionOptions = {
|