@pellux/goodvibes-daemon-sdk 0.30.2 → 0.33.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 +2 -2
- package/dist/api-router.d.ts +4 -2
- package/dist/api-router.d.ts.map +1 -1
- package/dist/api-router.js +18 -10
- package/dist/artifact-upload.d.ts +9 -9
- package/dist/artifact-upload.d.ts.map +1 -1
- package/dist/artifact-upload.js +27 -19
- package/dist/auth-helpers.d.ts +9 -0
- package/dist/auth-helpers.d.ts.map +1 -0
- package/dist/auth-helpers.js +10 -0
- package/dist/automation.js +10 -10
- package/dist/channel-route-types.d.ts +22 -23
- package/dist/channel-route-types.d.ts.map +1 -1
- package/dist/channel-routes.d.ts.map +1 -1
- package/dist/channel-routes.js +37 -42
- package/dist/context.d.ts +27 -27
- package/dist/context.d.ts.map +1 -1
- package/dist/control-routes.d.ts +12 -13
- package/dist/control-routes.d.ts.map +1 -1
- package/dist/control-routes.js +55 -26
- package/dist/error-response.d.ts +10 -3
- package/dist/error-response.d.ts.map +1 -1
- package/dist/error-response.js +102 -11
- package/dist/http-policy.d.ts +3 -4
- package/dist/http-policy.d.ts.map +1 -1
- package/dist/http-policy.js +2 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/integration-routes.d.ts +1 -1
- package/dist/integration-routes.d.ts.map +1 -1
- package/dist/integration-routes.js +72 -33
- package/dist/knowledge-refinement-routes.d.ts.map +1 -1
- package/dist/knowledge-refinement-routes.js +22 -15
- package/dist/knowledge-route-types.d.ts +16 -15
- package/dist/knowledge-route-types.d.ts.map +1 -1
- package/dist/knowledge-routes.d.ts.map +1 -1
- package/dist/knowledge-routes.js +144 -89
- package/dist/media-route-types.d.ts +2 -1
- package/dist/media-route-types.d.ts.map +1 -1
- package/dist/media-routes.d.ts.map +1 -1
- package/dist/media-routes.js +119 -55
- package/dist/operator.d.ts +16 -0
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +105 -61
- package/dist/otlp-protobuf.d.ts.map +1 -1
- package/dist/otlp-protobuf.js +28 -10
- package/dist/remote-routes.d.ts +9 -3
- package/dist/remote-routes.d.ts.map +1 -1
- package/dist/remote-routes.js +259 -163
- package/dist/route-helpers.d.ts +13 -2
- package/dist/route-helpers.d.ts.map +1 -1
- package/dist/route-helpers.js +38 -1
- package/dist/runtime-automation-routes.d.ts.map +1 -1
- package/dist/runtime-automation-routes.js +88 -54
- package/dist/runtime-route-types.d.ts +87 -93
- package/dist/runtime-route-types.d.ts.map +1 -1
- package/dist/runtime-session-routes.d.ts +6 -4
- package/dist/runtime-session-routes.d.ts.map +1 -1
- package/dist/runtime-session-routes.js +132 -88
- package/dist/sessions.js +3 -3
- package/dist/system-route-types.d.ts +25 -24
- package/dist/system-route-types.d.ts.map +1 -1
- package/dist/system-routes.d.ts +1 -1
- package/dist/system-routes.d.ts.map +1 -1
- package/dist/system-routes.js +126 -92
- package/dist/tasks.d.ts.map +1 -1
- package/dist/tasks.js +2 -0
- package/dist/telemetry-routes.d.ts +14 -14
- package/dist/telemetry-routes.d.ts.map +1 -1
- package/dist/telemetry-routes.js +54 -29
- package/package.json +5 -4
package/dist/media-routes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolvePrivateHostFetchOptions } from './http-policy.js';
|
|
2
2
|
import { jsonErrorResponse } from './error-response.js';
|
|
3
|
-
import { DaemonErrorCategory } from '@pellux/goodvibes-errors';
|
|
4
3
|
import { createArtifactFromUploadRequest, isArtifactUploadRequest } from './artifact-upload.js';
|
|
4
|
+
import { createRouteBodySchema, createRouteBodySchemaRegistry, readBoundedBodyInteger, readOptionalStringField, readStringArrayField, } from './route-helpers.js';
|
|
5
5
|
function readErrorMessage(error) {
|
|
6
6
|
if (typeof error === 'string')
|
|
7
7
|
return error;
|
|
@@ -13,22 +13,16 @@ function readErrorMessage(error) {
|
|
|
13
13
|
return 'Unknown error';
|
|
14
14
|
}
|
|
15
15
|
function isProviderNotConfiguredError(error) {
|
|
16
|
-
|
|
17
|
-
return (msg.includes('not configured')
|
|
18
|
-
|| msg.includes('no provider')
|
|
19
|
-
|| msg.includes('api key')
|
|
20
|
-
|| msg.includes('api_key')
|
|
21
|
-
|| msg.includes('missing key')
|
|
22
|
-
|| msg.includes('no api')
|
|
23
|
-
|| msg.includes('provider not')
|
|
24
|
-
|| msg.includes('unconfigured'));
|
|
16
|
+
return Boolean(error && typeof error === 'object' && error.code === 'PROVIDER_NOT_CONFIGURED');
|
|
25
17
|
}
|
|
26
18
|
export function createDaemonMediaRouteHandlers(context) {
|
|
27
19
|
return {
|
|
28
20
|
getVoiceStatus: async () => Response.json(await context.voiceService.getStatus(Boolean(context.configManager.get('ui.voiceEnabled')))),
|
|
29
|
-
getVoiceProviders: async () =>
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
getVoiceProviders: async () => {
|
|
22
|
+
// reuse the same status snapshot instead of issuing a second provider-status probe.
|
|
23
|
+
const status = await context.voiceService.getStatus(Boolean(context.configManager.get('ui.voiceEnabled')));
|
|
24
|
+
return Response.json({ providers: status.providers });
|
|
25
|
+
},
|
|
32
26
|
getVoiceVoices: async (url) => Response.json({ voices: await context.voiceService.listVoices(url.searchParams.get('providerId') ?? undefined) }),
|
|
33
27
|
postVoiceTts: async (request) => handleVoiceTts(context, request),
|
|
34
28
|
postVoiceTtsStream: async (request) => handleVoiceTtsStream(context, request),
|
|
@@ -42,7 +36,7 @@ export function createDaemonMediaRouteHandlers(context) {
|
|
|
42
36
|
const artifact = context.artifactStore.get(artifactId);
|
|
43
37
|
return artifact
|
|
44
38
|
? Response.json({ artifact })
|
|
45
|
-
:
|
|
39
|
+
: jsonErrorResponse({ error: 'Unknown artifact' }, { status: 404 });
|
|
46
40
|
},
|
|
47
41
|
getArtifactContent: async (artifactId, request) => handleArtifactContent(context, artifactId, request),
|
|
48
42
|
getMediaProviders: async () => Response.json({ providers: await context.mediaProviders.status() }),
|
|
@@ -60,6 +54,12 @@ function readOptionalConfigString(context, key) {
|
|
|
60
54
|
const value = context.configManager.get(key);
|
|
61
55
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
62
56
|
}
|
|
57
|
+
const MAX_MEDIA_WRITEBACK_TAGS = 64;
|
|
58
|
+
function readOptionalBoundedNumber(value, min, max) {
|
|
59
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
60
|
+
return undefined;
|
|
61
|
+
return Math.min(max, Math.max(min, value));
|
|
62
|
+
}
|
|
63
63
|
function readVoiceSynthesisRequest(body, context) {
|
|
64
64
|
const providerId = typeof body.providerId === 'string'
|
|
65
65
|
? body.providerId
|
|
@@ -73,7 +73,7 @@ function readVoiceSynthesisRequest(body, context) {
|
|
|
73
73
|
: undefined;
|
|
74
74
|
const modelId = typeof body.modelId === 'string' ? body.modelId : undefined;
|
|
75
75
|
const format = typeof body.format === 'string' ? body.format : undefined;
|
|
76
|
-
const speed =
|
|
76
|
+
const speed = readOptionalBoundedNumber(body.speed, 0.25, 4);
|
|
77
77
|
const input = {
|
|
78
78
|
text: typeof body.text === 'string' ? body.text : '',
|
|
79
79
|
metadata: typeof body.metadata === 'object' && body.metadata !== null ? body.metadata : {},
|
|
@@ -91,38 +91,83 @@ function readVoiceSynthesisRequest(body, context) {
|
|
|
91
91
|
input,
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
+
const mediaBodySchemas = createRouteBodySchemaRegistry({
|
|
95
|
+
webSearch: createRouteBodySchema('POST /api/web-search', (body) => {
|
|
96
|
+
const query = readOptionalStringField(body, 'query');
|
|
97
|
+
if (!query)
|
|
98
|
+
return jsonErrorResponse({ error: 'Missing query' }, { status: 400 });
|
|
99
|
+
const providerId = readOptionalStringField(body, 'providerId');
|
|
100
|
+
const verbosity = readOptionalStringField(body, 'verbosity');
|
|
101
|
+
const region = readOptionalStringField(body, 'region');
|
|
102
|
+
const safeSearch = readOptionalStringField(body, 'safeSearch');
|
|
103
|
+
const timeRange = readOptionalStringField(body, 'timeRange');
|
|
104
|
+
const evidenceExtract = readOptionalStringField(body, 'evidenceExtract');
|
|
105
|
+
return {
|
|
106
|
+
query,
|
|
107
|
+
...(providerId ? { providerId } : {}),
|
|
108
|
+
...(Object.hasOwn(body, 'maxResults') ? { maxResults: readBoundedBodyInteger(body.maxResults, 5, 50) } : {}),
|
|
109
|
+
...(verbosity ? { verbosity: verbosity } : {}),
|
|
110
|
+
...(region ? { region } : {}),
|
|
111
|
+
...(safeSearch ? { safeSearch: safeSearch } : {}),
|
|
112
|
+
...(timeRange ? { timeRange: timeRange } : {}),
|
|
113
|
+
...(typeof body.includeInstantAnswer === 'boolean' ? { includeInstantAnswer: body.includeInstantAnswer } : {}),
|
|
114
|
+
...(typeof body.includeEvidence === 'boolean' ? { includeEvidence: body.includeEvidence } : {}),
|
|
115
|
+
...(Object.hasOwn(body, 'evidenceTopN') ? { evidenceTopN: readBoundedBodyInteger(body.evidenceTopN, 3, 20) } : {}),
|
|
116
|
+
...(evidenceExtract ? { evidenceExtract: evidenceExtract } : {}),
|
|
117
|
+
};
|
|
118
|
+
}),
|
|
119
|
+
multimodalPacket: createRouteBodySchema('POST /api/multimodal/packet', (body) => {
|
|
120
|
+
if (typeof body.analysis !== 'object' || body.analysis === null) {
|
|
121
|
+
return jsonErrorResponse({ error: 'Missing analysis payload' }, { status: 400 });
|
|
122
|
+
}
|
|
123
|
+
const detail = readOptionalStringField(body, 'detail');
|
|
124
|
+
return {
|
|
125
|
+
analysis: body.analysis,
|
|
126
|
+
detail: detail ?? 'standard',
|
|
127
|
+
...(Object.hasOwn(body, 'budgetLimit') ? { budgetLimit: readBoundedBodyInteger(body.budgetLimit, 8, 100) } : {}),
|
|
128
|
+
};
|
|
129
|
+
}),
|
|
130
|
+
});
|
|
94
131
|
async function handleVoiceTts(context, req) {
|
|
132
|
+
const admin = context.requireAdmin(req);
|
|
133
|
+
if (admin)
|
|
134
|
+
return admin;
|
|
95
135
|
const body = await context.parseJsonBody(req);
|
|
96
136
|
if (body instanceof Response)
|
|
97
137
|
return body;
|
|
98
|
-
|
|
138
|
+
// pass context so defaults from tts.provider/tts.voice config are applied
|
|
139
|
+
// consistently with handleVoiceTtsStream.
|
|
140
|
+
const { providerId, input } = readVoiceSynthesisRequest(body, context);
|
|
99
141
|
if (!input.text.trim())
|
|
100
|
-
return
|
|
142
|
+
return jsonErrorResponse({ error: 'Missing text' }, { status: 400 });
|
|
101
143
|
try {
|
|
102
144
|
const result = await context.voiceService.synthesize(providerId, input);
|
|
103
145
|
return Response.json(result);
|
|
104
146
|
}
|
|
105
147
|
catch (error) {
|
|
106
148
|
if (isProviderNotConfiguredError(error)) {
|
|
107
|
-
return
|
|
149
|
+
return jsonErrorResponse({ code: 'PROVIDER_NOT_CONFIGURED', error: readErrorMessage(error), source: 'provider', recoverable: false, hint: 'Configure the voice provider API key or service credentials.' }, { status: 409 });
|
|
108
150
|
}
|
|
109
151
|
return jsonErrorResponse(error, { status: 400 });
|
|
110
152
|
}
|
|
111
153
|
}
|
|
112
154
|
async function handleVoiceTtsStream(context, req) {
|
|
155
|
+
const admin = context.requireAdmin(req);
|
|
156
|
+
if (admin)
|
|
157
|
+
return admin;
|
|
113
158
|
const body = await context.parseJsonBody(req);
|
|
114
159
|
if (body instanceof Response)
|
|
115
160
|
return body;
|
|
116
161
|
const { providerId, input } = readVoiceSynthesisRequest(body, context);
|
|
117
162
|
if (!input.text.trim())
|
|
118
|
-
return
|
|
163
|
+
return jsonErrorResponse({ error: 'Missing text' }, { status: 400 });
|
|
119
164
|
try {
|
|
120
165
|
const result = await context.voiceService.synthesizeStream(providerId, { ...input, signal: req.signal });
|
|
121
166
|
return voiceStreamResponse(result);
|
|
122
167
|
}
|
|
123
168
|
catch (error) {
|
|
124
169
|
if (isProviderNotConfiguredError(error)) {
|
|
125
|
-
return
|
|
170
|
+
return jsonErrorResponse({ code: 'PROVIDER_NOT_CONFIGURED', error: readErrorMessage(error), source: 'provider', recoverable: false, hint: 'Configure the streaming TTS provider API key or service credentials.' }, { status: 409 });
|
|
126
171
|
}
|
|
127
172
|
return jsonErrorResponse(error, { status: 400 });
|
|
128
173
|
}
|
|
@@ -162,11 +207,14 @@ function voiceStreamResponse(result) {
|
|
|
162
207
|
});
|
|
163
208
|
}
|
|
164
209
|
async function handleVoiceStt(context, req) {
|
|
210
|
+
const admin = context.requireAdmin(req);
|
|
211
|
+
if (admin)
|
|
212
|
+
return admin;
|
|
165
213
|
const body = await context.parseJsonBody(req);
|
|
166
214
|
if (body instanceof Response)
|
|
167
215
|
return body;
|
|
168
216
|
if (typeof body.audio !== 'object' || body.audio === null) {
|
|
169
|
-
return
|
|
217
|
+
return jsonErrorResponse({ error: 'Missing audio artifact' }, { status: 400 });
|
|
170
218
|
}
|
|
171
219
|
try {
|
|
172
220
|
const result = await context.voiceService.transcribe(typeof body.providerId === 'string' ? body.providerId : undefined, {
|
|
@@ -180,12 +228,15 @@ async function handleVoiceStt(context, req) {
|
|
|
180
228
|
}
|
|
181
229
|
catch (error) {
|
|
182
230
|
if (isProviderNotConfiguredError(error)) {
|
|
183
|
-
return
|
|
231
|
+
return jsonErrorResponse({ code: 'PROVIDER_NOT_CONFIGURED', error: readErrorMessage(error), source: 'provider', recoverable: false, hint: 'Configure the voice provider API key or service credentials.' }, { status: 409 });
|
|
184
232
|
}
|
|
185
233
|
return jsonErrorResponse(error, { status: 400 });
|
|
186
234
|
}
|
|
187
235
|
}
|
|
188
236
|
async function handleVoiceRealtimeSession(context, req) {
|
|
237
|
+
const admin = context.requireAdmin(req);
|
|
238
|
+
if (admin)
|
|
239
|
+
return admin;
|
|
189
240
|
const body = await context.parseJsonBody(req);
|
|
190
241
|
if (body instanceof Response)
|
|
191
242
|
return body;
|
|
@@ -202,18 +253,21 @@ async function handleVoiceRealtimeSession(context, req) {
|
|
|
202
253
|
}
|
|
203
254
|
catch (error) {
|
|
204
255
|
if (isProviderNotConfiguredError(error)) {
|
|
205
|
-
return
|
|
256
|
+
return jsonErrorResponse({ code: 'PROVIDER_NOT_CONFIGURED', error: readErrorMessage(error), source: 'provider', recoverable: false, hint: 'Configure the voice provider API key or service credentials.' }, { status: 409 });
|
|
206
257
|
}
|
|
207
258
|
return jsonErrorResponse(error, { status: 400 });
|
|
208
259
|
}
|
|
209
260
|
}
|
|
210
261
|
async function handleMediaAnalyze(context, req) {
|
|
262
|
+
const admin = context.requireAdmin(req);
|
|
263
|
+
if (admin)
|
|
264
|
+
return admin;
|
|
211
265
|
const body = await context.parseJsonBody(req);
|
|
212
266
|
if (body instanceof Response)
|
|
213
267
|
return body;
|
|
214
268
|
const provider = context.mediaProviders.findProvider('understand', typeof body.providerId === 'string' ? body.providerId : undefined);
|
|
215
269
|
if (!provider?.analyze)
|
|
216
|
-
return
|
|
270
|
+
return jsonErrorResponse({ error: 'No media analysis provider is registered' }, { status: 404 });
|
|
217
271
|
const artifact = typeof body.artifact === 'object' && body.artifact !== null
|
|
218
272
|
? body.artifact
|
|
219
273
|
: typeof body.artifactId === 'string' && body.artifactId.trim().length > 0
|
|
@@ -224,7 +278,7 @@ async function handleMediaAnalyze(context, req) {
|
|
|
224
278
|
}
|
|
225
279
|
: null;
|
|
226
280
|
if (!artifact) {
|
|
227
|
-
return
|
|
281
|
+
return jsonErrorResponse({ error: 'Missing media artifact' }, { status: 400 });
|
|
228
282
|
}
|
|
229
283
|
return Response.json(await provider.analyze({
|
|
230
284
|
artifact,
|
|
@@ -234,6 +288,9 @@ async function handleMediaAnalyze(context, req) {
|
|
|
234
288
|
}));
|
|
235
289
|
}
|
|
236
290
|
async function handleArtifactCreate(context, req) {
|
|
291
|
+
const admin = context.requireAdmin(req);
|
|
292
|
+
if (admin)
|
|
293
|
+
return admin;
|
|
237
294
|
if (isArtifactUploadRequest(req)) {
|
|
238
295
|
const uploaded = await createArtifactFromUploadRequest(context.artifactStore, req);
|
|
239
296
|
if (uploaded instanceof Response)
|
|
@@ -280,7 +337,9 @@ async function handleArtifactContent(context, artifactId, req) {
|
|
|
280
337
|
});
|
|
281
338
|
const download = new URL(req.url).searchParams.get('download');
|
|
282
339
|
if (record.filename && download !== '0') {
|
|
283
|
-
|
|
340
|
+
// Strip non-ASCII bytes so the ASCII filename parameter stays valid.
|
|
341
|
+
const asciiFallback = record.filename.replace(/[^\x20-\x7E]/g, '_').replace(/[\r\n"]/g, '_');
|
|
342
|
+
headers.set('Content-Disposition', `attachment; filename="${asciiFallback}"; filename*=UTF-8''${encodeURIComponent(record.filename)}`);
|
|
284
343
|
}
|
|
285
344
|
return new Response(bytes, { status: 200, headers });
|
|
286
345
|
}
|
|
@@ -289,44 +348,38 @@ async function handleArtifactContent(context, artifactId, req) {
|
|
|
289
348
|
}
|
|
290
349
|
}
|
|
291
350
|
async function handleWebSearch(context, req) {
|
|
351
|
+
const admin = context.requireAdmin(req);
|
|
352
|
+
if (admin)
|
|
353
|
+
return admin;
|
|
292
354
|
const body = await context.parseJsonBody(req);
|
|
293
355
|
if (body instanceof Response)
|
|
294
356
|
return body;
|
|
295
|
-
const
|
|
296
|
-
if (
|
|
297
|
-
return
|
|
357
|
+
const input = mediaBodySchemas.webSearch.parse(body);
|
|
358
|
+
if (input instanceof Response)
|
|
359
|
+
return input;
|
|
298
360
|
try {
|
|
299
|
-
return Response.json(await context.webSearchService.search(
|
|
300
|
-
query,
|
|
301
|
-
...(typeof body.providerId === 'string' ? { providerId: body.providerId } : {}),
|
|
302
|
-
...(typeof body.maxResults === 'number' ? { maxResults: body.maxResults } : {}),
|
|
303
|
-
...(typeof body.verbosity === 'string' ? { verbosity: body.verbosity } : {}),
|
|
304
|
-
...(typeof body.region === 'string' ? { region: body.region } : {}),
|
|
305
|
-
...(typeof body.safeSearch === 'string' ? { safeSearch: body.safeSearch } : {}),
|
|
306
|
-
...(typeof body.timeRange === 'string' ? { timeRange: body.timeRange } : {}),
|
|
307
|
-
...(typeof body.includeInstantAnswer === 'boolean' ? { includeInstantAnswer: body.includeInstantAnswer } : {}),
|
|
308
|
-
...(typeof body.includeEvidence === 'boolean' ? { includeEvidence: body.includeEvidence } : {}),
|
|
309
|
-
...(typeof body.evidenceTopN === 'number' ? { evidenceTopN: body.evidenceTopN } : {}),
|
|
310
|
-
...(typeof body.evidenceExtract === 'string' ? { evidenceExtract: body.evidenceExtract } : {}),
|
|
311
|
-
}));
|
|
361
|
+
return Response.json(await context.webSearchService.search(input));
|
|
312
362
|
}
|
|
313
363
|
catch (error) {
|
|
314
364
|
return jsonErrorResponse(error, { status: 400 });
|
|
315
365
|
}
|
|
316
366
|
}
|
|
317
367
|
async function handleMediaTransform(context, req) {
|
|
368
|
+
const admin = context.requireAdmin(req);
|
|
369
|
+
if (admin)
|
|
370
|
+
return admin;
|
|
318
371
|
const body = await context.parseJsonBody(req);
|
|
319
372
|
if (body instanceof Response)
|
|
320
373
|
return body;
|
|
321
374
|
const provider = context.mediaProviders.findProvider('transform', typeof body.providerId === 'string' ? body.providerId : undefined);
|
|
322
375
|
if (!provider?.transform)
|
|
323
|
-
return
|
|
376
|
+
return jsonErrorResponse({ error: 'No media transform provider is registered' }, { status: 404 });
|
|
324
377
|
if (typeof body.artifact !== 'object' || body.artifact === null) {
|
|
325
|
-
return
|
|
378
|
+
return jsonErrorResponse({ error: 'Missing media artifact' }, { status: 400 });
|
|
326
379
|
}
|
|
327
380
|
const operation = typeof body.operation === 'string' ? body.operation : '';
|
|
328
381
|
if (!operation)
|
|
329
|
-
return
|
|
382
|
+
return jsonErrorResponse({ error: 'Missing media transform operation' }, { status: 400 });
|
|
330
383
|
return Response.json(await provider.transform({
|
|
331
384
|
artifact: body.artifact,
|
|
332
385
|
operation,
|
|
@@ -336,15 +389,18 @@ async function handleMediaTransform(context, req) {
|
|
|
336
389
|
}));
|
|
337
390
|
}
|
|
338
391
|
async function handleMediaGenerate(context, req) {
|
|
392
|
+
const admin = context.requireAdmin(req);
|
|
393
|
+
if (admin)
|
|
394
|
+
return admin;
|
|
339
395
|
const body = await context.parseJsonBody(req);
|
|
340
396
|
if (body instanceof Response)
|
|
341
397
|
return body;
|
|
342
398
|
const provider = context.mediaProviders.findProvider('generate', typeof body.providerId === 'string' ? body.providerId : undefined);
|
|
343
399
|
if (!provider?.generate)
|
|
344
|
-
return
|
|
400
|
+
return jsonErrorResponse({ error: 'No media generation provider is registered' }, { status: 404 });
|
|
345
401
|
const prompt = typeof body.prompt === 'string' ? body.prompt : '';
|
|
346
402
|
if (!prompt.trim())
|
|
347
|
-
return
|
|
403
|
+
return jsonErrorResponse({ error: 'Missing media generation prompt' }, { status: 400 });
|
|
348
404
|
return Response.json(await provider.generate({
|
|
349
405
|
prompt,
|
|
350
406
|
outputMimeType: typeof body.outputMimeType === 'string' ? body.outputMimeType : undefined,
|
|
@@ -354,6 +410,9 @@ async function handleMediaGenerate(context, req) {
|
|
|
354
410
|
}));
|
|
355
411
|
}
|
|
356
412
|
async function handleMultimodalAnalyze(context, req) {
|
|
413
|
+
const admin = context.requireAdmin(req);
|
|
414
|
+
if (admin)
|
|
415
|
+
return admin;
|
|
357
416
|
const body = await context.parseJsonBody(req);
|
|
358
417
|
if (body instanceof Response)
|
|
359
418
|
return body;
|
|
@@ -412,30 +471,35 @@ async function handleMultimodalAnalyze(context, req) {
|
|
|
412
471
|
}
|
|
413
472
|
}
|
|
414
473
|
async function handleMultimodalPacket(context, req) {
|
|
474
|
+
const admin = context.requireAdmin(req);
|
|
475
|
+
if (admin)
|
|
476
|
+
return admin;
|
|
415
477
|
const body = await context.parseJsonBody(req);
|
|
416
478
|
if (body instanceof Response)
|
|
417
479
|
return body;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const detail = typeof body.detail === 'string' ? body.detail : 'standard';
|
|
422
|
-
const budgetLimit = typeof body.budgetLimit === 'number' ? body.budgetLimit : undefined;
|
|
480
|
+
const input = mediaBodySchemas.multimodalPacket.parse(body);
|
|
481
|
+
if (input instanceof Response)
|
|
482
|
+
return input;
|
|
423
483
|
return Response.json({
|
|
424
|
-
packet: context.multimodalService.buildPacket(
|
|
484
|
+
packet: context.multimodalService.buildPacket(input.analysis, input.detail, input.budgetLimit),
|
|
425
485
|
});
|
|
426
486
|
}
|
|
427
487
|
async function handleMultimodalWriteback(context, req) {
|
|
488
|
+
const admin = context.requireAdmin(req);
|
|
489
|
+
if (admin)
|
|
490
|
+
return admin;
|
|
428
491
|
const body = await context.parseJsonBody(req);
|
|
429
492
|
if (body instanceof Response)
|
|
430
493
|
return body;
|
|
431
494
|
if (typeof body.analysis !== 'object' || body.analysis === null) {
|
|
432
|
-
return
|
|
495
|
+
return jsonErrorResponse({ error: 'Missing analysis payload' }, { status: 400 });
|
|
433
496
|
}
|
|
497
|
+
const tags = readStringArrayField(body, 'tags', MAX_MEDIA_WRITEBACK_TAGS);
|
|
434
498
|
try {
|
|
435
499
|
const writeback = await context.multimodalService.writeBackAnalysis(body.analysis, {
|
|
436
500
|
...(typeof body.sessionId === 'string' ? { sessionId: body.sessionId } : {}),
|
|
437
501
|
...(typeof body.title === 'string' ? { title: body.title } : {}),
|
|
438
|
-
...(
|
|
502
|
+
...(tags ? { tags } : {}),
|
|
439
503
|
...(typeof body.folderPath === 'string' ? { folderPath: body.folderPath } : {}),
|
|
440
504
|
...(typeof body.metadata === 'object' && body.metadata !== null ? { metadata: body.metadata } : {}),
|
|
441
505
|
});
|
package/dist/operator.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
1
|
import type { DaemonOperatorRouteHandlers } from './context.js';
|
|
2
|
+
/**
|
|
3
|
+
* Route-level authentication is enforced inside each handler, not at the
|
|
4
|
+
* dispatcher level. Handler auth requirements by category:
|
|
5
|
+
*
|
|
6
|
+
* - READ-ONLY routes (status, providers, settings, continuity, intelligence,
|
|
7
|
+
* worktrees, watchers, approvals, telemetry snapshot) — require admin or
|
|
8
|
+
* authenticated session per handler implementation.
|
|
9
|
+
* - STATE-CHANGING routes (service install/start/stop, route bindings,
|
|
10
|
+
* automation jobs, knowledge ingest) — always `withAdmin(context, req, ...)`.
|
|
11
|
+
* - SCHEDULER/RUNTIME routes (getSchedulerCapacity, getRuntimeMetrics) —
|
|
12
|
+
* require admin per handler implementation.
|
|
13
|
+
*
|
|
14
|
+
* Dispatcher does not short-circuit unauthenticated requests; all auth
|
|
15
|
+
* enforcement lives in the handler factories (system-routes.ts,
|
|
16
|
+
* integration-routes.ts, runtime-automation-routes.ts, etc.).
|
|
17
|
+
*/
|
|
2
18
|
export declare function dispatchOperatorRoutes(req: Request, handlers: DaemonOperatorRouteHandlers): Promise<Response | null>;
|
|
3
19
|
//# sourceMappingURL=operator.d.ts.map
|
package/dist/operator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AA4BhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,2BAA2B,GACpC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAO1B"}
|