@myagentroam/node 0.9.154 → 0.9.155

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/connector.js CHANGED
@@ -717,8 +717,9 @@ export class NodeConnector {
717
717
  });
718
718
  this.runWorkbenchService = new RunWorkbenchService({
719
719
  runtime: this.runtime,
720
- readImage: async (runId, imageIndex) => this.runAttachmentService.read(runId, imageIndex) ??
721
- (await this.runAttachmentService.readNative(runId, imageIndex)),
720
+ readImage: async (runId, selector) => typeof selector === 'number'
721
+ ? this.runAttachmentService.read(runId, selector)
722
+ : this.runAttachmentService.readNative(runId, selector),
722
723
  respondUserInput: (runId, requestId, answers) => this.runnerInteractionService.respondUserInput(runId, requestId, answers),
723
724
  pauseQueue: (sessionId) => this.workspaceQueueWorkbenchService.pauseSessionQueue(sessionId),
724
725
  runInterrupted: (sessionId) => {
@@ -1556,8 +1557,7 @@ export class NodeConnector {
1556
1557
  emitWatchEvent: (payload) => this.send('watch.event', payload),
1557
1558
  nextWorkbenchEvent: (payload) => this.workbenchEventService.next('hosted-conversation', payload),
1558
1559
  emitWorkbenchEvent: (event) => this.workbenchEventService.publish(event),
1559
- readImage: async (runId, imageIndex) => this.runAttachmentService.read(runId, imageIndex) ??
1560
- (await this.runAttachmentService.readNative(runId, imageIndex)),
1560
+ readImage: (runId, imageRef) => this.runAttachmentService.readNative(runId, imageRef),
1561
1561
  processExecutorFactory: (input) => new BubblewrapSandboxExecutor({
1562
1562
  profile: hostedConversationSandboxProfile(input)
1563
1563
  }),
@@ -26,6 +26,7 @@ export function marAgentGeneratedImageSources(homeDirectory, sessionId, artifact
26
26
  {
27
27
  name: artifact.name,
28
28
  mime: artifact.mime,
29
+ sourceId: `${sessionId}:${artifact.fileName}`,
29
30
  localPath: resolve(directory, artifact.fileName)
30
31
  }
31
32
  ]
@@ -879,7 +879,7 @@ export class HostedConversationNodeService {
879
879
  this.options.store.requireConversation(payload.userId, input.conversationId);
880
880
  if (input.runId !== hostedConversationImageRunId(input.conversationId))
881
881
  throw new Error('HOSTED_CONVERSATION_NOT_AUTHORIZED');
882
- const image = await this.options.readImage(input.runId, input.imageIndex);
882
+ const image = await this.options.readImage(input.runId, input.imageRef);
883
883
  if (image === undefined)
884
884
  throw new Error('RUN_IMAGE_NOT_FOUND');
885
885
  return { image };
@@ -1,10 +1,12 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { tmpdir } from 'node:os';
2
3
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
3
4
  import { lstat, mkdir, mkdtemp, readFile, realpath, rm, writeFile } from 'node:fs/promises';
5
+ import { imageRefSchema } from '@myagentroam/protocol';
4
6
  import { AttachmentDomainState } from './attachment-domain-state.js';
5
7
  const MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;
6
8
  const IMAGE_CACHE_TTL_MS = 60 * 60_000;
7
- const NATIVE_IMAGE_INDEX_TTL_MS = 60 * 60_000;
9
+ const NATIVE_IMAGE_SOURCE_TTL_MS = 60 * 60_000;
8
10
  export class RunAttachmentService {
9
11
  nativeImageRoots;
10
12
  state = new AttachmentDomainState();
@@ -140,7 +142,7 @@ export class RunAttachmentService {
140
142
  }
141
143
  registerNativeImages(runId, nativeRoots, images, options = {}) {
142
144
  const roots = nativeRoots.map((root) => resolve(root));
143
- const sources = this.state.nativeHistoryImages.get(runId) ?? [];
145
+ const sources = this.state.nativeHistoryImages.get(runId) ?? new Map();
144
146
  const attachments = [];
145
147
  for (const image of images) {
146
148
  const cached = options.reuseCachedRunImages === false || image.localPath === undefined
@@ -157,7 +159,11 @@ export class RunAttachmentService {
157
159
  attachments.push({ name: image.name, mime: image.mime });
158
160
  continue;
159
161
  }
160
- let imageIndex = sources.findIndex((source) => source.kind === 'reader' && source.sourceId === image.sourceId);
162
+ const imageRef = nativeImageReference('reader', image.sourceId);
163
+ if (imageRef === undefined) {
164
+ attachments.push({ name: image.name, mime: image.mime });
165
+ continue;
166
+ }
161
167
  const source = {
162
168
  kind: 'reader',
163
169
  name: image.name,
@@ -166,18 +172,13 @@ export class RunAttachmentService {
166
172
  sourceId: image.sourceId,
167
173
  read: image.read
168
174
  };
169
- if (imageIndex < 0) {
170
- imageIndex = sources.length;
171
- sources.push(source);
172
- }
173
- else
174
- sources[imageIndex] = source;
175
+ sources.set(imageRef, source);
175
176
  attachments.push({
176
177
  name: image.name,
177
178
  mime: image.mime,
178
179
  ...(image.byteSize === undefined ? {} : { byteSize: image.byteSize }),
179
180
  runId,
180
- imageIndex
181
+ imageRef
181
182
  });
182
183
  continue;
183
184
  }
@@ -198,14 +199,24 @@ export class RunAttachmentService {
198
199
  attachments.push({ name: image.name, mime: image.mime });
199
200
  continue;
200
201
  }
201
- let imageIndex = sources.findIndex((source) => source.kind === 'file' && source.path === path);
202
- if (imageIndex < 0) {
203
- imageIndex = sources.length;
204
- sources.push({ kind: 'file', name: image.name, mime: image.mime, path, root });
202
+ // Derive identity from the original source, never its registration position.
203
+ // The path digest hides physical paths; it is not a content/version hash.
204
+ const imageRef = nativeImageReference('file', image.sourceId === undefined
205
+ ? createHash('sha256').update(path).digest('hex')
206
+ : image.sourceId);
207
+ if (imageRef === undefined) {
208
+ attachments.push({ name: image.name, mime: image.mime });
209
+ continue;
205
210
  }
206
- attachments.push({ name: image.name, mime: image.mime, runId, imageIndex });
211
+ const previous = sources.get(imageRef);
212
+ if (previous !== undefined && (previous.kind !== 'file' || previous.path !== path)) {
213
+ attachments.push({ name: image.name, mime: image.mime });
214
+ continue;
215
+ }
216
+ sources.set(imageRef, { kind: 'file', name: image.name, mime: image.mime, path, root });
217
+ attachments.push({ name: image.name, mime: image.mime, runId, imageRef });
207
218
  }
208
- if (sources.length > 0) {
219
+ if (sources.size > 0) {
209
220
  this.state.nativeHistoryImages.set(runId, sources);
210
221
  const previousTimer = this.state.nativeHistoryImageTimers.get(runId);
211
222
  if (previousTimer !== undefined)
@@ -213,7 +224,7 @@ export class RunAttachmentService {
213
224
  const timer = setTimeout(() => {
214
225
  this.state.nativeHistoryImageTimers.delete(runId);
215
226
  this.state.nativeHistoryImages.delete(runId);
216
- }, NATIVE_IMAGE_INDEX_TTL_MS);
227
+ }, NATIVE_IMAGE_SOURCE_TTL_MS);
217
228
  timer.unref();
218
229
  this.state.nativeHistoryImageTimers.set(runId, timer);
219
230
  }
@@ -242,8 +253,8 @@ export class RunAttachmentService {
242
253
  }
243
254
  return undefined;
244
255
  }
245
- async readNative(runId, imageIndex) {
246
- const source = this.state.nativeHistoryImages.get(runId)?.[imageIndex];
256
+ async readNative(runId, imageRef) {
257
+ const source = this.state.nativeHistoryImages.get(runId)?.get(imageRef);
247
258
  if (source === undefined)
248
259
  return undefined;
249
260
  try {
@@ -308,6 +319,15 @@ export class RunAttachmentService {
308
319
  this.state.nativeHistoryImages.clear();
309
320
  }
310
321
  }
322
+ function nativeImageReference(kind, identity) {
323
+ try {
324
+ const reference = `${kind}:${encodeURIComponent(identity)}`;
325
+ return imageRefSchema.safeParse(reference).success ? reference : undefined;
326
+ }
327
+ catch {
328
+ return undefined;
329
+ }
330
+ }
311
331
  function canonicalBase64(value) {
312
332
  if (value.length === 0)
313
333
  return false;
@@ -1,3 +1,5 @@
1
+ import { runImageReadInputSchema } from '@myagentroam/protocol';
2
+ import { nodeOperationData } from '../util/node-operation-data.js';
1
3
  import { isTerminalRunStatus } from '../util/node-operation-parsers.js';
2
4
  import { isPlainRecord } from '../runner/codex/conversation-parser.js';
3
5
  import { isHostedConversationImageRunId } from '../runner/mar-agent/generated-images.js';
@@ -22,14 +24,17 @@ export class RunWorkbenchService {
22
24
  return { run: this.requireRun(input.runId) };
23
25
  }
24
26
  async image(input) {
25
- if (typeof input.runId !== 'string' ||
26
- typeof input.imageIndex !== 'number' ||
27
- !Number.isInteger(input.imageIndex) ||
28
- input.imageIndex < 0)
27
+ const parsed = runImageReadInputSchema.safeParse(nodeOperationData(input));
28
+ if (!parsed.success)
29
+ throw new Error('RUN_IMAGE_INVALID');
30
+ const reference = parsed.data;
31
+ if (isHostedConversationImageRunId(reference.runId))
29
32
  throw new Error('RUN_IMAGE_INVALID');
30
- if (isHostedConversationImageRunId(input.runId))
33
+ const native = reference.runId.startsWith('native-history:');
34
+ if (native !== 'imageRef' in reference)
31
35
  throw new Error('RUN_IMAGE_INVALID');
32
- const image = await this.options.readImage(input.runId, input.imageIndex);
36
+ const selector = 'imageRef' in reference ? reference.imageRef : reference.imageIndex;
37
+ const image = await this.options.readImage(reference.runId, selector);
33
38
  if (image === undefined)
34
39
  throw new Error('RUN_IMAGE_NOT_FOUND');
35
40
  return { image };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.9.154",
3
+ "version": "0.9.155",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -36,10 +36,10 @@
36
36
  "playwright": "1.62.1",
37
37
  "ws": "^8.21.3",
38
38
  "zod": "4.4.3",
39
- "@myagentroam/agent": "0.9.154",
40
- "@myagentroam/protocol": "0.9.154",
39
+ "@myagentroam/agent": "0.9.155",
40
+ "@myagentroam/code-navigation": "0.9.129",
41
41
  "@myagentroam/marctl": "0.9.120",
42
- "@myagentroam/code-navigation": "0.9.129"
42
+ "@myagentroam/protocol": "0.9.155"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/ws": "^8.18.1"