@namzu/sdk 61.2.1 → 61.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/public-runtime.d.ts +1 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts +80 -0
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +193 -10
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/types/computer-use/index.d.ts +28 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/public-runtime.ts +4 -0
- package/src/tools/builtins/computer-use.ts +273 -8
- package/src/types/computer-use/index.ts +34 -0
|
@@ -11,11 +11,37 @@ const DEFAULT_SETTLE_MS = 500;
|
|
|
11
11
|
const DEFAULT_MAX_BATCH_ACTIONS = 20;
|
|
12
12
|
const DEFAULT_MAX_WAIT_MS = 10_000;
|
|
13
13
|
const DEFAULT_WAIT_FOR_MS = 10_000;
|
|
14
|
+
/**
|
|
15
|
+
* The wait between the last action and the screenshot that follows it. A host
|
|
16
|
+
* that can tell when the window stopped changing (see
|
|
17
|
+
* {@link ComputerUseHost.settle}) is asked first and ends the wait early; a
|
|
18
|
+
* host without it, one that cannot say, or one that fails keeps the fixed
|
|
19
|
+
* `settleMs` it always had. Cancellation is never swallowed.
|
|
20
|
+
*/
|
|
21
|
+
async function settleAfterActions(host, windowId, settleMs, signal) {
|
|
22
|
+
if (settleMs > 0 && typeof host.settle === 'function') {
|
|
23
|
+
try {
|
|
24
|
+
const settled = await host.settle({ budgetMs: settleMs, ...(windowId !== undefined ? { windowId } : {}) }, signal);
|
|
25
|
+
if (settled !== undefined)
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Fall through to the fixed wait; a cancelled signal makes it reject at once.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
await sleep(settleMs, signal);
|
|
33
|
+
}
|
|
14
34
|
const MAX_LISTED_WINDOWS = 50;
|
|
15
35
|
/** The most of a ui_snapshot the model is shown, in characters (about 4 000 tokens). */
|
|
16
36
|
const MAX_UI_SNAPSHOT_CHARS = 14_000;
|
|
17
37
|
/** The refs of earlier snapshots the tool still resolves for the host. */
|
|
18
38
|
const MAX_HELD_UI_REFS = 4_000;
|
|
39
|
+
/** The least confidence in the best control for the tool to act on it. */
|
|
40
|
+
const ADVICE_MIN_CONFIDENCE = 0.85;
|
|
41
|
+
/** How far the best control must lead the next one. */
|
|
42
|
+
const ADVICE_MIN_MARGIN = 0.4;
|
|
43
|
+
/** The most controls an advisor is asked about at once. */
|
|
44
|
+
const MAX_ADVISED_CANDIDATES = 255;
|
|
19
45
|
/**
|
|
20
46
|
* Why `provider` cannot drive `computer_use`, or undefined when it can.
|
|
21
47
|
*
|
|
@@ -149,6 +175,16 @@ const uiActSchema = z.object({
|
|
|
149
175
|
ref: z.string().min(1),
|
|
150
176
|
action: z.enum(UI_ACTIONS),
|
|
151
177
|
value: z.string().optional(),
|
|
178
|
+
/** What this is for, in a few words; only read when the tool has an advisor. */
|
|
179
|
+
intent: z.string().min(1).max(200).optional(),
|
|
180
|
+
});
|
|
181
|
+
const uiDoSchema = z.object({
|
|
182
|
+
type: z.literal('ui_do'),
|
|
183
|
+
/** The control, in words: "the Save button", "the name field". */
|
|
184
|
+
target: z.string().min(1).max(200),
|
|
185
|
+
action: z.enum(UI_ACTIONS),
|
|
186
|
+
value: z.string().optional(),
|
|
187
|
+
window_id: z.string().min(1).optional(),
|
|
152
188
|
});
|
|
153
189
|
/** What a batch may carry: everything but the image-returning actions and another batch. */
|
|
154
190
|
const batchItemSchema = z.discriminatedUnion('type', [
|
|
@@ -163,6 +199,7 @@ const batchItemSchema = z.discriminatedUnion('type', [
|
|
|
163
199
|
listWindowsSchema,
|
|
164
200
|
focusWindowSchema,
|
|
165
201
|
uiActSchema,
|
|
202
|
+
uiDoSchema,
|
|
166
203
|
]);
|
|
167
204
|
const withFrame = { screenshot_id: screenshotIdSchema };
|
|
168
205
|
const actionSchema = z.discriminatedUnion('type', [
|
|
@@ -184,6 +221,7 @@ const actionSchema = z.discriminatedUnion('type', [
|
|
|
184
221
|
uiSnapshotSchema,
|
|
185
222
|
waitForSchema,
|
|
186
223
|
uiActSchema.extend(withFrame),
|
|
224
|
+
uiDoSchema.extend(withFrame),
|
|
187
225
|
z.object({
|
|
188
226
|
type: z.literal('batch'),
|
|
189
227
|
actions: z.array(batchItemSchema).min(1),
|
|
@@ -216,6 +254,7 @@ const ALL_ACTIONS = [
|
|
|
216
254
|
'ui_snapshot',
|
|
217
255
|
'wait_for',
|
|
218
256
|
'ui_act',
|
|
257
|
+
'ui_do',
|
|
219
258
|
'batch',
|
|
220
259
|
];
|
|
221
260
|
/** Observations: they change nothing on the desktop. */
|
|
@@ -235,6 +274,7 @@ const DESTRUCTIVE_ACTIONS = new Set([
|
|
|
235
274
|
'key',
|
|
236
275
|
'scroll',
|
|
237
276
|
'ui_act',
|
|
277
|
+
'ui_do',
|
|
238
278
|
]);
|
|
239
279
|
/** Observations that show the model what is on the screen, on their own. */
|
|
240
280
|
const SCREEN_OBSERVATIONS = new Set([
|
|
@@ -300,6 +340,7 @@ function requiredCapability(type) {
|
|
|
300
340
|
case 'ui_snapshot':
|
|
301
341
|
case 'wait_for':
|
|
302
342
|
case 'ui_act':
|
|
343
|
+
case 'ui_do':
|
|
303
344
|
return 'uiTree';
|
|
304
345
|
default:
|
|
305
346
|
return null;
|
|
@@ -317,7 +358,7 @@ function windowCaptureAvailable(host, caps) {
|
|
|
317
358
|
typeof host.captureWindow === 'function' &&
|
|
318
359
|
typeof host.executeWindow === 'function');
|
|
319
360
|
}
|
|
320
|
-
function availableActions(host, caps) {
|
|
361
|
+
function availableActions(host, caps, advisor) {
|
|
321
362
|
const displayScreenshot = hostActionAvailable(caps, 'screenshot');
|
|
322
363
|
const window = windowCaptureAvailable(host, caps);
|
|
323
364
|
const screenshot = displayScreenshot || window;
|
|
@@ -350,6 +391,8 @@ function availableActions(host, caps) {
|
|
|
350
391
|
case 'wait_for':
|
|
351
392
|
case 'ui_act':
|
|
352
393
|
return uiTree;
|
|
394
|
+
case 'ui_do':
|
|
395
|
+
return uiTree && advisor?.acts === true;
|
|
353
396
|
case 'batch':
|
|
354
397
|
return false;
|
|
355
398
|
default:
|
|
@@ -383,8 +426,8 @@ function unavailableHostActions(host, caps) {
|
|
|
383
426
|
// ---------------------------------------------------------------------------
|
|
384
427
|
// Model-facing description and schema
|
|
385
428
|
// ---------------------------------------------------------------------------
|
|
386
|
-
function buildDescription(host, caps, settings) {
|
|
387
|
-
const available = availableActions(host, caps);
|
|
429
|
+
function buildDescription(host, caps, settings, advisor) {
|
|
430
|
+
const available = availableActions(host, caps, advisor);
|
|
388
431
|
const unavailable = unavailableHostActions(host, caps);
|
|
389
432
|
const intro = hostActionAvailable(caps, 'screenshot')
|
|
390
433
|
? `Controls the user's desktop on a ${caps.displayServer} host: screenshots, mouse and keyboard, for GUI tasks.`
|
|
@@ -413,6 +456,8 @@ function buildDescription(host, caps, settings) {
|
|
|
413
456
|
available.includes('key') &&
|
|
414
457
|
available.includes('type_text'))
|
|
415
458
|
lines.push('To start a Windows program, a shell command (Start-Process <program>, or cmd.exe /c start <program>) is surest when you have a shell tool. The Start menu searches by display names in the system language, and ENTER on a name it does not find opens a web search in the browser.');
|
|
459
|
+
if (available.includes('ui_do'))
|
|
460
|
+
lines.push('ui_do {target, action, value, window_id} acts on a control named in words ("the Save button") among those the latest ui_snapshot showed: a second model chooses it and the tool says which control it acted on. When it is not sure it acts on nothing and lists the closest controls: then use ui_act on one of their refs. Use ui_act with a ref whenever you already have one.');
|
|
416
461
|
if (available.includes('list_windows'))
|
|
417
462
|
lines.push('list_windows names the open windows with their ids; focus_window brings one to the front.');
|
|
418
463
|
if (windowCaptureAvailable(host, caps))
|
|
@@ -487,6 +532,7 @@ const ACTION_REQUIREMENTS = {
|
|
|
487
532
|
ui_snapshot: 'ui_snapshot takes an optional window_id, root (a ref to open) and query (text to find)',
|
|
488
533
|
wait_for: 'wait_for needs until and match; role, window_id and timeout_ms are optional',
|
|
489
534
|
ui_act: 'ui_act needs ref and action, and value for set_value',
|
|
535
|
+
ui_do: 'ui_do needs target (the control, in words) and action, and value for set_value',
|
|
490
536
|
batch: 'batch needs actions',
|
|
491
537
|
};
|
|
492
538
|
function actionRequirement(action, host, caps) {
|
|
@@ -494,10 +540,10 @@ function actionRequirement(action, host, caps) {
|
|
|
494
540
|
? `screenshot ${hostActionAvailable(caps, 'screenshot') ? 'takes an optional' : 'requires'} window_id to capture pixels for that window`
|
|
495
541
|
: ACTION_REQUIREMENTS[action];
|
|
496
542
|
}
|
|
497
|
-
function hostModelSchema(host, caps, settings) {
|
|
543
|
+
function hostModelSchema(host, caps, settings, advisor) {
|
|
498
544
|
// An unavailable host remains a diagnostic tool. Avoid invalid empty enums
|
|
499
545
|
// on provider wires; every execution is still refused before host access.
|
|
500
|
-
const offered = availableActions(host, caps);
|
|
546
|
+
const offered = availableActions(host, caps, advisor);
|
|
501
547
|
const actions = offered.length > 0 ? offered : ALL_ACTIONS.filter((a) => a !== 'batch');
|
|
502
548
|
const items = actions.filter((action) => !OUTSIDE_BATCH.has(action));
|
|
503
549
|
const buttons = new Set();
|
|
@@ -613,6 +659,28 @@ function hostModelSchema(host, caps, settings) {
|
|
|
613
659
|
type: 'string',
|
|
614
660
|
description: 'The text set_value puts in the control.',
|
|
615
661
|
};
|
|
662
|
+
if (advisor)
|
|
663
|
+
fields.intent = {
|
|
664
|
+
type: 'string',
|
|
665
|
+
description: 'For ui_act: what this is for, in a few words ("save the file"). Optional; it only helps check the choice.',
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
if (present.includes('ui_do')) {
|
|
669
|
+
fields.target = {
|
|
670
|
+
type: 'string',
|
|
671
|
+
description: 'For ui_do: the control in words, such as "the Save button" or "the name field". The tool picks the control from the latest ui_snapshot.',
|
|
672
|
+
};
|
|
673
|
+
if (!present.includes('ui_act')) {
|
|
674
|
+
fields.action = {
|
|
675
|
+
type: 'string',
|
|
676
|
+
enum: [...UI_ACTIONS],
|
|
677
|
+
description: 'What ui_do does to the control.',
|
|
678
|
+
};
|
|
679
|
+
fields.value = {
|
|
680
|
+
type: 'string',
|
|
681
|
+
description: 'The text set_value puts in the control.',
|
|
682
|
+
};
|
|
683
|
+
}
|
|
616
684
|
}
|
|
617
685
|
if (!forItems && present.includes('zoom'))
|
|
618
686
|
fields.region = {
|
|
@@ -719,6 +787,28 @@ function uiActLabel(input, describe) {
|
|
|
719
787
|
return `Scroll to ${target}`;
|
|
720
788
|
}
|
|
721
789
|
}
|
|
790
|
+
/** What a ui_do does, over the words the model named the control with. */
|
|
791
|
+
function uiDoLabel(input) {
|
|
792
|
+
const target = quotedText(input.target);
|
|
793
|
+
switch (input.action) {
|
|
794
|
+
case 'invoke':
|
|
795
|
+
return `Press the control for ${target}`;
|
|
796
|
+
case 'set_value':
|
|
797
|
+
return `Set the control for ${target} to ${quotedText(input.value ?? '')}`;
|
|
798
|
+
case 'toggle':
|
|
799
|
+
return `Toggle the control for ${target}`;
|
|
800
|
+
case 'select':
|
|
801
|
+
return `Select the control for ${target}`;
|
|
802
|
+
case 'expand':
|
|
803
|
+
return `Expand the control for ${target}`;
|
|
804
|
+
case 'collapse':
|
|
805
|
+
return `Collapse the control for ${target}`;
|
|
806
|
+
case 'focus':
|
|
807
|
+
return `Focus the control for ${target}`;
|
|
808
|
+
case 'scroll_into_view':
|
|
809
|
+
return `Scroll to the control for ${target}`;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
722
812
|
/**
|
|
723
813
|
* Human activity text for one action; the raw input remains the model-facing
|
|
724
814
|
* record. `describe` names a ui_act ref's control when the tool knows it.
|
|
@@ -759,6 +849,8 @@ function itemLabel(input, describe) {
|
|
|
759
849
|
return `Wait until ${input.until.replace('_', ' ')} ${quotedText(input.match)}`;
|
|
760
850
|
case 'ui_act':
|
|
761
851
|
return uiActLabel(input, describe);
|
|
852
|
+
case 'ui_do':
|
|
853
|
+
return uiDoLabel(input);
|
|
762
854
|
case 'batch':
|
|
763
855
|
return batchLabel(input.actions, describe);
|
|
764
856
|
}
|
|
@@ -973,13 +1065,16 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
973
1065
|
}
|
|
974
1066
|
: host.capabilities;
|
|
975
1067
|
const frames = new ScreenshotFrames();
|
|
976
|
-
const available = new Set(availableActions(host, caps));
|
|
1068
|
+
const available = new Set(availableActions(host, caps, options.advisor));
|
|
1069
|
+
const advisor = options.advisor;
|
|
977
1070
|
// The controls of the latest ui_snapshot, by the ref the model was shown.
|
|
978
1071
|
// A ref names a control, not one reading of it: the same host ref keeps the
|
|
979
1072
|
// same number in every snapshot, and a number is never reused for another
|
|
980
1073
|
// control. Whether the control is still there is the host's answer.
|
|
981
1074
|
const uiRefs = new Map();
|
|
982
1075
|
const uiRefByHost = new Map();
|
|
1076
|
+
// The refs the latest reading of each window showed, so an advisor is asked about what is there now.
|
|
1077
|
+
const shownRefs = new Map();
|
|
983
1078
|
let uiSnapshots = 0;
|
|
984
1079
|
let uiRefCount = 0;
|
|
985
1080
|
let uiSnapshotWindowId;
|
|
@@ -993,6 +1088,31 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
993
1088
|
return entry ? `${uiElementText(entry.element)} (${ref})` : undefined;
|
|
994
1089
|
};
|
|
995
1090
|
const label = (input) => itemLabel(input, describeUiRef);
|
|
1091
|
+
/** The controls of a window's latest reading that offer an action (any, when none is named), as an advisor is shown them. */
|
|
1092
|
+
const advisedCandidates = (windowId, action) => {
|
|
1093
|
+
const shown = shownRefs.get(windowId ?? '');
|
|
1094
|
+
const out = [];
|
|
1095
|
+
if (!shown)
|
|
1096
|
+
return out;
|
|
1097
|
+
for (const ref of shown) {
|
|
1098
|
+
const entry = uiRefs.get(ref);
|
|
1099
|
+
if (!entry)
|
|
1100
|
+
continue;
|
|
1101
|
+
const offered = entry.element.actions ?? [];
|
|
1102
|
+
if (offered.length === 0)
|
|
1103
|
+
continue;
|
|
1104
|
+
if (action !== undefined && !offered.includes(action))
|
|
1105
|
+
continue;
|
|
1106
|
+
const text = uiElementText(entry.element);
|
|
1107
|
+
out.push({
|
|
1108
|
+
ref,
|
|
1109
|
+
description: text.length > 80 ? `${text.slice(0, 79)}…` : text,
|
|
1110
|
+
});
|
|
1111
|
+
if (out.length >= MAX_ADVISED_CANDIDATES)
|
|
1112
|
+
break;
|
|
1113
|
+
}
|
|
1114
|
+
return out;
|
|
1115
|
+
};
|
|
996
1116
|
const refusal = (type) => {
|
|
997
1117
|
if (available.has(type))
|
|
998
1118
|
return null;
|
|
@@ -1242,6 +1362,14 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1242
1362
|
if (item.action === 'set_value' && item.value === undefined)
|
|
1243
1363
|
throw new StepFailure('set_value needs value, the text to put in the control');
|
|
1244
1364
|
return step(async () => {
|
|
1365
|
+
// A second opinion on the model's own choice: asked beside the action, never waited for.
|
|
1366
|
+
if (advisor && item.intent !== undefined) {
|
|
1367
|
+
const candidates = advisedCandidates(entry.windowId);
|
|
1368
|
+
if (candidates.length >= 2)
|
|
1369
|
+
void advisor
|
|
1370
|
+
.pick({ intent: item.intent, candidates, chosen: item.ref })
|
|
1371
|
+
.catch(() => undefined);
|
|
1372
|
+
}
|
|
1245
1373
|
let outcome;
|
|
1246
1374
|
try {
|
|
1247
1375
|
outcome = await host.uiAct(entry.hostRef, item.action, item.value, callSignal);
|
|
@@ -1260,6 +1388,56 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1260
1388
|
return deliveryOutcome(outcome);
|
|
1261
1389
|
});
|
|
1262
1390
|
}
|
|
1391
|
+
case 'ui_do': {
|
|
1392
|
+
if (!advisor?.acts)
|
|
1393
|
+
throw new StepFailure('ui_do is not available here; use ui_act with a ref');
|
|
1394
|
+
if (item.action === 'set_value' && item.value === undefined)
|
|
1395
|
+
throw new StepFailure('set_value needs value, the text to put in the control');
|
|
1396
|
+
if (uiSnapshots === 0)
|
|
1397
|
+
throw new StepFailure('no ui_snapshot has been taken yet; take one, because ui_do chooses among the controls it showed');
|
|
1398
|
+
const windowId = item.window_id ?? uiSnapshotWindowId;
|
|
1399
|
+
const candidates = advisedCandidates(windowId, item.action);
|
|
1400
|
+
if (candidates.length === 0)
|
|
1401
|
+
throw new StepFailure(`no control in the latest ui_snapshot${windowId ? ` of window ${windowId}` : ''} offers ${item.action}; take a ui_snapshot and act with ui_act on a ref`);
|
|
1402
|
+
const target = item.target;
|
|
1403
|
+
return step(async (signal) => {
|
|
1404
|
+
let advice;
|
|
1405
|
+
try {
|
|
1406
|
+
advice = await advisor.pick({ intent: target, candidates }, signal);
|
|
1407
|
+
}
|
|
1408
|
+
catch {
|
|
1409
|
+
if (signal?.aborted)
|
|
1410
|
+
throw new StepFailure('cancelled');
|
|
1411
|
+
}
|
|
1412
|
+
const [best, next] = advice?.ranked ?? [];
|
|
1413
|
+
const sure = best !== undefined &&
|
|
1414
|
+
best.confidence >= ADVICE_MIN_CONFIDENCE &&
|
|
1415
|
+
best.confidence - (next?.confidence ?? 0) >= ADVICE_MIN_MARGIN &&
|
|
1416
|
+
uiRefs.has(best.ref);
|
|
1417
|
+
if (!best || !sure) {
|
|
1418
|
+
const close = (advice?.ranked ?? [])
|
|
1419
|
+
.filter((entry) => uiRefs.has(entry.ref))
|
|
1420
|
+
.slice(0, 3)
|
|
1421
|
+
.map((entry) => describeUiRef(entry.ref));
|
|
1422
|
+
throw deliveryFailure({
|
|
1423
|
+
delivery: 'not_delivered',
|
|
1424
|
+
retrySafety: 'safe',
|
|
1425
|
+
detail: `ui_do was not sure which control is ${quotedText(target)}, so it acted on nothing.${close.length > 0 ? ` Closest: ${close.join('; ')}.` : ''} Use ui_act on one of the refs, or ui_snapshot {query: ...} to find it.`,
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
const chosen = describeUiRef(best.ref) ?? best.ref;
|
|
1429
|
+
const ran = await plan({
|
|
1430
|
+
type: 'ui_act',
|
|
1431
|
+
ref: best.ref,
|
|
1432
|
+
action: item.action,
|
|
1433
|
+
...(item.value !== undefined ? { value: item.value } : {}),
|
|
1434
|
+
}, undefined).run(signal);
|
|
1435
|
+
const prefix = `chose ${chosen} for ${quotedText(target)} (${Math.round(best.confidence * 100)}% sure)`;
|
|
1436
|
+
return typeof ran === 'string'
|
|
1437
|
+
? `${prefix}: ${ran}`
|
|
1438
|
+
: { ...ran, note: `${prefix}: ${ran.note}` };
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1263
1441
|
}
|
|
1264
1442
|
};
|
|
1265
1443
|
/** Read one window's controls, number the ones the model can act on, and show them. */
|
|
@@ -1344,6 +1522,11 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1344
1522
|
}
|
|
1345
1523
|
}
|
|
1346
1524
|
uiSnapshotWindowId = snapshot.windowId ?? requestedWindowId;
|
|
1525
|
+
{
|
|
1526
|
+
const key = uiSnapshotWindowId ?? '';
|
|
1527
|
+
const now = new Set(refs.keys());
|
|
1528
|
+
shownRefs.set(key, snapshot.region ? new Set([...(shownRefs.get(key) ?? []), ...now]) : now);
|
|
1529
|
+
}
|
|
1347
1530
|
if (uiSnapshotWindowId !== undefined)
|
|
1348
1531
|
treeUsable.set(uiSnapshotWindowId, refs.size > 0);
|
|
1349
1532
|
uiSnapshotFrame = frames.latest();
|
|
@@ -1815,7 +1998,7 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1815
1998
|
const outcome = typeof ran === 'string' ? { note: ran } : ran;
|
|
1816
1999
|
if (step.item.type === 'focus_window' && windowCaptureAvailable(host, caps))
|
|
1817
2000
|
postWindowId = step.item.window_id;
|
|
1818
|
-
else if (step.item.type === 'ui_act' &&
|
|
2001
|
+
else if ((step.item.type === 'ui_act' || step.item.type === 'ui_do') &&
|
|
1819
2002
|
uiSnapshotWindowId &&
|
|
1820
2003
|
!explicitDisplayFrame &&
|
|
1821
2004
|
windowCaptureAvailable(host, caps))
|
|
@@ -1869,7 +2052,7 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1869
2052
|
let shotError;
|
|
1870
2053
|
if (looks) {
|
|
1871
2054
|
try {
|
|
1872
|
-
await
|
|
2055
|
+
await settleAfterActions(host, postWindowId, settings.settleMs, signal);
|
|
1873
2056
|
shot = await capture(postWindowId);
|
|
1874
2057
|
}
|
|
1875
2058
|
catch (error) {
|
|
@@ -1964,9 +2147,9 @@ export function createComputerUseTool(host, options = {}) {
|
|
|
1964
2147
|
const capturesScreen = (input) => observes && capturesScreenInput(input, settings.screenshotAfterActions);
|
|
1965
2148
|
const tool = defineTool({
|
|
1966
2149
|
name: COMPUTER_USE_TOOL_NAME,
|
|
1967
|
-
description: buildDescription(host, caps, settings),
|
|
2150
|
+
description: buildDescription(host, caps, settings, options.advisor),
|
|
1968
2151
|
inputSchema: actionSchema,
|
|
1969
|
-
modelInputSchema: hostModelSchema(host, caps, settings),
|
|
2152
|
+
modelInputSchema: hostModelSchema(host, caps, settings, options.advisor),
|
|
1970
2153
|
validationErrorHint: `Action requirements: ${ALL_ACTIONS.map((action) => actionRequirement(action, host, caps)).join('; ')}. A batch is {"type":"batch","actions":[...]} with at most ${settings.maxBatchActions} actions and no screenshot, zoom, ui_snapshot or batch inside.`,
|
|
1971
2154
|
category: 'custom',
|
|
1972
2155
|
permissions: [],
|