Skip to content

Commit 06bfb77

Browse files
committed
feat: add job completion validation for robots commands with error handling
1 parent 442a12a commit 06bfb77

File tree

8 files changed

+88
-24
lines changed

8 files changed

+88
-24
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { describe, expect, test } from 'bun:test';
2+
import type { AnyRobotsJob } from './_shared.ts';
3+
import { assertJobCompleted } from './_shared.ts';
4+
5+
const baseJob = {
6+
id: 'rjob_xyz',
7+
workflow: 'summarize',
8+
created_at: 0,
9+
updated_at: 0,
10+
units_consumed: 0,
11+
parameters: { asset_id: 'asset_x' },
12+
} as unknown as AnyRobotsJob;
13+
14+
describe('assertJobCompleted', () => {
15+
test('returns silently on status=completed', () => {
16+
expect(() =>
17+
assertJobCompleted({ ...baseJob, status: 'completed' } as AnyRobotsJob),
18+
).not.toThrow();
19+
});
20+
21+
test('throws on status=errored', () => {
22+
expect(() =>
23+
assertJobCompleted({ ...baseJob, status: 'errored' } as AnyRobotsJob),
24+
).toThrow(/errored/i);
25+
});
26+
27+
test('throws on status=cancelled', () => {
28+
expect(() =>
29+
assertJobCompleted({ ...baseJob, status: 'cancelled' } as AnyRobotsJob),
30+
).toThrow(/cancelled/i);
31+
});
32+
33+
test('includes job.errors details when present', () => {
34+
const job = {
35+
...baseJob,
36+
status: 'errored',
37+
errors: [
38+
{ type: 'processing_error', message: 'asset not ready' },
39+
{ type: 'timeout', message: 'took too long' },
40+
],
41+
} as unknown as AnyRobotsJob;
42+
expect(() => assertJobCompleted(job)).toThrow(
43+
/processing_error: asset not ready.*timeout: took too long/,
44+
);
45+
});
46+
47+
test('includes job id in the error message', () => {
48+
expect(() =>
49+
assertJobCompleted({
50+
...baseJob,
51+
id: 'rjob_abc123',
52+
status: 'errored',
53+
} as AnyRobotsJob),
54+
).toThrow(/rjob_abc123/);
55+
});
56+
});

src/commands/robots/_shared.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ export function retrieveRobotsJob(
8181
}
8282
}
8383

84+
export function assertJobCompleted(job: AnyRobotsJob): void {
85+
if (job.status === 'completed') return;
86+
const details = job.errors?.length
87+
? `: ${job.errors.map((e) => `${e.type}: ${e.message}`).join('; ')}`
88+
: '';
89+
throw new Error(`Job ${job.id} ended with status "${job.status}"${details}`);
90+
}
91+
8492
export async function pollForRobotsJob(
8593
mux: Mux,
8694
workflow: RobotsWorkflow,

src/commands/robots/ask-questions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -135,13 +136,12 @@ export const askQuestionsCommand: Command<any> = new Command()
135136

136137
if (options.json) {
137138
console.log(JSON.stringify(job, null, 2));
138-
return;
139-
}
140-
141-
if (options.wait && job.outputs) {
139+
} else if (options.wait && job.outputs) {
142140
console.log('Outputs:');
143141
console.log(JSON.stringify(job.outputs, null, 2));
144142
}
143+
144+
if (options.wait) assertJobCompleted(job);
145145
} catch (error) {
146146
await handleCommandError(error, 'robots', 'ask-questions', options);
147147
}

src/commands/robots/find-key-moments.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -119,13 +120,12 @@ export const findKeyMomentsCommand: Command<any> = new Command()
119120

120121
if (options.json) {
121122
console.log(JSON.stringify(job, null, 2));
122-
return;
123-
}
124-
125-
if (options.wait && job.outputs) {
123+
} else if (options.wait && job.outputs) {
126124
console.log('Outputs:');
127125
console.log(JSON.stringify(job.outputs, null, 2));
128126
}
127+
128+
if (options.wait) assertJobCompleted(job);
129129
} catch (error) {
130130
await handleCommandError(error, 'robots', 'find-key-moments', options);
131131
}

src/commands/robots/generate-chapters.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -117,13 +118,12 @@ export const generateChaptersCommand: Command<any> = new Command()
117118

118119
if (options.json) {
119120
console.log(JSON.stringify(job, null, 2));
120-
return;
121-
}
122-
123-
if (options.wait && job.outputs) {
121+
} else if (options.wait && job.outputs) {
124122
console.log('Outputs:');
125123
console.log(JSON.stringify(job.outputs, null, 2));
126124
}
125+
126+
if (options.wait) assertJobCompleted(job);
127127
} catch (error) {
128128
await handleCommandError(error, 'robots', 'generate-chapters', options);
129129
}

src/commands/robots/moderate.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -149,13 +150,12 @@ export const moderateCommand: Command<any> = new Command()
149150

150151
if (options.json) {
151152
console.log(JSON.stringify(job, null, 2));
152-
return;
153-
}
154-
155-
if (options.wait && job.outputs) {
153+
} else if (options.wait && job.outputs) {
156154
console.log('Outputs:');
157155
console.log(JSON.stringify(job.outputs, null, 2));
158156
}
157+
158+
if (options.wait) assertJobCompleted(job);
159159
} catch (error) {
160160
await handleCommandError(error, 'robots', 'moderate', options);
161161
}

src/commands/robots/summarize.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -165,13 +166,12 @@ export const summarizeCommand: Command<any> = new Command()
165166

166167
if (options.json) {
167168
console.log(JSON.stringify(job, null, 2));
168-
return;
169-
}
170-
171-
if (options.wait && job.outputs) {
169+
} else if (options.wait && job.outputs) {
172170
console.log('Outputs:');
173171
console.log(JSON.stringify(job.outputs, null, 2));
174172
}
173+
174+
if (options.wait) assertJobCompleted(job);
175175
} catch (error) {
176176
await handleCommandError(error, 'robots', 'summarize', options);
177177
}

src/commands/robots/translate-captions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import { handleCommandError } from '@/lib/errors.ts';
77
import { createAuthenticatedMuxClient } from '@/lib/mux.ts';
88
import {
9+
assertJobCompleted,
910
FILE_MUTEX_MSG,
1011
loadJobParameters,
1112
pollForRobotsJob,
@@ -109,13 +110,12 @@ export const translateCaptionsCommand: Command<any> = new Command()
109110

110111
if (options.json) {
111112
console.log(JSON.stringify(job, null, 2));
112-
return;
113-
}
114-
115-
if (options.wait && job.outputs) {
113+
} else if (options.wait && job.outputs) {
116114
console.log('Outputs:');
117115
console.log(JSON.stringify(job.outputs, null, 2));
118116
}
117+
118+
if (options.wait) assertJobCompleted(job);
119119
} catch (error) {
120120
await handleCommandError(error, 'robots', 'translate-captions', options);
121121
}

0 commit comments

Comments
 (0)