@opengeni/runtime 3.2.2 → 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.
Files changed (69) hide show
  1. package/dist/agent-LJT5NPWT.js +9 -0
  2. package/dist/assets/codemode-client.json +1 -1
  3. package/dist/browser-current-tab.d.ts +46 -0
  4. package/dist/browser-model-text.d.ts +126 -0
  5. package/dist/{chunk-2AUDDDO2.js → chunk-3DFH3ZHU.js} +784 -121
  6. package/dist/chunk-3DFH3ZHU.js.map +1 -0
  7. package/dist/{chunk-HJSIPTFA.js → chunk-4XDJ4TJA.js} +2 -2
  8. package/dist/{chunk-XQ23VCZ4.js → chunk-6FQ6KEII.js} +3 -3
  9. package/dist/{chunk-7LJ7KDPI.js → chunk-ERD4ICVB.js} +4 -3
  10. package/dist/{chunk-462CH77G.js → chunk-ETTCGPBT.js} +400 -9
  11. package/dist/chunk-ETTCGPBT.js.map +1 -0
  12. package/dist/{chunk-7OUG7WBV.js → chunk-GWRBALGQ.js} +181 -13
  13. package/dist/chunk-GWRBALGQ.js.map +1 -0
  14. package/dist/{chunk-YG26XE7B.js → chunk-JYDG2A7H.js} +2 -2
  15. package/dist/{chunk-RSHQSLEJ.js → chunk-KIL4FGX5.js} +3 -3
  16. package/dist/{chunk-NWS4HPB7.js → chunk-MIAL5I4O.js} +2 -2
  17. package/dist/{chunk-Z5U6WE22.js → chunk-PRZPGRIK.js} +2 -2
  18. package/dist/{chunk-KCPW4K7L.js → chunk-PZQUUBEB.js} +2 -2
  19. package/dist/{chunk-5WJOPANS.js → chunk-Y5THZH5N.js} +7 -7
  20. package/dist/codex-tool-search.d.ts +9 -0
  21. package/dist/gmail-rest-mcp.js +8 -8
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.js +14 -12
  24. package/dist/interaction-tool-json-schema.d.ts +27 -0
  25. package/dist/{lazy-manifest-AJ6XPJ4F.js → lazy-manifest-BLZ3UZLX.js} +4 -4
  26. package/dist/lazy-tool-transport.d.ts +10 -0
  27. package/dist/{localSources-SSIEH5F5.js → localSources-I6SIQ6CX.js} +6 -6
  28. package/dist/model-call.js +3 -3
  29. package/dist/sandbox/browser-control-client.d.ts +87 -0
  30. package/dist/sandbox/browser-control-http.d.ts +33 -0
  31. package/dist/sandbox/index.d.ts +1 -1
  32. package/dist/sandbox/index.js +7 -7
  33. package/dist/sandbox/routing/backend-resolver.d.ts +1 -0
  34. package/dist/sandbox/selfhosted/session.d.ts +22 -0
  35. package/dist/slack-rest-mcp.js +8 -8
  36. package/dist/workspace-tool-gateway.js +12 -12
  37. package/package.json +14 -14
  38. package/src/browser-current-tab.ts +139 -0
  39. package/src/browser-model-text.ts +378 -0
  40. package/src/bundled_site_skills/opengeni-sites/SKILL.md +46 -12
  41. package/src/codex-tool-search.ts +53 -0
  42. package/src/index.ts +39 -1
  43. package/src/interaction-tool-json-schema.ts +281 -0
  44. package/src/interaction-tools.ts +425 -235
  45. package/src/lazy-tool-transport.ts +229 -10
  46. package/src/model-input.ts +12 -1
  47. package/src/sandbox/browser-control-client.ts +425 -0
  48. package/src/sandbox/browser-control-http.ts +32 -0
  49. package/src/sandbox/index.ts +4 -0
  50. package/src/sandbox/routing/backend-resolver.ts +2 -0
  51. package/src/sandbox/selfhosted/session.ts +154 -0
  52. package/dist/agent-CTPLA3HP.js +0 -9
  53. package/dist/browser-action-json-schema.d.ts +0 -4
  54. package/dist/chunk-2AUDDDO2.js.map +0 -1
  55. package/dist/chunk-462CH77G.js.map +0 -1
  56. package/dist/chunk-7OUG7WBV.js.map +0 -1
  57. package/src/browser-action-json-schema.ts +0 -10
  58. /package/dist/{agent-CTPLA3HP.js.map → agent-LJT5NPWT.js.map} +0 -0
  59. /package/dist/{chunk-HJSIPTFA.js.map → chunk-4XDJ4TJA.js.map} +0 -0
  60. /package/dist/{chunk-XQ23VCZ4.js.map → chunk-6FQ6KEII.js.map} +0 -0
  61. /package/dist/{chunk-7LJ7KDPI.js.map → chunk-ERD4ICVB.js.map} +0 -0
  62. /package/dist/{chunk-YG26XE7B.js.map → chunk-JYDG2A7H.js.map} +0 -0
  63. /package/dist/{chunk-RSHQSLEJ.js.map → chunk-KIL4FGX5.js.map} +0 -0
  64. /package/dist/{chunk-NWS4HPB7.js.map → chunk-MIAL5I4O.js.map} +0 -0
  65. /package/dist/{chunk-Z5U6WE22.js.map → chunk-PRZPGRIK.js.map} +0 -0
  66. /package/dist/{chunk-KCPW4K7L.js.map → chunk-PZQUUBEB.js.map} +0 -0
  67. /package/dist/{chunk-5WJOPANS.js.map → chunk-Y5THZH5N.js.map} +0 -0
  68. /package/dist/{lazy-manifest-AJ6XPJ4F.js.map → lazy-manifest-BLZ3UZLX.js.map} +0 -0
  69. /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-462CH77G.js";
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-7OUG7WBV.js";
105
+ } from "./chunk-GWRBALGQ.js";
105
106
  import {
106
107
  GMAIL_REST_MCP_BRIDGE_ADAPTER,
107
108
  gmailRestResultOutcome,
108
109
  isOfficialGmailMcpConfig
109
- } from "./chunk-XQ23VCZ4.js";
110
+ } from "./chunk-6FQ6KEII.js";
110
111
  import {
111
112
  SLACK_REST_MCP_BRIDGE_ADAPTER
112
- } from "./chunk-RSHQSLEJ.js";
113
+ } from "./chunk-KIL4FGX5.js";
113
114
  import {
114
115
  ConnectorAttachmentTransferError,
115
116
  projectConnectorAttachmentTransfers
116
- } from "./chunk-Z5U6WE22.js";
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-5WJOPANS.js";
131
+ } from "./chunk-Y5THZH5N.js";
131
132
  import {
132
133
  SandboxAgent,
133
134
  filesystem,
134
135
  shell
135
- } from "./chunk-HJSIPTFA.js";
136
+ } from "./chunk-4XDJ4TJA.js";
136
137
  import {
137
138
  connectMcpServers
138
- } from "./chunk-KCPW4K7L.js";
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-7LJ7KDPI.js";
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-action-json-schema.ts
388
- function browserActionInputJsonSchema(schema) {
389
- return external_exports.toJSONSchema(schema, {
390
- target: "draft-2020-12",
391
- reused: "ref"
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: external_exports.string().uuid(),
467
- targetId: external_exports.string().min(1).max(512),
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: external_exports.string().uuid(),
489
- targetId: external_exports.string().min(1).max(512),
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: external_exports.string().uuid() }).strict(),
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: external_exports.string().uuid(),
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: external_exports.string().uuid(),
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: external_exports.string().uuid(),
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: external_exports.string().uuid(),
708
- targetId: external_exports.string().min(1).max(512),
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: external_exports.string().uuid(),
714
- targetId: external_exports.string().min(1).max(512),
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: external_exports.string().uuid(),
724
- targetId: external_exports.string().min(1).max(512),
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.name === "browser_act" ? browserActionInputJsonSchema(options.input) : jsonSchema(options.input),
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 exact session and tab state, plus observation: a compact snapshot of the opened (or selected) tab when one is available. With initialUrl, targets holds only the opened tab and otherTabCount counts the rest (browser_tabs list shows them). Reuse its refs and generations for the first action instead of observing again.`,
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
- execute: async (value, context) => await openBrowser(input.transport, input.workspaceId, input.sessionId, value, context)
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 mutationObservation, the operation's compact page snapshot. Reuse its refs and generations for immediate actions; refresh after later page changes.",
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
- execute: async (value) => {
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
- value.browserSessionId,
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
- value.browserSessionId,
1562
+ browserSessionId,
1000
1563
  value.targetId
1001
1564
  );
1002
1565
  } else if (value.operation === "close") {
1003
- return agentTargetList(
1004
- await input.transport.closeBrowserTarget(
1005
- input.workspaceId,
1006
- value.browserSessionId,
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
- input.workspaceId,
1013
- value.browserSessionId
1014
- );
1015
- return mutationObservation ? {
1016
- ...agentTargetList(tabs),
1017
- mutationObservation: projectBrowserObservation(mutationObservation, "compact")
1018
- } : agentTargetList(tabs);
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: "Read one tab's URL, title, viewport, causal generations, and a bounded accessibility view. Compact view is the default: agentView lists selected refs, and omittedNodeCount or clippedFieldCount appear only when something was left out; it is not a complete page tree. Empty and default fields are omitted. Set view=full for the complete accessibility snapshot. Set includeScreenshot=true to add a current still image as tool image content; browser_screenshot is faster when only pixels are needed.",
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
- execute: async (value) => {
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
- value.browserSessionId,
1034
- value.targetId
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
- value.browserSessionId,
1056
- value.targetId
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
- execute: async (value) => {
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
- value.browserSessionId,
1082
- value.targetId
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
- value.browserSessionId,
1114
- value.targetId,
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
- value.browserSessionId,
1143
- value.targetId,
1700
+ browserSessionId,
1701
+ targetId,
1144
1702
  {},
1145
- { fullPage: value.fullPage ?? false, ...value.quality ? { quality: value.quality } : {} }
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. Omit generation fences to fetch fresh generation metadata without scanning accessibility; supplying all three fences skips that state read while preserving controller validation. The default receipt includes a compact accessibility view with explicit omissions; set view=full for the complete observation, or view=none when no post-action tree 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.",
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
- execute: async (value, context) => {
1178
- const receipt = await input.transport.actInBrowser(
1179
- input.workspaceId,
1180
- value.browserSessionId,
1181
- {
1182
- operationId: context.operationId,
1183
- targetId: value.targetId,
1184
- ...value.expectedTargetGeneration === void 0 ? {} : { expectedTargetGeneration: value.expectedTargetGeneration },
1185
- ...value.expectedDocumentGeneration === void 0 ? {} : { expectedDocumentGeneration: value.expectedDocumentGeneration },
1186
- ...value.expectedFrameId === void 0 ? {} : { expectedFrameId: value.expectedFrameId },
1187
- ...value.view === "none" ? { observationMode: "none" } : {},
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 input.transport.listBrowserDiagnostics(
1215
- input.workspaceId,
1216
- value.browserSessionId,
1217
- value.targetId,
1218
- {
1219
- ...value.kinds ? { kinds: value.kinds } : {},
1220
- ...value.after !== void 0 ? { after: value.after } : {},
1221
- ...value.limit !== void 0 ? { limit: value.limit } : {}
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
- session = (await transport.createBrowserSession(workspaceId, {
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
- })).session;
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) : void 0;
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
- async function safeInteractionExecution(inputSchema, outputSchema, raw, context, execute, readOnly) {
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: JSON.stringify(structuredContent) },
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", "Interaction tool arguments are invalid.");
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.2.2",
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.2.2",
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.2.2",
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.2.2",
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
- return memoizedInputItemProjectionFilter(
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
- ...this.accountLabel ? {
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-AJ6XPJ4F.js");
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-2AUDDDO2.js.map
16672
+ //# sourceMappingURL=chunk-3DFH3ZHU.js.map