@elizaos/plugin-agent-orchestrator 0.3.0 → 0.3.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/dist/index.js +684 -393
- package/dist/index.js.map +9 -9
- package/dist/services/pty-service.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/actions/coding-task-handlers.d.ts +0 -44
- package/dist/actions/coding-task-handlers.d.ts.map +0 -1
- package/dist/actions/coding-task-helpers.d.ts +0 -27
- package/dist/actions/coding-task-helpers.d.ts.map +0 -1
- package/dist/actions/finalize-workspace.d.ts +0 -11
- package/dist/actions/finalize-workspace.d.ts.map +0 -1
- package/dist/actions/list-agents.d.ts +0 -11
- package/dist/actions/list-agents.d.ts.map +0 -1
- package/dist/actions/manage-issues.d.ts +0 -11
- package/dist/actions/manage-issues.d.ts.map +0 -1
- package/dist/actions/provision-workspace.d.ts +0 -11
- package/dist/actions/provision-workspace.d.ts.map +0 -1
- package/dist/actions/send-to-agent.d.ts +0 -11
- package/dist/actions/send-to-agent.d.ts.map +0 -1
- package/dist/actions/spawn-agent.d.ts +0 -11
- package/dist/actions/spawn-agent.d.ts.map +0 -1
- package/dist/actions/start-coding-task.d.ts +0 -17
- package/dist/actions/start-coding-task.d.ts.map +0 -1
- package/dist/actions/stop-agent.d.ts +0 -11
- package/dist/actions/stop-agent.d.ts.map +0 -1
- package/dist/api/agent-routes.d.ts +0 -18
- package/dist/api/agent-routes.d.ts.map +0 -1
- package/dist/api/coordinator-routes.d.ts +0 -22
- package/dist/api/coordinator-routes.d.ts.map +0 -1
- package/dist/api/issue-routes.d.ts +0 -17
- package/dist/api/issue-routes.d.ts.map +0 -1
- package/dist/api/routes.d.ts +0 -36
- package/dist/api/routes.d.ts.map +0 -1
- package/dist/api/workspace-routes.d.ts +0 -17
- package/dist/api/workspace-routes.d.ts.map +0 -1
- package/dist/index.d.ts +0 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/providers/action-examples.d.ts +0 -13
- package/dist/providers/action-examples.d.ts.map +0 -1
- package/dist/providers/active-workspace-context.d.ts +0 -13
- package/dist/providers/active-workspace-context.d.ts.map +0 -1
- package/dist/services/agent-metrics.d.ts +0 -28
- package/dist/services/agent-metrics.d.ts.map +0 -1
- package/dist/services/agent-selection.d.ts +0 -53
- package/dist/services/agent-selection.d.ts.map +0 -1
- package/dist/services/ansi-utils.d.ts +0 -48
- package/dist/services/ansi-utils.d.ts.map +0 -1
- package/dist/services/pty-auto-response.d.ts +0 -30
- package/dist/services/pty-auto-response.d.ts.map +0 -1
- package/dist/services/pty-init.d.ts +0 -45
- package/dist/services/pty-init.d.ts.map +0 -1
- package/dist/services/pty-service.d.ts +0 -92
- package/dist/services/pty-session-io.d.ts +0 -46
- package/dist/services/pty-session-io.d.ts.map +0 -1
- package/dist/services/pty-spawn.d.ts +0 -50
- package/dist/services/pty-spawn.d.ts.map +0 -1
- package/dist/services/pty-types.d.ts +0 -80
- package/dist/services/pty-types.d.ts.map +0 -1
- package/dist/services/stall-classifier.d.ts +0 -44
- package/dist/services/stall-classifier.d.ts.map +0 -1
- package/dist/services/swarm-coordinator-prompts.d.ts +0 -75
- package/dist/services/swarm-coordinator-prompts.d.ts.map +0 -1
- package/dist/services/swarm-coordinator.d.ts +0 -196
- package/dist/services/swarm-coordinator.d.ts.map +0 -1
- package/dist/services/swarm-decision-loop.d.ts +0 -44
- package/dist/services/swarm-decision-loop.d.ts.map +0 -1
- package/dist/services/swarm-event-triage.d.ts +0 -49
- package/dist/services/swarm-event-triage.d.ts.map +0 -1
- package/dist/services/swarm-idle-watchdog.d.ts +0 -22
- package/dist/services/swarm-idle-watchdog.d.ts.map +0 -1
- package/dist/services/workspace-git-ops.d.ts +0 -28
- package/dist/services/workspace-git-ops.d.ts.map +0 -1
- package/dist/services/workspace-github.d.ts +0 -58
- package/dist/services/workspace-github.d.ts.map +0 -1
- package/dist/services/workspace-lifecycle.d.ts +0 -18
- package/dist/services/workspace-lifecycle.d.ts.map +0 -1
- package/dist/services/workspace-service.d.ts +0 -84
- package/dist/services/workspace-service.d.ts.map +0 -1
- package/dist/services/workspace-types.d.ts +0 -81
- package/dist/services/workspace-types.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {createRequire} from "node:module";
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
3
7
|
var __export = (target, all) => {
|
|
4
8
|
for (var name in all)
|
|
5
9
|
__defProp(target, name, {
|
|
6
10
|
get: all[name],
|
|
7
11
|
enumerable: true,
|
|
8
12
|
configurable: true,
|
|
9
|
-
set: (
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
10
14
|
});
|
|
11
15
|
};
|
|
12
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -21,7 +25,8 @@ function stripAnsi(raw) {
|
|
|
21
25
|
}
|
|
22
26
|
function cleanForChat(raw) {
|
|
23
27
|
const stripped = applyAnsiStrip(raw);
|
|
24
|
-
return stripped.replace(TUI_DECORATIVE, " ").replace(/\xa0/g, " ").split(
|
|
28
|
+
return stripped.replace(TUI_DECORATIVE, " ").replace(/\xa0/g, " ").split(`
|
|
29
|
+
`).filter((line) => {
|
|
25
30
|
const trimmed = line.trim();
|
|
26
31
|
if (!trimmed)
|
|
27
32
|
return false;
|
|
@@ -32,7 +37,10 @@ function cleanForChat(raw) {
|
|
|
32
37
|
if (!/[a-zA-Z0-9]/.test(trimmed))
|
|
33
38
|
return false;
|
|
34
39
|
return true;
|
|
35
|
-
}).map((line) => line.replace(/ {2,}/g, " ").trim()).filter((line) => line.length > 0).join(
|
|
40
|
+
}).map((line) => line.replace(/ {2,}/g, " ").trim()).filter((line) => line.length > 0).join(`
|
|
41
|
+
`).replace(/\n{3,}/g, `
|
|
42
|
+
|
|
43
|
+
`).trim();
|
|
36
44
|
}
|
|
37
45
|
function extractCompletionSummary(raw) {
|
|
38
46
|
const stripped = applyAnsiStrip(raw);
|
|
@@ -57,7 +65,8 @@ function extractCompletionSummary(raw) {
|
|
|
57
65
|
for (const m of diffStat)
|
|
58
66
|
lines.push(m.trim());
|
|
59
67
|
}
|
|
60
|
-
return lines.join(
|
|
68
|
+
return lines.join(`
|
|
69
|
+
`);
|
|
61
70
|
}
|
|
62
71
|
function extractDevServerUrl(raw) {
|
|
63
72
|
const stripped = applyAnsiStrip(raw);
|
|
@@ -71,7 +80,8 @@ function captureTaskResponse(sessionId, buffers, markers) {
|
|
|
71
80
|
return "";
|
|
72
81
|
const responseLines = buffer.slice(marker);
|
|
73
82
|
markers.delete(sessionId);
|
|
74
|
-
return cleanForChat(responseLines.join(
|
|
83
|
+
return cleanForChat(responseLines.join(`
|
|
84
|
+
`));
|
|
75
85
|
}
|
|
76
86
|
var CURSOR_MOVEMENT, CURSOR_POSITION, ERASE, OSC, ALL_ANSI, CONTROL_CHARS, ORPHAN_SGR, LONG_SPACES, TUI_DECORATIVE, LOADING_LINE, STATUS_LINE;
|
|
77
87
|
var init_ansi_utils = __esm(() => {
|
|
@@ -90,54 +100,208 @@ var init_ansi_utils = __esm(() => {
|
|
|
90
100
|
|
|
91
101
|
// src/services/swarm-coordinator-prompts.ts
|
|
92
102
|
function buildCoordinationPrompt(taskCtx, promptText, recentOutput, decisionHistory) {
|
|
93
|
-
const historySection = decisionHistory.length > 0 ?
|
|
94
|
-
|
|
103
|
+
const historySection = decisionHistory.length > 0 ? `
|
|
104
|
+
Previous decisions for this session:
|
|
105
|
+
${decisionHistory.slice(-5).map((d, i) => ` ${i + 1}. [${d.event}] prompt="${d.promptText}" → ${d.action}${d.response ? ` ("${d.response}")` : ""} — ${d.reasoning}`).join(`
|
|
106
|
+
`)}
|
|
107
|
+
` : "";
|
|
108
|
+
return `You are Milady, an AI orchestrator managing a swarm of coding agents. ` + `A ${taskCtx.agentType} coding agent ("${taskCtx.label}", session: ${taskCtx.sessionId}) ` + `is blocked and waiting for input.
|
|
109
|
+
|
|
110
|
+
` + `Original task: "${taskCtx.originalTask}"
|
|
111
|
+
` + `Working directory: ${taskCtx.workdir}
|
|
112
|
+
` + `Repository: ${taskCtx.repo ?? "none (scratch directory)"}
|
|
113
|
+
` + historySection + `
|
|
114
|
+
Recent terminal output (last 50 lines):
|
|
115
|
+
` + `---
|
|
116
|
+
${recentOutput.slice(-3000)}
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
` + `The agent is showing this blocking prompt:
|
|
120
|
+
` + `"${promptText}"
|
|
121
|
+
|
|
122
|
+
` + `Decide how to respond. Your options:
|
|
123
|
+
|
|
124
|
+
` + `1. "respond" — Send a response to unblock the agent. For text prompts (Y/n, questions), ` + `set "response" to the text to send. For TUI menus or interactive prompts that need ` + `special keys, set "useKeys": true and "keys" to the key sequence ` + `(e.g. ["enter"], ["down","enter"], ["y","enter"]).
|
|
125
|
+
|
|
126
|
+
` + `2. "complete" — The original task has been fulfilled. The agent has finished its work ` + `(e.g. code written, PR created, tests passed) and is back at the idle prompt. ` + `Use this when the terminal output shows the task objectives have been met.
|
|
95
127
|
|
|
96
|
-
` + `
|
|
97
|
-
` + `- When in doubt, escalate \u2014 it's better to ask the human than to make a wrong choice.
|
|
128
|
+
` + `3. "escalate" — The prompt requires human judgment (e.g. design decisions, ` + `ambiguous requirements, security-sensitive actions). Do NOT respond yourself.
|
|
98
129
|
|
|
99
|
-
` + `
|
|
130
|
+
` + `4. "ignore" — The prompt is not actually blocking or is already being handled.
|
|
131
|
+
|
|
132
|
+
` + `Guidelines:
|
|
133
|
+
` + `- IMPORTANT: If the prompt asks to approve access to files or directories OUTSIDE the working ` + `directory (${taskCtx.workdir}), DECLINE the request and REDIRECT the agent. Do NOT approve ` + `access to paths like /etc, ~/.ssh, ~/, /tmp, or any path that doesn't start with the working ` + `directory. Instead, respond with "n" (or the decline option) and tell the agent: ` + `"That path is outside your workspace. Use ${taskCtx.workdir} instead — ` + `create any files or directories you need there." This keeps the agent moving without ` + `granting out-of-scope access. The coordinator will also notify the human in case ` + `broader access was intended.
|
|
134
|
+
` + `- For tool approval prompts (file writes, shell commands, etc.), respond "y" or use keys:["enter"] to approve.
|
|
135
|
+
` + `- For Y/n confirmations that align with the original task, respond "y".
|
|
136
|
+
` + `- For design questions or choices that could go either way, escalate.
|
|
137
|
+
` + `- For error recovery prompts, try to respond if the path forward is clear.
|
|
138
|
+
` + `- If the output shows a PR was just created (e.g. "Created pull request #N"), do NOT use "complete" yet. ` + `Instead respond with "Review your PR, run each test plan item to verify it works, update the PR to check off each item, then confirm all items pass".
|
|
139
|
+
` + `- Only use "complete" if the agent confirmed it verified ALL test plan items after creating the PR.
|
|
140
|
+
` + `- If the agent is asking for information that was NOT provided in the original task ` + `(e.g. which repository to use, project requirements, credentials), ESCALATE. ` + `The coordinator does not have this information — the human must provide it.
|
|
141
|
+
` + `- When in doubt, escalate — it's better to ask the human than to make a wrong choice.
|
|
142
|
+
|
|
143
|
+
` + `Respond with ONLY a JSON object:
|
|
144
|
+
` + `{"action": "respond|complete|escalate|ignore", "response": "...", "useKeys": false, "keys": [], "reasoning": "..."}`;
|
|
100
145
|
}
|
|
101
146
|
function buildIdleCheckPrompt(taskCtx, recentOutput, idleMinutes, idleCheckNumber, maxIdleChecks, decisionHistory) {
|
|
102
|
-
const historySection = decisionHistory.length > 0 ?
|
|
103
|
-
|
|
147
|
+
const historySection = decisionHistory.length > 0 ? `
|
|
148
|
+
Previous decisions for this session:
|
|
149
|
+
${decisionHistory.slice(-5).map((d, i) => ` ${i + 1}. [${d.event}] prompt="${d.promptText}" → ${d.action}${d.response ? ` ("${d.response}")` : ""} — ${d.reasoning}`).join(`
|
|
150
|
+
`)}
|
|
151
|
+
` : "";
|
|
152
|
+
return `You are Milady, an AI orchestrator managing a swarm of coding agents. ` + `A ${taskCtx.agentType} coding agent ("${taskCtx.label}", session: ${taskCtx.sessionId}) ` + `has been idle for ${idleMinutes} minutes with no events or output changes.
|
|
153
|
+
|
|
154
|
+
` + `Original task: "${taskCtx.originalTask}"
|
|
155
|
+
` + `Working directory: ${taskCtx.workdir}
|
|
156
|
+
` + `Repository: ${taskCtx.repo ?? "none (scratch directory)"}
|
|
157
|
+
` + `Idle check: ${idleCheckNumber} of ${maxIdleChecks} (session will be force-escalated after ${maxIdleChecks})
|
|
158
|
+
` + historySection + `
|
|
159
|
+
Recent terminal output (last 50 lines):
|
|
160
|
+
` + `---
|
|
161
|
+
${recentOutput.slice(-3000)}
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
` + `The session has gone silent. Analyze the terminal output and decide:
|
|
165
|
+
|
|
166
|
+
` + `1. "complete" — The task is FULLY done. ALL objectives in the original task were met ` + `AND the final deliverable is visible in the output (e.g. a PR URL was printed, or the ` + `task explicitly did not require a PR). The agent is back at the idle prompt.
|
|
167
|
+
|
|
168
|
+
` + `2. "respond" — The agent appears stuck or waiting for input that wasn't detected ` + `as a blocking prompt. Send a message to nudge it (e.g. "continue", or answer a question ` + `visible in the output). If code was committed but no PR was created yet, respond with ` + `"please create a pull request with your changes" or similar.
|
|
169
|
+
|
|
170
|
+
` + `3. "escalate" — Something looks wrong or unclear. The human should review.
|
|
104
171
|
|
|
105
|
-
` + `4. "ignore"
|
|
172
|
+
` + `4. "ignore" — The agent is still actively working (e.g. compiling, running tests, ` + `pushing to remote, creating a PR). The idle period is expected and it will produce output soon.
|
|
106
173
|
|
|
107
|
-
` + `
|
|
174
|
+
` + `Guidelines:
|
|
175
|
+
` + `- IMPORTANT: Do NOT mark "complete" if the original task involves creating a PR and no PR URL ` + `(e.g. github.com/...pull/...) appears in the output. Instead use "respond" to nudge the agent ` + `to create the PR.
|
|
176
|
+
` + `- Do NOT mark "complete" just because code was committed — commits alone don't finish a task ` + `that requires a PR.
|
|
177
|
+
` + `- Network operations (git push, gh pr create, API calls) can cause several minutes of silence — ` + `prefer "ignore" for early idle checks if the agent was mid-workflow.
|
|
178
|
+
` + `- If the output ends with a command prompt ($ or >) and ALL task objectives are confirmed met, use "complete".
|
|
179
|
+
` + `- If the output shows an error or the agent seems stuck in a loop, escalate.
|
|
180
|
+
` + `- If the agent is clearly mid-operation (build output, test runner, git operations), use "ignore".
|
|
181
|
+
` + `- On check ${idleCheckNumber} of ${maxIdleChecks} — if unsure, lean toward "respond" with a nudge rather than "complete".
|
|
182
|
+
|
|
183
|
+
` + `Respond with ONLY a JSON object:
|
|
184
|
+
` + `{"action": "respond|complete|escalate|ignore", "response": "...", "useKeys": false, "keys": [], "reasoning": "..."}`;
|
|
108
185
|
}
|
|
109
186
|
function buildTurnCompletePrompt(taskCtx, turnOutput, decisionHistory) {
|
|
110
|
-
const historySection = decisionHistory.length > 0 ?
|
|
111
|
-
|
|
187
|
+
const historySection = decisionHistory.length > 0 ? `
|
|
188
|
+
Previous decisions for this session:
|
|
189
|
+
${decisionHistory.slice(-5).map((d, i) => ` ${i + 1}. [${d.event}] prompt="${d.promptText}" → ${d.action}${d.response ? ` ("${d.response}")` : ""} — ${d.reasoning}`).join(`
|
|
190
|
+
`)}
|
|
191
|
+
` : "";
|
|
192
|
+
return `You are Milady, an AI orchestrator managing a swarm of coding agents. ` + `A ${taskCtx.agentType} coding agent ("${taskCtx.label}", session: ${taskCtx.sessionId}) ` + `just finished a turn and is back at the idle prompt waiting for input.
|
|
193
|
+
|
|
194
|
+
` + `Original task: "${taskCtx.originalTask}"
|
|
195
|
+
` + `Working directory: ${taskCtx.workdir}
|
|
196
|
+
` + `Repository: ${taskCtx.repo ?? "none (scratch directory)"}
|
|
197
|
+
` + historySection + `
|
|
198
|
+
Output from this turn:
|
|
199
|
+
` + `---
|
|
200
|
+
${turnOutput.slice(-3000)}
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
` + `The agent completed a turn. Decide if the OVERALL task is done or if more work is needed.
|
|
204
|
+
|
|
205
|
+
` + `IMPORTANT: Coding agents work in multiple turns. A single turn completing does NOT mean ` + `the task is done. You must verify that EVERY objective in the original task has been addressed ` + `in the output before declaring "complete".
|
|
206
|
+
|
|
207
|
+
` + `Your options:
|
|
208
|
+
|
|
209
|
+
` + `1. "respond" — The agent finished a step but the overall task is NOT done yet. ` + `Send a follow-up instruction to continue. Set "response" to the next instruction ` + `(e.g. "Now run the tests", "Create a PR with these changes", "Continue with the next part"). ` + `THIS IS THE DEFAULT — most turns are intermediate steps, not the final result.
|
|
210
|
+
|
|
211
|
+
` + `2. "complete" — The original task objectives have ALL been fully met. For repo-based tasks, ` + `this means code was written, changes were committed, pushed, AND a pull request was created. ` + `Only use this when you can point to specific evidence in the output for EVERY objective ` + `(e.g. "Created pull request #N" in the output).
|
|
112
212
|
|
|
113
|
-
` + `
|
|
213
|
+
` + `3. "escalate" — Something looks wrong or you're unsure whether the task is complete. ` + `Let the human decide.
|
|
114
214
|
|
|
115
|
-
` + `
|
|
116
|
-
` + `- If the task mentions multiple features/fixes, verify EACH one is addressed, not just the first.\n` + `- If the agent only analyzed code or read files, it hasn't done the actual work yet \u2014 send a follow-up.
|
|
117
|
-
` + `- If the agent wrote code but didn't test it and testing seems appropriate, ask it to run tests.\n` + `- If the output shows errors or failed tests, send a follow-up to fix them.\n` + `- IMPORTANT: If the working directory is a git repository clone (not a scratch dir), the agent ` + `MUST commit its changes, push them, and create a pull request before the task can be "complete". ` + `If the output only shows code edits with no git commit or PR, respond with "Now commit your changes, push, and create a pull request".\n` + `- IMPORTANT: Creating a PR is NOT the final step. If this is the turn where the PR was created ` + `(i.e. "Created pull request" or a PR URL appears for the FIRST time and no previous decision ` + `already sent a review follow-up), respond with "Review your PR, run each test plan item to verify ` + `it works, update the PR to check off each item, then confirm all items pass".\n` + `- If a previous decision ALREADY sent a review/verification follow-up (check the decision history), ` + `and the agent has now responded with its review results, you MAY mark "complete" if the agent ` + `indicates the work is done (e.g. "Done", "verified", "all checks pass", "Here's what I did", ` + `or a clear summary of completed work). Do NOT require exact phrases \u2014 use judgment.
|
|
118
|
-
` + `- Keep follow-up instructions concise and specific.\n` + `- Default to "respond" \u2014 only use "complete" when you're certain ALL work is done.
|
|
215
|
+
` + `4. "ignore" — Should not normally be used here.
|
|
119
216
|
|
|
120
|
-
` + `
|
|
217
|
+
` + `Guidelines:
|
|
218
|
+
` + `- BEFORE choosing "complete", enumerate each objective from the original task and verify ` + `evidence in the output. If ANY objective lacks evidence, use "respond" with the missing work.
|
|
219
|
+
` + `- A PR being created does NOT mean the task is done — check that the PR covers ALL requested changes.
|
|
220
|
+
` + `- If the task mentions multiple features/fixes, verify EACH one is addressed, not just the first.
|
|
221
|
+
` + `- If the agent only analyzed code or read files, it hasn't done the actual work yet — send a follow-up.
|
|
222
|
+
` + `- If the agent wrote code but didn't test it and testing seems appropriate, ask it to run tests.
|
|
223
|
+
` + `- If the output shows errors or failed tests, send a follow-up to fix them.
|
|
224
|
+
` + `- IMPORTANT: If the working directory is a git repository clone (not a scratch dir), the agent ` + `MUST commit its changes, push them, and create a pull request before the task can be "complete". ` + `If the output only shows code edits with no git commit or PR, respond with "Now commit your changes, push, and create a pull request".
|
|
225
|
+
` + `- IMPORTANT: Creating a PR is NOT the final step. If this is the turn where the PR was created ` + `(i.e. "Created pull request" or a PR URL appears for the FIRST time and no previous decision ` + `already sent a review follow-up), respond with "Review your PR, run each test plan item to verify ` + `it works, update the PR to check off each item, then confirm all items pass".
|
|
226
|
+
` + `- If a previous decision ALREADY sent a review/verification follow-up (check the decision history), ` + `and the agent has now responded with its review results, you MAY mark "complete" if the agent ` + `indicates the work is done (e.g. "Done", "verified", "all checks pass", "Here's what I did", ` + `or a clear summary of completed work). Do NOT require exact phrases — use judgment.
|
|
227
|
+
` + `- Keep follow-up instructions concise and specific.
|
|
228
|
+
` + `- When asking agents to verify work, prefer CLI tools (gh, curl, cat, git diff, etc.) over ` + `browser automation. Browser tools may not be available in headless environments and can cause delays.
|
|
229
|
+
` + `- Default to "respond" — only use "complete" when you're certain ALL work is done.
|
|
230
|
+
|
|
231
|
+
` + `Respond with ONLY a JSON object:
|
|
232
|
+
` + `{"action": "respond|complete|escalate|ignore", "response": "...", "useKeys": false, "keys": [], "reasoning": "..."}`;
|
|
121
233
|
}
|
|
122
234
|
function buildBlockedEventMessage(taskCtx, promptText, recentOutput, decisionHistory) {
|
|
123
|
-
const historySection = decisionHistory.length > 0 ?
|
|
124
|
-
|
|
125
|
-
` +
|
|
126
|
-
`
|
|
127
|
-
`
|
|
235
|
+
const historySection = decisionHistory.length > 0 ? `
|
|
236
|
+
Previous decisions:
|
|
237
|
+
${decisionHistory.slice(-5).map((d, i) => ` ${i + 1}. [${d.event}] "${d.promptText}" → ${d.action}${d.response ? ` ("${d.response}")` : ""} — ${d.reasoning}`).join(`
|
|
238
|
+
`)}
|
|
239
|
+
` : "";
|
|
240
|
+
return `[Coding Agent Event] A ${taskCtx.agentType} agent ("${taskCtx.label}") is blocked and waiting for input.
|
|
241
|
+
|
|
242
|
+
` + `Task: "${taskCtx.originalTask}"
|
|
243
|
+
` + `Workdir: ${taskCtx.workdir}
|
|
244
|
+
` + `Repo: ${taskCtx.repo ?? "none (scratch directory)"}
|
|
245
|
+
` + historySection + `
|
|
246
|
+
Recent terminal output:
|
|
247
|
+
---
|
|
248
|
+
${recentOutput.slice(-3000)}
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
` + `Blocking prompt: "${promptText}"
|
|
252
|
+
|
|
253
|
+
` + `Decide how to handle this. Options:
|
|
254
|
+
` + `- "respond" — send text or keys to unblock the agent
|
|
255
|
+
` + `- "complete" — the task is fully done
|
|
256
|
+
` + `- "escalate" — you need the user's input
|
|
257
|
+
` + `- "ignore" — not actually blocking
|
|
128
258
|
|
|
129
|
-
` + `Guidelines
|
|
259
|
+
` + `Guidelines:
|
|
260
|
+
` + `- For tool approvals / Y/n that align with the task, respond "y" or keys:["enter"].
|
|
261
|
+
` + `- If the prompt asks for info NOT in the original task, escalate.
|
|
262
|
+
` + `- Decline access to paths outside ${taskCtx.workdir}.
|
|
263
|
+
` + `- If a PR was just created, respond to review & verify test plan items before completing.
|
|
264
|
+
` + `- When in doubt, escalate.
|
|
265
|
+
|
|
266
|
+
` + `Include a JSON action block at the end of your response:
|
|
267
|
+
` + "```json\n" + `{"action": "respond|complete|escalate|ignore", "response": "...", "useKeys": false, "keys": [], "reasoning": "..."}
|
|
268
|
+
` + "```";
|
|
130
269
|
}
|
|
131
270
|
function buildTurnCompleteEventMessage(taskCtx, turnOutput, decisionHistory) {
|
|
132
|
-
const historySection = decisionHistory.length > 0 ?
|
|
133
|
-
|
|
134
|
-
` +
|
|
135
|
-
`
|
|
136
|
-
`
|
|
271
|
+
const historySection = decisionHistory.length > 0 ? `
|
|
272
|
+
Previous decisions:
|
|
273
|
+
${decisionHistory.slice(-5).map((d, i) => ` ${i + 1}. [${d.event}] "${d.promptText}" → ${d.action}${d.response ? ` ("${d.response}")` : ""} — ${d.reasoning}`).join(`
|
|
274
|
+
`)}
|
|
275
|
+
` : "";
|
|
276
|
+
return `[Coding Agent Event] A ${taskCtx.agentType} agent ("${taskCtx.label}") just finished a turn and is idle.
|
|
277
|
+
|
|
278
|
+
` + `Task: "${taskCtx.originalTask}"
|
|
279
|
+
` + `Workdir: ${taskCtx.workdir}
|
|
280
|
+
` + `Repo: ${taskCtx.repo ?? "none (scratch directory)"}
|
|
281
|
+
` + historySection + `
|
|
282
|
+
Turn output:
|
|
283
|
+
---
|
|
284
|
+
${turnOutput.slice(-3000)}
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
` + `Decide if the overall task is done or if the agent needs more work.
|
|
137
288
|
|
|
138
|
-
` + `
|
|
289
|
+
` + `Options:
|
|
290
|
+
` + `- "respond" — send a follow-up instruction (DEFAULT for intermediate steps)
|
|
291
|
+
` + `- "complete" — ALL task objectives met (code written, committed, PR created & verified)
|
|
292
|
+
` + `- "escalate" — something looks wrong, ask the user
|
|
293
|
+
` + `- "ignore" — should not normally be used here
|
|
139
294
|
|
|
140
|
-
` + `
|
|
295
|
+
` + `Guidelines:
|
|
296
|
+
` + `- Verify evidence for EVERY objective before using "complete".
|
|
297
|
+
` + `- If code was written but not committed/pushed/PR'd, respond with next step.
|
|
298
|
+
` + `- If a PR was just created, respond to review & verify test plan items.
|
|
299
|
+
` + `- When asking agents to verify work, prefer CLI tools (gh, curl, cat, etc.) over browser automation.
|
|
300
|
+
` + `- Default to "respond" — only "complete" when certain ALL work is done.
|
|
301
|
+
|
|
302
|
+
` + `Include a JSON action block at the end of your response:
|
|
303
|
+
` + "```json\n" + `{"action": "respond|complete|escalate|ignore", "response": "...", "useKeys": false, "keys": [], "reasoning": "..."}
|
|
304
|
+
` + "```";
|
|
141
305
|
}
|
|
142
306
|
function parseCoordinationResponse(llmOutput) {
|
|
143
307
|
const jsonMatch = llmOutput.match(/\{[\s\S]*\}/);
|
|
@@ -169,7 +333,7 @@ function parseCoordinationResponse(llmOutput) {
|
|
|
169
333
|
}
|
|
170
334
|
|
|
171
335
|
// src/services/swarm-event-triage.ts
|
|
172
|
-
import {ModelType as ModelType2} from "@elizaos/core";
|
|
336
|
+
import { ModelType as ModelType2 } from "@elizaos/core";
|
|
173
337
|
function classifyByHeuristic(ctx) {
|
|
174
338
|
if (ctx.promptType) {
|
|
175
339
|
if (ROUTINE_PROMPT_TYPES.has(ctx.promptType))
|
|
@@ -196,8 +360,17 @@ function classifyByHeuristic(ctx) {
|
|
|
196
360
|
return null;
|
|
197
361
|
}
|
|
198
362
|
function buildTriagePrompt(ctx) {
|
|
199
|
-
const eventDesc = ctx.eventType === "blocked" ? `BLOCKED prompt: "${ctx.promptText.slice(0, 300)}"` : `TURN COMPLETE. Recent output
|
|
200
|
-
|
|
363
|
+
const eventDesc = ctx.eventType === "blocked" ? `BLOCKED prompt: "${ctx.promptText.slice(0, 300)}"` : `TURN COMPLETE. Recent output:
|
|
364
|
+
${(ctx.recentOutput ?? "").slice(-500)}`;
|
|
365
|
+
return `Classify this coding agent event as "routine" or "creative".
|
|
366
|
+
|
|
367
|
+
` + `Task: ${ctx.originalTask.slice(0, 200)}
|
|
368
|
+
` + `Event: ${eventDesc}
|
|
369
|
+
|
|
370
|
+
` + `"routine" = simple approval, permission, config, yes/no, tool consent, obvious pass/fail.
|
|
371
|
+
` + `"creative" = needs task context, error recovery, design choice, ambiguous situation, approach selection.
|
|
372
|
+
|
|
373
|
+
` + `Respond with ONLY a JSON object: {"tier": "routine"} or {"tier": "creative"}`;
|
|
201
374
|
}
|
|
202
375
|
function parseTriageResponse(llmOutput) {
|
|
203
376
|
const matches = llmOutput.matchAll(/\{[\s\S]*?\}/g);
|
|
@@ -207,15 +380,14 @@ function parseTriageResponse(llmOutput) {
|
|
|
207
380
|
if (parsed.tier === "routine" || parsed.tier === "creative") {
|
|
208
381
|
return parsed.tier;
|
|
209
382
|
}
|
|
210
|
-
} catch {
|
|
211
|
-
}
|
|
383
|
+
} catch {}
|
|
212
384
|
}
|
|
213
385
|
return null;
|
|
214
386
|
}
|
|
215
387
|
async function classifyEventTier(runtime, ctx, log) {
|
|
216
388
|
const heuristicResult = classifyByHeuristic(ctx);
|
|
217
389
|
if (heuristicResult) {
|
|
218
|
-
log(`Triage: heuristic
|
|
390
|
+
log(`Triage: heuristic → ${heuristicResult}`);
|
|
219
391
|
return heuristicResult;
|
|
220
392
|
}
|
|
221
393
|
try {
|
|
@@ -223,12 +395,12 @@ async function classifyEventTier(runtime, ctx, log) {
|
|
|
223
395
|
const result = await runtime.useModel(ModelType2.TEXT_SMALL, { prompt });
|
|
224
396
|
const tier = parseTriageResponse(result);
|
|
225
397
|
if (tier) {
|
|
226
|
-
log(`Triage: LLM
|
|
398
|
+
log(`Triage: LLM → ${tier}`);
|
|
227
399
|
return tier;
|
|
228
400
|
}
|
|
229
|
-
log(`Triage: LLM returned unparseable response
|
|
401
|
+
log(`Triage: LLM returned unparseable response — defaulting to creative`);
|
|
230
402
|
} catch (err) {
|
|
231
|
-
log(`Triage: LLM classifier failed: ${err}
|
|
403
|
+
log(`Triage: LLM classifier failed: ${err} — defaulting to creative`);
|
|
232
404
|
}
|
|
233
405
|
return "creative";
|
|
234
406
|
}
|
|
@@ -298,7 +470,7 @@ __export(exports_swarm_decision_loop, {
|
|
|
298
470
|
checkAllTasksComplete: () => checkAllTasksComplete
|
|
299
471
|
});
|
|
300
472
|
import * as path from "node:path";
|
|
301
|
-
import {ModelType as ModelType3} from "@elizaos/core";
|
|
473
|
+
import { ModelType as ModelType3 } from "@elizaos/core";
|
|
302
474
|
function toContextSummary(taskCtx) {
|
|
303
475
|
return {
|
|
304
476
|
sessionId: taskCtx.sessionId,
|
|
@@ -422,10 +594,11 @@ async function executeDecision(ctx, sessionId, decision) {
|
|
|
422
594
|
try {
|
|
423
595
|
const rawOutput = await ctx.ptyService.getSessionOutput(sessionId, 50);
|
|
424
596
|
summary = extractCompletionSummary(rawOutput);
|
|
425
|
-
} catch {
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
|
|
597
|
+
} catch {}
|
|
598
|
+
ctx.sendChatMessage(summary ? `Finished "${taskCtx?.label ?? sessionId}".
|
|
599
|
+
|
|
600
|
+
${summary}` : `Finished "${taskCtx?.label ?? sessionId}".`, "coding-agent");
|
|
601
|
+
ctx.ptyService.stopSession(sessionId, true).catch((err) => {
|
|
429
602
|
ctx.log(`Failed to stop session after LLM-detected completion: ${err}`);
|
|
430
603
|
});
|
|
431
604
|
checkAllTasksComplete(ctx);
|
|
@@ -469,7 +642,7 @@ async function handleBlocked(ctx, sessionId, taskCtx, data) {
|
|
|
469
642
|
});
|
|
470
643
|
ctx.sendChatMessage(`[${taskCtx.label}] WARNING: Auto-approved access to path outside workspace (${taskCtx.workdir}). ` + `Prompt: "${promptText.slice(0, 150)}". Stopping session for safety.`, "coding-agent");
|
|
471
644
|
taskCtx.status = "error";
|
|
472
|
-
ctx.ptyService?.stopSession(sessionId).catch((err) => {
|
|
645
|
+
ctx.ptyService?.stopSession(sessionId, true).catch((err) => {
|
|
473
646
|
ctx.log(`Failed to stop session after out-of-scope auto-approval: ${err}`);
|
|
474
647
|
});
|
|
475
648
|
return;
|
|
@@ -541,7 +714,7 @@ async function handleBlocked(ctx, sessionId, taskCtx, data) {
|
|
|
541
714
|
event: "blocked",
|
|
542
715
|
promptText,
|
|
543
716
|
decision: "escalate",
|
|
544
|
-
reasoning: "Supervision level is notify
|
|
717
|
+
reasoning: "Supervision level is notify — broadcasting only"
|
|
545
718
|
});
|
|
546
719
|
break;
|
|
547
720
|
}
|
|
@@ -553,7 +726,7 @@ async function handleTurnComplete(ctx, sessionId, taskCtx, data) {
|
|
|
553
726
|
}
|
|
554
727
|
ctx.inFlightDecisions.add(sessionId);
|
|
555
728
|
try {
|
|
556
|
-
ctx.log(`Turn complete for "${taskCtx.label}"
|
|
729
|
+
ctx.log(`Turn complete for "${taskCtx.label}" — assessing whether task is done`);
|
|
557
730
|
const rawResponse = data.response ?? "";
|
|
558
731
|
let turnOutput = cleanForChat(rawResponse);
|
|
559
732
|
if (!turnOutput) {
|
|
@@ -588,7 +761,7 @@ async function handleTurnComplete(ctx, sessionId, taskCtx, data) {
|
|
|
588
761
|
if (decision)
|
|
589
762
|
decisionFromPipeline = true;
|
|
590
763
|
} catch (err) {
|
|
591
|
-
ctx.log(`Agent decision callback failed for turn-complete: ${err}
|
|
764
|
+
ctx.log(`Agent decision callback failed for turn-complete: ${err} — falling back to small LLM`);
|
|
592
765
|
}
|
|
593
766
|
}
|
|
594
767
|
if (!decision) {
|
|
@@ -604,13 +777,13 @@ async function handleTurnComplete(ctx, sessionId, taskCtx, data) {
|
|
|
604
777
|
}
|
|
605
778
|
}
|
|
606
779
|
if (!decision) {
|
|
607
|
-
ctx.log(`Turn-complete for "${taskCtx.label}": all decision paths failed
|
|
780
|
+
ctx.log(`Turn-complete for "${taskCtx.label}": all decision paths failed — escalating`);
|
|
608
781
|
decision = {
|
|
609
782
|
action: "escalate",
|
|
610
|
-
reasoning: "All decision paths returned invalid response
|
|
783
|
+
reasoning: "All decision paths returned invalid response — escalating for human review"
|
|
611
784
|
};
|
|
612
785
|
}
|
|
613
|
-
ctx.log(`Turn assessment for "${taskCtx.label}": ${decision.action}${decision.action === "respond" ? `
|
|
786
|
+
ctx.log(`Turn assessment for "${taskCtx.label}": ${decision.action}${decision.action === "respond" ? ` → "${(decision.response ?? "").slice(0, 80)}"` : ""} — ${decision.reasoning.slice(0, 120)}`);
|
|
614
787
|
taskCtx.decisions.push({
|
|
615
788
|
timestamp: Date.now(),
|
|
616
789
|
event: "turn_complete",
|
|
@@ -634,7 +807,7 @@ async function handleTurnComplete(ctx, sessionId, taskCtx, data) {
|
|
|
634
807
|
const preview = instruction.length > 120 ? `${instruction.slice(0, 120)}...` : instruction;
|
|
635
808
|
ctx.sendChatMessage(`[${taskCtx.label}] Turn done, continuing: ${preview}`, "coding-agent");
|
|
636
809
|
} else if (decision.action === "escalate") {
|
|
637
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Turn finished
|
|
810
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Turn finished — needs your attention: ${decision.reasoning}`, "coding-agent");
|
|
638
811
|
}
|
|
639
812
|
}
|
|
640
813
|
await executeDecision(ctx, sessionId, decision);
|
|
@@ -674,7 +847,7 @@ async function handleAutonomousDecision(ctx, sessionId, taskCtx, promptText, rec
|
|
|
674
847
|
if (decision)
|
|
675
848
|
decisionFromPipeline = true;
|
|
676
849
|
} catch (err) {
|
|
677
|
-
ctx.log(`Agent decision callback failed: ${err}
|
|
850
|
+
ctx.log(`Agent decision callback failed: ${err} — falling back to small LLM`);
|
|
678
851
|
}
|
|
679
852
|
}
|
|
680
853
|
if (!decision) {
|
|
@@ -703,7 +876,7 @@ async function handleAutonomousDecision(ctx, sessionId, taskCtx, promptText, rec
|
|
|
703
876
|
if (decision.action === "respond" && isOutOfScopeAccess(promptText, taskCtx.workdir)) {
|
|
704
877
|
decision = {
|
|
705
878
|
action: "respond",
|
|
706
|
-
response: `No
|
|
879
|
+
response: `No — that path is outside your workspace. Use ${taskCtx.workdir} instead. Create any files or directories you need there.`,
|
|
707
880
|
reasoning: `Declined out-of-scope access (outside ${taskCtx.workdir}) and redirected agent to workspace.`
|
|
708
881
|
};
|
|
709
882
|
ctx.sendChatMessage(`[${taskCtx.label}] Declined out-of-scope access and redirected to workspace (${taskCtx.workdir}). If you intended broader access, send the agent an override.`, "coding-agent");
|
|
@@ -733,7 +906,7 @@ async function handleAutonomousDecision(ctx, sessionId, taskCtx, promptText, rec
|
|
|
733
906
|
if (decision.action === "respond") {
|
|
734
907
|
const actionDesc = decision.useKeys ? `Sent keys: ${decision.keys?.join(", ")}` : decision.response ? `Responded: ${decision.response.length > 100 ? `${decision.response.slice(0, 100)}...` : decision.response}` : "Responded";
|
|
735
908
|
const reasonExcerpt = decision.reasoning.length > 150 ? `${decision.reasoning.slice(0, 150)}...` : decision.reasoning;
|
|
736
|
-
ctx.sendChatMessage(`[${taskCtx.label}] ${actionDesc}
|
|
909
|
+
ctx.sendChatMessage(`[${taskCtx.label}] ${actionDesc} — ${reasonExcerpt}`, "coding-agent");
|
|
737
910
|
} else if (decision.action === "escalate") {
|
|
738
911
|
ctx.sendChatMessage(`[${taskCtx.label}] Needs your attention: ${decision.reasoning}`, "coding-agent");
|
|
739
912
|
}
|
|
@@ -773,7 +946,7 @@ async function handleConfirmDecision(ctx, sessionId, taskCtx, promptText, recent
|
|
|
773
946
|
if (decision)
|
|
774
947
|
decisionFromPipeline = true;
|
|
775
948
|
} catch (err) {
|
|
776
|
-
ctx.log(`Agent decision callback failed (confirm): ${err}
|
|
949
|
+
ctx.log(`Agent decision callback failed (confirm): ${err} — falling back to small LLM`);
|
|
777
950
|
}
|
|
778
951
|
}
|
|
779
952
|
if (!decision) {
|
|
@@ -787,7 +960,7 @@ async function handleConfirmDecision(ctx, sessionId, taskCtx, promptText, recent
|
|
|
787
960
|
recentOutput: output,
|
|
788
961
|
llmDecision: {
|
|
789
962
|
action: "escalate",
|
|
790
|
-
reasoning: "All decision paths returned invalid response
|
|
963
|
+
reasoning: "All decision paths returned invalid response — needs human review"
|
|
791
964
|
},
|
|
792
965
|
taskContext: taskCtx,
|
|
793
966
|
createdAt: Date.now()
|
|
@@ -911,7 +1084,9 @@ var finalizeWorkspaceAction = {
|
|
|
911
1084
|
data: { workspaceId, status }
|
|
912
1085
|
};
|
|
913
1086
|
}
|
|
914
|
-
const commitMessage = content.commitMessage ?? `feat: automated changes from coding agent
|
|
1087
|
+
const commitMessage = content.commitMessage ?? `feat: automated changes from coding agent
|
|
1088
|
+
|
|
1089
|
+
Generated by Milady coding agent plugin.`;
|
|
915
1090
|
const commitHash = await workspaceService.commit(workspaceId, {
|
|
916
1091
|
message: commitMessage,
|
|
917
1092
|
all: true
|
|
@@ -920,7 +1095,15 @@ var finalizeWorkspaceAction = {
|
|
|
920
1095
|
let prInfo = null;
|
|
921
1096
|
if (!content.skipPR) {
|
|
922
1097
|
const prTitle = content.prTitle ?? `[Milady] ${workspace.branch}`;
|
|
923
|
-
const prBody = content.prBody ?? `## Summary
|
|
1098
|
+
const prBody = content.prBody ?? `## Summary
|
|
1099
|
+
|
|
1100
|
+
Automated changes generated by Milady coding agent.
|
|
1101
|
+
|
|
1102
|
+
` + `**Branch:** ${workspace.branch}
|
|
1103
|
+
` + `**Commit:** ${commitHash}
|
|
1104
|
+
|
|
1105
|
+
` + `---
|
|
1106
|
+
*Generated by @elizaos/plugin-agent-orchestrator*`;
|
|
924
1107
|
prInfo = await workspaceService.createPR(workspaceId, {
|
|
925
1108
|
title: prTitle,
|
|
926
1109
|
body: prBody,
|
|
@@ -931,11 +1114,14 @@ var finalizeWorkspaceAction = {
|
|
|
931
1114
|
if (callback) {
|
|
932
1115
|
if (prInfo) {
|
|
933
1116
|
await callback({
|
|
934
|
-
text: `Workspace finalized
|
|
1117
|
+
text: `Workspace finalized!
|
|
1118
|
+
` + `Commit: ${commitHash.slice(0, 8)}
|
|
1119
|
+
` + `PR #${prInfo.number}: ${prInfo.url}`
|
|
935
1120
|
});
|
|
936
1121
|
} else {
|
|
937
1122
|
await callback({
|
|
938
|
-
text: `Workspace changes committed and pushed
|
|
1123
|
+
text: `Workspace changes committed and pushed.
|
|
1124
|
+
` + `Commit: ${commitHash.slice(0, 8)}`
|
|
939
1125
|
});
|
|
940
1126
|
}
|
|
941
1127
|
}
|
|
@@ -1079,18 +1265,23 @@ var listAgentsAction = {
|
|
|
1079
1265
|
}));
|
|
1080
1266
|
const lines = sessions.map((session, index) => {
|
|
1081
1267
|
const statusEmoji = {
|
|
1082
|
-
running: "
|
|
1083
|
-
idle: "
|
|
1084
|
-
blocked: "
|
|
1085
|
-
completed: "
|
|
1086
|
-
error: "
|
|
1087
|
-
}[session.status] ?? "
|
|
1268
|
+
running: "▶️",
|
|
1269
|
+
idle: "⏸️",
|
|
1270
|
+
blocked: "⚠️",
|
|
1271
|
+
completed: "✅",
|
|
1272
|
+
error: "❌"
|
|
1273
|
+
}[session.status] ?? "❓";
|
|
1088
1274
|
return `${index + 1}. ${statusEmoji} ${session.agentType} (${session.id.slice(0, 8)}...)
|
|
1089
|
-
\uD83D\uDCC1 ${session.workdir}
|
|
1275
|
+
\uD83D\uDCC1 ${session.workdir}
|
|
1276
|
+
Status: ${session.status}`;
|
|
1090
1277
|
});
|
|
1091
1278
|
if (callback) {
|
|
1092
1279
|
await callback({
|
|
1093
|
-
text: `Active coding agents
|
|
1280
|
+
text: `Active coding agents:
|
|
1281
|
+
|
|
1282
|
+
${lines.join(`
|
|
1283
|
+
|
|
1284
|
+
`)}`
|
|
1094
1285
|
});
|
|
1095
1286
|
}
|
|
1096
1287
|
return {
|
|
@@ -1103,6 +1294,150 @@ var listAgentsAction = {
|
|
|
1103
1294
|
};
|
|
1104
1295
|
|
|
1105
1296
|
// src/actions/manage-issues.ts
|
|
1297
|
+
var manageIssuesAction = {
|
|
1298
|
+
name: "MANAGE_ISSUES",
|
|
1299
|
+
similes: [
|
|
1300
|
+
"CREATE_ISSUE",
|
|
1301
|
+
"LIST_ISSUES",
|
|
1302
|
+
"CLOSE_ISSUE",
|
|
1303
|
+
"COMMENT_ISSUE",
|
|
1304
|
+
"UPDATE_ISSUE",
|
|
1305
|
+
"GET_ISSUE"
|
|
1306
|
+
],
|
|
1307
|
+
description: "Manage GitHub issues for a repository. " + "Supports creating issues, listing issues, getting issue details, " + "adding comments, updating, closing, and reopening issues.",
|
|
1308
|
+
examples: [
|
|
1309
|
+
[
|
|
1310
|
+
{
|
|
1311
|
+
name: "{{user1}}",
|
|
1312
|
+
content: {
|
|
1313
|
+
text: "Create an issue on the testbed repo to add a login page"
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
name: "{{agentName}}",
|
|
1318
|
+
content: {
|
|
1319
|
+
text: "I'll create that issue for you.",
|
|
1320
|
+
action: "MANAGE_ISSUES"
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
],
|
|
1324
|
+
[
|
|
1325
|
+
{
|
|
1326
|
+
name: "{{user1}}",
|
|
1327
|
+
content: {
|
|
1328
|
+
text: "List the open issues on HaruHunab1320/git-workspace-service-testbed"
|
|
1329
|
+
}
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "{{agentName}}",
|
|
1333
|
+
content: {
|
|
1334
|
+
text: "Let me check the open issues for that repo.",
|
|
1335
|
+
action: "MANAGE_ISSUES"
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
],
|
|
1339
|
+
[
|
|
1340
|
+
{
|
|
1341
|
+
name: "{{user1}}",
|
|
1342
|
+
content: { text: "Close issue #3 on the testbed repo" }
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
name: "{{agentName}}",
|
|
1346
|
+
content: {
|
|
1347
|
+
text: "I'll close that issue.",
|
|
1348
|
+
action: "MANAGE_ISSUES"
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
]
|
|
1352
|
+
],
|
|
1353
|
+
validate: async (runtime, _message) => {
|
|
1354
|
+
const workspaceService = runtime.getService("CODING_WORKSPACE_SERVICE");
|
|
1355
|
+
return workspaceService != null;
|
|
1356
|
+
},
|
|
1357
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
1358
|
+
const workspaceService = runtime.getService("CODING_WORKSPACE_SERVICE");
|
|
1359
|
+
if (!workspaceService) {
|
|
1360
|
+
if (callback) {
|
|
1361
|
+
await callback({ text: "Workspace Service is not available." });
|
|
1362
|
+
}
|
|
1363
|
+
return { success: false, error: "SERVICE_UNAVAILABLE" };
|
|
1364
|
+
}
|
|
1365
|
+
workspaceService.setAuthPromptCallback((prompt) => {
|
|
1366
|
+
if (callback) {
|
|
1367
|
+
callback({
|
|
1368
|
+
text: `I need GitHub access to manage issues. Please authorize me:
|
|
1369
|
+
|
|
1370
|
+
` + `Go to: ${prompt.verificationUri}
|
|
1371
|
+
` + `Enter code: **${prompt.userCode}**
|
|
1372
|
+
|
|
1373
|
+
` + `This code expires in ${Math.floor(prompt.expiresIn / 60)} minutes. ` + `I'll wait for you to complete authorization...`
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
});
|
|
1377
|
+
const params = options?.parameters;
|
|
1378
|
+
const content = message.content;
|
|
1379
|
+
const text = content.text ?? "";
|
|
1380
|
+
const operation = params?.operation ?? content.operation ?? inferOperation(text);
|
|
1381
|
+
const repo = params?.repo ?? content.repo;
|
|
1382
|
+
if (!repo) {
|
|
1383
|
+
const urlMatch = text?.match(/(?:https?:\/\/github\.com\/)?([a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+)/);
|
|
1384
|
+
if (!urlMatch) {
|
|
1385
|
+
if (callback) {
|
|
1386
|
+
await callback({
|
|
1387
|
+
text: "Please specify a repository (e.g., owner/repo or a GitHub URL)."
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
return { success: false, error: "MISSING_REPO" };
|
|
1391
|
+
}
|
|
1392
|
+
return handleOperation(workspaceService, urlMatch[1], operation, params ?? content, text, callback);
|
|
1393
|
+
}
|
|
1394
|
+
return handleOperation(workspaceService, repo, operation, params ?? content, text, callback);
|
|
1395
|
+
},
|
|
1396
|
+
parameters: [
|
|
1397
|
+
{
|
|
1398
|
+
name: "operation",
|
|
1399
|
+
description: "The operation to perform: create, list, get, update, comment, close, reopen, add_labels",
|
|
1400
|
+
required: true,
|
|
1401
|
+
schema: { type: "string" }
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
name: "repo",
|
|
1405
|
+
description: "Repository in owner/repo format or full GitHub URL.",
|
|
1406
|
+
required: true,
|
|
1407
|
+
schema: { type: "string" }
|
|
1408
|
+
},
|
|
1409
|
+
{
|
|
1410
|
+
name: "title",
|
|
1411
|
+
description: "Issue title (for create operation).",
|
|
1412
|
+
required: false,
|
|
1413
|
+
schema: { type: "string" }
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
name: "body",
|
|
1417
|
+
description: "Issue body/description (for create or comment operations).",
|
|
1418
|
+
required: false,
|
|
1419
|
+
schema: { type: "string" }
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
name: "issueNumber",
|
|
1423
|
+
description: "Issue number (for get, update, comment, close, reopen operations).",
|
|
1424
|
+
required: false,
|
|
1425
|
+
schema: { type: "number" }
|
|
1426
|
+
},
|
|
1427
|
+
{
|
|
1428
|
+
name: "labels",
|
|
1429
|
+
description: "Labels to add (comma-separated string or array).",
|
|
1430
|
+
required: false,
|
|
1431
|
+
schema: { type: "string" }
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
name: "state",
|
|
1435
|
+
description: "Filter by state: open, closed, or all (for list operation).",
|
|
1436
|
+
required: false,
|
|
1437
|
+
schema: { type: "string" }
|
|
1438
|
+
}
|
|
1439
|
+
]
|
|
1440
|
+
};
|
|
1106
1441
|
async function handleOperation(service, repo, operation, params, originalText, callback) {
|
|
1107
1442
|
try {
|
|
1108
1443
|
switch (operation.toLowerCase()) {
|
|
@@ -1123,9 +1458,12 @@ async function handleOperation(service, repo, operation, params, originalText, c
|
|
|
1123
1458
|
created.push(issue2);
|
|
1124
1459
|
}
|
|
1125
1460
|
if (callback) {
|
|
1126
|
-
const summary = created.map((i) => `#${i.number}: ${i.title}
|
|
1461
|
+
const summary = created.map((i) => `#${i.number}: ${i.title}
|
|
1462
|
+
${i.url}`).join(`
|
|
1463
|
+
`);
|
|
1127
1464
|
await callback({
|
|
1128
|
-
text: `Created ${created.length} issues
|
|
1465
|
+
text: `Created ${created.length} issues:
|
|
1466
|
+
${summary}`
|
|
1129
1467
|
});
|
|
1130
1468
|
}
|
|
1131
1469
|
return { success: true, data: { issues: created } };
|
|
@@ -1142,7 +1480,8 @@ async function handleOperation(service, repo, operation, params, originalText, c
|
|
|
1142
1480
|
});
|
|
1143
1481
|
if (callback) {
|
|
1144
1482
|
await callback({
|
|
1145
|
-
text: `Created issue #${issue.number}: ${issue.title}
|
|
1483
|
+
text: `Created issue #${issue.number}: ${issue.title}
|
|
1484
|
+
${issue.url}`
|
|
1146
1485
|
});
|
|
1147
1486
|
}
|
|
1148
1487
|
return { success: true, data: { issue } };
|
|
@@ -1160,8 +1499,10 @@ async function handleOperation(service, repo, operation, params, originalText, c
|
|
|
1160
1499
|
text: `No ${stateFilter} issues found in ${repo}.`
|
|
1161
1500
|
});
|
|
1162
1501
|
} else {
|
|
1163
|
-
const summary = issues.map((i) => `#${i.number} [${i.state}] ${i.title}${i.labels.length > 0 ? ` (${i.labels.join(", ")})` : ""}`).join(
|
|
1164
|
-
|
|
1502
|
+
const summary = issues.map((i) => `#${i.number} [${i.state}] ${i.title}${i.labels.length > 0 ? ` (${i.labels.join(", ")})` : ""}`).join(`
|
|
1503
|
+
`);
|
|
1504
|
+
await callback({ text: `Issues in ${repo}:
|
|
1505
|
+
${summary}` });
|
|
1165
1506
|
}
|
|
1166
1507
|
}
|
|
1167
1508
|
return { success: true, data: { issues } };
|
|
@@ -1176,7 +1517,12 @@ async function handleOperation(service, repo, operation, params, originalText, c
|
|
|
1176
1517
|
const issue = await service.getIssue(repo, issueNumber);
|
|
1177
1518
|
if (callback) {
|
|
1178
1519
|
await callback({
|
|
1179
|
-
text: `Issue #${issue.number}: ${issue.title} [${issue.state}]
|
|
1520
|
+
text: `Issue #${issue.number}: ${issue.title} [${issue.state}]
|
|
1521
|
+
|
|
1522
|
+
${issue.body}
|
|
1523
|
+
|
|
1524
|
+
Labels: ${issue.labels.join(", ") || "none"}
|
|
1525
|
+
${issue.url}`
|
|
1180
1526
|
});
|
|
1181
1527
|
}
|
|
1182
1528
|
return { success: true, data: { issue } };
|
|
@@ -1345,145 +1691,6 @@ function parseLabels(input) {
|
|
|
1345
1691
|
return input.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1346
1692
|
return [];
|
|
1347
1693
|
}
|
|
1348
|
-
var manageIssuesAction = {
|
|
1349
|
-
name: "MANAGE_ISSUES",
|
|
1350
|
-
similes: [
|
|
1351
|
-
"CREATE_ISSUE",
|
|
1352
|
-
"LIST_ISSUES",
|
|
1353
|
-
"CLOSE_ISSUE",
|
|
1354
|
-
"COMMENT_ISSUE",
|
|
1355
|
-
"UPDATE_ISSUE",
|
|
1356
|
-
"GET_ISSUE"
|
|
1357
|
-
],
|
|
1358
|
-
description: "Manage GitHub issues for a repository. " + "Supports creating issues, listing issues, getting issue details, " + "adding comments, updating, closing, and reopening issues.",
|
|
1359
|
-
examples: [
|
|
1360
|
-
[
|
|
1361
|
-
{
|
|
1362
|
-
name: "{{user1}}",
|
|
1363
|
-
content: {
|
|
1364
|
-
text: "Create an issue on the testbed repo to add a login page"
|
|
1365
|
-
}
|
|
1366
|
-
},
|
|
1367
|
-
{
|
|
1368
|
-
name: "{{agentName}}",
|
|
1369
|
-
content: {
|
|
1370
|
-
text: "I'll create that issue for you.",
|
|
1371
|
-
action: "MANAGE_ISSUES"
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
],
|
|
1375
|
-
[
|
|
1376
|
-
{
|
|
1377
|
-
name: "{{user1}}",
|
|
1378
|
-
content: {
|
|
1379
|
-
text: "List the open issues on HaruHunab1320/git-workspace-service-testbed"
|
|
1380
|
-
}
|
|
1381
|
-
},
|
|
1382
|
-
{
|
|
1383
|
-
name: "{{agentName}}",
|
|
1384
|
-
content: {
|
|
1385
|
-
text: "Let me check the open issues for that repo.",
|
|
1386
|
-
action: "MANAGE_ISSUES"
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
],
|
|
1390
|
-
[
|
|
1391
|
-
{
|
|
1392
|
-
name: "{{user1}}",
|
|
1393
|
-
content: { text: "Close issue #3 on the testbed repo" }
|
|
1394
|
-
},
|
|
1395
|
-
{
|
|
1396
|
-
name: "{{agentName}}",
|
|
1397
|
-
content: {
|
|
1398
|
-
text: "I'll close that issue.",
|
|
1399
|
-
action: "MANAGE_ISSUES"
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
]
|
|
1403
|
-
],
|
|
1404
|
-
validate: async (runtime, _message) => {
|
|
1405
|
-
const workspaceService = runtime.getService("CODING_WORKSPACE_SERVICE");
|
|
1406
|
-
return workspaceService != null;
|
|
1407
|
-
},
|
|
1408
|
-
handler: async (runtime, message, _state, options, callback) => {
|
|
1409
|
-
const workspaceService = runtime.getService("CODING_WORKSPACE_SERVICE");
|
|
1410
|
-
if (!workspaceService) {
|
|
1411
|
-
if (callback) {
|
|
1412
|
-
await callback({ text: "Workspace Service is not available." });
|
|
1413
|
-
}
|
|
1414
|
-
return { success: false, error: "SERVICE_UNAVAILABLE" };
|
|
1415
|
-
}
|
|
1416
|
-
workspaceService.setAuthPromptCallback((prompt) => {
|
|
1417
|
-
if (callback) {
|
|
1418
|
-
callback({
|
|
1419
|
-
text: `I need GitHub access to manage issues. Please authorize me:\n\n` + `Go to: ${prompt.verificationUri}\n` + `Enter code: **${prompt.userCode}**\n\n` + `This code expires in ${Math.floor(prompt.expiresIn / 60)} minutes. ` + `I'll wait for you to complete authorization...`
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
});
|
|
1423
|
-
const params = options?.parameters;
|
|
1424
|
-
const content = message.content;
|
|
1425
|
-
const text = content.text ?? "";
|
|
1426
|
-
const operation = params?.operation ?? content.operation ?? inferOperation(text);
|
|
1427
|
-
const repo = params?.repo ?? content.repo;
|
|
1428
|
-
if (!repo) {
|
|
1429
|
-
const urlMatch = text?.match(/(?:https?:\/\/github\.com\/)?([a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+)/);
|
|
1430
|
-
if (!urlMatch) {
|
|
1431
|
-
if (callback) {
|
|
1432
|
-
await callback({
|
|
1433
|
-
text: "Please specify a repository (e.g., owner/repo or a GitHub URL)."
|
|
1434
|
-
});
|
|
1435
|
-
}
|
|
1436
|
-
return { success: false, error: "MISSING_REPO" };
|
|
1437
|
-
}
|
|
1438
|
-
return handleOperation(workspaceService, urlMatch[1], operation, params ?? content, text, callback);
|
|
1439
|
-
}
|
|
1440
|
-
return handleOperation(workspaceService, repo, operation, params ?? content, text, callback);
|
|
1441
|
-
},
|
|
1442
|
-
parameters: [
|
|
1443
|
-
{
|
|
1444
|
-
name: "operation",
|
|
1445
|
-
description: "The operation to perform: create, list, get, update, comment, close, reopen, add_labels",
|
|
1446
|
-
required: true,
|
|
1447
|
-
schema: { type: "string" }
|
|
1448
|
-
},
|
|
1449
|
-
{
|
|
1450
|
-
name: "repo",
|
|
1451
|
-
description: "Repository in owner/repo format or full GitHub URL.",
|
|
1452
|
-
required: true,
|
|
1453
|
-
schema: { type: "string" }
|
|
1454
|
-
},
|
|
1455
|
-
{
|
|
1456
|
-
name: "title",
|
|
1457
|
-
description: "Issue title (for create operation).",
|
|
1458
|
-
required: false,
|
|
1459
|
-
schema: { type: "string" }
|
|
1460
|
-
},
|
|
1461
|
-
{
|
|
1462
|
-
name: "body",
|
|
1463
|
-
description: "Issue body/description (for create or comment operations).",
|
|
1464
|
-
required: false,
|
|
1465
|
-
schema: { type: "string" }
|
|
1466
|
-
},
|
|
1467
|
-
{
|
|
1468
|
-
name: "issueNumber",
|
|
1469
|
-
description: "Issue number (for get, update, comment, close, reopen operations).",
|
|
1470
|
-
required: false,
|
|
1471
|
-
schema: { type: "number" }
|
|
1472
|
-
},
|
|
1473
|
-
{
|
|
1474
|
-
name: "labels",
|
|
1475
|
-
description: "Labels to add (comma-separated string or array).",
|
|
1476
|
-
required: false,
|
|
1477
|
-
schema: { type: "string" }
|
|
1478
|
-
},
|
|
1479
|
-
{
|
|
1480
|
-
name: "state",
|
|
1481
|
-
description: "Filter by state: open, closed, or all (for list operation).",
|
|
1482
|
-
required: false,
|
|
1483
|
-
schema: { type: "string" }
|
|
1484
|
-
}
|
|
1485
|
-
]
|
|
1486
|
-
};
|
|
1487
1694
|
|
|
1488
1695
|
// src/actions/provision-workspace.ts
|
|
1489
1696
|
var provisionWorkspaceAction = {
|
|
@@ -1596,7 +1803,9 @@ var provisionWorkspaceAction = {
|
|
|
1596
1803
|
}
|
|
1597
1804
|
if (callback) {
|
|
1598
1805
|
await callback({
|
|
1599
|
-
text: `Created workspace at ${workspace.path}
|
|
1806
|
+
text: `Created workspace at ${workspace.path}
|
|
1807
|
+
` + `Branch: ${workspace.branch}
|
|
1808
|
+
` + `Type: ${workspace.isWorktree ? "worktree" : "clone"}`
|
|
1600
1809
|
});
|
|
1601
1810
|
}
|
|
1602
1811
|
return {
|
|
@@ -1805,19 +2014,19 @@ var sendToAgentAction = {
|
|
|
1805
2014
|
import * as os from "node:os";
|
|
1806
2015
|
import * as path2 from "node:path";
|
|
1807
2016
|
import {
|
|
1808
|
-
logger as logger3
|
|
2017
|
+
logger as logger3
|
|
1809
2018
|
} from "@elizaos/core";
|
|
1810
2019
|
|
|
1811
2020
|
// src/services/pty-service.ts
|
|
1812
|
-
import {mkdir, readFile, writeFile} from "node:fs/promises";
|
|
1813
|
-
import {dirname, join} from "node:path";
|
|
1814
|
-
import {logger as logger2} from "@elizaos/core";
|
|
2021
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2022
|
+
import { dirname, join } from "node:path";
|
|
2023
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
1815
2024
|
import {
|
|
1816
|
-
checkAdapters,
|
|
1817
|
-
createAdapter,
|
|
1818
|
-
generateApprovalConfig
|
|
2025
|
+
checkAdapters,
|
|
2026
|
+
createAdapter,
|
|
2027
|
+
generateApprovalConfig
|
|
1819
2028
|
} from "coding-agent-adapters";
|
|
1820
|
-
import {PTYConsoleBridge} from "pty-console";
|
|
2029
|
+
import { PTYConsoleBridge } from "pty-console";
|
|
1821
2030
|
|
|
1822
2031
|
// src/services/agent-metrics.ts
|
|
1823
2032
|
class AgentMetricsTracker {
|
|
@@ -1873,6 +2082,7 @@ function computeAgentScore(metrics) {
|
|
|
1873
2082
|
const speedPenalty = Math.min(avgCompletionMs / 300000, 1) * 0.1;
|
|
1874
2083
|
return Math.max(0, successRate - stallPenalty - speedPenalty);
|
|
1875
2084
|
}
|
|
2085
|
+
var DEFAULT_ORDER = ["claude", "gemini", "codex", "aider"];
|
|
1876
2086
|
function selectAgentType(ctx) {
|
|
1877
2087
|
if (ctx.config.strategy === "fixed") {
|
|
1878
2088
|
return ctx.config.fixedAgentType;
|
|
@@ -1894,7 +2104,6 @@ function selectAgentType(ctx) {
|
|
|
1894
2104
|
}
|
|
1895
2105
|
return bestAgent;
|
|
1896
2106
|
}
|
|
1897
|
-
var DEFAULT_ORDER = ["claude", "gemini", "codex", "aider"];
|
|
1898
2107
|
|
|
1899
2108
|
// src/services/pty-auto-response.ts
|
|
1900
2109
|
async function pushDefaultRules(ctx, sessionId, agentType) {
|
|
@@ -1972,14 +2181,27 @@ async function handleGeminiAuth(ctx, sessionId, sendKeysToSession) {
|
|
|
1972
2181
|
|
|
1973
2182
|
// src/services/pty-init.ts
|
|
1974
2183
|
init_ansi_utils();
|
|
1975
|
-
import {createRequire as createRequire2} from "node:module";
|
|
1976
|
-
import {createAllAdapters} from "coding-agent-adapters";
|
|
2184
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
2185
|
+
import { createAllAdapters } from "coding-agent-adapters";
|
|
1977
2186
|
import {
|
|
1978
|
-
BunCompatiblePTYManager,
|
|
1979
|
-
isBun,
|
|
1980
|
-
PTYManager,
|
|
1981
|
-
ShellAdapter
|
|
2187
|
+
BunCompatiblePTYManager,
|
|
2188
|
+
isBun,
|
|
2189
|
+
PTYManager,
|
|
2190
|
+
ShellAdapter
|
|
1982
2191
|
} from "pty-manager";
|
|
2192
|
+
var _require = createRequire2(import.meta.url);
|
|
2193
|
+
var resolvedAdapterModule = "coding-agent-adapters";
|
|
2194
|
+
try {
|
|
2195
|
+
resolvedAdapterModule = _require.resolve("coding-agent-adapters");
|
|
2196
|
+
} catch {}
|
|
2197
|
+
function forwardReadyAsTaskComplete(ctx, session) {
|
|
2198
|
+
if (!ctx.hasActiveTask?.(session.id) || !ctx.hasTaskActivity?.(session.id)) {
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2201
|
+
const response = ctx.taskResponseMarkers.has(session.id) ? captureTaskResponse(session.id, ctx.sessionOutputBuffers, ctx.taskResponseMarkers) : "";
|
|
2202
|
+
ctx.log(`session_ready for active task ${session.id} — forwarding as task_complete (stall classifier path, response: ${response.length} chars)`);
|
|
2203
|
+
ctx.emitEvent(session.id, "task_complete", { session, response });
|
|
2204
|
+
}
|
|
1983
2205
|
async function initializePTYManager(ctx) {
|
|
1984
2206
|
const usingBunWorker = isBun();
|
|
1985
2207
|
if (usingBunWorker) {
|
|
@@ -1996,11 +2218,7 @@ async function initializePTYManager(ctx) {
|
|
|
1996
2218
|
bunManager.on("session_ready", (session) => {
|
|
1997
2219
|
ctx.log(`session_ready event received for ${session.id} (type: ${session.type}, status: ${session.status})`);
|
|
1998
2220
|
ctx.emitEvent(session.id, "ready", { session });
|
|
1999
|
-
|
|
2000
|
-
const response = captureTaskResponse(session.id, ctx.sessionOutputBuffers, ctx.taskResponseMarkers);
|
|
2001
|
-
ctx.log(`session_ready for active task ${session.id} \u2014 forwarding as task_complete (stall classifier path)`);
|
|
2002
|
-
ctx.emitEvent(session.id, "task_complete", { session, response });
|
|
2003
|
-
}
|
|
2221
|
+
forwardReadyAsTaskComplete(ctx, session);
|
|
2004
2222
|
});
|
|
2005
2223
|
bunManager.on("session_exit", (id, code) => {
|
|
2006
2224
|
ctx.emitEvent(id, "stopped", { reason: `exit code ${code}` });
|
|
@@ -2027,7 +2245,7 @@ async function initializePTYManager(ctx) {
|
|
|
2027
2245
|
ctx.emitEvent(session.id, "task_complete", { session, response });
|
|
2028
2246
|
});
|
|
2029
2247
|
bunManager.on("tool_running", (session, info) => {
|
|
2030
|
-
ctx.log(`tool_running for ${session.id}: ${info.toolName}${info.description ? `
|
|
2248
|
+
ctx.log(`tool_running for ${session.id}: ${info.toolName}${info.description ? ` — ${info.description}` : ""}`);
|
|
2031
2249
|
ctx.emitEvent(session.id, "tool_running", { session, ...info });
|
|
2032
2250
|
});
|
|
2033
2251
|
bunManager.on("message", (message) => {
|
|
@@ -2079,11 +2297,7 @@ async function initializePTYManager(ctx) {
|
|
|
2079
2297
|
}
|
|
2080
2298
|
nodeManager.on("session_ready", (session) => {
|
|
2081
2299
|
ctx.emitEvent(session.id, "ready", { session });
|
|
2082
|
-
|
|
2083
|
-
const response = captureTaskResponse(session.id, ctx.sessionOutputBuffers, ctx.taskResponseMarkers);
|
|
2084
|
-
ctx.log(`session_ready for active task ${session.id} \u2014 forwarding as task_complete (stall classifier path)`);
|
|
2085
|
-
ctx.emitEvent(session.id, "task_complete", { session, response });
|
|
2086
|
-
}
|
|
2300
|
+
forwardReadyAsTaskComplete(ctx, session);
|
|
2087
2301
|
});
|
|
2088
2302
|
nodeManager.on("blocking_prompt", (session, promptInfo, autoResponded) => {
|
|
2089
2303
|
ctx.emitEvent(session.id, "blocked", { promptInfo, autoResponded });
|
|
@@ -2102,7 +2316,7 @@ async function initializePTYManager(ctx) {
|
|
|
2102
2316
|
ctx.emitEvent(session.id, "task_complete", { session, response });
|
|
2103
2317
|
});
|
|
2104
2318
|
nodeManager.on("tool_running", (session, info) => {
|
|
2105
|
-
ctx.log(`tool_running for ${session.id}: ${info.toolName}${info.description ? `
|
|
2319
|
+
ctx.log(`tool_running for ${session.id}: ${info.toolName}${info.description ? ` — ${info.description}` : ""}`);
|
|
2106
2320
|
ctx.emitEvent(session.id, "tool_running", { session, ...info });
|
|
2107
2321
|
});
|
|
2108
2322
|
nodeManager.on("session_stopped", (session, reason) => {
|
|
@@ -2116,12 +2330,6 @@ async function initializePTYManager(ctx) {
|
|
|
2116
2330
|
});
|
|
2117
2331
|
return { manager: nodeManager, usingBunWorker: false };
|
|
2118
2332
|
}
|
|
2119
|
-
var _require = createRequire2(import.meta.url);
|
|
2120
|
-
var resolvedAdapterModule = "coding-agent-adapters";
|
|
2121
|
-
try {
|
|
2122
|
-
resolvedAdapterModule = _require.resolve("coding-agent-adapters");
|
|
2123
|
-
} catch {
|
|
2124
|
-
}
|
|
2125
2333
|
|
|
2126
2334
|
// src/services/pty-session-io.ts
|
|
2127
2335
|
async function sendToSession(ctx, sessionId, input) {
|
|
@@ -2151,26 +2359,39 @@ async function sendKeysToSession(ctx, sessionId, keys) {
|
|
|
2151
2359
|
ptySession.sendKeys(keys);
|
|
2152
2360
|
}
|
|
2153
2361
|
}
|
|
2154
|
-
async function stopSession(ctx, sessionId, sessionMetadata, sessionWorkdirs, log) {
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2362
|
+
async function stopSession(ctx, sessionId, sessionMetadata, sessionWorkdirs, log, force = false) {
|
|
2363
|
+
try {
|
|
2364
|
+
const session = ctx.manager.get(sessionId);
|
|
2365
|
+
if (!session) {
|
|
2366
|
+
throw new Error(`Session ${sessionId} not found`);
|
|
2367
|
+
}
|
|
2368
|
+
if (ctx.usingBunWorker) {
|
|
2369
|
+
if (force) {
|
|
2370
|
+
await ctx.manager.kill(sessionId, "SIGKILL");
|
|
2371
|
+
} else {
|
|
2372
|
+
await ctx.manager.kill(sessionId);
|
|
2373
|
+
}
|
|
2374
|
+
} else {
|
|
2375
|
+
if (force) {
|
|
2376
|
+
await ctx.manager.stop(sessionId, { force: true });
|
|
2377
|
+
} else {
|
|
2378
|
+
await ctx.manager.stop(sessionId);
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
} finally {
|
|
2382
|
+
try {
|
|
2383
|
+
const unsubscribe = ctx.outputUnsubscribers.get(sessionId);
|
|
2384
|
+
if (unsubscribe) {
|
|
2385
|
+
unsubscribe();
|
|
2386
|
+
}
|
|
2387
|
+
} catch {}
|
|
2167
2388
|
ctx.outputUnsubscribers.delete(sessionId);
|
|
2389
|
+
sessionMetadata.delete(sessionId);
|
|
2390
|
+
sessionWorkdirs.delete(sessionId);
|
|
2391
|
+
ctx.sessionOutputBuffers.delete(sessionId);
|
|
2392
|
+
ctx.taskResponseMarkers.delete(sessionId);
|
|
2393
|
+
log(`Stopped session ${sessionId}`);
|
|
2168
2394
|
}
|
|
2169
|
-
sessionMetadata.delete(sessionId);
|
|
2170
|
-
sessionWorkdirs.delete(sessionId);
|
|
2171
|
-
ctx.sessionOutputBuffers.delete(sessionId);
|
|
2172
|
-
ctx.taskResponseMarkers.delete(sessionId);
|
|
2173
|
-
log(`Stopped session ${sessionId}`);
|
|
2174
2395
|
}
|
|
2175
2396
|
function subscribeToOutput(ctx, sessionId, callback) {
|
|
2176
2397
|
if (ctx.usingBunWorker) {
|
|
@@ -2193,7 +2414,8 @@ async function getSessionOutput(ctx, sessionId, lines) {
|
|
|
2193
2414
|
if (!buffer)
|
|
2194
2415
|
return "";
|
|
2195
2416
|
const tail = lines ?? buffer.length;
|
|
2196
|
-
return buffer.slice(-tail).join(
|
|
2417
|
+
return buffer.slice(-tail).join(`
|
|
2418
|
+
`);
|
|
2197
2419
|
}
|
|
2198
2420
|
const output = [];
|
|
2199
2421
|
for await (const line of ctx.manager.logs(sessionId, {
|
|
@@ -2201,10 +2423,26 @@ async function getSessionOutput(ctx, sessionId, lines) {
|
|
|
2201
2423
|
})) {
|
|
2202
2424
|
output.push(line);
|
|
2203
2425
|
}
|
|
2204
|
-
return output.join(
|
|
2426
|
+
return output.join(`
|
|
2427
|
+
`);
|
|
2205
2428
|
}
|
|
2206
2429
|
|
|
2207
2430
|
// src/services/pty-spawn.ts
|
|
2431
|
+
var ENV_ALLOWLIST = [
|
|
2432
|
+
"PATH",
|
|
2433
|
+
"HOME",
|
|
2434
|
+
"USER",
|
|
2435
|
+
"SHELL",
|
|
2436
|
+
"LANG",
|
|
2437
|
+
"LC_ALL",
|
|
2438
|
+
"LC_CTYPE",
|
|
2439
|
+
"TERM",
|
|
2440
|
+
"TZ",
|
|
2441
|
+
"TMPDIR",
|
|
2442
|
+
"XDG_RUNTIME_DIR",
|
|
2443
|
+
"NODE_OPTIONS",
|
|
2444
|
+
"BUN_INSTALL"
|
|
2445
|
+
];
|
|
2208
2446
|
function buildSanitizedBaseEnv() {
|
|
2209
2447
|
const env = {};
|
|
2210
2448
|
for (const key of ENV_ALLOWLIST) {
|
|
@@ -2218,7 +2456,8 @@ function setupOutputBuffer(ctx, sessionId) {
|
|
|
2218
2456
|
const buffer = [];
|
|
2219
2457
|
ctx.sessionOutputBuffers.set(sessionId, buffer);
|
|
2220
2458
|
const unsubscribe = ctx.manager.onSessionData(sessionId, (data) => {
|
|
2221
|
-
const lines = data.split(
|
|
2459
|
+
const lines = data.split(`
|
|
2460
|
+
`);
|
|
2222
2461
|
buffer.push(...lines);
|
|
2223
2462
|
while (buffer.length > (ctx.serviceConfig.maxLogLines ?? 1000)) {
|
|
2224
2463
|
buffer.shift();
|
|
@@ -2241,17 +2480,17 @@ function setupDeferredTaskDelivery(ctx, session, task, agentType) {
|
|
|
2241
2480
|
const sendTaskWithRetry = (attempt) => {
|
|
2242
2481
|
const buffer = ctx.sessionOutputBuffers.get(sid);
|
|
2243
2482
|
const baselineLength = buffer?.length ?? 0;
|
|
2244
|
-
ctx.log(`Session ${sid}
|
|
2483
|
+
ctx.log(`Session ${sid} — sending task (attempt ${attempt + 1}, ${settleMs}ms settle, baseline ${baselineLength} lines)`);
|
|
2245
2484
|
ctx.sendToSession(sid, task).catch((err) => ctx.log(`Failed to send deferred task to ${sid}: ${err}`));
|
|
2246
2485
|
if (attempt < MAX_RETRIES) {
|
|
2247
2486
|
setTimeout(() => {
|
|
2248
2487
|
const currentLength = buffer?.length ?? 0;
|
|
2249
2488
|
const newLines = currentLength - baselineLength;
|
|
2250
2489
|
if (newLines < MIN_NEW_LINES) {
|
|
2251
|
-
ctx.log(`Session ${sid}
|
|
2490
|
+
ctx.log(`Session ${sid} — task may not have been accepted (only ${newLines} new lines after ${VERIFY_DELAY_MS}ms). Retrying (attempt ${attempt + 2}/${MAX_RETRIES + 1})`);
|
|
2252
2491
|
sendTaskWithRetry(attempt + 1);
|
|
2253
2492
|
} else {
|
|
2254
|
-
ctx.log(`Session ${sid}
|
|
2493
|
+
ctx.log(`Session ${sid} — task accepted (${newLines} new lines after ${VERIFY_DELAY_MS}ms)`);
|
|
2255
2494
|
}
|
|
2256
2495
|
}, VERIFY_DELAY_MS);
|
|
2257
2496
|
}
|
|
@@ -2315,21 +2554,6 @@ function buildSpawnConfig(sessionId, options, workdir) {
|
|
|
2315
2554
|
}
|
|
2316
2555
|
};
|
|
2317
2556
|
}
|
|
2318
|
-
var ENV_ALLOWLIST = [
|
|
2319
|
-
"PATH",
|
|
2320
|
-
"HOME",
|
|
2321
|
-
"USER",
|
|
2322
|
-
"SHELL",
|
|
2323
|
-
"LANG",
|
|
2324
|
-
"LC_ALL",
|
|
2325
|
-
"LC_CTYPE",
|
|
2326
|
-
"TERM",
|
|
2327
|
-
"TZ",
|
|
2328
|
-
"TMPDIR",
|
|
2329
|
-
"XDG_RUNTIME_DIR",
|
|
2330
|
-
"NODE_OPTIONS",
|
|
2331
|
-
"BUN_INSTALL"
|
|
2332
|
-
];
|
|
2333
2557
|
|
|
2334
2558
|
// src/services/pty-types.ts
|
|
2335
2559
|
var PI_AGENT_ALIASES = new Set([
|
|
@@ -2374,17 +2598,39 @@ var toPiCommand = (task) => {
|
|
|
2374
2598
|
|
|
2375
2599
|
// src/services/stall-classifier.ts
|
|
2376
2600
|
init_ansi_utils();
|
|
2377
|
-
import {ModelType} from "@elizaos/core";
|
|
2601
|
+
import { ModelType } from "@elizaos/core";
|
|
2378
2602
|
import {
|
|
2379
|
-
buildTaskCompletionTimeline,
|
|
2380
|
-
extractTaskCompletionTraceRecords
|
|
2603
|
+
buildTaskCompletionTimeline,
|
|
2604
|
+
extractTaskCompletionTraceRecords
|
|
2381
2605
|
} from "pty-manager";
|
|
2382
2606
|
function buildStallClassificationPrompt(agentType, sessionId, output) {
|
|
2383
|
-
return `You are Milady, an AI orchestrator managing coding agent sessions. ` + `A ${agentType} coding agent (session: ${sessionId}) appears to have stalled
|
|
2607
|
+
return `You are Milady, an AI orchestrator managing coding agent sessions. ` + `A ${agentType} coding agent (session: ${sessionId}) appears to have stalled — ` + `it has stopped producing output while in a busy state.
|
|
2608
|
+
|
|
2609
|
+
` + `Here is the recent terminal output:
|
|
2610
|
+
` + `---
|
|
2611
|
+
${output.slice(-1500)}
|
|
2612
|
+
---
|
|
2613
|
+
|
|
2614
|
+
` + `Classify what's happening. Read the output carefully and choose the MOST specific match:
|
|
2384
2615
|
|
|
2385
|
-
` + `
|
|
2616
|
+
` + `1. "task_complete" — The agent FINISHED its task and returned to its idle prompt. ` + `Strong indicators: a summary of completed work ("Done", "All done", "Here's what was completed"), ` + `timing info ("Baked for", "Churned for", "Crunched for", "Cooked for", "Worked for"), ` + `or the agent's main prompt symbol (❯) appearing AFTER completion output. ` + `If the output contains evidence of completed work followed by an idle prompt, this is ALWAYS task_complete, ` + `even though the agent is technically "waiting" — it is waiting for a NEW task, not asking a question.
|
|
2386
2617
|
|
|
2387
|
-
` + `
|
|
2618
|
+
` + `2. "waiting_for_input" — The agent is MID-TASK and blocked on a specific question or permission prompt. ` + `The agent has NOT finished its work — it needs a response to continue. ` + `Examples: Y/n confirmation, file permission dialogs, "Do you want to proceed?", ` + `tool approval prompts, or interactive menus. ` + `This is NOT the same as the agent sitting at its idle prompt after finishing work.
|
|
2619
|
+
|
|
2620
|
+
` + `3. "still_working" — The agent is actively processing (API call, compilation, thinking, etc.) ` + `and has not produced final output yet. No prompt or completion summary visible.
|
|
2621
|
+
|
|
2622
|
+
` + `4. "error" — The agent hit an error state (crash, unrecoverable error, stack trace).
|
|
2623
|
+
|
|
2624
|
+
` + `5. "tool_running" — The agent is using an external tool (browser automation, ` + `MCP tool, etc.). Indicators: "Claude in Chrome", "javascript_tool", ` + `"computer_tool", "screenshot", "navigate", tool execution output. ` + `The agent is actively working but the terminal may be quiet.
|
|
2625
|
+
|
|
2626
|
+
` + `IMPORTANT: If you see BOTH completed work output AND an idle prompt (❯), choose "task_complete". ` + `Only choose "waiting_for_input" if the agent is clearly asking a question mid-task.
|
|
2627
|
+
|
|
2628
|
+
` + `If "waiting_for_input", also provide:
|
|
2629
|
+
` + `- "prompt": the text of what it's asking
|
|
2630
|
+
` + `- "suggestedResponse": what to type/send. Use "keys:enter" for TUI menu confirmation, ` + `"keys:down,enter" to select a non-default option, or plain text like "y" for text prompts.
|
|
2631
|
+
|
|
2632
|
+
` + `Respond with ONLY a JSON object:
|
|
2633
|
+
` + `{"state": "...", "prompt": "...", "suggestedResponse": "..."}`;
|
|
2388
2634
|
}
|
|
2389
2635
|
async function writeStallSnapshot(sessionId, agentType, recentOutput, effectiveOutput, buffers, traceEntries, log) {
|
|
2390
2636
|
try {
|
|
@@ -2394,7 +2640,8 @@ async function writeStallSnapshot(sessionId, agentType, recentOutput, effectiveO
|
|
|
2394
2640
|
const snapshotDir = path.join(os.homedir(), ".milady", "debug");
|
|
2395
2641
|
fs.mkdirSync(snapshotDir, { recursive: true });
|
|
2396
2642
|
const ourBuffer = buffers.get(sessionId);
|
|
2397
|
-
const ourTail = ourBuffer ? ourBuffer.slice(-100).join(
|
|
2643
|
+
const ourTail = ourBuffer ? ourBuffer.slice(-100).join(`
|
|
2644
|
+
`) : "(no buffer)";
|
|
2398
2645
|
let traceTimeline = "(no trace entries)";
|
|
2399
2646
|
try {
|
|
2400
2647
|
const records = extractTaskCompletionTraceRecords(traceEntries);
|
|
@@ -2417,14 +2664,15 @@ async function writeStallSnapshot(sessionId, agentType, recentOutput, effectiveO
|
|
|
2417
2664
|
traceTimeline,
|
|
2418
2665
|
``,
|
|
2419
2666
|
`--- raw trace entries (last 20 of ${traceEntries.length}) ---`,
|
|
2420
|
-
traceEntries.slice(-20).join(
|
|
2667
|
+
traceEntries.slice(-20).join(`
|
|
2668
|
+
`),
|
|
2421
2669
|
``
|
|
2422
|
-
].join(
|
|
2670
|
+
].join(`
|
|
2671
|
+
`);
|
|
2423
2672
|
const snapshotPath = path.join(snapshotDir, `stall-snapshot-${sessionId}.txt`);
|
|
2424
2673
|
fs.writeFileSync(snapshotPath, snapshot);
|
|
2425
|
-
log(`Stall snapshot
|
|
2426
|
-
} catch (_) {
|
|
2427
|
-
}
|
|
2674
|
+
log(`Stall snapshot → ${snapshotPath}`);
|
|
2675
|
+
} catch (_) {}
|
|
2428
2676
|
}
|
|
2429
2677
|
async function classifyStallOutput(ctx) {
|
|
2430
2678
|
const {
|
|
@@ -2443,7 +2691,8 @@ async function classifyStallOutput(ctx) {
|
|
|
2443
2691
|
if (!recentOutput || recentOutput.trim().length < 200) {
|
|
2444
2692
|
const ourBuffer = buffers.get(sessionId);
|
|
2445
2693
|
if (ourBuffer && ourBuffer.length > 0) {
|
|
2446
|
-
const rawTail = ourBuffer.slice(-100).join(
|
|
2694
|
+
const rawTail = ourBuffer.slice(-100).join(`
|
|
2695
|
+
`);
|
|
2447
2696
|
const stripped = stripAnsi(rawTail);
|
|
2448
2697
|
if (stripped.length > effectiveOutput.length) {
|
|
2449
2698
|
effectiveOutput = stripped;
|
|
@@ -2483,7 +2732,7 @@ async function classifyStallOutput(ctx) {
|
|
|
2483
2732
|
prompt: parsed.prompt,
|
|
2484
2733
|
suggestedResponse: parsed.suggestedResponse
|
|
2485
2734
|
};
|
|
2486
|
-
log(`Stall classification for ${sessionId}: ${classification.state}${classification.suggestedResponse ? `
|
|
2735
|
+
log(`Stall classification for ${sessionId}: ${classification.state}${classification.suggestedResponse ? ` → "${classification.suggestedResponse}"` : ""}`);
|
|
2487
2736
|
if (classification.state === "task_complete") {
|
|
2488
2737
|
const session = manager?.get(sessionId);
|
|
2489
2738
|
const durationMs = session?.startedAt ? Date.now() - new Date(session.startedAt).getTime() : 0;
|
|
@@ -2499,12 +2748,14 @@ async function classifyStallOutput(ctx) {
|
|
|
2499
2748
|
// src/services/swarm-coordinator.ts
|
|
2500
2749
|
init_ansi_utils();
|
|
2501
2750
|
init_swarm_decision_loop();
|
|
2502
|
-
import {logger} from "@elizaos/core";
|
|
2751
|
+
import { logger } from "@elizaos/core";
|
|
2503
2752
|
|
|
2504
2753
|
// src/services/swarm-idle-watchdog.ts
|
|
2505
2754
|
init_ansi_utils();
|
|
2506
2755
|
init_swarm_decision_loop();
|
|
2507
|
-
import {ModelType as ModelType4} from "@elizaos/core";
|
|
2756
|
+
import { ModelType as ModelType4 } from "@elizaos/core";
|
|
2757
|
+
var IDLE_THRESHOLD_MS = 5 * 60 * 1000;
|
|
2758
|
+
var MAX_IDLE_CHECKS = 4;
|
|
2508
2759
|
async function scanIdleSessions(ctx) {
|
|
2509
2760
|
const now = Date.now();
|
|
2510
2761
|
for (const taskCtx of ctx.tasks.values()) {
|
|
@@ -2513,7 +2764,7 @@ async function scanIdleSessions(ctx) {
|
|
|
2513
2764
|
if (ctx.ptyService) {
|
|
2514
2765
|
const session = ctx.ptyService.getSession(taskCtx.sessionId);
|
|
2515
2766
|
if (!session) {
|
|
2516
|
-
ctx.log(`Idle watchdog: "${taskCtx.label}"
|
|
2767
|
+
ctx.log(`Idle watchdog: "${taskCtx.label}" — PTY session no longer exists, marking as stopped`);
|
|
2517
2768
|
taskCtx.status = "stopped";
|
|
2518
2769
|
taskCtx.decisions.push({
|
|
2519
2770
|
timestamp: now,
|
|
@@ -2528,7 +2779,7 @@ async function scanIdleSessions(ctx) {
|
|
|
2528
2779
|
timestamp: now,
|
|
2529
2780
|
data: { reason: "pty_session_gone" }
|
|
2530
2781
|
});
|
|
2531
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Session lost
|
|
2782
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Session lost — the agent process is no longer running (likely killed during a restart).`, "coding-agent");
|
|
2532
2783
|
checkAllTasksComplete(ctx);
|
|
2533
2784
|
continue;
|
|
2534
2785
|
}
|
|
@@ -2547,11 +2798,10 @@ async function scanIdleSessions(ctx) {
|
|
|
2547
2798
|
if (currentOutput !== lastSeen) {
|
|
2548
2799
|
taskCtx.lastActivityAt = now;
|
|
2549
2800
|
taskCtx.idleCheckCount = 0;
|
|
2550
|
-
ctx.log(`Idle watchdog: "${taskCtx.label}" has fresh PTY output
|
|
2801
|
+
ctx.log(`Idle watchdog: "${taskCtx.label}" has fresh PTY output — not idle`);
|
|
2551
2802
|
continue;
|
|
2552
2803
|
}
|
|
2553
|
-
} catch {
|
|
2554
|
-
}
|
|
2804
|
+
} catch {}
|
|
2555
2805
|
}
|
|
2556
2806
|
taskCtx.idleCheckCount++;
|
|
2557
2807
|
const idleMinutes = Math.round(idleMs / 60000);
|
|
@@ -2576,10 +2826,10 @@ async function scanIdleSessions(ctx) {
|
|
|
2576
2826
|
idleCheckCount: taskCtx.idleCheckCount
|
|
2577
2827
|
}
|
|
2578
2828
|
});
|
|
2579
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Session stopped
|
|
2829
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Session stopped — idle for ${idleMinutes} minutes with no progress.`, "coding-agent");
|
|
2580
2830
|
if (ctx.ptyService) {
|
|
2581
2831
|
try {
|
|
2582
|
-
await ctx.ptyService.stopSession(taskCtx.sessionId);
|
|
2832
|
+
await ctx.ptyService.stopSession(taskCtx.sessionId, true);
|
|
2583
2833
|
} catch (err) {
|
|
2584
2834
|
ctx.log(`Idle watchdog: failed to stop session ${taskCtx.sessionId}: ${err}`);
|
|
2585
2835
|
taskCtx.status = "error";
|
|
@@ -2635,8 +2885,8 @@ async function handleIdleCheck(ctx, taskCtx, idleMinutes) {
|
|
|
2635
2885
|
ctx.log(`Idle check LLM call failed: ${err}`);
|
|
2636
2886
|
}
|
|
2637
2887
|
if (!decision) {
|
|
2638
|
-
ctx.log(`Idle check for "${taskCtx.label}": LLM returned invalid response
|
|
2639
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Session idle for ${idleMinutes}m
|
|
2888
|
+
ctx.log(`Idle check for "${taskCtx.label}": LLM returned invalid response — escalating`);
|
|
2889
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Session idle for ${idleMinutes}m — couldn't determine status. Needs your attention.`, "coding-agent");
|
|
2640
2890
|
return;
|
|
2641
2891
|
}
|
|
2642
2892
|
taskCtx.decisions.push({
|
|
@@ -2658,22 +2908,19 @@ async function handleIdleCheck(ctx, taskCtx, idleMinutes) {
|
|
|
2658
2908
|
reasoning: decision.reasoning
|
|
2659
2909
|
}
|
|
2660
2910
|
});
|
|
2661
|
-
if (decision.action === "complete") {
|
|
2662
|
-
} else if (decision.action === "respond") {
|
|
2911
|
+
if (decision.action === "complete") {} else if (decision.action === "respond") {
|
|
2663
2912
|
const actionDesc = decision.useKeys ? `Sent keys: ${decision.keys?.join(", ")}` : `Nudged: ${decision.response ?? ""}`;
|
|
2664
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Idle for ${idleMinutes}m
|
|
2913
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Idle for ${idleMinutes}m — ${actionDesc}`, "coding-agent");
|
|
2665
2914
|
} else if (decision.action === "escalate") {
|
|
2666
|
-
ctx.sendChatMessage(`[${taskCtx.label}] Idle for ${idleMinutes}m
|
|
2915
|
+
ctx.sendChatMessage(`[${taskCtx.label}] Idle for ${idleMinutes}m — needs your attention: ${decision.reasoning}`, "coding-agent");
|
|
2667
2916
|
} else if (decision.action === "ignore") {
|
|
2668
|
-
ctx.log(`Idle check for "${taskCtx.label}": LLM says still working
|
|
2917
|
+
ctx.log(`Idle check for "${taskCtx.label}": LLM says still working — ${decision.reasoning}`);
|
|
2669
2918
|
}
|
|
2670
2919
|
await executeDecision(ctx, sessionId, decision);
|
|
2671
2920
|
} finally {
|
|
2672
2921
|
ctx.inFlightDecisions.delete(sessionId);
|
|
2673
2922
|
}
|
|
2674
2923
|
}
|
|
2675
|
-
var IDLE_THRESHOLD_MS = 5 * 60 * 1000;
|
|
2676
|
-
var MAX_IDLE_CHECKS = 4;
|
|
2677
2924
|
|
|
2678
2925
|
// src/services/swarm-coordinator.ts
|
|
2679
2926
|
var UNREGISTERED_BUFFER_MS = 2000;
|
|
@@ -2713,7 +2960,7 @@ class SwarmCoordinator {
|
|
|
2713
2960
|
}
|
|
2714
2961
|
setAgentDecisionCallback(cb) {
|
|
2715
2962
|
this.agentDecisionCb = cb;
|
|
2716
|
-
this.log("Agent decision callback wired
|
|
2963
|
+
this.log("Agent decision callback wired — events will route through Milaidy");
|
|
2717
2964
|
}
|
|
2718
2965
|
getAgentDecisionCallback() {
|
|
2719
2966
|
return this.agentDecisionCb;
|
|
@@ -2776,7 +3023,7 @@ class SwarmCoordinator {
|
|
|
2776
3023
|
if (this._paused)
|
|
2777
3024
|
return;
|
|
2778
3025
|
this._paused = true;
|
|
2779
|
-
this.log("Coordinator paused
|
|
3026
|
+
this.log("Coordinator paused — buffering LLM decisions until user message is processed");
|
|
2780
3027
|
this.broadcast({ type: "coordinator_paused", sessionId: "", timestamp: Date.now(), data: {} });
|
|
2781
3028
|
this.pauseTimeout = setTimeout(() => {
|
|
2782
3029
|
if (this._paused) {
|
|
@@ -2793,7 +3040,7 @@ class SwarmCoordinator {
|
|
|
2793
3040
|
clearTimeout(this.pauseTimeout);
|
|
2794
3041
|
this.pauseTimeout = null;
|
|
2795
3042
|
}
|
|
2796
|
-
this.log(`Coordinator resumed
|
|
3043
|
+
this.log(`Coordinator resumed — replaying ${this.pauseBuffer.length} buffered events`);
|
|
2797
3044
|
this.broadcast({ type: "coordinator_resumed", sessionId: "", timestamp: Date.now(), data: {} });
|
|
2798
3045
|
const buffered = [...this.pauseBuffer];
|
|
2799
3046
|
this.pauseBuffer = [];
|
|
@@ -2888,9 +3135,10 @@ class SwarmCoordinator {
|
|
|
2888
3135
|
}
|
|
2889
3136
|
writeSseEvent(res, event) {
|
|
2890
3137
|
try {
|
|
2891
|
-
res.write(`data: ${JSON.stringify(event)}
|
|
2892
|
-
|
|
2893
|
-
|
|
3138
|
+
res.write(`data: ${JSON.stringify(event)}
|
|
3139
|
+
|
|
3140
|
+
`);
|
|
3141
|
+
} catch {}
|
|
2894
3142
|
}
|
|
2895
3143
|
async handleSessionEvent(sessionId, event, data) {
|
|
2896
3144
|
const taskCtx = this.tasks.get(sessionId);
|
|
@@ -2909,8 +3157,7 @@ class SwarmCoordinator {
|
|
|
2909
3157
|
if (ctx) {
|
|
2910
3158
|
this.unregisteredBuffer.delete(sessionId);
|
|
2911
3159
|
for (const entry of stillBuffered) {
|
|
2912
|
-
this.handleSessionEvent(sessionId, entry.event, entry.data).catch(() => {
|
|
2913
|
-
});
|
|
3160
|
+
this.handleSessionEvent(sessionId, entry.event, entry.data).catch(() => {});
|
|
2914
3161
|
}
|
|
2915
3162
|
} else {
|
|
2916
3163
|
this.unregisteredBuffer.delete(sessionId);
|
|
@@ -3016,10 +3263,9 @@ class SwarmCoordinator {
|
|
|
3016
3263
|
if (devUrl) {
|
|
3017
3264
|
urlSuffix = ` Dev server running at ${devUrl}`;
|
|
3018
3265
|
}
|
|
3019
|
-
} catch {
|
|
3020
|
-
}
|
|
3266
|
+
} catch {}
|
|
3021
3267
|
}
|
|
3022
|
-
this.sendChatMessage(`[${taskCtx.label}] Running ${toolDesc}.${urlSuffix} The agent is working outside the terminal
|
|
3268
|
+
this.sendChatMessage(`[${taskCtx.label}] Running ${toolDesc}.${urlSuffix} The agent is working outside the terminal — I'll let it finish.`, "coding-agent");
|
|
3023
3269
|
}
|
|
3024
3270
|
break;
|
|
3025
3271
|
}
|
|
@@ -3158,14 +3404,21 @@ class PTYService {
|
|
|
3158
3404
|
const config = runtime.getSetting("PTY_SERVICE_CONFIG");
|
|
3159
3405
|
const service = new PTYService(runtime, config ?? {});
|
|
3160
3406
|
await service.initialize();
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
service.coordinator =
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3407
|
+
const servicesMap = runtime.services;
|
|
3408
|
+
const existing = servicesMap?.get?.("SWARM_COORDINATOR");
|
|
3409
|
+
if (existing && existing.length > 0) {
|
|
3410
|
+
service.coordinator = existing[0];
|
|
3411
|
+
logger2.info("[PTYService] SwarmCoordinator already registered, skipping duplicate start");
|
|
3412
|
+
} else {
|
|
3413
|
+
try {
|
|
3414
|
+
const coordinator = new SwarmCoordinator(runtime);
|
|
3415
|
+
coordinator.start(service);
|
|
3416
|
+
service.coordinator = coordinator;
|
|
3417
|
+
servicesMap?.set?.("SWARM_COORDINATOR", [coordinator]);
|
|
3418
|
+
logger2.info("[PTYService] SwarmCoordinator wired and started");
|
|
3419
|
+
} catch (err) {
|
|
3420
|
+
logger2.error(`[PTYService] Failed to wire SwarmCoordinator: ${err}`);
|
|
3421
|
+
}
|
|
3169
3422
|
}
|
|
3170
3423
|
return service;
|
|
3171
3424
|
}
|
|
@@ -3193,6 +3446,13 @@ class PTYService {
|
|
|
3193
3446
|
return false;
|
|
3194
3447
|
const taskCtx = coordinator.getTaskContext(sessionId);
|
|
3195
3448
|
return taskCtx?.status === "active";
|
|
3449
|
+
},
|
|
3450
|
+
hasTaskActivity: (sessionId) => {
|
|
3451
|
+
const coordinator = this.coordinator;
|
|
3452
|
+
if (!coordinator)
|
|
3453
|
+
return false;
|
|
3454
|
+
const taskCtx = coordinator.getTaskContext(sessionId);
|
|
3455
|
+
return (taskCtx?.decisions.length ?? 0) > 0;
|
|
3196
3456
|
}
|
|
3197
3457
|
});
|
|
3198
3458
|
this.manager = result.manager;
|
|
@@ -3284,8 +3544,7 @@ class PTYService {
|
|
|
3284
3544
|
let settings = {};
|
|
3285
3545
|
try {
|
|
3286
3546
|
settings = JSON.parse(await readFile(settingsPath, "utf-8"));
|
|
3287
|
-
} catch {
|
|
3288
|
-
}
|
|
3547
|
+
} catch {}
|
|
3289
3548
|
const permissions = settings.permissions ?? {};
|
|
3290
3549
|
permissions.allowedDirectories = [workdir];
|
|
3291
3550
|
settings.permissions = permissions;
|
|
@@ -3361,10 +3620,10 @@ class PTYService {
|
|
|
3361
3620
|
throw new Error("PTYService not initialized");
|
|
3362
3621
|
return sendKeysToSession(this.ioContext(), sessionId, keys);
|
|
3363
3622
|
}
|
|
3364
|
-
async stopSession(sessionId) {
|
|
3623
|
+
async stopSession(sessionId, force = false) {
|
|
3365
3624
|
if (!this.manager)
|
|
3366
3625
|
throw new Error("PTYService not initialized");
|
|
3367
|
-
return stopSession(this.ioContext(), sessionId, this.sessionMetadata, this.sessionWorkdirs, (msg) => this.log(msg));
|
|
3626
|
+
return stopSession(this.ioContext(), sessionId, this.sessionMetadata, this.sessionWorkdirs, (msg) => this.log(msg), force);
|
|
3368
3627
|
}
|
|
3369
3628
|
get defaultApprovalPreset() {
|
|
3370
3629
|
const fromEnv = this.runtime.getSetting("PARALLAX_DEFAULT_APPROVAL_PRESET");
|
|
@@ -3657,7 +3916,9 @@ var spawnAgentAction = {
|
|
|
3657
3916
|
if (preflight && !preflight.installed) {
|
|
3658
3917
|
if (callback) {
|
|
3659
3918
|
await callback({
|
|
3660
|
-
text: `${preflight.adapter} CLI is not installed
|
|
3919
|
+
text: `${preflight.adapter} CLI is not installed.
|
|
3920
|
+
` + `Install with: ${preflight.installCommand}
|
|
3921
|
+
` + `Docs: ${preflight.docsUrl}`
|
|
3661
3922
|
});
|
|
3662
3923
|
}
|
|
3663
3924
|
return { success: false, error: "AGENT_NOT_INSTALLED" };
|
|
@@ -3783,16 +4044,16 @@ var spawnAgentAction = {
|
|
|
3783
4044
|
|
|
3784
4045
|
// src/actions/coding-task-handlers.ts
|
|
3785
4046
|
import {
|
|
3786
|
-
logger as logger5
|
|
4047
|
+
logger as logger5
|
|
3787
4048
|
} from "@elizaos/core";
|
|
3788
4049
|
|
|
3789
4050
|
// src/actions/coding-task-helpers.ts
|
|
3790
|
-
import {randomUUID} from "node:crypto";
|
|
4051
|
+
import { randomUUID } from "node:crypto";
|
|
3791
4052
|
import * as fs from "node:fs";
|
|
3792
4053
|
import * as os2 from "node:os";
|
|
3793
4054
|
import * as path3 from "node:path";
|
|
3794
4055
|
import {
|
|
3795
|
-
logger as logger4
|
|
4056
|
+
logger as logger4
|
|
3796
4057
|
} from "@elizaos/core";
|
|
3797
4058
|
function createScratchDir() {
|
|
3798
4059
|
const baseDir = path3.join(os2.homedir(), ".milady", "workspaces");
|
|
@@ -3831,10 +4092,12 @@ function registerSessionEvents(ptyService, runtime, sessionId, label, scratchDir
|
|
|
3831
4092
|
const response = data.response ?? "";
|
|
3832
4093
|
const preview = response.length > 500 ? `${response.slice(0, 500)}...` : response;
|
|
3833
4094
|
callback({
|
|
3834
|
-
text: preview ? `Agent "${label}" completed the task
|
|
4095
|
+
text: preview ? `Agent "${label}" completed the task.
|
|
4096
|
+
|
|
4097
|
+
${preview}` : `Agent "${label}" completed the task.`
|
|
3835
4098
|
});
|
|
3836
4099
|
}
|
|
3837
|
-
ptyService.stopSession(sessionId).catch((err) => {
|
|
4100
|
+
ptyService.stopSession(sessionId, true).catch((err) => {
|
|
3838
4101
|
logger4.warn(`[START_CODING_TASK] Failed to stop session for "${label}" after task complete: ${err}`);
|
|
3839
4102
|
});
|
|
3840
4103
|
}
|
|
@@ -3856,6 +4119,7 @@ function registerSessionEvents(ptyService, runtime, sessionId, label, scratchDir
|
|
|
3856
4119
|
}
|
|
3857
4120
|
|
|
3858
4121
|
// src/actions/coding-task-handlers.ts
|
|
4122
|
+
var MAX_CONCURRENT_AGENTS = 8;
|
|
3859
4123
|
async function handleMultiAgent(ctx, agentsParam) {
|
|
3860
4124
|
const {
|
|
3861
4125
|
runtime,
|
|
@@ -4036,7 +4300,8 @@ async function handleMultiAgent(ctx, agentsParam) {
|
|
|
4036
4300
|
`Launched ${succeeded.length}/${agentSpecs.length} agents${repo ? ` on ${repo}` : ""}:`,
|
|
4037
4301
|
...succeeded.map((r) => ` - "${r.label}" (${r.agentType}) [session: ${r.sessionId}]`),
|
|
4038
4302
|
...failed.length > 0 ? [`Failed: ${failed.map((r) => `"${r.label}": ${r.error}`).join(", ")}`] : []
|
|
4039
|
-
].join(
|
|
4303
|
+
].join(`
|
|
4304
|
+
`);
|
|
4040
4305
|
if (callback) {
|
|
4041
4306
|
await callback({ text: summary });
|
|
4042
4307
|
}
|
|
@@ -4117,7 +4382,9 @@ async function handleSingleAgent(ctx, task) {
|
|
|
4117
4382
|
logger5.warn(`[START_CODING_TASK] ${preflight.adapter} CLI not installed`);
|
|
4118
4383
|
if (callback) {
|
|
4119
4384
|
await callback({
|
|
4120
|
-
text: `${preflight.adapter} CLI is not installed
|
|
4385
|
+
text: `${preflight.adapter} CLI is not installed.
|
|
4386
|
+
Install with: ${preflight.installCommand}
|
|
4387
|
+
Docs: ${preflight.docsUrl}`
|
|
4121
4388
|
});
|
|
4122
4389
|
}
|
|
4123
4390
|
return { success: false, error: "AGENT_NOT_INSTALLED" };
|
|
@@ -4170,7 +4437,8 @@ async function handleSingleAgent(ctx, task) {
|
|
|
4170
4437
|
}
|
|
4171
4438
|
const summary = repo ? `Cloned ${repo} and started ${displayType} agent as "${label}"${task ? ` with task: "${task}"` : ""}` : `Started ${displayType} agent as "${label}" in scratch workspace${task ? ` with task: "${task}"` : ""}`;
|
|
4172
4439
|
if (callback) {
|
|
4173
|
-
await callback({ text: `${summary}
|
|
4440
|
+
await callback({ text: `${summary}
|
|
4441
|
+
Session ID: ${session.id}` });
|
|
4174
4442
|
}
|
|
4175
4443
|
return {
|
|
4176
4444
|
success: true,
|
|
@@ -4196,7 +4464,6 @@ async function handleSingleAgent(ctx, task) {
|
|
|
4196
4464
|
return { success: false, error: errorMessage };
|
|
4197
4465
|
}
|
|
4198
4466
|
}
|
|
4199
|
-
var MAX_CONCURRENT_AGENTS = 8;
|
|
4200
4467
|
|
|
4201
4468
|
// src/actions/start-coding-task.ts
|
|
4202
4469
|
var startCodingTaskAction = {
|
|
@@ -4208,7 +4475,7 @@ var startCodingTaskAction = {
|
|
|
4208
4475
|
"SPAWN_AND_PROVISION",
|
|
4209
4476
|
"CODE_THIS"
|
|
4210
4477
|
],
|
|
4211
|
-
description: "Start a coding task: optionally clone a repo, then spawn a coding agent (Claude Code, Codex, Gemini, Aider, Pi) " + "to work on it. If no repo is provided, the agent runs in a safe scratch directory. " + "Use this whenever the user asks to work on code, research something with an agent, or run any agent task. " + "IMPORTANT: If the user references a repository from conversation history (e.g. 'in the same repo', " + "'on that project', 'add a feature to it'), you MUST include the repo URL in the `repo` parameter. " + "If the task involves code changes to a real project but you don't know the repo URL, ASK the user for it " + "before calling this action
|
|
4478
|
+
description: "Start a coding task: optionally clone a repo, then spawn a coding agent (Claude Code, Codex, Gemini, Aider, Pi) " + "to work on it. If no repo is provided, the agent runs in a safe scratch directory. " + "Use this whenever the user asks to work on code, research something with an agent, or run any agent task. " + "IMPORTANT: If the user references a repository from conversation history (e.g. 'in the same repo', " + "'on that project', 'add a feature to it'), you MUST include the repo URL in the `repo` parameter. " + "If the task involves code changes to a real project but you don't know the repo URL, ASK the user for it " + "before calling this action — do not default to a scratch directory for real project work.",
|
|
4212
4479
|
examples: [
|
|
4213
4480
|
[
|
|
4214
4481
|
{
|
|
@@ -4368,7 +4635,7 @@ var startCodingTaskAction = {
|
|
|
4368
4635
|
|
|
4369
4636
|
// src/actions/stop-agent.ts
|
|
4370
4637
|
import {
|
|
4371
|
-
logger as logger6
|
|
4638
|
+
logger as logger6
|
|
4372
4639
|
} from "@elizaos/core";
|
|
4373
4640
|
var stopAgentAction = {
|
|
4374
4641
|
name: "STOP_CODING_AGENT",
|
|
@@ -4531,15 +4798,6 @@ var stopAgentAction = {
|
|
|
4531
4798
|
};
|
|
4532
4799
|
|
|
4533
4800
|
// src/providers/action-examples.ts
|
|
4534
|
-
function formatExample(ex) {
|
|
4535
|
-
const actionTags = ex.actions.map((a) => ` <action>${a}</action>`).join("\n");
|
|
4536
|
-
const paramBlocks = Object.entries(ex.params ?? {}).map(([actionName, params]) => {
|
|
4537
|
-
const inner = Object.entries(params).map(([k, v]) => ` <${k}>${v}</${k}>`).join("\n");
|
|
4538
|
-
return ` <${actionName}>\n${inner}\n </${actionName}>`;
|
|
4539
|
-
}).join("\n");
|
|
4540
|
-
const paramsSection = paramBlocks ? `\n<params>\n${paramBlocks}\n</params>` : "";
|
|
4541
|
-
return `User: ${ex.user}\nAssistant:\n<actions>\n${actionTags}\n</actions>${paramsSection}`;
|
|
4542
|
-
}
|
|
4543
4801
|
var CODING_AGENT_EXAMPLES = [
|
|
4544
4802
|
{
|
|
4545
4803
|
user: "Can you set up a workspace for https://github.com/acme/my-app and have Claude fix the login bug?",
|
|
@@ -4548,7 +4806,7 @@ var CODING_AGENT_EXAMPLES = [
|
|
|
4548
4806
|
START_CODING_TASK: {
|
|
4549
4807
|
repo: "https://github.com/acme/my-app",
|
|
4550
4808
|
agentType: "claude",
|
|
4551
|
-
task: "Fix the login bug in src/auth.ts
|
|
4809
|
+
task: "Fix the login bug in src/auth.ts — users are getting 401 errors after token refresh"
|
|
4552
4810
|
}
|
|
4553
4811
|
}
|
|
4554
4812
|
},
|
|
@@ -4601,7 +4859,28 @@ var CODING_AGENT_EXAMPLES = [
|
|
|
4601
4859
|
}
|
|
4602
4860
|
}
|
|
4603
4861
|
];
|
|
4604
|
-
|
|
4862
|
+
function formatExample(ex) {
|
|
4863
|
+
const actionTags = ex.actions.map((a) => ` <action>${a}</action>`).join(`
|
|
4864
|
+
`);
|
|
4865
|
+
const paramBlocks = Object.entries(ex.params ?? {}).map(([actionName, params]) => {
|
|
4866
|
+
const inner = Object.entries(params).map(([k, v]) => ` <${k}>${v}</${k}>`).join(`
|
|
4867
|
+
`);
|
|
4868
|
+
return ` <${actionName}>
|
|
4869
|
+
${inner}
|
|
4870
|
+
</${actionName}>`;
|
|
4871
|
+
}).join(`
|
|
4872
|
+
`);
|
|
4873
|
+
const paramsSection = paramBlocks ? `
|
|
4874
|
+
<params>
|
|
4875
|
+
${paramBlocks}
|
|
4876
|
+
</params>` : "";
|
|
4877
|
+
return `User: ${ex.user}
|
|
4878
|
+
Assistant:
|
|
4879
|
+
<actions>
|
|
4880
|
+
${actionTags}
|
|
4881
|
+
</actions>${paramsSection}`;
|
|
4882
|
+
}
|
|
4883
|
+
var MULTI_AGENT_EXAMPLE = `User: Spin up 3 agents on https://github.com/acme/app — one to fix auth, one to write tests, one to update docs
|
|
4605
4884
|
Assistant:
|
|
4606
4885
|
<actions>
|
|
4607
4886
|
<action>REPLY</action>
|
|
@@ -4610,7 +4889,7 @@ Assistant:
|
|
|
4610
4889
|
<params>
|
|
4611
4890
|
<START_CODING_TASK>
|
|
4612
4891
|
<repo>https://github.com/acme/app</repo>
|
|
4613
|
-
<agents>Fix the authentication bug in src/auth.ts
|
|
4892
|
+
<agents>Fix the authentication bug in src/auth.ts — users get 401 after token refresh. Your unique identifier is "alpha". | Write comprehensive unit tests for the auth module in src/auth.ts. Your unique identifier is "beta". | Update the API documentation in docs/ to reflect the new auth flow. Your unique identifier is "gamma".</agents>
|
|
4614
4893
|
</START_CODING_TASK>
|
|
4615
4894
|
</params>`;
|
|
4616
4895
|
var codingAgentExamplesProvider = {
|
|
@@ -4618,12 +4897,14 @@ var codingAgentExamplesProvider = {
|
|
|
4618
4897
|
description: "Structured examples showing how to use coding agent actions with parameters",
|
|
4619
4898
|
position: -1,
|
|
4620
4899
|
get: async (_runtime, _message, _state) => {
|
|
4621
|
-
const examples = CODING_AGENT_EXAMPLES.map(formatExample).join(
|
|
4900
|
+
const examples = CODING_AGENT_EXAMPLES.map(formatExample).join(`
|
|
4901
|
+
|
|
4902
|
+
`);
|
|
4622
4903
|
const text = [
|
|
4623
4904
|
"# Coding Agent Action Call Examples",
|
|
4624
4905
|
"When the user asks you to work on code, clone repos, spawn agents, or run agent tasks,",
|
|
4625
4906
|
"you MUST select the appropriate actions and include parameters. Do NOT just describe",
|
|
4626
|
-
"what you would do
|
|
4907
|
+
"what you would do — actually select the actions.",
|
|
4627
4908
|
"",
|
|
4628
4909
|
"IMPORTANT: Use START_CODING_TASK to launch coding agents. It handles workspace setup",
|
|
4629
4910
|
"automatically. If a repo URL is provided, it clones it first. If no repo, the agent",
|
|
@@ -4641,7 +4922,8 @@ var codingAgentExamplesProvider = {
|
|
|
4641
4922
|
"and unique identifiers so their work is clearly differentiated.",
|
|
4642
4923
|
"",
|
|
4643
4924
|
MULTI_AGENT_EXAMPLE
|
|
4644
|
-
].join(
|
|
4925
|
+
].join(`
|
|
4926
|
+
`);
|
|
4645
4927
|
return {
|
|
4646
4928
|
data: { codingAgentExamples: CODING_AGENT_EXAMPLES },
|
|
4647
4929
|
values: { codingAgentExamples: text },
|
|
@@ -4674,7 +4956,7 @@ function formatWorkspaceLine(ws, sessions) {
|
|
|
4674
4956
|
const label = ws.label || ws.id.slice(0, 8);
|
|
4675
4957
|
const agents = sessions.filter((s) => s.workdir === ws.path);
|
|
4676
4958
|
const agentSummary = agents.length > 0 ? agents.map((a) => `${a.agentType}:${formatStatus(a.status)}`).join(", ") : "no agents";
|
|
4677
|
-
return ` - "${label}"
|
|
4959
|
+
return ` - "${label}" → ${ws.repo} (branch: ${ws.branch}, ${agentSummary})`;
|
|
4678
4960
|
}
|
|
4679
4961
|
var activeWorkspaceContextProvider = {
|
|
4680
4962
|
name: "ACTIVE_WORKSPACE_CONTEXT",
|
|
@@ -4703,7 +4985,8 @@ var activeWorkspaceContextProvider = {
|
|
|
4703
4985
|
"# Active Workspaces & Agents",
|
|
4704
4986
|
"No active workspaces or coding agent sessions.",
|
|
4705
4987
|
"Use START_CODING_TASK to launch a new coding agent."
|
|
4706
|
-
].join(
|
|
4988
|
+
].join(`
|
|
4989
|
+
`);
|
|
4707
4990
|
return {
|
|
4708
4991
|
data: { activeWorkspaces: [], activeSessions: [] },
|
|
4709
4992
|
values: { activeWorkspaceContext: text2 },
|
|
@@ -4733,9 +5016,9 @@ var activeWorkspaceContextProvider = {
|
|
|
4733
5016
|
const supervisionLevel = coordinator.getSupervisionLevel();
|
|
4734
5017
|
if (pending.length > 0) {
|
|
4735
5018
|
lines.push("");
|
|
4736
|
-
lines.push(`## Pending Confirmations (${pending.length})
|
|
5019
|
+
lines.push(`## Pending Confirmations (${pending.length}) — supervision: ${supervisionLevel}`);
|
|
4737
5020
|
for (const p of pending) {
|
|
4738
|
-
lines.push(` - "${p.taskContext.label}" blocked: "${p.promptText}"
|
|
5021
|
+
lines.push(` - "${p.taskContext.label}" blocked: "${p.promptText}" → suggested: ${p.llmDecision.action}`);
|
|
4739
5022
|
}
|
|
4740
5023
|
} else if (supervisionLevel !== "autonomous") {
|
|
4741
5024
|
lines.push("");
|
|
@@ -4746,7 +5029,8 @@ var activeWorkspaceContextProvider = {
|
|
|
4746
5029
|
lines.push("");
|
|
4747
5030
|
lines.push("You can interact with agents using SEND_TO_CODING_AGENT (pass sessionId), " + "stop them with STOP_CODING_AGENT, or finalize their work with FINALIZE_WORKSPACE.");
|
|
4748
5031
|
}
|
|
4749
|
-
const text = lines.join(
|
|
5032
|
+
const text = lines.join(`
|
|
5033
|
+
`);
|
|
4750
5034
|
return {
|
|
4751
5035
|
data: {
|
|
4752
5036
|
activeWorkspaces: workspaces.map((ws) => ({
|
|
@@ -4774,16 +5058,16 @@ var activeWorkspaceContextProvider = {
|
|
|
4774
5058
|
import * as os3 from "node:os";
|
|
4775
5059
|
import * as path5 from "node:path";
|
|
4776
5060
|
import {
|
|
4777
|
-
CredentialService,
|
|
4778
|
-
GitHubPatClient as GitHubPatClient2,
|
|
4779
|
-
MemoryTokenStore,
|
|
4780
|
-
WorkspaceService
|
|
5061
|
+
CredentialService,
|
|
5062
|
+
GitHubPatClient as GitHubPatClient2,
|
|
5063
|
+
MemoryTokenStore,
|
|
5064
|
+
WorkspaceService
|
|
4781
5065
|
} from "git-workspace-service";
|
|
4782
5066
|
|
|
4783
5067
|
// src/services/workspace-github.ts
|
|
4784
5068
|
import {
|
|
4785
|
-
GitHubPatClient,
|
|
4786
|
-
OAuthDeviceFlow
|
|
5069
|
+
GitHubPatClient,
|
|
5070
|
+
OAuthDeviceFlow
|
|
4787
5071
|
} from "git-workspace-service";
|
|
4788
5072
|
function parseOwnerRepo(repo) {
|
|
4789
5073
|
const match = repo.match(/(?:github\.com\/)?([^/]+)\/([^/.]+)/);
|
|
@@ -4839,7 +5123,9 @@ async function performOAuthFlow(ctx, clientId) {
|
|
|
4839
5123
|
expiresIn: deviceCode.expiresIn
|
|
4840
5124
|
});
|
|
4841
5125
|
} else {
|
|
4842
|
-
console.log(
|
|
5126
|
+
console.log(`
|
|
5127
|
+
[GitHub Auth] Go to ${deviceCode.verificationUri} and enter code: ${deviceCode.userCode}
|
|
5128
|
+
`);
|
|
4843
5129
|
}
|
|
4844
5130
|
const token = await oauth.pollForToken(deviceCode);
|
|
4845
5131
|
const client = new GitHubPatClient({ token: token.accessToken });
|
|
@@ -4908,7 +5194,8 @@ async function getStatus(workspacePath) {
|
|
|
4908
5194
|
cwd: workspacePath,
|
|
4909
5195
|
encoding: "utf-8"
|
|
4910
5196
|
}).trim();
|
|
4911
|
-
const lines = statusOutput.split(
|
|
5197
|
+
const lines = statusOutput.split(`
|
|
5198
|
+
`).filter(Boolean);
|
|
4912
5199
|
const modified = [];
|
|
4913
5200
|
const staged = [];
|
|
4914
5201
|
const untracked = [];
|
|
@@ -5616,6 +5903,7 @@ async function handleAgentRoutes(req, res, pathname, ctx) {
|
|
|
5616
5903
|
}
|
|
5617
5904
|
|
|
5618
5905
|
// src/api/coordinator-routes.ts
|
|
5906
|
+
var COORDINATOR_PREFIX = "/api/coding-agents/coordinator";
|
|
5619
5907
|
async function handleCoordinatorRoutes(req, res, pathname, ctx) {
|
|
5620
5908
|
if (!pathname.startsWith(COORDINATOR_PREFIX)) {
|
|
5621
5909
|
return false;
|
|
@@ -5633,7 +5921,9 @@ async function handleCoordinatorRoutes(req, res, pathname, ctx) {
|
|
|
5633
5921
|
"Cache-Control": "no-cache",
|
|
5634
5922
|
Connection: "keep-alive"
|
|
5635
5923
|
});
|
|
5636
|
-
res.write(
|
|
5924
|
+
res.write(`:ok
|
|
5925
|
+
|
|
5926
|
+
`);
|
|
5637
5927
|
const unsubscribe = coordinator.addSseClient(res);
|
|
5638
5928
|
req.on("close", unsubscribe);
|
|
5639
5929
|
const keepAlive = setInterval(() => {
|
|
@@ -5641,7 +5931,9 @@ async function handleCoordinatorRoutes(req, res, pathname, ctx) {
|
|
|
5641
5931
|
clearInterval(keepAlive);
|
|
5642
5932
|
return;
|
|
5643
5933
|
}
|
|
5644
|
-
res.write(
|
|
5934
|
+
res.write(`:ping
|
|
5935
|
+
|
|
5936
|
+
`);
|
|
5645
5937
|
}, 30000);
|
|
5646
5938
|
req.on("close", () => clearInterval(keepAlive));
|
|
5647
5939
|
return true;
|
|
@@ -5726,7 +6018,6 @@ async function handleCoordinatorRoutes(req, res, pathname, ctx) {
|
|
|
5726
6018
|
}
|
|
5727
6019
|
return false;
|
|
5728
6020
|
}
|
|
5729
|
-
var COORDINATOR_PREFIX = "/api/coding-agents/coordinator";
|
|
5730
6021
|
|
|
5731
6022
|
// src/api/issue-routes.ts
|
|
5732
6023
|
async function handleIssueRoutes(req, res, pathname, ctx) {
|
|
@@ -5958,6 +6249,7 @@ async function handleWorkspaceRoutes(req, res, pathname, ctx) {
|
|
|
5958
6249
|
}
|
|
5959
6250
|
|
|
5960
6251
|
// src/api/routes.ts
|
|
6252
|
+
var MAX_BODY_SIZE = 1024 * 1024;
|
|
5961
6253
|
async function parseBody(req) {
|
|
5962
6254
|
return new Promise((resolve5, reject) => {
|
|
5963
6255
|
let body = "";
|
|
@@ -6014,7 +6306,6 @@ function createCodingAgentRouteHandler(runtime, coordinator) {
|
|
|
6014
6306
|
};
|
|
6015
6307
|
return (req, res, pathname) => handleCodingAgentRoutes(req, res, pathname, ctx);
|
|
6016
6308
|
}
|
|
6017
|
-
var MAX_BODY_SIZE = 1024 * 1024;
|
|
6018
6309
|
|
|
6019
6310
|
// src/index.ts
|
|
6020
6311
|
var codingAgentPlugin = {
|
|
@@ -6059,5 +6350,5 @@ export {
|
|
|
6059
6350
|
CodingWorkspaceService
|
|
6060
6351
|
};
|
|
6061
6352
|
|
|
6062
|
-
//# debugId=
|
|
6353
|
+
//# debugId=A1B0DE07402807E864756E2164756E21
|
|
6063
6354
|
//# sourceMappingURL=index.js.map
|