@c8y/ngx-components 1024.20.1 → 1024.21.3
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/fesm2022/c8y-ngx-components-ai-agent-chat.mjs +527 -12
- package/fesm2022/c8y-ngx-components-ai-agent-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs +31 -9
- package/fesm2022/c8y-ngx-components-ai-ai-chat.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ai.mjs +503 -62
- package/fesm2022/c8y-ngx-components-ai.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs +2 -2
- package/fesm2022/c8y-ngx-components-alarm-event-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-alarms.mjs +3 -3
- package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-application-access-list.mjs +1 -1
- package/fesm2022/c8y-ngx-components-application-access-list.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-application-select.mjs +1 -1
- package/fesm2022/c8y-ngx-components-application-select.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-asset-properties.mjs +3 -2
- package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-auth-configuration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-auth-configuration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-bookmarks.mjs +1 -1
- package/fesm2022/c8y-ngx-components-bookmarks.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs +1 -1
- package/fesm2022/c8y-ngx-components-branding-shared-lazy.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-cockpit-config.mjs +5 -5
- package/fesm2022/c8y-ngx-components-cockpit-config.mjs.map +1 -1
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-version-history.component-Jyjkv4JT.mjs → c8y-ngx-components-context-dashboard-dashboard-version-history.component-CP1afwVe.mjs} +2 -2
- package/fesm2022/{c8y-ngx-components-context-dashboard-dashboard-version-history.component-Jyjkv4JT.mjs.map → c8y-ngx-components-context-dashboard-dashboard-version-history.component-CP1afwVe.mjs.map} +1 -1
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs +81 -20
- package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
- package/fesm2022/{c8y-ngx-components-dashboard-details-advanced-tab-dashboard-details-advanced-tab.component-UEUYsXBv.mjs → c8y-ngx-components-dashboard-details-advanced-tab-dashboard-details-advanced-tab.component-CRvgIgri.mjs} +2 -2
- package/fesm2022/{c8y-ngx-components-dashboard-details-advanced-tab-dashboard-details-advanced-tab.component-UEUYsXBv.mjs.map → c8y-ngx-components-dashboard-details-advanced-tab-dashboard-details-advanced-tab.component-CRvgIgri.mjs.map} +1 -1
- package/fesm2022/c8y-ngx-components-dashboard-details-advanced-tab.mjs +2 -2
- package/fesm2022/c8y-ngx-components-dashboard-manager.mjs +1 -1
- package/fesm2022/c8y-ngx-components-dashboard-manager.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +3 -3
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +2 -2
- package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-device-profile.mjs +2 -2
- package/fesm2022/c8y-ngx-components-device-profile.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-diagnostics.mjs +1 -1
- package/fesm2022/c8y-ngx-components-diagnostics.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart.mjs +146 -126
- package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs +2 -2
- package/fesm2022/c8y-ngx-components-ecosystem-application-plugins.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-ecosystem.mjs +4 -4
- package/fesm2022/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-events-events-timeline.mjs +1 -1
- package/fesm2022/c8y-ngx-components-events-events-timeline.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-events.mjs +2 -2
- package/fesm2022/c8y-ngx-components-events.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-icon-selector.mjs +4 -4
- package/fesm2022/c8y-ngx-components-icon-selector.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-bulk-operation-list-item.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-bulk-operation-list-item.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-operations-list.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-operations-list.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-operations-timeline.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-configuration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs +2 -2
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-device-profile.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-firmware.mjs +2 -2
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-firmware.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs +2 -2
- package/fesm2022/c8y-ngx-components-operations-stepper-bulk-type-software.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs +5 -5
- package/fesm2022/c8y-ngx-components-protocol-lpwan.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +1 -1
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-register-device.mjs +3 -3
- package/fesm2022/c8y-ngx-components-register-device.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs +1 -1
- package/fesm2022/c8y-ngx-components-remote-access-configurations.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-replace-device-replace-device-wizard.mjs +1 -1
- package/fesm2022/c8y-ngx-components-replace-device-replace-device-wizard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-report-dashboard.mjs +1 -1
- package/fesm2022/c8y-ngx-components-report-dashboard.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-configuration.mjs +4 -4
- package/fesm2022/c8y-ngx-components-repository-configuration.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-firmware.mjs +4 -4
- package/fesm2022/c8y-ngx-components-repository-firmware.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-shared.mjs +2 -2
- package/fesm2022/c8y-ngx-components-repository-shared.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-repository-software.mjs +3 -3
- package/fesm2022/c8y-ngx-components-repository-software.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs +1 -1
- package/fesm2022/c8y-ngx-components-static-assets-modal.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-tracking.mjs +1 -1
- package/fesm2022/c8y-ngx-components-tracking.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +1 -1
- package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +17 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs +21 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-scada.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +60 -31
- package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +2 -2
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs +2 -2
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-image.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +500 -38
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/de.po +72 -0
- package/locales/es.po +72 -0
- package/locales/fr.po +72 -0
- package/locales/ja_JP.po +72 -0
- package/locales/ko.po +72 -0
- package/locales/locales.pot +72 -3
- package/locales/nl.po +72 -0
- package/locales/pl.po +73 -1
- package/locales/pt_BR.po +74 -2
- package/locales/zh_CN.po +72 -0
- package/locales/zh_TW.po +72 -0
- package/package.json +1 -1
- package/types/c8y-ngx-components-ai-agent-chat.d.ts +201 -3
- package/types/c8y-ngx-components-ai-agent-chat.d.ts.map +1 -1
- package/types/c8y-ngx-components-ai-ai-chat.d.ts +14 -4
- package/types/c8y-ngx-components-ai-ai-chat.d.ts.map +1 -1
- package/types/c8y-ngx-components-ai.d.ts +157 -2
- package/types/c8y-ngx-components-ai.d.ts.map +1 -1
- package/types/c8y-ngx-components-asset-properties.d.ts.map +1 -1
- package/types/c8y-ngx-components-context-dashboard.d.ts +37 -3
- package/types/c8y-ngx-components-context-dashboard.d.ts.map +1 -1
- package/types/c8y-ngx-components-echart.d.ts +6 -0
- package/types/c8y-ngx-components-echart.d.ts.map +1 -1
- package/types/c8y-ngx-components-widgets-implementations-asset-table.d.ts +5 -0
- package/types/c8y-ngx-components-widgets-implementations-asset-table.d.ts.map +1 -1
- package/types/c8y-ngx-components.d.ts +310 -12
- package/types/c8y-ngx-components.d.ts.map +1 -1
|
@@ -5,6 +5,143 @@ import { FetchClient } from '@c8y/client';
|
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
import { gettext } from '@c8y/ngx-components/gettext';
|
|
7
7
|
|
|
8
|
+
function convertToolOutputToAgentFormat(tool) {
|
|
9
|
+
const { output, outputType, error } = tool;
|
|
10
|
+
// Content arrays need outputType="content" for roundtripping (set by convertStreamingToolOutputToToolCallPart)
|
|
11
|
+
if (outputType === 'content' && Array.isArray(output)) {
|
|
12
|
+
return { type: 'content', value: output };
|
|
13
|
+
}
|
|
14
|
+
if (error) {
|
|
15
|
+
return typeof output === 'string'
|
|
16
|
+
? { type: 'error-text', value: output }
|
|
17
|
+
: { type: 'error-json', value: output ?? null };
|
|
18
|
+
}
|
|
19
|
+
if (typeof output === 'string') {
|
|
20
|
+
return { type: 'text', value: output };
|
|
21
|
+
}
|
|
22
|
+
if (output == null) {
|
|
23
|
+
return { type: 'text', value: '' };
|
|
24
|
+
}
|
|
25
|
+
return { type: 'json', value: output };
|
|
26
|
+
}
|
|
27
|
+
/** Builds the `tool-call` content part for a tool call or a tool call awaiting/holding an approval decision. */
|
|
28
|
+
function toToolCallContent(part) {
|
|
29
|
+
return {
|
|
30
|
+
type: 'tool-call',
|
|
31
|
+
toolCallId: part.toolCallId,
|
|
32
|
+
toolName: part.toolName,
|
|
33
|
+
input: part.input ?? {} // must be a dict
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resolves the outcome to record beside a decided tool-approval exchange: the refusal itself when
|
|
38
|
+
* the user said no, or the result of the call it authorised. Returns `undefined` when the call was
|
|
39
|
+
* approved but has not produced a result yet.
|
|
40
|
+
*
|
|
41
|
+
* @param part The approval part; `part.approval.approved` must already be defined.
|
|
42
|
+
* @param resultsByToolCallId Completed tool results indexed by call id. The result of an approved
|
|
43
|
+
* call usually streams in with a later message, but may also live on `part` itself already, when
|
|
44
|
+
* the conversation being converted was itself restored from storage.
|
|
45
|
+
* @param convertOutput Converts a completed tool call's recorded output into the wire format.
|
|
46
|
+
*/
|
|
47
|
+
function resolveApprovalOutcome(part, resultsByToolCallId, convertOutput) {
|
|
48
|
+
if (!part.approval?.approved) {
|
|
49
|
+
return {
|
|
50
|
+
type: 'tool-result',
|
|
51
|
+
toolCallId: part.toolCallId,
|
|
52
|
+
toolName: part.toolName,
|
|
53
|
+
output: {
|
|
54
|
+
type: 'execution-denied',
|
|
55
|
+
...(part.approval?.reason ? { reason: part.approval.reason } : {})
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const result = resultsByToolCallId.get(part.toolCallId) ?? (part.output !== undefined ? part : undefined);
|
|
60
|
+
// No result anywhere means the call was approved but has not run yet.
|
|
61
|
+
return result
|
|
62
|
+
? {
|
|
63
|
+
type: 'tool-result',
|
|
64
|
+
toolCallId: part.toolCallId,
|
|
65
|
+
toolName: part.toolName,
|
|
66
|
+
output: convertOutput(result)
|
|
67
|
+
}
|
|
68
|
+
: undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Splits an assistant message's content into per-step groups at `step-start` boundaries.
|
|
72
|
+
* Parts before the first `step-start` are placed in an implicit first step, and empty groups
|
|
73
|
+
* (from leading, consecutive or trailing `step-start` parts) are dropped.
|
|
74
|
+
*
|
|
75
|
+
* Each step has to become its own message in the wire format, which has no `step-start` part:
|
|
76
|
+
* this ensures text from a later step is never placed after tool calls from an earlier step,
|
|
77
|
+
* which some AI providers forbid.
|
|
78
|
+
*/
|
|
79
|
+
function splitIntoSteps(content) {
|
|
80
|
+
const steps = [[]];
|
|
81
|
+
for (const part of content) {
|
|
82
|
+
if (part.type === 'step-start') {
|
|
83
|
+
if (steps[steps.length - 1].length > 0)
|
|
84
|
+
steps.push([]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
steps[steps.length - 1].push(part);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (steps[steps.length - 1].length === 0)
|
|
91
|
+
steps.pop();
|
|
92
|
+
return steps;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Converts from our UI-friendly message format back to the format the API requires when
|
|
96
|
+
* sending message history back to the agent manager service.
|
|
97
|
+
*
|
|
98
|
+
* Currently the format is Vercel v6 ModelMessage (so this is a little similar to Vercel's convertToModelMessages).
|
|
99
|
+
*
|
|
100
|
+
* We do not bother with details such as reasoning (not worth the tokens) or in-progress tool calls
|
|
101
|
+
* (since this method is only used on completed responses).
|
|
102
|
+
*/
|
|
103
|
+
function convertToAgentMessageFormat(messages) {
|
|
104
|
+
return messages.flatMap(message => {
|
|
105
|
+
if (message.role === 'user' || message.role === 'system') {
|
|
106
|
+
return [{ role: message.role, content: message.content }];
|
|
107
|
+
}
|
|
108
|
+
// Each step maps to its own assistant message + optional tool message.
|
|
109
|
+
const steps = splitIntoSteps(message.content);
|
|
110
|
+
const stepMessages = [];
|
|
111
|
+
for (const stepParts of steps) {
|
|
112
|
+
const stepAssistantContent = [];
|
|
113
|
+
const stepToolResultContent = [];
|
|
114
|
+
for (const part of stepParts) {
|
|
115
|
+
if (part.type === 'text' && part.text) {
|
|
116
|
+
stepAssistantContent.push({ type: 'text', text: part.text });
|
|
117
|
+
}
|
|
118
|
+
else if (part.type === 'tool-result') {
|
|
119
|
+
stepAssistantContent.push({
|
|
120
|
+
type: 'tool-call',
|
|
121
|
+
toolCallId: part.toolCallId,
|
|
122
|
+
toolName: part.toolName,
|
|
123
|
+
input: !part.input ? {} : part.input // must be a dict
|
|
124
|
+
});
|
|
125
|
+
stepToolResultContent.push({
|
|
126
|
+
type: 'tool-result',
|
|
127
|
+
toolCallId: part.toolCallId,
|
|
128
|
+
toolName: part.toolName,
|
|
129
|
+
output: convertToolOutputToAgentFormat(part)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// Reasoning, tool-input-streaming and tool-executing (in-progress calls) are intentionally skipped
|
|
133
|
+
}
|
|
134
|
+
if (stepAssistantContent.length > 0) {
|
|
135
|
+
stepMessages.push({ role: 'assistant', content: stepAssistantContent });
|
|
136
|
+
}
|
|
137
|
+
if (stepToolResultContent.length > 0) {
|
|
138
|
+
stepMessages.push({ role: 'tool', content: stepToolResultContent });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return stepMessages;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
8
145
|
// Internal implementation detail; maybe we don't even need this enum since
|
|
9
146
|
var DataStreamType;
|
|
10
147
|
(function (DataStreamType) {
|
|
@@ -305,7 +442,10 @@ class AIService {
|
|
|
305
442
|
if (m.role !== 'assistant')
|
|
306
443
|
continue;
|
|
307
444
|
for (const part of m.content) {
|
|
308
|
-
|
|
445
|
+
// A conversation restored from storage carries the result on the approval part itself,
|
|
446
|
+
// rather than in the following message where it originally streamed in.
|
|
447
|
+
if (part.type === 'tool-result' ||
|
|
448
|
+
(part.type === 'tool-approval-responded' && part.output !== undefined)) {
|
|
309
449
|
resultsByToolCallId.set(part.toolCallId, part);
|
|
310
450
|
}
|
|
311
451
|
}
|
|
@@ -373,12 +513,7 @@ class AIService {
|
|
|
373
513
|
case 'tool-approval-responded':
|
|
374
514
|
if (!part.approval)
|
|
375
515
|
break;
|
|
376
|
-
assistantContent.push(
|
|
377
|
-
type: 'tool-call',
|
|
378
|
-
toolCallId: part.toolCallId,
|
|
379
|
-
toolName: part.toolName,
|
|
380
|
-
input: part.input ?? {}
|
|
381
|
-
});
|
|
516
|
+
assistantContent.push(toToolCallContent(part));
|
|
382
517
|
assistantContent.push({
|
|
383
518
|
type: 'tool-approval-request',
|
|
384
519
|
approvalId: part.approval.approvalId,
|
|
@@ -392,32 +527,13 @@ class AIService {
|
|
|
392
527
|
...(part.approval.reason ? { reason: part.approval.reason } : {})
|
|
393
528
|
});
|
|
394
529
|
if (!serializedToolCallIds.has(part.toolCallId)) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
output: {
|
|
401
|
-
type: 'execution-denied',
|
|
402
|
-
...(part.approval.reason ? { reason: part.approval.reason } : {})
|
|
403
|
-
}
|
|
404
|
-
});
|
|
530
|
+
// No outcome means the call was approved but has not run yet: this approval is the
|
|
531
|
+
// one triggering the resume, and the agent executes the tool itself.
|
|
532
|
+
const outcome = resolveApprovalOutcome(part, resultsByToolCallId, result => this.convertToolResultOutputForAgent(result));
|
|
533
|
+
if (outcome) {
|
|
534
|
+
toolContent.push(outcome);
|
|
405
535
|
serializedToolCallIds.add(part.toolCallId);
|
|
406
536
|
}
|
|
407
|
-
else {
|
|
408
|
-
const result = resultsByToolCallId.get(part.toolCallId);
|
|
409
|
-
if (result) {
|
|
410
|
-
toolContent.push({
|
|
411
|
-
type: 'tool-result',
|
|
412
|
-
toolCallId: part.toolCallId,
|
|
413
|
-
toolName: part.toolName,
|
|
414
|
-
output: this.convertToolResultOutputForAgent(result)
|
|
415
|
-
});
|
|
416
|
-
serializedToolCallIds.add(part.toolCallId);
|
|
417
|
-
}
|
|
418
|
-
// No result yet: this approval is the one triggering the resume,
|
|
419
|
-
// and the agent executes the tool itself.
|
|
420
|
-
}
|
|
421
537
|
}
|
|
422
538
|
}
|
|
423
539
|
break;
|
|
@@ -425,12 +541,7 @@ class AIService {
|
|
|
425
541
|
// Skip results already serialized next to their approval exchange in an earlier message
|
|
426
542
|
if (serializedToolCallIds.has(part.toolCallId))
|
|
427
543
|
break;
|
|
428
|
-
assistantContent.push(
|
|
429
|
-
type: 'tool-call',
|
|
430
|
-
toolCallId: part.toolCallId,
|
|
431
|
-
toolName: part.toolName,
|
|
432
|
-
input: part.input ?? {}
|
|
433
|
-
});
|
|
544
|
+
assistantContent.push(toToolCallContent(part));
|
|
434
545
|
toolContent.push({
|
|
435
546
|
type: 'tool-result',
|
|
436
547
|
toolCallId: part.toolCallId,
|
|
@@ -666,22 +777,10 @@ function defaultPruneMessagesForAgent(messages) {
|
|
|
666
777
|
// Tool calls that went through an approval exchange must keep their results as well:
|
|
667
778
|
// the wire format pairs each resolved approval with its result, so pruning the result
|
|
668
779
|
// would leave the approved tool call dangling in the prompt sent to the model.
|
|
669
|
-
const approvalToolCallIds =
|
|
670
|
-
for (const m of messages) {
|
|
671
|
-
if (m.role !== 'assistant')
|
|
672
|
-
continue;
|
|
673
|
-
for (const part of m.content) {
|
|
674
|
-
if (part.type === 'tool-approval-requested' || part.type === 'tool-approval-responded') {
|
|
675
|
-
approvalToolCallIds.add(part.toolCallId);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
780
|
+
const approvalToolCallIds = collectApprovalToolCallIds(messages);
|
|
679
781
|
return messages.map(m => {
|
|
680
782
|
if (m.role !== 'assistant') {
|
|
681
|
-
return {
|
|
682
|
-
role: m.role,
|
|
683
|
-
content: m.content
|
|
684
|
-
};
|
|
783
|
+
return { role: m.role, content: m.content };
|
|
685
784
|
}
|
|
686
785
|
const textParts = m.content.filter((part) => part.type === 'text');
|
|
687
786
|
const objectParts = m.content.filter((part) => part.type === 'object');
|
|
@@ -691,22 +790,364 @@ function defaultPruneMessagesForAgent(messages) {
|
|
|
691
790
|
part.type === 'tool-approval-responded' ||
|
|
692
791
|
(part.type === 'tool-result' && approvalToolCallIds.has(part.toolCallId)));
|
|
693
792
|
const content = [];
|
|
694
|
-
// Only add text part if there are text parts
|
|
695
793
|
if (textParts.length > 0) {
|
|
696
|
-
content.push({
|
|
697
|
-
type: 'text',
|
|
698
|
-
text: textParts.map(part => part.text).join('\n\n')
|
|
699
|
-
});
|
|
794
|
+
content.push({ type: 'text', text: textParts.map(part => part.text).join('\n\n') });
|
|
700
795
|
}
|
|
701
|
-
// Preserve object parts for object agents
|
|
702
796
|
content.push(...objectParts);
|
|
703
797
|
content.push(...approvalParts);
|
|
704
|
-
return {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
798
|
+
return { role: m.role, content };
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* The default implementation for preparing messages for conversation persistence.
|
|
803
|
+
*
|
|
804
|
+
* Unlike `defaultPruneMessagesForAgent` (which strips tool calls for token efficiency),
|
|
805
|
+
* this preserves tool call history so stored conversations can be fully restored in the UI.
|
|
806
|
+
*
|
|
807
|
+
* Strips only transient streaming states that should never be persisted:
|
|
808
|
+
* reasoning blocks, in-progress tool-input-streaming, and tool-executing parts.
|
|
809
|
+
*
|
|
810
|
+
* Tool outputs longer than 10,000 characters are truncated, as the storage service rejects
|
|
811
|
+
* conversations of about 1 MB and above. `defaultPruneMessagesForAgent` never sends these outputs
|
|
812
|
+
* back to the agent, so the truncation only shows in the UI once the conversation is reopened.
|
|
813
|
+
* The results of tool calls that went through an approval are the exception: the agent does get
|
|
814
|
+
* them back, so they are kept whole for a reopened conversation to send it the same history.
|
|
815
|
+
*
|
|
816
|
+
* Step boundaries are kept because `toConversationMessages`, which converts the result into the
|
|
817
|
+
* format the storage service accepts, needs them to split a multi-step turn into one message per step.
|
|
818
|
+
*
|
|
819
|
+
* Implements `pruneMessagesFunction`.
|
|
820
|
+
*/
|
|
821
|
+
function defaultPruneMessagesForPersistence(messages) {
|
|
822
|
+
const approvalToolCallIds = collectApprovalToolCallIds(messages);
|
|
823
|
+
return messages.map(m => {
|
|
824
|
+
if (m.role !== 'assistant') {
|
|
825
|
+
return m;
|
|
826
|
+
}
|
|
827
|
+
const content = m.content
|
|
828
|
+
.filter(part => part.type === 'step-start' ||
|
|
829
|
+
part.type === 'text' ||
|
|
830
|
+
part.type === 'tool-result' ||
|
|
831
|
+
part.type === 'object' ||
|
|
832
|
+
// Approval parts carry the user's decision on a tool call, including a refusal, which is
|
|
833
|
+
// the only record that the call was attempted at all.
|
|
834
|
+
part.type === 'tool-approval-requested' ||
|
|
835
|
+
part.type === 'tool-approval-responded')
|
|
836
|
+
.map(part => part.type === 'tool-result' && !approvalToolCallIds.has(part.toolCallId)
|
|
837
|
+
? truncateToolOutput(part)
|
|
838
|
+
: part);
|
|
839
|
+
return { ...m, content };
|
|
708
840
|
});
|
|
709
841
|
}
|
|
842
|
+
const MAX_PERSISTED_TOOL_OUTPUT_LENGTH = 10_000;
|
|
843
|
+
/** Matches the note `truncateToolOutput` appends to the outputs it cuts. */
|
|
844
|
+
const TRUNCATED_OUTPUT_PATTERN = /… \[truncated to \d+ of \d+ characters\]$/;
|
|
845
|
+
/**
|
|
846
|
+
* Cuts a tool output longer than `MAX_PERSISTED_TOOL_OUTPUT_LENGTH` characters (of its JSON form,
|
|
847
|
+
* for a structured output) down to that length. The cut no longer parses, so it is kept as text.
|
|
848
|
+
*/
|
|
849
|
+
function truncateToolOutput(part) {
|
|
850
|
+
const serialized = typeof part.output === 'string' ? part.output : JSON.stringify(part.output);
|
|
851
|
+
if (!serialized || serialized.length <= MAX_PERSISTED_TOOL_OUTPUT_LENGTH) {
|
|
852
|
+
return part;
|
|
853
|
+
}
|
|
854
|
+
// Cut when the conversation was saved before, so it already notes the original size, which
|
|
855
|
+
// cutting it again would replace with the size of the cut.
|
|
856
|
+
if (typeof part.output === 'string' && TRUNCATED_OUTPUT_PATTERN.test(part.output)) {
|
|
857
|
+
return part;
|
|
858
|
+
}
|
|
859
|
+
return {
|
|
860
|
+
...part,
|
|
861
|
+
output: `${serialized.slice(0, MAX_PERSISTED_TOOL_OUTPUT_LENGTH)}… [truncated to ${MAX_PERSISTED_TOOL_OUTPUT_LENGTH} of ${serialized.length} characters]`,
|
|
862
|
+
outputType: undefined
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
/** Collects the ids of the tool calls that went through an approval exchange. */
|
|
866
|
+
function collectApprovalToolCallIds(messages) {
|
|
867
|
+
const ids = new Set();
|
|
868
|
+
for (const m of messages) {
|
|
869
|
+
if (m.role !== 'assistant')
|
|
870
|
+
continue;
|
|
871
|
+
for (const part of m.content) {
|
|
872
|
+
if (part.type === 'tool-approval-requested' || part.type === 'tool-approval-responded') {
|
|
873
|
+
ids.add(part.toolCallId);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return ids;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Converts chat messages into the format accepted by the conversation storage API.
|
|
882
|
+
*
|
|
883
|
+
* Unlike the history sent to the agent, tool calls are preserved so a stored conversation can be
|
|
884
|
+
* restored with its full transcript by `fromConversationMessages`. Note that:
|
|
885
|
+
* - each step of a multi-step assistant turn becomes its own message, since the wire format has no
|
|
886
|
+
* `step-start` part — `fromConversationMessages` rebuilds the boundaries from the message split;
|
|
887
|
+
* - a tool call that required approval keeps its full exchange: the `tool-approval-request` beside
|
|
888
|
+
* the call, and the user's `tool-approval-response` beside the outcome, which for a refused call
|
|
889
|
+
* is an `execution-denied` result;
|
|
890
|
+
* - the agent that produced an assistant turn is recorded on every assistant message of that turn,
|
|
891
|
+
* so it survives pruning of individual steps;
|
|
892
|
+
* - `object` parts are stored as text, as the wire format has no structured-object equivalent;
|
|
893
|
+
* - `system` messages are dropped, as the service rejects them: a conversation's system prompt
|
|
894
|
+
* comes from the agent's server-side configuration, never from stored history;
|
|
895
|
+
* - reasoning and in-progress tool calls are dropped, as they are not worth persisting.
|
|
896
|
+
*
|
|
897
|
+
* @param messages The chat messages to store, typically already pruned for persistence.
|
|
898
|
+
*/
|
|
899
|
+
function toConversationMessages(messages) {
|
|
900
|
+
// The result of an approved tool call streams in with a later assistant message, but on the wire
|
|
901
|
+
// it has to sit beside its approval exchange, so index every result up front.
|
|
902
|
+
const resultsByToolCallId = new Map();
|
|
903
|
+
for (const message of messages) {
|
|
904
|
+
if (message.role !== 'assistant')
|
|
905
|
+
continue;
|
|
906
|
+
for (const part of message.content) {
|
|
907
|
+
if (part.type === 'tool-result')
|
|
908
|
+
resultsByToolCallId.set(part.toolCallId, part);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
// Tracks calls already written beside their approval, so the copy carried by a later message is
|
|
912
|
+
// not written a second time.
|
|
913
|
+
const serializedToolCallIds = new Set();
|
|
914
|
+
return messages.flatMap(message => {
|
|
915
|
+
if (message.role === 'system') {
|
|
916
|
+
return [];
|
|
917
|
+
}
|
|
918
|
+
if (message.role === 'user') {
|
|
919
|
+
return [withDisplayMetadata({ role: 'user', content: message.content }, message)];
|
|
920
|
+
}
|
|
921
|
+
const stored = [];
|
|
922
|
+
for (const stepParts of splitIntoSteps(message.content)) {
|
|
923
|
+
stored.push(...buildStepMessages(stepParts, resultsByToolCallId, serializedToolCallIds));
|
|
924
|
+
}
|
|
925
|
+
if (stored.length > 0) {
|
|
926
|
+
stored[0] = withDisplayMetadata(stored[0], message);
|
|
927
|
+
}
|
|
928
|
+
return message.agentName
|
|
929
|
+
? stored.map(m => (m.role === 'assistant' ? { ...m, agentName: message.agentName } : m))
|
|
930
|
+
: stored;
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Converts one step's parts into the `assistant` message it maps to, paired with a `tool` message
|
|
935
|
+
* when the step carries tool results or approval decisions.
|
|
936
|
+
*
|
|
937
|
+
* @param resultsByToolCallId Completed tool results indexed by call id, so an approved call's result
|
|
938
|
+
* (which streams in with a later message) can be matched to the approval it belongs beside.
|
|
939
|
+
* @param serializedToolCallIds Tracks calls already written beside their approval, so the copy
|
|
940
|
+
* carried by a later message is not written a second time.
|
|
941
|
+
*/
|
|
942
|
+
function buildStepMessages(stepParts, resultsByToolCallId, serializedToolCallIds) {
|
|
943
|
+
const assistantContent = [];
|
|
944
|
+
const toolContent = [];
|
|
945
|
+
for (const part of stepParts) {
|
|
946
|
+
if (part.type === 'text' && part.text) {
|
|
947
|
+
assistantContent.push({ type: 'text', text: part.text });
|
|
948
|
+
}
|
|
949
|
+
else if (part.type === 'object') {
|
|
950
|
+
assistantContent.push({ type: 'text', text: part.jsonContent });
|
|
951
|
+
}
|
|
952
|
+
else if (part.type === 'tool-approval-requested' || part.type === 'tool-approval-responded') {
|
|
953
|
+
if (!part.approval)
|
|
954
|
+
continue;
|
|
955
|
+
assistantContent.push(toToolCallContent(part));
|
|
956
|
+
assistantContent.push({
|
|
957
|
+
type: 'tool-approval-request',
|
|
958
|
+
approvalId: part.approval.approvalId,
|
|
959
|
+
toolCallId: part.toolCallId
|
|
960
|
+
});
|
|
961
|
+
// An undecided approval is stored as the pending request alone.
|
|
962
|
+
if (part.approval.approved === undefined)
|
|
963
|
+
continue;
|
|
964
|
+
toolContent.push({
|
|
965
|
+
type: 'tool-approval-response',
|
|
966
|
+
approvalId: part.approval.approvalId,
|
|
967
|
+
approved: part.approval.approved,
|
|
968
|
+
...(part.approval.reason ? { reason: part.approval.reason } : {})
|
|
969
|
+
});
|
|
970
|
+
if (serializedToolCallIds.has(part.toolCallId))
|
|
971
|
+
continue;
|
|
972
|
+
const outcome = resolveApprovalOutcome(part, resultsByToolCallId, convertToolOutputToAgentFormat);
|
|
973
|
+
if (outcome) {
|
|
974
|
+
toolContent.push(outcome);
|
|
975
|
+
serializedToolCallIds.add(part.toolCallId);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
else if (part.type === 'tool-result') {
|
|
979
|
+
if (serializedToolCallIds.has(part.toolCallId))
|
|
980
|
+
continue;
|
|
981
|
+
assistantContent.push(toToolCallContent(part));
|
|
982
|
+
toolContent.push({
|
|
983
|
+
type: 'tool-result',
|
|
984
|
+
toolCallId: part.toolCallId,
|
|
985
|
+
toolName: part.toolName,
|
|
986
|
+
output: convertToolOutputToAgentFormat(part)
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const stepMessages = [];
|
|
991
|
+
if (assistantContent.length > 0) {
|
|
992
|
+
stepMessages.push({ role: 'assistant', content: assistantContent });
|
|
993
|
+
}
|
|
994
|
+
if (toolContent.length > 0) {
|
|
995
|
+
stepMessages.push({ role: 'tool', content: toolContent });
|
|
996
|
+
}
|
|
997
|
+
return stepMessages;
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Restores stored messages into the format the chat renders, inverting `toConversationMessages`.
|
|
1001
|
+
*
|
|
1002
|
+
* The consecutive assistant and tool messages that one assistant turn was split into are merged
|
|
1003
|
+
* back into a single message, with a `step-start` part marking each boundary, and each tool call
|
|
1004
|
+
* is reunited with its result and, where it needed one, with the user's approval decision.
|
|
1005
|
+
*
|
|
1006
|
+
* A restored approved call carries its result on the approval part itself, rather than in the
|
|
1007
|
+
* following message where it originally streamed in. The chat renders that identically, and a
|
|
1008
|
+
* restored decision is never re-actionable: the approval buttons only appear on the latest message.
|
|
1009
|
+
*
|
|
1010
|
+
* Note that the wire format marks where a step ended but not where a turn did, so assistant
|
|
1011
|
+
* messages that followed one another without the user speaking in between — an approval and the
|
|
1012
|
+
* response resumed from it, for example — come back merged into a single turn. Every part and its
|
|
1013
|
+
* order is preserved; only the split into separate messages is not. The merged turn carries the
|
|
1014
|
+
* sum of their token usage and the timestamp of the last one. Messages recorded as coming from
|
|
1015
|
+
* different agents are never merged.
|
|
1016
|
+
*
|
|
1017
|
+
* @param messages The messages of a stored conversation.
|
|
1018
|
+
*/
|
|
1019
|
+
function fromConversationMessages(messages) {
|
|
1020
|
+
const restored = [];
|
|
1021
|
+
// The assistant turn currently being rebuilt, or undefined when the last message was not one.
|
|
1022
|
+
let turn;
|
|
1023
|
+
for (const message of messages) {
|
|
1024
|
+
if (message.role === 'tool') {
|
|
1025
|
+
for (const part of message.content) {
|
|
1026
|
+
if (part.type === 'tool-approval-response') {
|
|
1027
|
+
applyApprovalResponse(turn, part);
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1030
|
+
applyToolResult(turn, part);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
else if (message.role === 'assistant') {
|
|
1035
|
+
// A different agent answering starts a new turn, even without the user speaking in between.
|
|
1036
|
+
const agentChanged = !!turn?.agentName && !!message.agentName && turn.agentName !== message.agentName;
|
|
1037
|
+
if (!turn || agentChanged) {
|
|
1038
|
+
turn = {
|
|
1039
|
+
role: 'assistant',
|
|
1040
|
+
content: [],
|
|
1041
|
+
...(message.timestamp ? { timestamp: message.timestamp } : {}),
|
|
1042
|
+
...(message.usage ? { usage: message.usage } : {}),
|
|
1043
|
+
...(message.agentName ? { agentName: message.agentName } : {})
|
|
1044
|
+
};
|
|
1045
|
+
restored.push(turn);
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
if (!turn.agentName && message.agentName)
|
|
1049
|
+
turn.agentName = message.agentName;
|
|
1050
|
+
// Only the first stored message of a chat message carries its metadata, so a later one with
|
|
1051
|
+
// it was a separate chat message, such as the response resumed after a tool approval.
|
|
1052
|
+
if (message.usage)
|
|
1053
|
+
turn.usage = addUsage(turn.usage, message.usage);
|
|
1054
|
+
if (message.timestamp)
|
|
1055
|
+
turn.timestamp = message.timestamp;
|
|
1056
|
+
turn.content.push({ type: 'step-start' });
|
|
1057
|
+
}
|
|
1058
|
+
// Another client may store an assistant message as plain text, which the wire format allows.
|
|
1059
|
+
const content = typeof message.content === 'string'
|
|
1060
|
+
? [{ type: 'text', text: message.content }]
|
|
1061
|
+
: message.content;
|
|
1062
|
+
for (const part of content) {
|
|
1063
|
+
if (part.type === 'text') {
|
|
1064
|
+
turn.content.push({ type: 'text', text: part.text });
|
|
1065
|
+
}
|
|
1066
|
+
else if (part.type === 'tool-call') {
|
|
1067
|
+
// Stored as a completed call: its output is filled in from the tool message that follows.
|
|
1068
|
+
turn.content.push({
|
|
1069
|
+
type: 'tool-result',
|
|
1070
|
+
toolName: part.toolName,
|
|
1071
|
+
toolCallId: part.toolCallId,
|
|
1072
|
+
input: part.input
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
else if (part.type === 'tool-approval-request') {
|
|
1076
|
+
const call = findToolCall(turn, part.toolCallId);
|
|
1077
|
+
if (call) {
|
|
1078
|
+
call.type = 'tool-approval-requested';
|
|
1079
|
+
call.approval = { approvalId: part.approvalId };
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
turn = undefined;
|
|
1086
|
+
restored.push({
|
|
1087
|
+
role: message.role,
|
|
1088
|
+
content: message.content,
|
|
1089
|
+
...(message.timestamp ? { timestamp: message.timestamp } : {})
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
return restored;
|
|
1094
|
+
}
|
|
1095
|
+
function withDisplayMetadata(stored, source) {
|
|
1096
|
+
return {
|
|
1097
|
+
...stored,
|
|
1098
|
+
...(source.timestamp ? { timestamp: source.timestamp } : {}),
|
|
1099
|
+
...(source.role === 'assistant' && source.usage ? { usage: source.usage } : {})
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
function addUsage(total, usage) {
|
|
1103
|
+
if (!total)
|
|
1104
|
+
return usage;
|
|
1105
|
+
return {
|
|
1106
|
+
inputTokens: (total.inputTokens ?? 0) + (usage.inputTokens ?? 0),
|
|
1107
|
+
outputTokens: (total.outputTokens ?? 0) + (usage.outputTokens ?? 0),
|
|
1108
|
+
totalTokens: (total.totalTokens ?? 0) + (usage.totalTokens ?? 0)
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function findToolCall(turn, toolCallId) {
|
|
1112
|
+
return turn?.content.find((candidate) => 'toolCallId' in candidate && candidate.toolCallId === toolCallId);
|
|
1113
|
+
}
|
|
1114
|
+
function applyApprovalResponse(turn, part) {
|
|
1115
|
+
const call = turn?.content.find((candidate) => 'approval' in candidate && candidate.approval?.approvalId === part.approvalId);
|
|
1116
|
+
if (!call) {
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
call.type = 'tool-approval-responded';
|
|
1120
|
+
call.approval = {
|
|
1121
|
+
approvalId: part.approvalId,
|
|
1122
|
+
approved: part.approved,
|
|
1123
|
+
...(part.reason ? { reason: part.reason } : {})
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function applyToolResult(turn, part) {
|
|
1127
|
+
const call = findToolCall(turn, part.toolCallId);
|
|
1128
|
+
if (!call) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
const output = part.output;
|
|
1132
|
+
switch (part.output.type) {
|
|
1133
|
+
case 'execution-denied':
|
|
1134
|
+
// A refused call never ran, so it has no output — the decision itself is on the approval part.
|
|
1135
|
+
break;
|
|
1136
|
+
case 'content':
|
|
1137
|
+
call.output = output.value;
|
|
1138
|
+
// Marks the output as a multi-part content array so it can be sent back to the agent as one.
|
|
1139
|
+
call.outputType = 'content';
|
|
1140
|
+
break;
|
|
1141
|
+
case 'error-text':
|
|
1142
|
+
case 'error-json':
|
|
1143
|
+
call.output = output.value;
|
|
1144
|
+
call.error = true;
|
|
1145
|
+
break;
|
|
1146
|
+
default:
|
|
1147
|
+
// text and json outputs both restore to the plain value the UI renders.
|
|
1148
|
+
call.output = output.value;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
710
1151
|
|
|
711
1152
|
/**
|
|
712
1153
|
* Remembers the user's "always approve" decisions for tool calls that require human approval.
|
|
@@ -852,5 +1293,5 @@ function summarizeQuery(query, translateService) {
|
|
|
852
1293
|
* Generated bundle index. Do not edit.
|
|
853
1294
|
*/
|
|
854
1295
|
|
|
855
|
-
export { AIService, AiToolApprovalMemoryService, DataStreamType, cumulocityApiRequestLabelProvider, defaultPruneMessagesForAgent };
|
|
1296
|
+
export { AIService, AiToolApprovalMemoryService, DataStreamType, cumulocityApiRequestLabelProvider, defaultPruneMessagesForAgent, defaultPruneMessagesForPersistence, fromConversationMessages, toConversationMessages };
|
|
856
1297
|
//# sourceMappingURL=c8y-ngx-components-ai.mjs.map
|