@agentuity/opencode 1.0.18 → 1.0.20
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/agents/expert-backend.d.ts +1 -1
- package/dist/agents/expert-backend.d.ts.map +1 -1
- package/dist/agents/expert-backend.js +0 -17
- package/dist/agents/expert-backend.js.map +1 -1
- package/dist/agents/expert.d.ts +1 -1
- package/dist/agents/expert.d.ts.map +1 -1
- package/dist/agents/expert.js +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +0 -2
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lead.d.ts +1 -1
- package/dist/agents/lead.d.ts.map +1 -1
- package/dist/agents/lead.js +25 -145
- package/dist/agents/lead.js.map +1 -1
- package/dist/agents/scout.d.ts +1 -1
- package/dist/agents/scout.d.ts.map +1 -1
- package/dist/agents/scout.js +16 -0
- package/dist/agents/scout.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +1 -33
- package/dist/config/loader.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin/hooks/cadence.d.ts +1 -2
- package/dist/plugin/hooks/cadence.d.ts.map +1 -1
- package/dist/plugin/hooks/cadence.js +7 -33
- package/dist/plugin/hooks/cadence.js.map +1 -1
- package/dist/plugin/hooks/compaction-utils.d.ts.map +1 -1
- package/dist/plugin/hooks/compaction-utils.js +6 -13
- package/dist/plugin/hooks/compaction-utils.js.map +1 -1
- package/dist/plugin/hooks/completion.d.ts.map +1 -1
- package/dist/plugin/hooks/completion.js +2 -3
- package/dist/plugin/hooks/completion.js.map +1 -1
- package/dist/plugin/hooks/params.d.ts.map +1 -1
- package/dist/plugin/hooks/params.js +0 -1
- package/dist/plugin/hooks/params.js.map +1 -1
- package/dist/plugin/hooks/session-memory.d.ts +1 -2
- package/dist/plugin/hooks/session-memory.d.ts.map +1 -1
- package/dist/plugin/hooks/session-memory.js +6 -29
- package/dist/plugin/hooks/session-memory.js.map +1 -1
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +8 -222
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/sqlite/types.d.ts +0 -6
- package/dist/sqlite/types.d.ts.map +1 -1
- package/dist/tmux/manager.d.ts +4 -4
- package/dist/tmux/manager.js +4 -4
- package/dist/tmux/types.d.ts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +2 -20
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -9
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/agents/expert-backend.ts +0 -17
- package/src/agents/expert.ts +1 -1
- package/src/agents/index.ts +0 -2
- package/src/agents/lead.ts +25 -145
- package/src/agents/scout.ts +16 -0
- package/src/config/loader.ts +1 -45
- package/src/index.ts +0 -1
- package/src/plugin/hooks/cadence.ts +6 -39
- package/src/plugin/hooks/compaction-utils.ts +6 -12
- package/src/plugin/hooks/completion.ts +2 -4
- package/src/plugin/hooks/params.ts +0 -3
- package/src/plugin/hooks/session-memory.ts +5 -35
- package/src/plugin/plugin.ts +7 -257
- package/src/sqlite/types.ts +0 -2
- package/src/tmux/manager.ts +4 -4
- package/src/tmux/types.ts +2 -2
- package/src/tools/index.ts +2 -9
- package/src/types.ts +0 -13
- package/dist/agents/monitor.d.ts +0 -4
- package/dist/agents/monitor.d.ts.map +0 -1
- package/dist/agents/monitor.js +0 -159
- package/dist/agents/monitor.js.map +0 -1
- package/dist/background/concurrency.d.ts +0 -36
- package/dist/background/concurrency.d.ts.map +0 -1
- package/dist/background/concurrency.js +0 -92
- package/dist/background/concurrency.js.map +0 -1
- package/dist/background/index.d.ts +0 -5
- package/dist/background/index.d.ts.map +0 -1
- package/dist/background/index.js +0 -4
- package/dist/background/index.js.map +0 -1
- package/dist/background/manager.d.ts +0 -123
- package/dist/background/manager.d.ts.map +0 -1
- package/dist/background/manager.js +0 -1081
- package/dist/background/manager.js.map +0 -1
- package/dist/background/types.d.ts +0 -90
- package/dist/background/types.d.ts.map +0 -1
- package/dist/background/types.js +0 -2
- package/dist/background/types.js.map +0 -1
- package/dist/tools/background.d.ts +0 -67
- package/dist/tools/background.d.ts.map +0 -1
- package/dist/tools/background.js +0 -95
- package/dist/tools/background.js.map +0 -1
- package/src/agents/monitor.ts +0 -161
- package/src/background/concurrency.ts +0 -116
- package/src/background/index.ts +0 -4
- package/src/background/manager.ts +0 -1226
- package/src/background/types.ts +0 -82
- package/src/tools/background.ts +0 -179
|
@@ -70,13 +70,12 @@ export function buildCustomCompactionPrompt(mode: 'cadence' | 'regular'): string
|
|
|
70
70
|
|
|
71
71
|
## CRITICAL — Preserve These Verbatim
|
|
72
72
|
1. The current task/objective (quote the user's original request exactly)
|
|
73
|
-
2.
|
|
74
|
-
3.
|
|
75
|
-
4.
|
|
76
|
-
5.
|
|
77
|
-
6.
|
|
78
|
-
7.
|
|
79
|
-
8. Descriptions of any images or attachments that appeared in conversation${cadenceSection}
|
|
73
|
+
2. Active planning state: current phase, completed phases, next steps, blockers
|
|
74
|
+
3. ALL file paths being actively worked on (with role: created/modified/read)
|
|
75
|
+
4. Key decisions made and their rationale
|
|
76
|
+
5. Any corrections or gotchas discovered during the session
|
|
77
|
+
6. Todo list state (what's done, in progress, pending)
|
|
78
|
+
7. Descriptions of any images or attachments that appeared in conversation${cadenceSection}
|
|
80
79
|
|
|
81
80
|
## Structure Your Summary As:
|
|
82
81
|
|
|
@@ -86,9 +85,6 @@ export function buildCustomCompactionPrompt(mode: 'cadence' | 'regular'): string
|
|
|
86
85
|
### Planning State
|
|
87
86
|
[Phases with status. Include phase notes, not just titles.]
|
|
88
87
|
|
|
89
|
-
### Background Tasks
|
|
90
|
-
[bg_xxx: description → status (running/completed/errored). Include session IDs.]
|
|
91
|
-
|
|
92
88
|
### Key Context
|
|
93
89
|
[Decisions, constraints, user preferences, corrections discovered]
|
|
94
90
|
|
|
@@ -104,7 +100,6 @@ export function buildCustomCompactionPrompt(mode: 'cadence' | 'regular'): string
|
|
|
104
100
|
## Rules
|
|
105
101
|
- Use specific file paths, task IDs, phase names — NOT vague references.
|
|
106
102
|
- State what tools returned, not just that they were called.
|
|
107
|
-
- NEVER drop background task references — the agent MUST know what's still running.
|
|
108
103
|
- Prefer completeness over brevity — this is the agent's entire working memory.`;
|
|
109
104
|
}
|
|
110
105
|
|
|
@@ -267,7 +262,6 @@ export async function restoreCadenceStateFromKV(
|
|
|
267
262
|
export function formatCompactionDiagnostics(stats: CompactionStats): string {
|
|
268
263
|
const parts: string[] = [];
|
|
269
264
|
if (stats.planningPhasesCount > 0) parts.push(`${stats.planningPhasesCount} planning phases`);
|
|
270
|
-
if (stats.backgroundTasksCount > 0) parts.push(`${stats.backgroundTasksCount} background tasks`);
|
|
271
265
|
if (stats.imageDescriptionsCount > 0) parts.push(`${stats.imageDescriptionsCount} image refs`);
|
|
272
266
|
if (stats.toolCallSummariesCount > 0) parts.push(`${stats.toolCallSummariesCount} tool calls`);
|
|
273
267
|
|
|
@@ -62,10 +62,8 @@ export function createCompletionHooks(ctx: PluginInput, _config: CoderConfig): C
|
|
|
62
62
|
|
|
63
63
|
const logLine = `Completion: agent=${start.agent} model=${start.model} duration=${durationSec}s`;
|
|
64
64
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// Also send to the OpenCode log service
|
|
65
|
+
// Send to the OpenCode log service (never use console.* in a TUI context —
|
|
66
|
+
// raw stdout writes bypass the terminal renderer and corrupt the display)
|
|
69
67
|
ctx.client.app.log({
|
|
70
68
|
body: {
|
|
71
69
|
service: 'agentuity-coder',
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
2
|
import type { CoderConfig } from '../../types';
|
|
3
|
-
import type { BackgroundManager } from '../../background';
|
|
4
3
|
import type { OpenCodeDBReader } from '../../sqlite';
|
|
5
4
|
import type { CompactionStats } from '../../sqlite/types';
|
|
6
5
|
import {
|
|
@@ -34,7 +33,6 @@ export interface SessionMemoryHooks {
|
|
|
34
33
|
export function createSessionMemoryHooks(
|
|
35
34
|
ctx: PluginInput,
|
|
36
35
|
config: CoderConfig,
|
|
37
|
-
backgroundManager?: BackgroundManager,
|
|
38
36
|
dbReader?: OpenCodeDBReader
|
|
39
37
|
): SessionMemoryHooks {
|
|
40
38
|
const log = (msg: string) => {
|
|
@@ -188,40 +186,17 @@ After compaction:
|
|
|
188
186
|
2. If planning is active, Memory should update planning.progress with this compaction
|
|
189
187
|
3. Memory will apply inline reasoning if significant patterns/corrections emerged`;
|
|
190
188
|
|
|
191
|
-
// 4.
|
|
192
|
-
const tasks = backgroundManager?.getTasksByParent(sessionId) ?? [];
|
|
193
|
-
let backgroundSection: string | null = null;
|
|
194
|
-
|
|
195
|
-
if (tasks.length > 0) {
|
|
196
|
-
const taskList = tasks
|
|
197
|
-
.map(
|
|
198
|
-
(t) =>
|
|
199
|
-
`- **${t.id}**: ${t.description || 'No description'} (session: ${t.sessionId ?? 'pending'}, status: ${t.status})`
|
|
200
|
-
)
|
|
201
|
-
.join('\n');
|
|
202
|
-
|
|
203
|
-
backgroundSection = `## Active Background Tasks
|
|
204
|
-
|
|
205
|
-
This session has ${tasks.length} background task(s) running in separate sessions:
|
|
206
|
-
${taskList}
|
|
207
|
-
|
|
208
|
-
**CRITICAL:** Task IDs and session IDs persist across compaction - these tasks are still running.
|
|
209
|
-
Use \`agentuity_background_output({ task_id: "..." })\` to check their status.`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// 5. Combine everything into the full prompt
|
|
189
|
+
// 4. Combine everything into the full prompt
|
|
213
190
|
const sections: string[] = [];
|
|
214
191
|
if (instructions) sections.push(instructions);
|
|
215
192
|
sections.push(sessionStateSection);
|
|
216
|
-
if (backgroundSection) sections.push(backgroundSection);
|
|
217
193
|
if (planningState) sections.push(planningState);
|
|
218
194
|
if (imageDescs) sections.push(imageDescs);
|
|
219
195
|
if (toolSummaries) sections.push(toolSummaries);
|
|
220
196
|
|
|
221
|
-
//
|
|
197
|
+
// 5. Add diagnostics
|
|
222
198
|
const stats: CompactionStats = {
|
|
223
199
|
planningPhasesCount: countListItems(planningState),
|
|
224
|
-
backgroundTasksCount: tasks.length,
|
|
225
200
|
imageDescriptionsCount: countListItems(imageDescs),
|
|
226
201
|
toolCallSummariesCount: countListItems(toolSummaries),
|
|
227
202
|
estimatedTokens: Math.ceil(sections.join('\n\n').length / 4),
|
|
@@ -229,7 +204,7 @@ Use \`agentuity_background_output({ task_id: "..." })\` to check their status.`;
|
|
|
229
204
|
const diagnostics = formatCompactionDiagnostics(stats);
|
|
230
205
|
if (diagnostics) sections.push(diagnostics);
|
|
231
206
|
|
|
232
|
-
//
|
|
207
|
+
// 6. Enforce token budget
|
|
233
208
|
let fullPrompt = sections.join('\n\n');
|
|
234
209
|
const estimatedTokens = Math.ceil(fullPrompt.length / 4);
|
|
235
210
|
if (maxTokens > 0 && estimatedTokens > maxTokens) {
|
|
@@ -245,24 +220,19 @@ Use \`agentuity_background_output({ task_id: "..." })\` to check their status.`;
|
|
|
245
220
|
fullPrompt = trimmed.join('\n\n');
|
|
246
221
|
}
|
|
247
222
|
|
|
248
|
-
//
|
|
223
|
+
// 7. Set the full prompt or push to context
|
|
249
224
|
if (useCustomPrompt) {
|
|
250
225
|
output.prompt = fullPrompt;
|
|
251
226
|
} else {
|
|
252
227
|
output.context.push(fullPrompt);
|
|
253
228
|
}
|
|
254
229
|
|
|
255
|
-
//
|
|
230
|
+
// 8. Store pre-compaction snapshot to KV (fire-and-forget)
|
|
256
231
|
if (useSnapshotToKV) {
|
|
257
232
|
storePreCompactionSnapshot(sessionId, {
|
|
258
233
|
timestamp: new Date().toISOString(),
|
|
259
234
|
sessionId,
|
|
260
235
|
planningState: planningState ? { raw: planningState } : undefined,
|
|
261
|
-
backgroundTasks: tasks.map((t) => ({
|
|
262
|
-
id: t.id,
|
|
263
|
-
description: t.description || 'No description',
|
|
264
|
-
status: t.status,
|
|
265
|
-
})),
|
|
266
236
|
branch,
|
|
267
237
|
}).catch(() => {}); // Fire and forget
|
|
268
238
|
}
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -17,7 +17,6 @@ import { createCadenceHooks } from './hooks/cadence';
|
|
|
17
17
|
import { createSessionMemoryHooks } from './hooks/session-memory';
|
|
18
18
|
import { createCompletionHooks } from './hooks/completion';
|
|
19
19
|
import type { AgentRole } from '../types';
|
|
20
|
-
import { BackgroundManager } from '../background';
|
|
21
20
|
import type { SessionTreeNode } from '../sqlite';
|
|
22
21
|
import { OpenCodeDBReader } from '../sqlite';
|
|
23
22
|
import { TmuxSessionManager } from '../tmux';
|
|
@@ -114,76 +113,18 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
114
113
|
}),
|
|
115
114
|
})
|
|
116
115
|
: undefined;
|
|
117
|
-
const backgroundManager = new BackgroundManager(
|
|
118
|
-
ctx,
|
|
119
|
-
coderConfig.background,
|
|
120
|
-
{
|
|
121
|
-
onSubagentSessionCreated: tmuxManager
|
|
122
|
-
? (event) => {
|
|
123
|
-
void tmuxManager.onSessionCreated(event);
|
|
124
|
-
}
|
|
125
|
-
: undefined,
|
|
126
|
-
onSubagentSessionDeleted: tmuxManager
|
|
127
|
-
? (event) => {
|
|
128
|
-
void tmuxManager.onSessionDeleted(event);
|
|
129
|
-
}
|
|
130
|
-
: undefined,
|
|
131
|
-
onShutdown: tmuxManager
|
|
132
|
-
? () => {
|
|
133
|
-
void tmuxManager.cleanup();
|
|
134
|
-
}
|
|
135
|
-
: undefined,
|
|
136
|
-
},
|
|
137
|
-
dbReader
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
// Recover any background tasks from previous sessions
|
|
141
|
-
// This allows tasks to survive plugin restarts
|
|
142
|
-
void backgroundManager
|
|
143
|
-
.recoverTasks()
|
|
144
|
-
.then((count) => {
|
|
145
|
-
if (count > 0) {
|
|
146
|
-
ctx.client.app.log({
|
|
147
|
-
body: {
|
|
148
|
-
service: 'agentuity-coder',
|
|
149
|
-
level: 'info',
|
|
150
|
-
message: `Recovered ${count} background task(s) from previous sessions`,
|
|
151
|
-
},
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
.catch((error) => {
|
|
156
|
-
ctx.client.app.log({
|
|
157
|
-
body: {
|
|
158
|
-
service: 'agentuity-coder',
|
|
159
|
-
level: 'warn',
|
|
160
|
-
message: `Failed to recover background tasks: ${error}`,
|
|
161
|
-
},
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
116
|
|
|
165
|
-
// Create hooks
|
|
166
|
-
const cadenceHooks = createCadenceHooks(
|
|
167
|
-
ctx,
|
|
168
|
-
coderConfig,
|
|
169
|
-
backgroundManager,
|
|
170
|
-
dbReader,
|
|
171
|
-
lastUserMessages
|
|
172
|
-
);
|
|
117
|
+
// Create hooks for session routing and compaction behavior
|
|
118
|
+
const cadenceHooks = createCadenceHooks(ctx, coderConfig, dbReader, lastUserMessages);
|
|
173
119
|
|
|
174
120
|
// Session memory hooks handle checkpointing and compaction for non-Cadence sessions
|
|
175
121
|
// Orchestration (deciding which module handles which session) happens below in the hooks
|
|
176
|
-
const sessionMemoryHooks = createSessionMemoryHooks(
|
|
177
|
-
ctx,
|
|
178
|
-
coderConfig,
|
|
179
|
-
backgroundManager,
|
|
180
|
-
dbReader
|
|
181
|
-
);
|
|
122
|
+
const sessionMemoryHooks = createSessionMemoryHooks(ctx, coderConfig, dbReader);
|
|
182
123
|
|
|
183
124
|
const configHandler = createConfigHandler(coderConfig);
|
|
184
125
|
|
|
185
126
|
// Create plugin tools using the @opencode-ai/plugin tool helper
|
|
186
|
-
const tools = createTools(
|
|
127
|
+
const tools = createTools(dbReader);
|
|
187
128
|
|
|
188
129
|
// Create a logger for shutdown handler
|
|
189
130
|
const shutdownLogger = (message: string) =>
|
|
@@ -195,7 +136,7 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
195
136
|
},
|
|
196
137
|
});
|
|
197
138
|
|
|
198
|
-
registerShutdownHandler(
|
|
139
|
+
registerShutdownHandler(tmuxManager, shutdownLogger, dbReader);
|
|
199
140
|
|
|
200
141
|
// Show startup toast (fire and forget, don't block)
|
|
201
142
|
try {
|
|
@@ -245,10 +186,6 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
245
186
|
}
|
|
246
187
|
},
|
|
247
188
|
event: async (input) => {
|
|
248
|
-
const event = extractEventFromInput(input);
|
|
249
|
-
if (event) {
|
|
250
|
-
backgroundManager.handleEvent(event);
|
|
251
|
-
}
|
|
252
189
|
// Orchestrate: route to appropriate module based on session type
|
|
253
190
|
const sessionId = extractSessionIdFromEvent(input);
|
|
254
191
|
if (sessionId) {
|
|
@@ -628,7 +565,7 @@ $ARGUMENTS
|
|
|
628
565
|
## Lead-of-Leads (Parallel Work)
|
|
629
566
|
If the task has **independent workstreams** that can run in parallel (e.g., "build auth, payments, and notifications"):
|
|
630
567
|
1. Ask @Agentuity Coder Product to create PRD with workstreams
|
|
631
|
-
2. Spawn child Leads
|
|
568
|
+
2. Spawn child Leads using the \`task\` tool (issue multiple task calls in a single response for parallel work)
|
|
632
569
|
3. Each child Lead claims a workstream, works autonomously, marks done when complete
|
|
633
570
|
4. Monitor progress via PRD workstream status
|
|
634
571
|
5. Do integration work when all children complete
|
|
@@ -674,170 +611,10 @@ function normalizeBaseDir(path: string): string {
|
|
|
674
611
|
return path.replace(/[\\/]+$/, '');
|
|
675
612
|
}
|
|
676
613
|
|
|
677
|
-
function createTools(
|
|
678
|
-
backgroundManager: BackgroundManager,
|
|
679
|
-
dbReader?: OpenCodeDBReader
|
|
680
|
-
): Hooks['tool'] {
|
|
614
|
+
function createTools(dbReader?: OpenCodeDBReader): Hooks['tool'] {
|
|
681
615
|
// Use the schema from @opencode-ai/plugin's tool helper to avoid Zod version mismatches
|
|
682
616
|
const s = tool.schema;
|
|
683
617
|
|
|
684
|
-
const backgroundTask = tool({
|
|
685
|
-
description: `Launch a task to run in the background. Use this for parallel execution of multiple independent tasks.
|
|
686
|
-
|
|
687
|
-
IMPORTANT: Use this tool instead of the 'task' tool when:
|
|
688
|
-
- You need to run multiple agents in parallel
|
|
689
|
-
- Tasks are independent and don't need sequential execution
|
|
690
|
-
- The user asks for "parallel", "background", or "concurrent" work`,
|
|
691
|
-
args: {
|
|
692
|
-
agent: s
|
|
693
|
-
.enum([
|
|
694
|
-
'lead',
|
|
695
|
-
'scout',
|
|
696
|
-
'builder',
|
|
697
|
-
'architect',
|
|
698
|
-
'reviewer',
|
|
699
|
-
'memory',
|
|
700
|
-
'expert',
|
|
701
|
-
'runner',
|
|
702
|
-
'product',
|
|
703
|
-
'monitor',
|
|
704
|
-
])
|
|
705
|
-
.describe('Agent role to run the task'),
|
|
706
|
-
task: s.string().describe('Task prompt to run in the background'),
|
|
707
|
-
description: s.string().optional().describe('Short description of the task'),
|
|
708
|
-
},
|
|
709
|
-
async execute(args, context) {
|
|
710
|
-
const parentSessionId = context.sessionID;
|
|
711
|
-
if (!parentSessionId) {
|
|
712
|
-
return JSON.stringify({
|
|
713
|
-
taskId: 'unknown',
|
|
714
|
-
status: 'error',
|
|
715
|
-
message: 'Missing session context for background task.',
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
const agentName = resolveAgentName(args.agent as AgentRole);
|
|
720
|
-
const bgTask = await backgroundManager.launch({
|
|
721
|
-
description: args.description ?? args.task,
|
|
722
|
-
prompt: args.task,
|
|
723
|
-
agent: agentName,
|
|
724
|
-
parentSessionId,
|
|
725
|
-
parentMessageId: context.messageID,
|
|
726
|
-
});
|
|
727
|
-
return JSON.stringify({
|
|
728
|
-
taskId: bgTask.id,
|
|
729
|
-
status: bgTask.status,
|
|
730
|
-
message:
|
|
731
|
-
bgTask.status === 'error'
|
|
732
|
-
? (bgTask.error ?? 'Failed to launch background task.')
|
|
733
|
-
: 'Background task launched.',
|
|
734
|
-
});
|
|
735
|
-
},
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
const backgroundOutput = tool({
|
|
739
|
-
description: 'Retrieve output for a background task.',
|
|
740
|
-
args: {
|
|
741
|
-
task_id: s.string().describe('Background task ID'),
|
|
742
|
-
},
|
|
743
|
-
async execute(args) {
|
|
744
|
-
const bgTask = backgroundManager.getTask(args.task_id);
|
|
745
|
-
if (!bgTask) {
|
|
746
|
-
return JSON.stringify({
|
|
747
|
-
taskId: args.task_id,
|
|
748
|
-
status: 'error',
|
|
749
|
-
error: 'Task not found.',
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
return JSON.stringify({
|
|
753
|
-
taskId: bgTask.id,
|
|
754
|
-
status: bgTask.status,
|
|
755
|
-
result: bgTask.result,
|
|
756
|
-
error: bgTask.error,
|
|
757
|
-
});
|
|
758
|
-
},
|
|
759
|
-
});
|
|
760
|
-
|
|
761
|
-
const backgroundCancel = tool({
|
|
762
|
-
description: 'Cancel a running background task.',
|
|
763
|
-
args: {
|
|
764
|
-
task_id: s.string().describe('Background task ID'),
|
|
765
|
-
},
|
|
766
|
-
async execute(args) {
|
|
767
|
-
const success = backgroundManager.cancel(args.task_id);
|
|
768
|
-
return JSON.stringify({
|
|
769
|
-
taskId: args.task_id,
|
|
770
|
-
success,
|
|
771
|
-
message: success ? 'Background task cancelled.' : 'Unable to cancel task.',
|
|
772
|
-
});
|
|
773
|
-
},
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
const backgroundInspect = tool({
|
|
777
|
-
description: `Inspect a background task to see its session messages and current state. Useful for debugging or checking what a child agent is doing.`,
|
|
778
|
-
args: {
|
|
779
|
-
task_id: s.string().describe('Background task ID to inspect'),
|
|
780
|
-
},
|
|
781
|
-
async execute(args) {
|
|
782
|
-
const inspection = await backgroundManager.inspectTask(args.task_id);
|
|
783
|
-
if (!inspection) {
|
|
784
|
-
return JSON.stringify({
|
|
785
|
-
taskId: args.task_id,
|
|
786
|
-
status: 'unknown',
|
|
787
|
-
found: false,
|
|
788
|
-
error: 'Task not found or session no longer exists.',
|
|
789
|
-
});
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
const messages = inspection.messages ?? [];
|
|
793
|
-
const enhanced =
|
|
794
|
-
inspection.messageCount !== undefined ||
|
|
795
|
-
inspection.activeTools !== undefined ||
|
|
796
|
-
inspection.todos !== undefined ||
|
|
797
|
-
inspection.costSummary !== undefined ||
|
|
798
|
-
inspection.childSessionCount !== undefined;
|
|
799
|
-
|
|
800
|
-
if (enhanced) {
|
|
801
|
-
return JSON.stringify({
|
|
802
|
-
taskId: inspection.taskId,
|
|
803
|
-
status: inspection.status,
|
|
804
|
-
found: true,
|
|
805
|
-
messageCount: inspection.messageCount ?? messages.length,
|
|
806
|
-
messages,
|
|
807
|
-
lastActivity: inspection.lastActivity,
|
|
808
|
-
activeTools: inspection.activeTools,
|
|
809
|
-
todos: inspection.todos,
|
|
810
|
-
costSummary: inspection.costSummary,
|
|
811
|
-
childSessionCount: inspection.childSessionCount,
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// Extract last few messages for summary (fallback)
|
|
816
|
-
const lastMessages = messages
|
|
817
|
-
.slice(-3)
|
|
818
|
-
.map((m) => {
|
|
819
|
-
const parts = m.parts ?? [];
|
|
820
|
-
const textParts = parts.filter(
|
|
821
|
-
(p: unknown) => (p as { type?: string }).type === 'text'
|
|
822
|
-
);
|
|
823
|
-
return textParts
|
|
824
|
-
.map((p: unknown) => ((p as { text?: string }).text ?? '').slice(0, 200))
|
|
825
|
-
.join(' ')
|
|
826
|
-
.slice(0, 300);
|
|
827
|
-
})
|
|
828
|
-
.filter(Boolean);
|
|
829
|
-
|
|
830
|
-
return JSON.stringify({
|
|
831
|
-
taskId: inspection.taskId,
|
|
832
|
-
status: inspection.status,
|
|
833
|
-
found: true,
|
|
834
|
-
messageCount: messages.length,
|
|
835
|
-
lastMessages,
|
|
836
|
-
lastActivity: inspection.lastActivity,
|
|
837
|
-
});
|
|
838
|
-
},
|
|
839
|
-
});
|
|
840
|
-
|
|
841
618
|
const sessionDashboard = tool({
|
|
842
619
|
description:
|
|
843
620
|
'Inspect a parent session dashboard from the local OpenCode SQLite database. Useful for Lead-of-Leads monitoring and nested session visibility.',
|
|
@@ -1007,10 +784,6 @@ Returns the public URL that can be copied and used anywhere.`,
|
|
|
1007
784
|
});
|
|
1008
785
|
|
|
1009
786
|
return {
|
|
1010
|
-
agentuity_background_task: backgroundTask,
|
|
1011
|
-
agentuity_background_output: backgroundOutput,
|
|
1012
|
-
agentuity_background_cancel: backgroundCancel,
|
|
1013
|
-
agentuity_background_inspect: backgroundInspect,
|
|
1014
787
|
agentuity_session_dashboard: sessionDashboard,
|
|
1015
788
|
agentuity_memory_share: memoryShare,
|
|
1016
789
|
};
|
|
@@ -1032,20 +805,6 @@ function extractSessionIdFromEvent(input: unknown): string | undefined {
|
|
|
1032
805
|
);
|
|
1033
806
|
}
|
|
1034
807
|
|
|
1035
|
-
function resolveAgentName(role: AgentRole): string {
|
|
1036
|
-
const agent = agents[role];
|
|
1037
|
-
return agent?.displayName ?? role;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
function extractEventFromInput(
|
|
1041
|
-
input: unknown
|
|
1042
|
-
): { type: string; properties?: Record<string, unknown> } | undefined {
|
|
1043
|
-
if (typeof input !== 'object' || input === null) return undefined;
|
|
1044
|
-
const inp = input as { event?: { type?: string; properties?: Record<string, unknown> } };
|
|
1045
|
-
if (!inp.event || typeof inp.event.type !== 'string') return undefined;
|
|
1046
|
-
return { type: inp.event.type, properties: inp.event.properties };
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
808
|
function parseDisplayTitle(rawTitle: string): string {
|
|
1050
809
|
try {
|
|
1051
810
|
const parsed = JSON.parse(rawTitle);
|
|
@@ -1210,7 +969,6 @@ function isMemoryPath(path: string): boolean {
|
|
|
1210
969
|
}
|
|
1211
970
|
|
|
1212
971
|
function registerShutdownHandler(
|
|
1213
|
-
manager: BackgroundManager,
|
|
1214
972
|
tmuxManager?: TmuxSessionManager,
|
|
1215
973
|
logger?: (msg: string) => void,
|
|
1216
974
|
dbReader?: OpenCodeDBReader
|
|
@@ -1238,14 +996,6 @@ function registerShutdownHandler(
|
|
|
1238
996
|
|
|
1239
997
|
log(`Shutdown triggered by ${signal ?? 'unknown'} signal`);
|
|
1240
998
|
|
|
1241
|
-
try {
|
|
1242
|
-
log('Shutting down background manager...');
|
|
1243
|
-
manager.shutdown();
|
|
1244
|
-
log('Background manager shutdown complete');
|
|
1245
|
-
} catch (error) {
|
|
1246
|
-
log(`Background manager shutdown error: ${error}`);
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
999
|
if (tmuxManager) {
|
|
1250
1000
|
try {
|
|
1251
1001
|
log('Cleaning up tmux sessions...');
|
package/src/sqlite/types.ts
CHANGED
|
@@ -142,7 +142,6 @@ export interface DBToolCallSummary {
|
|
|
142
142
|
/** Stats about what compaction preserved */
|
|
143
143
|
export interface CompactionStats {
|
|
144
144
|
planningPhasesCount: number;
|
|
145
|
-
backgroundTasksCount: number;
|
|
146
145
|
imageDescriptionsCount: number;
|
|
147
146
|
toolCallSummariesCount: number;
|
|
148
147
|
estimatedTokens: number;
|
|
@@ -153,7 +152,6 @@ export interface PreCompactionSnapshot {
|
|
|
153
152
|
timestamp: string;
|
|
154
153
|
sessionId: string;
|
|
155
154
|
planningState?: Record<string, unknown>;
|
|
156
|
-
backgroundTasks?: Array<{ id: string; description: string; status: string }>;
|
|
157
155
|
imageDescriptions?: string[];
|
|
158
156
|
toolCallSummaries?: string[];
|
|
159
157
|
cadenceState?: Record<string, unknown>;
|
package/src/tmux/manager.ts
CHANGED
|
@@ -52,7 +52,7 @@ export interface TmuxSessionManagerCallbacks {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Manages tmux panes for
|
|
55
|
+
* Manages tmux panes for agent sessions.
|
|
56
56
|
*
|
|
57
57
|
* Architecture:
|
|
58
58
|
* 1. QUERY: Get actual tmux pane state (source of truth)
|
|
@@ -106,8 +106,8 @@ export class TmuxSessionManager {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
|
-
* Handle a new
|
|
110
|
-
* This is called
|
|
109
|
+
* Handle a new subagent session being created
|
|
110
|
+
* This is called when a delegated session starts
|
|
111
111
|
*
|
|
112
112
|
* Operations are queued to prevent race conditions when multiple sessions
|
|
113
113
|
* are created rapidly.
|
|
@@ -251,7 +251,7 @@ export class TmuxSessionManager {
|
|
|
251
251
|
/**
|
|
252
252
|
* Handle a session being deleted
|
|
253
253
|
*
|
|
254
|
-
* Explicitly kills the pane when a
|
|
254
|
+
* Explicitly kills the pane when a subagent session completes.
|
|
255
255
|
* We can't rely on `opencode attach` exiting because it's an interactive
|
|
256
256
|
* terminal that keeps running even after the session goes idle.
|
|
257
257
|
*
|
package/src/tmux/types.ts
CHANGED
|
@@ -29,11 +29,11 @@ export interface WindowState {
|
|
|
29
29
|
windowWidth: number;
|
|
30
30
|
windowHeight: number;
|
|
31
31
|
mainPane: TmuxPaneInfo | null; // The pane running the main agent
|
|
32
|
-
agentPanes: TmuxPaneInfo[]; // Panes for
|
|
32
|
+
agentPanes: TmuxPaneInfo[]; // Panes for subagent sessions
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Tracked session for a
|
|
36
|
+
* Tracked session for a subagent in tmux
|
|
37
37
|
*/
|
|
38
38
|
export interface TrackedSession {
|
|
39
39
|
sessionId: string; // OpenCode session ID
|
package/src/tools/index.ts
CHANGED
|
@@ -1,9 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
BackgroundTaskArgsSchema,
|
|
4
|
-
BackgroundOutputArgsSchema,
|
|
5
|
-
BackgroundCancelArgsSchema,
|
|
6
|
-
type BackgroundTaskArgs,
|
|
7
|
-
type BackgroundOutputArgs,
|
|
8
|
-
type BackgroundCancelArgs,
|
|
9
|
-
} from './background';
|
|
1
|
+
// Tools are registered directly in plugin/plugin.ts
|
|
2
|
+
export {};
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type { BackgroundTaskConfig } from './background/types';
|
|
3
2
|
import type { SkillsConfig } from './skills/types';
|
|
4
3
|
import type { TmuxConfig } from './tmux/types';
|
|
5
4
|
|
|
@@ -11,7 +10,6 @@ export type {
|
|
|
11
10
|
ToolDefinition,
|
|
12
11
|
} from '@opencode-ai/plugin';
|
|
13
12
|
|
|
14
|
-
export type { BackgroundTaskConfig } from './background/types';
|
|
15
13
|
export type { SkillsConfig, LoadedSkill, SkillMetadata, SkillScope } from './skills';
|
|
16
14
|
export type { TmuxConfig } from './tmux/types';
|
|
17
15
|
|
|
@@ -28,7 +26,6 @@ export const AgentRoleSchema = z.enum([
|
|
|
28
26
|
'expert-ops',
|
|
29
27
|
'runner',
|
|
30
28
|
'product',
|
|
31
|
-
'monitor',
|
|
32
29
|
]);
|
|
33
30
|
export type AgentRole = z.infer<typeof AgentRoleSchema>;
|
|
34
31
|
|
|
@@ -184,20 +181,11 @@ export interface CoderConfig {
|
|
|
184
181
|
disabledMcps?: string[];
|
|
185
182
|
/** CLI command patterns to block for security (e.g., 'cloud secrets', 'auth token') */
|
|
186
183
|
blockedCommands?: string[];
|
|
187
|
-
background?: BackgroundTaskConfig;
|
|
188
184
|
skills?: SkillsConfig;
|
|
189
185
|
tmux?: TmuxConfig;
|
|
190
186
|
compaction?: CompactionConfig;
|
|
191
187
|
}
|
|
192
188
|
|
|
193
|
-
export const BackgroundTaskConfigSchema = z.object({
|
|
194
|
-
enabled: z.boolean(),
|
|
195
|
-
defaultConcurrency: z.number(),
|
|
196
|
-
staleTimeoutMs: z.number(),
|
|
197
|
-
providerConcurrency: z.record(z.string(), z.number()).optional(),
|
|
198
|
-
modelConcurrency: z.record(z.string(), z.number()).optional(),
|
|
199
|
-
});
|
|
200
|
-
|
|
201
189
|
export const SkillsConfigSchema = z.object({
|
|
202
190
|
enabled: z.boolean(),
|
|
203
191
|
paths: z.array(z.string()).optional(),
|
|
@@ -225,7 +213,6 @@ export const CoderConfigSchema = z.object({
|
|
|
225
213
|
org: z.string().optional(),
|
|
226
214
|
disabledMcps: z.array(z.string()).optional(),
|
|
227
215
|
blockedCommands: z.array(z.string()).optional(),
|
|
228
|
-
background: BackgroundTaskConfigSchema.optional(),
|
|
229
216
|
skills: SkillsConfigSchema.optional(),
|
|
230
217
|
tmux: TmuxConfigSchema.optional(),
|
|
231
218
|
compaction: CompactionConfigSchema.optional(),
|
package/dist/agents/monitor.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { AgentDefinition } from './types';
|
|
2
|
-
export declare const MONITOR_SYSTEM_PROMPT = "# BackgroundMonitor Agent\n\nYou are an auto-launched background task monitor. You were spawned automatically when Lead started background tasks. Your ONLY job is to watch those tasks and push a consolidated completion report back to Lead when they are all done.\n\n**Lead is not polling. Lead is not watching. You are the eyes. Lead trusts you to report.**\n\n## How You Discover Tasks\n\nYou receive a parent session ID in your prompt. Use it to discover all sibling tasks:\n\n```\nagentuity_session_dashboard({ session_id: \"<parentSessionId>\" })\n```\n\nThis is scoped to child sessions of that parent only \u2014 it does not expose unrelated sessions.\nFrom the dashboard, extract the task IDs (bg_xxx format) from session titles.\nThen use `agentuity_background_output({ task_id: \"bg_xxx\" })` to get status + progress for each.\n\nIgnore sessions that are other Monitor instances \u2014 their `displayTitle` will be \"Monitor background tasks\". Filter these out when processing the dashboard results.\n\n## Progress Signal\n\n`agentuity_background_output` now returns a `progress` object on running tasks:\n\n```json\n{\n \"status\": \"running\",\n \"progress\": {\n \"toolCalls\": 21,\n \"lastTool\": \"read\",\n \"lastToolSec\": 12,\n \"activeTools\": 1\n }\n}\n```\n\n- `toolCalls`: total tool calls completed \u2014 growing means active work\n- `lastTool`: name of the most recently completed tool\n- `lastToolSec`: seconds since last tool activity \u2014 <300 with growth means healthy\n- `activeTools`: tool calls currently in-flight\n\nA task is **stuck** only if `lastToolSec > 300` AND `activeTools === 0` AND `toolCalls` has not grown between checks.\n\n## Check Cadence \u2014 CRITICAL\n\n**You MUST wait at least 20 seconds between each check cycle.** This is a hard requirement, not a suggestion.\n\n- Minimum 20 seconds between checks \u2014 count them, do not rush\n- Maximum 10 check cycles total (covers ~3-4 minutes of typical work)\n- After EACH check, output: \"\u23F3 Waiting 20 seconds before next check...\" \u2014 this helps you pace yourself\n- Scout tasks typically take 3\u20138 minutes \u2014 be patient, checking faster does NOT make them complete faster\n- Excessive polling wastes tokens and provides no benefit\n\nFor each poll cycle (track cycle number starting at 1):\n1. Check each task ID with `agentuity_background_output({ task_id: \"bg_xxx\" })`\n2. Track the status of each task\n3. If any task is still \"pending\" or \"running\" **and cycle < 10**, wait 20 seconds and poll again\n4. When all tasks are \"completed\" or \"error\" **OR cycle reaches 10**, generate the final report\n\n## When Tasks Are Stuck\n\nIf a task shows `lastToolSec > 300` AND `activeTools === 0`:\n1. Call `agentuity_background_inspect({ task_id: \"bg_xxx\" })` for a full view\n2. Include what you found in your final report under \"Stuck Tasks\"\n3. Do NOT cancel the task \u2014 report it to Lead for a decision\n\n## Completion Condition\n\nAll work tasks are done when every non-monitor task is `completed`, `error`, or `cancelled`.\n\n## Final Report Format\n\nWhen all tasks are done (or after 20 cycles), output exactly this:\n\n```markdown\n## [ALL BACKGROUND TASKS COMPLETE]\n\n- **bg_xxx** (completed): [first 100 chars of result]\n- **bg_yyy** (error): [error message]\n- **bg_zzz** (completed): [first 100 chars of result]\n\n### Results\n\n**bg_xxx:**\n[full result text]\n\n**bg_yyy (error):**\n[error]\n```\n\nIf tasks are still running after 10 cycles, use \"## [BACKGROUND TASKS STILL RUNNING]\" as the header and list the stuck ones with their last known progress.\n\n## Timeout Errors\n\n- **Timeout errors** (\"Background task timed out (no activity).\") often occur when the model is\n generating a long text response without making tool calls. These are server-side inactivity\n timeouts, not true failures \u2014 the model was still working but appeared idle to the server.\n- If a task errors with a timeout, note this in your report. It may be worth retrying.\n\n## What You Do NOT Do\n\n- \u274C Interpret or analyze task results beyond summarizing\n- \u274C Make decisions about next steps\n- \u274C Cancel tasks (ever)\n- \u274C Interact with the user\n- \u274C Modify any files\n- \u274C Call other agents\n- \u274C Use tools other than agentuity_background_output, agentuity_background_inspect, and agentuity_session_dashboard\n\nYou are a patient, focused watcher. When work is done, you report. Nothing more.\n\n## Example Workflow\n\nGiven task: \"Monitor these tasks: bg_abc123, bg_def456\"\n\n1. Call agentuity_background_output for bg_abc123\n2. Call agentuity_background_output for bg_def456\n3. If any status is \"pending\" or \"running\" and cycle < 10, wait 20 seconds\n4. Repeat steps 1-3 until all complete or 10 cycles reached\n5. Output final report\n\n## Waiting Between Polls\n\nSince you cannot use setTimeout, after checking all tasks and finding some still running, you MUST output:\n\n\"\u23F3 Waiting 20 seconds before next check... (cycle 3/10)\"\n\nThen poll again. The conversation history serves as your \"timer\" \u2014 each response and check adds natural delay. Do NOT skip the waiting message.\n\n**After 10 cycles:** Report final status even if tasks are still running, noting which tasks did not complete within the monitoring window.\n";
|
|
3
|
-
export declare const monitorAgent: AgentDefinition;
|
|
4
|
-
//# sourceMappingURL=monitor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../../src/agents/monitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,qBAAqB,muKAkIjC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,eA0B1B,CAAC"}
|