@guildai/cli 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent/chat.d.ts +1 -0
- package/dist/commands/agent/chat.js +24 -1
- package/dist/commands/agent/init.js +1 -1
- package/dist/commands/agent/test.d.ts +1 -0
- package/dist/commands/agent/test.js +80 -28
- package/dist/commands/chat.d.ts +1 -0
- package/dist/commands/chat.js +178 -46
- package/dist/commands/integration/connect.js +1 -1
- package/dist/commands/integration/create.js +36 -36
- package/dist/commands/integration/operation/create.js +2 -1
- package/dist/commands/integration/operation/list.js +23 -15
- package/dist/commands/job/get-step.d.ts +3 -0
- package/dist/commands/job/{step-get.js → get-step.js} +3 -3
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/session/create.js +1 -1
- package/dist/commands/session/events.js +16 -7
- package/dist/commands/session/list.js +1 -1
- package/dist/commands/session/send.js +1 -1
- package/dist/commands/workspace/agent/add.js +16 -3
- package/dist/commands/workspace/agent/list.js +14 -1
- package/dist/commands/workspace/agent/remove.js +14 -1
- package/dist/commands/workspace/clear.d.ts +3 -0
- package/dist/commands/workspace/clear.js +45 -0
- package/dist/commands/workspace/select.js +3 -1
- package/dist/index.js +58 -8
- package/dist/lib/api-types.d.ts +7 -0
- package/dist/lib/generated-types.d.ts +1 -1
- package/dist/lib/generated-types.js +1 -0
- package/dist/lib/guild-config.d.ts +13 -0
- package/dist/lib/guild-config.js +19 -0
- package/dist/lib/npmrc.js +6 -2
- package/dist/lib/output.js +25 -99
- package/dist/lib/polling.d.ts +7 -0
- package/dist/lib/polling.js +12 -3
- package/dist/lib/session-events.d.ts +32 -16
- package/dist/lib/session-events.js +22 -0
- package/dist/lib/session-polling.d.ts +4 -3
- package/dist/lib/session-polling.js +75 -17
- package/dist/lib/session-resume.js +4 -1
- package/dist/lib/stdin.d.ts +4 -0
- package/dist/lib/stdin.js +23 -0
- package/dist/lib/validate-input-schema.d.ts +19 -0
- package/dist/lib/validate-input-schema.js +208 -0
- package/dist/lib/version-helpers.js +38 -0
- package/dist/lib/workspace-helpers.d.ts +20 -0
- package/dist/lib/workspace-helpers.js +49 -0
- package/dist/mcp/tools.js +8 -52
- package/docs/CLI_WORKFLOW.md +1 -1
- package/docs/skills/agent-dev.md +192 -129
- package/docs/skills/integrations.md +1 -1
- package/package.json +2 -1
- package/dist/commands/job/step-get.d.ts +0 -3
package/dist/lib/api-types.d.ts
CHANGED
|
@@ -71,6 +71,7 @@ export interface WorkspaceAgent {
|
|
|
71
71
|
id: string;
|
|
72
72
|
name: string;
|
|
73
73
|
};
|
|
74
|
+
is_default_chat_agent: boolean;
|
|
74
75
|
should_autoupdate: boolean;
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
@@ -116,6 +117,12 @@ export interface ValidationStep {
|
|
|
116
117
|
export interface ValidationStepsResponse {
|
|
117
118
|
steps: ValidationStep[];
|
|
118
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Response from /versions/{id}/publish/steps
|
|
122
|
+
*/
|
|
123
|
+
export interface PublishStepsResponse {
|
|
124
|
+
steps: ValidationStep[];
|
|
125
|
+
}
|
|
119
126
|
/**
|
|
120
127
|
* Workspace context entity from the API.
|
|
121
128
|
* Used by: workspace context list, get, edit
|
|
@@ -2,6 +2,6 @@ export declare const WEBHOOK_SERVICES: readonly ["AZURE_DEVOPS", "BITBUCKET", "C
|
|
|
2
2
|
export type WebhookService = (typeof WEBHOOK_SERVICES)[number];
|
|
3
3
|
export declare const TIME_TRIGGER_FREQUENCIES: readonly ["HOURLY", "DAILY", "WEEKLY", "MONTHLY", "CRON"];
|
|
4
4
|
export type TimeTriggerFrequency = (typeof TIME_TRIGGER_FREQUENCIES)[number];
|
|
5
|
-
export declare const EVENT_TYPES: readonly ["user_message", "agent_console", "runtime_start", "runtime_running", "runtime_waiting", "runtime_error", "runtime_done", "credentials_request", "agent_install_request", "agent_notification_message", "agent_notification_progress", "agent_notification_error", "system_error", "trigger_message", "interrupted", "llm_start", "llm_done"];
|
|
5
|
+
export declare const EVENT_TYPES: readonly ["user_message", "agent_console", "runtime_start", "runtime_running", "runtime_waiting", "runtime_error", "runtime_done", "credentials_request", "agent_install_request", "agent_notification_message", "agent_notification_progress", "agent_notification_error", "system_error", "system_message", "trigger_message", "interrupted", "llm_start", "llm_done"];
|
|
6
6
|
export type EventType = (typeof EVENT_TYPES)[number];
|
|
7
7
|
//# sourceMappingURL=generated-types.d.ts.map
|
|
@@ -83,4 +83,17 @@ export declare function getWorkspaceId(cwd?: string): Promise<{
|
|
|
83
83
|
* Check if we're in an agent directory (has guild.json)
|
|
84
84
|
*/
|
|
85
85
|
export declare function isAgentDirectory(cwd?: string): Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* Get a human-readable label for the workspace source.
|
|
88
|
+
* Returns undefined for 'env' (treated as explicit, like --workspace flag; no label needed).
|
|
89
|
+
*
|
|
90
|
+
* @param source - The source of workspace resolution
|
|
91
|
+
* @returns Human-readable label, or undefined for env source
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* getWorkspaceSourceLabel('local') // → 'guild.json'
|
|
95
|
+
* getWorkspaceSourceLabel('global') // → 'global config'
|
|
96
|
+
* getWorkspaceSourceLabel('env') // → undefined
|
|
97
|
+
*/
|
|
98
|
+
export declare function getWorkspaceSourceLabel(source: 'env' | 'local' | 'global'): string | undefined;
|
|
86
99
|
//# sourceMappingURL=guild-config.d.ts.map
|
package/dist/lib/guild-config.js
CHANGED
|
@@ -156,4 +156,23 @@ export async function getWorkspaceId(cwd = process.cwd()) {
|
|
|
156
156
|
export async function isAgentDirectory(cwd = process.cwd()) {
|
|
157
157
|
return fileExists(getLocalConfigPath(cwd));
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Get a human-readable label for the workspace source.
|
|
161
|
+
* Returns undefined for 'env' (treated as explicit, like --workspace flag; no label needed).
|
|
162
|
+
*
|
|
163
|
+
* @param source - The source of workspace resolution
|
|
164
|
+
* @returns Human-readable label, or undefined for env source
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* getWorkspaceSourceLabel('local') // → 'guild.json'
|
|
168
|
+
* getWorkspaceSourceLabel('global') // → 'global config'
|
|
169
|
+
* getWorkspaceSourceLabel('env') // → undefined
|
|
170
|
+
*/
|
|
171
|
+
export function getWorkspaceSourceLabel(source) {
|
|
172
|
+
if (source === 'local')
|
|
173
|
+
return 'guild.json';
|
|
174
|
+
if (source === 'global')
|
|
175
|
+
return 'global config';
|
|
176
|
+
return undefined; // 'env' is explicit (GUILD_WORKSPACE_ID), no magic label needed
|
|
177
|
+
}
|
|
159
178
|
//# sourceMappingURL=guild-config.js.map
|
package/dist/lib/npmrc.js
CHANGED
|
@@ -8,7 +8,8 @@ function getRegistryUrl() {
|
|
|
8
8
|
const url = getGuildcoreUrl();
|
|
9
9
|
return url.replace('/api', '/npm') + (url.endsWith('/') ? '' : '/');
|
|
10
10
|
}
|
|
11
|
-
const SCOPES = ['@guildai
|
|
11
|
+
const SCOPES = ['@guildai-services', '@guildai-agents'];
|
|
12
|
+
const LEGACY_SCOPES = ['@guildai'];
|
|
12
13
|
export async function configureNpmrc() {
|
|
13
14
|
const registryUrl = getRegistryUrl();
|
|
14
15
|
const scope = registryUrl.split(':').slice(1).join(':');
|
|
@@ -35,7 +36,10 @@ export async function configureNpmrc() {
|
|
|
35
36
|
export async function cleanupNpmrc() {
|
|
36
37
|
const registryUrl = getRegistryUrl();
|
|
37
38
|
const scope = registryUrl.split(':').slice(1).join(':');
|
|
38
|
-
const keys = [
|
|
39
|
+
const keys = [
|
|
40
|
+
...[...SCOPES, ...LEGACY_SCOPES].map((s) => `${s}:registry`),
|
|
41
|
+
`${scope}:_authToken`,
|
|
42
|
+
];
|
|
39
43
|
for (const key of keys) {
|
|
40
44
|
try {
|
|
41
45
|
await execa('npm', [
|
package/dist/lib/output.js
CHANGED
|
@@ -38,6 +38,20 @@ function truncate(str, maxLen) {
|
|
|
38
38
|
return str;
|
|
39
39
|
return str.slice(0, maxLen - 1) + '…';
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Print the "Showing N of M <entity>" footer after a paginated table.
|
|
43
|
+
*/
|
|
44
|
+
function printPaginationFooter(pagination, count, entityName) {
|
|
45
|
+
const showing = Math.min(pagination.limit, count);
|
|
46
|
+
if (pagination.has_more) {
|
|
47
|
+
const nextOffset = pagination.offset + pagination.limit;
|
|
48
|
+
console.log(`\nShowing ${showing} of ${pagination.total_count} ${entityName}. ` +
|
|
49
|
+
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
50
|
+
}
|
|
51
|
+
else if (pagination.total_count > showing) {
|
|
52
|
+
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} ${entityName}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
41
55
|
/**
|
|
42
56
|
* Format an agent list as a human-readable table.
|
|
43
57
|
* Shared by agent list and agent search commands.
|
|
@@ -75,15 +89,7 @@ export function formatAgentTable(agents, pagination, showArchived = false) {
|
|
|
75
89
|
});
|
|
76
90
|
});
|
|
77
91
|
table.printTable();
|
|
78
|
-
|
|
79
|
-
if (pagination.has_more) {
|
|
80
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
81
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} agents. ` +
|
|
82
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
83
|
-
}
|
|
84
|
-
else if (pagination.total_count > showing) {
|
|
85
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} agents`));
|
|
86
|
-
}
|
|
92
|
+
printPaginationFooter(pagination, agents.length, 'agents');
|
|
87
93
|
}
|
|
88
94
|
/**
|
|
89
95
|
* Format an integration list as a human-readable table.
|
|
@@ -113,15 +119,7 @@ export function formatIntegrationTable(integrations, pagination) {
|
|
|
113
119
|
});
|
|
114
120
|
});
|
|
115
121
|
table.printTable();
|
|
116
|
-
|
|
117
|
-
if (pagination.has_more) {
|
|
118
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
119
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} integrations. ` +
|
|
120
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
121
|
-
}
|
|
122
|
-
else if (pagination.total_count > showing) {
|
|
123
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} integrations`));
|
|
124
|
-
}
|
|
122
|
+
printPaginationFooter(pagination, integrations.length, 'integrations');
|
|
125
123
|
}
|
|
126
124
|
/**
|
|
127
125
|
* Format an integration version list as a human-readable table.
|
|
@@ -169,15 +167,7 @@ export function formatIntegrationVersionTable(versions, pagination, integrationN
|
|
|
169
167
|
});
|
|
170
168
|
});
|
|
171
169
|
table.printTable();
|
|
172
|
-
|
|
173
|
-
if (pagination.has_more) {
|
|
174
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
175
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} versions. ` +
|
|
176
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
177
|
-
}
|
|
178
|
-
else if (pagination.total_count > showing) {
|
|
179
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} versions`));
|
|
180
|
-
}
|
|
170
|
+
printPaginationFooter(pagination, versions.length, 'versions');
|
|
181
171
|
}
|
|
182
172
|
/**
|
|
183
173
|
* Format an agent version list as a human-readable table.
|
|
@@ -214,15 +204,7 @@ export function formatVersionTable(versions, pagination) {
|
|
|
214
204
|
});
|
|
215
205
|
});
|
|
216
206
|
table.printTable();
|
|
217
|
-
|
|
218
|
-
if (pagination.has_more) {
|
|
219
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
220
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} versions. ` +
|
|
221
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
222
|
-
}
|
|
223
|
-
else if (pagination.total_count > showing) {
|
|
224
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} versions`));
|
|
225
|
-
}
|
|
207
|
+
printPaginationFooter(pagination, versions.length, 'versions');
|
|
226
208
|
}
|
|
227
209
|
/**
|
|
228
210
|
* Format a context list as a human-readable table.
|
|
@@ -250,15 +232,7 @@ export function formatContextTable(contexts, pagination) {
|
|
|
250
232
|
});
|
|
251
233
|
});
|
|
252
234
|
table.printTable();
|
|
253
|
-
|
|
254
|
-
if (pagination.has_more) {
|
|
255
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
256
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} contexts. ` +
|
|
257
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
258
|
-
}
|
|
259
|
-
else if (pagination.total_count > showing) {
|
|
260
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} contexts`));
|
|
261
|
-
}
|
|
235
|
+
printPaginationFooter(pagination, contexts.length, 'contexts');
|
|
262
236
|
}
|
|
263
237
|
/**
|
|
264
238
|
* Format a workspace agent list as a human-readable table.
|
|
@@ -314,15 +288,7 @@ export function formatWorkspaceTable(workspaces, pagination) {
|
|
|
314
288
|
});
|
|
315
289
|
});
|
|
316
290
|
table.printTable();
|
|
317
|
-
|
|
318
|
-
if (pagination.has_more) {
|
|
319
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
320
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} workspaces. ` +
|
|
321
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
322
|
-
}
|
|
323
|
-
else if (pagination.total_count > showing) {
|
|
324
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} workspaces`));
|
|
325
|
-
}
|
|
291
|
+
printPaginationFooter(pagination, workspaces.length, 'workspaces');
|
|
326
292
|
}
|
|
327
293
|
/**
|
|
328
294
|
* Format a session list as a human-readable table.
|
|
@@ -353,15 +319,7 @@ export function formatSessionTable(sessions, pagination) {
|
|
|
353
319
|
});
|
|
354
320
|
});
|
|
355
321
|
table.printTable();
|
|
356
|
-
|
|
357
|
-
if (pagination.has_more) {
|
|
358
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
359
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} sessions. ` +
|
|
360
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
361
|
-
}
|
|
362
|
-
else if (pagination.total_count > showing) {
|
|
363
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} sessions`));
|
|
364
|
-
}
|
|
322
|
+
printPaginationFooter(pagination, sessions.length, 'sessions');
|
|
365
323
|
}
|
|
366
324
|
/**
|
|
367
325
|
* Format a task list as a human-readable table.
|
|
@@ -403,15 +361,7 @@ export function formatTaskTable(tasks, pagination) {
|
|
|
403
361
|
});
|
|
404
362
|
});
|
|
405
363
|
table.printTable();
|
|
406
|
-
|
|
407
|
-
if (pagination.has_more) {
|
|
408
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
409
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} tasks. ` +
|
|
410
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
411
|
-
}
|
|
412
|
-
else if (pagination.total_count > showing) {
|
|
413
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} tasks`));
|
|
414
|
-
}
|
|
364
|
+
printPaginationFooter(pagination, tasks.length, 'tasks');
|
|
415
365
|
}
|
|
416
366
|
/**
|
|
417
367
|
* Format a trigger list as a human-readable table.
|
|
@@ -453,15 +403,7 @@ export function formatTriggerTable(triggers, pagination) {
|
|
|
453
403
|
});
|
|
454
404
|
});
|
|
455
405
|
table.printTable();
|
|
456
|
-
|
|
457
|
-
if (pagination.has_more) {
|
|
458
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
459
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} triggers. ` +
|
|
460
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
461
|
-
}
|
|
462
|
-
else if (pagination.total_count > showing) {
|
|
463
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} triggers`));
|
|
464
|
-
}
|
|
406
|
+
printPaginationFooter(pagination, triggers.length, 'triggers');
|
|
465
407
|
}
|
|
466
408
|
export function formatCredentialsTable(credentials, pagination) {
|
|
467
409
|
if (credentials.length === 0) {
|
|
@@ -485,15 +427,7 @@ export function formatCredentialsTable(credentials, pagination) {
|
|
|
485
427
|
});
|
|
486
428
|
});
|
|
487
429
|
table.printTable();
|
|
488
|
-
|
|
489
|
-
if (pagination.has_more) {
|
|
490
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
491
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} credentials. ` +
|
|
492
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
493
|
-
}
|
|
494
|
-
else if (pagination.total_count > showing) {
|
|
495
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} credentials`));
|
|
496
|
-
}
|
|
430
|
+
printPaginationFooter(pagination, credentials.length, 'credentials');
|
|
497
431
|
}
|
|
498
432
|
export function formatPoliciesTable(policies, pagination) {
|
|
499
433
|
if (policies.length === 0) {
|
|
@@ -534,15 +468,7 @@ export function formatPoliciesTable(policies, pagination) {
|
|
|
534
468
|
});
|
|
535
469
|
});
|
|
536
470
|
table.printTable();
|
|
537
|
-
|
|
538
|
-
if (pagination.has_more) {
|
|
539
|
-
const nextOffset = pagination.offset + pagination.limit;
|
|
540
|
-
console.log(`\nShowing ${showing} of ${pagination.total_count} policies. ` +
|
|
541
|
-
chalk.dim(`Use --offset ${nextOffset} to see more.`));
|
|
542
|
-
}
|
|
543
|
-
else if (pagination.total_count > showing) {
|
|
544
|
-
console.log(chalk.dim(`\nShowing ${showing} of ${pagination.total_count} policies`));
|
|
545
|
-
}
|
|
471
|
+
printPaginationFooter(pagination, policies.length, 'policies');
|
|
546
472
|
}
|
|
547
473
|
/**
|
|
548
474
|
* Format job steps as a human-readable table.
|
package/dist/lib/polling.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export interface PollOptions<T = unknown> {
|
|
|
37
37
|
* @default "Operation timed out"
|
|
38
38
|
*/
|
|
39
39
|
timeoutMessage?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Optional callback invoked after each poll when the operation is not yet
|
|
42
|
+
* complete. Return a non-null string to override the default spinner text
|
|
43
|
+
* (`${message} (${attempts}/${maxAttempts})`). Return null to keep the
|
|
44
|
+
* default. Errors thrown by the callback are silently ignored.
|
|
45
|
+
*/
|
|
46
|
+
onPoll?: (response: T, attempts: number) => Promise<string | null>;
|
|
40
47
|
}
|
|
41
48
|
export interface PollResult<T = unknown> {
|
|
42
49
|
/**
|
package/dist/lib/polling.js
CHANGED
|
@@ -21,7 +21,7 @@ import { createSpinner } from './progress.js';
|
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
export async function pollUntilComplete(options) {
|
|
24
|
-
const { endpoint, isComplete, message = 'Waiting for operation to complete...', maxAttempts = 60, delayMs = 1000, successMessage = 'Operation complete', timeoutMessage = 'Operation timed out', } = options;
|
|
24
|
+
const { endpoint, isComplete, message = 'Waiting for operation to complete...', maxAttempts = 60, delayMs = 1000, successMessage = 'Operation complete', timeoutMessage = 'Operation timed out', onPoll, } = options;
|
|
25
25
|
const client = new GuildAPIClient();
|
|
26
26
|
const spinner = createSpinner(message);
|
|
27
27
|
spinner.start();
|
|
@@ -40,8 +40,17 @@ export async function pollUntilComplete(options) {
|
|
|
40
40
|
attempts,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
// Update spinner with progress
|
|
44
|
-
|
|
43
|
+
// Update spinner with progress — prefer onPoll text when available
|
|
44
|
+
let spinnerText = null;
|
|
45
|
+
if (onPoll) {
|
|
46
|
+
try {
|
|
47
|
+
spinnerText = await onPoll(response, attempts);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Silently ignore step-fetch errors; fall back to default text
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
spinner.text = spinnerText ?? `${message} (${attempts}/${maxAttempts})`;
|
|
45
54
|
}
|
|
46
55
|
catch {
|
|
47
56
|
// If we can't fetch the resource, continue polling
|
|
@@ -19,10 +19,12 @@ export interface AgentRef {
|
|
|
19
19
|
}
|
|
20
20
|
export interface SessionTaskAgentItem extends BaseTaskFields {
|
|
21
21
|
agent: AgentRef;
|
|
22
|
+
parent_task_id: string | null;
|
|
22
23
|
}
|
|
23
24
|
export interface SessionTaskToolItem extends BaseTaskFields {
|
|
24
25
|
tool_name: string;
|
|
25
26
|
tool_call_id: string;
|
|
27
|
+
parent_task: SessionTaskItem | null;
|
|
26
28
|
}
|
|
27
29
|
export type SessionTaskItem = SessionTaskAgentItem | SessionTaskToolItem;
|
|
28
30
|
export interface SessionTaskAgent extends SessionTaskAgentItem {
|
|
@@ -91,26 +93,29 @@ export interface RuntimeDoneEvent extends BaseEvent {
|
|
|
91
93
|
type: 'runtime_done';
|
|
92
94
|
content: Record<string, unknown>;
|
|
93
95
|
}
|
|
96
|
+
export interface TextContent {
|
|
97
|
+
type: 'text';
|
|
98
|
+
data: string;
|
|
99
|
+
}
|
|
100
|
+
export interface ResponseStreamContent {
|
|
101
|
+
type: 'application/guild-response-stream';
|
|
102
|
+
stream_id: string;
|
|
103
|
+
sequence: number;
|
|
104
|
+
status: 'streaming' | 'done' | 'aborted';
|
|
105
|
+
text: string;
|
|
106
|
+
}
|
|
107
|
+
export type AgentNotificationMessageContent = TextContent | ResponseStreamContent;
|
|
94
108
|
export interface AgentNotificationMessageEvent extends BaseEvent {
|
|
95
109
|
type: 'agent_notification_message';
|
|
96
|
-
content:
|
|
97
|
-
type: 'text';
|
|
98
|
-
data: string;
|
|
99
|
-
};
|
|
110
|
+
content: AgentNotificationMessageContent;
|
|
100
111
|
}
|
|
101
112
|
export interface AgentNotificationProgressEvent extends BaseEvent {
|
|
102
113
|
type: 'agent_notification_progress';
|
|
103
|
-
content:
|
|
104
|
-
type: 'text';
|
|
105
|
-
data: string;
|
|
106
|
-
};
|
|
114
|
+
content: TextContent;
|
|
107
115
|
}
|
|
108
116
|
export interface AgentNotificationErrorEvent extends BaseEvent {
|
|
109
117
|
type: 'agent_notification_error';
|
|
110
|
-
content:
|
|
111
|
-
type: 'text';
|
|
112
|
-
data: string;
|
|
113
|
-
};
|
|
118
|
+
content: TextContent;
|
|
114
119
|
}
|
|
115
120
|
export interface AgentConsoleEvent extends BaseEvent {
|
|
116
121
|
type: 'agent_console';
|
|
@@ -126,10 +131,7 @@ export interface TriggerMessageEvent extends BaseEvent {
|
|
|
126
131
|
}
|
|
127
132
|
export interface SystemErrorEvent extends BaseEvent {
|
|
128
133
|
type: 'system_error';
|
|
129
|
-
content:
|
|
130
|
-
type: 'text';
|
|
131
|
-
data: string;
|
|
132
|
-
};
|
|
134
|
+
content: TextContent;
|
|
133
135
|
details?: Record<string, unknown>;
|
|
134
136
|
}
|
|
135
137
|
export interface LlmStartEvent extends BaseEvent {
|
|
@@ -169,6 +171,20 @@ export interface CredentialsRequestEvent extends BaseEvent {
|
|
|
169
171
|
export declare function isUnfulfilledAgentInstallRequest(event: SessionEvent): event is AgentInstallRequestEvent;
|
|
170
172
|
/** Check if event is an unfulfilled credentials request */
|
|
171
173
|
export declare function isUnfulfilledCredentialsRequest(event: SessionEvent): event is CredentialsRequestEvent;
|
|
174
|
+
/** Check if an agent notification message is a transient response stream draft. */
|
|
175
|
+
export declare function isResponseStreamEvent(event: SessionEvent): event is AgentNotificationMessageEvent & {
|
|
176
|
+
content: ResponseStreamContent;
|
|
177
|
+
};
|
|
178
|
+
/** Check if a response stream event carries the final generated text. */
|
|
179
|
+
export declare function isDoneResponseStreamEvent(event: SessionEvent): event is AgentNotificationMessageEvent & {
|
|
180
|
+
content: ResponseStreamContent & {
|
|
181
|
+
status: 'done';
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
/** Extract display text from notification content. */
|
|
185
|
+
export declare function getAgentNotificationText(event: AgentNotificationMessageEvent): string;
|
|
186
|
+
/** Check if an event belongs to the root task or has no task context. */
|
|
187
|
+
export declare function isRootTaskEvent(event: SessionEvent): boolean;
|
|
172
188
|
export interface InterruptedEvent extends BaseEvent {
|
|
173
189
|
type: 'interrupted';
|
|
174
190
|
interrupted_at: string;
|
|
@@ -87,4 +87,26 @@ export function isUnfulfilledAgentInstallRequest(event) {
|
|
|
87
87
|
export function isUnfulfilledCredentialsRequest(event) {
|
|
88
88
|
return event.type === 'credentials_request' && !event.is_fulfilled;
|
|
89
89
|
}
|
|
90
|
+
/** Check if an agent notification message is a transient response stream draft. */
|
|
91
|
+
export function isResponseStreamEvent(event) {
|
|
92
|
+
return (event.type === 'agent_notification_message' &&
|
|
93
|
+
event.content.type === 'application/guild-response-stream');
|
|
94
|
+
}
|
|
95
|
+
/** Check if a response stream event carries the final generated text. */
|
|
96
|
+
export function isDoneResponseStreamEvent(event) {
|
|
97
|
+
return isResponseStreamEvent(event) && event.content.status === 'done';
|
|
98
|
+
}
|
|
99
|
+
/** Extract display text from notification content. */
|
|
100
|
+
export function getAgentNotificationText(event) {
|
|
101
|
+
return event.content.type === 'text' ? event.content.data : event.content.text;
|
|
102
|
+
}
|
|
103
|
+
/** Check if an event belongs to the root task or has no task context. */
|
|
104
|
+
export function isRootTaskEvent(event) {
|
|
105
|
+
const task = event.task;
|
|
106
|
+
if (!task)
|
|
107
|
+
return true;
|
|
108
|
+
if ('parent_task_id' in task)
|
|
109
|
+
return task.parent_task_id === null;
|
|
110
|
+
return task.parent_task === null;
|
|
111
|
+
}
|
|
90
112
|
//# sourceMappingURL=session-events.js.map
|
|
@@ -11,9 +11,10 @@ export interface PollResult {
|
|
|
11
11
|
* and one-shot agents (which may only emit runtime_done with output content).
|
|
12
12
|
*
|
|
13
13
|
* Priority:
|
|
14
|
-
* 1. agent_notification_message — preferred, immediate return
|
|
15
|
-
* 2.
|
|
16
|
-
* 3.
|
|
14
|
+
* 1. root agent_notification_message — preferred, immediate return
|
|
15
|
+
* 2. root runtime_error — fail fast
|
|
16
|
+
* 3. root runtime_done content — fallback for one-shot agents
|
|
17
|
+
* 4. root done response-stream after root runtime_done — streaming fallback
|
|
17
18
|
*/
|
|
18
19
|
export declare function pollForResponse(client: GuildAPIClient, sessionId: string, afterEventId: string | undefined, maxWaitTime?: number): Promise<PollResult>;
|
|
19
20
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { debug, isDebugMode } from './errors.js';
|
|
4
4
|
import { shouldShowEvent } from './event-filter.js';
|
|
5
5
|
import { fetchEvents } from './session-events-fetch.js';
|
|
6
|
+
import { getAgentNotificationText, isDoneResponseStreamEvent, isResponseStreamEvent, isRootTaskEvent, } from './session-events.js';
|
|
6
7
|
/**
|
|
7
8
|
* Poll for agent response using from_id cursor.
|
|
8
9
|
*
|
|
@@ -10,28 +11,51 @@ import { fetchEvents } from './session-events-fetch.js';
|
|
|
10
11
|
* and one-shot agents (which may only emit runtime_done with output content).
|
|
11
12
|
*
|
|
12
13
|
* Priority:
|
|
13
|
-
* 1. agent_notification_message — preferred, immediate return
|
|
14
|
-
* 2.
|
|
15
|
-
* 3.
|
|
14
|
+
* 1. root agent_notification_message — preferred, immediate return
|
|
15
|
+
* 2. root runtime_error — fail fast
|
|
16
|
+
* 3. root runtime_done content — fallback for one-shot agents
|
|
17
|
+
* 4. root done response-stream after root runtime_done — streaming fallback
|
|
16
18
|
*/
|
|
17
19
|
export async function pollForResponse(client, sessionId, afterEventId, maxWaitTime = 60000) {
|
|
18
20
|
const startTime = Date.now();
|
|
19
21
|
let fromId = afterEventId;
|
|
22
|
+
let responseStreamDone = null;
|
|
20
23
|
while (Date.now() - startTime < maxWaitTime) {
|
|
21
24
|
const events = await fetchEvents(client, sessionId, { fromId });
|
|
22
25
|
let lastAgentRuntimeDone = null;
|
|
26
|
+
let rootRuntimeDone = false;
|
|
23
27
|
for (const event of events) {
|
|
24
28
|
debug(`pollForResponse event: ${event.type}`);
|
|
25
29
|
if (event.type === 'agent_notification_message') {
|
|
26
|
-
|
|
30
|
+
if (isResponseStreamEvent(event)) {
|
|
31
|
+
if (isRootTaskEvent(event) && isDoneResponseStreamEvent(event)) {
|
|
32
|
+
responseStreamDone = {
|
|
33
|
+
response: getAgentNotificationText(event),
|
|
34
|
+
lastEventId: event.id,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!isRootTaskEvent(event))
|
|
40
|
+
continue;
|
|
41
|
+
return {
|
|
42
|
+
response: getAgentNotificationText(event),
|
|
43
|
+
lastEventId: event.id,
|
|
44
|
+
};
|
|
27
45
|
}
|
|
28
46
|
if (event.type === 'runtime_done' &&
|
|
29
|
-
event.content !== undefined &&
|
|
30
47
|
event.task &&
|
|
31
|
-
'agent' in event.task
|
|
32
|
-
|
|
48
|
+
'agent' in event.task &&
|
|
49
|
+
isRootTaskEvent(event)) {
|
|
50
|
+
rootRuntimeDone = true;
|
|
51
|
+
if (event.content !== undefined) {
|
|
52
|
+
lastAgentRuntimeDone = JSON.stringify(event.content);
|
|
53
|
+
}
|
|
33
54
|
}
|
|
34
|
-
if (event.type === 'runtime_error' &&
|
|
55
|
+
if (event.type === 'runtime_error' &&
|
|
56
|
+
event.task &&
|
|
57
|
+
'agent' in event.task &&
|
|
58
|
+
isRootTaskEvent(event)) {
|
|
35
59
|
return {
|
|
36
60
|
response: JSON.stringify({ error: event.content }),
|
|
37
61
|
lastEventId: event.id,
|
|
@@ -47,9 +71,14 @@ export async function pollForResponse(client, sessionId, afterEventId, maxWaitTi
|
|
|
47
71
|
if (lastAgentRuntimeDone !== null) {
|
|
48
72
|
return { response: lastAgentRuntimeDone, lastEventId: fromId };
|
|
49
73
|
}
|
|
74
|
+
if (rootRuntimeDone && responseStreamDone !== null) {
|
|
75
|
+
return { response: responseStreamDone.response, lastEventId: fromId };
|
|
76
|
+
}
|
|
50
77
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
51
78
|
}
|
|
52
|
-
return
|
|
79
|
+
return responseStreamDone
|
|
80
|
+
? { response: responseStreamDone.response, lastEventId: fromId }
|
|
81
|
+
: { response: null, lastEventId: fromId };
|
|
53
82
|
}
|
|
54
83
|
/**
|
|
55
84
|
* Poll for agent response while streaming matching events to stdout as JSONL.
|
|
@@ -61,25 +90,49 @@ export async function pollForResponse(client, sessionId, afterEventId, maxWaitTi
|
|
|
61
90
|
export async function pollForResponseWithEvents(client, sessionId, eventFilter, afterEventId, maxWaitTime = 60000) {
|
|
62
91
|
const startTime = Date.now();
|
|
63
92
|
let fromId = afterEventId;
|
|
93
|
+
let responseStreamDone = null;
|
|
64
94
|
while (Date.now() - startTime < maxWaitTime) {
|
|
65
95
|
const events = await fetchEvents(client, sessionId, { fromId });
|
|
66
96
|
let lastAgentRuntimeDone = null;
|
|
97
|
+
let rootRuntimeDone = false;
|
|
67
98
|
for (const event of events) {
|
|
68
99
|
debug(`pollForResponseWithEvents event: ${event.type}`);
|
|
69
|
-
// Stream matching events to stdout as JSONL
|
|
70
|
-
|
|
100
|
+
// Stream matching events to stdout as JSONL. Response-stream events are
|
|
101
|
+
// transient drafts, so keep automation output stable and wait for the
|
|
102
|
+
// final agent message or terminal fallback.
|
|
103
|
+
if (shouldShowEvent(event.type, eventFilter) && !isResponseStreamEvent(event)) {
|
|
71
104
|
process.stdout.write(JSON.stringify(event) + '\n');
|
|
72
105
|
}
|
|
73
106
|
if (event.type === 'agent_notification_message') {
|
|
74
|
-
|
|
107
|
+
if (isResponseStreamEvent(event)) {
|
|
108
|
+
if (isRootTaskEvent(event) && isDoneResponseStreamEvent(event)) {
|
|
109
|
+
responseStreamDone = {
|
|
110
|
+
response: getAgentNotificationText(event),
|
|
111
|
+
lastEventId: event.id,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!isRootTaskEvent(event))
|
|
117
|
+
continue;
|
|
118
|
+
return {
|
|
119
|
+
response: getAgentNotificationText(event),
|
|
120
|
+
lastEventId: event.id,
|
|
121
|
+
};
|
|
75
122
|
}
|
|
76
123
|
if (event.type === 'runtime_done' &&
|
|
77
|
-
event.content !== undefined &&
|
|
78
124
|
event.task &&
|
|
79
|
-
'agent' in event.task
|
|
80
|
-
|
|
125
|
+
'agent' in event.task &&
|
|
126
|
+
isRootTaskEvent(event)) {
|
|
127
|
+
rootRuntimeDone = true;
|
|
128
|
+
if (event.content !== undefined) {
|
|
129
|
+
lastAgentRuntimeDone = JSON.stringify(event.content);
|
|
130
|
+
}
|
|
81
131
|
}
|
|
82
|
-
if (event.type === 'runtime_error' &&
|
|
132
|
+
if (event.type === 'runtime_error' &&
|
|
133
|
+
event.task &&
|
|
134
|
+
'agent' in event.task &&
|
|
135
|
+
isRootTaskEvent(event)) {
|
|
83
136
|
return {
|
|
84
137
|
response: JSON.stringify({ error: event.content }),
|
|
85
138
|
lastEventId: event.id,
|
|
@@ -95,8 +148,13 @@ export async function pollForResponseWithEvents(client, sessionId, eventFilter,
|
|
|
95
148
|
if (lastAgentRuntimeDone !== null) {
|
|
96
149
|
return { response: lastAgentRuntimeDone, lastEventId: fromId };
|
|
97
150
|
}
|
|
151
|
+
if (rootRuntimeDone && responseStreamDone !== null) {
|
|
152
|
+
return { response: responseStreamDone.response, lastEventId: fromId };
|
|
153
|
+
}
|
|
98
154
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
99
155
|
}
|
|
100
|
-
return
|
|
156
|
+
return responseStreamDone
|
|
157
|
+
? { response: responseStreamDone.response, lastEventId: fromId }
|
|
158
|
+
: { response: null, lastEventId: fromId };
|
|
101
159
|
}
|
|
102
160
|
//# sourceMappingURL=session-polling.js.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import { marked } from 'marked';
|
|
9
9
|
import { markedTerminal } from 'marked-terminal';
|
|
10
|
+
import { getAgentNotificationText, isResponseStreamEvent, } from './session-events.js';
|
|
10
11
|
import { fetchEvents } from './session-events-fetch.js';
|
|
11
12
|
import { brand, code as codeColor } from './colors.js';
|
|
12
13
|
// Configure marked for terminal rendering (same config as chat.tsx)
|
|
@@ -64,7 +65,9 @@ export function eventsToDisplayMessages(events) {
|
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
else if (event.type === 'agent_notification_message') {
|
|
67
|
-
|
|
68
|
+
if (isResponseStreamEvent(event))
|
|
69
|
+
continue;
|
|
70
|
+
const text = getAgentNotificationText(event);
|
|
68
71
|
if (text.trim()) {
|
|
69
72
|
const rendered = renderMarkdown(text);
|
|
70
73
|
const messageContent = `${chalk.green('●')} ${chalk.bold('assistant')}\n${rendered.trim()}`;
|