@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.
Files changed (64) 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-XRX57ZQO.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-EK7IW2FR.js → chunk-ETTCGPBT.js} +224 -6
  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 +77 -0
  30. package/dist/sandbox/index.d.ts +1 -1
  31. package/dist/sandbox/index.js +7 -7
  32. package/dist/sandbox/selfhosted/session.d.ts +3 -0
  33. package/dist/slack-rest-mcp.js +8 -8
  34. package/dist/workspace-tool-gateway.js +12 -12
  35. package/package.json +14 -14
  36. package/src/browser-current-tab.ts +139 -0
  37. package/src/browser-model-text.ts +378 -0
  38. package/src/codex-tool-search.ts +53 -0
  39. package/src/index.ts +39 -1
  40. package/src/interaction-tool-json-schema.ts +281 -0
  41. package/src/interaction-tools.ts +425 -235
  42. package/src/lazy-tool-transport.ts +229 -10
  43. package/src/model-input.ts +12 -1
  44. package/src/sandbox/browser-control-client.ts +336 -0
  45. package/src/sandbox/index.ts +4 -0
  46. package/src/sandbox/selfhosted/session.ts +38 -0
  47. package/dist/agent-CTPLA3HP.js +0 -9
  48. package/dist/browser-action-json-schema.d.ts +0 -4
  49. package/dist/chunk-7OUG7WBV.js.map +0 -1
  50. package/dist/chunk-EK7IW2FR.js.map +0 -1
  51. package/dist/chunk-XRX57ZQO.js.map +0 -1
  52. package/src/browser-action-json-schema.ts +0 -10
  53. /package/dist/{agent-CTPLA3HP.js.map → agent-LJT5NPWT.js.map} +0 -0
  54. /package/dist/{chunk-HJSIPTFA.js.map → chunk-4XDJ4TJA.js.map} +0 -0
  55. /package/dist/{chunk-XQ23VCZ4.js.map → chunk-6FQ6KEII.js.map} +0 -0
  56. /package/dist/{chunk-7LJ7KDPI.js.map → chunk-ERD4ICVB.js.map} +0 -0
  57. /package/dist/{chunk-YG26XE7B.js.map → chunk-JYDG2A7H.js.map} +0 -0
  58. /package/dist/{chunk-RSHQSLEJ.js.map → chunk-KIL4FGX5.js.map} +0 -0
  59. /package/dist/{chunk-NWS4HPB7.js.map → chunk-MIAL5I4O.js.map} +0 -0
  60. /package/dist/{chunk-Z5U6WE22.js.map → chunk-PRZPGRIK.js.map} +0 -0
  61. /package/dist/{chunk-KCPW4K7L.js.map → chunk-PZQUUBEB.js.map} +0 -0
  62. /package/dist/{chunk-5WJOPANS.js.map → chunk-Y5THZH5N.js.map} +0 -0
  63. /package/dist/{lazy-manifest-AJ6XPJ4F.js.map → lazy-manifest-BLZ3UZLX.js.map} +0 -0
  64. /package/dist/{localSources-SSIEH5F5.js.map → localSources-I6SIQ6CX.js.map} +0 -0
@@ -270,6 +270,8 @@ export type PlacementBrowserSessionReference = {
270
270
 
271
271
  export type PlacementBrowserSession = PlacementBrowserSessionReference & {
272
272
  observation: BrowserObservationValue;
273
+ /** The tab inventory at creation, when the controller reports it. */
274
+ targets?: BrowserTargetValue[];
273
275
  };
274
276
 
275
277
  export type PlacementComputerSessionReference = {
@@ -415,6 +417,73 @@ export type PlacementBrowserStateCaptureReceipt = PlacementBrowserSessionReferen
415
417
  };
416
418
  };
417
419
 
420
+ /** The exact controller authority a preserved working copy was launched
421
+ * under; the controller refuses any other. */
422
+ export type PlacementBrowserWorkingCopyAuthority = PlacementBrowserSessionReference & {
423
+ tokenGeneration: number;
424
+ controlToken: string;
425
+ viewToken: string;
426
+ };
427
+
428
+ export const BROWSER_WORKING_COPY_REFUSALS = [
429
+ "unsupported_platform",
430
+ "browser_running",
431
+ "working_copy_invalid",
432
+ "receipt_not_adoptable",
433
+ "authority_changed",
434
+ "process_state_unknown",
435
+ "adoption_not_needed",
436
+ "adoption_unresolved",
437
+ ] as const;
438
+ export type PlacementBrowserWorkingCopyRefusal = (typeof BROWSER_WORKING_COPY_REFUSALS)[number];
439
+
440
+ export const BROWSER_WORKING_COPY_ADOPTION_PHASES = [
441
+ "intent",
442
+ "copied",
443
+ "receipt",
444
+ "source_preserved",
445
+ "adopted",
446
+ "interrupted",
447
+ "failed",
448
+ "collision",
449
+ "reverting",
450
+ "reverted",
451
+ ] as const;
452
+ export type PlacementBrowserWorkingCopyAdoptionPhase =
453
+ (typeof BROWSER_WORKING_COPY_ADOPTION_PHASES)[number];
454
+
455
+ export type PlacementBrowserWorkingCopyAdoption = PlacementBrowserSessionReference & {
456
+ operationId: string;
457
+ manifestDigest: string;
458
+ phase: PlacementBrowserWorkingCopyAdoptionPhase;
459
+ failureCode: string | null;
460
+ /** Directories this adoption kept beside the browser's own, by name. */
461
+ retainedDirectories: string[];
462
+ createdAt: string;
463
+ updatedAt: string;
464
+ };
465
+
466
+ export type PlacementBrowserWorkingCopyInspection = PlacementBrowserSessionReference & {
467
+ platformSupported: boolean;
468
+ refusal: PlacementBrowserWorkingCopyRefusal | null;
469
+ /** Exact digest of the bytes an adoption would take; null when refused. */
470
+ manifest: { digest: string; entries: number; bytes: number; excluded: string[] } | null;
471
+ profileIdentityMatches: boolean;
472
+ /** false only when no process provably uses the profile. */
473
+ profileInUse: boolean | null;
474
+ receipt: {
475
+ operationId: string;
476
+ intent: "launch" | "suspend" | "retire" | "adopt";
477
+ state: string;
478
+ directoryLaunchAllowed: boolean;
479
+ authorityMatches: boolean;
480
+ /** True when this working copy was first launched from a saved checkpoint. */
481
+ launchedFromCheckpoint: boolean;
482
+ adoption: { operationId: string; manifestDigest: string } | null;
483
+ } | null;
484
+ activeAdoption: PlacementBrowserWorkingCopyAdoption | null;
485
+ };
486
+
418
487
  export type ProvisionBrowserControlClientInput = {
419
488
  adminToken: string;
420
489
  adminTokenFile?: string;
@@ -652,6 +721,7 @@ export class BrowserControlClient {
652
721
  return {
653
722
  ...returnedReference,
654
723
  observation: BrowserObservation.parse(data.observation),
724
+ ...creationTargets(data.targets, returnedReference),
655
725
  };
656
726
  }
657
727
 
@@ -882,6 +952,103 @@ export class BrowserControlClient {
882
952
  return receipt;
883
953
  }
884
954
 
955
+ /** Read-only evidence about a preserved working copy whose controller
956
+ * memory was lost: the exact digest of its bytes and whether it can be
957
+ * adopted. Hashing a large profile can take minutes. */
958
+ async inspectWorkingCopy(
959
+ input: PlacementBrowserWorkingCopyAuthority,
960
+ ): Promise<PlacementBrowserWorkingCopyInspection> {
961
+ const reference = parseReference(input);
962
+ const data = await this.requestJson({
963
+ method: "POST",
964
+ path: `/v1/browser-sessions/${reference.browserSessionId}/working-copy/inspection`,
965
+ token: this.adminToken,
966
+ body: workingCopyAuthorityBody(reference, input),
967
+ timeoutMs: BROWSER_STATE_TRANSFER_TIMEOUT_MS,
968
+ });
969
+ return parseWorkingCopyInspection(data, reference);
970
+ }
971
+
972
+ /** Adopt the exact inspected bytes of a preserved working copy. A lost reply
973
+ * is checked with {@link workingCopyAdoption}. Sending the same operation id
974
+ * again never repeats a side effect: it only settles what that operation
975
+ * already did, under the authority that approved it. */
976
+ async adoptWorkingCopy(
977
+ input: PlacementBrowserWorkingCopyAuthority & { operationId: string; manifestDigest: string },
978
+ ): Promise<PlacementBrowserWorkingCopyAdoption> {
979
+ const reference = parseReference(input);
980
+ const operationId = requireUuid(input.operationId, "working copy adoption id");
981
+ const data = await this.requestJson({
982
+ method: "POST",
983
+ path: `/v1/browser-sessions/${reference.browserSessionId}/working-copy/adoptions`,
984
+ token: this.adminToken,
985
+ body: {
986
+ ...workingCopyAuthorityBody(reference, input),
987
+ operationId,
988
+ manifestDigest: sha256(input.manifestDigest, "working copy manifest digest"),
989
+ },
990
+ timeoutMs: BROWSER_STATE_TRANSFER_TIMEOUT_MS,
991
+ });
992
+ const adoption = parseWorkingCopyAdoption(data, reference, "current");
993
+ if (adoption.operationId !== operationId) {
994
+ throw new BrowserControlProtocolError("browser controller returned another adoption");
995
+ }
996
+ return adoption;
997
+ }
998
+
999
+ /** The recorded state of one adoption, read without changing it. */
1000
+ async workingCopyAdoption(
1001
+ reference: PlacementBrowserSessionReference,
1002
+ operationId: string,
1003
+ ): Promise<{ inFlight: boolean; adoption: PlacementBrowserWorkingCopyAdoption | null }> {
1004
+ const binding = parseReference(reference);
1005
+ const id = requireUuid(operationId, "working copy adoption id");
1006
+ const data = await this.requestJson({
1007
+ method: "GET",
1008
+ path: `/v1/browser-sessions/${binding.browserSessionId}/working-copy/adoptions/${id}`,
1009
+ token: this.adminToken,
1010
+ });
1011
+ if (!isRecord(data) || typeof data.inFlight !== "boolean") {
1012
+ throw new BrowserControlProtocolError(
1013
+ "browser controller returned malformed adoption status",
1014
+ );
1015
+ }
1016
+ const adoption =
1017
+ data.adoption === null ? null : parseWorkingCopyAdoption(data.adoption, binding, "recorded");
1018
+ if (adoption && adoption.operationId !== id) {
1019
+ throw new BrowserControlProtocolError("browser controller returned another adoption");
1020
+ }
1021
+ return { inFlight: data.inFlight, adoption };
1022
+ }
1023
+
1024
+ /** Revert one unfinished adoption under the browser's current authority:
1025
+ * its own directory goes back to the live path and the staged copy is
1026
+ * kept. Retrying the same revert finishes one that stopped part way. */
1027
+ async revertWorkingCopyAdoption(
1028
+ input: PlacementBrowserWorkingCopyAuthority & { operationId: string },
1029
+ ): Promise<{ inFlight: boolean; adoption: PlacementBrowserWorkingCopyAdoption | null }> {
1030
+ const reference = parseReference(input);
1031
+ const id = requireUuid(input.operationId, "working copy adoption id");
1032
+ const data = await this.requestJson({
1033
+ method: "POST",
1034
+ path: `/v1/browser-sessions/${reference.browserSessionId}/working-copy/adoptions/${id}/revert`,
1035
+ token: this.adminToken,
1036
+ body: workingCopyAuthorityBody(reference, input),
1037
+ timeoutMs: BROWSER_STATE_TRANSFER_TIMEOUT_MS,
1038
+ });
1039
+ if (!isRecord(data) || typeof data.inFlight !== "boolean") {
1040
+ throw new BrowserControlProtocolError("browser controller returned malformed revert status");
1041
+ }
1042
+ const adoption =
1043
+ data.adoption === null
1044
+ ? null
1045
+ : parseWorkingCopyAdoption(data.adoption, reference, "recorded");
1046
+ if (adoption && adoption.operationId !== id) {
1047
+ throw new BrowserControlProtocolError("browser controller returned another adoption");
1048
+ }
1049
+ return { inFlight: data.inFlight, adoption };
1050
+ }
1051
+
885
1052
  sessionClient(input: {
886
1053
  reference: PlacementBrowserSessionReference;
887
1054
  controlToken: string;
@@ -2704,6 +2871,28 @@ function parseReference(value: unknown): PlacementBrowserSessionReference {
2704
2871
  };
2705
2872
  }
2706
2873
 
2874
+ /** A create's tab inventory is a convenience: an older controller omits it,
2875
+ * and an inventory that does not validate, or that belongs to another
2876
+ * binding, is dropped rather than failing a browser that did launch. */
2877
+ function creationTargets(
2878
+ value: unknown,
2879
+ reference: PlacementBrowserSessionReference,
2880
+ ): { targets?: BrowserTargetValue[] } {
2881
+ if (!Array.isArray(value) || value.length > 10_000) return {};
2882
+ const targets: BrowserTargetValue[] = [];
2883
+ for (const entry of value) {
2884
+ const parsed = BrowserTarget.safeParse(entry);
2885
+ if (
2886
+ !parsed.success ||
2887
+ parsed.data.browserSessionId !== reference.browserSessionId ||
2888
+ parsed.data.controllerGeneration !== reference.controllerGeneration
2889
+ )
2890
+ return {};
2891
+ targets.push(parsed.data);
2892
+ }
2893
+ return { targets };
2894
+ }
2895
+
2707
2896
  function parseComputerReference(value: unknown): PlacementComputerSessionReference {
2708
2897
  if (!isRecord(value)) {
2709
2898
  throw new BrowserControlProtocolError("computer session binding is invalid");
@@ -2879,6 +3068,140 @@ function boundedProxyUrl(value: string): string {
2879
3068
  return url.toString();
2880
3069
  }
2881
3070
 
3071
+ function workingCopyAuthorityBody(
3072
+ reference: PlacementBrowserSessionReference,
3073
+ input: PlacementBrowserWorkingCopyAuthority,
3074
+ ) {
3075
+ return {
3076
+ controllerGeneration: reference.controllerGeneration,
3077
+ tokenGeneration: positiveSafeInteger(input.tokenGeneration, "token generation"),
3078
+ controlToken: requireToken(input.controlToken, "control token"),
3079
+ viewToken: requireToken(input.viewToken, "view token"),
3080
+ };
3081
+ }
3082
+
3083
+ /**
3084
+ * An adoption record. `generation: "current"` (a new adoption) requires the
3085
+ * record to belong to the requesting controller generation. `"recorded"`
3086
+ * (status, revert, inspection) keeps the generation the adoption was recorded
3087
+ * under: recovering an unfinished adoption after a controller restart means
3088
+ * reading and reverting a record made by an earlier generation, under the
3089
+ * browser's legitimate current control. The browser and operation always
3090
+ * have to match exactly.
3091
+ */
3092
+ function parseWorkingCopyAdoption(
3093
+ value: unknown,
3094
+ reference: PlacementBrowserSessionReference,
3095
+ generation: "current" | "recorded",
3096
+ ): PlacementBrowserWorkingCopyAdoption {
3097
+ if (
3098
+ !isRecord(value) ||
3099
+ value.browserSessionId !== reference.browserSessionId ||
3100
+ (generation === "current" && value.controllerGeneration !== reference.controllerGeneration) ||
3101
+ !BROWSER_WORKING_COPY_ADOPTION_PHASES.includes(
3102
+ value.phase as PlacementBrowserWorkingCopyAdoptionPhase,
3103
+ ) ||
3104
+ !(value.failureCode === null || typeof value.failureCode === "string") ||
3105
+ !Array.isArray(value.retainedDirectories) ||
3106
+ value.retainedDirectories.length > 64 ||
3107
+ !value.retainedDirectories.every(
3108
+ (name) => typeof name === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/u.test(name),
3109
+ )
3110
+ ) {
3111
+ throw new BrowserControlProtocolError("browser controller returned a malformed adoption");
3112
+ }
3113
+ return {
3114
+ browserSessionId: reference.browserSessionId,
3115
+ controllerGeneration:
3116
+ generation === "current"
3117
+ ? reference.controllerGeneration
3118
+ : requireGeneration(value.controllerGeneration),
3119
+ operationId: requireUuid(value.operationId, "working copy adoption id"),
3120
+ manifestDigest: sha256(value.manifestDigest, "working copy manifest digest"),
3121
+ phase: value.phase as PlacementBrowserWorkingCopyAdoptionPhase,
3122
+ failureCode:
3123
+ value.failureCode === null ? null : requireOpaqueId(value.failureCode, "failure code"),
3124
+ retainedDirectories: value.retainedDirectories as string[],
3125
+ createdAt: timestamp(value.createdAt, "adoption created at"),
3126
+ updatedAt: timestamp(value.updatedAt, "adoption updated at"),
3127
+ };
3128
+ }
3129
+
3130
+ function parseWorkingCopyInspection(
3131
+ value: unknown,
3132
+ reference: PlacementBrowserSessionReference,
3133
+ ): PlacementBrowserWorkingCopyInspection {
3134
+ if (
3135
+ !isRecord(value) ||
3136
+ value.browserSessionId !== reference.browserSessionId ||
3137
+ value.controllerGeneration !== reference.controllerGeneration ||
3138
+ typeof value.platformSupported !== "boolean" ||
3139
+ typeof value.profileIdentityMatches !== "boolean" ||
3140
+ !(value.profileInUse === null || typeof value.profileInUse === "boolean") ||
3141
+ !(
3142
+ value.refusal === null ||
3143
+ BROWSER_WORKING_COPY_REFUSALS.includes(value.refusal as PlacementBrowserWorkingCopyRefusal)
3144
+ )
3145
+ ) {
3146
+ throw new BrowserControlProtocolError("browser controller returned a malformed inspection");
3147
+ }
3148
+ let manifest: PlacementBrowserWorkingCopyInspection["manifest"] = null;
3149
+ if (value.manifest !== null) {
3150
+ if (!isRecord(value.manifest)) {
3151
+ throw new BrowserControlProtocolError("browser controller returned a malformed manifest");
3152
+ }
3153
+ manifest = {
3154
+ digest: sha256(value.manifest.digest, "working copy manifest digest"),
3155
+ entries: nonnegativeSafeInteger(value.manifest.entries, "working copy entries"),
3156
+ bytes: nonnegativeSafeInteger(value.manifest.bytes, "working copy bytes"),
3157
+ excluded: excludedWorkingCopyEntries(value.manifest.excluded),
3158
+ };
3159
+ }
3160
+ let receipt: PlacementBrowserWorkingCopyInspection["receipt"] = null;
3161
+ if (value.receipt !== null) {
3162
+ const raw = value.receipt;
3163
+ if (
3164
+ !isRecord(raw) ||
3165
+ !["launch", "suspend", "retire", "adopt"].includes(raw.intent as string) ||
3166
+ typeof raw.state !== "string" ||
3167
+ typeof raw.directoryLaunchAllowed !== "boolean" ||
3168
+ typeof raw.authorityMatches !== "boolean" ||
3169
+ !(raw.restoreAuthorityDigest === null || typeof raw.restoreAuthorityDigest === "string") ||
3170
+ !(raw.adoption === null || isRecord(raw.adoption))
3171
+ ) {
3172
+ throw new BrowserControlProtocolError("browser controller returned a malformed receipt");
3173
+ }
3174
+ receipt = {
3175
+ operationId: requireUuid(raw.operationId, "working runtime receipt id"),
3176
+ intent: raw.intent as "launch" | "suspend" | "retire" | "adopt",
3177
+ state: requireOpaqueId(raw.state, "working runtime receipt state"),
3178
+ directoryLaunchAllowed: raw.directoryLaunchAllowed,
3179
+ authorityMatches: raw.authorityMatches,
3180
+ launchedFromCheckpoint: raw.restoreAuthorityDigest !== null,
3181
+ adoption: isRecord(raw.adoption)
3182
+ ? {
3183
+ operationId: requireUuid(raw.adoption.operationId, "working copy adoption id"),
3184
+ manifestDigest: sha256(raw.adoption.manifestDigest, "working copy manifest digest"),
3185
+ }
3186
+ : null,
3187
+ };
3188
+ }
3189
+ return {
3190
+ browserSessionId: reference.browserSessionId,
3191
+ controllerGeneration: reference.controllerGeneration,
3192
+ platformSupported: value.platformSupported,
3193
+ refusal: value.refusal as PlacementBrowserWorkingCopyRefusal | null,
3194
+ manifest,
3195
+ profileIdentityMatches: value.profileIdentityMatches,
3196
+ profileInUse: value.profileInUse,
3197
+ receipt,
3198
+ activeAdoption:
3199
+ value.activeAdoption === null || value.activeAdoption === undefined
3200
+ ? null
3201
+ : parseWorkingCopyAdoption(value.activeAdoption, reference, "recorded"),
3202
+ };
3203
+ }
3204
+
2882
3205
  function parseStateCaptureReceipt(value: unknown): PlacementBrowserStateCaptureReceipt {
2883
3206
  if (!isRecord(value) || !isRecord(value.manifest)) {
2884
3207
  throw new BrowserControlProtocolError(
@@ -3687,6 +4010,19 @@ function nonnegativeSafeInteger(value: unknown, label: string): number {
3687
4010
  return value;
3688
4011
  }
3689
4012
 
4013
+ function excludedWorkingCopyEntries(value: unknown): string[] {
4014
+ if (
4015
+ !Array.isArray(value) ||
4016
+ value.length > 16 ||
4017
+ !value.every((entry) => typeof entry === "string" && entry.length > 0 && entry.length <= 256)
4018
+ ) {
4019
+ throw new BrowserControlProtocolError(
4020
+ "browser controller returned malformed working copy exclusions",
4021
+ );
4022
+ }
4023
+ return [...value];
4024
+ }
4025
+
3690
4026
  function parseUnsignedInteger(value: string, label: string): number {
3691
4027
  const trimmed = value.trim();
3692
4028
  if (!/^(0|[1-9][0-9]*)$/u.test(trimmed)) {
@@ -361,6 +361,10 @@ export {
361
361
  type PlacementBrowserNetworkRoute,
362
362
  type PlacementBrowserTransport,
363
363
  type PlacementBrowserStateCaptureReceipt,
364
+ type PlacementBrowserWorkingCopyAdoption,
365
+ type PlacementBrowserWorkingCopyAuthority,
366
+ type PlacementBrowserWorkingCopyInspection,
367
+ type PlacementBrowserWorkingCopyRefusal,
364
368
  type ComputerControlFrame,
365
369
  type ComputerControlFrameMetadata,
366
370
  type ComputerFrameEvidenceMismatchReason,
@@ -284,6 +284,9 @@ export interface SelfhostedBackgroundCommandAdoption {
284
284
  connectionInstanceId: string;
285
285
  opId: string;
286
286
  command: string;
287
+ /** The exec already failed because the machine stopped answering. Record it
288
+ * with a stop request instead of as a running background command. */
289
+ abandoned?: boolean;
287
290
  }
288
291
 
289
292
  /** Exact command-admission snapshot. A worker resolves this immediately before
@@ -1359,6 +1362,34 @@ export class SelfhostedSession {
1359
1362
  reason: null,
1360
1363
  retryable: false,
1361
1364
  });
1365
+ if (
1366
+ !terminalProof &&
1367
+ !adoptedCommandId &&
1368
+ !controlError.neverSent &&
1369
+ machineStoppedAnswering(controlError) &&
1370
+ this.adoptBackgroundCommand
1371
+ ) {
1372
+ // The machine went away mid-operation. The command may still run there,
1373
+ // but only the machine can stop or report it, so this turn must not wait
1374
+ // for it. Hand it to the session's command ledger with a stop request;
1375
+ // the reconciler stops or settles it once the machine returns or its
1376
+ // runner is retired. If recording fails, turn cleanup keeps ownership.
1377
+ try {
1378
+ notifyDurableOpOwnershipTransferStarted(opId);
1379
+ const abandoned = await this.adoptBackgroundCommand({
1380
+ controlWorkspaceId: admission.controlWorkspaceId,
1381
+ enrollmentId: this.agentId,
1382
+ connectionInstanceId: admission.connectionInstanceId,
1383
+ opId,
1384
+ command,
1385
+ abandoned: true,
1386
+ });
1387
+ adoptedCommandId = abandoned.commandId;
1388
+ notifyDurableOpOwnershipTransferred(opId);
1389
+ } catch {
1390
+ notifyDurableOpOwnershipTransferFailed(opId);
1391
+ }
1392
+ }
1362
1393
  this.emitOp({
1363
1394
  op: "exec",
1364
1395
  outcome: "failed",
@@ -2703,6 +2734,13 @@ function mediaTypeFromPath(path: string): string | undefined {
2703
2734
 
2704
2735
  /** A random uint64-safe numeric nonce (the wire `PingRequest.nonce` is a uint64,
2705
2736
  * represented as a numeric string by ts-proto). */
2737
+ /** The machine itself stopped answering (offline, reconnecting past the hold
2738
+ * window, or draining), as opposed to an answer that the operation failed. */
2739
+ function machineStoppedAnswering(error: SelfhostedControlError): boolean {
2740
+ const faultClass = selfhostedFaultClass(error);
2741
+ return faultClass === "offline" || faultClass === "reconnecting" || faultClass === "draining";
2742
+ }
2743
+
2706
2744
  function randomNonce(): string {
2707
2745
  // 2^53-safe random integer as a decimal string.
2708
2746
  return String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
@@ -1,9 +0,0 @@
1
- import {
2
- SandboxAgent
3
- } from "./chunk-HJSIPTFA.js";
4
- import "./chunk-7LJ7KDPI.js";
5
- import "./chunk-PLDDJCW6.js";
6
- export {
7
- SandboxAgent
8
- };
9
- //# sourceMappingURL=agent-CTPLA3HP.js.map
@@ -1,4 +0,0 @@
1
- import type { AttemptToolJsonSchema } from "@opengeni/contracts";
2
- import { z } from "zod";
3
- /** Keep repeated browser action and locator variants once in the model schema. */
4
- export declare function browserActionInputJsonSchema(schema: z.ZodType): AttemptToolJsonSchema;