feat(core-api): add rapid order transcribe and parse endpoints

This commit is contained in:
zouantchaw
2026-02-27 11:12:32 -05:00
parent feb38c81fa
commit 7740ad4d2d
7 changed files with 808 additions and 12 deletions

View File

@@ -150,6 +150,130 @@ test('POST /core/invoke-llm enforces per-user rate limit', async () => {
assert.equal(typeof second.headers['retry-after'], 'string');
});
test('POST /core/upload-file accepts audio/webm for rapid transcription', async () => {
const app = createApp();
const res = await request(app)
.post('/core/upload-file')
.set('Authorization', 'Bearer test-token')
.field('visibility', 'private')
.attach('file', Buffer.from('fake-audio-data'), {
filename: 'rapid-request.webm',
contentType: 'audio/webm',
});
assert.equal(res.status, 200);
assert.equal(res.body.contentType, 'audio/webm');
assert.equal(typeof res.body.fileUri, 'string');
});
test('POST /core/rapid-orders/transcribe returns transcript in mock mode', async () => {
const app = createApp();
const res = await request(app)
.post('/core/rapid-orders/transcribe')
.set('Authorization', 'Bearer test-token')
.send({
audioFileUri: 'gs://krow-workforce-dev-private/uploads/test-user/request.webm',
locale: 'en-US',
promptHints: ['server', 'urgent'],
});
assert.equal(res.status, 200);
assert.equal(typeof res.body.transcript, 'string');
assert.ok(res.body.transcript.length > 0);
assert.equal(typeof res.body.confidence, 'number');
assert.equal(typeof res.body.model, 'string');
assert.equal(typeof res.body.requestId, 'string');
});
test('POST /core/rapid-orders/transcribe rejects non-owned file URI', async () => {
const app = createApp();
const res = await request(app)
.post('/core/rapid-orders/transcribe')
.set('Authorization', 'Bearer test-token')
.send({
audioFileUri: 'gs://krow-workforce-dev-private/uploads/other-user/request.webm',
locale: 'en-US',
});
assert.equal(res.status, 403);
assert.equal(res.body.code, 'FORBIDDEN');
});
test('POST /core/rapid-orders/parse returns structured rapid order draft', async () => {
const app = createApp();
const res = await request(app)
.post('/core/rapid-orders/parse')
.set('Authorization', 'Bearer test-token')
.send({
text: 'Need 2 servers ASAP for 4 hours',
locale: 'en-US',
timezone: 'America/New_York',
now: '2026-02-27T12:00:00.000Z',
});
assert.equal(res.status, 200);
assert.equal(res.body.parsed.orderType, 'ONE_TIME');
assert.equal(res.body.parsed.isRapid, true);
assert.equal(Array.isArray(res.body.parsed.positions), true);
assert.equal(res.body.parsed.positions[0].role, 'server');
assert.equal(res.body.parsed.positions[0].count, 2);
assert.equal(res.body.parsed.durationMinutes, 240);
assert.equal(typeof res.body.confidence.overall, 'number');
assert.equal(typeof res.body.requestId, 'string');
});
test('POST /core/rapid-orders/parse validates timezone', async () => {
const app = createApp();
const res = await request(app)
.post('/core/rapid-orders/parse')
.set('Authorization', 'Bearer test-token')
.send({
text: 'Need 2 servers ASAP',
timezone: 'Mars/OlympusMons',
});
assert.equal(res.status, 400);
assert.equal(res.body.code, 'VALIDATION_ERROR');
});
test('POST /core/rapid-orders/parse rejects unknown fields', async () => {
const app = createApp();
const res = await request(app)
.post('/core/rapid-orders/parse')
.set('Authorization', 'Bearer test-token')
.send({
text: 'Need 2 servers ASAP',
unexpected: 'not-allowed',
});
assert.equal(res.status, 400);
assert.equal(res.body.code, 'VALIDATION_ERROR');
});
test('POST /core/rapid-orders/parse enforces per-user model rate limit', async () => {
process.env.LLM_RATE_LIMIT_PER_MINUTE = '1';
const app = createApp();
const first = await request(app)
.post('/core/rapid-orders/parse')
.set('Authorization', 'Bearer test-token')
.send({
text: 'Need 2 servers ASAP for 4 hours',
});
const second = await request(app)
.post('/core/rapid-orders/parse')
.set('Authorization', 'Bearer test-token')
.send({
text: 'Need 3 bartenders tonight',
});
assert.equal(first.status, 200);
assert.equal(second.status, 429);
assert.equal(second.body.code, 'RATE_LIMITED');
assert.equal(typeof second.headers['retry-after'], 'string');
});
test('POST /core/verifications creates async job and GET returns status', async () => {
const app = createApp();
const created = await request(app)