@agentuity/opencode 0.1.36 → 0.1.38
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/memory.d.ts +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +170 -93
- package/dist/agents/memory.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin/hooks/cadence.d.ts +14 -2
- package/dist/plugin/hooks/cadence.d.ts.map +1 -1
- package/dist/plugin/hooks/cadence.js +60 -28
- package/dist/plugin/hooks/cadence.js.map +1 -1
- package/dist/plugin/hooks/keyword.d.ts +3 -2
- package/dist/plugin/hooks/keyword.d.ts.map +1 -1
- package/dist/plugin/hooks/keyword.js.map +1 -1
- package/dist/plugin/hooks/params.d.ts +3 -2
- package/dist/plugin/hooks/params.d.ts.map +1 -1
- package/dist/plugin/hooks/params.js +5 -2
- package/dist/plugin/hooks/params.js.map +1 -1
- package/dist/plugin/hooks/session-memory.d.ts +25 -0
- package/dist/plugin/hooks/session-memory.d.ts.map +1 -0
- package/dist/plugin/hooks/session-memory.js +111 -0
- package/dist/plugin/hooks/session-memory.js.map +1 -0
- package/dist/plugin/hooks/session.d.ts +3 -2
- package/dist/plugin/hooks/session.d.ts.map +1 -1
- package/dist/plugin/hooks/session.js.map +1 -1
- package/dist/plugin/hooks/tools.d.ts +3 -2
- package/dist/plugin/hooks/tools.d.ts.map +1 -1
- package/dist/plugin/hooks/tools.js +5 -2
- package/dist/plugin/hooks/tools.js.map +1 -1
- package/dist/plugin/plugin.d.ts +2 -2
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +41 -3
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/types.d.ts +1 -61
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
- package/src/agents/memory.ts +170 -93
- package/src/index.ts +3 -3
- package/src/plugin/hooks/cadence.ts +71 -32
- package/src/plugin/hooks/keyword.ts +3 -2
- package/src/plugin/hooks/params.ts +8 -4
- package/src/plugin/hooks/session-memory.ts +137 -0
- package/src/plugin/hooks/session.ts +3 -2
- package/src/plugin/hooks/tools.ts +12 -5
- package/src/plugin/plugin.ts +51 -7
- package/src/types.ts +10 -54
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
3
|
+
|
|
4
|
+
/** Compacting hook input/output types */
|
|
5
|
+
type CompactingInput = { sessionID: string };
|
|
6
|
+
type CompactingOutput = { context: string[]; prompt?: string };
|
|
2
7
|
|
|
3
8
|
export interface CadenceHooks {
|
|
4
9
|
onMessage: (input: unknown, output: unknown) => Promise<void>;
|
|
5
10
|
onEvent: (input: unknown) => Promise<void>;
|
|
6
11
|
onCompacting: (input: CompactingInput, output: CompactingOutput) => Promise<void>;
|
|
12
|
+
/** Check if a session is currently in Cadence mode */
|
|
13
|
+
isActiveCadenceSession: (sessionId: string) => boolean;
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
const COMPLETION_PATTERN = /<promise>\s*DONE\s*<\/promise>/i;
|
|
@@ -41,7 +48,7 @@ interface CadenceSessionState {
|
|
|
41
48
|
* 4. Trigger continuation after compaction (session.compacted)
|
|
42
49
|
* 5. Clean up on session abort/error
|
|
43
50
|
*/
|
|
44
|
-
export function createCadenceHooks(ctx:
|
|
51
|
+
export function createCadenceHooks(ctx: PluginInput, _config: CoderConfig): CadenceHooks {
|
|
45
52
|
const activeCadenceSessions = new Map<string, CadenceSessionState>();
|
|
46
53
|
|
|
47
54
|
const log = (msg: string) => {
|
|
@@ -151,7 +158,7 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
|
|
|
151
158
|
|
|
152
159
|
log(`Event received: ${event.type}`);
|
|
153
160
|
|
|
154
|
-
// Handle session.compacted -
|
|
161
|
+
// Handle session.compacted - save compaction AND continue loop
|
|
155
162
|
if (event.type === 'session.compacted') {
|
|
156
163
|
const sessionId = event.sessionId;
|
|
157
164
|
if (!sessionId) return;
|
|
@@ -159,10 +166,9 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
|
|
|
159
166
|
const state = activeCadenceSessions.get(sessionId);
|
|
160
167
|
if (!state) return;
|
|
161
168
|
|
|
162
|
-
log(`Compaction completed for Cadence session ${sessionId} -
|
|
163
|
-
showToast(ctx, '🔄
|
|
169
|
+
log(`Compaction completed for Cadence session ${sessionId} - saving and continuing`);
|
|
170
|
+
showToast(ctx, '🔄 Compaction saved, resuming Cadence...');
|
|
164
171
|
|
|
165
|
-
// Inject continuation prompt if session.prompt is available
|
|
166
172
|
try {
|
|
167
173
|
await ctx.client.session?.prompt?.({
|
|
168
174
|
path: { id: sessionId },
|
|
@@ -170,24 +176,59 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
|
|
|
170
176
|
parts: [
|
|
171
177
|
{
|
|
172
178
|
type: 'text',
|
|
173
|
-
text: `[CADENCE
|
|
179
|
+
text: `[CADENCE COMPACTION COMPLETE]
|
|
180
|
+
|
|
181
|
+
The compaction summary above contains our Cadence session context.
|
|
182
|
+
|
|
183
|
+
1. Have @Agentuity Coder Memory save this compaction:
|
|
184
|
+
- Get existing session: \`agentuity cloud kv get agentuity-opencode-memory "session:${sessionId}" --json --region use\`
|
|
185
|
+
- Append compaction to \`compactions\` array with timestamp
|
|
186
|
+
- Ensure \`cadence\` object exists with: loopId="${state.loopId ?? 'unknown'}", iteration=${state.iteration}, maxIterations=${state.maxIterations}, status="active"
|
|
187
|
+
- Save back to KV and upsert to Vector
|
|
188
|
+
|
|
189
|
+
After saving the compaction:
|
|
190
|
+
1. Read back the session record from KV
|
|
191
|
+
2. Return to Lead the PREVIOUS compactions only (not the one just saved - Lead already has the current compaction in context)
|
|
192
|
+
3. Format as a readable summary with timestamps
|
|
193
|
+
4. Include "what's next" - the Cadence iteration to continue
|
|
194
|
+
|
|
195
|
+
Response format:
|
|
196
|
+
\`\`\`
|
|
197
|
+
## Prior Session History: ${sessionId}
|
|
198
|
+
|
|
199
|
+
### Compaction 1 (timestamp)
|
|
200
|
+
[summary]
|
|
201
|
+
|
|
202
|
+
### Compaction 2 (timestamp)
|
|
203
|
+
[summary]
|
|
204
|
+
|
|
205
|
+
(Current compaction already in your context)
|
|
174
206
|
|
|
175
|
-
|
|
207
|
+
## What's Next
|
|
208
|
+
Continue Cadence iteration ${state.iteration} of ${state.maxIterations}
|
|
209
|
+
\`\`\`
|
|
176
210
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
4. Do NOT restart from the beginning - pick up where you left off
|
|
211
|
+
If no prior compactions exist:
|
|
212
|
+
\`\`\`
|
|
213
|
+
## Prior Session History: ${sessionId}
|
|
181
214
|
|
|
182
|
-
|
|
215
|
+
No prior compactions - this is the first one.
|
|
216
|
+
|
|
217
|
+
## What's Next
|
|
218
|
+
Continue Cadence iteration ${state.iteration} of ${state.maxIterations}
|
|
219
|
+
\`\`\`
|
|
220
|
+
|
|
221
|
+
2. Then continue the Cadence loop:
|
|
222
|
+
- Review the compaction summary above for context
|
|
223
|
+
- Continue with iteration ${state.iteration}
|
|
224
|
+
- Do NOT restart from the beginning - pick up where we left off`,
|
|
183
225
|
},
|
|
184
226
|
],
|
|
185
227
|
agent: 'Agentuity Coder Lead',
|
|
186
228
|
},
|
|
187
229
|
});
|
|
188
230
|
} catch (err) {
|
|
189
|
-
log(`Failed to
|
|
190
|
-
// Continuation will rely on auto-generated "Continue if you have next steps"
|
|
231
|
+
log(`Failed to save compaction and continue: ${err}`);
|
|
191
232
|
}
|
|
192
233
|
}
|
|
193
234
|
|
|
@@ -227,35 +268,33 @@ Continue executing the task.`,
|
|
|
227
268
|
log(`Injecting Cadence context during compaction for session ${sessionId}`);
|
|
228
269
|
showToast(ctx, '💾 Compacting Cadence context...');
|
|
229
270
|
|
|
230
|
-
const loopIdStr = state.loopId ?? '{loopId}';
|
|
231
|
-
|
|
232
|
-
// Inject Cadence state into the compaction context
|
|
233
271
|
output.context.push(`
|
|
234
272
|
## CADENCE MODE ACTIVE
|
|
235
273
|
|
|
236
274
|
This session is running in Cadence mode (long-running autonomous loop).
|
|
237
275
|
|
|
238
276
|
**Cadence State:**
|
|
277
|
+
- Session ID: ${sessionId}
|
|
239
278
|
- Loop ID: ${state.loopId ?? 'unknown'}
|
|
240
279
|
- Started: ${state.startedAt}
|
|
241
280
|
- Iteration: ${state.iteration} / ${state.maxIterations}
|
|
242
281
|
- Last activity: ${state.lastActivity}
|
|
243
282
|
|
|
244
|
-
**
|
|
245
|
-
|
|
246
|
-
2. Read the loop state from KV: \`agentuity cloud kv get agentuity-opencode-tasks "loop:${loopIdStr}:state"\`
|
|
247
|
-
3. Emit CADENCE_STATUS tag with current state
|
|
248
|
-
4. Continue the iteration workflow from where you left off
|
|
249
|
-
5. Do NOT restart the task from the beginning
|
|
250
|
-
|
|
251
|
-
**Memory Keys to Query:**
|
|
252
|
-
- \`loop:${loopIdStr}:state\` - Current loop state
|
|
253
|
-
- \`loop:${loopIdStr}:checkpoint:{N}\` - Iteration checkpoints
|
|
254
|
-
- \`loop:${loopIdStr}:compaction:{N}\` - Compaction snapshots
|
|
283
|
+
**Session Record Location:**
|
|
284
|
+
\`session:${sessionId}\` in agentuity-opencode-memory
|
|
255
285
|
|
|
256
|
-
|
|
286
|
+
After compaction, Memory will save this summary and update the cadence state.
|
|
287
|
+
Then Lead will continue the loop from iteration ${state.iteration}.
|
|
257
288
|
`);
|
|
258
289
|
},
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Check if a session is currently in Cadence mode.
|
|
293
|
+
* Used by session-memory hooks to avoid double-handling.
|
|
294
|
+
*/
|
|
295
|
+
isActiveCadenceSession(sessionId: string): boolean {
|
|
296
|
+
return activeCadenceSessions.has(sessionId);
|
|
297
|
+
},
|
|
259
298
|
};
|
|
260
299
|
}
|
|
261
300
|
|
|
@@ -339,9 +378,9 @@ function isCadenceStop(text: string): boolean {
|
|
|
339
378
|
);
|
|
340
379
|
}
|
|
341
380
|
|
|
342
|
-
function showToast(ctx:
|
|
381
|
+
function showToast(ctx: PluginInput, message: string): void {
|
|
343
382
|
try {
|
|
344
|
-
ctx.client.tui
|
|
383
|
+
ctx.client.tui.showToast({ body: { message, variant: 'info' } });
|
|
345
384
|
} catch {
|
|
346
385
|
// Toast may not be available
|
|
347
386
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
2
3
|
|
|
3
4
|
export interface KeywordHooks {
|
|
4
5
|
onMessage: (input: unknown, output: unknown) => Promise<void>;
|
|
@@ -35,7 +36,7 @@ Run \`agentuity ai schema show\` to see all available CLI commands.
|
|
|
35
36
|
</coder-mode>
|
|
36
37
|
`;
|
|
37
38
|
|
|
38
|
-
export function createKeywordHooks(ctx:
|
|
39
|
+
export function createKeywordHooks(ctx: PluginInput, _config: CoderConfig): KeywordHooks {
|
|
39
40
|
const activatedSessions = new Set<string>();
|
|
40
41
|
|
|
41
42
|
const log = (msg: string) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
2
3
|
|
|
3
4
|
export interface ParamsHooks {
|
|
4
5
|
onParams: (input: unknown, output: unknown) => Promise<void>;
|
|
@@ -94,7 +95,7 @@ function detectMode(
|
|
|
94
95
|
return null;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
export function createParamsHooks(ctx:
|
|
98
|
+
export function createParamsHooks(ctx: PluginInput, _config: CoderConfig): ParamsHooks {
|
|
98
99
|
return {
|
|
99
100
|
async onParams(input: unknown, output: unknown): Promise<void> {
|
|
100
101
|
// Input contains: sessionID, agent, model, provider, message
|
|
@@ -138,8 +139,11 @@ export function createParamsHooks(ctx: PluginContext, _config: CoderConfig): Par
|
|
|
138
139
|
};
|
|
139
140
|
|
|
140
141
|
try {
|
|
141
|
-
ctx.client.tui
|
|
142
|
-
body: {
|
|
142
|
+
ctx.client.tui.showToast({
|
|
143
|
+
body: {
|
|
144
|
+
message: modeMessages[detected.mode] || `${detected.mode} mode activated`,
|
|
145
|
+
variant: 'info',
|
|
146
|
+
},
|
|
143
147
|
});
|
|
144
148
|
} catch {
|
|
145
149
|
// Toast may not be available in all contexts (e.g., headless)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
3
|
+
|
|
4
|
+
export interface SessionMemoryHooks {
|
|
5
|
+
onEvent: (input: {
|
|
6
|
+
event: { type: string; properties?: Record<string, unknown> };
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
onCompacting: (
|
|
9
|
+
input: { sessionID: string },
|
|
10
|
+
output: { context: string[]; prompt?: string }
|
|
11
|
+
) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Session memory hooks handle compaction for non-Cadence sessions.
|
|
16
|
+
*
|
|
17
|
+
* Strategy:
|
|
18
|
+
* 1. On compacting: Inject Memory system info into compaction prompt
|
|
19
|
+
* 2. On session.compacted: Tell Lead to have Memory save the summary (it's already in context!)
|
|
20
|
+
*/
|
|
21
|
+
export function createSessionMemoryHooks(
|
|
22
|
+
ctx: PluginInput,
|
|
23
|
+
_config: CoderConfig
|
|
24
|
+
): SessionMemoryHooks {
|
|
25
|
+
const log = (msg: string) => {
|
|
26
|
+
ctx.client.app.log({
|
|
27
|
+
body: {
|
|
28
|
+
service: 'session-memory',
|
|
29
|
+
level: 'debug',
|
|
30
|
+
message: msg,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
/**
|
|
37
|
+
* Listen for session.compacted event.
|
|
38
|
+
* The compaction summary is already in context - just tell Lead to save it.
|
|
39
|
+
*/
|
|
40
|
+
async onEvent(input: {
|
|
41
|
+
event: { type: string; properties?: Record<string, unknown> };
|
|
42
|
+
}): Promise<void> {
|
|
43
|
+
const { event } = input;
|
|
44
|
+
if (event?.type !== 'session.compacted') return;
|
|
45
|
+
|
|
46
|
+
const sessionId =
|
|
47
|
+
(event.properties?.sessionId as string | undefined) ??
|
|
48
|
+
(event.properties?.sessionID as string | undefined);
|
|
49
|
+
|
|
50
|
+
if (!sessionId) return;
|
|
51
|
+
|
|
52
|
+
log(`Compaction complete for session ${sessionId} - triggering memory save`);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await ctx.client.session.prompt({
|
|
56
|
+
path: { id: sessionId },
|
|
57
|
+
body: {
|
|
58
|
+
parts: [
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: `[COMPACTION COMPLETE]
|
|
62
|
+
|
|
63
|
+
The compaction summary above contains our session context.
|
|
64
|
+
|
|
65
|
+
Have @Agentuity Coder Memory save this compaction:
|
|
66
|
+
1. Get existing session record (or create new): \`agentuity cloud kv get agentuity-opencode-memory "session:${sessionId}" --json --region use\`
|
|
67
|
+
2. Append this compaction summary to the \`compactions\` array with timestamp
|
|
68
|
+
3. Save back: \`agentuity cloud kv set agentuity-opencode-memory "session:${sessionId}" '{...}' --region use\`
|
|
69
|
+
4. Upsert to Vector for semantic search: \`agentuity cloud vector upsert agentuity-opencode-sessions "session:${sessionId}" --document "..." --metadata '...' --region use\`
|
|
70
|
+
|
|
71
|
+
After saving the compaction:
|
|
72
|
+
1. Read back the session record from KV
|
|
73
|
+
2. Return to Lead the PREVIOUS compactions only (not the one just saved - Lead already has the current compaction in context)
|
|
74
|
+
3. Format as a readable summary with timestamps
|
|
75
|
+
4. Include "what's next" - the user's pending request if there is one
|
|
76
|
+
|
|
77
|
+
Response format:
|
|
78
|
+
\`\`\`
|
|
79
|
+
## Prior Session History: ${sessionId}
|
|
80
|
+
|
|
81
|
+
### Compaction 1 (timestamp)
|
|
82
|
+
[summary]
|
|
83
|
+
|
|
84
|
+
### Compaction 2 (timestamp)
|
|
85
|
+
[summary]
|
|
86
|
+
|
|
87
|
+
(Current compaction already in your context)
|
|
88
|
+
|
|
89
|
+
## What's Next
|
|
90
|
+
[User's pending request if there is one]
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
If no prior compactions exist:
|
|
94
|
+
\`\`\`
|
|
95
|
+
## Prior Session History: ${sessionId}
|
|
96
|
+
|
|
97
|
+
No prior compactions - this is the first one.
|
|
98
|
+
|
|
99
|
+
## What's Next
|
|
100
|
+
[User's pending request if there is one]
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
Then continue with the current task if there is one.`,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
agent: 'Agentuity Coder Lead',
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
log(`Memory save triggered for session ${sessionId}`);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
log(`Failed to trigger memory save: ${err}`);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Inject Memory system info during compaction.
|
|
118
|
+
* This gets included in OpenCode's generated summary.
|
|
119
|
+
*/
|
|
120
|
+
async onCompacting(
|
|
121
|
+
input: { sessionID: string },
|
|
122
|
+
output: { context: string[]; prompt?: string }
|
|
123
|
+
): Promise<void> {
|
|
124
|
+
const sessionId = input.sessionID;
|
|
125
|
+
log(`Compacting session ${sessionId}`);
|
|
126
|
+
|
|
127
|
+
output.context.push(`
|
|
128
|
+
## Session Memory
|
|
129
|
+
|
|
130
|
+
This session's context is being saved to persistent memory.
|
|
131
|
+
Session record location: \`session:${sessionId}\` in agentuity-opencode-memory
|
|
132
|
+
|
|
133
|
+
After compaction, Memory will automatically save this summary for future recovery.
|
|
134
|
+
`);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
2
3
|
|
|
3
4
|
export interface SessionHooks {
|
|
4
5
|
onMessage: (input: unknown, output: unknown) => Promise<void>;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
export function createSessionHooks(_ctx:
|
|
8
|
+
export function createSessionHooks(_ctx: PluginInput, _config: CoderConfig): SessionHooks {
|
|
8
9
|
const initializedSessions = new Set<string>();
|
|
9
10
|
|
|
10
11
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import type { CoderConfig } from '../../types';
|
|
2
3
|
import { checkAuth } from '../../services/auth';
|
|
3
4
|
|
|
4
5
|
export interface ToolHooks {
|
|
@@ -33,7 +34,7 @@ const CLOUD_SERVICES: Record<string, { name: string; emoji: string }> = {
|
|
|
33
34
|
'agentuity cloud scp': { name: 'File Transfer', emoji: '📤' },
|
|
34
35
|
};
|
|
35
36
|
|
|
36
|
-
export function createToolHooks(ctx:
|
|
37
|
+
export function createToolHooks(ctx: PluginInput, config: CoderConfig): ToolHooks {
|
|
37
38
|
const blockedCommands = config.blockedCommands ?? [];
|
|
38
39
|
|
|
39
40
|
return {
|
|
@@ -79,7 +80,10 @@ export function createToolHooks(ctx: PluginContext, config: CoderConfig): ToolHo
|
|
|
79
80
|
// Check if AGENTUITY_PROFILE already exists (anywhere in the command)
|
|
80
81
|
if (/AGENTUITY_PROFILE=\S+/.test(command)) {
|
|
81
82
|
// Replace all existing AGENTUITY_PROFILE occurrences to enforce our profile
|
|
82
|
-
modifiedCommand = command.replace(
|
|
83
|
+
modifiedCommand = command.replace(
|
|
84
|
+
/AGENTUITY_PROFILE=\S+/g,
|
|
85
|
+
`AGENTUITY_PROFILE=${profile}`
|
|
86
|
+
);
|
|
83
87
|
} else {
|
|
84
88
|
// Prepend AGENTUITY_PROFILE
|
|
85
89
|
modifiedCommand = `AGENTUITY_PROFILE=${profile} ${command}`;
|
|
@@ -90,8 +94,11 @@ export function createToolHooks(ctx: PluginContext, config: CoderConfig): ToolHo
|
|
|
90
94
|
const service = detectCloudService(command);
|
|
91
95
|
if (service) {
|
|
92
96
|
try {
|
|
93
|
-
ctx.client.tui
|
|
94
|
-
body: {
|
|
97
|
+
ctx.client.tui.showToast({
|
|
98
|
+
body: {
|
|
99
|
+
message: `${service.emoji} Agentuity ${service.name}`,
|
|
100
|
+
variant: 'info',
|
|
101
|
+
},
|
|
95
102
|
});
|
|
96
103
|
} catch {
|
|
97
104
|
// Toast may not be available
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PluginInput, Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
import type { AgentConfig, CommandDefinition } from '../types';
|
|
2
3
|
import { agents } from '../agents';
|
|
3
4
|
import { loadCoderConfig, getDefaultConfig, mergeConfig } from '../config';
|
|
4
5
|
import { createSessionHooks } from './hooks/session';
|
|
@@ -6,6 +7,7 @@ import { createToolHooks } from './hooks/tools';
|
|
|
6
7
|
import { createKeywordHooks } from './hooks/keyword';
|
|
7
8
|
import { createParamsHooks } from './hooks/params';
|
|
8
9
|
import { createCadenceHooks } from './hooks/cadence';
|
|
10
|
+
import { createSessionMemoryHooks } from './hooks/session-memory';
|
|
9
11
|
import { z } from 'zod';
|
|
10
12
|
import type { AgentRole } from '../types';
|
|
11
13
|
|
|
@@ -19,7 +21,7 @@ const AGENT_MENTIONS: Record<AgentRole, string> = {
|
|
|
19
21
|
expert: '@Agentuity Coder Expert',
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
export async function createCoderPlugin(ctx:
|
|
24
|
+
export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
23
25
|
ctx.client.app.log({
|
|
24
26
|
body: {
|
|
25
27
|
service: 'agentuity-coder',
|
|
@@ -37,6 +39,10 @@ export async function createCoderPlugin(ctx: PluginContext): Promise<PluginHooks
|
|
|
37
39
|
const paramsHooks = createParamsHooks(ctx, coderConfig);
|
|
38
40
|
const cadenceHooks = createCadenceHooks(ctx, coderConfig);
|
|
39
41
|
|
|
42
|
+
// Session memory hooks handle checkpointing and compaction for non-Cadence sessions
|
|
43
|
+
// Orchestration (deciding which module handles which session) happens below in the hooks
|
|
44
|
+
const sessionMemoryHooks = createSessionMemoryHooks(ctx, coderConfig);
|
|
45
|
+
|
|
40
46
|
const configHandler = createConfigHandler(coderConfig);
|
|
41
47
|
|
|
42
48
|
// Get the tool helper from Open Code context if available
|
|
@@ -48,7 +54,9 @@ export async function createCoderPlugin(ctx: PluginContext): Promise<PluginHooks
|
|
|
48
54
|
|
|
49
55
|
// Show startup toast (fire and forget, don't block)
|
|
50
56
|
try {
|
|
51
|
-
ctx.client.tui
|
|
57
|
+
ctx.client.tui.showToast({
|
|
58
|
+
body: { message: '🚀 Agentuity Coder ready', variant: 'success' },
|
|
59
|
+
});
|
|
52
60
|
} catch {
|
|
53
61
|
// Toast may not be available
|
|
54
62
|
}
|
|
@@ -64,8 +72,26 @@ export async function createCoderPlugin(ctx: PluginContext): Promise<PluginHooks
|
|
|
64
72
|
'chat.params': paramsHooks.onParams,
|
|
65
73
|
'tool.execute.before': toolHooks.before,
|
|
66
74
|
'tool.execute.after': toolHooks.after,
|
|
67
|
-
event:
|
|
68
|
-
|
|
75
|
+
event: async (input) => {
|
|
76
|
+
// Orchestrate: route to appropriate module based on session type
|
|
77
|
+
const sessionId = extractSessionIdFromEvent(input);
|
|
78
|
+
if (sessionId && cadenceHooks.isActiveCadenceSession(sessionId)) {
|
|
79
|
+
await cadenceHooks.onEvent(input);
|
|
80
|
+
} else if (sessionId) {
|
|
81
|
+
// Non-Cadence sessions - handle session.compacted for checkpointing
|
|
82
|
+
await sessionMemoryHooks.onEvent(
|
|
83
|
+
input as { event: { type: string; properties?: Record<string, unknown> } }
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
'experimental.session.compacting': async (input, output) => {
|
|
88
|
+
// Orchestrate: route to appropriate module based on session type
|
|
89
|
+
if (cadenceHooks.isActiveCadenceSession(input.sessionID)) {
|
|
90
|
+
await cadenceHooks.onCompacting(input, output);
|
|
91
|
+
} else {
|
|
92
|
+
await sessionMemoryHooks.onCompacting(input, output);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
69
95
|
};
|
|
70
96
|
}
|
|
71
97
|
|
|
@@ -304,7 +330,7 @@ $ARGUMENTS
|
|
|
304
330
|
};
|
|
305
331
|
}
|
|
306
332
|
|
|
307
|
-
function createTools(tool: (schema: (s: typeof z) => unknown) => unknown):
|
|
333
|
+
function createTools(tool: (schema: (s: typeof z) => unknown) => unknown): Hooks['tool'] {
|
|
308
334
|
const coderDelegate = tool((s) => ({
|
|
309
335
|
description: `Delegate a task to a specialized Agentuity Coder agent.
|
|
310
336
|
|
|
@@ -333,7 +359,25 @@ Use this to:
|
|
|
333
359
|
},
|
|
334
360
|
}));
|
|
335
361
|
|
|
362
|
+
// Type assertion needed because the tool() helper returns unknown
|
|
363
|
+
// but the runtime type is correct (it's created by OpenCode's tool helper)
|
|
336
364
|
return {
|
|
337
365
|
coder_delegate: coderDelegate,
|
|
338
|
-
};
|
|
366
|
+
} as Hooks['tool'];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
370
|
+
// Helper Functions
|
|
371
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
372
|
+
|
|
373
|
+
function extractSessionIdFromEvent(input: unknown): string | undefined {
|
|
374
|
+
if (typeof input !== 'object' || input === null) return undefined;
|
|
375
|
+
|
|
376
|
+
const inp = input as { event?: { properties?: Record<string, unknown> } };
|
|
377
|
+
if (!inp.event?.properties) return undefined;
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
(inp.event.properties.sessionId as string | undefined) ??
|
|
381
|
+
(inp.event.properties.sessionID as string | undefined)
|
|
382
|
+
);
|
|
339
383
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
+
// Re-export types from @opencode-ai/plugin
|
|
4
|
+
export type {
|
|
5
|
+
Plugin,
|
|
6
|
+
PluginInput,
|
|
7
|
+
Hooks as PluginHooks,
|
|
8
|
+
ToolDefinition,
|
|
9
|
+
} from '@opencode-ai/plugin';
|
|
10
|
+
|
|
3
11
|
export const AgentRoleSchema = z.enum(['lead', 'scout', 'builder', 'reviewer', 'memory', 'expert']);
|
|
4
12
|
export type AgentRole = z.infer<typeof AgentRoleSchema>;
|
|
5
13
|
|
|
@@ -114,55 +122,7 @@ export interface McpConfig {
|
|
|
114
122
|
headers?: Record<string, string>;
|
|
115
123
|
}
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
app: {
|
|
119
|
-
log: (options: {
|
|
120
|
-
body: { service: string; level: string; message: string; extra?: unknown };
|
|
121
|
-
}) => void;
|
|
122
|
-
};
|
|
123
|
-
tui?: {
|
|
124
|
-
showToast?: (options: { body: { message: string } }) => void;
|
|
125
|
-
};
|
|
126
|
-
session?: {
|
|
127
|
-
prompt?: (options: {
|
|
128
|
-
path: { id: string };
|
|
129
|
-
body: {
|
|
130
|
-
parts: Array<{ type: 'text'; text: string }>;
|
|
131
|
-
agent?: string;
|
|
132
|
-
};
|
|
133
|
-
noReply?: boolean;
|
|
134
|
-
}) => Promise<unknown>;
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export interface PluginContext {
|
|
139
|
-
directory: string;
|
|
140
|
-
client: PluginClient;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface CompactingInput {
|
|
144
|
-
sessionID: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export interface CompactingOutput {
|
|
148
|
-
context: string[];
|
|
149
|
-
prompt?: string;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export interface PluginHooks {
|
|
153
|
-
agents?: Record<string, AgentConfig>;
|
|
154
|
-
tool?: Record<string, unknown>; // Open Code tool format (created via tool() helper)
|
|
155
|
-
config?: (config: Record<string, unknown>) => Promise<void>;
|
|
156
|
-
'chat.message'?: (input: unknown, output: unknown) => Promise<void>;
|
|
157
|
-
'chat.params'?: (input: unknown, output: unknown) => Promise<void>;
|
|
158
|
-
'tool.execute.before'?: (input: unknown, output: unknown) => Promise<void>;
|
|
159
|
-
'tool.execute.after'?: (input: unknown, output: unknown) => Promise<void>;
|
|
160
|
-
event?: (input: unknown) => Promise<void>;
|
|
161
|
-
'experimental.session.compacting'?: (
|
|
162
|
-
input: CompactingInput,
|
|
163
|
-
output: CompactingOutput
|
|
164
|
-
) => Promise<void>;
|
|
165
|
-
}
|
|
125
|
+
// Note: PluginInput and PluginHooks are now imported from @opencode-ai/plugin above.
|
|
166
126
|
|
|
167
127
|
export interface CommandDefinition {
|
|
168
128
|
name: string;
|
|
@@ -175,8 +135,4 @@ export interface CommandDefinition {
|
|
|
175
135
|
subtask?: boolean;
|
|
176
136
|
}
|
|
177
137
|
|
|
178
|
-
|
|
179
|
-
description: string;
|
|
180
|
-
args: unknown; // Zod schema or JSON schema
|
|
181
|
-
execute: (args: unknown, context: unknown) => Promise<unknown>;
|
|
182
|
-
}
|
|
138
|
+
// ToolDefinition is re-exported from @opencode-ai/plugin above
|