@datalayer/agent-runtimes 1.3.82 → 1.3.84
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/lib/chat/base/ChatBase.js +16 -0
- package/lib/chat/base/loopElement.d.ts +53 -0
- package/lib/chat/base/loopElement.js +78 -0
- package/lib/chat/base/loopWindow.d.ts +31 -0
- package/lib/chat/base/loopWindow.js +74 -0
- package/lib/components/a2ui/datalayer/FileUpload.d.ts +10 -2
- package/lib/components/a2ui/datalayer/FileUpload.js +10 -7
- package/lib/components/a2ui/datalayer/Form.d.ts +2 -0
- package/lib/components/a2ui/datalayer/Form.js +26 -2
- package/lib/components/a2ui/datalayer/formWidgets.d.ts +19 -0
- package/lib/components/a2ui/datalayer/formWidgets.js +51 -0
- package/lib/loop/apps/AppComposer.d.ts +39 -4
- package/lib/loop/apps/AppComposer.js +191 -19
- package/lib/loop/apps/AppRenderer.d.ts +20 -3
- package/lib/loop/apps/AppRenderer.js +58 -27
- package/lib/loop/apps/appspec.d.ts +2 -0
- package/lib/loop/apps/appspec.js +196 -39
- package/lib/loop/apps/checks.d.ts +6 -0
- package/lib/loop/apps/checks.js +187 -8
- package/lib/loop/apps/composer.d.ts +21 -10
- package/lib/loop/apps/composer.js +41 -8
- package/lib/loop/apps/language.d.ts +68 -0
- package/lib/loop/apps/language.js +275 -0
- package/lib/loop/apps/settingsInputs.d.ts +29 -0
- package/lib/loop/apps/settingsInputs.js +147 -0
- package/lib/loop/apps/uploads.d.ts +43 -0
- package/lib/loop/apps/uploads.js +66 -0
- package/lib/loop/core/index.d.ts +14 -1
- package/lib/loop/embed/AppEmbed.d.ts +14 -0
- package/lib/loop/embed/AppEmbed.js +64 -2
- package/lib/loop/embed/element.js +23 -0
- package/lib/loop/embed/embedSession.d.ts +14 -0
- package/lib/loop/embed/embedSession.js +34 -0
- package/lib/loop/embed/hostBridge.d.ts +22 -1
- package/lib/loop/plugins/app-elements/AppElements.d.ts +27 -0
- package/lib/loop/plugins/app-elements/AppElements.js +76 -0
- package/lib/loop/plugins/app-elements/index.d.ts +20 -0
- package/lib/loop/plugins/app-elements/index.js +43 -0
- package/lib/loop/plugins/app-page/appPageModel.d.ts +14 -5
- package/lib/loop/plugins/app-page/appPageModel.js +82 -88
- package/lib/loop/plugins/chat/ChatView.js +10 -2
- package/lib/protocols/BrowserAgentAdapter.d.ts +8 -6
- package/lib/protocols/BrowserAgentAdapter.js +13 -10
- package/lib/runtimes/browser/protocol.d.ts +1 -1
- package/lib/specs/agents/agents.js +6 -3
- package/lib/specs/apps.js +337 -176
- package/lib/specs/appspecSchema.js +455 -88
- package/lib/specs/cogs.js +3 -2
- package/lib/specs/uiPlugins.js +6 -1
- package/lib/types/agentspecs.d.ts +167 -11
- package/package.json +1 -1
- package/scripts/codegen/generate_apps.py +16 -1
|
@@ -141,6 +141,25 @@ export const APP_KIND_PATHS = {
|
|
|
141
141
|
export const isAppPageKind = (kind) => Object.prototype.hasOwnProperty.call(APP_KIND_PATHS, kind);
|
|
142
142
|
/** The path a setting, an input of the page, is kept at. */
|
|
143
143
|
export const inputPath = (id) => `/inputs/${id}`;
|
|
144
|
+
/**
|
|
145
|
+
* The fields of an application's settings (C-16), by name, in the order its
|
|
146
|
+
* form says them; none when it has no settings.
|
|
147
|
+
*/
|
|
148
|
+
export function settingFields(settings) {
|
|
149
|
+
const properties = settings?.properties;
|
|
150
|
+
if (!properties || typeof properties !== 'object') {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
return Object.entries(properties).filter((entry) => typeof entry[1] === 'object' && entry[1] !== null);
|
|
154
|
+
}
|
|
155
|
+
/** A setting as a person reads it: its field's `title`, else its name. */
|
|
156
|
+
export const settingTitle = (id, field) => typeof field.title === 'string' && field.title ? field.title : id;
|
|
157
|
+
/** What each setting starts at: its field's `default`, for those that say one. */
|
|
158
|
+
export function settingDefaults(settings) {
|
|
159
|
+
return Object.fromEntries(settingFields(settings)
|
|
160
|
+
.filter(([, field]) => field.default !== undefined)
|
|
161
|
+
.map(([id, field]) => [id, field.default]));
|
|
162
|
+
}
|
|
144
163
|
/**
|
|
145
164
|
* What an application publishes and takes, with its own settings: the kind's
|
|
146
165
|
* list, and for a kind that has inputs each setting at `/inputs/<id>`, both
|
|
@@ -154,10 +173,10 @@ export function appKindPaths(app) {
|
|
|
154
173
|
if (!kind.inputs) {
|
|
155
174
|
return kind;
|
|
156
175
|
}
|
|
157
|
-
const inputs = app.interface.settings.map(
|
|
158
|
-
path: inputPath(
|
|
159
|
-
meaning: `The setting “${
|
|
160
|
-
words:
|
|
176
|
+
const inputs = settingFields(app.interface.settings).map(([id, field]) => ({
|
|
177
|
+
path: inputPath(id),
|
|
178
|
+
meaning: `The setting “${settingTitle(id, field)}”.`,
|
|
179
|
+
words: settingTitle(id, field),
|
|
161
180
|
}));
|
|
162
181
|
return {
|
|
163
182
|
...kind,
|
|
@@ -199,24 +218,6 @@ const STATUS_WORDS = {
|
|
|
199
218
|
done: 'Answered',
|
|
200
219
|
error: 'Stopped',
|
|
201
220
|
};
|
|
202
|
-
/** A setting's first value, as its input holds it. */
|
|
203
|
-
export function initialInput(setting) {
|
|
204
|
-
switch (setting.type) {
|
|
205
|
-
case 'toggle':
|
|
206
|
-
return Boolean(setting.default ?? false);
|
|
207
|
-
case 'select':
|
|
208
|
-
// A ChoicePicker holds a list of the values chosen.
|
|
209
|
-
return setting.default === undefined ? [] : [String(setting.default)];
|
|
210
|
-
case 'slider':
|
|
211
|
-
return Number(setting.default ?? setting.min ?? 0);
|
|
212
|
-
case 'number':
|
|
213
|
-
return setting.max === undefined
|
|
214
|
-
? String(setting.default ?? '')
|
|
215
|
-
: Number(setting.default ?? setting.min ?? 0);
|
|
216
|
-
default:
|
|
217
|
-
return String(setting.default ?? '');
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
221
|
/**
|
|
221
222
|
* What the conversation publishes to the page, by path, now: from its
|
|
222
223
|
* current turn, and for a chat its whole conversation.
|
|
@@ -253,10 +254,20 @@ export function appPageInitialData(app) {
|
|
|
253
254
|
}
|
|
254
255
|
const paths = appKindPaths(app);
|
|
255
256
|
if (paths.inputs) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
// Each setting at its default, as the settings' form holds it; a
|
|
258
|
+
// ChoicePicker a builder placed at a setting holds a list of the values
|
|
259
|
+
// chosen.
|
|
260
|
+
const inputs = settingDefaults(app.interface.settings);
|
|
261
|
+
for (const node of app.interface.surface?.components ?? []) {
|
|
262
|
+
const bound = node.value?.path;
|
|
263
|
+
const id = typeof bound === 'string' && bound.startsWith('/inputs/')
|
|
264
|
+
? bound.slice('/inputs/'.length)
|
|
265
|
+
: undefined;
|
|
266
|
+
if (node.component === 'ChoicePicker' && id && id in inputs) {
|
|
267
|
+
inputs[id] = Array.isArray(inputs[id]) ? inputs[id] : [inputs[id]];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
tree.inputs = inputs;
|
|
260
271
|
}
|
|
261
272
|
if (paths.accepts.some(entry => entry.path === DRAFT.path)) {
|
|
262
273
|
tree.draft = '';
|
|
@@ -289,9 +300,9 @@ export function inputsInWords(app, inputs) {
|
|
|
289
300
|
: {};
|
|
290
301
|
const lines = [];
|
|
291
302
|
const seen = new Set();
|
|
292
|
-
for (const
|
|
293
|
-
seen.add(
|
|
294
|
-
lines.push(inputWords(
|
|
303
|
+
for (const [id, field] of settingFields(app.interface.settings)) {
|
|
304
|
+
seen.add(id);
|
|
305
|
+
lines.push(inputWords(settingTitle(id, field), values[id]));
|
|
295
306
|
}
|
|
296
307
|
for (const [id, value] of Object.entries(values)) {
|
|
297
308
|
if (!seen.has(id)) {
|
|
@@ -345,38 +356,43 @@ export function givenFiles(files) {
|
|
|
345
356
|
}
|
|
346
357
|
/**
|
|
347
358
|
* The application's settings as the page holds them, as the session API
|
|
348
|
-
* takes them
|
|
349
|
-
* as on or off
|
|
359
|
+
* takes them, each as its field's type says (C-16): a number as a number, a
|
|
360
|
+
* boolean as on or off, a word as the option chosen — a ChoicePicker holds a
|
|
361
|
+
* list of them — each setting the page has a value for. The runtime checks
|
|
362
|
+
* them against the settings' form.
|
|
350
363
|
*/
|
|
351
364
|
export function settingsOf(app, inputs) {
|
|
352
365
|
const values = inputs && typeof inputs === 'object'
|
|
353
366
|
? inputs
|
|
354
367
|
: {};
|
|
355
368
|
const settings = {};
|
|
356
|
-
for (const
|
|
357
|
-
const
|
|
369
|
+
for (const [id, field] of settingFields(app.interface.settings)) {
|
|
370
|
+
const held = values[id];
|
|
371
|
+
if (held === undefined || held === null) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (field.type === 'array' || field.type === 'object') {
|
|
375
|
+
settings[id] = held;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
const value = Array.isArray(held) ? held[0] : held;
|
|
358
379
|
if (value === undefined || value === null) {
|
|
359
380
|
continue;
|
|
360
381
|
}
|
|
361
|
-
switch (
|
|
362
|
-
case '
|
|
363
|
-
const chosen = Array.isArray(value) ? value[0] : value;
|
|
364
|
-
if (chosen !== undefined && chosen !== '') {
|
|
365
|
-
settings[setting.id] = String(chosen);
|
|
366
|
-
}
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
case 'toggle':
|
|
370
|
-
settings[setting.id] = Boolean(value);
|
|
371
|
-
break;
|
|
372
|
-
case 'slider':
|
|
382
|
+
switch (field.type) {
|
|
383
|
+
case 'integer':
|
|
373
384
|
case 'number':
|
|
374
385
|
if (value !== '' && !Number.isNaN(Number(value))) {
|
|
375
|
-
settings[
|
|
386
|
+
settings[id] = Number(value);
|
|
376
387
|
}
|
|
377
388
|
break;
|
|
389
|
+
case 'boolean':
|
|
390
|
+
settings[id] = Boolean(value);
|
|
391
|
+
break;
|
|
378
392
|
default:
|
|
379
|
-
|
|
393
|
+
if (value !== '' || !Array.isArray(field.enum)) {
|
|
394
|
+
settings[id] = typeof value === 'string' ? value : String(value);
|
|
395
|
+
}
|
|
380
396
|
}
|
|
381
397
|
}
|
|
382
398
|
return settings;
|
|
@@ -464,44 +480,24 @@ const button = (id, label, name, primary = false) => [
|
|
|
464
480
|
},
|
|
465
481
|
{ id: `${id}-label`, component: 'Text', text: label },
|
|
466
482
|
];
|
|
467
|
-
/**
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
};
|
|
486
|
-
case 'slider':
|
|
487
|
-
return {
|
|
488
|
-
...base,
|
|
489
|
-
component: 'Slider',
|
|
490
|
-
min: setting.min ?? 0,
|
|
491
|
-
max: setting.max ?? 100,
|
|
492
|
-
};
|
|
493
|
-
case 'number':
|
|
494
|
-
return setting.max === undefined
|
|
495
|
-
? { ...base, component: 'TextField', variant: 'number' }
|
|
496
|
-
: {
|
|
497
|
-
...base,
|
|
498
|
-
component: 'Slider',
|
|
499
|
-
min: setting.min ?? 0,
|
|
500
|
-
max: setting.max,
|
|
501
|
-
};
|
|
502
|
-
default:
|
|
503
|
-
return { ...base, component: 'TextField' };
|
|
504
|
-
}
|
|
483
|
+
/**
|
|
484
|
+
* The settings as one Form block (C-16): their form drawn with
|
|
485
|
+
* `@datalayer/primer-rjsf`, the values written at `/inputs` as they are
|
|
486
|
+
* filled — no action, no button: they go with the next run.
|
|
487
|
+
*/
|
|
488
|
+
function settingsForm(app) {
|
|
489
|
+
return app.interface.settings && settingFields(app.interface.settings).length
|
|
490
|
+
? [
|
|
491
|
+
{
|
|
492
|
+
id: 'settings',
|
|
493
|
+
component: 'Form',
|
|
494
|
+
schema: app.interface.settings,
|
|
495
|
+
// Drawn with the inputs its uiSchema names (P-20).
|
|
496
|
+
...(app.interface.settingsUi ? { ui: app.interface.settingsUi } : {}),
|
|
497
|
+
values: { path: '/inputs' },
|
|
498
|
+
},
|
|
499
|
+
]
|
|
500
|
+
: [];
|
|
505
501
|
}
|
|
506
502
|
/**
|
|
507
503
|
* The page drawn when the application has a page layout and no surface
|
|
@@ -509,9 +505,7 @@ function settingInput(setting) {
|
|
|
509
505
|
* buttons its kind handles that the conversation does not already give.
|
|
510
506
|
*/
|
|
511
507
|
export function defaultAppSurface(app) {
|
|
512
|
-
const inputs = appKindPaths(app).inputs
|
|
513
|
-
? app.interface.settings.map(settingInput)
|
|
514
|
-
: [];
|
|
508
|
+
const inputs = appKindPaths(app).inputs ? settingsForm(app) : [];
|
|
515
509
|
const body = [];
|
|
516
510
|
switch (app.kind) {
|
|
517
511
|
case 'chat':
|
|
@@ -372,11 +372,12 @@ export default function ChatView({ workspace }) {
|
|
|
372
372
|
* itself (`modeEffect`, `BrowserAgentAdapter`).
|
|
373
373
|
*/
|
|
374
374
|
const sendNow = useCallback((message, given) => {
|
|
375
|
-
const
|
|
375
|
+
const forwardedProps = runForwardedProps(runPropsRef.current.map(entry => entry.value), given);
|
|
376
|
+
// The page's files, or those attached in the composer (LOOP P-21).
|
|
377
|
+
const loop = forwardedProps?.loop;
|
|
376
378
|
if (inPageRef.current && loop?.files && loop.files.length > 0) {
|
|
377
379
|
return 'A file is given to an application running on a runtime: run it on Datalayer or on your machine to give it one.';
|
|
378
380
|
}
|
|
379
|
-
const forwardedProps = runForwardedProps(runPropsRef.current.map(entry => entry.value), given);
|
|
380
381
|
// A new turn: whatever the panel showed is gone, this message is it.
|
|
381
382
|
turnFeedRef.current?.begin(message, controlsRef.current?.thread());
|
|
382
383
|
const send = controlsRef.current?.send;
|
|
@@ -752,6 +753,7 @@ export default function ChatView({ workspace }) {
|
|
|
752
753
|
const suggestionEntries = useContributions(LoopChatSuggestion);
|
|
753
754
|
const hiddenOpeners = chatExtras.hiddenOpeners;
|
|
754
755
|
const hideOpeners = chatExtras.hideOpeners;
|
|
756
|
+
const liveOpeners = chatExtras.openers;
|
|
755
757
|
const suggestions = useMemo(() => {
|
|
756
758
|
if (hideOpeners) {
|
|
757
759
|
return [];
|
|
@@ -760,6 +762,11 @@ export default function ChatView({ workspace }) {
|
|
|
760
762
|
// the two-group merge below uses to tell openers apart.
|
|
761
763
|
const hidden = new Set(hiddenOpeners ?? []);
|
|
762
764
|
const offered = (items) => hidden.size === 0 ? items : items.filter(item => !hidden.has(item.text));
|
|
765
|
+
// What a plugin offers live (an application's profile's starters,
|
|
766
|
+
// LOOP P-20) wins over what was contributed when the reactor was built.
|
|
767
|
+
if (liveOpeners) {
|
|
768
|
+
return offered(liveOpeners);
|
|
769
|
+
}
|
|
763
770
|
const contributed = suggestionEntries.flatMap(entry => entry.value.suggestions);
|
|
764
771
|
if (contributed.length > 0) {
|
|
765
772
|
return offered(contributed);
|
|
@@ -788,6 +795,7 @@ export default function ChatView({ workspace }) {
|
|
|
788
795
|
agentId,
|
|
789
796
|
hiddenOpeners,
|
|
790
797
|
hideOpeners,
|
|
798
|
+
liveOpeners,
|
|
791
799
|
]);
|
|
792
800
|
/*
|
|
793
801
|
* The same openers in the shape the chat's empty state asks for.
|
|
@@ -70,7 +70,7 @@ export interface BrowserAgentAdapterConfig extends ProtocolAdapterConfig, Fronte
|
|
|
70
70
|
* rules. Unsaid for an agent with no modes, which refuses a run sent in
|
|
71
71
|
* some.
|
|
72
72
|
*/
|
|
73
|
-
modeEffect?: (chosen: Record<string, string
|
|
73
|
+
modeEffect?: (chosen: Record<string, string>, profile?: string) => AppModeEffect;
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* An agent loop running in the page, speaking the protocol adapter interface.
|
|
@@ -120,12 +120,14 @@ export declare class BrowserAgentAdapter extends BaseProtocolAdapter {
|
|
|
120
120
|
*/
|
|
121
121
|
private resolveModel;
|
|
122
122
|
/**
|
|
123
|
-
* What the modes a run is sent in
|
|
124
|
-
*
|
|
123
|
+
* What the modes a run is sent in, and the profile its conversation is
|
|
124
|
+
* with, tell it, and the model it runs on (LOOP P-19, P-20) — the
|
|
125
|
+
* runtime's session API applies the same, for that run only.
|
|
125
126
|
*
|
|
126
|
-
* Refused, in a sentence, rather than run without them: modes
|
|
127
|
-
* agent that has none, modes that are not the
|
|
128
|
-
*
|
|
127
|
+
* Refused, in a sentence, rather than run without them: modes or a profile
|
|
128
|
+
* sent to an agent that has none, modes or a profile that are not the
|
|
129
|
+
* application's, and a model chosen for an agent whose model is the host's
|
|
130
|
+
* own.
|
|
129
131
|
*/
|
|
130
132
|
private runModes;
|
|
131
133
|
/**
|
|
@@ -141,26 +141,29 @@ export class BrowserAgentAdapter extends BaseProtocolAdapter {
|
|
|
141
141
|
return createBrowserModel({ ...inference, model: requested || model });
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
|
-
* What the modes a run is sent in
|
|
145
|
-
*
|
|
144
|
+
* What the modes a run is sent in, and the profile its conversation is
|
|
145
|
+
* with, tell it, and the model it runs on (LOOP P-19, P-20) — the
|
|
146
|
+
* runtime's session API applies the same, for that run only.
|
|
146
147
|
*
|
|
147
|
-
* Refused, in a sentence, rather than run without them: modes
|
|
148
|
-
* agent that has none, modes that are not the
|
|
149
|
-
*
|
|
148
|
+
* Refused, in a sentence, rather than run without them: modes or a profile
|
|
149
|
+
* sent to an agent that has none, modes or a profile that are not the
|
|
150
|
+
* application's, and a model chosen for an agent whose model is the host's
|
|
151
|
+
* own.
|
|
150
152
|
*/
|
|
151
153
|
runModes(forwardedProps) {
|
|
152
154
|
const loop = forwardedProps?.loop;
|
|
153
|
-
const chosen = loop?.modes;
|
|
154
|
-
|
|
155
|
+
const chosen = loop?.modes ?? {};
|
|
156
|
+
const profile = loop?.profile || undefined;
|
|
157
|
+
if (Object.keys(chosen).length === 0 && !profile) {
|
|
155
158
|
return undefined;
|
|
156
159
|
}
|
|
157
160
|
const { modeEffect, languageModel } = this.browserConfig;
|
|
158
161
|
if (!modeEffect) {
|
|
159
|
-
throw new Error('This agent has no modes:
|
|
162
|
+
throw new Error('This agent has no modes or profiles: what was chosen in the composer cannot be applied to it.');
|
|
160
163
|
}
|
|
161
|
-
const effect = modeEffect(chosen);
|
|
164
|
+
const effect = modeEffect(chosen, profile);
|
|
162
165
|
if (effect.model && languageModel) {
|
|
163
|
-
throw new Error(`The mode chosen runs on ${effect.model}, and this agent's model is its host's own: it cannot run on another.`);
|
|
166
|
+
throw new Error(`The mode or profile chosen runs on ${effect.model}, and this agent's model is its host's own: it cannot run on another.`);
|
|
164
167
|
}
|
|
165
168
|
return effect;
|
|
166
169
|
}
|
|
@@ -39,7 +39,7 @@ export type BrowserProtocolOptions = {
|
|
|
39
39
|
/** Told what a delegated run does, as it does it — see `subagentTools`. */
|
|
40
40
|
onSubagentEvent?: (event: AgentStreamSubagentPayload) => void;
|
|
41
41
|
/** What the modes a run is sent in tell it (LOOP P-19); none when unsaid. */
|
|
42
|
-
modeEffect?: (chosen: Record<string, string
|
|
42
|
+
modeEffect?: (chosen: Record<string, string>, profile?: string) => AppModeEffect;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
45
|
* The protocol config for an agent whose loop runs in this page.
|
|
@@ -4900,8 +4900,9 @@ export const JUPYTER_DATA_ANALYST_AGENTSPEC_0_0_1 = {
|
|
|
4900
4900
|
'collaboration',
|
|
4901
4901
|
],
|
|
4902
4902
|
domain: undefined,
|
|
4903
|
-
enabled:
|
|
4903
|
+
enabled: true,
|
|
4904
4904
|
model: 'bedrock:us.anthropic.claude-sonnet-4-6',
|
|
4905
|
+
modelAdditionals: ['alibaba:qwen-max'],
|
|
4905
4906
|
mcpServers: [],
|
|
4906
4907
|
skills: [].filter(Boolean),
|
|
4907
4908
|
backendTools: [TOOL_MAP['runtime-echo:0.0.1']],
|
|
@@ -7966,8 +7967,9 @@ export const WORKER_CUSTOMER_INTERVIEWER_AGENTSPEC_0_0_1 = {
|
|
|
7966
7967
|
description: `Conducts adaptive, AI-led interviews that respond intelligently to each answer. It asks relevant follow-up questions, uncovers motivations and decision-making patterns, and transforms conversations into structured, actionable insights.`,
|
|
7967
7968
|
tags: ['research', 'customer-support', 'analysis'],
|
|
7968
7969
|
domain: 'market-analyst',
|
|
7969
|
-
enabled:
|
|
7970
|
+
enabled: true,
|
|
7970
7971
|
model: 'bedrock:us.anthropic.claude-sonnet-4-6',
|
|
7972
|
+
modelAdditionals: ['alibaba:qwen-max'],
|
|
7971
7973
|
mcpServers: [],
|
|
7972
7974
|
skills: [
|
|
7973
7975
|
SKILL_MAP['text-summarizer:0.0.1']
|
|
@@ -8249,8 +8251,9 @@ export const WORKER_DOCUMENT_QA_AGENTSPEC_0_0_1 = {
|
|
|
8249
8251
|
'qa',
|
|
8250
8252
|
],
|
|
8251
8253
|
domain: 'personal-assistant',
|
|
8252
|
-
enabled:
|
|
8254
|
+
enabled: true,
|
|
8253
8255
|
model: 'bedrock:us.anthropic.claude-sonnet-4-6',
|
|
8256
|
+
modelAdditionals: ['alibaba:qwen-max'],
|
|
8254
8257
|
mcpServers: [],
|
|
8255
8258
|
skills: [
|
|
8256
8259
|
SKILL_MAP['events:0.0.1']
|