@iinm/plain-agent 1.6.1 → 1.7.1
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 +16 -12
- package/{.config → config}/config.predefined.json +82 -7
- package/package.json +2 -2
- package/src/agent.d.ts +1 -0
- package/src/agent.mjs +14 -0
- package/src/agentLoop.mjs +12 -9
- package/src/cliArgs.mjs +5 -5
- package/src/cliCompleter.mjs +2 -2
- package/src/cliInteractive.mjs +14 -4
- package/src/cliPasteTransform.mjs +3 -4
- package/src/config.mjs +1 -1
- package/src/context/loadAgentRoles.mjs +1 -1
- package/src/context/loadPrompts.mjs +1 -1
- package/src/env.mjs +0 -5
- package/src/modelDefinition.d.ts +7 -0
- package/src/providers/openaiCompatible.mjs +3 -0
- package/src/subagent.mjs +7 -3
- package/bin/plain-interrupt +0 -6
- package/src/context/consumeInterruptMessage.mjs +0 -30
- /package/{.config → config}/agents.predefined/worker.md +0 -0
- /package/{.config → config}/prompts.predefined/shortcuts/commit-by-user.md +0 -0
- /package/{.config → config}/prompts.predefined/shortcuts/commit.md +0 -0
- /package/{.config → config}/prompts.predefined/shortcuts/general-question.md +0 -0
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Create the configuration.
|
|
|
66
66
|
{
|
|
67
67
|
// Requires Azure CLI to get access token
|
|
68
68
|
"name": "azure",
|
|
69
|
-
"variant": "
|
|
69
|
+
"variant": "openai",
|
|
70
70
|
"baseURL": "https://<resource>.openai.azure.com/openai",
|
|
71
71
|
// Optional
|
|
72
72
|
"azureConfigDir": "/home/xxx/.azure-for-agent"
|
|
@@ -131,21 +131,27 @@ Create the configuration.
|
|
|
131
131
|
{
|
|
132
132
|
"platforms": [
|
|
133
133
|
{
|
|
134
|
-
"name": "openai",
|
|
134
|
+
"name": "openai-compatible",
|
|
135
135
|
"variant": "ollama",
|
|
136
136
|
"baseURL": "https://ollama.com",
|
|
137
137
|
"apiKey": "FIXME"
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
|
-
"name": "openai",
|
|
140
|
+
"name": "openai-compatible",
|
|
141
141
|
"variant": "huggingface",
|
|
142
142
|
"baseURL": "https://router.huggingface.co",
|
|
143
143
|
"apiKey": "FIXME"
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
|
-
"name": "openai",
|
|
146
|
+
"name": "openai-compatible",
|
|
147
147
|
"variant": "xai",
|
|
148
148
|
"apiKey": "FIXME"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "openai-compatible",
|
|
152
|
+
"variant": "fireworks",
|
|
153
|
+
"baseURL": "https://api.fireworks.ai/inference",
|
|
154
|
+
"apiKey": "FIXME"
|
|
149
155
|
}
|
|
150
156
|
]
|
|
151
157
|
}
|
|
@@ -238,9 +244,10 @@ Run in batch mode (non-interactive).
|
|
|
238
244
|
In batch mode, config files are not loaded automatically. Only the files specified with `--config` are loaded.
|
|
239
245
|
|
|
240
246
|
```sh
|
|
241
|
-
plain batch
|
|
242
|
-
|
|
243
|
-
|
|
247
|
+
plain batch \
|
|
248
|
+
-c ~/.config/plain-agent/config.local.json \
|
|
249
|
+
-c .plain-agent/config.json \
|
|
250
|
+
"Add tests for ..."
|
|
244
251
|
```
|
|
245
252
|
|
|
246
253
|
Display the help message.
|
|
@@ -249,11 +256,9 @@ Display the help message.
|
|
|
249
256
|
/help
|
|
250
257
|
```
|
|
251
258
|
|
|
252
|
-
Interrupt the agent while it's running
|
|
259
|
+
Interrupt the agent while it's running:
|
|
253
260
|
|
|
254
|
-
|
|
255
|
-
plain-interrupt Stop and report the progress
|
|
256
|
-
```
|
|
261
|
+
Press **Ctrl-C** to pause auto-approve. The agent will finish the current tool call, then return to the prompt.
|
|
257
262
|
|
|
258
263
|
## Available Tools
|
|
259
264
|
|
|
@@ -281,7 +286,6 @@ The agent can use the following tools to assist with tasks:
|
|
|
281
286
|
\__ .plain-agent/
|
|
282
287
|
\__ config.json # Project-specific configuration
|
|
283
288
|
\__ config.local.json # Project-specific local configuration (including secrets)
|
|
284
|
-
\__ interrupt-message.txt # Interrupt message consumed by the agent
|
|
285
289
|
\__ memory/ # Task-specific memory files
|
|
286
290
|
\__ prompts/ # Project-specific prompts
|
|
287
291
|
\__ agents/ # Project-specific agent roles
|
|
@@ -891,7 +891,7 @@
|
|
|
891
891
|
"variant": "thinking-medium-azure",
|
|
892
892
|
"platform": {
|
|
893
893
|
"name": "azure",
|
|
894
|
-
"variant": "
|
|
894
|
+
"variant": "openai"
|
|
895
895
|
},
|
|
896
896
|
"model": {
|
|
897
897
|
"format": "openai-responses",
|
|
@@ -972,10 +972,33 @@
|
|
|
972
972
|
}
|
|
973
973
|
},
|
|
974
974
|
{
|
|
975
|
-
"name": "glm-5",
|
|
975
|
+
"name": "glm-5.1",
|
|
976
|
+
"variant": "fireworks",
|
|
977
|
+
"platform": {
|
|
978
|
+
"name": "openai-compatible",
|
|
979
|
+
"variant": "fireworks"
|
|
980
|
+
},
|
|
981
|
+
"model": {
|
|
982
|
+
"format": "openai-messages",
|
|
983
|
+
"config": {
|
|
984
|
+
"model": "accounts/fireworks/models/glm-5p1"
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
"cost": {
|
|
988
|
+
"currency": "USD",
|
|
989
|
+
"unit": "1M",
|
|
990
|
+
"costs": {
|
|
991
|
+
"prompt_tokens": 1.4,
|
|
992
|
+
"prompt_tokens_details.cached_tokens": -1.14,
|
|
993
|
+
"completion_tokens": 4.4
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
"name": "glm-5.1",
|
|
976
999
|
"variant": "ollama",
|
|
977
1000
|
"platform": {
|
|
978
|
-
"name": "openai",
|
|
1001
|
+
"name": "openai-compatible",
|
|
979
1002
|
"variant": "ollama"
|
|
980
1003
|
},
|
|
981
1004
|
"model": {
|
|
@@ -986,16 +1009,16 @@
|
|
|
986
1009
|
}
|
|
987
1010
|
},
|
|
988
1011
|
{
|
|
989
|
-
"name": "glm-5",
|
|
1012
|
+
"name": "glm-5.1",
|
|
990
1013
|
"variant": "huggingface",
|
|
991
1014
|
"platform": {
|
|
992
|
-
"name": "openai",
|
|
1015
|
+
"name": "openai-compatible",
|
|
993
1016
|
"variant": "huggingface"
|
|
994
1017
|
},
|
|
995
1018
|
"model": {
|
|
996
1019
|
"format": "openai-messages",
|
|
997
1020
|
"config": {
|
|
998
|
-
"model": "zai-org/GLM-5:
|
|
1021
|
+
"model": "zai-org/GLM-5.1:together"
|
|
999
1022
|
}
|
|
1000
1023
|
}
|
|
1001
1024
|
},
|
|
@@ -1066,7 +1089,7 @@
|
|
|
1066
1089
|
"name": "minimax-m2.7",
|
|
1067
1090
|
"variant": "ollama",
|
|
1068
1091
|
"platform": {
|
|
1069
|
-
"name": "openai",
|
|
1092
|
+
"name": "openai-compatible",
|
|
1070
1093
|
"variant": "ollama"
|
|
1071
1094
|
},
|
|
1072
1095
|
"model": {
|
|
@@ -1091,6 +1114,58 @@
|
|
|
1091
1114
|
}
|
|
1092
1115
|
}
|
|
1093
1116
|
},
|
|
1117
|
+
{
|
|
1118
|
+
"name": "qwen3.6-plus",
|
|
1119
|
+
"variant": "fireworks",
|
|
1120
|
+
"platform": {
|
|
1121
|
+
"name": "openai-compatible",
|
|
1122
|
+
"variant": "fireworks"
|
|
1123
|
+
},
|
|
1124
|
+
"model": {
|
|
1125
|
+
"format": "openai-messages",
|
|
1126
|
+
"config": {
|
|
1127
|
+
"model": "accounts/fireworks/models/qwen3p6-plus"
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
"cost": {
|
|
1131
|
+
"currency": "USD",
|
|
1132
|
+
"unit": "1M",
|
|
1133
|
+
"costs": {
|
|
1134
|
+
"prompt_tokens": 0.5,
|
|
1135
|
+
"prompt_tokens_details.cached_tokens": -0.4,
|
|
1136
|
+
"completion_tokens": 3
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
},
|
|
1140
|
+
|
|
1141
|
+
{
|
|
1142
|
+
"name": "gemma4",
|
|
1143
|
+
"variant": "ollama",
|
|
1144
|
+
"platform": {
|
|
1145
|
+
"name": "openai-compatible",
|
|
1146
|
+
"variant": "ollama"
|
|
1147
|
+
},
|
|
1148
|
+
"model": {
|
|
1149
|
+
"format": "openai-responses",
|
|
1150
|
+
"config": {
|
|
1151
|
+
"model": "gemma4:31b-cloud"
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
1155
|
+
{
|
|
1156
|
+
"name": "gemma4",
|
|
1157
|
+
"variant": "huggingface",
|
|
1158
|
+
"platform": {
|
|
1159
|
+
"name": "openai-compatible",
|
|
1160
|
+
"variant": "huggingface"
|
|
1161
|
+
},
|
|
1162
|
+
"model": {
|
|
1163
|
+
"format": "openai-messages",
|
|
1164
|
+
"config": {
|
|
1165
|
+
"model": "google/gemma-4-31B-it:together"
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
},
|
|
1094
1169
|
|
|
1095
1170
|
{
|
|
1096
1171
|
"name": "nova-2-lite",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iinm/plain-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "A lightweight CLI-based coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"bin",
|
|
20
20
|
"sandbox/bin",
|
|
21
|
-
"
|
|
21
|
+
"config",
|
|
22
22
|
"src/**/*.mjs",
|
|
23
23
|
"src/**/*.d.ts",
|
|
24
24
|
"!src/**/*.test.mjs",
|
package/src/agent.d.ts
CHANGED
package/src/agent.mjs
CHANGED
|
@@ -144,6 +144,16 @@ export function createAgent({
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
// Pause signal: set by Ctrl-C during agent execution, checked after each tool batch completes
|
|
148
|
+
let paused = false;
|
|
149
|
+
/** @type {import("./agentLoop.mjs").PauseSignal} */
|
|
150
|
+
const pauseSignal = {
|
|
151
|
+
isPaused: () => paused,
|
|
152
|
+
reset: () => {
|
|
153
|
+
paused = false;
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
147
157
|
const agentLoop = createAgentLoop({
|
|
148
158
|
callModel,
|
|
149
159
|
stateManager,
|
|
@@ -152,6 +162,7 @@ export function createAgent({
|
|
|
152
162
|
agentEventEmitter,
|
|
153
163
|
toolUseApprover,
|
|
154
164
|
subagentManager,
|
|
165
|
+
pauseSignal,
|
|
155
166
|
});
|
|
156
167
|
|
|
157
168
|
userEventEmitter.on("userInput", agentLoop.handleUserInput);
|
|
@@ -163,6 +174,9 @@ export function createAgent({
|
|
|
163
174
|
dumpMessages,
|
|
164
175
|
loadMessages,
|
|
165
176
|
getCostSummary: () => costTracker.calculateCost(),
|
|
177
|
+
pauseAutoApprove: () => {
|
|
178
|
+
paused = true;
|
|
179
|
+
},
|
|
166
180
|
},
|
|
167
181
|
};
|
|
168
182
|
}
|
package/src/agentLoop.mjs
CHANGED
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { styleText } from "node:util";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} PauseSignal
|
|
13
|
+
* @property {() => boolean} isPaused - Returns true if auto-approve should be paused
|
|
14
|
+
* @property {() => void} reset - Resets the paused state
|
|
15
|
+
*/
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* @typedef {Object} AgentLoopConfig
|
|
@@ -18,6 +23,7 @@ import { consumeInterruptMessage } from "./context/consumeInterruptMessage.mjs";
|
|
|
18
23
|
* @property {AgentEventEmitter} agentEventEmitter - Event emitter for agent events
|
|
19
24
|
* @property {ToolUseApprover} toolUseApprover - Tool use approval checker
|
|
20
25
|
* @property {SubagentManager} subagentManager - Subagent manager instance
|
|
26
|
+
* @property {PauseSignal} pauseSignal - Signal to pause auto-approve after current tool completes
|
|
21
27
|
*/
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -36,6 +42,7 @@ export function createAgentLoop({
|
|
|
36
42
|
agentEventEmitter,
|
|
37
43
|
toolUseApprover,
|
|
38
44
|
subagentManager,
|
|
45
|
+
pauseSignal,
|
|
39
46
|
}) {
|
|
40
47
|
const inputHandler = createInputHandler({
|
|
41
48
|
stateManager,
|
|
@@ -198,14 +205,10 @@ export function createAgentLoop({
|
|
|
198
205
|
stateManager.appendMessages([{ role: "user", content: toolResults }]);
|
|
199
206
|
}
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
role: "user",
|
|
206
|
-
content: [{ type: "text", text: interruptMessage }],
|
|
207
|
-
},
|
|
208
|
-
]);
|
|
208
|
+
// Check if auto-approve was paused by Ctrl-C during tool execution
|
|
209
|
+
if (pauseSignal.isPaused()) {
|
|
210
|
+
pauseSignal.reset();
|
|
211
|
+
break;
|
|
209
212
|
}
|
|
210
213
|
}
|
|
211
214
|
}
|
package/src/cliArgs.mjs
CHANGED
|
@@ -125,10 +125,12 @@ Usage: plain [options]
|
|
|
125
125
|
Options:
|
|
126
126
|
-m, --model <model+variant> Model to use
|
|
127
127
|
-h, --help Show this help message
|
|
128
|
-
-c, --config <file> Config file to load
|
|
128
|
+
-c, --config <file> Config file to load (repeatable)
|
|
129
129
|
|
|
130
130
|
Subcommands:
|
|
131
|
-
batch <task> Run in batch mode with the given task instruction
|
|
131
|
+
batch <task> Run in batch mode with the given task instruction.
|
|
132
|
+
Config files are NOT auto-loaded in batch mode;
|
|
133
|
+
use -c to specify config files explicitly.
|
|
132
134
|
list-models List available models
|
|
133
135
|
install-claude-code-plugins Install Claude Code plugins
|
|
134
136
|
|
|
@@ -137,9 +139,7 @@ Examples:
|
|
|
137
139
|
plain batch \\
|
|
138
140
|
-c ~/.config/plain-agent/config.local.json \\
|
|
139
141
|
-c .plain-agent/config.json \\
|
|
140
|
-
"Add tests for
|
|
141
|
-
plain list-models
|
|
142
|
-
plain install-claude-code-plugins
|
|
142
|
+
"Add tests for ..."
|
|
143
143
|
`);
|
|
144
144
|
process.exit(exitCode);
|
|
145
145
|
}
|
package/src/cliCompleter.mjs
CHANGED
|
@@ -200,8 +200,8 @@ export function createCompleter(getCliRef, claudeCodePlugins) {
|
|
|
200
200
|
const name = typeof cmd === "string" ? cmd : cmd.name;
|
|
201
201
|
return (
|
|
202
202
|
name !== "/<id>" &&
|
|
203
|
-
(name === "/agents:" || !name.startsWith("/
|
|
204
|
-
(name === "/prompts:" || !name.startsWith("/
|
|
203
|
+
(name === "/agents:" || !name.startsWith("/agents:")) &&
|
|
204
|
+
(name === "/prompts:" || !name.startsWith("/prompts:"))
|
|
205
205
|
);
|
|
206
206
|
},
|
|
207
207
|
);
|
package/src/cliInteractive.mjs
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
createPasteTransform,
|
|
17
17
|
resolvePastePlaceholders,
|
|
18
18
|
} from "./cliPasteTransform.mjs";
|
|
19
|
-
import { consumeInterruptMessage } from "./context/consumeInterruptMessage.mjs";
|
|
20
19
|
import { notify } from "./utils/notify.mjs";
|
|
21
20
|
|
|
22
21
|
const HELP_MESSAGE = [
|
|
@@ -121,7 +120,19 @@ export function startInteractiveSession({
|
|
|
121
120
|
let lastExitAttempt = 0;
|
|
122
121
|
const EXIT_CONFIRM_TIMEOUT = 1500;
|
|
123
122
|
|
|
124
|
-
const
|
|
123
|
+
const handleCtrlC = () => {
|
|
124
|
+
// If agent is running, pause auto-approve instead of exiting
|
|
125
|
+
if (!state.turn) {
|
|
126
|
+
agentCommands.pauseAutoApprove();
|
|
127
|
+
console.log(
|
|
128
|
+
styleText(
|
|
129
|
+
"yellow",
|
|
130
|
+
"\n⚠ Ctrl-C: Auto-approve paused. Finishing current tool...",
|
|
131
|
+
),
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
125
136
|
const now = Date.now();
|
|
126
137
|
if (now - lastExitAttempt < EXIT_CONFIRM_TIMEOUT) {
|
|
127
138
|
handleExit();
|
|
@@ -132,7 +143,7 @@ export function startInteractiveSession({
|
|
|
132
143
|
};
|
|
133
144
|
|
|
134
145
|
// Create a transform stream to handle bracketed paste before readline
|
|
135
|
-
const pasteTransform = createPasteTransform(
|
|
146
|
+
const pasteTransform = createPasteTransform(handleCtrlC);
|
|
136
147
|
|
|
137
148
|
// Set up transformed stdin for readline
|
|
138
149
|
process.stdin.pipe(pasteTransform);
|
|
@@ -198,7 +209,6 @@ export function startInteractiveSession({
|
|
|
198
209
|
}
|
|
199
210
|
|
|
200
211
|
cli.setPrompt(currentCliPrompt);
|
|
201
|
-
await consumeInterruptMessage();
|
|
202
212
|
|
|
203
213
|
const result = await handleCommand(inputTrimmed);
|
|
204
214
|
if (result === "prompt") {
|
|
@@ -53,10 +53,10 @@ export function resolvePastePlaceholders(input) {
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Create a Transform stream to handle bracketed paste before readline.
|
|
56
|
-
* @param {() => void}
|
|
56
|
+
* @param {() => void} onCtrlC - Called when Ctrl-C or Ctrl-D is detected
|
|
57
57
|
* @returns {Transform}
|
|
58
58
|
*/
|
|
59
|
-
export function createPasteTransform(
|
|
59
|
+
export function createPasteTransform(onCtrlC) {
|
|
60
60
|
let inPasteMode = false;
|
|
61
61
|
let pasteBuffer = "";
|
|
62
62
|
|
|
@@ -67,8 +67,7 @@ export function createPasteTransform(onExitRequest) {
|
|
|
67
67
|
|
|
68
68
|
// Handle Ctrl-C and Ctrl-D
|
|
69
69
|
if (data.includes("\x03") || data.includes("\x04")) {
|
|
70
|
-
|
|
71
|
-
onExitRequest();
|
|
70
|
+
onCtrlC();
|
|
72
71
|
callback();
|
|
73
72
|
return;
|
|
74
73
|
}
|
package/src/config.mjs
CHANGED
|
@@ -34,7 +34,7 @@ export async function loadAppConfig(options = {}) {
|
|
|
34
34
|
} = options;
|
|
35
35
|
|
|
36
36
|
// Always load predefined config
|
|
37
|
-
const paths = [`${AGENT_ROOT}
|
|
37
|
+
const paths = [`${AGENT_ROOT}/config/config.predefined.json`];
|
|
38
38
|
|
|
39
39
|
if (!skipUserConfig) {
|
|
40
40
|
paths.push(
|
|
@@ -30,7 +30,7 @@ export async function loadAgentRoles(claudeCodePlugins) {
|
|
|
30
30
|
/** @type {Array<{dir: string, idPrefix: string, only?: RegExp}>} */
|
|
31
31
|
const agentDirs = [
|
|
32
32
|
{
|
|
33
|
-
dir: path.resolve(AGENT_ROOT, "
|
|
33
|
+
dir: path.resolve(AGENT_ROOT, "config", "agents.predefined"),
|
|
34
34
|
idPrefix: "",
|
|
35
35
|
},
|
|
36
36
|
{ dir: path.resolve(AGENT_USER_CONFIG_DIR, "agents"), idPrefix: "" },
|
|
@@ -34,7 +34,7 @@ export async function loadPrompts(claudeCodePlugins) {
|
|
|
34
34
|
/** @type {Array<{dir: string, idPrefix: string, only?: RegExp}>} */
|
|
35
35
|
const promptDirs = [
|
|
36
36
|
{
|
|
37
|
-
dir: path.resolve(AGENT_ROOT, "
|
|
37
|
+
dir: path.resolve(AGENT_ROOT, "config", "prompts.predefined"),
|
|
38
38
|
idPrefix: "",
|
|
39
39
|
},
|
|
40
40
|
{ dir: path.resolve(AGENT_USER_CONFIG_DIR, "prompts"), idPrefix: "" },
|
package/src/env.mjs
CHANGED
|
@@ -38,9 +38,4 @@ export const AGENT_NOTIFY_CMD_DEFAULT = path.join(
|
|
|
38
38
|
"plain-notify-terminal-bell",
|
|
39
39
|
);
|
|
40
40
|
|
|
41
|
-
export const AGENT_INTERRUPT_MESSAGE_FILE_PATH = path.join(
|
|
42
|
-
AGENT_PROJECT_METADATA_DIR,
|
|
43
|
-
"interrupt-message.txt",
|
|
44
|
-
);
|
|
45
|
-
|
|
46
41
|
export const USER_NAME = process.env.USER || "unknown";
|
package/src/modelDefinition.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export type PlatformConfig =
|
|
|
34
34
|
customHeaders?: Record<string, string>;
|
|
35
35
|
apiKey: string;
|
|
36
36
|
}
|
|
37
|
+
| {
|
|
38
|
+
name: "openai-compatible";
|
|
39
|
+
variant: string;
|
|
40
|
+
baseURL: string;
|
|
41
|
+
customHeaders?: Record<string, string>;
|
|
42
|
+
apiKey: string;
|
|
43
|
+
}
|
|
37
44
|
| {
|
|
38
45
|
name: "azure";
|
|
39
46
|
variant: string;
|
|
@@ -36,6 +36,7 @@ export async function callOpenAICompatibleModel(
|
|
|
36
36
|
|
|
37
37
|
switch (platformConfig.name) {
|
|
38
38
|
case "openai":
|
|
39
|
+
case "openai-compatible":
|
|
39
40
|
return `${baseURL}/v1/chat/completions`;
|
|
40
41
|
case "bedrock":
|
|
41
42
|
return `${baseURL}/model/${modelConfig.model}/invoke-with-response-stream`;
|
|
@@ -50,6 +51,7 @@ export async function callOpenAICompatibleModel(
|
|
|
50
51
|
const headers = await (async () => {
|
|
51
52
|
switch (platformConfig.name) {
|
|
52
53
|
case "openai":
|
|
54
|
+
case "openai-compatible":
|
|
53
55
|
return {
|
|
54
56
|
...platformConfig.customHeaders,
|
|
55
57
|
Authorization: `Bearer ${platformConfig.apiKey}`,
|
|
@@ -68,6 +70,7 @@ export async function callOpenAICompatibleModel(
|
|
|
68
70
|
const platformRequest = (() => {
|
|
69
71
|
switch (platformConfig.name) {
|
|
70
72
|
case "openai":
|
|
73
|
+
case "openai-compatible":
|
|
71
74
|
return {
|
|
72
75
|
...modelConfig,
|
|
73
76
|
stream: true,
|
package/src/subagent.mjs
CHANGED
|
@@ -25,6 +25,7 @@ import { reportAsSubagentToolName } from "./tools/reportAsSubagent.mjs";
|
|
|
25
25
|
export function createSubagentManager(agentRoles, handlers) {
|
|
26
26
|
/** @type {{name: string; goal: string; delegationMessageIndex: number}[]} */
|
|
27
27
|
const subagents = [];
|
|
28
|
+
let subagentCount = 0;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* @typedef {DelegateSuccess | DelegateFailure} DelegateResult
|
|
@@ -79,6 +80,9 @@ export function createSubagentManager(agentRoles, handlers) {
|
|
|
79
80
|
: role.content;
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
subagentCount++;
|
|
84
|
+
const sequenceNumber = String(subagentCount).padStart(2, "0");
|
|
85
|
+
|
|
82
86
|
subagents.push({
|
|
83
87
|
name: actualName,
|
|
84
88
|
goal,
|
|
@@ -89,11 +93,11 @@ export function createSubagentManager(agentRoles, handlers) {
|
|
|
89
93
|
return {
|
|
90
94
|
success: true,
|
|
91
95
|
value: [
|
|
92
|
-
|
|
96
|
+
`You are now the subagent "${actualName}". Start working on the following goal.`,
|
|
93
97
|
`Your goal: ${goal}`,
|
|
94
98
|
`Role: ${actualName}\n---\n${roleContent}\n---`,
|
|
95
|
-
`Memory file path format: ${AGENT_PROJECT_METADATA_DIR}/memory/<session-id>--${actualName}--<kebab-case-title>.md (Replace <kebab-case-title>
|
|
96
|
-
`
|
|
99
|
+
`Memory file path format: ${AGENT_PROJECT_METADATA_DIR}/memory/<session-id>--${sequenceNumber}--${actualName}--<kebab-case-title>.md (Replace <kebab-case-title> with a short title describing your own goal)`,
|
|
100
|
+
`When finished, call "report_as_subagent" with the memory file path.`,
|
|
97
101
|
].join("\n\n"),
|
|
98
102
|
};
|
|
99
103
|
}
|
package/bin/plain-interrupt
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import { AGENT_INTERRUPT_MESSAGE_FILE_PATH } from "../env.mjs";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @returns {Promise<string | undefined>}
|
|
6
|
-
*/
|
|
7
|
-
export async function consumeInterruptMessage() {
|
|
8
|
-
try {
|
|
9
|
-
const content = await fs.readFile(
|
|
10
|
-
AGENT_INTERRUPT_MESSAGE_FILE_PATH,
|
|
11
|
-
"utf8",
|
|
12
|
-
);
|
|
13
|
-
await fs.truncate(AGENT_INTERRUPT_MESSAGE_FILE_PATH, 0);
|
|
14
|
-
|
|
15
|
-
if (content.trim() === "") {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
return content;
|
|
19
|
-
} catch (err) {
|
|
20
|
-
if (
|
|
21
|
-
err instanceof Error &&
|
|
22
|
-
"code" in err &&
|
|
23
|
-
typeof err.code === "string" &&
|
|
24
|
-
err.code === "ENOENT"
|
|
25
|
-
) {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
throw err;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|