@opengeni/runtime 3.3.0 → 3.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/dist/agent-LJT5NPWT.js +9 -0
- package/dist/assets/codemode-client.json +1 -1
- package/dist/browser-current-tab.d.ts +46 -0
- package/dist/browser-model-text.d.ts +126 -0
- package/dist/{chunk-XRX57ZQO.js → chunk-3DFH3ZHU.js} +784 -121
- package/dist/chunk-3DFH3ZHU.js.map +1 -0
- package/dist/{chunk-HJSIPTFA.js → chunk-4XDJ4TJA.js} +2 -2
- package/dist/{chunk-XQ23VCZ4.js → chunk-6FQ6KEII.js} +3 -3
- package/dist/{chunk-7LJ7KDPI.js → chunk-ERD4ICVB.js} +4 -3
- package/dist/{chunk-EK7IW2FR.js → chunk-ETTCGPBT.js} +224 -6
- package/dist/chunk-ETTCGPBT.js.map +1 -0
- package/dist/{chunk-7OUG7WBV.js → chunk-GWRBALGQ.js} +181 -13
- package/dist/chunk-GWRBALGQ.js.map +1 -0
- package/dist/{chunk-YG26XE7B.js → chunk-JYDG2A7H.js} +2 -2
- package/dist/{chunk-RSHQSLEJ.js → chunk-KIL4FGX5.js} +3 -3
- package/dist/{chunk-NWS4HPB7.js → chunk-MIAL5I4O.js} +2 -2
- package/dist/{chunk-Z5U6WE22.js → chunk-PRZPGRIK.js} +2 -2
- package/dist/{chunk-KCPW4K7L.js → chunk-PZQUUBEB.js} +2 -2
- package/dist/{chunk-5WJOPANS.js → chunk-Y5THZH5N.js} +7 -7
- package/dist/codex-tool-search.d.ts +9 -0
- package/dist/gmail-rest-mcp.js +8 -8
- package/dist/index.d.ts +3 -0
- package/dist/index.js +14 -12
- package/dist/interaction-tool-json-schema.d.ts +27 -0
- package/dist/{lazy-manifest-AJ6XPJ4F.js → lazy-manifest-BLZ3UZLX.js} +4 -4
- package/dist/lazy-tool-transport.d.ts +10 -0
- package/dist/{localSources-SSIEH5F5.js → localSources-I6SIQ6CX.js} +6 -6
- package/dist/model-call.js +3 -3
- package/dist/sandbox/browser-control-client.d.ts +77 -0
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +7 -7
- package/dist/sandbox/selfhosted/session.d.ts +3 -0
- package/dist/slack-rest-mcp.js +8 -8
- package/dist/workspace-tool-gateway.js +12 -12
- package/package.json +14 -14
- package/src/browser-current-tab.ts +139 -0
- package/src/browser-model-text.ts +378 -0
- package/src/codex-tool-search.ts +53 -0
- package/src/index.ts +39 -1
- package/src/interaction-tool-json-schema.ts +281 -0
- package/src/interaction-tools.ts +425 -235
- package/src/lazy-tool-transport.ts +229 -10
- package/src/model-input.ts +12 -1
- package/src/sandbox/browser-control-client.ts +336 -0
- package/src/sandbox/index.ts +4 -0
- package/src/sandbox/selfhosted/session.ts +38 -0
- package/dist/agent-CTPLA3HP.js +0 -9
- package/dist/browser-action-json-schema.d.ts +0 -4
- package/dist/chunk-7OUG7WBV.js.map +0 -1
- package/dist/chunk-EK7IW2FR.js.map +0 -1
- package/dist/chunk-XRX57ZQO.js.map +0 -1
- package/src/browser-action-json-schema.ts +0 -10
- /package/dist/{agent-CTPLA3HP.js.map → agent-LJT5NPWT.js.map} +0 -0
- /package/dist/{chunk-HJSIPTFA.js.map → chunk-4XDJ4TJA.js.map} +0 -0
- /package/dist/{chunk-XQ23VCZ4.js.map → chunk-6FQ6KEII.js.map} +0 -0
- /package/dist/{chunk-7LJ7KDPI.js.map → chunk-ERD4ICVB.js.map} +0 -0
- /package/dist/{chunk-YG26XE7B.js.map → chunk-JYDG2A7H.js.map} +0 -0
- /package/dist/{chunk-RSHQSLEJ.js.map → chunk-KIL4FGX5.js.map} +0 -0
- /package/dist/{chunk-NWS4HPB7.js.map → chunk-MIAL5I4O.js.map} +0 -0
- /package/dist/{chunk-Z5U6WE22.js.map → chunk-PRZPGRIK.js.map} +0 -0
- /package/dist/{chunk-KCPW4K7L.js.map → chunk-PZQUUBEB.js.map} +0 -0
- /package/dist/{chunk-5WJOPANS.js.map → chunk-Y5THZH5N.js.map} +0 -0
- /package/dist/{lazy-manifest-AJ6XPJ4F.js.map → lazy-manifest-BLZ3UZLX.js.map} +0 -0
- /package/dist/{localSources-SSIEH5F5.js.map → localSources-I6SIQ6CX.js.map} +0 -0
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
withCommandNotStartedCallProof,
|
|
22
22
|
withRunCredentialsClient,
|
|
23
23
|
withRunCredentialsSession
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-ETTCGPBT.js";
|
|
25
25
|
import {
|
|
26
26
|
SKILL_MAX_FILES,
|
|
27
27
|
SKILL_READ_MAX_OUTPUT_BYTES,
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
estimateCompleteModelInputTokens,
|
|
59
59
|
estimateSerializedValueTokens,
|
|
60
60
|
estimateTextTokens,
|
|
61
|
+
expandInteractionFamilyDisclosures,
|
|
61
62
|
extractOpenSuffixMembers,
|
|
62
63
|
extractRemoteCompactionV2OutputItem,
|
|
63
64
|
hasModelGeneratedItem,
|
|
@@ -101,19 +102,19 @@ import {
|
|
|
101
102
|
withModelRequestCapture,
|
|
102
103
|
withModelTransportStartedObserver,
|
|
103
104
|
withPreparedCompactionRequest
|
|
104
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-GWRBALGQ.js";
|
|
105
106
|
import {
|
|
106
107
|
GMAIL_REST_MCP_BRIDGE_ADAPTER,
|
|
107
108
|
gmailRestResultOutcome,
|
|
108
109
|
isOfficialGmailMcpConfig
|
|
109
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-6FQ6KEII.js";
|
|
110
111
|
import {
|
|
111
112
|
SLACK_REST_MCP_BRIDGE_ADAPTER
|
|
112
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-KIL4FGX5.js";
|
|
113
114
|
import {
|
|
114
115
|
ConnectorAttachmentTransferError,
|
|
115
116
|
projectConnectorAttachmentTransfers
|
|
116
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-PRZPGRIK.js";
|
|
117
118
|
import {
|
|
118
119
|
SelfhostedControlError,
|
|
119
120
|
SynchronousCommandOutcomeUnknownError,
|
|
@@ -127,15 +128,15 @@ import {
|
|
|
127
128
|
runWithToolCallCorrelation,
|
|
128
129
|
withRoutingMutationOutputRejectionFence,
|
|
129
130
|
wrapCapabilityToolsForTurnCancellation
|
|
130
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-Y5THZH5N.js";
|
|
131
132
|
import {
|
|
132
133
|
SandboxAgent,
|
|
133
134
|
filesystem,
|
|
134
135
|
shell
|
|
135
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-4XDJ4TJA.js";
|
|
136
137
|
import {
|
|
137
138
|
connectMcpServers
|
|
138
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-PZQUUBEB.js";
|
|
139
140
|
import {
|
|
140
141
|
Agent,
|
|
141
142
|
AgentsError,
|
|
@@ -151,6 +152,7 @@ import {
|
|
|
151
152
|
Usage,
|
|
152
153
|
applyDiff,
|
|
153
154
|
azureBlobMount,
|
|
155
|
+
defineToolInputGuardrail,
|
|
154
156
|
dir,
|
|
155
157
|
external_exports,
|
|
156
158
|
file,
|
|
@@ -162,7 +164,7 @@ import {
|
|
|
162
164
|
setDefaultModelProvider,
|
|
163
165
|
setTracingDisabled,
|
|
164
166
|
tool
|
|
165
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-ERD4ICVB.js";
|
|
166
168
|
import {
|
|
167
169
|
MCP_MAX_CONCURRENT_SERVER_OPERATIONS,
|
|
168
170
|
MCP_MAX_RESPONSE_BYTES,
|
|
@@ -384,13 +386,520 @@ import {
|
|
|
384
386
|
interactionControlFailureFromError
|
|
385
387
|
} from "@opengeni/sdk";
|
|
386
388
|
|
|
387
|
-
// src/browser-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
389
|
+
// src/browser-current-tab.ts
|
|
390
|
+
var BrowserTargetResolutionError = class extends Error {
|
|
391
|
+
constructor(code, message) {
|
|
392
|
+
super(message);
|
|
393
|
+
this.code = code;
|
|
394
|
+
this.name = "BrowserTargetResolutionError";
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var CurrentBrowserTab = class {
|
|
398
|
+
constructor(deps) {
|
|
399
|
+
this.deps = deps;
|
|
400
|
+
}
|
|
401
|
+
current = null;
|
|
402
|
+
/** Record the session and, when known, the tab a successful call used. */
|
|
403
|
+
use(browserSessionId, targetId) {
|
|
404
|
+
if (targetId === void 0) {
|
|
405
|
+
if (this.current?.browserSessionId !== browserSessionId) {
|
|
406
|
+
this.current = { browserSessionId, targetId: null };
|
|
407
|
+
}
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.current = { browserSessionId, targetId };
|
|
411
|
+
}
|
|
412
|
+
forgetTarget(browserSessionId, targetId) {
|
|
413
|
+
if (this.current?.browserSessionId === browserSessionId && this.current.targetId === targetId) {
|
|
414
|
+
this.current = { browserSessionId, targetId: null };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
forgetSession(browserSessionId) {
|
|
418
|
+
if (this.current?.browserSessionId === browserSessionId) this.current = null;
|
|
419
|
+
}
|
|
420
|
+
/** A call that relied on remembered identifiers failed: resolve afresh next time. */
|
|
421
|
+
failed(resolved) {
|
|
422
|
+
if (resolved.implicit) this.forgetSession(resolved.browserSessionId);
|
|
423
|
+
else if (resolved.implicitTarget && this.current?.browserSessionId === resolved.browserSessionId) {
|
|
424
|
+
this.current = { browserSessionId: resolved.browserSessionId, targetId: null };
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async session(browserSessionId) {
|
|
428
|
+
if (browserSessionId !== void 0) return { browserSessionId, implicit: false };
|
|
429
|
+
if (this.current) return { browserSessionId: this.current.browserSessionId, implicit: true };
|
|
430
|
+
const sessions = [...await this.deps.listLiveSessions()].sort(
|
|
431
|
+
(left, right) => right.lastUsedAt.localeCompare(left.lastUsedAt)
|
|
432
|
+
);
|
|
433
|
+
const latest = sessions[0];
|
|
434
|
+
if (!latest) {
|
|
435
|
+
throw new BrowserTargetResolutionError(
|
|
436
|
+
"browser_session_required",
|
|
437
|
+
"This session has no open browser. Call browser_open first, or pass browserSessionId."
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
return { browserSessionId: latest.id, implicit: true };
|
|
441
|
+
}
|
|
442
|
+
async target(value) {
|
|
443
|
+
const session = await this.session(value.browserSessionId);
|
|
444
|
+
if (value.targetId !== void 0) {
|
|
445
|
+
return { ...session, targetId: value.targetId, implicitTarget: false };
|
|
446
|
+
}
|
|
447
|
+
if (this.current?.browserSessionId === session.browserSessionId && this.current.targetId) {
|
|
448
|
+
return { ...session, targetId: this.current.targetId, implicitTarget: true };
|
|
449
|
+
}
|
|
450
|
+
const pages = (await this.deps.listTargets(session.browserSessionId)).filter(
|
|
451
|
+
(target) => target.kind === "page" || target.kind === "popup"
|
|
452
|
+
);
|
|
453
|
+
const chosen = pages.find((target) => target.selected) ?? (pages.length === 1 ? pages[0] : null);
|
|
454
|
+
if (!chosen) {
|
|
455
|
+
throw new BrowserTargetResolutionError(
|
|
456
|
+
"browser_target_required",
|
|
457
|
+
pages.length === 0 ? "This browser has no open tab. Open one with browser_tabs operation=open." : `This browser has ${pages.length} tabs and none is selected. Pass targetId from browser_tabs operation=list.`
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
return { ...session, targetId: chosen.id, implicitTarget: true };
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
function expandRefShorthand(action) {
|
|
464
|
+
if (!action || typeof action !== "object" || Array.isArray(action)) return action;
|
|
465
|
+
const record = action;
|
|
466
|
+
let expanded = null;
|
|
467
|
+
for (const field of ["locator", "from", "to"]) {
|
|
468
|
+
const value = record[field];
|
|
469
|
+
if (typeof value === "string") {
|
|
470
|
+
expanded ??= { ...record };
|
|
471
|
+
expanded[field] = { kind: "ref", ref: value };
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (Array.isArray(record.actions)) {
|
|
475
|
+
expanded ??= { ...record };
|
|
476
|
+
expanded.actions = record.actions.map(expandRefShorthand);
|
|
477
|
+
}
|
|
478
|
+
return expanded ?? action;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/interaction-tool-json-schema.ts
|
|
482
|
+
var VALIDATION_ONLY_KEYWORDS = /* @__PURE__ */ new Set(["$schema", "$id", "minLength", "maxLength"]);
|
|
483
|
+
var MEANINGFUL_NUMERIC_BOUND = 1e5;
|
|
484
|
+
var MEANINGFUL_MAX_ITEMS = 64;
|
|
485
|
+
var MEANINGFUL_PATTERN_LENGTH = 32;
|
|
486
|
+
function interactionToolInputJsonSchema(schema) {
|
|
487
|
+
const generated = external_exports.toJSONSchema(schema, { target: "draft-2020-12" });
|
|
488
|
+
return modelFacingSchema(generated);
|
|
489
|
+
}
|
|
490
|
+
var flattenedVariants = /* @__PURE__ */ new WeakMap();
|
|
491
|
+
var LOCATOR_FIELDS = /* @__PURE__ */ new Set(["locator", "from", "to"]);
|
|
492
|
+
function withRefShorthandLocators(schema) {
|
|
493
|
+
return refShorthand(schema);
|
|
494
|
+
}
|
|
495
|
+
function refShorthand(node) {
|
|
496
|
+
if (Array.isArray(node)) return node.map(refShorthand);
|
|
497
|
+
if (!isNode(node)) return node;
|
|
498
|
+
const out = {};
|
|
499
|
+
for (const [key, value] of Object.entries(node)) {
|
|
500
|
+
if (key !== "properties" || !isNode(value)) {
|
|
501
|
+
out[key] = refShorthand(value);
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const properties = {};
|
|
505
|
+
for (const [field, schema] of Object.entries(value)) {
|
|
506
|
+
properties[field] = LOCATOR_FIELDS.has(field) && isRefLocator(schema) ? { anyOf: [{ type: "string", description: "An element ref." }, refShorthand(schema)] } : refShorthand(schema);
|
|
507
|
+
}
|
|
508
|
+
out[key] = properties;
|
|
509
|
+
}
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
512
|
+
function isRefLocator(schema) {
|
|
513
|
+
if (!isNode(schema)) return false;
|
|
514
|
+
if (Array.isArray(schema.anyOf)) return schema.anyOf.some(isRefLocator);
|
|
515
|
+
return isNode(schema.properties) && (tagValues(schema.properties.kind) ?? []).includes("ref");
|
|
516
|
+
}
|
|
517
|
+
function modelFacingSchema(node) {
|
|
518
|
+
if (Array.isArray(node)) return node.map(modelFacingSchema);
|
|
519
|
+
if (!isNode(node)) return node;
|
|
520
|
+
const out = {};
|
|
521
|
+
for (const [key, value] of Object.entries(node)) {
|
|
522
|
+
if (VALIDATION_ONLY_KEYWORDS.has(key)) continue;
|
|
523
|
+
if (key === "additionalProperties" && value === false) continue;
|
|
524
|
+
if ((key === "minimum" || key === "maximum") && typeof value === "number" && Math.abs(value) >= MEANINGFUL_NUMERIC_BOUND) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
if (key === "minItems" && typeof value === "number" && value <= 1) continue;
|
|
528
|
+
if (key === "maxItems" && typeof value === "number" && value > MEANINGFUL_MAX_ITEMS) continue;
|
|
529
|
+
if (key === "pattern" && typeof value === "string" && value.length > MEANINGFUL_PATTERN_LENGTH) {
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
out[key] = modelFacingSchema(value);
|
|
533
|
+
}
|
|
534
|
+
for (const unionKey of ["oneOf", "anyOf"]) {
|
|
535
|
+
const members = out[unionKey];
|
|
536
|
+
if (!Array.isArray(members)) continue;
|
|
537
|
+
const flattened = flattenTaggedUnion(members);
|
|
538
|
+
if (!flattened) continue;
|
|
539
|
+
delete out[unionKey];
|
|
540
|
+
const { description, ...rest } = flattened;
|
|
541
|
+
Object.assign(out, rest);
|
|
542
|
+
const own = typeof out.description === "string" ? out.description : "";
|
|
543
|
+
out.description = own ? `${own} ${String(description)}` : description;
|
|
544
|
+
flattenedVariants.set(out, flattenedVariants.get(flattened) ?? []);
|
|
545
|
+
}
|
|
546
|
+
return out;
|
|
547
|
+
}
|
|
548
|
+
function flattenTaggedUnion(members) {
|
|
549
|
+
if (members.length < 2 || !members.every(isObjectSchema)) return null;
|
|
550
|
+
const objects = members;
|
|
551
|
+
const tag = ["type", "kind", "operation"].find(
|
|
552
|
+
(candidate) => objects.every((member) => tagValues(member.properties[candidate]) !== null)
|
|
553
|
+
);
|
|
554
|
+
if (!tag) return null;
|
|
555
|
+
const variants = [];
|
|
556
|
+
const tagValuesInOrder = [];
|
|
557
|
+
const properties = /* @__PURE__ */ new Map();
|
|
558
|
+
for (const member of objects) {
|
|
559
|
+
const nested = flattenedVariants.get(member);
|
|
560
|
+
const required = new Set(Array.isArray(member.required) ? member.required : []);
|
|
561
|
+
if (nested) {
|
|
562
|
+
variants.push(...nested);
|
|
563
|
+
} else {
|
|
564
|
+
const fields = Object.keys(member.properties).filter((field) => field !== tag).map((field) => required.has(field) ? field : `${field}?`);
|
|
565
|
+
for (const value of tagValues(member.properties[tag])) variants.push([value, fields]);
|
|
566
|
+
}
|
|
567
|
+
for (const value of tagValues(member.properties[tag])) {
|
|
568
|
+
if (!tagValuesInOrder.includes(value)) tagValuesInOrder.push(value);
|
|
569
|
+
}
|
|
570
|
+
for (const [field, schema] of Object.entries(member.properties)) {
|
|
571
|
+
if (field === tag) continue;
|
|
572
|
+
const seen = properties.get(field) ?? [];
|
|
573
|
+
if (!seen.some((existing) => sameSchema(existing, schema))) seen.push(schema);
|
|
574
|
+
properties.set(field, seen);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const merged = {
|
|
578
|
+
[tag]: { type: "string", enum: tagValuesInOrder }
|
|
579
|
+
};
|
|
580
|
+
for (const [field, schemas] of properties) {
|
|
581
|
+
merged[field] = schemas.length === 1 ? schemas[0] : mergeAlternatives(schemas);
|
|
582
|
+
}
|
|
583
|
+
const summary = mergeSameTagVariants(variants).map(([value, fields]) => fields.length > 0 ? `${value}: ${fields.join(", ")}` : value).join("; ");
|
|
584
|
+
const flattened = {
|
|
585
|
+
type: "object",
|
|
586
|
+
properties: merged,
|
|
587
|
+
required: [tag],
|
|
588
|
+
description: `Fields by ${tag} (? = optional): ${summary}.`
|
|
589
|
+
};
|
|
590
|
+
flattenedVariants.set(flattened, variants);
|
|
591
|
+
return flattened;
|
|
592
|
+
}
|
|
593
|
+
function mergeSameTagVariants(variants) {
|
|
594
|
+
const byValue = /* @__PURE__ */ new Map();
|
|
595
|
+
for (const [value, fields] of variants) {
|
|
596
|
+
const seen = byValue.get(value) ?? [];
|
|
597
|
+
seen.push(fields);
|
|
598
|
+
byValue.set(value, seen);
|
|
599
|
+
}
|
|
600
|
+
return [...byValue].map(([value, members]) => {
|
|
601
|
+
if (members.length === 1) return [value, members[0]];
|
|
602
|
+
const names = [];
|
|
603
|
+
for (const fields of members) {
|
|
604
|
+
for (const field of fields) {
|
|
605
|
+
const name = field.endsWith("?") ? field.slice(0, -1) : field;
|
|
606
|
+
if (!names.includes(name)) names.push(name);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return [
|
|
610
|
+
value,
|
|
611
|
+
names.map((name) => members.every((fields) => fields.includes(name)) ? name : `${name}?`)
|
|
612
|
+
];
|
|
392
613
|
});
|
|
393
614
|
}
|
|
615
|
+
function mergeAlternatives(schemas) {
|
|
616
|
+
if (schemas.every((schema) => tagValues(schema) !== null)) {
|
|
617
|
+
return { type: "string", enum: [...new Set(schemas.flatMap((schema) => tagValues(schema)))] };
|
|
618
|
+
}
|
|
619
|
+
return { anyOf: schemas };
|
|
620
|
+
}
|
|
621
|
+
function tagValues(schema) {
|
|
622
|
+
if (!isNode(schema)) return null;
|
|
623
|
+
if (typeof schema.const === "string") return [schema.const];
|
|
624
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0 && schema.enum.every((value) => typeof value === "string")) {
|
|
625
|
+
return schema.enum;
|
|
626
|
+
}
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
function isObjectSchema(schema) {
|
|
630
|
+
return isNode(schema) && schema.type === "object" && isNode(schema.properties);
|
|
631
|
+
}
|
|
632
|
+
function sameSchema(left, right) {
|
|
633
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
634
|
+
}
|
|
635
|
+
function isNode(value) {
|
|
636
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
637
|
+
}
|
|
638
|
+
var MAX_REPORTED_ISSUES = 4;
|
|
639
|
+
var MAX_ISSUE_MESSAGE_CHARS = 240;
|
|
640
|
+
function describeInvalidToolArguments(error) {
|
|
641
|
+
const issues = leafIssues(error.issues, []).slice(0, MAX_REPORTED_ISSUES);
|
|
642
|
+
const described = issues.map(({ path, message }) => {
|
|
643
|
+
const text = message.replace(/^Invalid input: /u, "").slice(0, MAX_ISSUE_MESSAGE_CHARS);
|
|
644
|
+
return path.length > 0 ? `${path.join(".")}: ${text}` : text;
|
|
645
|
+
});
|
|
646
|
+
return `Interaction tool arguments are invalid: ${described.join("; ")}.`;
|
|
647
|
+
}
|
|
648
|
+
function leafIssues(issues, base) {
|
|
649
|
+
const leaves = [];
|
|
650
|
+
for (const issue of issues) {
|
|
651
|
+
const path = [...base, ...issue.path];
|
|
652
|
+
if (issue.code === "invalid_union" && issue.errors.length > 0) {
|
|
653
|
+
leaves.push(...leafIssues(chosenUnionBranch(issue.errors), path));
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (issue.code === "unrecognized_keys") {
|
|
657
|
+
leaves.push({ path, message: `unexpected field ${issue.keys.join(", ")}` });
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
leaves.push({ path, message: issue.message });
|
|
661
|
+
}
|
|
662
|
+
return leaves;
|
|
663
|
+
}
|
|
664
|
+
function chosenUnionBranch(branches) {
|
|
665
|
+
const tagMismatch = (issue) => issue.code === "invalid_union" && issue.errors.length === 0 || issue.code === "invalid_value" && ["type", "kind", "operation"].includes(String(issue.path.at(-1)));
|
|
666
|
+
const matching = branches.filter((branch) => !branch.some(tagMismatch));
|
|
667
|
+
if (matching.length > 0) {
|
|
668
|
+
return matching.reduce((best, branch) => branch.length < best.length ? branch : best);
|
|
669
|
+
}
|
|
670
|
+
const unknownTag = branches.find(
|
|
671
|
+
(branch) => branch.some((issue) => issue.code === "invalid_union" && issue.errors.length === 0)
|
|
672
|
+
);
|
|
673
|
+
return unknownTag?.filter((issue) => issue.code === "invalid_union") ?? branches.reduce((best, branch) => branch.length < best.length ? branch : best);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// src/browser-model-text.ts
|
|
677
|
+
var REFLESS_ROLES = /* @__PURE__ */ new Set([
|
|
678
|
+
"article",
|
|
679
|
+
"banner",
|
|
680
|
+
"blockquote",
|
|
681
|
+
"caption",
|
|
682
|
+
"cell",
|
|
683
|
+
"code",
|
|
684
|
+
"columnheader",
|
|
685
|
+
"complementary",
|
|
686
|
+
"contentinfo",
|
|
687
|
+
"definition",
|
|
688
|
+
"deletion",
|
|
689
|
+
"document",
|
|
690
|
+
"emphasis",
|
|
691
|
+
"figure",
|
|
692
|
+
"form",
|
|
693
|
+
"generic",
|
|
694
|
+
"group",
|
|
695
|
+
"heading",
|
|
696
|
+
"insertion",
|
|
697
|
+
"LabelText",
|
|
698
|
+
"LineBreak",
|
|
699
|
+
"list",
|
|
700
|
+
"listitem",
|
|
701
|
+
"log",
|
|
702
|
+
"main",
|
|
703
|
+
"mark",
|
|
704
|
+
"navigation",
|
|
705
|
+
"none",
|
|
706
|
+
"note",
|
|
707
|
+
"paragraph",
|
|
708
|
+
"presentation",
|
|
709
|
+
"region",
|
|
710
|
+
"row",
|
|
711
|
+
"rowgroup",
|
|
712
|
+
"rowheader",
|
|
713
|
+
"Section",
|
|
714
|
+
"separator",
|
|
715
|
+
"status",
|
|
716
|
+
"strong",
|
|
717
|
+
"subscript",
|
|
718
|
+
"superscript",
|
|
719
|
+
"table",
|
|
720
|
+
"term",
|
|
721
|
+
"text",
|
|
722
|
+
"time"
|
|
723
|
+
]);
|
|
724
|
+
function shownState(role, state) {
|
|
725
|
+
if (state === "focusable" || state === "settable" || state === "editable") return false;
|
|
726
|
+
if (state.startsWith("editable=") || state.startsWith("url=")) return false;
|
|
727
|
+
if (state.endsWith("=")) return false;
|
|
728
|
+
if (role === "document" && state === "focused") return false;
|
|
729
|
+
return true;
|
|
730
|
+
}
|
|
731
|
+
function quoted(value) {
|
|
732
|
+
return JSON.stringify(value);
|
|
733
|
+
}
|
|
734
|
+
function browserNodeLine(node, allRefs, baseDepth = 0) {
|
|
735
|
+
const parts = [`${" ".repeat(Math.max(0, node.depth - baseDepth))}- ${node.role}`];
|
|
736
|
+
if (node.name) parts.push(quoted(node.name));
|
|
737
|
+
if (allRefs || (node.actions?.length ?? 0) > 0 || !REFLESS_ROLES.has(node.role)) {
|
|
738
|
+
parts.push(`[${node.ref}]`);
|
|
739
|
+
}
|
|
740
|
+
if (node.value !== void 0 && node.value !== "") {
|
|
741
|
+
parts.push(typeof node.value === "string" ? `value=${quoted(node.value)}` : "value=<redacted>");
|
|
742
|
+
}
|
|
743
|
+
if (node.description) parts.push(`description=${quoted(node.description)}`);
|
|
744
|
+
for (const state of node.states ?? []) if (shownState(node.role, state)) parts.push(state);
|
|
745
|
+
return parts.join(" ");
|
|
746
|
+
}
|
|
747
|
+
function browserTargetLine(target) {
|
|
748
|
+
const kind = target.kind === "page" ? "" : ` (${target.kind})`;
|
|
749
|
+
const selected = target.selected ? " selected" : "";
|
|
750
|
+
return `Tab ${target.id}${kind}${selected}: ${quoted(target.title)} ${target.url}`;
|
|
751
|
+
}
|
|
752
|
+
function shallowestDepth(nodes) {
|
|
753
|
+
let base = Number.POSITIVE_INFINITY;
|
|
754
|
+
for (const node of nodes) base = Math.min(base, node.depth);
|
|
755
|
+
return Number.isFinite(base) ? base : 0;
|
|
756
|
+
}
|
|
757
|
+
function plural(count, noun) {
|
|
758
|
+
if (count === 1) return `${count} ${noun}`;
|
|
759
|
+
return `${count} ${noun}${/(?:s|x|ch|sh)$/.test(noun) ? "es" : "s"}`;
|
|
760
|
+
}
|
|
761
|
+
function browserObservationText(observation, options = {}) {
|
|
762
|
+
const allRefs = options.allRefs === true;
|
|
763
|
+
const lines = [browserTargetLine({ ...observation.target, selected: false })];
|
|
764
|
+
const viewport = observation.viewport;
|
|
765
|
+
if (viewport) {
|
|
766
|
+
const extras = [
|
|
767
|
+
viewport.deviceScaleFactor && viewport.deviceScaleFactor !== 1 ? `scale ${viewport.deviceScaleFactor}` : null,
|
|
768
|
+
viewport.maxTouchPoints ? `${viewport.maxTouchPoints} touch points` : null
|
|
769
|
+
].filter((entry) => entry !== null);
|
|
770
|
+
lines.push(
|
|
771
|
+
`Viewport ${viewport.width}x${viewport.height}${extras.length ? ` (${extras.join(", ")})` : ""}`
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
const dialog = observation.dialog;
|
|
775
|
+
if (dialog) {
|
|
776
|
+
const prompt = dialog.type === "prompt" && dialog.defaultPrompt ? ` default ${quoted(dialog.defaultPrompt)}` : "";
|
|
777
|
+
lines.push(`Open ${dialog.type} dialog: ${quoted(dialog.message)}${prompt}`);
|
|
778
|
+
}
|
|
779
|
+
const diagnostics = observation.diagnostics;
|
|
780
|
+
if (diagnostics) {
|
|
781
|
+
const reported = [
|
|
782
|
+
diagnostics.consoleErrorCount ? plural(diagnostics.consoleErrorCount, "console error") : null,
|
|
783
|
+
diagnostics.pageErrorCount ? plural(diagnostics.pageErrorCount, "page error") : null,
|
|
784
|
+
diagnostics.failedRequestCount ? plural(diagnostics.failedRequestCount, "failed request") : null,
|
|
785
|
+
diagnostics.downloadCount ? plural(diagnostics.downloadCount, "download") : null
|
|
786
|
+
].filter((entry) => entry !== null);
|
|
787
|
+
if (reported.length) lines.push(`Page reported ${reported.join(", ")}`);
|
|
788
|
+
}
|
|
789
|
+
if (observation.changedRegions && observation.changedRegions.length > 0) {
|
|
790
|
+
lines.push(`Changed regions: ${JSON.stringify(observation.changedRegions)}`);
|
|
791
|
+
}
|
|
792
|
+
if (observation.screenshot) lines.push(`Screenshot: ${JSON.stringify(observation.screenshot)}`);
|
|
793
|
+
const view = observation.agentView;
|
|
794
|
+
const nodes = view.nodes;
|
|
795
|
+
if (observation.focusedRef && !nodes.some(
|
|
796
|
+
(node) => node.ref === observation.focusedRef && (node.states ?? []).includes("focused")
|
|
797
|
+
)) {
|
|
798
|
+
lines.push(`Focused element: ${observation.focusedRef}`);
|
|
799
|
+
}
|
|
800
|
+
if (view.sourceKind === "none") {
|
|
801
|
+
lines.push("No accessibility view is available for this tab.");
|
|
802
|
+
} else {
|
|
803
|
+
if (view.sourceKind === "diff") lines.push("Changed elements:");
|
|
804
|
+
const base = shallowestDepth(nodes);
|
|
805
|
+
for (const node of nodes) lines.push(browserNodeLine(node, allRefs, base));
|
|
806
|
+
}
|
|
807
|
+
const notes = [
|
|
808
|
+
view.omittedNodeCount ? `${plural(view.omittedNodeCount, "element")} not shown` : null,
|
|
809
|
+
view.removedRefCount ? `${plural(view.removedRefCount, "earlier element")} removed` : null,
|
|
810
|
+
view.clippedFieldCount ? `${plural(view.clippedFieldCount, "long field")} clipped` : null
|
|
811
|
+
].filter((entry) => entry !== null);
|
|
812
|
+
if (notes.length) lines.push(`(${notes.join("; ")})`);
|
|
813
|
+
return lines.join("\n");
|
|
814
|
+
}
|
|
815
|
+
function resolvedTargetText(target) {
|
|
816
|
+
const parts = [`#${target.actionIndex} ${target.role}`];
|
|
817
|
+
if (target.name) parts.push(quoted(target.name));
|
|
818
|
+
if (target.ref) parts.push(`[${target.ref}]`);
|
|
819
|
+
if (target.container) {
|
|
820
|
+
parts.push(
|
|
821
|
+
`in ${target.container.role}${target.container.name ? ` ${quoted(target.container.name)}` : ""}`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
return parts.join(" ");
|
|
825
|
+
}
|
|
826
|
+
function browserActionText(receipt) {
|
|
827
|
+
const lines = [`Action ${receipt.state} on tab ${receipt.targetId}.`];
|
|
828
|
+
if (receipt.error) {
|
|
829
|
+
const { code, message, retryable, ...details } = receipt.error;
|
|
830
|
+
lines.push(
|
|
831
|
+
`Error ${code}${retryable ? " (retryable)" : ""}: ${message}${Object.keys(details).length ? ` ${JSON.stringify(details)}` : ""}`
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
if (receipt.targets && receipt.targets.length > 0) {
|
|
835
|
+
lines.push(`Acted on: ${receipt.targets.map(resolvedTargetText).join("; ")}`);
|
|
836
|
+
}
|
|
837
|
+
if (receipt.observation) {
|
|
838
|
+
lines.push(browserObservationText(receipt.observation, { allRefs: receipt.allRefs === true }));
|
|
839
|
+
}
|
|
840
|
+
return lines.join("\n");
|
|
841
|
+
}
|
|
842
|
+
var PLACEMENT_LABELS = {
|
|
843
|
+
sandbox_group: "the managed sandbox",
|
|
844
|
+
connected_machine: "a Connected Machine",
|
|
845
|
+
external_provider: "a remote browser provider",
|
|
846
|
+
attached_device: "the user's own Chrome"
|
|
847
|
+
};
|
|
848
|
+
function browserSessionLine(session) {
|
|
849
|
+
const engine = session.engine ?? "browser";
|
|
850
|
+
const mode = session.placement.kind === "attached_device" ? "" : session.headless ? " headless" : " headed";
|
|
851
|
+
const placement = PLACEMENT_LABELS[session.placement.kind] ?? session.placement.kind;
|
|
852
|
+
const extras = [
|
|
853
|
+
session.identityId ? `identity ${session.identityId}` : null,
|
|
854
|
+
session.failureCode ? `failure ${session.failureCode}` : null
|
|
855
|
+
].filter((entry) => entry !== null);
|
|
856
|
+
return `BrowserSession ${session.id} (${session.lifecycle}): ${engine}${mode} on ${placement}${extras.length ? `, ${extras.join(", ")}` : ""}`;
|
|
857
|
+
}
|
|
858
|
+
function attachedProfileText(profile) {
|
|
859
|
+
return `${quoted(profile.name)}${profile.profileLabel ? ` (${profile.profileLabel})` : ""} deviceId ${profile.id}`;
|
|
860
|
+
}
|
|
861
|
+
function browserOpenText(output) {
|
|
862
|
+
const lines = [browserSessionLine(output.session)];
|
|
863
|
+
if (output.attachedProfile) {
|
|
864
|
+
lines.push(`Attached Chrome profile: ${attachedProfileText(output.attachedProfile)}`);
|
|
865
|
+
}
|
|
866
|
+
if (output.otherAttachedProfiles && output.otherAttachedProfiles.length > 0) {
|
|
867
|
+
lines.push(
|
|
868
|
+
`Other attached profiles: ${output.otherAttachedProfiles.map(attachedProfileText).join("; ")}`
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
const observedId = output.observation?.target.id;
|
|
872
|
+
for (const target of output.targets) {
|
|
873
|
+
if (target.id !== observedId) lines.push(browserTargetLine(target));
|
|
874
|
+
}
|
|
875
|
+
if (output.otherTabCount) {
|
|
876
|
+
lines.push(`${plural(output.otherTabCount, "other tab")} (browser_tabs list shows them)`);
|
|
877
|
+
}
|
|
878
|
+
if (output.observation) lines.push(browserObservationText(output.observation));
|
|
879
|
+
else if (output.targets.length === 0) lines.push("No tabs are open.");
|
|
880
|
+
return lines.join("\n");
|
|
881
|
+
}
|
|
882
|
+
function browserTabsText(output) {
|
|
883
|
+
const lines = [
|
|
884
|
+
`BrowserSession ${output.browserSessionId} has ${plural(output.targets.length, "tab")}:`
|
|
885
|
+
];
|
|
886
|
+
for (const target of output.targets) lines.push(browserTargetLine(target));
|
|
887
|
+
if (output.mutationObservation) lines.push(browserObservationText(output.mutationObservation));
|
|
888
|
+
return lines.join("\n");
|
|
889
|
+
}
|
|
890
|
+
function browserReadText(output) {
|
|
891
|
+
const lines = [
|
|
892
|
+
`Tab ${output.targetId}: ${plural(output.totalMatches, "match")} (${output.mode})${output.scopeFound ? "" : "; the scope element was not found"}`
|
|
893
|
+
];
|
|
894
|
+
const base = shallowestDepth(output.nodes);
|
|
895
|
+
for (const node of output.nodes) lines.push(browserNodeLine(node, true, base));
|
|
896
|
+
const notes = [
|
|
897
|
+
output.omittedMatches ? `${plural(output.omittedMatches, "match")} not shown` : null,
|
|
898
|
+
output.clippedFieldCount ? `${plural(output.clippedFieldCount, "long field")} clipped` : null
|
|
899
|
+
].filter((entry) => entry !== null);
|
|
900
|
+
if (notes.length) lines.push(`(${notes.join("; ")})`);
|
|
901
|
+
return lines.join("\n");
|
|
902
|
+
}
|
|
394
903
|
|
|
395
904
|
// src/interaction-tools.ts
|
|
396
905
|
var INTERACTION_ATTEMPT_TOOL_NAMES = FIRST_PARTY_IN_PROCESS_TOOL_NAMES;
|
|
@@ -462,9 +971,11 @@ var CompactBrowserActionReceipt = external_exports.object({
|
|
|
462
971
|
observation: CompactBrowserObservation.optional()
|
|
463
972
|
}).strict();
|
|
464
973
|
var BrowserAgentActionReceipt = external_exports.union([BrowserActionReceipt, CompactBrowserActionReceipt]);
|
|
974
|
+
var CurrentBrowserSessionId = external_exports.string().uuid().optional().describe("Omit to use the browser you used last.");
|
|
975
|
+
var CurrentBrowserTargetId = external_exports.string().min(1).max(512).optional().describe("Omit to use the tab you used last.");
|
|
465
976
|
var BrowserScreenshotInput = external_exports.object({
|
|
466
|
-
browserSessionId:
|
|
467
|
-
targetId:
|
|
977
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
978
|
+
targetId: CurrentBrowserTargetId,
|
|
468
979
|
fullPage: external_exports.boolean().optional(),
|
|
469
980
|
quality: external_exports.number().int().min(1).max(100).optional()
|
|
470
981
|
}).strict();
|
|
@@ -485,8 +996,8 @@ var BrowserScreenshotOutput = external_exports.object({
|
|
|
485
996
|
fullPage: external_exports.boolean()
|
|
486
997
|
}).strict();
|
|
487
998
|
var BrowserReadInput = external_exports.object({
|
|
488
|
-
browserSessionId:
|
|
489
|
-
targetId:
|
|
999
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
1000
|
+
targetId: CurrentBrowserTargetId,
|
|
490
1001
|
mode: external_exports.enum(["matches", "count", "subtree", "dom"]).optional(),
|
|
491
1002
|
dom: external_exports.discriminatedUnion("kind", [
|
|
492
1003
|
external_exports.object({
|
|
@@ -681,20 +1192,20 @@ var BrowserOpenOutput = external_exports.object({
|
|
|
681
1192
|
otherAttachedProfiles: external_exports.array(AgentAttachedProfile).optional()
|
|
682
1193
|
}).strict();
|
|
683
1194
|
var BrowserTabsInput = external_exports.discriminatedUnion("operation", [
|
|
684
|
-
external_exports.object({ operation: external_exports.literal("list"), browserSessionId:
|
|
1195
|
+
external_exports.object({ operation: external_exports.literal("list"), browserSessionId: CurrentBrowserSessionId }).strict(),
|
|
685
1196
|
external_exports.object({
|
|
686
1197
|
operation: external_exports.literal("open"),
|
|
687
|
-
browserSessionId:
|
|
1198
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
688
1199
|
url: external_exports.string().url().max(16384).optional()
|
|
689
1200
|
}).strict(),
|
|
690
1201
|
external_exports.object({
|
|
691
1202
|
operation: external_exports.literal("select"),
|
|
692
|
-
browserSessionId:
|
|
1203
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
693
1204
|
targetId: external_exports.string().min(1).max(512)
|
|
694
1205
|
}).strict(),
|
|
695
1206
|
external_exports.object({
|
|
696
1207
|
operation: external_exports.literal("close"),
|
|
697
|
-
browserSessionId:
|
|
1208
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
698
1209
|
targetId: external_exports.string().min(1).max(512)
|
|
699
1210
|
}).strict()
|
|
700
1211
|
]);
|
|
@@ -704,24 +1215,24 @@ var BrowserTabsOutput = external_exports.object({
|
|
|
704
1215
|
mutationObservation: CompactBrowserObservation.optional()
|
|
705
1216
|
}).strict();
|
|
706
1217
|
var BrowserObserveInput = external_exports.object({
|
|
707
|
-
browserSessionId:
|
|
708
|
-
targetId:
|
|
1218
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
1219
|
+
targetId: CurrentBrowserTargetId,
|
|
709
1220
|
view: external_exports.enum(["compact", "full"]).optional(),
|
|
710
1221
|
includeScreenshot: external_exports.boolean().optional()
|
|
711
1222
|
}).strict();
|
|
712
1223
|
var BrowserActInput = external_exports.object({
|
|
713
|
-
browserSessionId:
|
|
714
|
-
targetId:
|
|
1224
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
1225
|
+
targetId: CurrentBrowserTargetId,
|
|
715
1226
|
expectedTargetGeneration: external_exports.string().min(1).max(256).optional(),
|
|
716
1227
|
expectedDocumentGeneration: external_exports.string().min(1).max(256).nullable().optional(),
|
|
717
1228
|
expectedFrameId: external_exports.string().min(1).max(256).nullable().optional(),
|
|
718
1229
|
view: external_exports.enum(["compact", "full", "none"]).optional(),
|
|
719
|
-
action: external_exports.union([BrowserAction, BrowserActionBatch])
|
|
1230
|
+
action: external_exports.preprocess(expandRefShorthand, external_exports.union([BrowserAction, BrowserActionBatch]))
|
|
720
1231
|
}).strict();
|
|
721
1232
|
var BrowserClipboardInput = external_exports.object({ browserSessionId: external_exports.string().uuid() }).strict();
|
|
722
1233
|
var BrowserDebugInput = external_exports.object({
|
|
723
|
-
browserSessionId:
|
|
724
|
-
targetId:
|
|
1234
|
+
browserSessionId: CurrentBrowserSessionId,
|
|
1235
|
+
targetId: CurrentBrowserTargetId,
|
|
725
1236
|
kinds: external_exports.array(external_exports.enum(["console", "page_error", "failed_request", "download"])).max(4).optional(),
|
|
726
1237
|
after: external_exports.number().int().nonnegative().optional(),
|
|
727
1238
|
limit: external_exports.number().int().min(1).max(1e3).optional()
|
|
@@ -872,6 +1383,40 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
872
1383
|
const selected = new Set(input.selectedTools ?? DEFAULT_FIRST_PARTY_MCP_TOOLS);
|
|
873
1384
|
const permissions = input.permissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS;
|
|
874
1385
|
const definitions = [];
|
|
1386
|
+
const currentTab = new CurrentBrowserTab({
|
|
1387
|
+
listLiveSessions: async () => filterDiscoveredSessions(
|
|
1388
|
+
(await input.transport.listBrowserSessions(input.workspaceId, {
|
|
1389
|
+
associatedSessionId: input.sessionId,
|
|
1390
|
+
includeTerminal: false
|
|
1391
|
+
})).sessions,
|
|
1392
|
+
input.sessionId,
|
|
1393
|
+
"current_session",
|
|
1394
|
+
false
|
|
1395
|
+
),
|
|
1396
|
+
listTargets: async (browserSessionId) => (await input.transport.listBrowserTargets(input.workspaceId, browserSessionId)).targets
|
|
1397
|
+
});
|
|
1398
|
+
const onTab = async (value, run2) => {
|
|
1399
|
+
const tab = await currentTab.target(value);
|
|
1400
|
+
try {
|
|
1401
|
+
const output = await run2(tab);
|
|
1402
|
+
currentTab.use(tab.browserSessionId, tab.targetId);
|
|
1403
|
+
return output;
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
if (isGoneBrowserError(error)) currentTab.failed(tab);
|
|
1406
|
+
throw error;
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
const onBrowser = async (browserSessionId, run2) => {
|
|
1410
|
+
const browser = await currentTab.session(browserSessionId);
|
|
1411
|
+
try {
|
|
1412
|
+
const output = await run2(browser);
|
|
1413
|
+
currentTab.use(browser.browserSessionId);
|
|
1414
|
+
return output;
|
|
1415
|
+
} catch (error) {
|
|
1416
|
+
if (isGoneBrowserError(error)) currentTab.failed(browser);
|
|
1417
|
+
throw error;
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
875
1420
|
const add = (options) => {
|
|
876
1421
|
if (!selected.has(options.name) || !hasToolPermission(permissions, TOOL_PERMISSION[options.name])) {
|
|
877
1422
|
return;
|
|
@@ -882,7 +1427,9 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
882
1427
|
codemodePath: options.codemodePath,
|
|
883
1428
|
title: options.title,
|
|
884
1429
|
description: options.description,
|
|
885
|
-
inputSchema: options.
|
|
1430
|
+
inputSchema: (options.modelInputSchema ?? ((schema) => schema))(
|
|
1431
|
+
interactionToolInputJsonSchema(options.input)
|
|
1432
|
+
),
|
|
886
1433
|
outputSchema: jsonSchema(options.output),
|
|
887
1434
|
annotations: {
|
|
888
1435
|
title: options.title,
|
|
@@ -899,7 +1446,8 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
899
1446
|
raw,
|
|
900
1447
|
context,
|
|
901
1448
|
options.execute,
|
|
902
|
-
options.readOnly
|
|
1449
|
+
options.readOnly,
|
|
1450
|
+
options.modelText
|
|
903
1451
|
)
|
|
904
1452
|
});
|
|
905
1453
|
};
|
|
@@ -969,80 +1517,93 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
969
1517
|
name: "browser_open",
|
|
970
1518
|
codemodePath: ["interaction", "browser", "open"],
|
|
971
1519
|
title: "Open or reuse browser",
|
|
972
|
-
description: `Open a managed BrowserSession on the current agent placement, reuse a relevant compatible live session by default, attach to an explicit workspace BrowserSession, or open the user's own Chrome with placement={kind:'attached_device'}. Use that directly for requests about 'my browser', 'my tabs', or current Chrome: it opens the only Chrome profile connected through the Opengeni Browser extension, or else the most recently active one (reported as attachedProfile, the rest as otherAttachedProfiles). Add deviceId (from interaction_discover scope=attached_browsers or otherAttachedProfiles) only when the user wants a different profile. Omitting placement never uses the user's Chrome. If no profile is connected, explain that the Chrome extension must be connected instead of silently creating a blank managed browser (it needs a Connected Machine, then the Opengeni Browser extension: ${OPENGENI_BROWSER_EXTENSION_URL}). BrowserSessions persist across tool calls; shell-launched browser daemons do not survive remote-command cleanup. Never switch to the user's attached Chrome as a fallback for a failed managed browser unless the user requested that profile. A new attached session opens a dedicated tab. Managed Chromium defaults to headed so OAuth and later human interaction use a supported browser; request headless=true only for agent-only work that will not require sign-in or human control. Operator-enabled disposable sandbox verification may explicitly request storageMode=ephemeral_context with headless=true: no saved identity, route, Computer, checkpoint or resume; process loss ends the session. Default private_profile storage is unchanged. Returns
|
|
1520
|
+
description: `Open a managed BrowserSession on the current agent placement, reuse a relevant compatible live session by default, attach to an explicit workspace BrowserSession, or open the user's own Chrome with placement={kind:'attached_device'}. Use that directly for requests about 'my browser', 'my tabs', or current Chrome: it opens the only Chrome profile connected through the Opengeni Browser extension, or else the most recently active one (reported as attachedProfile, the rest as otherAttachedProfiles). Add deviceId (from interaction_discover scope=attached_browsers or otherAttachedProfiles) only when the user wants a different profile. Omitting placement never uses the user's Chrome. If no profile is connected, explain that the Chrome extension must be connected instead of silently creating a blank managed browser (it needs a Connected Machine, then the Opengeni Browser extension: ${OPENGENI_BROWSER_EXTENSION_URL}). BrowserSessions persist across tool calls; shell-launched browser daemons do not survive remote-command cleanup. Never switch to the user's attached Chrome as a fallback for a failed managed browser unless the user requested that profile. A new attached session opens a dedicated tab. Managed Chromium defaults to headed so OAuth and later human interaction use a supported browser; request headless=true only for agent-only work that will not require sign-in or human control. Operator-enabled disposable sandbox verification may explicitly request storageMode=ephemeral_context with headless=true: no saved identity, route, Computer, checkpoint or resume; process loss ends the session. Default private_profile storage is unchanged. Returns the session, its tabs and an outline of the opened (or selected) tab when one is available, in the browser_observe format. With initialUrl, only the opened tab is listed and the others are counted (browser_tabs list shows them). Act on the outline's elements directly instead of observing again. Call it first for any browser task; browser_observe, browser_act, browser_screenshot and browser_tabs then work on the session it returns.`,
|
|
973
1521
|
input: BrowserOpenInput,
|
|
974
1522
|
output: BrowserOpenOutput,
|
|
975
1523
|
readOnly: false,
|
|
976
1524
|
idempotent: true,
|
|
977
|
-
|
|
1525
|
+
modelText: browserOpenText,
|
|
1526
|
+
execute: async (value, context) => {
|
|
1527
|
+
const opened = await openBrowser(
|
|
1528
|
+
input.transport,
|
|
1529
|
+
input.workspaceId,
|
|
1530
|
+
input.sessionId,
|
|
1531
|
+
value,
|
|
1532
|
+
context
|
|
1533
|
+
);
|
|
1534
|
+
currentTab.use(
|
|
1535
|
+
opened.session.id,
|
|
1536
|
+
opened.observation?.target.id ?? opened.targets.find((target) => target.selected)?.id ?? null
|
|
1537
|
+
);
|
|
1538
|
+
return opened;
|
|
1539
|
+
}
|
|
978
1540
|
});
|
|
979
1541
|
add({
|
|
980
1542
|
name: "browser_tabs",
|
|
981
1543
|
codemodePath: ["interaction", "browser", "tabs"],
|
|
982
1544
|
title: "Manage browser tabs",
|
|
983
|
-
description: "List, open, logically select, or close tabs in one exact BrowserSession. Selection changes the BrowserSession's default target, not the visible desktop tab. New attached-Chrome tabs open in the background. Use browser_act activate only when foregrounding the owned tab is explicitly intended. Closing a tab does not release the browser process; use browser_lifecycle for session cleanup. Returns the authoritative complete tab list after the operation. Open/select also return
|
|
1545
|
+
description: "List, open, logically select, or close tabs in one exact BrowserSession. Selection changes the BrowserSession's default target, not the visible desktop tab. New attached-Chrome tabs open in the background. Use browser_act activate only when foregrounding the owned tab is explicitly intended. Closing a tab does not release the browser process; use browser_lifecycle for session cleanup. Returns the authoritative complete tab list after the operation. Open/select also return the page outline. Act on its elements directly; observe again after later page changes.",
|
|
984
1546
|
input: BrowserTabsInput,
|
|
985
1547
|
output: BrowserTabsOutput,
|
|
986
1548
|
readOnly: false,
|
|
987
1549
|
idempotent: false,
|
|
988
|
-
|
|
1550
|
+
modelText: browserTabsText,
|
|
1551
|
+
execute: async (value) => await onBrowser(value.browserSessionId, async ({ browserSessionId }) => {
|
|
989
1552
|
let mutationObservation;
|
|
990
1553
|
if (value.operation === "open") {
|
|
991
1554
|
mutationObservation = await input.transport.openBrowserTarget(
|
|
992
1555
|
input.workspaceId,
|
|
993
|
-
|
|
1556
|
+
browserSessionId,
|
|
994
1557
|
{ ...value.url ? { url: value.url } : {} }
|
|
995
1558
|
);
|
|
996
1559
|
} else if (value.operation === "select") {
|
|
997
1560
|
mutationObservation = await input.transport.selectBrowserTarget(
|
|
998
1561
|
input.workspaceId,
|
|
999
|
-
|
|
1562
|
+
browserSessionId,
|
|
1000
1563
|
value.targetId
|
|
1001
1564
|
);
|
|
1002
1565
|
} else if (value.operation === "close") {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
value.targetId
|
|
1008
|
-
)
|
|
1566
|
+
const closed = await input.transport.closeBrowserTarget(
|
|
1567
|
+
input.workspaceId,
|
|
1568
|
+
browserSessionId,
|
|
1569
|
+
value.targetId
|
|
1009
1570
|
);
|
|
1571
|
+
currentTab.forgetTarget(browserSessionId, value.targetId);
|
|
1572
|
+
return agentTargetList(closed);
|
|
1010
1573
|
}
|
|
1011
|
-
const tabs = await input.transport.listBrowserTargets(
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1574
|
+
const tabs = await input.transport.listBrowserTargets(input.workspaceId, browserSessionId);
|
|
1575
|
+
if (mutationObservation) {
|
|
1576
|
+
currentTab.use(browserSessionId, mutationObservation.target.id);
|
|
1577
|
+
return {
|
|
1578
|
+
...agentTargetList(tabs),
|
|
1579
|
+
mutationObservation: projectBrowserObservation(mutationObservation, "compact")
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
return agentTargetList(tabs);
|
|
1583
|
+
})
|
|
1020
1584
|
});
|
|
1021
1585
|
add({
|
|
1022
1586
|
name: "browser_observe",
|
|
1023
1587
|
codemodePath: ["interaction", "browser", "observe"],
|
|
1024
1588
|
title: "Observe browser tab",
|
|
1025
|
-
description:
|
|
1589
|
+
description: `Read one tab's URL, title, viewport and accessibility outline: one line per element, role "name" [ref] value and states, indented by nesting. Locate an element by role and name, or by ref ({kind:'ref',ref}); refs are listed on controls and other actionable elements, not on text and layout lines. The default view is selective and says how many elements it left out; it is not a complete page tree. Set view=full for every element with its ref. Set includeScreenshot=true to add a current still image as tool image content; browser_screenshot is faster when only pixels are needed.`,
|
|
1026
1590
|
input: BrowserObserveInput,
|
|
1027
1591
|
output: BrowserAgentObservation,
|
|
1028
1592
|
readOnly: true,
|
|
1029
1593
|
idempotent: true,
|
|
1030
|
-
|
|
1594
|
+
modelText: agentObservationText,
|
|
1595
|
+
execute: async (value) => await onTab(value, async ({ browserSessionId, targetId }) => {
|
|
1031
1596
|
const observationRequest = input.transport.observeBrowserTarget(
|
|
1032
1597
|
input.workspaceId,
|
|
1033
|
-
|
|
1034
|
-
|
|
1598
|
+
browserSessionId,
|
|
1599
|
+
targetId
|
|
1035
1600
|
);
|
|
1036
1601
|
if (!value.includeScreenshot)
|
|
1037
1602
|
return projectBrowserObservation(await observationRequest, value.view ?? "compact");
|
|
1038
1603
|
const [observed, captured] = await Promise.allSettled([
|
|
1039
1604
|
observationRequest,
|
|
1040
1605
|
Promise.resolve().then(
|
|
1041
|
-
() => input.transport.captureBrowserTarget(
|
|
1042
|
-
input.workspaceId,
|
|
1043
|
-
value.browserSessionId,
|
|
1044
|
-
value.targetId
|
|
1045
|
-
)
|
|
1606
|
+
() => input.transport.captureBrowserTarget(input.workspaceId, browserSessionId, targetId)
|
|
1046
1607
|
)
|
|
1047
1608
|
]);
|
|
1048
1609
|
if (observed.status === "rejected") throw observed.reason;
|
|
@@ -1052,8 +1613,8 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1052
1613
|
if (observation.target.targetGeneration !== frame.targetGeneration || observation.target.documentGeneration !== frame.documentGeneration) {
|
|
1053
1614
|
observation = await input.transport.observeBrowserTarget(
|
|
1054
1615
|
input.workspaceId,
|
|
1055
|
-
|
|
1056
|
-
|
|
1616
|
+
browserSessionId,
|
|
1617
|
+
targetId
|
|
1057
1618
|
);
|
|
1058
1619
|
}
|
|
1059
1620
|
if (observation.target.targetGeneration !== frame.targetGeneration || observation.target.documentGeneration !== frame.documentGeneration) {
|
|
@@ -1063,7 +1624,7 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1063
1624
|
projectBrowserObservation(observation, value.view ?? "compact"),
|
|
1064
1625
|
[browserToolImageContent(frame.data, frame.mediaType)]
|
|
1065
1626
|
);
|
|
1066
|
-
}
|
|
1627
|
+
})
|
|
1067
1628
|
});
|
|
1068
1629
|
add({
|
|
1069
1630
|
name: "browser_read",
|
|
@@ -1074,12 +1635,13 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1074
1635
|
output: BrowserReadToolOutput,
|
|
1075
1636
|
readOnly: true,
|
|
1076
1637
|
idempotent: true,
|
|
1077
|
-
|
|
1638
|
+
modelText: (output) => output.source === "accessibility" ? browserReadText(output) : JSON.stringify(output),
|
|
1639
|
+
execute: async (value) => await onTab(value, async ({ browserSessionId, targetId }) => {
|
|
1078
1640
|
if (value.mode === "dom") {
|
|
1079
1641
|
const state = value.expectedTargetGeneration !== void 0 && value.expectedDocumentGeneration !== void 0 && value.expectedFrameId !== void 0 ? null : await input.transport.getBrowserTargetState(
|
|
1080
1642
|
input.workspaceId,
|
|
1081
|
-
|
|
1082
|
-
|
|
1643
|
+
browserSessionId,
|
|
1644
|
+
targetId
|
|
1083
1645
|
);
|
|
1084
1646
|
const fences = {
|
|
1085
1647
|
expectedTargetGeneration: value.expectedTargetGeneration ?? state.targetGeneration,
|
|
@@ -1110,22 +1672,18 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1110
1672
|
return {
|
|
1111
1673
|
...await input.transport.readBrowserDom(
|
|
1112
1674
|
input.workspaceId,
|
|
1113
|
-
|
|
1114
|
-
|
|
1675
|
+
browserSessionId,
|
|
1676
|
+
targetId,
|
|
1115
1677
|
request
|
|
1116
1678
|
),
|
|
1117
1679
|
source: "dom"
|
|
1118
1680
|
};
|
|
1119
1681
|
}
|
|
1120
1682
|
return readBrowserObservation(
|
|
1121
|
-
await input.transport.observeBrowserTarget(
|
|
1122
|
-
input.workspaceId,
|
|
1123
|
-
value.browserSessionId,
|
|
1124
|
-
value.targetId
|
|
1125
|
-
),
|
|
1683
|
+
await input.transport.observeBrowserTarget(input.workspaceId, browserSessionId, targetId),
|
|
1126
1684
|
value
|
|
1127
1685
|
);
|
|
1128
|
-
}
|
|
1686
|
+
})
|
|
1129
1687
|
});
|
|
1130
1688
|
add({
|
|
1131
1689
|
name: "browser_screenshot",
|
|
@@ -1136,13 +1694,16 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1136
1694
|
output: BrowserScreenshotOutput,
|
|
1137
1695
|
readOnly: true,
|
|
1138
1696
|
idempotent: true,
|
|
1139
|
-
execute: async (value) => {
|
|
1697
|
+
execute: async (value) => await onTab(value, async ({ browserSessionId, targetId }) => {
|
|
1140
1698
|
const frame = await input.transport.captureBrowserTarget(
|
|
1141
1699
|
input.workspaceId,
|
|
1142
|
-
|
|
1143
|
-
|
|
1700
|
+
browserSessionId,
|
|
1701
|
+
targetId,
|
|
1144
1702
|
{},
|
|
1145
|
-
{
|
|
1703
|
+
{
|
|
1704
|
+
fullPage: value.fullPage ?? false,
|
|
1705
|
+
...value.quality ? { quality: value.quality } : {}
|
|
1706
|
+
}
|
|
1146
1707
|
);
|
|
1147
1708
|
return new InteractionExecutionResult(
|
|
1148
1709
|
{
|
|
@@ -1163,33 +1724,31 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1163
1724
|
},
|
|
1164
1725
|
[browserToolImageContent(frame.data, frame.mediaType)]
|
|
1165
1726
|
);
|
|
1166
|
-
}
|
|
1727
|
+
})
|
|
1167
1728
|
});
|
|
1168
1729
|
add({
|
|
1169
1730
|
name: "browser_act",
|
|
1170
1731
|
codemodePath: ["interaction", "browser", "act"],
|
|
1171
1732
|
title: "Act in browser tab",
|
|
1172
|
-
description: "Perform one semantic-first browser action or bounded batch. Prefer action={type:'batch',actions:[...],fenceEachAction:true} for predictable edits in the same observed document, such as filling known form fields before one authorized submit. Pause for new page state, a dialog, or a decision instead of batching steps that depend on an unseen result. Reuse a page observation, when present, from browser_open, tab open/select or a prior action; observe only when none is present or it lacks needed content. Observe again after page changes or when needed content was omitted. If an action reports outcome_unknown, inspect the outcome and do not replay the batch. Use viewport to set page width, height, desktop/mobile layout and touch emulation, then check the measured viewport in the returned observation; emulation does not prove physical mobile-browser behavior. Use history back/forward for tab navigation; keypress shortcuts are page input and may not navigate browser history. A press key is one character or a key name (Enter, Tab, Escape, Backspace, Delete, Insert, Home, End, PageUp, PageDown, ArrowUp/Down/Left/Right, Space, F1-F24), optionally prefixed by Ctrl+, Alt+, Shift+, Meta+ or Mod+. The explicit activate action foregrounds the target in the user's desktop browser; use only when that is intended. Permission actions set a managed browser's web permission for this tab's exact current top-level origin.
|
|
1733
|
+
description: "Perform one semantic-first browser action or bounded batch. Prefer action={type:'batch',actions:[...],fenceEachAction:true} for predictable edits in the same observed document, such as filling known form fields before one authorized submit. Pause for new page state, a dialog, or a decision instead of batching steps that depend on an unseen result. Reuse a page observation, when present, from browser_open, tab open/select or a prior action; observe only when none is present or it lacks needed content. Observe again after page changes or when needed content was omitted. If an action reports outcome_unknown, inspect the outcome and do not replay the batch. Use viewport to set page width, height, desktop/mobile layout and touch emulation, then check the measured viewport in the returned observation; emulation does not prove physical mobile-browser behavior. Use history back/forward for tab navigation; keypress shortcuts are page input and may not navigate browser history. A press key is one character or a key name (Enter, Tab, Escape, Backspace, Delete, Insert, Home, End, PageUp, PageDown, ArrowUp/Down/Left/Right, Space, F1-F24), optionally prefixed by Ctrl+, Alt+, Shift+, Meta+ or Mod+. The explicit activate action foregrounds the target in the user's desktop browser; use only when that is intended. Permission actions set a managed browser's web permission for this tab's exact current top-level origin. The default receipt includes the page outline after the action, in the browser_observe format; set view=full for every element, or view=none when no post-action outline is needed. An upload action takes workspace File IDs; the artifact.artifactId returned by sandbox_file_publish is one. Text in fill, type and clipboard write may contain {{secret:\u2026}} references; the value (or the current TOTP code for /otp) is typed at dispatch and never shown to you. Use type with mode:'keys' for split one-time-code boxes or inputs that ignore pasted text.",
|
|
1173
1734
|
input: BrowserActInput,
|
|
1735
|
+
modelInputSchema: withRefShorthandLocators,
|
|
1174
1736
|
output: BrowserAgentActionReceipt,
|
|
1175
1737
|
readOnly: false,
|
|
1176
1738
|
idempotent: true,
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
action: value.action
|
|
1189
|
-
}
|
|
1190
|
-
);
|
|
1739
|
+
modelText: agentActionText,
|
|
1740
|
+
execute: async (value, context) => await onTab(value, async ({ browserSessionId, targetId }) => {
|
|
1741
|
+
const receipt = await input.transport.actInBrowser(input.workspaceId, browserSessionId, {
|
|
1742
|
+
operationId: context.operationId,
|
|
1743
|
+
targetId,
|
|
1744
|
+
...value.expectedTargetGeneration === void 0 ? {} : { expectedTargetGeneration: value.expectedTargetGeneration },
|
|
1745
|
+
...value.expectedDocumentGeneration === void 0 ? {} : { expectedDocumentGeneration: value.expectedDocumentGeneration },
|
|
1746
|
+
...value.expectedFrameId === void 0 ? {} : { expectedFrameId: value.expectedFrameId },
|
|
1747
|
+
...value.view === "none" ? { observationMode: "none" } : {},
|
|
1748
|
+
action: value.action
|
|
1749
|
+
});
|
|
1191
1750
|
return value.view === "full" ? receipt : compactActionReceipt(receipt);
|
|
1192
|
-
}
|
|
1751
|
+
})
|
|
1193
1752
|
});
|
|
1194
1753
|
add({
|
|
1195
1754
|
name: "browser_clipboard",
|
|
@@ -1211,15 +1770,18 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1211
1770
|
output: BrowserDiagnosticBatch,
|
|
1212
1771
|
readOnly: true,
|
|
1213
1772
|
idempotent: true,
|
|
1214
|
-
execute: async (value) => await
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1773
|
+
execute: async (value) => await onTab(
|
|
1774
|
+
value,
|
|
1775
|
+
async ({ browserSessionId, targetId }) => await input.transport.listBrowserDiagnostics(
|
|
1776
|
+
input.workspaceId,
|
|
1777
|
+
browserSessionId,
|
|
1778
|
+
targetId,
|
|
1779
|
+
{
|
|
1780
|
+
...value.kinds ? { kinds: value.kinds } : {},
|
|
1781
|
+
...value.after !== void 0 ? { after: value.after } : {},
|
|
1782
|
+
...value.limit !== void 0 ? { limit: value.limit } : {}
|
|
1783
|
+
}
|
|
1784
|
+
)
|
|
1223
1785
|
)
|
|
1224
1786
|
});
|
|
1225
1787
|
add({
|
|
@@ -1502,6 +2064,7 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1502
2064
|
request
|
|
1503
2065
|
);
|
|
1504
2066
|
}
|
|
2067
|
+
currentTab.forgetSession(value.browserSessionId);
|
|
1505
2068
|
return await input.transport.endBrowserSession(
|
|
1506
2069
|
input.workspaceId,
|
|
1507
2070
|
value.browserSessionId,
|
|
@@ -1513,7 +2076,7 @@ function createInteractionAttemptToolDefinitions(input) {
|
|
|
1513
2076
|
name: "computer_open",
|
|
1514
2077
|
codemodePath: ["interaction", "computer", "open"],
|
|
1515
2078
|
title: "Open or reuse computer",
|
|
1516
|
-
description: "Open a ComputerSession on the current agent placement, reuse a relevant live session by default, or attach to an explicit workspace ComputerSession. Returns exact apps/windows/screens.",
|
|
2079
|
+
description: "Open a ComputerSession on the current agent placement, reuse a relevant live session by default, or attach to an explicit workspace ComputerSession. Returns exact apps/windows/screens. Call it first for any computer task; computer_observe and computer_act then work on the session it returns.",
|
|
1517
2080
|
input: ComputerOpenInput,
|
|
1518
2081
|
output: ComputerOpenOutput,
|
|
1519
2082
|
readOnly: false,
|
|
@@ -1800,6 +2363,7 @@ function createFirstPartyInteractionAttemptToolDefinitions(input) {
|
|
|
1800
2363
|
async function openBrowser(transport, workspaceId, sourceSessionId, value, context) {
|
|
1801
2364
|
let session;
|
|
1802
2365
|
let created = false;
|
|
2366
|
+
let initialView;
|
|
1803
2367
|
let profileChoice;
|
|
1804
2368
|
if (value.browserSessionId) {
|
|
1805
2369
|
session = await transport.getBrowserSession(workspaceId, value.browserSessionId);
|
|
@@ -1827,7 +2391,7 @@ async function openBrowser(transport, workspaceId, sourceSessionId, value, conte
|
|
|
1827
2391
|
created = true;
|
|
1828
2392
|
if (attachedInventory) profileChoice = chooseAttachedProfile(attachedInventory);
|
|
1829
2393
|
const placement = profileChoice ? { kind: "attached_device", deviceId: profileChoice.chosen.id } : value.placement;
|
|
1830
|
-
|
|
2394
|
+
const createdResponse = await transport.createBrowserSession(workspaceId, {
|
|
1831
2395
|
operationId: context.operationId,
|
|
1832
2396
|
sessionId: sourceSessionId,
|
|
1833
2397
|
...value.name ? { name: value.name } : {},
|
|
@@ -1839,7 +2403,9 @@ async function openBrowser(transport, workspaceId, sourceSessionId, value, conte
|
|
|
1839
2403
|
...value.baseRevisionId ? { baseRevisionId: value.baseRevisionId } : {},
|
|
1840
2404
|
...value.networkRouteId ? { networkRouteId: value.networkRouteId } : {},
|
|
1841
2405
|
...value.linkedComputerSessionId ? { linkedComputerSessionId: value.linkedComputerSessionId } : {}
|
|
1842
|
-
})
|
|
2406
|
+
});
|
|
2407
|
+
session = createdResponse.session;
|
|
2408
|
+
initialView = createdResponse.initialView;
|
|
1843
2409
|
}
|
|
1844
2410
|
}
|
|
1845
2411
|
if (session.lifecycle === "suspended") {
|
|
@@ -1852,7 +2418,7 @@ async function openBrowser(transport, workspaceId, sourceSessionId, value, conte
|
|
|
1852
2418
|
...profileChoice.others.length > 0 ? { otherAttachedProfiles: profileChoice.others.map(agentAttachedProfile) } : {}
|
|
1853
2419
|
} : {};
|
|
1854
2420
|
if (session.lifecycle !== "active") return { session, targets: [], ...chosenProfile };
|
|
1855
|
-
let targets = (await transport.listBrowserTargets(workspaceId, session.id)).targets;
|
|
2421
|
+
let targets = initialView?.targets ?? (await transport.listBrowserTargets(workspaceId, session.id)).targets;
|
|
1856
2422
|
if (value.initialUrl && !created && !targets.some((target) => sameBrowserUrl(target.url, value.initialUrl))) {
|
|
1857
2423
|
if (!transport.openBrowserTargetWithInventory) {
|
|
1858
2424
|
throw new Error("browser transport does not support metadata-only tab opening");
|
|
@@ -1871,7 +2437,7 @@ async function openBrowser(transport, workspaceId, sourceSessionId, value, conte
|
|
|
1871
2437
|
targets = inventory.targets;
|
|
1872
2438
|
}
|
|
1873
2439
|
const primary = openedBrowserTarget(targets, value.initialUrl);
|
|
1874
|
-
const observation = primary ? await observeOpenedBrowserTarget(transport, workspaceId, session.id, primary)
|
|
2440
|
+
const observation = !primary ? void 0 : initialView?.observation.target.id === primary.id ? projectBrowserObservation(initialView.observation, "compact") : await observeOpenedBrowserTarget(transport, workspaceId, session.id, primary);
|
|
1875
2441
|
const opened = value.initialUrl && primary && sameBrowserUrl(primary.url, value.initialUrl) ? primary : void 0;
|
|
1876
2442
|
const shown = opened && targets.length > 1 ? [opened] : targets;
|
|
1877
2443
|
return {
|
|
@@ -2207,7 +2773,62 @@ function readBrowserObservation(observation, input) {
|
|
|
2207
2773
|
maxNodeBytes: BROWSER_AGENT_MAX_NODE_BYTES
|
|
2208
2774
|
};
|
|
2209
2775
|
}
|
|
2210
|
-
|
|
2776
|
+
function resultModelText(output, modelText) {
|
|
2777
|
+
if (modelText) {
|
|
2778
|
+
try {
|
|
2779
|
+
return modelText(output);
|
|
2780
|
+
} catch {
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
return JSON.stringify(output);
|
|
2784
|
+
}
|
|
2785
|
+
function fullObservationText(observation) {
|
|
2786
|
+
const semantic = observation.semantic;
|
|
2787
|
+
const roots = semantic?.kind === "snapshot" ? semantic.roots : semantic?.kind === "diff" ? semantic.changed : [];
|
|
2788
|
+
return browserObservationText(
|
|
2789
|
+
{
|
|
2790
|
+
target: observation.target,
|
|
2791
|
+
viewport: observation.viewport,
|
|
2792
|
+
focusedRef: observation.focusedRef,
|
|
2793
|
+
changedRegions: observation.changedRegions,
|
|
2794
|
+
diagnostics: observation.diagnostics,
|
|
2795
|
+
dialog: observation.dialog,
|
|
2796
|
+
screenshot: observation.screenshot ?? void 0,
|
|
2797
|
+
agentView: {
|
|
2798
|
+
sourceKind: semantic?.kind ?? "none",
|
|
2799
|
+
nodes: flattenBrowserNodes(roots).map(({ node, depth }) => ({
|
|
2800
|
+
ref: node.ref,
|
|
2801
|
+
role: node.role,
|
|
2802
|
+
depth,
|
|
2803
|
+
...node.name !== void 0 ? { name: node.name } : {},
|
|
2804
|
+
...node.description !== void 0 ? { description: node.description } : {},
|
|
2805
|
+
...node.value !== void 0 ? { value: node.value } : {},
|
|
2806
|
+
states: node.states,
|
|
2807
|
+
actions: node.actions
|
|
2808
|
+
})),
|
|
2809
|
+
...semantic?.kind === "diff" && semantic.removedRefs.length > 0 ? { removedRefCount: semantic.removedRefs.length } : {}
|
|
2810
|
+
}
|
|
2811
|
+
},
|
|
2812
|
+
{ allRefs: true }
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
function agentObservationText(observation) {
|
|
2816
|
+
return "agentView" in observation ? browserObservationText(observation) : fullObservationText(observation);
|
|
2817
|
+
}
|
|
2818
|
+
function agentActionText(receipt) {
|
|
2819
|
+
if ("protocolVersion" in receipt) {
|
|
2820
|
+
const text = browserActionText({
|
|
2821
|
+
targetId: receipt.targetId,
|
|
2822
|
+
state: receipt.state,
|
|
2823
|
+
error: receipt.error,
|
|
2824
|
+
...receipt.targets ? { targets: receipt.targets } : {}
|
|
2825
|
+
});
|
|
2826
|
+
return receipt.observation ? `${text}
|
|
2827
|
+
${fullObservationText(receipt.observation)}` : text;
|
|
2828
|
+
}
|
|
2829
|
+
return browserActionText(receipt);
|
|
2830
|
+
}
|
|
2831
|
+
async function safeInteractionExecution(inputSchema, outputSchema, raw, context, execute, readOnly, modelText) {
|
|
2211
2832
|
try {
|
|
2212
2833
|
const value = inputSchema.parse(raw);
|
|
2213
2834
|
const executed = await execute(value, context);
|
|
@@ -2216,7 +2837,7 @@ async function safeInteractionExecution(inputSchema, outputSchema, raw, context,
|
|
|
2216
2837
|
);
|
|
2217
2838
|
const result = {
|
|
2218
2839
|
content: [
|
|
2219
|
-
{ type: "text", text:
|
|
2840
|
+
{ type: "text", text: resultModelText(structuredContent, modelText) },
|
|
2220
2841
|
...executed instanceof InteractionExecutionResult ? executed.additionalContent : []
|
|
2221
2842
|
],
|
|
2222
2843
|
structuredContent
|
|
@@ -2224,7 +2845,10 @@ async function safeInteractionExecution(inputSchema, outputSchema, raw, context,
|
|
|
2224
2845
|
return result;
|
|
2225
2846
|
} catch (error) {
|
|
2226
2847
|
if (error instanceof external_exports.ZodError) {
|
|
2227
|
-
return interactionErrorResult("invalid_arguments",
|
|
2848
|
+
return interactionErrorResult("invalid_arguments", describeInvalidToolArguments(error));
|
|
2849
|
+
}
|
|
2850
|
+
if (error instanceof BrowserTargetResolutionError) {
|
|
2851
|
+
return interactionErrorResult(error.code, error.message);
|
|
2228
2852
|
}
|
|
2229
2853
|
const secretReferenceFailure = secretReferenceToolResult(error);
|
|
2230
2854
|
if (secretReferenceFailure) return secretReferenceFailure;
|
|
@@ -2282,6 +2906,9 @@ function browserToolImageContent(data, mimeType) {
|
|
|
2282
2906
|
}
|
|
2283
2907
|
return { type: "image", data: Buffer.from(data).toString("base64"), mimeType };
|
|
2284
2908
|
}
|
|
2909
|
+
function isGoneBrowserError(error) {
|
|
2910
|
+
return error instanceof OpenGeniApiError && (error.status === 404 || error.status === 410);
|
|
2911
|
+
}
|
|
2285
2912
|
function interactionErrorResult(code, message, retryable = false, requestId) {
|
|
2286
2913
|
const error = { code, message, retryable, ...requestId ? { requestId } : {} };
|
|
2287
2914
|
return {
|
|
@@ -3101,6 +3728,7 @@ function createSecretArgumentResolver(input) {
|
|
|
3101
3728
|
import {
|
|
3102
3729
|
approvalIdentifier,
|
|
3103
3730
|
INTERACTION_REQUEST_HUMAN_MODEL_TOOL_NAME as INTERACTION_REQUEST_HUMAN_MODEL_TOOL_NAME2,
|
|
3731
|
+
RequestHumanInteractionToolInput as RequestHumanInteractionToolInput2,
|
|
3104
3732
|
CAPABILITY_DESCRIPTORS,
|
|
3105
3733
|
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS4,
|
|
3106
3734
|
DEFAULT_FIRST_PARTY_MCP_TOOLS as DEFAULT_FIRST_PARTY_MCP_TOOLS2,
|
|
@@ -5111,7 +5739,7 @@ import { existsSync, readdirSync } from "fs";
|
|
|
5111
5739
|
// ../sdk/package.json
|
|
5112
5740
|
var package_default = {
|
|
5113
5741
|
name: "@opengeni/sdk",
|
|
5114
|
-
version: "3.
|
|
5742
|
+
version: "3.4.0",
|
|
5115
5743
|
description: "Framework-agnostic TypeScript SDK for the Opengeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
|
|
5116
5744
|
license: "Apache-2.0",
|
|
5117
5745
|
repository: {
|
|
@@ -5333,7 +5961,7 @@ var package_default = {
|
|
|
5333
5961
|
// ../react/package.json
|
|
5334
5962
|
var package_default2 = {
|
|
5335
5963
|
name: "@opengeni/react",
|
|
5336
|
-
version: "3.
|
|
5964
|
+
version: "3.4.0",
|
|
5337
5965
|
description: "React hooks and styled components for Opengeni: live session streaming, chat composer, message timeline, session status, and fleet views \u2014 token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
|
|
5338
5966
|
license: "Apache-2.0",
|
|
5339
5967
|
repository: {
|
|
@@ -5670,7 +6298,7 @@ var package_default2 = {
|
|
|
5670
6298
|
// ../codemode/package.json
|
|
5671
6299
|
var package_default3 = {
|
|
5672
6300
|
name: "@opengeni/codemode",
|
|
5673
|
-
version: "3.
|
|
6301
|
+
version: "3.4.0",
|
|
5674
6302
|
description: "Attempt-frozen programmatic tool catalog and execution authority for Opengeni.",
|
|
5675
6303
|
license: "Apache-2.0",
|
|
5676
6304
|
repository: {
|
|
@@ -5720,7 +6348,7 @@ var package_default3 = {
|
|
|
5720
6348
|
// ../ogtool/package.json
|
|
5721
6349
|
var package_default4 = {
|
|
5722
6350
|
name: "@opengeni/ogtool",
|
|
5723
|
-
version: "3.
|
|
6351
|
+
version: "3.4.0",
|
|
5724
6352
|
description: "Codemode CLI and typed client entrypoint for an Opengeni execution attempt.",
|
|
5725
6353
|
license: "Apache-2.0",
|
|
5726
6354
|
repository: {
|
|
@@ -7287,7 +7915,7 @@ function callModelInputFilterForSettings(settings, options = {}) {
|
|
|
7287
7915
|
}
|
|
7288
7916
|
function baseModelInputFilterForSettings(settings) {
|
|
7289
7917
|
const stripProviderIds = settings.openaiProviderItemIds === "strip";
|
|
7290
|
-
|
|
7918
|
+
const projectItems = memoizedInputItemProjectionFilter(
|
|
7291
7919
|
(source) => {
|
|
7292
7920
|
let item = restoreGenericDispatchHistoryItem(source);
|
|
7293
7921
|
item = normalizeComputerCallAction(
|
|
@@ -7303,7 +7931,12 @@ function baseModelInputFilterForSettings(settings) {
|
|
|
7303
7931
|
// latest model/tool step instead of walking a six-figure history again.
|
|
7304
7932
|
{ appendOnlyInput: true }
|
|
7305
7933
|
);
|
|
7934
|
+
return composeCallModelInputFilters([interactionFamilyDisclosureFilter, projectItems]);
|
|
7306
7935
|
}
|
|
7936
|
+
var interactionFamilyDisclosureFilter = ({ modelData }) => {
|
|
7937
|
+
const input = expandInteractionFamilyDisclosures(modelData.input);
|
|
7938
|
+
return input === modelData.input ? modelData : { ...modelData, input };
|
|
7939
|
+
};
|
|
7307
7940
|
|
|
7308
7941
|
// src/workspace-governance.ts
|
|
7309
7942
|
import {
|
|
@@ -9367,6 +10000,18 @@ function activeModelToolInvocation(modelName) {
|
|
|
9367
10000
|
const invocation = modelToolInvocation.getStore();
|
|
9368
10001
|
return invocation?.modelName === modelName ? invocation : null;
|
|
9369
10002
|
}
|
|
10003
|
+
function interactionRequestArgumentsProblem(serialized) {
|
|
10004
|
+
let value;
|
|
10005
|
+
try {
|
|
10006
|
+
value = JSON.parse(serialized);
|
|
10007
|
+
} catch {
|
|
10008
|
+
return "Invalid interaction_request_human arguments: they are not valid JSON. Nothing was requested; call it again with a JSON object matching its schema.";
|
|
10009
|
+
}
|
|
10010
|
+
const parsed = RequestHumanInteractionToolInput2.safeParse(value);
|
|
10011
|
+
if (parsed.success) return null;
|
|
10012
|
+
const issues = parsed.error.issues.slice(0, 5).map((issue) => `${issue.path.join(".") || "arguments"}: ${issue.message}`);
|
|
10013
|
+
return `Invalid interaction_request_human arguments: ${issues.join("; ")}. Nothing was requested; call it again with corrected arguments.`;
|
|
10014
|
+
}
|
|
9370
10015
|
function installInteractionInterventionPolicy(agent, approvedToolCallId) {
|
|
9371
10016
|
const approvalRequiredCallIds = /* @__PURE__ */ new Set();
|
|
9372
10017
|
const listMcpTools = agent.getMcpTools.bind(agent);
|
|
@@ -9380,6 +10025,20 @@ function installInteractionInterventionPolicy(agent, approvedToolCallId) {
|
|
|
9380
10025
|
const originalInvoke = tool2.invoke.bind(tool2);
|
|
9381
10026
|
return {
|
|
9382
10027
|
...tool2,
|
|
10028
|
+
// Runs before the approval pause, so invalid arguments come back to
|
|
10029
|
+
// the model as a correctable tool result. Without it the call would
|
|
10030
|
+
// pause first, the intervention could never be recorded, and the
|
|
10031
|
+
// turn would fail.
|
|
10032
|
+
inputGuardrails: [
|
|
10033
|
+
...tool2.inputGuardrails ?? [],
|
|
10034
|
+
defineToolInputGuardrail({
|
|
10035
|
+
name: "validate_interaction_request_human",
|
|
10036
|
+
run: async ({ toolCall }) => {
|
|
10037
|
+
const problem = interactionRequestArgumentsProblem(toolCall.arguments);
|
|
10038
|
+
return problem ? ToolGuardrailFunctionOutputFactory.rejectContent(problem) : ToolGuardrailFunctionOutputFactory.allow();
|
|
10039
|
+
}
|
|
10040
|
+
})
|
|
10041
|
+
],
|
|
9383
10042
|
needsApproval: async (_runContext, _parsedInput, callId) => {
|
|
9384
10043
|
if (!callId) {
|
|
9385
10044
|
throw new Error("Interaction intervention is missing its durable approval identity");
|
|
@@ -12309,7 +12968,10 @@ var PrefixedMcpServer = class _PrefixedMcpServer {
|
|
|
12309
12968
|
return {
|
|
12310
12969
|
...tool2,
|
|
12311
12970
|
name,
|
|
12312
|
-
|
|
12971
|
+
// Name the account only when the turn has several accounts of this
|
|
12972
|
+
// connector to tell apart. With one account the line adds nothing
|
|
12973
|
+
// the model can act on, and it would repeat on every tool.
|
|
12974
|
+
...this.accountLabel?.account ? {
|
|
12313
12975
|
description: `Account: ${this.accountLabel.model}. Use only this account; if the intended account for a write is unclear, ask before calling.
|
|
12314
12976
|
${tool2.description ?? ""}`.trimEnd()
|
|
12315
12977
|
} : {}
|
|
@@ -13466,7 +14128,7 @@ async function runOwnedSandboxSetup(agent, session, setupSession, opts) {
|
|
|
13466
14128
|
if (opts.recordLazyManifest) {
|
|
13467
14129
|
const manifest = agent.defaultManifest;
|
|
13468
14130
|
if (manifest) {
|
|
13469
|
-
const { recordLazyMaterializedDirectories } = await import("./lazy-manifest-
|
|
14131
|
+
const { recordLazyMaterializedDirectories } = await import("./lazy-manifest-BLZ3UZLX.js");
|
|
13470
14132
|
await recordLazyMaterializedDirectories(session, manifest);
|
|
13471
14133
|
}
|
|
13472
14134
|
}
|
|
@@ -15942,6 +16604,7 @@ export {
|
|
|
15942
16604
|
hasCanonicalEditableArtifactToolSurface,
|
|
15943
16605
|
buildOpenGeniAgent,
|
|
15944
16606
|
sessionMcpApprovalConnectionId,
|
|
16607
|
+
interactionRequestArgumentsProblem,
|
|
15945
16608
|
withStructuredViewImageFunctionResults,
|
|
15946
16609
|
buildAgentCapabilities,
|
|
15947
16610
|
sandboxRunAs,
|
|
@@ -16006,4 +16669,4 @@ export {
|
|
|
16006
16669
|
runAzureCliLoginHook,
|
|
16007
16670
|
renderSessionGoalContext2 as renderSessionGoalContext
|
|
16008
16671
|
};
|
|
16009
|
-
//# sourceMappingURL=chunk-
|
|
16672
|
+
//# sourceMappingURL=chunk-3DFH3ZHU.js.map
|