@opengeni/worker-bundle 3.0.1-canary.38874404583001 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1434,7 +1434,7 @@ async function createDefaultWorkerActivities(role, dependencies = {}) {
1434
1434
  if (dependencies.objectStorage == null) {
1435
1435
  prepareObjectStorageProvider(dependencies.settings ?? getSettings());
1436
1436
  }
1437
- return role === "control" ? (await import("./activities-control-HDHPG2FN.js")).createControlActivities(dependencies) : (await import("./activities-turn-YJ5D55CO.js")).createTurnActivities(dependencies);
1437
+ return role === "control" ? (await import("./activities-control-ROJJNNTJ.js")).createControlActivities(dependencies) : (await import("./activities-turn-4SWYWKI5.js")).createTurnActivities(dependencies);
1438
1438
  }
1439
1439
  function resolveOpenGeniWorkflowDefinition(moduleUrl = import.meta.url) {
1440
1440
  const modulePath = fileURLToPath(moduleUrl).replaceAll("\\", "/");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/worker-bundle",
3
- "version": "3.0.1-canary.38874404583001",
3
+ "version": "3.1.2",
4
4
  "description": "Opengeni worker entry and reusable embedded lifecycle, shipped with a release-coherent pre-bundled Temporal workflow artifact.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -55,29 +55,29 @@
55
55
  "dependencies": {
56
56
  "@1password/sdk": "0.5.0",
57
57
  "@llamaindex/liteparse": "2.14.2",
58
- "@opengeni/agent-proto": "3.0.1-canary.38874404583001",
59
- "@opengeni/capabilities": "3.0.1-canary.38874404583001",
60
- "@opengeni/codemode": "3.0.1-canary.38874404583001",
61
- "@opengeni/codex": "3.0.1-canary.38874404583001",
62
- "@opengeni/config": "3.0.1-canary.38874404583001",
63
- "@opengeni/contracts": "3.0.1-canary.38874404583001",
64
- "@opengeni/core": "3.0.1-canary.38874404583001",
65
- "@opengeni/db": "3.0.1-canary.38874404583001",
66
- "@opengeni/documents": "3.0.1-canary.38874404583001",
67
- "@opengeni/events": "3.0.1-canary.38874404583001",
68
- "@opengeni/github": "3.0.1-canary.38874404583001",
69
- "@opengeni/interaction": "3.0.1-canary.38874404583001",
70
- "@opengeni/jev": "3.0.1-canary.38874404583001",
71
- "@opengeni/network": "3.0.1-canary.38874404583001",
72
- "@opengeni/observability": "3.0.1-canary.38874404583001",
73
- "@opengeni/runtime": "3.0.1-canary.38874404583001",
74
- "@opengeni/sdk": "3.0.1-canary.38874404583001",
75
- "@opengeni/storage": "3.0.1-canary.38874404583001",
76
- "@opengeni/subscriptions": "3.0.1-canary.38874404583001",
77
- "@opengeni/tool-gateway": "3.0.1-canary.38874404583001",
78
- "@opengeni/vaults": "3.0.1-canary.38874404583001",
79
- "@opengeni/vaults-onepassword": "3.0.1-canary.38874404583001",
80
- "@opengeni/xai-subscription": "3.0.1-canary.38874404583001",
58
+ "@opengeni/agent-proto": "3.1.2",
59
+ "@opengeni/capabilities": "3.1.2",
60
+ "@opengeni/codemode": "3.1.2",
61
+ "@opengeni/codex": "3.1.2",
62
+ "@opengeni/config": "3.1.2",
63
+ "@opengeni/contracts": "3.1.2",
64
+ "@opengeni/core": "3.1.2",
65
+ "@opengeni/db": "3.1.2",
66
+ "@opengeni/documents": "3.1.2",
67
+ "@opengeni/events": "3.1.2",
68
+ "@opengeni/github": "3.1.2",
69
+ "@opengeni/interaction": "3.1.2",
70
+ "@opengeni/jev": "3.1.2",
71
+ "@opengeni/network": "3.1.2",
72
+ "@opengeni/observability": "3.1.2",
73
+ "@opengeni/runtime": "3.1.2",
74
+ "@opengeni/sdk": "3.1.2",
75
+ "@opengeni/storage": "3.1.2",
76
+ "@opengeni/subscriptions": "3.1.2",
77
+ "@opengeni/tool-gateway": "3.1.2",
78
+ "@opengeni/vaults": "3.1.2",
79
+ "@opengeni/vaults-onepassword": "3.1.2",
80
+ "@opengeni/xai-subscription": "3.1.2",
81
81
  "@temporalio/activity": "^1.17.0",
82
82
  "@temporalio/client": "^1.17.0",
83
83
  "@temporalio/worker": "^1.17.0",
@@ -2,6 +2,7 @@ import {
2
2
  MODEL_ATTACHMENT_REFS_FIELD,
3
3
  MODEL_ATTACHMENT_CATALOG_MARKER,
4
4
  MODEL_ATTACHMENT_CATALOG_RENDERED_FIELD,
5
+ MODEL_ATTACHMENT_IMAGE_MAX_DIMENSION_FIELD,
5
6
  FileResourceRef,
6
7
  resourceMountPath,
7
8
  readTurnExecutionPolicyV1,
@@ -21,6 +22,7 @@ import {
21
22
  type Database,
22
23
  } from "@opengeni/db";
23
24
  import {
25
+ createModelImageSizer,
24
26
  projectHistoryForProvider,
25
27
  projectRejectedProviderArtifactsFromSerializedRunState,
26
28
  projectRejectedReasoningArtifact,
@@ -418,10 +420,64 @@ function unavailableAttachmentReceiptText(ref: FileResourceRef): string {
418
420
  return requesterUnavailableReceiptText(`Attachment: fileId=${ref.fileId}`, "file");
419
421
  }
420
422
 
423
+ /** The image bound stamped on a message when it was accepted, if any. */
424
+ function attachmentImageBound(item: Record<string, unknown>): number | undefined {
425
+ const raw = item[MODEL_ATTACHMENT_IMAGE_MAX_DIMENSION_FIELD];
426
+ return typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 64 && raw <= 8192
427
+ ? raw
428
+ : undefined;
429
+ }
430
+
431
+ // Process-wide, so a long conversation does not re-encode the same photos on
432
+ // every turn. The projection depends only on the image bytes and the bound.
433
+ const boundedImageSizers = new Map<number, ReturnType<typeof createModelImageSizer>>();
434
+
435
+ type BoundedAttachmentImage = { image: string; note: string };
436
+
437
+ /**
438
+ * The model-facing rendition of one image under the bound its message was
439
+ * stamped with. Smaller images keep their original bytes. The file in the
440
+ * sandbox and in storage stays at full resolution.
441
+ */
442
+ async function boundedAttachmentImage(
443
+ attachment: ModelAttachmentContent,
444
+ bound: number,
445
+ ): Promise<BoundedAttachmentImage> {
446
+ const original = { image: attachment.dataUrl, note: "" };
447
+ const comma = attachment.dataUrl.indexOf(",");
448
+ if (comma < 0) return original;
449
+ const data = attachment.dataUrl.slice(comma + 1);
450
+ let sizer = boundedImageSizers.get(bound);
451
+ if (!sizer) {
452
+ sizer = createModelImageSizer(bound, 10 * 1024 * 1024, { jpegQuality: 85 });
453
+ boundedImageSizers.set(bound, sizer);
454
+ }
455
+ try {
456
+ const sized = await sizer(data, attachment.contentType);
457
+ if (sized.data === data && sized.mediaType === attachment.contentType) return original;
458
+ return {
459
+ image: `data:${sized.mediaType};base64,${sized.data}`,
460
+ note:
461
+ ` Shown to you downscaled to ${sized.width}x${sized.height} from ` +
462
+ `${sized.originalWidth}x${sized.originalHeight}; the file itself is full resolution.`,
463
+ };
464
+ } catch (error) {
465
+ // Decoding is deterministic: an image that cannot be resized here keeps
466
+ // the original projection on every turn rather than being dropped.
467
+ console.error("model attachment image could not be resized; sending original", {
468
+ fileId: attachment.fileId,
469
+ errorType: safeErrorType(error),
470
+ });
471
+ return original;
472
+ }
473
+ }
474
+
421
475
  /**
422
476
  * Build one turn-scoped durable-attachment projector. Resolve active refs under
423
477
  * current file authority and memoize metadata/bytes for retries and compaction.
424
478
  * A turn boundary never changes an authorized attachment's representation.
479
+ * Images of a message stamped with an image bound are shown downscaled to fit
480
+ * it; unstamped (older) messages keep their full-resolution projection.
425
481
  */
426
482
  export function createModelHistoryAttachmentProjector(
427
483
  policy: ModelAttachmentInputPolicy,
@@ -433,6 +489,7 @@ export function createModelHistoryAttachmentProjector(
433
489
  const fileById = new Map<string, FileAsset>();
434
490
  const resolvedFileIds = new Set<string>();
435
491
  const retainedByteSizes = new Map<string, number>();
492
+ const boundedById = new Map<string, BoundedAttachmentImage>();
436
493
 
437
494
  return async (items, options = {}) => {
438
495
  for (const file of options.inlineFiles ?? []) {
@@ -526,6 +583,19 @@ export function createModelHistoryAttachmentProjector(
526
583
  for (const attachment of content) contentById.set(attachment.fileId, attachment);
527
584
  }
528
585
 
586
+ for (const [index, refs] of refsByIndex) {
587
+ const item = items[index]!;
588
+ if (item[MODEL_ATTACHMENT_CATALOG_MARKER] === true) continue;
589
+ const bound = attachmentImageBound(item);
590
+ if (bound === undefined) continue;
591
+ for (const ref of refs) {
592
+ const attachment = fileById.has(ref.fileId) ? contentById.get(ref.fileId) : undefined;
593
+ const key = `${bound}:${ref.fileId}`;
594
+ if (!attachment || attachment.kind !== "image" || boundedById.has(key)) continue;
595
+ boundedById.set(key, await boundedAttachmentImage(attachment, bound));
596
+ }
597
+ }
598
+
529
599
  const projected = [...items];
530
600
  for (const [index, refs] of refsByIndex) {
531
601
  const original = items[index]!;
@@ -551,14 +621,20 @@ export function createModelHistoryAttachmentProjector(
551
621
  resolvedFileIds.has(ref.fileId) &&
552
622
  currentFile === undefined;
553
623
  const attachment = currentFile ? contentById.get(ref.fileId) : undefined;
554
- const receipt = {
555
- type: "input_text",
556
- text: excluded ? unavailableAttachmentReceiptText(ref) : attachmentReceiptText(ref),
557
- };
558
624
  if (!attachment || attachment.kind !== "image") {
559
- return [receipt];
625
+ return [
626
+ {
627
+ type: "input_text",
628
+ text: excluded ? unavailableAttachmentReceiptText(ref) : attachmentReceiptText(ref),
629
+ },
630
+ ];
560
631
  }
561
- return [receipt, { type: "input_image", image: attachment.dataUrl }];
632
+ const bound = attachmentImageBound(original);
633
+ const bounded = bound === undefined ? undefined : boundedById.get(`${bound}:${ref.fileId}`);
634
+ return [
635
+ { type: "input_text", text: attachmentReceiptText(ref) + (bounded?.note ?? "") },
636
+ { type: "input_image", image: bounded?.image ?? attachment.dataUrl },
637
+ ];
562
638
  });
563
639
  const clone: Record<string, unknown> = {
564
640
  ...original,