agent-orchestrator-mcp-server 0.7.16 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/package.json +1 -1
- package/shared/orchestrator-client/orchestrator-client.d.ts +7 -7
- package/shared/orchestrator-client/orchestrator-client.integration-mock.js +13 -13
- package/shared/orchestrator-client/orchestrator-client.js +3 -3
- package/shared/resources.js +6 -6
- package/shared/tools/action-session.js +2 -2
- package/shared/tools/action-trigger.d.ts +4 -4
- package/shared/tools/action-trigger.js +4 -4
- package/shared/tools/get-configs.js +16 -16
- package/shared/tools/get-session.js +2 -2
- package/shared/tools/manage-enqueued-messages.d.ts +4 -4
- package/shared/tools/manage-enqueued-messages.js +11 -11
- package/shared/tools/search-triggers.js +2 -2
- package/shared/tools/start-session.d.ts +5 -5
- package/shared/tools/start-session.js +10 -10
- package/shared/tools/wake-me-up-when-session-changes-state.d.ts +4 -4
- package/shared/tools/wake-me-up-when-session-changes-state.js +33 -14
- package/shared/types.d.ts +10 -10
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ MCP server for PulseMCP's agent-orchestrator: a Claude Code + MCP-powered agent-
|
|
|
25
25
|
| -------------------------- | ------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
26
26
|
| `quick_search_sessions` | sessions | read | Quick title-based search/list sessions with optional ID lookup, title query, and status filter |
|
|
27
27
|
| `get_session` | sessions | read | Get detailed session info with optional logs, transcripts, and transcript format (text/json) |
|
|
28
|
-
| `get_configs` | sessions | read | Fetch all static configuration (MCP servers, agent roots,
|
|
28
|
+
| `get_configs` | sessions | read | Fetch all static configuration (MCP servers, agent roots, goals) |
|
|
29
29
|
| `get_transcript_archive` | sessions | read | Get download URL and metadata for the transcript archive zip file |
|
|
30
30
|
| `start_session` | sessions | write | Create and start a new agent session |
|
|
31
31
|
| `action_session` | sessions | write | Perform actions: follow_up, pause, restart, archive, unarchive, change_mcp_servers, change_model, fork, refresh, refresh_all, update_notes, update_title, toggle_favorite, bulk_archive |
|
|
@@ -40,12 +40,12 @@ MCP server for PulseMCP's agent-orchestrator: a Claude Code + MCP-powered agent-
|
|
|
40
40
|
|
|
41
41
|
### Resources
|
|
42
42
|
|
|
43
|
-
| Resource
|
|
44
|
-
|
|
|
45
|
-
| `agent-orchestrator://config`
|
|
46
|
-
| `agent-orchestrator://configs/mcp-servers`
|
|
47
|
-
| `agent-orchestrator://configs/agent-roots`
|
|
48
|
-
| `agent-orchestrator://configs/
|
|
43
|
+
| Resource | Description |
|
|
44
|
+
| ------------------------------------------ | ----------------------------------------------- |
|
|
45
|
+
| `agent-orchestrator://config` | Server configuration and status (for debugging) |
|
|
46
|
+
| `agent-orchestrator://configs/mcp-servers` | List of available MCP servers for sessions |
|
|
47
|
+
| `agent-orchestrator://configs/agent-roots` | Preconfigured repository settings with defaults |
|
|
48
|
+
| `agent-orchestrator://configs/goals` | Session completion criteria definitions |
|
|
49
49
|
|
|
50
50
|
### Tool Groups
|
|
51
51
|
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ export interface RawAgentRoot {
|
|
|
13
13
|
default_branch?: string;
|
|
14
14
|
subdirectory?: string;
|
|
15
15
|
custom?: boolean;
|
|
16
|
-
|
|
16
|
+
default_goal?: string;
|
|
17
17
|
default?: boolean;
|
|
18
18
|
default_mcp_servers?: string[];
|
|
19
19
|
default_skills?: string[];
|
|
@@ -52,7 +52,7 @@ export interface IAgentOrchestratorClient {
|
|
|
52
52
|
unarchiveSession(id: string | number): Promise<Session>;
|
|
53
53
|
followUp(id: string | number, prompt: string, options?: {
|
|
54
54
|
force_immediate?: boolean;
|
|
55
|
-
|
|
55
|
+
goal?: string;
|
|
56
56
|
}): Promise<SessionActionResponse>;
|
|
57
57
|
pauseSession(id: string | number): Promise<SessionActionResponse>;
|
|
58
58
|
sleepSession(id: string | number): Promise<Session>;
|
|
@@ -98,11 +98,11 @@ export interface IAgentOrchestratorClient {
|
|
|
98
98
|
getEnqueuedMessage(sessionId: string | number, messageId: number): Promise<EnqueuedMessage>;
|
|
99
99
|
createEnqueuedMessage(sessionId: string | number, data: {
|
|
100
100
|
content: string;
|
|
101
|
-
|
|
101
|
+
goal?: string;
|
|
102
102
|
}): Promise<EnqueuedMessage>;
|
|
103
103
|
updateEnqueuedMessage(sessionId: string | number, messageId: number, data: {
|
|
104
104
|
content?: string;
|
|
105
|
-
|
|
105
|
+
goal?: string;
|
|
106
106
|
}): Promise<EnqueuedMessage>;
|
|
107
107
|
deleteEnqueuedMessage(sessionId: string | number, messageId: number): Promise<void>;
|
|
108
108
|
reorderEnqueuedMessage(sessionId: string | number, messageId: number, position: number): Promise<EnqueuedMessage>;
|
|
@@ -179,7 +179,7 @@ export declare class AgentOrchestratorClient implements IAgentOrchestratorClient
|
|
|
179
179
|
unarchiveSession(id: string | number): Promise<Session>;
|
|
180
180
|
followUp(id: string | number, prompt: string, options?: {
|
|
181
181
|
force_immediate?: boolean;
|
|
182
|
-
|
|
182
|
+
goal?: string;
|
|
183
183
|
}): Promise<SessionActionResponse>;
|
|
184
184
|
pauseSession(id: string | number): Promise<SessionActionResponse>;
|
|
185
185
|
sleepSession(id: string | number): Promise<Session>;
|
|
@@ -225,11 +225,11 @@ export declare class AgentOrchestratorClient implements IAgentOrchestratorClient
|
|
|
225
225
|
getEnqueuedMessage(sessionId: string | number, messageId: number): Promise<EnqueuedMessage>;
|
|
226
226
|
createEnqueuedMessage(sessionId: string | number, data: {
|
|
227
227
|
content: string;
|
|
228
|
-
|
|
228
|
+
goal?: string;
|
|
229
229
|
}): Promise<EnqueuedMessage>;
|
|
230
230
|
updateEnqueuedMessage(sessionId: string | number, messageId: number, data: {
|
|
231
231
|
content?: string;
|
|
232
|
-
|
|
232
|
+
goal?: string;
|
|
233
233
|
}): Promise<EnqueuedMessage>;
|
|
234
234
|
deleteEnqueuedMessage(sessionId: string | number, messageId: number): Promise<void>;
|
|
235
235
|
reorderEnqueuedMessage(sessionId: string | number, messageId: number, position: number): Promise<EnqueuedMessage>;
|
|
@@ -20,7 +20,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
20
20
|
branch: 'main',
|
|
21
21
|
subdirectory: null,
|
|
22
22
|
execution_provider: 'local_filesystem',
|
|
23
|
-
|
|
23
|
+
goal: null,
|
|
24
24
|
mcp_servers: ['github-development'],
|
|
25
25
|
config: {},
|
|
26
26
|
metadata: { clone_path: 'repo-main-123' },
|
|
@@ -144,7 +144,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
144
144
|
branch: data.branch || 'main',
|
|
145
145
|
subdirectory: data.subdirectory || null,
|
|
146
146
|
execution_provider: data.execution_provider || 'local_filesystem',
|
|
147
|
-
|
|
147
|
+
goal: data.goal || null,
|
|
148
148
|
mcp_servers: data.mcp_servers || [],
|
|
149
149
|
config: data.config || {},
|
|
150
150
|
metadata: {},
|
|
@@ -168,8 +168,8 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
168
168
|
session.title = data.title;
|
|
169
169
|
if (data.slug !== undefined)
|
|
170
170
|
session.slug = data.slug;
|
|
171
|
-
if (data.
|
|
172
|
-
session.
|
|
171
|
+
if (data.goal !== undefined)
|
|
172
|
+
session.goal = data.goal;
|
|
173
173
|
if (data.mcp_servers !== undefined)
|
|
174
174
|
session.mcp_servers = data.mcp_servers;
|
|
175
175
|
if (data.custom_metadata !== undefined)
|
|
@@ -447,7 +447,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
447
447
|
default_skills: ['discovery-classify', 'discovery-validate'],
|
|
448
448
|
},
|
|
449
449
|
],
|
|
450
|
-
|
|
450
|
+
goals: [
|
|
451
451
|
{
|
|
452
452
|
id: 'pr_merged',
|
|
453
453
|
name: 'PR Merged',
|
|
@@ -546,7 +546,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
546
546
|
id: messageId,
|
|
547
547
|
session_id: 1,
|
|
548
548
|
content: 'Test message',
|
|
549
|
-
|
|
549
|
+
goal: null,
|
|
550
550
|
position: 1,
|
|
551
551
|
status: 'pending',
|
|
552
552
|
created_at: new Date().toISOString(),
|
|
@@ -558,7 +558,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
558
558
|
id: 1,
|
|
559
559
|
session_id: Number(sessionId),
|
|
560
560
|
content: data.content,
|
|
561
|
-
|
|
561
|
+
goal: data.goal || null,
|
|
562
562
|
position: 1,
|
|
563
563
|
status: 'pending',
|
|
564
564
|
created_at: new Date().toISOString(),
|
|
@@ -570,7 +570,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
570
570
|
id: messageId,
|
|
571
571
|
session_id: 1,
|
|
572
572
|
content: data.content || 'Updated message',
|
|
573
|
-
|
|
573
|
+
goal: data.goal || null,
|
|
574
574
|
position: 1,
|
|
575
575
|
status: 'pending',
|
|
576
576
|
created_at: new Date().toISOString(),
|
|
@@ -585,7 +585,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
585
585
|
id: messageId,
|
|
586
586
|
session_id: 1,
|
|
587
587
|
content: 'Test message',
|
|
588
|
-
|
|
588
|
+
goal: null,
|
|
589
589
|
position,
|
|
590
590
|
status: 'pending',
|
|
591
591
|
created_at: new Date().toISOString(),
|
|
@@ -614,7 +614,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
614
614
|
status: 'enabled',
|
|
615
615
|
agent_root_name: 'mcp-servers',
|
|
616
616
|
prompt_template: 'Test prompt',
|
|
617
|
-
|
|
617
|
+
goal: null,
|
|
618
618
|
reuse_session: false,
|
|
619
619
|
mcp_servers: [],
|
|
620
620
|
conditions: [
|
|
@@ -650,7 +650,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
650
650
|
status: data.status || 'enabled',
|
|
651
651
|
agent_root_name: data.agent_root_name,
|
|
652
652
|
prompt_template: data.prompt_template,
|
|
653
|
-
|
|
653
|
+
goal: data.goal || null,
|
|
654
654
|
reuse_session: data.reuse_session || false,
|
|
655
655
|
mcp_servers: data.mcp_servers || [],
|
|
656
656
|
conditions,
|
|
@@ -676,7 +676,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
676
676
|
status: data.status || 'enabled',
|
|
677
677
|
agent_root_name: data.agent_root_name || 'mcp-servers',
|
|
678
678
|
prompt_template: data.prompt_template || 'Test prompt',
|
|
679
|
-
|
|
679
|
+
goal: data.goal || null,
|
|
680
680
|
reuse_session: data.reuse_session || false,
|
|
681
681
|
mcp_servers: data.mcp_servers || [],
|
|
682
682
|
conditions,
|
|
@@ -697,7 +697,7 @@ export function createIntegrationMockOrchestratorClient(initialMockData) {
|
|
|
697
697
|
status: 'disabled',
|
|
698
698
|
agent_root_name: 'mcp-servers',
|
|
699
699
|
prompt_template: 'Test prompt',
|
|
700
|
-
|
|
700
|
+
goal: null,
|
|
701
701
|
reuse_session: false,
|
|
702
702
|
mcp_servers: [],
|
|
703
703
|
conditions: [],
|
|
@@ -16,7 +16,7 @@ export function mapAgentRoot(raw) {
|
|
|
16
16
|
git_root: raw.url,
|
|
17
17
|
default_branch: raw.default_branch,
|
|
18
18
|
default_subdirectory: raw.subdirectory,
|
|
19
|
-
|
|
19
|
+
default_goal: raw.default_goal,
|
|
20
20
|
default_mcp_servers: raw.default_mcp_servers,
|
|
21
21
|
default_skills: raw.default_skills,
|
|
22
22
|
default_model: raw.default_model,
|
|
@@ -208,7 +208,7 @@ export class AgentOrchestratorClient {
|
|
|
208
208
|
return this.request('POST', `/sessions/${id}/follow_up`, {
|
|
209
209
|
prompt,
|
|
210
210
|
...(options?.force_immediate && { force_immediate: true }),
|
|
211
|
-
...(options?.
|
|
211
|
+
...(options?.goal && { goal: options.goal }),
|
|
212
212
|
});
|
|
213
213
|
}
|
|
214
214
|
async pauseSession(id) {
|
|
@@ -282,7 +282,7 @@ export class AgentOrchestratorClient {
|
|
|
282
282
|
return {
|
|
283
283
|
mcp_servers: raw.mcp_servers,
|
|
284
284
|
agent_roots: raw.agent_roots.map(mapAgentRoot),
|
|
285
|
-
|
|
285
|
+
goals: raw.goals,
|
|
286
286
|
};
|
|
287
287
|
}
|
|
288
288
|
// Notifications
|
package/shared/resources.js
CHANGED
|
@@ -26,12 +26,12 @@ export function createRegisterResources(clientFactory) {
|
|
|
26
26
|
{
|
|
27
27
|
uri: 'agent-orchestrator://configs/agent-roots',
|
|
28
28
|
name: 'Agent Roots',
|
|
29
|
-
description: 'Preconfigured repository settings with default branch, MCP servers, and
|
|
29
|
+
description: 'Preconfigured repository settings with default branch, MCP servers, and goals.',
|
|
30
30
|
mimeType: 'application/json',
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
uri: 'agent-orchestrator://configs/
|
|
34
|
-
name: '
|
|
33
|
+
uri: 'agent-orchestrator://configs/goals',
|
|
34
|
+
name: 'Goals',
|
|
35
35
|
description: 'Available session completion criteria for use with start_session.',
|
|
36
36
|
mimeType: 'application/json',
|
|
37
37
|
},
|
|
@@ -121,15 +121,15 @@ export function createRegisterResources(clientFactory) {
|
|
|
121
121
|
],
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
if (uri === 'agent-orchestrator://configs/
|
|
124
|
+
if (uri === 'agent-orchestrator://configs/goals') {
|
|
125
125
|
return {
|
|
126
126
|
contents: [
|
|
127
127
|
{
|
|
128
128
|
uri,
|
|
129
129
|
mimeType: 'application/json',
|
|
130
130
|
text: JSON.stringify({
|
|
131
|
-
|
|
132
|
-
_usage: 'Use the "id" field when specifying
|
|
131
|
+
goals: configs.goals,
|
|
132
|
+
_usage: 'Use the "id" field when specifying goal in start_session',
|
|
133
133
|
}, null, 2),
|
|
134
134
|
},
|
|
135
135
|
],
|
|
@@ -43,7 +43,7 @@ export const ActionSessionSchema = z.object({
|
|
|
43
43
|
const TOOL_DESCRIPTION = `Perform an action on an agent session.
|
|
44
44
|
|
|
45
45
|
**Actions:**
|
|
46
|
-
- **follow_up**: Send a follow-up prompt to a session (requires "prompt"; optional "force_immediate" to interrupt a running session). Without "force_immediate", uses smart routing: sends immediately if idle, auto-queues if running. Alternative: use manage_enqueued_messages "send_now" for one-step immediate delivery with
|
|
46
|
+
- **follow_up**: Send a follow-up prompt to a session (requires "prompt"; optional "force_immediate" to interrupt a running session). Without "force_immediate", uses smart routing: sends immediately if idle, auto-queues if running. Alternative: use manage_enqueued_messages "send_now" for one-step immediate delivery with goal support.
|
|
47
47
|
- **pause**: Pause a running session, transitioning it to idle "needs_input" status
|
|
48
48
|
- **restart**: Restart an idle or failed session without providing new input
|
|
49
49
|
- **archive**: Archive a session (marks as completed)
|
|
@@ -527,7 +527,7 @@ const SELF_SESSION_TOOL_DESCRIPTION = `Perform a self-management action on a ses
|
|
|
527
527
|
- Archive the session when work is complete
|
|
528
528
|
|
|
529
529
|
**Archive guidelines:**
|
|
530
|
-
- Only self-archive when explicitly instructed to (e.g., a
|
|
530
|
+
- Only self-archive when explicitly instructed to (e.g., a goal says "archive yourself")
|
|
531
531
|
- Subagents that report results back to a parent agent via a tool call may self-archive, since no human needs to read the session output directly
|
|
532
532
|
- Do NOT self-archive if a human user needs to read your output. Sessions in \`needs_input\` appear on the user's homepage — archiving removes them before the user can see your work. If your work product is a message the user should read, let the session stay in \`needs_input\``;
|
|
533
533
|
export function selfSessionActionSessionTool(_server, clientFactory) {
|
|
@@ -9,14 +9,14 @@ export declare const ActionTriggerSchema: z.ZodObject<{
|
|
|
9
9
|
agent_root_name: z.ZodOptional<z.ZodString>;
|
|
10
10
|
prompt_template: z.ZodOptional<z.ZodString>;
|
|
11
11
|
status: z.ZodOptional<z.ZodEnum<["enabled", "disabled"]>>;
|
|
12
|
-
|
|
12
|
+
goal: z.ZodOptional<z.ZodString>;
|
|
13
13
|
reuse_session: z.ZodOptional<z.ZodBoolean>;
|
|
14
14
|
mcp_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
15
15
|
configuration: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
16
16
|
}, "strip", z.ZodTypeAny, {
|
|
17
17
|
action: "create" | "update" | "delete" | "toggle";
|
|
18
18
|
status?: "enabled" | "disabled" | undefined;
|
|
19
|
-
|
|
19
|
+
goal?: string | undefined;
|
|
20
20
|
mcp_servers?: string[] | undefined;
|
|
21
21
|
trigger_type?: "slack" | "schedule" | undefined;
|
|
22
22
|
id?: number | undefined;
|
|
@@ -28,7 +28,7 @@ export declare const ActionTriggerSchema: z.ZodObject<{
|
|
|
28
28
|
}, {
|
|
29
29
|
action: "create" | "update" | "delete" | "toggle";
|
|
30
30
|
status?: "enabled" | "disabled" | undefined;
|
|
31
|
-
|
|
31
|
+
goal?: string | undefined;
|
|
32
32
|
mcp_servers?: string[] | undefined;
|
|
33
33
|
trigger_type?: "slack" | "schedule" | undefined;
|
|
34
34
|
id?: number | undefined;
|
|
@@ -75,7 +75,7 @@ export declare function actionTriggerTool(_server: Server, clientFactory: () =>
|
|
|
75
75
|
enum: string[];
|
|
76
76
|
description: string;
|
|
77
77
|
};
|
|
78
|
-
|
|
78
|
+
goal: {
|
|
79
79
|
type: string;
|
|
80
80
|
description: string;
|
|
81
81
|
};
|
|
@@ -9,7 +9,7 @@ export const ActionTriggerSchema = z.object({
|
|
|
9
9
|
agent_root_name: z.string().optional(),
|
|
10
10
|
prompt_template: z.string().optional(),
|
|
11
11
|
status: z.enum(['enabled', 'disabled']).optional(),
|
|
12
|
-
|
|
12
|
+
goal: z.string().optional(),
|
|
13
13
|
reuse_session: z.boolean().optional(),
|
|
14
14
|
mcp_servers: z.array(z.string()).optional(),
|
|
15
15
|
configuration: z.record(z.unknown()).optional(),
|
|
@@ -49,7 +49,7 @@ export function actionTriggerTool(_server, clientFactory) {
|
|
|
49
49
|
agent_root_name: { type: 'string', description: 'Agent root name. Required for create.' },
|
|
50
50
|
prompt_template: { type: 'string', description: 'Prompt template. Required for create.' },
|
|
51
51
|
status: { type: 'string', enum: ['enabled', 'disabled'], description: 'Trigger status.' },
|
|
52
|
-
|
|
52
|
+
goal: { type: 'string', description: 'Goal for triggered sessions.' },
|
|
53
53
|
reuse_session: { type: 'boolean', description: 'Whether to reuse existing sessions.' },
|
|
54
54
|
mcp_servers: {
|
|
55
55
|
type: 'array',
|
|
@@ -103,7 +103,7 @@ export function actionTriggerTool(_server, clientFactory) {
|
|
|
103
103
|
agent_root_name: validated.agent_root_name,
|
|
104
104
|
prompt_template: validated.prompt_template,
|
|
105
105
|
status: validated.status,
|
|
106
|
-
|
|
106
|
+
goal: validated.goal,
|
|
107
107
|
reuse_session: validated.reuse_session,
|
|
108
108
|
mcp_servers: validated.mcp_servers,
|
|
109
109
|
configuration: validated.configuration,
|
|
@@ -136,7 +136,7 @@ export function actionTriggerTool(_server, clientFactory) {
|
|
|
136
136
|
agent_root_name: validated.agent_root_name,
|
|
137
137
|
prompt_template: validated.prompt_template,
|
|
138
138
|
status: validated.status,
|
|
139
|
-
|
|
139
|
+
goal: validated.goal,
|
|
140
140
|
reuse_session: validated.reuse_session,
|
|
141
141
|
mcp_servers: validated.mcp_servers,
|
|
142
142
|
configuration: validated.configuration,
|
|
@@ -11,8 +11,8 @@ const TOOL_DESCRIPTION = `Fetches all static configuration data in a single call
|
|
|
11
11
|
|
|
12
12
|
Returns:
|
|
13
13
|
- **MCP servers**: Available servers for use with start_session (name, title, description)
|
|
14
|
-
- **Agent roots**: Preconfigured repository settings with defaults (git_root, branch, mcp_servers, skills,
|
|
15
|
-
- **
|
|
14
|
+
- **Agent roots**: Preconfigured repository settings with defaults (git_root, branch, mcp_servers, skills, goal)
|
|
15
|
+
- **Goals**: Available session completion criteria (id, name, description)
|
|
16
16
|
|
|
17
17
|
**Use this tool** to get all configuration options before calling start_session.
|
|
18
18
|
|
|
@@ -101,19 +101,19 @@ function formatResponse(configs, fromCache) {
|
|
|
101
101
|
formatAgentRoot(lines, root);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
//
|
|
104
|
+
// Goals section
|
|
105
105
|
lines.push('---');
|
|
106
106
|
lines.push('');
|
|
107
|
-
lines.push('##
|
|
107
|
+
lines.push('## Goals');
|
|
108
108
|
lines.push('');
|
|
109
|
-
if (configs.
|
|
110
|
-
lines.push('*No
|
|
109
|
+
if (configs.goals.length === 0) {
|
|
110
|
+
lines.push('*No goals defined.*');
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
|
-
lines.push(`Found ${configs.
|
|
113
|
+
lines.push(`Found ${configs.goals.length} goal${configs.goals.length === 1 ? '' : 's'}:`);
|
|
114
114
|
lines.push('');
|
|
115
|
-
for (const
|
|
116
|
-
|
|
115
|
+
for (const goal of configs.goals) {
|
|
116
|
+
formatGoal(lines, goal);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
// Usage hints
|
|
@@ -125,7 +125,7 @@ function formatResponse(configs, fromCache) {
|
|
|
125
125
|
lines.push('- Use `git_root` from **Agent Roots** to start sessions with preconfigured defaults');
|
|
126
126
|
lines.push('- If an **Agent Root** has a `default_subdirectory`, pass it as `subdirectory` in `start_session` — do not set `subdirectory` to arbitrary internal paths');
|
|
127
127
|
lines.push("- Pass `default_skills` from **Agent Roots** in the `skills` parameter of `start_session` — sessions won't have skills loaded unless you explicitly pass them");
|
|
128
|
-
lines.push('- Use `id` values from **
|
|
128
|
+
lines.push('- Use `id` values from **Goals** in `start_session` `goal` parameter');
|
|
129
129
|
if (fromCache) {
|
|
130
130
|
lines.push('');
|
|
131
131
|
lines.push('*(Returned from cache. Use `force_refresh: true` to fetch fresh data.)*');
|
|
@@ -154,8 +154,8 @@ function formatAgentRoot(lines, root) {
|
|
|
154
154
|
if (root.default_mcp_servers && root.default_mcp_servers.length > 0) {
|
|
155
155
|
lines.push(`- **Default MCP Servers:** ${root.default_mcp_servers.map((s) => `\`${s}\``).join(', ')}`);
|
|
156
156
|
}
|
|
157
|
-
if (root.
|
|
158
|
-
lines.push(`- **Default
|
|
157
|
+
if (root.default_goal) {
|
|
158
|
+
lines.push(`- **Default Goal:** \`${root.default_goal}\``);
|
|
159
159
|
}
|
|
160
160
|
if (root.default_skills && root.default_skills.length > 0) {
|
|
161
161
|
lines.push(`- **Default Skills:** ${root.default_skills.map((s) => `\`${s}\``).join(', ')}`);
|
|
@@ -165,9 +165,9 @@ function formatAgentRoot(lines, root) {
|
|
|
165
165
|
}
|
|
166
166
|
lines.push('');
|
|
167
167
|
}
|
|
168
|
-
function
|
|
169
|
-
lines.push(`### ${
|
|
170
|
-
lines.push(`- **ID:** \`${
|
|
171
|
-
lines.push(`- **Description:** ${
|
|
168
|
+
function formatGoal(lines, goal) {
|
|
169
|
+
lines.push(`### ${goal.name}`);
|
|
170
|
+
lines.push(`- **ID:** \`${goal.id}\``);
|
|
171
|
+
lines.push(`- **Description:** ${goal.description}`);
|
|
172
172
|
lines.push('');
|
|
173
173
|
}
|
|
@@ -69,8 +69,8 @@ function formatSessionDetails(session, includeTranscript) {
|
|
|
69
69
|
lines.push('');
|
|
70
70
|
lines.push('### Execution');
|
|
71
71
|
lines.push(`- **Execution Provider:** ${session.execution_provider}`);
|
|
72
|
-
if (session.
|
|
73
|
-
lines.push(`- **
|
|
72
|
+
if (session.goal)
|
|
73
|
+
lines.push(`- **Goal:** ${session.goal}`);
|
|
74
74
|
if (session.mcp_servers && session.mcp_servers.length > 0) {
|
|
75
75
|
lines.push(`- **MCP Servers:** ${session.mcp_servers.join(', ')}`);
|
|
76
76
|
}
|
|
@@ -6,7 +6,7 @@ export declare const ManageEnqueuedMessagesSchema: z.ZodObject<{
|
|
|
6
6
|
action: z.ZodEnum<["list", "get", "create", "update", "delete", "reorder", "interrupt", "send_now"]>;
|
|
7
7
|
message_id: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
content: z.ZodOptional<z.ZodString>;
|
|
9
|
-
|
|
9
|
+
goal: z.ZodOptional<z.ZodString>;
|
|
10
10
|
position: z.ZodOptional<z.ZodNumber>;
|
|
11
11
|
page: z.ZodOptional<z.ZodNumber>;
|
|
12
12
|
per_page: z.ZodOptional<z.ZodNumber>;
|
|
@@ -15,7 +15,7 @@ export declare const ManageEnqueuedMessagesSchema: z.ZodObject<{
|
|
|
15
15
|
action: "list" | "get" | "create" | "update" | "delete" | "reorder" | "interrupt" | "send_now";
|
|
16
16
|
per_page?: number | undefined;
|
|
17
17
|
page?: number | undefined;
|
|
18
|
-
|
|
18
|
+
goal?: string | undefined;
|
|
19
19
|
content?: string | undefined;
|
|
20
20
|
message_id?: number | undefined;
|
|
21
21
|
position?: number | undefined;
|
|
@@ -24,7 +24,7 @@ export declare const ManageEnqueuedMessagesSchema: z.ZodObject<{
|
|
|
24
24
|
action: "list" | "get" | "create" | "update" | "delete" | "reorder" | "interrupt" | "send_now";
|
|
25
25
|
per_page?: number | undefined;
|
|
26
26
|
page?: number | undefined;
|
|
27
|
-
|
|
27
|
+
goal?: string | undefined;
|
|
28
28
|
content?: string | undefined;
|
|
29
29
|
message_id?: number | undefined;
|
|
30
30
|
position?: number | undefined;
|
|
@@ -54,7 +54,7 @@ export declare function manageEnqueuedMessagesTool(_server: Server, clientFactor
|
|
|
54
54
|
type: string;
|
|
55
55
|
description: string;
|
|
56
56
|
};
|
|
57
|
-
|
|
57
|
+
goal: {
|
|
58
58
|
type: string;
|
|
59
59
|
description: string;
|
|
60
60
|
};
|
|
@@ -14,7 +14,7 @@ export const ManageEnqueuedMessagesSchema = z.object({
|
|
|
14
14
|
action: z.enum(ACTION_ENUM),
|
|
15
15
|
message_id: z.number().optional(),
|
|
16
16
|
content: z.string().optional(),
|
|
17
|
-
|
|
17
|
+
goal: z.string().optional(),
|
|
18
18
|
position: z.number().min(1).optional(),
|
|
19
19
|
page: z.number().min(1).optional(),
|
|
20
20
|
per_page: z.number().min(1).max(100).optional(),
|
|
@@ -32,7 +32,7 @@ Use "send_now" when you need the agent to act on something urgently. Use "create
|
|
|
32
32
|
- **create**: Add a new message to the end of the queue for later delivery (requires "content"). The message waits until the session becomes idle.
|
|
33
33
|
- **list**: List all enqueued messages for a session (supports pagination with "page" and "per_page")
|
|
34
34
|
- **get**: Get a specific enqueued message by ID (requires "message_id")
|
|
35
|
-
- **update**: Update an existing queued message's content or
|
|
35
|
+
- **update**: Update an existing queued message's content or goal (requires "message_id")
|
|
36
36
|
- **delete**: Remove a message from the queue (requires "message_id")
|
|
37
37
|
- **reorder**: Change a message's position in the queue (requires "message_id" and "position")
|
|
38
38
|
- **interrupt**: Pause the session and send an existing queued message immediately (requires "message_id"). Prefer "send_now" for new messages — "interrupt" is for promoting an already-queued message.`;
|
|
@@ -60,9 +60,9 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
60
60
|
type: 'string',
|
|
61
61
|
description: 'Message content. Required for create and send_now. Optional for update.',
|
|
62
62
|
},
|
|
63
|
-
|
|
63
|
+
goal: {
|
|
64
64
|
type: 'string',
|
|
65
|
-
description: '
|
|
65
|
+
description: 'Goal for this message. Optional for create, send_now, and update.',
|
|
66
66
|
},
|
|
67
67
|
position: {
|
|
68
68
|
type: 'number',
|
|
@@ -83,7 +83,7 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
83
83
|
try {
|
|
84
84
|
const validated = ManageEnqueuedMessagesSchema.parse(args);
|
|
85
85
|
const client = clientFactory();
|
|
86
|
-
const { session_id, action, message_id, content,
|
|
86
|
+
const { session_id, action, message_id, content, goal, position, page, per_page } = validated;
|
|
87
87
|
let result;
|
|
88
88
|
switch (action) {
|
|
89
89
|
case 'list': {
|
|
@@ -100,8 +100,8 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
100
100
|
lines.push(`### Position ${msg.position} (ID: ${msg.id})`);
|
|
101
101
|
lines.push(`- **Status:** ${msg.status}`);
|
|
102
102
|
lines.push(`- **Content:** ${msg.content.substring(0, 200)}${msg.content.length > 200 ? '...' : ''}`);
|
|
103
|
-
if (msg.
|
|
104
|
-
lines.push(`- **
|
|
103
|
+
if (msg.goal)
|
|
104
|
+
lines.push(`- **Goal:** ${msg.goal}`);
|
|
105
105
|
lines.push('');
|
|
106
106
|
});
|
|
107
107
|
result = lines.join('\n');
|
|
@@ -125,7 +125,7 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
125
125
|
`- **Position:** ${msg.position}`,
|
|
126
126
|
`- **Status:** ${msg.status}`,
|
|
127
127
|
`- **Content:** ${msg.content}`,
|
|
128
|
-
msg.
|
|
128
|
+
msg.goal ? `- **Goal:** ${msg.goal}` : '',
|
|
129
129
|
`- **Created:** ${msg.created_at}`,
|
|
130
130
|
]
|
|
131
131
|
.filter(Boolean)
|
|
@@ -143,7 +143,7 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
143
143
|
}
|
|
144
144
|
const msg = await client.createEnqueuedMessage(session_id, {
|
|
145
145
|
content,
|
|
146
|
-
|
|
146
|
+
goal: goal || undefined,
|
|
147
147
|
});
|
|
148
148
|
result = [
|
|
149
149
|
'## Message Queued',
|
|
@@ -171,7 +171,7 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
171
171
|
}
|
|
172
172
|
const msg = await client.updateEnqueuedMessage(session_id, message_id, {
|
|
173
173
|
content: content || undefined,
|
|
174
|
-
|
|
174
|
+
goal: goal || undefined,
|
|
175
175
|
});
|
|
176
176
|
result = [
|
|
177
177
|
'## Message Updated',
|
|
@@ -263,7 +263,7 @@ export function manageEnqueuedMessagesTool(_server, clientFactory) {
|
|
|
263
263
|
}
|
|
264
264
|
const response = await client.followUp(session_id, content, {
|
|
265
265
|
force_immediate: true,
|
|
266
|
-
|
|
266
|
+
goal: goal || undefined,
|
|
267
267
|
});
|
|
268
268
|
result = [
|
|
269
269
|
'## Message Sent Immediately',
|
|
@@ -92,8 +92,8 @@ export function searchTriggersTool(_server, clientFactory) {
|
|
|
92
92
|
`- **Reuse Session:** ${t.reuse_session ? 'Yes' : 'No'}`,
|
|
93
93
|
`- **MCP Servers:** ${t.mcp_servers && t.mcp_servers.length > 0 ? t.mcp_servers.join(', ') : '(none)'}`,
|
|
94
94
|
];
|
|
95
|
-
if (t.
|
|
96
|
-
lines.push(`- **
|
|
95
|
+
if (t.goal)
|
|
96
|
+
lines.push(`- **Goal:** ${t.goal}`);
|
|
97
97
|
lines.push(`- **Sessions Created:** ${t.sessions_created_count}`);
|
|
98
98
|
if (t.last_triggered_at)
|
|
99
99
|
lines.push(`- **Last Triggered:** ${t.last_triggered_at}`);
|
|
@@ -7,7 +7,7 @@ export declare const StartSessionSchema: z.ZodObject<{
|
|
|
7
7
|
agent_root: z.ZodOptional<z.ZodString>;
|
|
8
8
|
title: z.ZodOptional<z.ZodString>;
|
|
9
9
|
slug: z.ZodOptional<z.ZodString>;
|
|
10
|
-
|
|
10
|
+
goal: z.ZodOptional<z.ZodString>;
|
|
11
11
|
execution_provider: z.ZodOptional<z.ZodEnum<["local_filesystem", "remote_sandbox"]>>;
|
|
12
12
|
mcp_servers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
13
13
|
skills: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -22,7 +22,7 @@ export declare const StartSessionSchema: z.ZodObject<{
|
|
|
22
22
|
prompt?: string | undefined;
|
|
23
23
|
title?: string | undefined;
|
|
24
24
|
slug?: string | undefined;
|
|
25
|
-
|
|
25
|
+
goal?: string | undefined;
|
|
26
26
|
execution_provider?: "local_filesystem" | "remote_sandbox" | undefined;
|
|
27
27
|
mcp_servers?: string[] | undefined;
|
|
28
28
|
agent_root?: string | undefined;
|
|
@@ -36,7 +36,7 @@ export declare const StartSessionSchema: z.ZodObject<{
|
|
|
36
36
|
prompt?: string | undefined;
|
|
37
37
|
title?: string | undefined;
|
|
38
38
|
slug?: string | undefined;
|
|
39
|
-
|
|
39
|
+
goal?: string | undefined;
|
|
40
40
|
execution_provider?: "local_filesystem" | "remote_sandbox" | undefined;
|
|
41
41
|
mcp_servers?: string[] | undefined;
|
|
42
42
|
agent_root?: string | undefined;
|
|
@@ -70,9 +70,9 @@ export declare function startSessionTool(_server: Server, clientFactory: () => I
|
|
|
70
70
|
type: string;
|
|
71
71
|
description: "URL-friendly identifier for the session. Must be unique.";
|
|
72
72
|
};
|
|
73
|
-
|
|
73
|
+
goal: {
|
|
74
74
|
type: string;
|
|
75
|
-
description: "
|
|
75
|
+
description: "Goal ID from get_configs (e.g. \"pr_merged\"). The description is automatically resolved and passed to the agent as context.";
|
|
76
76
|
};
|
|
77
77
|
execution_provider: {
|
|
78
78
|
type: string;
|
|
@@ -11,7 +11,7 @@ const PARAM_DESCRIPTIONS = {
|
|
|
11
11
|
'(e.g. "Fix login redirect loop on mobile Safari", "Add dark mode toggle to settings page"). ' +
|
|
12
12
|
'Only omit if you truly have zero context about the session purpose, which should be extremely rare.',
|
|
13
13
|
slug: 'URL-friendly identifier for the session. Must be unique.',
|
|
14
|
-
|
|
14
|
+
goal: 'Goal ID from get_configs (e.g. "pr_merged"). The description is automatically resolved and passed to the agent as context.',
|
|
15
15
|
execution_provider: 'Execution environment. Options: "local_filesystem" (runs locally), "remote_sandbox" (runs in isolated sandbox). Default: "local_filesystem"',
|
|
16
16
|
mcp_servers: 'List of MCP server names to enable for this session. Example: ["github-development", "slack"]',
|
|
17
17
|
skills: 'List of skill names to enable for this session. Always include the agent root\'s default_skills from get_configs as the starting point — omitting skills means the session gets none. Add extras as needed; removing a default should be rare and intentional. Example: ["discovery-classify", "publish-and-pr"]',
|
|
@@ -30,7 +30,7 @@ export const StartSessionSchema = z.object({
|
|
|
30
30
|
agent_root: z.string().optional().describe(PARAM_DESCRIPTIONS.agent_root),
|
|
31
31
|
title: z.string().optional().describe(PARAM_DESCRIPTIONS.title),
|
|
32
32
|
slug: z.string().optional().describe(PARAM_DESCRIPTIONS.slug),
|
|
33
|
-
|
|
33
|
+
goal: z.string().optional().describe(PARAM_DESCRIPTIONS.goal),
|
|
34
34
|
execution_provider: z
|
|
35
35
|
.enum(['local_filesystem', 'remote_sandbox'])
|
|
36
36
|
.optional()
|
|
@@ -44,7 +44,7 @@ export const StartSessionSchema = z.object({
|
|
|
44
44
|
});
|
|
45
45
|
const TOOL_DESCRIPTION = `Start a new agent session in the Agent Orchestrator.
|
|
46
46
|
|
|
47
|
-
**IMPORTANT:** Before starting a session, call get_configs to discover available agent roots, MCP servers,
|
|
47
|
+
**IMPORTANT:** Before starting a session, call get_configs to discover available agent roots, MCP servers, goals, and their defaults.
|
|
48
48
|
|
|
49
49
|
**Returns:** The created session with its ID, status, and configuration.
|
|
50
50
|
|
|
@@ -54,7 +54,7 @@ const TOOL_DESCRIPTION = `Start a new agent session in the Agent Orchestrator.
|
|
|
54
54
|
|
|
55
55
|
**Agent Roots:** Use \`agent_root\` to specify which preconfigured agent root to use. The API resolves git_root, branch, subdirectory, default_model, and other defaults from the agent root configuration.
|
|
56
56
|
|
|
57
|
-
**Defaults from Agent Roots:** The agent root defines \`default_mcp_servers\`, \`default_skills\`, and optionally a \`
|
|
57
|
+
**Defaults from Agent Roots:** The agent root defines \`default_mcp_servers\`, \`default_skills\`, and optionally a \`default_goal\`. Omitting \`mcp_servers\` or \`skills\` means the session gets NONE — there is no automatic fallback to defaults.
|
|
58
58
|
|
|
59
59
|
- **MCP servers:** Start with \`default_mcp_servers\`. Drop servers the task doesn't need (least-privilege). Add extras when the task requires tools beyond the defaults. When \`ALLOWED_AGENT_ROOTS\` is active, you cannot add servers beyond the defaults.
|
|
60
60
|
- **Skills:** Start with \`default_skills\`. You can freely add skills beyond the defaults. Removing a default skill should be rare and intentional — only when you have a specific reason, like replacing a skill with a more capable variant that covers the same ground. Skills are lightweight text files with no blast radius, so keeping all defaults costs nothing.
|
|
@@ -91,9 +91,9 @@ export function startSessionTool(_server, clientFactory) {
|
|
|
91
91
|
type: 'string',
|
|
92
92
|
description: PARAM_DESCRIPTIONS.slug,
|
|
93
93
|
},
|
|
94
|
-
|
|
94
|
+
goal: {
|
|
95
95
|
type: 'string',
|
|
96
|
-
description: PARAM_DESCRIPTIONS.
|
|
96
|
+
description: PARAM_DESCRIPTIONS.goal,
|
|
97
97
|
},
|
|
98
98
|
execution_provider: {
|
|
99
99
|
type: 'string',
|
|
@@ -151,18 +151,18 @@ export function startSessionTool(_server, clientFactory) {
|
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
// Resolve
|
|
154
|
+
// Resolve goal ID to its description so the agent receives
|
|
155
155
|
// meaningful context about when to stop, not just an opaque identifier.
|
|
156
156
|
let createArgs = validatedArgs;
|
|
157
|
-
if (validatedArgs.
|
|
157
|
+
if (validatedArgs.goal) {
|
|
158
158
|
let configs = getConfigsCache();
|
|
159
159
|
if (!configs) {
|
|
160
160
|
configs = await client.getConfigs();
|
|
161
161
|
setConfigsCache(configs);
|
|
162
162
|
}
|
|
163
|
-
const match = configs.
|
|
163
|
+
const match = configs.goals.find((sc) => sc.id === validatedArgs.goal);
|
|
164
164
|
if (match) {
|
|
165
|
-
createArgs = { ...validatedArgs,
|
|
165
|
+
createArgs = { ...validatedArgs, goal: match.description };
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
const session = await client.createSession(createArgs);
|
|
@@ -4,18 +4,18 @@ import type { IAgentOrchestratorClient } from '../orchestrator-client/orchestrat
|
|
|
4
4
|
export declare const WakeMeUpWhenSessionChangesStateSchema: z.ZodObject<{
|
|
5
5
|
session_id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
|
|
6
6
|
watched_session_id: z.ZodNumber;
|
|
7
|
-
event_name: z.ZodEnum<["session_needs_input", "session_failed"]>;
|
|
7
|
+
event_name: z.ZodEnum<["session_needs_input", "session_failed", "session_archived"]>;
|
|
8
8
|
prompt: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
10
|
prompt: string;
|
|
11
11
|
session_id: string | number;
|
|
12
12
|
watched_session_id: number;
|
|
13
|
-
event_name: "session_needs_input" | "session_failed";
|
|
13
|
+
event_name: "session_needs_input" | "session_failed" | "session_archived";
|
|
14
14
|
}, {
|
|
15
15
|
prompt: string;
|
|
16
16
|
session_id: string | number;
|
|
17
17
|
watched_session_id: number;
|
|
18
|
-
event_name: "session_needs_input" | "session_failed";
|
|
18
|
+
event_name: "session_needs_input" | "session_failed" | "session_archived";
|
|
19
19
|
}>;
|
|
20
20
|
export declare function wakeMeUpWhenSessionChangesStateTool(_server: Server, clientFactory: () => IAgentOrchestratorClient): {
|
|
21
21
|
name: string;
|
|
@@ -35,7 +35,7 @@ export declare function wakeMeUpWhenSessionChangesStateTool(_server: Server, cli
|
|
|
35
35
|
};
|
|
36
36
|
event_name: {
|
|
37
37
|
type: string;
|
|
38
|
-
enum: ("session_needs_input" | "session_failed")[];
|
|
38
|
+
enum: ("session_needs_input" | "session_failed" | "session_archived")[];
|
|
39
39
|
description: string;
|
|
40
40
|
};
|
|
41
41
|
prompt: {
|
|
@@ -1,45 +1,53 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { parseAllowedAgentRoots } from '../allowed-agent-roots.js';
|
|
3
|
-
const AO_EVENT_NAMES = ['session_needs_input', 'session_failed'];
|
|
3
|
+
const AO_EVENT_NAMES = ['session_needs_input', 'session_failed', 'session_archived'];
|
|
4
4
|
export const WakeMeUpWhenSessionChangesStateSchema = z.object({
|
|
5
5
|
session_id: z.union([z.string(), z.number()]),
|
|
6
6
|
watched_session_id: z.number().int().positive(),
|
|
7
7
|
event_name: z.enum(AO_EVENT_NAMES),
|
|
8
8
|
prompt: z.string(),
|
|
9
9
|
});
|
|
10
|
-
const TOOL_DESCRIPTION = `Schedule this session to be woken up when another session transitions to \`needs_input\` or \`
|
|
10
|
+
const TOOL_DESCRIPTION = `Schedule this session to be woken up when another session transitions to \`needs_input\`, \`failed\`, or \`archived\`. The requester session is put to sleep (waiting status) and a one-time trigger fires when the watched session enters the matching state. If the requester is manually resumed before the watched session transitions, the trigger is silently consumed and won't re-fire.
|
|
11
11
|
|
|
12
|
-
This is the **state-based analog of \`wake_me_up_later\`**. Use \`wake_me_up_later\` when you know *when* to wake up (a clock time). Use this tool when you know *what event* to wake up on but not when it will happen — e.g., a subagent session you spawned will eventually
|
|
12
|
+
This is the **state-based analog of \`wake_me_up_later\`**. Use \`wake_me_up_later\` when you know *when* to wake up (a clock time). Use this tool when you know *what event* to wake up on but not when it will happen — e.g., a subagent session you spawned will eventually finish (self-archive), pause for input, or crash, and you want to be the first to handle it without polling.
|
|
13
|
+
|
|
14
|
+
**Triple-wake pattern (typical use).** When you spawn a downstream session and want to wake up on whatever outcome it produces, you'll TYPICALLY want to schedule THREE state-change triggers — one for each terminal/idle event — so you wake on whichever happens first:
|
|
15
|
+
- \`session_archived\` — the watched session self-archived on success (common for closed-loop tasks like "open a PR and self-archive when CI is green"). A downstream session that self-archives goes \`running\` → \`archived\` directly, skipping \`needs_input\`, so a trigger on \`session_needs_input\` alone would NEVER fire for these tasks.
|
|
16
|
+
- \`session_needs_input\` — the watched session paused for user input or finished a turn awaiting follow-up.
|
|
17
|
+
- \`session_failed\` — the watched session crashed.
|
|
18
|
+
|
|
19
|
+
Pair these three triggers with ONE \`wake_me_up_later\` deadline backstop so a hung watched session can't keep you sleeping forever. The first trigger to fire wins; the others are silently consumed when the requester resumes. **Picking only ONE of the three is a footgun** — if you only schedule \`session_needs_input\` and the downstream session self-archives directly, the only thing that wakes you is the deadline (long, wasteful). Schedule all three unless you have a specific reason to wake only on one outcome.
|
|
13
20
|
|
|
14
21
|
**IMPORTANT — Use this tool instead of polling.** When this tool is available, it is the correct way to wait on another session's state. Do NOT use these alternatives:
|
|
15
22
|
- **Repeated \`get_session\` calls in a poll loop**: wastes compute, racks up tool-call overhead, and either polls too often (waste) or too rarely (latency). The trigger fires immediately on transition with no polling latency.
|
|
16
|
-
- **\`wake_me_up_later\` with a guessed duration**: time-based wake-ups are wrong here — you don't know when the watched session will transition, and a guess is either too short (you wake up early and have to re-sleep) or too long (the watched session has been sitting in \`needs_input\` while you sleep).
|
|
23
|
+
- **\`wake_me_up_later\` with a guessed duration**: time-based wake-ups are wrong as the *primary* signal here — you don't know when the watched session will transition, and a guess is either too short (you wake up early and have to re-sleep) or too long (the watched session has been sitting in \`needs_input\` / archived while you sleep). Use \`wake_me_up_later\` only as a deadline backstop alongside the state-change triggers.
|
|
17
24
|
|
|
18
25
|
**The watched session can be ANY session**, not just one the requester spawned. You can watch a peer session, a session a different agent created, or even a session run by a different user — as long as the requester knows the watched session's id.
|
|
19
26
|
|
|
20
|
-
**One-shot semantics.**
|
|
27
|
+
**One-shot semantics.** Each trigger auto-disables after firing. If the watched session transitions, the requester wakes up exactly once and only the first-firing trigger's prompt is delivered; any companion triggers (the other two state events plus the deadline backstop) are silently consumed and gone. To wake on a future transition too, schedule another trigger from the woken-up turn.
|
|
21
28
|
|
|
22
|
-
**Important — fires on transitions, not on current state.** The trigger fires when the watched session *moves into* the target state, not when it is *already in* it.
|
|
29
|
+
**Important — fires on transitions, not on current state.** The trigger fires when the watched session *moves into* the target state, not when it is *already in* it. \`failed\` and \`archived\` are both terminal under typical flow — a session that is already \`failed\` will not transition to \`failed\` again, and a session that is already \`archived\` will not transition to \`archived\` again unless someone unarchives it and re-archives it (rare and surprising). \`needs_input\` is non-terminal: if the watched session is already \`needs_input\` when you create the trigger, it waits for the next transition out and back in. This tool rejects up front any case where the trigger could never fire — already-failed and already-archived watched sessions (terminal states), plus the self-watch case (requester == watched) — so the requester doesn't sleep on a trigger that can never fire.
|
|
23
30
|
|
|
24
|
-
**Deadline backstop pattern.**
|
|
31
|
+
**Deadline backstop pattern.** Always pair the state-change triggers with one \`wake_me_up_later\` trigger so the requester eventually wakes even if the watched session hangs. First trigger to fire wins; the AO firing path resumes the requester once and the others are silently dropped.
|
|
25
32
|
|
|
26
33
|
**Parameters:**
|
|
27
34
|
- **session_id**: The session to wake up (the requester). Works from either \`needs_input\` or \`running\` state — if you call this tool from within your own currently-running session, the sleep transition is recorded and takes effect after the current turn ends.
|
|
28
35
|
- **watched_session_id**: The session to watch. Must be a positive integer. The Rails API rejects unknown ids with a clear 422.
|
|
29
36
|
- **event_name**: Which transition to wake on:
|
|
30
|
-
- \`session_needs_input\`: watched session moves to \`needs_input\` (typically: it finished a turn
|
|
31
|
-
- \`session_failed\`: watched session moves to \`failed\` (a hard error — the session crashed or was killed)
|
|
37
|
+
- \`session_needs_input\`: watched session moves to \`needs_input\` (typically: it finished a turn, or it asked a clarifying question).
|
|
38
|
+
- \`session_failed\`: watched session moves to \`failed\` (a hard error — the session crashed or was killed).
|
|
39
|
+
- \`session_archived\`: watched session moves to \`archived\` (typically: it self-archived after completing closed-loop work, OR a user manually archived it).
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
- **prompt**: The prompt to send when waking up the session. Include enough context that the woken-up turn knows what to do (e.g., "session #N you were watching just transitioned — check its output and decide next steps").
|
|
41
|
+
When in doubt, schedule all three (see the triple-wake pattern above) — the first to fire wins.
|
|
42
|
+
- **prompt**: The prompt to send when waking up the session. Include enough context that the woken-up turn knows what to do (e.g., "session #N you were watching just transitioned — check its output and decide next steps"). If you scheduled multiple triggers (the typical case), each trigger's prompt should make clear which event fired so the woken-up turn knows the outcome without re-checking.
|
|
35
43
|
|
|
36
44
|
**What happens:**
|
|
37
45
|
1. Creates a one-time \`ao_event\` trigger bound to the requester (\`reuse_session: true\`, \`last_session_id: session_id\`) with a single condition scoped to \`watched_session_id\` and \`event_name\`.
|
|
38
46
|
2. As a side effect of creating the trigger, the AO API transitions the requester to sleeping (waiting) status — immediately if currently \`needs_input\`, or after the current turn ends if currently \`running\`.
|
|
39
47
|
3. When the watched session transitions to the matching state, the trigger fires and resumes the requester with the provided prompt. The trigger then auto-deletes (one-shot).
|
|
40
|
-
4. If the requester is manually resumed first, the pending trigger is consumed (won't fire). If the watched session is archived without ever transitioning, the trigger is cleaned up.
|
|
48
|
+
4. If the requester is manually resumed first, the pending trigger is consumed (won't fire). If the watched session is archived without ever transitioning to the matching state (e.g., you only scheduled \`session_needs_input\` and it went straight to \`archived\`), the trigger is cleaned up — and you'll only wake when your deadline backstop fires.
|
|
41
49
|
|
|
42
|
-
**You must end your conversation turn after calling this tool** so the auto-sleep can take effect. If your turn keeps running, the requester will not be in a wakeable state when the watched session transitions, and the wake-up will be silently dropped.`;
|
|
50
|
+
**You must end your conversation turn after calling this tool** so the auto-sleep can take effect. If your turn keeps running, the requester will not be in a wakeable state when the watched session transitions, and the wake-up will be silently dropped. When scheduling multiple triggers (the typical triple-wake + deadline pattern), call this tool repeatedly within the same turn — the auto-sleep is idempotent and only takes effect once the turn ends.`;
|
|
43
51
|
export function wakeMeUpWhenSessionChangesStateTool(_server, clientFactory) {
|
|
44
52
|
return {
|
|
45
53
|
name: 'wake_me_up_when_session_changes_state',
|
|
@@ -58,7 +66,7 @@ export function wakeMeUpWhenSessionChangesStateTool(_server, clientFactory) {
|
|
|
58
66
|
event_name: {
|
|
59
67
|
type: 'string',
|
|
60
68
|
enum: [...AO_EVENT_NAMES],
|
|
61
|
-
description: 'Which transition to wake on: "session_needs_input" (watched session is waiting for input)
|
|
69
|
+
description: 'Which transition to wake on: "session_needs_input" (watched session is waiting for input), "session_failed" (watched session crashed), or "session_archived" (watched session self-archived or was archived by a user). Typically schedule all three (plus a wake_me_up_later deadline backstop) for a downstream session you spawned — see the triple-wake pattern in the tool description.',
|
|
62
70
|
},
|
|
63
71
|
prompt: {
|
|
64
72
|
type: 'string',
|
|
@@ -170,6 +178,17 @@ export function wakeMeUpWhenSessionChangesStateTool(_server, clientFactory) {
|
|
|
170
178
|
isError: true,
|
|
171
179
|
};
|
|
172
180
|
}
|
|
181
|
+
if (event_name === 'session_archived' && watchedSession.status === 'archived') {
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
type: 'text',
|
|
186
|
+
text: `Error: Watched session ${watched_session_id} is already in "archived" state. The trigger fires on transitions only — a session that is already archived will not transition to archived again (barring an unarchive + re-archive, which is rare), so the requester would sleep forever. Pass an active session id, or inspect the archived session directly.`,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
isError: true,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
173
192
|
if (watchedSession.status === 'archived') {
|
|
174
193
|
return {
|
|
175
194
|
content: [
|
package/shared/types.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export interface Session {
|
|
|
21
21
|
branch: string | null;
|
|
22
22
|
subdirectory: string | null;
|
|
23
23
|
execution_provider: string;
|
|
24
|
-
|
|
24
|
+
goal: string | null;
|
|
25
25
|
mcp_servers: string[];
|
|
26
26
|
catalog_skills?: string[];
|
|
27
27
|
catalog_plugins?: string[];
|
|
@@ -114,12 +114,12 @@ export interface AgentRootInfo {
|
|
|
114
114
|
git_root: string;
|
|
115
115
|
default_branch?: string;
|
|
116
116
|
default_subdirectory?: string;
|
|
117
|
-
|
|
117
|
+
default_goal?: string;
|
|
118
118
|
default_mcp_servers?: string[];
|
|
119
119
|
default_skills?: string[];
|
|
120
120
|
default_model?: string;
|
|
121
121
|
}
|
|
122
|
-
export interface
|
|
122
|
+
export interface GoalInfo {
|
|
123
123
|
id: string;
|
|
124
124
|
name: string;
|
|
125
125
|
description: string;
|
|
@@ -127,7 +127,7 @@ export interface StopConditionInfo {
|
|
|
127
127
|
export interface ConfigsResponse {
|
|
128
128
|
mcp_servers: MCPServerInfo[];
|
|
129
129
|
agent_roots: AgentRootInfo[];
|
|
130
|
-
|
|
130
|
+
goals: GoalInfo[];
|
|
131
131
|
}
|
|
132
132
|
export interface SendPushNotificationResponse {
|
|
133
133
|
success: boolean;
|
|
@@ -142,7 +142,7 @@ export interface CreateSessionRequest {
|
|
|
142
142
|
subdirectory?: string;
|
|
143
143
|
title?: string;
|
|
144
144
|
slug?: string;
|
|
145
|
-
|
|
145
|
+
goal?: string;
|
|
146
146
|
execution_provider?: string;
|
|
147
147
|
mcp_servers?: string[];
|
|
148
148
|
skills?: string[];
|
|
@@ -155,7 +155,7 @@ export interface CreateSessionRequest {
|
|
|
155
155
|
export interface UpdateSessionRequest {
|
|
156
156
|
title?: string;
|
|
157
157
|
slug?: string;
|
|
158
|
-
|
|
158
|
+
goal?: string;
|
|
159
159
|
mcp_servers?: string[];
|
|
160
160
|
custom_metadata?: Record<string, unknown>;
|
|
161
161
|
}
|
|
@@ -198,7 +198,7 @@ export interface EnqueuedMessage {
|
|
|
198
198
|
id: number;
|
|
199
199
|
session_id: number;
|
|
200
200
|
content: string;
|
|
201
|
-
|
|
201
|
+
goal: string | null;
|
|
202
202
|
position: number;
|
|
203
203
|
status: EnqueuedMessageStatus;
|
|
204
204
|
created_at: string;
|
|
@@ -232,7 +232,7 @@ export interface Trigger {
|
|
|
232
232
|
status: TriggerStatus;
|
|
233
233
|
agent_root_name: string;
|
|
234
234
|
prompt_template: string;
|
|
235
|
-
|
|
235
|
+
goal: string | null;
|
|
236
236
|
reuse_session: boolean;
|
|
237
237
|
enqueue_messages?: boolean;
|
|
238
238
|
resuscitate_archived?: boolean;
|
|
@@ -269,7 +269,7 @@ export interface CreateTriggerRequest {
|
|
|
269
269
|
agent_root_name: string;
|
|
270
270
|
prompt_template: string;
|
|
271
271
|
status?: TriggerStatus;
|
|
272
|
-
|
|
272
|
+
goal?: string;
|
|
273
273
|
reuse_session?: boolean;
|
|
274
274
|
mcp_servers?: string[];
|
|
275
275
|
last_session_id?: number;
|
|
@@ -282,7 +282,7 @@ export interface UpdateTriggerRequest {
|
|
|
282
282
|
agent_root_name?: string;
|
|
283
283
|
prompt_template?: string;
|
|
284
284
|
status?: TriggerStatus;
|
|
285
|
-
|
|
285
|
+
goal?: string;
|
|
286
286
|
reuse_session?: boolean;
|
|
287
287
|
mcp_servers?: string[];
|
|
288
288
|
trigger_conditions_attributes?: TriggerConditionAttributes[];
|