@acorex-platform/module-ai-management-client 0.0.37 → 0.0.46

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.
Files changed (55) hide show
  1. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-agent.mjs +30 -0
  2. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-agent.mjs.map +1 -1
  3. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-assist.mjs +16 -0
  4. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-assist.mjs.map +1 -1
  5. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-mcp-server.mjs +30 -0
  6. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-mcp-server.mjs.map +1 -1
  7. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-model.mjs +52 -15
  8. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-model.mjs.map +1 -1
  9. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-open-ai-endpoint.mjs +30 -0
  10. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-open-ai-endpoint.mjs.map +1 -1
  11. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-rule.mjs +30 -0
  12. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-rule.mjs.map +1 -1
  13. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-run-log.mjs +430 -0
  14. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-run-log.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-skill.mjs +30 -0
  16. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entities-skill.mjs.map +1 -1
  17. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-acorex-platform-module-ai-management-client-contracts-entity-catalog-oTY4z5q8.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-acorex-platform-module-ai-management-client-contracts-entity-catalog-D8jl5iFT.mjs} +25 -8
  18. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-acorex-platform-module-ai-management-client-contracts-entity-catalog-D8jl5iFT.mjs.map +1 -0
  19. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-agent.entity-C75X-uZh.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-agent.entity-Dj7dZRjE.mjs} +16 -2
  20. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-agent.entity-Dj7dZRjE.mjs.map +1 -0
  21. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-assist.entity-DrlJo7CZ.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-assist.entity-DUlikO9I.mjs} +2 -2
  22. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-assist.entity-DrlJo7CZ.mjs.map → acorex-platform-module-ai-management-client-contracts-entity-catalog-assist.entity-DUlikO9I.mjs.map} +1 -1
  23. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-mcp-server.entity-UxFvQ92v.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-mcp-server.entity-BVI_7IhH.mjs} +16 -2
  24. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-mcp-server.entity-BVI_7IhH.mjs.map +1 -0
  25. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-model.entity-DEdFUAPx.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-model.entity-Xd45s9xE.mjs} +38 -17
  26. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-model.entity-Xd45s9xE.mjs.map +1 -0
  27. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-open-ai-endpoint.entity-CygH9dU_.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-open-ai-endpoint.entity-CWsUMad_.mjs} +16 -2
  28. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-open-ai-endpoint.entity-CWsUMad_.mjs.map +1 -0
  29. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-rule.entity-Ddul_n4_.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-rule.entity-Z6wYZrFU.mjs} +16 -2
  30. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-rule.entity-Z6wYZrFU.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-run-log.entity-B2PG0QN0.mjs +343 -0
  32. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-run-log.entity-B2PG0QN0.mjs.map +1 -0
  33. package/fesm2022/{acorex-platform-module-ai-management-client-contracts-entity-catalog-skill.entity-CeMnKpRg.mjs → acorex-platform-module-ai-management-client-contracts-entity-catalog-skill.entity-sNsPtjnT.mjs} +16 -2
  34. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-skill.entity-sNsPtjnT.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog.mjs +1 -1
  36. package/fesm2022/acorex-platform-module-ai-management-client-contracts.mjs +598 -526
  37. package/fesm2022/acorex-platform-module-ai-management-client-contracts.mjs.map +1 -1
  38. package/fesm2022/{acorex-platform-module-ai-management-client-list-ai-query-registry-catalog.query-BX0uU1YX.mjs → acorex-platform-module-ai-management-client-list-ai-query-registry-catalog.query-BxL3pxzj.mjs} +3 -3
  39. package/fesm2022/acorex-platform-module-ai-management-client-list-ai-query-registry-catalog.query-BxL3pxzj.mjs.map +1 -0
  40. package/fesm2022/acorex-platform-module-ai-management-client-local-entities.mjs +1 -0
  41. package/fesm2022/acorex-platform-module-ai-management-client-local-entities.mjs.map +1 -1
  42. package/fesm2022/acorex-platform-module-ai-management-client.mjs +240 -109
  43. package/fesm2022/acorex-platform-module-ai-management-client.mjs.map +1 -1
  44. package/package.json +5 -1
  45. package/types/acorex-platform-module-ai-management-client-contracts-entities-run-log.d.ts +5 -0
  46. package/types/acorex-platform-module-ai-management-client-contracts.d.ts +149 -85
  47. package/types/acorex-platform-module-ai-management-client.d.ts +24 -18
  48. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-acorex-platform-module-ai-management-client-contracts-entity-catalog-oTY4z5q8.mjs.map +0 -1
  49. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-agent.entity-C75X-uZh.mjs.map +0 -1
  50. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-mcp-server.entity-UxFvQ92v.mjs.map +0 -1
  51. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-model.entity-DEdFUAPx.mjs.map +0 -1
  52. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-open-ai-endpoint.entity-CygH9dU_.mjs.map +0 -1
  53. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-rule.entity-Ddul_n4_.mjs.map +0 -1
  54. package/fesm2022/acorex-platform-module-ai-management-client-contracts-entity-catalog-skill.entity-CeMnKpRg.mjs.map +0 -1
  55. package/fesm2022/acorex-platform-module-ai-management-client-list-ai-query-registry-catalog.query-BX0uU1YX.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { axpContextDefinitionIsAiPrompt, resolveMultiLanguageString } from '@acorex-platform/framework-shared/core';
1
+ import { resolveMultiLanguageString, axpContextDefinitionIsAiPrompt } from '@acorex-platform/framework-shared/core';
2
2
 
3
3
  //#region ---- Feature keys ----
4
4
  /**
@@ -162,172 +162,310 @@ const RootConfig = {
162
162
  titlePlural: '@ai-management:mcp-servers.entities.mcp-server.plural',
163
163
  icon: 'fa-light fa-plug-circle-bolt',
164
164
  },
165
+ runLog: {
166
+ name: 'AiRunLog',
167
+ fullName: `${config.module}.AiRunLog`,
168
+ title: '@ai-management:run-logs.entities.run-log.title',
169
+ titlePlural: '@ai-management:run-logs.entities.run-log.plural',
170
+ icon: 'fa-light fa-chart-mixed',
171
+ },
172
+ },
173
+ queries: {
174
+ reports: {
175
+ assistTokenUsage: `${config.module}:Reports:AssistTokenUsage`,
176
+ modelUsage: `${config.module}:Reports:ModelUsage`,
177
+ userUsage: `${config.module}:Reports:UserUsage`,
178
+ dailyTrend: `${config.module}:Reports:DailyTrend`,
179
+ runLog: `${config.module}:Reports:RunLog`,
180
+ },
165
181
  },
166
182
  };
167
183
  //#endregion
168
184
 
185
+ //#region ---- Imports ----
186
+ //#endregion
187
+ //#region ---- Manifest Definition ----
188
+ /**
189
+ * AI Management Module Manifest.
190
+ * Defines module metadata for AI provider and API key management.
191
+ */
192
+ const AiManagementManifest = {
193
+ name: RootConfig.module.name,
194
+ version: '1.0.0',
195
+ title: RootConfig.module.title,
196
+ icon: RootConfig.module.icon,
197
+ i18n: RootConfig.config.i18n,
198
+ type: 'domain',
199
+ domain: 'ai',
200
+ dependencies: [],
201
+ };
169
202
  //#endregion
170
203
 
171
- //#region ---- Platform runtime time & notes ----
172
- const AXM_AI_PLATFORM_RUNTIME_CONTEXT_DEFINITIONS = [
173
- {
174
- name: 'currentInstant',
175
- title: 'Current instant (UTC)',
176
- description: 'Current moment as ISO 8601 UTC, built when platform runtime context is assembled before an AI engine run.',
177
- order: 80,
178
- capabilities: ['ai'],
179
- },
180
- {
181
- name: 'currentLocalDateTime',
182
- title: 'Current local date and time',
183
- description: 'Current date and time formatted in the user IANA time zone for natural-language interpretation in system prompts.',
184
- order: 90,
185
- capabilities: ['ai'],
186
- },
187
- {
188
- name: 'notes',
189
- title: 'Runtime notes',
190
- description: 'Optional free-text or structured notes merged into platform runtime context for a specific AI run (caller-supplied).',
191
- order: 100,
192
- capabilities: ['ai'],
193
- },
194
- ];
195
204
  //#endregion
196
205
 
197
- //#region ---- Imports ----
198
206
  //#endregion
199
207
 
200
- //#region ----- Imports -----
201
- const AXP_AI_SDK_TOOL_CONTEXT_JSON_SCHEMA = {
202
- type: 'object',
203
- properties: {
204
- runId: { type: 'string' },
205
- assistId: { type: 'string' },
206
- agentId: { type: 'string' },
207
- chatTransport: { type: 'string' },
208
- modelEntityId: { type: 'string' },
209
- },
210
- additionalProperties: false,
211
- };
212
- function stringifyRuntimeValue(value) {
213
- if (value == null) {
214
- return undefined;
208
+ //#region ----- Types -----
209
+ //#endregion
210
+ //#region ----- Constants -----
211
+ const IMAGE_MIME_TYPES = new Set([
212
+ 'image/jpeg',
213
+ 'image/png',
214
+ 'image/webp',
215
+ 'image/gif',
216
+ 'image/bmp',
217
+ 'image/tiff',
218
+ ]);
219
+ const IMAGE_EXTENSION_PATTERN = /\.(png|jpe?g|gif|webp|bmp|tif|tiff)$/i;
220
+ const TEXT_MIME_TYPES = new Set([
221
+ 'text/plain',
222
+ 'text/markdown',
223
+ 'text/csv',
224
+ 'application/json',
225
+ ]);
226
+ const TEXT_EXTENSION_PATTERN = /\.(txt|md|csv|json)$/i;
227
+ const PDF_MIME = 'application/pdf';
228
+ const PDF_EXTENSION_PATTERN = /\.pdf$/i;
229
+ //#endregion
230
+ //#region ----- Helpers -----
231
+ function normalizeMime(mimeType) {
232
+ return typeof mimeType === 'string' ? mimeType.trim().toLowerCase() : '';
233
+ }
234
+ function isTextMime(mime) {
235
+ if (TEXT_MIME_TYPES.has(mime)) {
236
+ return true;
215
237
  }
216
- if (typeof value === 'string') {
217
- const trimmed = value.trim();
218
- return trimmed.length > 0 ? trimmed : undefined;
238
+ return mime.startsWith('text/');
239
+ }
240
+ function classifyByFilename(filename) {
241
+ const name = typeof filename === 'string' ? filename.trim() : '';
242
+ if (!name) {
243
+ return 'unsupported';
219
244
  }
220
- if (typeof value === 'number' || typeof value === 'boolean') {
221
- return String(value);
245
+ if (IMAGE_EXTENSION_PATTERN.test(name)) {
246
+ return 'image';
222
247
  }
223
- try {
224
- const json = JSON.stringify(value);
225
- return json && json !== '{}' && json !== '[]' ? json : undefined;
248
+ if (PDF_EXTENSION_PATTERN.test(name)) {
249
+ return 'pdf';
226
250
  }
227
- catch {
228
- return undefined;
251
+ if (TEXT_EXTENSION_PATTERN.test(name)) {
252
+ return 'text';
229
253
  }
254
+ return 'unsupported';
230
255
  }
231
- function compactStringRecord(input) {
232
- const out = {};
233
- for (const [key, value] of Object.entries(input)) {
234
- const trimmed = value?.trim();
235
- if (trimmed) {
236
- out[key] = trimmed;
256
+ //#endregion
257
+ //#region ----- Classification -----
258
+ /**
259
+ * Classifies a document for AI text extraction (image OCR, PDF file part, or UTF-8 text).
260
+ * Does not include Office formats.
261
+ */
262
+ function classifyAiExtractDocument(mimeType, filename) {
263
+ const mime = normalizeMime(mimeType);
264
+ if (mime && mime !== 'application/octet-stream') {
265
+ if (mime.startsWith('image/') || IMAGE_MIME_TYPES.has(mime)) {
266
+ return 'image';
267
+ }
268
+ if (mime === PDF_MIME) {
269
+ return 'pdf';
270
+ }
271
+ if (isTextMime(mime)) {
272
+ return 'text';
237
273
  }
238
274
  }
239
- return Object.keys(out).length > 0 ? out : undefined;
275
+ return classifyByFilename(filename);
240
276
  }
277
+ function canAiExtractDocument(mimeType, filename) {
278
+ return classifyAiExtractDocument(mimeType, filename) !== 'unsupported';
279
+ }
280
+ //#endregion
281
+
282
+ //#region ----- AI run cost -----
241
283
  /**
242
- * Turns registered AI-capable context definitions + live values into the
243
- * `## Platform runtime` system-prompt block. Identity ids are never assembled into values.
284
+ * Estimated USD cost from catalog prices (USD per 1M tokens) and usage totals.
285
+ * Snapshot prices at write time so later catalog edits do not rewrite history.
244
286
  */
245
- function formatAxpAiPlatformRuntimePrompt(platformRuntimeContext, definitions) {
246
- if (!platformRuntimeContext || !definitions?.length) {
247
- return '';
248
- }
249
- const lines = definitions
250
- .filter(axpContextDefinitionIsAiPrompt)
251
- .slice()
252
- .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
253
- .map((field) => {
254
- const value = stringifyRuntimeValue(platformRuntimeContext[field.name]);
255
- return value ? `- ${field.title}: ${value}` : null;
256
- })
257
- .filter((line) => line != null);
258
- if (lines.length === 0) {
259
- return '';
287
+ function estimateAiRunCostUsd(promptTokens, completionTokens, inputPricePerMillion, outputPricePerMillion) {
288
+ const prompt = Math.max(0, Number(promptTokens) || 0) / 1_000_000;
289
+ const completion = Math.max(0, Number(completionTokens) || 0) / 1_000_000;
290
+ const inputPrice = Number(inputPricePerMillion) || 0;
291
+ const outputPrice = Number(outputPricePerMillion) || 0;
292
+ return Number((prompt * inputPrice + completion * outputPrice).toFixed(6));
293
+ }
294
+ //#endregion
295
+
296
+ //#region ---- Imports ----
297
+ //#endregion
298
+ //#region ---- Supervisor delegated-agent helpers ----
299
+ /** Prefix for supervisor-delegated specialist tools (`${AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX}${agentId}`). */
300
+ const AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX = 'agent:';
301
+ function axpAiSupervisorAgentToolName(agentCatalogId) {
302
+ return `${AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX}${agentCatalogId.trim()}`;
303
+ }
304
+ function axpAiParseSupervisorAgentToolName(toolName) {
305
+ const n = toolName.trim();
306
+ if (!n.startsWith(AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX)) {
307
+ return null;
260
308
  }
261
- return ['## Platform runtime', ...lines].join('\n');
309
+ const id = n.slice(AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX.length).trim();
310
+ return id.length > 0 ? id : null;
262
311
  }
263
- function buildAxpAiSdkChatContextBundle(input) {
264
- const runtimeContext = compactStringRecord({
265
- runId: input.runId,
266
- assistId: input.assistId,
267
- agentId: input.agentId,
268
- agentName: input.agentName,
269
- chatTransport: input.chatTransport,
270
- modelEntityId: input.modelEntityId,
271
- demisSessionUuid: input.demisSessionUuid,
272
- });
273
- const toolsContext = compactStringRecord({
274
- runId: input.runId,
275
- assistId: input.assistId,
276
- agentId: input.agentId,
277
- chatTransport: input.chatTransport,
278
- modelEntityId: input.modelEntityId,
279
- });
312
+ //#endregion
313
+ //#region ---- Message builders ----
314
+ function axpAiChatTextMessage(role, text) {
280
315
  return {
281
- ...(runtimeContext ? { runtimeContext } : {}),
282
- ...(toolsContext ? { toolsContext } : {}),
283
- promptAddendum: formatAxpAiPlatformRuntimePrompt(input.platformRuntimeContext, input.contextDefinitions),
316
+ role,
317
+ responses: [{ type: 'text', content: text }],
284
318
  };
285
319
  }
286
- function attachAxpAiSdkChatContext(options, bundle) {
287
- const hasTools = Boolean(options.tools && options.tools.length > 0);
320
+ function axpAiChatToolResultMessage(callId, content, toolName) {
321
+ const id = callId.trim();
288
322
  return {
289
- ...options,
290
- ...(bundle.runtimeContext ? { runtimeContext: bundle.runtimeContext } : {}),
291
- ...(hasTools && bundle.toolsContext ? { toolsContext: bundle.toolsContext } : {}),
323
+ role: 'tool',
324
+ ...(toolName?.trim() ? { name: toolName.trim() } : {}),
325
+ responses: [
326
+ {
327
+ type: 'tool_result',
328
+ callId: id,
329
+ content,
330
+ },
331
+ ],
292
332
  };
293
333
  }
294
- function formatAxpAiPlatformRuntimeLocalDateTime(now, ianaTimeZone) {
295
- const tz = ianaTimeZone?.trim() || 'UTC';
296
- try {
297
- return (now.toLocaleString('en-US', {
298
- timeZone: tz,
299
- dateStyle: 'full',
300
- timeStyle: 'long',
301
- }) + ` (${tz})`);
334
+ //#endregion
335
+ //#region ---- Transcript read helpers ----
336
+ function axpAiChatMessageGetText(message) {
337
+ const parts = [];
338
+ for (const r of message.responses) {
339
+ if (r.type === 'text') {
340
+ parts.push(r.content);
341
+ }
342
+ else if (r.type === 'node' || r.type === 'followUp') {
343
+ try {
344
+ parts.push(JSON.stringify({ type: r.type, content: r.content }));
345
+ }
346
+ catch {
347
+ parts.push(`[${r.type}]`);
348
+ }
349
+ }
350
+ }
351
+ return parts.join('\n\n');
352
+ }
353
+ //#endregion
354
+ //#region ---- Tool result normalization ----
355
+ function axpAiNormalizeHandlerResultToToolBody(handlerResult) {
356
+ if (handlerResult === undefined || handlerResult === null) {
357
+ return { success: false, error: 'Tool returned no result.' };
358
+ }
359
+ if (typeof handlerResult === 'string') {
360
+ const t = handlerResult.trim();
361
+ if (!t) {
362
+ return { success: false, error: 'Tool returned an empty string.' };
363
+ }
364
+ try {
365
+ return JSON.parse(t);
366
+ }
367
+ catch {
368
+ return { success: true, kind: 'object', data: handlerResult };
369
+ }
370
+ }
371
+ if (typeof handlerResult === 'object' && !Array.isArray(handlerResult)) {
372
+ return handlerResult;
373
+ }
374
+ return { success: true, kind: 'object', data: handlerResult };
375
+ }
376
+ /** Unwraps a command/tool envelope and returns `data.node` when it is a widget-like object. */
377
+ function axpAiExtractChatWidgetNodeFromUnknown(content) {
378
+ if (content == null || typeof content !== 'object' || Array.isArray(content)) {
379
+ return null;
380
+ }
381
+ const o = content;
382
+ const dataRaw = o['data'];
383
+ const d = o['success'] === true && dataRaw != null && typeof dataRaw === 'object' && !Array.isArray(dataRaw)
384
+ ? dataRaw
385
+ : o;
386
+ const node = d['node'];
387
+ if (node == null || typeof node !== 'object' || Array.isArray(node)) {
388
+ return null;
389
+ }
390
+ const type = node['type'];
391
+ if (typeof type !== 'string' || !type.trim()) {
392
+ return null;
393
+ }
394
+ return node;
395
+ }
396
+ //#endregion
397
+
398
+ //#region ---- Imports ----
399
+ //#endregion
400
+ //#region ---- Transcript helpers ----
401
+ function axpAiChatMessagesFromProviderAssistant(text, toolCalls) {
402
+ const normalized = (text ?? '')
403
+ .replace(/&lt;(\/?redacted_thinking)&gt;/gi, '<$1>')
404
+ .replace(/&lt;(\/?think)&gt;/gi, '<$1>');
405
+ const responses = [];
406
+ const thinkRe = /<(redacted_thinking|think)>([\s\S]*?)<\/\1>/gi;
407
+ let last = 0;
408
+ let m;
409
+ while ((m = thinkRe.exec(normalized)) !== null) {
410
+ const plain = normalized.slice(last, m.index).trim();
411
+ if (plain.length > 0) {
412
+ responses.push({ type: 'text', content: plain });
413
+ }
414
+ const think = (m[2] ?? '').trim();
415
+ if (think.length > 0) {
416
+ responses.push({ type: 'think', content: think });
417
+ }
418
+ last = m.index + m[0].length;
419
+ }
420
+ const tail = normalized.slice(last).trim();
421
+ if (tail.length > 0) {
422
+ responses.push({ type: 'text', content: tail });
423
+ }
424
+ const out = [];
425
+ if (responses.length > 0) {
426
+ out.push({ role: 'assistant', responses });
427
+ }
428
+ for (const tc of toolCalls ?? []) {
429
+ const isDelegatedAgent = axpAiParseSupervisorAgentToolName(tc.name) != null;
430
+ out.push({
431
+ role: 'assistant',
432
+ responses: [
433
+ isDelegatedAgent
434
+ ? {
435
+ type: 'agent',
436
+ content: { command: tc.name, arguments: tc.arguments },
437
+ callId: tc.id,
438
+ ...(tc.metadata ? { metadata: { ...tc.metadata } } : {}),
439
+ }
440
+ : {
441
+ type: 'tool',
442
+ content: { command: tc.name, arguments: tc.arguments },
443
+ callId: tc.id,
444
+ ...(tc.metadata ? { metadata: { ...tc.metadata } } : {}),
445
+ },
446
+ ],
447
+ });
448
+ }
449
+ return out;
450
+ }
451
+ function axcResolveAiMlOrPlainString(value, locale = 'en-US') {
452
+ if (value == null) {
453
+ return '';
302
454
  }
303
- catch {
304
- return `${now.toISOString()} (UTC)`;
455
+ if (typeof value === 'string') {
456
+ return value.trim();
305
457
  }
458
+ return resolveMultiLanguageString(value, locale).trim();
306
459
  }
307
- function assembleAxpAiPlatformRuntimeContext(sources) {
308
- const now = sources.now ?? new Date();
309
- const ctx = {};
310
- const set = (key, value) => {
311
- if (value == null) {
312
- return;
313
- }
314
- const asString = typeof value === 'string' ? value.trim() : String(value).trim();
315
- if (asString.length > 0) {
316
- ctx[key] = typeof value === 'string' ? asString : value;
317
- }
318
- };
319
- set('userDisplayName', sources.userDisplayName);
320
- set('tenantTitle', sources.tenantTitle);
321
- set('applicationTitle', sources.applicationTitle);
322
- set('locale', sources.locale);
323
- set('calendarSystem', sources.calendarSystem);
324
- set('timeZone', sources.timeZone);
325
- set('country', sources.country);
326
- set('notes', sources.notes);
327
- set('currentInstant', now.toISOString());
328
- set('currentLocalDateTime', formatAxpAiPlatformRuntimeLocalDateTime(now, sources.timeZone));
329
- return ctx;
330
- }
460
+ //#endregion
461
+
462
+ //#region ---- AI chat registry command keys ----
463
+ const AIMANAGEMENT_CHAT_GENERATE_IMAGE_COMMAND_KEY = 'AiManagement:ChatGenerateImage';
464
+ const AIMANAGEMENT_CHAT_TRANSCRIBE_SPEECH_COMMAND_KEY = 'AiManagement:ChatTranscribeSpeech';
465
+ const AIMANAGEMENT_CHAT_SYNTHESIZE_SPEECH_COMMAND_KEY = 'AiManagement:ChatSynthesizeSpeech';
466
+ const AIMANAGEMENT_EXTRACT_DOCUMENT_TEXT_COMMAND_KEY = 'AiManagement:ExtractDocumentText';
467
+ const AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY = 'AiManagement:StructuredTextCompletion';
468
+ const AIMANAGEMENT_RENDER_CHAT_CHART_COMMAND_KEY = 'AiManagement:RenderChatChart';
331
469
  //#endregion
332
470
 
333
471
  //#region ---- Imports ----
@@ -463,6 +601,76 @@ function axpAiAgentOutputContractStructuredRetryCap(contract) {
463
601
  }
464
602
  //#endregion
465
603
 
604
+ //#region ---- Imports ----
605
+ /**
606
+ * Native structured output (AI SDK `output` / provider schema) must not run on tool-calling
607
+ * turns — only when tools are absent or explicitly disabled (`toolChoice: 'none'`).
608
+ */
609
+ function axpAiShouldApplyChatStructuredOutput(params) {
610
+ const format = params.responseFormat;
611
+ if (!format || format.type === 'text') {
612
+ return false;
613
+ }
614
+ if (!params.hasTools) {
615
+ return true;
616
+ }
617
+ return params.toolChoice === 'none';
618
+ }
619
+ //#endregion
620
+ //#region ---- Duplicate JSON in text ----
621
+ function stripJsonFences(raw) {
622
+ const fence = raw.match(/```(?:json)?\s*([\s\S]*?)```/i);
623
+ return fence ? fence[1].trim() : raw.trim();
624
+ }
625
+ function axpAiTryParseJsonValueFromAssistantText(text) {
626
+ const trimmed = stripJsonFences(text.trim());
627
+ if (!trimmed) {
628
+ return undefined;
629
+ }
630
+ if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
631
+ return undefined;
632
+ }
633
+ try {
634
+ return JSON.parse(trimmed);
635
+ }
636
+ catch {
637
+ return undefined;
638
+ }
639
+ }
640
+ function isFollowUpEnvelope(value) {
641
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
642
+ return false;
643
+ }
644
+ const o = value;
645
+ return o['type'] === 'followUp' && Array.isArray(o['content']);
646
+ }
647
+ function isLikelyWidgetRoot(value) {
648
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
649
+ return false;
650
+ }
651
+ const t = value['type'];
652
+ return typeof t === 'string' && t.trim().length > 0 && t !== 'node' && t !== 'followUp';
653
+ }
654
+ function isNodeEnvelope(value) {
655
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
656
+ return false;
657
+ }
658
+ const o = value;
659
+ return o['type'] === 'node' && o['content'] != null;
660
+ }
661
+ /** True when assistant `text` duplicates a structured segment already attached as `node` / `followUp`. */
662
+ function axpAiTextDuplicatesStructuredSegment(text, segment) {
663
+ const parsed = axpAiTryParseJsonValueFromAssistantText(text);
664
+ if (parsed === undefined) {
665
+ return false;
666
+ }
667
+ if (segment === 'followUp') {
668
+ return isFollowUpEnvelope(parsed);
669
+ }
670
+ return isLikelyWidgetRoot(parsed) || isNodeEnvelope(parsed);
671
+ }
672
+ //#endregion
673
+
466
674
  //#region ---- Imports ----
467
675
  function isSegmentPresetId(value) {
468
676
  return value === 'text' || value === 'node' || value === 'followUp' || value === 'file';
@@ -520,11 +728,173 @@ function resolveEffectiveOutputContract(params) {
520
728
  if (agent) {
521
729
  return agent;
522
730
  }
523
- const assist = contractFromUnknown(params.assist);
524
- if (assist) {
525
- return assist;
731
+ const assist = contractFromUnknown(params.assist);
732
+ if (assist) {
733
+ return assist;
734
+ }
735
+ return resolveAgentOutputContract(null);
736
+ }
737
+ //#endregion
738
+
739
+ //#region ---- Imports ----
740
+ //#endregion
741
+
742
+ //#region ---- Platform runtime time & notes ----
743
+ const AXM_AI_PLATFORM_RUNTIME_CONTEXT_DEFINITIONS = [
744
+ {
745
+ name: 'currentInstant',
746
+ title: 'Current instant (UTC)',
747
+ description: 'Current moment as ISO 8601 UTC, built when platform runtime context is assembled before an AI engine run.',
748
+ order: 80,
749
+ capabilities: ['ai'],
750
+ },
751
+ {
752
+ name: 'currentLocalDateTime',
753
+ title: 'Current local date and time',
754
+ description: 'Current date and time formatted in the user IANA time zone for natural-language interpretation in system prompts.',
755
+ order: 90,
756
+ capabilities: ['ai'],
757
+ },
758
+ {
759
+ name: 'notes',
760
+ title: 'Runtime notes',
761
+ description: 'Optional free-text or structured notes merged into platform runtime context for a specific AI run (caller-supplied).',
762
+ order: 100,
763
+ capabilities: ['ai'],
764
+ },
765
+ ];
766
+ //#endregion
767
+
768
+ //#region ----- Imports -----
769
+ const AXP_AI_SDK_TOOL_CONTEXT_JSON_SCHEMA = {
770
+ type: 'object',
771
+ properties: {
772
+ runId: { type: 'string' },
773
+ assistId: { type: 'string' },
774
+ agentId: { type: 'string' },
775
+ chatTransport: { type: 'string' },
776
+ modelEntityId: { type: 'string' },
777
+ },
778
+ additionalProperties: false,
779
+ };
780
+ function stringifyRuntimeValue(value) {
781
+ if (value == null) {
782
+ return undefined;
783
+ }
784
+ if (typeof value === 'string') {
785
+ const trimmed = value.trim();
786
+ return trimmed.length > 0 ? trimmed : undefined;
787
+ }
788
+ if (typeof value === 'number' || typeof value === 'boolean') {
789
+ return String(value);
790
+ }
791
+ try {
792
+ const json = JSON.stringify(value);
793
+ return json && json !== '{}' && json !== '[]' ? json : undefined;
794
+ }
795
+ catch {
796
+ return undefined;
797
+ }
798
+ }
799
+ function compactStringRecord(input) {
800
+ const out = {};
801
+ for (const [key, value] of Object.entries(input)) {
802
+ const trimmed = value?.trim();
803
+ if (trimmed) {
804
+ out[key] = trimmed;
805
+ }
806
+ }
807
+ return Object.keys(out).length > 0 ? out : undefined;
808
+ }
809
+ /**
810
+ * Turns registered AI-capable context definitions + live values into the
811
+ * `## Platform runtime` system-prompt block. Identity ids are never assembled into values.
812
+ */
813
+ function formatAxpAiPlatformRuntimePrompt(platformRuntimeContext, definitions) {
814
+ if (!platformRuntimeContext || !definitions?.length) {
815
+ return '';
816
+ }
817
+ const lines = definitions
818
+ .filter(axpContextDefinitionIsAiPrompt)
819
+ .slice()
820
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
821
+ .map((field) => {
822
+ const value = stringifyRuntimeValue(platformRuntimeContext[field.name]);
823
+ return value ? `- ${field.title}: ${value}` : null;
824
+ })
825
+ .filter((line) => line != null);
826
+ if (lines.length === 0) {
827
+ return '';
828
+ }
829
+ return ['## Platform runtime', ...lines].join('\n');
830
+ }
831
+ function buildAxpAiSdkChatContextBundle(input) {
832
+ const runtimeContext = compactStringRecord({
833
+ runId: input.runId,
834
+ assistId: input.assistId,
835
+ agentId: input.agentId,
836
+ agentName: input.agentName,
837
+ chatTransport: input.chatTransport,
838
+ modelEntityId: input.modelEntityId,
839
+ demisSessionUuid: input.demisSessionUuid,
840
+ });
841
+ const toolsContext = compactStringRecord({
842
+ runId: input.runId,
843
+ assistId: input.assistId,
844
+ agentId: input.agentId,
845
+ chatTransport: input.chatTransport,
846
+ modelEntityId: input.modelEntityId,
847
+ });
848
+ return {
849
+ ...(runtimeContext ? { runtimeContext } : {}),
850
+ ...(toolsContext ? { toolsContext } : {}),
851
+ promptAddendum: formatAxpAiPlatformRuntimePrompt(input.platformRuntimeContext, input.contextDefinitions),
852
+ };
853
+ }
854
+ function attachAxpAiSdkChatContext(options, bundle) {
855
+ const hasTools = Boolean(options.tools && options.tools.length > 0);
856
+ return {
857
+ ...options,
858
+ ...(bundle.runtimeContext ? { runtimeContext: bundle.runtimeContext } : {}),
859
+ ...(hasTools && bundle.toolsContext ? { toolsContext: bundle.toolsContext } : {}),
860
+ };
861
+ }
862
+ function formatAxpAiPlatformRuntimeLocalDateTime(now, ianaTimeZone) {
863
+ const tz = ianaTimeZone?.trim() || 'UTC';
864
+ try {
865
+ return (now.toLocaleString('en-US', {
866
+ timeZone: tz,
867
+ dateStyle: 'full',
868
+ timeStyle: 'long',
869
+ }) + ` (${tz})`);
870
+ }
871
+ catch {
872
+ return `${now.toISOString()} (UTC)`;
526
873
  }
527
- return resolveAgentOutputContract(null);
874
+ }
875
+ function assembleAxpAiPlatformRuntimeContext(sources) {
876
+ const now = sources.now ?? new Date();
877
+ const ctx = {};
878
+ const set = (key, value) => {
879
+ if (value == null) {
880
+ return;
881
+ }
882
+ const asString = typeof value === 'string' ? value.trim() : String(value).trim();
883
+ if (asString.length > 0) {
884
+ ctx[key] = typeof value === 'string' ? asString : value;
885
+ }
886
+ };
887
+ set('userDisplayName', sources.userDisplayName);
888
+ set('tenantTitle', sources.tenantTitle);
889
+ set('applicationTitle', sources.applicationTitle);
890
+ set('locale', sources.locale);
891
+ set('calendarSystem', sources.calendarSystem);
892
+ set('timeZone', sources.timeZone);
893
+ set('country', sources.country);
894
+ set('notes', sources.notes);
895
+ set('currentInstant', now.toISOString());
896
+ set('currentLocalDateTime', formatAxpAiPlatformRuntimeLocalDateTime(now, sources.timeZone));
897
+ return ctx;
528
898
  }
529
899
  //#endregion
530
900
 
@@ -590,352 +960,97 @@ const AXP_FOLLOW_UP_ENVELOPE_JSON_SCHEMA = {
590
960
  maxItems: 5,
591
961
  description: 'Suggestion chips: each item is either a plain string label or { text, command: { name, options? } }.',
592
962
  items: {
593
- oneOf: [
594
- { type: 'string', minLength: 1 },
595
- {
596
- type: 'object',
597
- required: ['text', 'command'],
598
- additionalProperties: false,
599
- properties: {
600
- text: { type: 'string' },
601
- command: {
602
- type: 'object',
603
- required: ['name'],
604
- additionalProperties: true,
605
- properties: {
606
- name: { type: 'string' },
607
- options: { type: 'object', additionalProperties: true },
608
- },
609
- },
610
- },
611
- },
612
- ],
613
- },
614
- },
615
- },
616
- };
617
- //#endregion
618
- //#region ---- Resolve builtin schema ----
619
- /** Built-in JSON Schema for known transcript segments when the contract omits `schema`. */
620
- function resolveBuiltinSchemaForOutputContract(contract) {
621
- if (contract.kind !== 'object') {
622
- return undefined;
623
- }
624
- const segment = resolveOutputTranscriptSegment(contract);
625
- if (segment === 'node') {
626
- return AXP_WIDGET_NODE_JSON_SCHEMA;
627
- }
628
- if (segment === 'followUp') {
629
- return AXP_FOLLOW_UP_ENVELOPE_JSON_SCHEMA;
630
- }
631
- return undefined;
632
- }
633
- //#endregion
634
-
635
- //#region ---- Imports ----
636
- //#endregion
637
- //#region ---- Structured output kinds ----
638
- const STRUCTURED_OUTPUT_KINDS = new Set(['object', 'array']);
639
- function usesStructuredFinalize(kind) {
640
- return STRUCTURED_OUTPUT_KINDS.has(kind);
641
- }
642
- function isJsonSchemaLike(value) {
643
- return value != null && typeof value === 'object' && !Array.isArray(value);
644
- }
645
- //#endregion
646
- //#region ---- Retry defaults ----
647
- /** Default structured retry count for a contract kind when `structuredRetries` is omitted. */
648
- function defaultRetriesForKind(kind) {
649
- if (kind === 'string') {
650
- return 0;
651
- }
652
- return AXPAI_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES;
653
- }
654
- //#endregion
655
- //#region ---- Derive provider format ----
656
- /**
657
- * Maps an effective output contract to a provider request hint.
658
- * Explicit {@link AXPAiAgentOutputContract.providerResponseFormat} wins; otherwise derived from `kind` + `schema`.
659
- */
660
- function deriveProviderResponseFormat(contract) {
661
- if (contract.providerResponseFormat) {
662
- return contract.providerResponseFormat;
663
- }
664
- if (!usesStructuredFinalize(contract.kind)) {
665
- return undefined;
666
- }
667
- const schema = (contract.schema && isJsonSchemaLike(contract.schema) ? contract.schema : undefined) ??
668
- resolveBuiltinSchemaForOutputContract(contract);
669
- if (schema) {
670
- const segment = resolveOutputTranscriptSegment(contract);
671
- const name = contract.schemaName?.trim() ||
672
- (segment === 'node' ? 'widget_layout' : segment === 'followUp' ? 'follow_up' : 'structured_output');
673
- return {
674
- type: 'json_schema',
675
- schema,
676
- name,
677
- strict: contract.schemaStrict === true,
678
- };
679
- }
680
- return { type: 'json_object' };
681
- }
682
- //#endregion
683
-
684
- //#region ---- Imports ----
685
- /**
686
- * Native structured output (AI SDK `output` / provider schema) must not run on tool-calling
687
- * turns — only when tools are absent or explicitly disabled (`toolChoice: 'none'`).
688
- */
689
- function axpAiShouldApplyChatStructuredOutput(params) {
690
- const format = params.responseFormat;
691
- if (!format || format.type === 'text') {
692
- return false;
693
- }
694
- if (!params.hasTools) {
695
- return true;
696
- }
697
- return params.toolChoice === 'none';
698
- }
699
- //#endregion
700
- //#region ---- Duplicate JSON in text ----
701
- function stripJsonFences(raw) {
702
- const fence = raw.match(/```(?:json)?\s*([\s\S]*?)```/i);
703
- return fence ? fence[1].trim() : raw.trim();
704
- }
705
- function axpAiTryParseJsonValueFromAssistantText(text) {
706
- const trimmed = stripJsonFences(text.trim());
707
- if (!trimmed) {
708
- return undefined;
709
- }
710
- if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
711
- return undefined;
712
- }
713
- try {
714
- return JSON.parse(trimmed);
715
- }
716
- catch {
717
- return undefined;
718
- }
719
- }
720
- function isFollowUpEnvelope(value) {
721
- if (value == null || typeof value !== 'object' || Array.isArray(value)) {
722
- return false;
723
- }
724
- const o = value;
725
- return o['type'] === 'followUp' && Array.isArray(o['content']);
726
- }
727
- function isLikelyWidgetRoot(value) {
728
- if (value == null || typeof value !== 'object' || Array.isArray(value)) {
729
- return false;
730
- }
731
- const t = value['type'];
732
- return typeof t === 'string' && t.trim().length > 0 && t !== 'node' && t !== 'followUp';
733
- }
734
- function isNodeEnvelope(value) {
735
- if (value == null || typeof value !== 'object' || Array.isArray(value)) {
736
- return false;
737
- }
738
- const o = value;
739
- return o['type'] === 'node' && o['content'] != null;
740
- }
741
- /** True when assistant `text` duplicates a structured segment already attached as `node` / `followUp`. */
742
- function axpAiTextDuplicatesStructuredSegment(text, segment) {
743
- const parsed = axpAiTryParseJsonValueFromAssistantText(text);
744
- if (parsed === undefined) {
745
- return false;
746
- }
747
- if (segment === 'followUp') {
748
- return isFollowUpEnvelope(parsed);
749
- }
750
- return isLikelyWidgetRoot(parsed) || isNodeEnvelope(parsed);
751
- }
752
- //#endregion
753
-
754
- //#region ---- Imports ----
755
- //#endregion
756
- //#region ---- Supervisor delegated-agent helpers ----
757
- /** Prefix for supervisor-delegated specialist tools (`${AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX}${agentId}`). */
758
- const AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX = 'agent:';
759
- function axpAiSupervisorAgentToolName(agentCatalogId) {
760
- return `${AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX}${agentCatalogId.trim()}`;
761
- }
762
- function axpAiParseSupervisorAgentToolName(toolName) {
763
- const n = toolName.trim();
764
- if (!n.startsWith(AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX)) {
765
- return null;
766
- }
767
- const id = n.slice(AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX.length).trim();
768
- return id.length > 0 ? id : null;
769
- }
770
- //#endregion
771
- //#region ---- Message builders ----
772
- function axpAiChatTextMessage(role, text) {
773
- return {
774
- role,
775
- responses: [{ type: 'text', content: text }],
776
- };
777
- }
778
- function axpAiChatToolResultMessage(callId, content, toolName) {
779
- const id = callId.trim();
780
- return {
781
- role: 'tool',
782
- ...(toolName?.trim() ? { name: toolName.trim() } : {}),
783
- responses: [
784
- {
785
- type: 'tool_result',
786
- callId: id,
787
- content,
788
- },
789
- ],
790
- };
791
- }
792
- //#endregion
793
- //#region ---- Transcript read helpers ----
794
- function axpAiChatMessageGetText(message) {
795
- const parts = [];
796
- for (const r of message.responses) {
797
- if (r.type === 'text') {
798
- parts.push(r.content);
799
- }
800
- else if (r.type === 'node' || r.type === 'followUp') {
801
- try {
802
- parts.push(JSON.stringify({ type: r.type, content: r.content }));
803
- }
804
- catch {
805
- parts.push(`[${r.type}]`);
806
- }
807
- }
808
- }
809
- return parts.join('\n\n');
810
- }
963
+ oneOf: [
964
+ { type: 'string', minLength: 1 },
965
+ {
966
+ type: 'object',
967
+ required: ['text', 'command'],
968
+ additionalProperties: false,
969
+ properties: {
970
+ text: { type: 'string' },
971
+ command: {
972
+ type: 'object',
973
+ required: ['name'],
974
+ additionalProperties: true,
975
+ properties: {
976
+ name: { type: 'string' },
977
+ options: { type: 'object', additionalProperties: true },
978
+ },
979
+ },
980
+ },
981
+ },
982
+ ],
983
+ },
984
+ },
985
+ },
986
+ };
811
987
  //#endregion
812
- //#region ---- Tool result normalization ----
813
- function axpAiNormalizeHandlerResultToToolBody(handlerResult) {
814
- if (handlerResult === undefined || handlerResult === null) {
815
- return { success: false, error: 'Tool returned no result.' };
988
+ //#region ---- Resolve builtin schema ----
989
+ /** Built-in JSON Schema for known transcript segments when the contract omits `schema`. */
990
+ function resolveBuiltinSchemaForOutputContract(contract) {
991
+ if (contract.kind !== 'object') {
992
+ return undefined;
816
993
  }
817
- if (typeof handlerResult === 'string') {
818
- const t = handlerResult.trim();
819
- if (!t) {
820
- return { success: false, error: 'Tool returned an empty string.' };
821
- }
822
- try {
823
- return JSON.parse(t);
824
- }
825
- catch {
826
- return { success: true, kind: 'object', data: handlerResult };
827
- }
994
+ const segment = resolveOutputTranscriptSegment(contract);
995
+ if (segment === 'node') {
996
+ return AXP_WIDGET_NODE_JSON_SCHEMA;
828
997
  }
829
- if (typeof handlerResult === 'object' && !Array.isArray(handlerResult)) {
830
- return handlerResult;
998
+ if (segment === 'followUp') {
999
+ return AXP_FOLLOW_UP_ENVELOPE_JSON_SCHEMA;
831
1000
  }
832
- return { success: true, kind: 'object', data: handlerResult };
1001
+ return undefined;
833
1002
  }
834
1003
  //#endregion
835
1004
 
836
1005
  //#region ---- Imports ----
837
1006
  //#endregion
838
-
839
- //#region ----- Types -----
840
- //#endregion
841
- //#region ----- Constants -----
842
- const IMAGE_MIME_TYPES = new Set([
843
- 'image/jpeg',
844
- 'image/png',
845
- 'image/webp',
846
- 'image/gif',
847
- 'image/bmp',
848
- 'image/tiff',
849
- ]);
850
- const IMAGE_EXTENSION_PATTERN = /\.(png|jpe?g|gif|webp|bmp|tif|tiff)$/i;
851
- const TEXT_MIME_TYPES = new Set([
852
- 'text/plain',
853
- 'text/markdown',
854
- 'text/csv',
855
- 'application/json',
856
- ]);
857
- const TEXT_EXTENSION_PATTERN = /\.(txt|md|csv|json)$/i;
858
- const PDF_MIME = 'application/pdf';
859
- const PDF_EXTENSION_PATTERN = /\.pdf$/i;
860
- //#endregion
861
- //#region ----- Helpers -----
862
- function normalizeMime(mimeType) {
863
- return typeof mimeType === 'string' ? mimeType.trim().toLowerCase() : '';
1007
+ //#region ---- Structured output kinds ----
1008
+ const STRUCTURED_OUTPUT_KINDS = new Set(['object', 'array']);
1009
+ function usesStructuredFinalize(kind) {
1010
+ return STRUCTURED_OUTPUT_KINDS.has(kind);
864
1011
  }
865
- function isTextMime(mime) {
866
- if (TEXT_MIME_TYPES.has(mime)) {
867
- return true;
868
- }
869
- return mime.startsWith('text/');
1012
+ function isJsonSchemaLike(value) {
1013
+ return value != null && typeof value === 'object' && !Array.isArray(value);
870
1014
  }
871
- function classifyByFilename(filename) {
872
- const name = typeof filename === 'string' ? filename.trim() : '';
873
- if (!name) {
874
- return 'unsupported';
875
- }
876
- if (IMAGE_EXTENSION_PATTERN.test(name)) {
877
- return 'image';
878
- }
879
- if (PDF_EXTENSION_PATTERN.test(name)) {
880
- return 'pdf';
881
- }
882
- if (TEXT_EXTENSION_PATTERN.test(name)) {
883
- return 'text';
1015
+ //#endregion
1016
+ //#region ---- Retry defaults ----
1017
+ /** Default structured retry count for a contract kind when `structuredRetries` is omitted. */
1018
+ function defaultRetriesForKind(kind) {
1019
+ if (kind === 'string') {
1020
+ return 0;
884
1021
  }
885
- return 'unsupported';
1022
+ return AXPAI_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES;
886
1023
  }
887
1024
  //#endregion
888
- //#region ----- Classification -----
1025
+ //#region ---- Derive provider format ----
889
1026
  /**
890
- * Classifies a document for AI text extraction (image OCR, PDF file part, or UTF-8 text).
891
- * Does not include Office formats.
1027
+ * Maps an effective output contract to a provider request hint.
1028
+ * Explicit {@link AXPAiAgentOutputContract.providerResponseFormat} wins; otherwise derived from `kind` + `schema`.
892
1029
  */
893
- function classifyAiExtractDocument(mimeType, filename) {
894
- const mime = normalizeMime(mimeType);
895
- if (mime && mime !== 'application/octet-stream') {
896
- if (mime.startsWith('image/') || IMAGE_MIME_TYPES.has(mime)) {
897
- return 'image';
898
- }
899
- if (mime === PDF_MIME) {
900
- return 'pdf';
901
- }
902
- if (isTextMime(mime)) {
903
- return 'text';
904
- }
1030
+ function deriveProviderResponseFormat(contract) {
1031
+ if (contract.providerResponseFormat) {
1032
+ return contract.providerResponseFormat;
905
1033
  }
906
- return classifyByFilename(filename);
907
- }
908
- function canAiExtractDocument(mimeType, filename) {
909
- return classifyAiExtractDocument(mimeType, filename) !== 'unsupported';
1034
+ if (!usesStructuredFinalize(contract.kind)) {
1035
+ return undefined;
1036
+ }
1037
+ const schema = (contract.schema && isJsonSchemaLike(contract.schema) ? contract.schema : undefined) ??
1038
+ resolveBuiltinSchemaForOutputContract(contract);
1039
+ if (schema) {
1040
+ const segment = resolveOutputTranscriptSegment(contract);
1041
+ const name = contract.schemaName?.trim() ||
1042
+ (segment === 'node' ? 'widget_layout' : segment === 'followUp' ? 'follow_up' : 'structured_output');
1043
+ return {
1044
+ type: 'json_schema',
1045
+ schema,
1046
+ name,
1047
+ strict: contract.schemaStrict === true,
1048
+ };
1049
+ }
1050
+ return { type: 'json_object' };
910
1051
  }
911
1052
  //#endregion
912
1053
 
913
- //#region ---- Imports ----
914
- //#endregion
915
-
916
- //#region ---- AI chat registry command keys ----
917
- const AIMANAGEMENT_CHAT_GENERATE_IMAGE_COMMAND_KEY = 'AiManagement:ChatGenerateImage';
918
- const AIMANAGEMENT_CHAT_TRANSCRIBE_SPEECH_COMMAND_KEY = 'AiManagement:ChatTranscribeSpeech';
919
- const AIMANAGEMENT_CHAT_SYNTHESIZE_SPEECH_COMMAND_KEY = 'AiManagement:ChatSynthesizeSpeech';
920
- const AIMANAGEMENT_EXTRACT_DOCUMENT_TEXT_COMMAND_KEY = 'AiManagement:ExtractDocumentText';
921
- const AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY = 'AiManagement:StructuredTextCompletion';
922
- //#endregion
923
-
924
- //#region ---- AI engine runtime transport keys ----
925
- const AXMAiManagementTransportKeys = {
926
- Engine: {
927
- Run: 'AiManagement:Engine:Run',
928
- SubmitToolResult: 'AiManagement:Engine:SubmitToolResult',
929
- },
930
- ConversationAssist: {
931
- Subscribe: 'ConversationManagement:Assist:Subscribe',
932
- AssistSync: 'ConversationManagement:Assist:AssistSync',
933
- RetryAssist: 'ConversationManagement:Assist:RetryAssist',
934
- CancelAssist: 'ConversationManagement:Assist:CancelAssist',
935
- },
936
- };
937
- //#endregion
938
-
939
1054
  //#region ---- Model catalog helpers ----
940
1055
  function readModelPurposes(row) {
941
1056
  if (!row) {
@@ -975,66 +1090,23 @@ function parseChatTransport(raw) {
975
1090
 
976
1091
  //#region ---- Imports ----
977
1092
  //#endregion
978
- //#region ---- Transcript helpers ----
979
- function axpAiChatMessagesFromProviderAssistant(text, toolCalls) {
980
- const normalized = (text ?? '')
981
- .replace(/&lt;(\/?redacted_thinking)&gt;/gi, '<$1>')
982
- .replace(/&lt;(\/?think)&gt;/gi, '<$1>');
983
- const responses = [];
984
- const thinkRe = /<(redacted_thinking|think)>([\s\S]*?)<\/\1>/gi;
985
- let last = 0;
986
- let m;
987
- while ((m = thinkRe.exec(normalized)) !== null) {
988
- const plain = normalized.slice(last, m.index).trim();
989
- if (plain.length > 0) {
990
- responses.push({ type: 'text', content: plain });
991
- }
992
- const think = (m[2] ?? '').trim();
993
- if (think.length > 0) {
994
- responses.push({ type: 'think', content: think });
995
- }
996
- last = m.index + m[0].length;
997
- }
998
- const tail = normalized.slice(last).trim();
999
- if (tail.length > 0) {
1000
- responses.push({ type: 'text', content: tail });
1001
- }
1002
- const out = [];
1003
- if (responses.length > 0) {
1004
- out.push({ role: 'assistant', responses });
1005
- }
1006
- for (const tc of toolCalls ?? []) {
1007
- const isDelegatedAgent = axpAiParseSupervisorAgentToolName(tc.name) != null;
1008
- out.push({
1009
- role: 'assistant',
1010
- responses: [
1011
- isDelegatedAgent
1012
- ? {
1013
- type: 'agent',
1014
- content: { command: tc.name, arguments: tc.arguments },
1015
- callId: tc.id,
1016
- ...(tc.metadata ? { metadata: { ...tc.metadata } } : {}),
1017
- }
1018
- : {
1019
- type: 'tool',
1020
- content: { command: tc.name, arguments: tc.arguments },
1021
- callId: tc.id,
1022
- ...(tc.metadata ? { metadata: { ...tc.metadata } } : {}),
1023
- },
1024
- ],
1025
- });
1026
- }
1027
- return out;
1028
- }
1029
- function axcResolveAiMlOrPlainString(value, locale = 'en-US') {
1030
- if (value == null) {
1031
- return '';
1032
- }
1033
- if (typeof value === 'string') {
1034
- return value.trim();
1035
- }
1036
- return resolveMultiLanguageString(value, locale).trim();
1037
- }
1093
+
1094
+ //#region ---- AI engine runtime transport keys ----
1095
+ const AXMAiManagementTransportKeys = {
1096
+ Engine: {
1097
+ Run: 'AiManagement:Engine:Run',
1098
+ SubmitToolResult: 'AiManagement:Engine:SubmitToolResult',
1099
+ },
1100
+ ConversationAssist: {
1101
+ Subscribe: 'ConversationManagement:Assist:Subscribe',
1102
+ AssistSync: 'ConversationManagement:Assist:AssistSync',
1103
+ RetryAssist: 'ConversationManagement:Assist:RetryAssist',
1104
+ CancelAssist: 'ConversationManagement:Assist:CancelAssist',
1105
+ },
1106
+ };
1107
+ //#endregion
1108
+
1109
+ //#region ---- Imports ----
1038
1110
  //#endregion
1039
1111
 
1040
1112
  //#region ---- Contracts barrel ----
@@ -1043,5 +1115,5 @@ function axcResolveAiMlOrPlainString(value, locale = 'en-US') {
1043
1115
  * Generated bundle index. Do not edit.
1044
1116
  */
1045
1117
 
1046
- export { AIMANAGEMENT_CHAT_GENERATE_IMAGE_COMMAND_KEY, AIMANAGEMENT_CHAT_SYNTHESIZE_SPEECH_COMMAND_KEY, AIMANAGEMENT_CHAT_TRANSCRIBE_SPEECH_COMMAND_KEY, AIMANAGEMENT_EXTRACT_DOCUMENT_TEXT_COMMAND_KEY, AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, AXMAiAssistPermissionKeys, AXMAiManagementTransportKeys, AXMPermissionsKeys, AXM_AI_PLATFORM_RUNTIME_CONTEXT_DEFINITIONS, AXPAI_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES, AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX, AXPAdministrationPermissionKeys, AXPAiManagementFeatureKeys, AXPAiManagementMenuKeys, AXPAiManagementSettings, AXP_AI_SDK_TOOL_CONTEXT_JSON_SCHEMA, AXP_FOLLOW_UP_ENVELOPE_JSON_SCHEMA, AXP_WIDGET_NODE_JSON_SCHEMA, RootConfig, assembleAxpAiPlatformRuntimeContext, attachAxpAiSdkChatContext, axcResolveAiMlOrPlainString, axpAiAgentOutputContractOmitsRoleBaseline, axpAiAgentOutputContractStructuredRetryCap, axpAiAgentOutputContractUsesStructuredFinalize, axpAiChatMessageGetText, axpAiChatMessagesFromProviderAssistant, axpAiChatTextMessage, axpAiChatToolResultMessage, axpAiNormalizeHandlerResultToToolBody, axpAiParseSupervisorAgentToolName, axpAiShouldApplyChatStructuredOutput, axpAiSupervisorAgentToolName, axpAiTextDuplicatesStructuredSegment, axpAiTryParseJsonValueFromAssistantText, buildAxpAiSdkChatContextBundle, canAiExtractDocument, classifyAiExtractDocument, defaultRetriesForKind, deriveProviderResponseFormat, formatAxpAiPlatformRuntimeLocalDateTime, formatAxpAiPlatformRuntimePrompt, isChatPurposeModelRow, modelRowHasPurpose, parseAgentOutputContract, parseChatTransport, parseJsonSchemaLike, parseResponseFormat, readModelPurposes, resolveAgentOutputContract, resolveBuiltinSchemaForOutputContract, resolveEffectiveOutputContract, resolveOutputTranscriptSegment };
1118
+ export { AIMANAGEMENT_CHAT_GENERATE_IMAGE_COMMAND_KEY, AIMANAGEMENT_CHAT_SYNTHESIZE_SPEECH_COMMAND_KEY, AIMANAGEMENT_CHAT_TRANSCRIBE_SPEECH_COMMAND_KEY, AIMANAGEMENT_EXTRACT_DOCUMENT_TEXT_COMMAND_KEY, AIMANAGEMENT_RENDER_CHAT_CHART_COMMAND_KEY, AIMANAGEMENT_STRUCTURED_TEXT_COMPLETION_COMMAND_KEY, AXMAiAssistPermissionKeys, AXMAiManagementTransportKeys, AXMPermissionsKeys, AXM_AI_PLATFORM_RUNTIME_CONTEXT_DEFINITIONS, AXPAI_AGENT_OUTPUT_CONTRACT_DEFAULT_STRUCTURED_RETRIES, AXPAI_SUPERVISOR_AGENT_TOOL_PREFIX, AXPAdministrationPermissionKeys, AXPAiManagementFeatureKeys, AXPAiManagementMenuKeys, AXPAiManagementSettings, AXP_AI_SDK_TOOL_CONTEXT_JSON_SCHEMA, AXP_FOLLOW_UP_ENVELOPE_JSON_SCHEMA, AXP_WIDGET_NODE_JSON_SCHEMA, AiManagementManifest, RootConfig, assembleAxpAiPlatformRuntimeContext, attachAxpAiSdkChatContext, axcResolveAiMlOrPlainString, axpAiAgentOutputContractOmitsRoleBaseline, axpAiAgentOutputContractStructuredRetryCap, axpAiAgentOutputContractUsesStructuredFinalize, axpAiChatMessageGetText, axpAiChatMessagesFromProviderAssistant, axpAiChatTextMessage, axpAiChatToolResultMessage, axpAiExtractChatWidgetNodeFromUnknown, axpAiNormalizeHandlerResultToToolBody, axpAiParseSupervisorAgentToolName, axpAiShouldApplyChatStructuredOutput, axpAiSupervisorAgentToolName, axpAiTextDuplicatesStructuredSegment, axpAiTryParseJsonValueFromAssistantText, buildAxpAiSdkChatContextBundle, canAiExtractDocument, classifyAiExtractDocument, defaultRetriesForKind, deriveProviderResponseFormat, estimateAiRunCostUsd, formatAxpAiPlatformRuntimeLocalDateTime, formatAxpAiPlatformRuntimePrompt, isChatPurposeModelRow, modelRowHasPurpose, parseAgentOutputContract, parseChatTransport, parseJsonSchemaLike, parseResponseFormat, readModelPurposes, resolveAgentOutputContract, resolveBuiltinSchemaForOutputContract, resolveEffectiveOutputContract, resolveOutputTranscriptSegment };
1047
1119
  //# sourceMappingURL=acorex-platform-module-ai-management-client-contracts.mjs.map