vargai 0.4.0-alpha77 → 0.4.0-alpha78

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/package.json CHANGED
@@ -71,7 +71,7 @@
71
71
  "zod": "^4.2.1"
72
72
  },
73
73
  "sideEffects": false,
74
- "version": "0.4.0-alpha77",
74
+ "version": "0.4.0-alpha78",
75
75
  "exports": {
76
76
  ".": "./src/index.ts",
77
77
  "./ai": "./src/ai-sdk/index.ts",
@@ -1,5 +1,6 @@
1
1
  import { existsSync, statSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
+ import { ResolvedElement } from "../resolved-element";
3
4
  import type { VargElement, VargNode } from "../types";
4
5
 
5
6
  export function resolvePath(path: string): string {
@@ -84,11 +85,22 @@ function serializeValue(v: unknown): string {
84
85
  }
85
86
  return v;
86
87
  }
88
+ // Never put raw binary data in cache keys — use semantic identity instead.
89
+ // Audio segments can be 48-110KB; base64-encoding them would exceed
90
+ // Upstash Redis' 32KB key size limit.
87
91
  if (v instanceof Uint8Array) {
88
- // Hash binary data instead of base64-encoding to keep cache keys small.
89
- // Raw base64 can produce 65-110KB strings for audio segments, exceeding
90
- // Upstash Redis' 32KB key size limit.
91
- return `uint8:${v.byteLength}:${Bun.hash(v).toString(16)}`;
92
+ return `uint8:${v.byteLength}`;
93
+ }
94
+ // ResolvedElement (e.g. a speech segment used as Video audio input):
95
+ // serialize by content identity (type + text + duration), not binary data.
96
+ if (v instanceof ResolvedElement) {
97
+ const parts = [v.type];
98
+ for (const child of v.children) {
99
+ if (typeof child === "string") parts.push(child);
100
+ }
101
+ if (v.meta.duration) parts.push(String(v.meta.duration));
102
+ if (v.meta.file?.url) parts.push(v.meta.file.url);
103
+ return `resolved(${parts.join(",")})`;
92
104
  }
93
105
  if (isVargElement(v)) {
94
106
  return `element:${computeCacheKey(v).join(":")}`;
@@ -97,6 +109,12 @@ function serializeValue(v: unknown): string {
97
109
  return `[${v.map(serializeValue).join(",")}]`;
98
110
  }
99
111
  if (v && typeof v === "object") {
112
+ // Skip File-like objects with binary data — use URL if available
113
+ if ("_data" in v && "_mediaType" in v) {
114
+ const url = (v as { _url?: string | null })._url;
115
+ const mediaType = (v as { _mediaType: string })._mediaType;
116
+ return url ? `file(${url})` : `file(${mediaType})`;
117
+ }
100
118
  const entries = Object.entries(v)
101
119
  .map(([key, val]) => `${key}:${serializeValue(val)}`)
102
120
  .join(",");
@@ -134,7 +152,7 @@ export function computeCacheKey(element: VargElement): CacheKeyPart[] {
134
152
  } else if (v === null || v === undefined) {
135
153
  key.push(k, v);
136
154
  } else if (v instanceof Uint8Array) {
137
- key.push(k, `uint8:${v.byteLength}:${Bun.hash(v).toString(16)}`);
155
+ key.push(k, `uint8:${v.byteLength}`);
138
156
  } else if (isVargElement(v)) {
139
157
  key.push(k, ...computeCacheKey(v));
140
158
  } else if (Array.isArray(v) || typeof v === "object") {
@@ -187,6 +187,12 @@ async function sliceSegments(
187
187
  descriptors.map(async (desc) => {
188
188
  const bytes = await sliceAudio(fullFile, desc.start, desc.end);
189
189
  const segmentFile = File.fromBuffer(bytes, "audio/mpeg");
190
+ // Upload segment to storage so downstream cache keys use the URL
191
+ // instead of serializing raw audio bytes (which can exceed Redis key limits).
192
+ const ctx = getResolveContext();
193
+ if (ctx?.storage) {
194
+ await segmentFile.upload(ctx.storage);
195
+ }
190
196
 
191
197
  // Rebase word timings relative to the segment's sliced audio (t=0)
192
198
  const segmentWords = allWords