@myagentroam/agent 0.11.34 → 0.11.36

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 (30) hide show
  1. package/dist/sandbox/linux/bubblewrap-launch.d.ts +11 -0
  2. package/dist/sandbox/linux/bubblewrap-launch.js +202 -0
  3. package/dist/sandbox/linux/bubblewrap-policy.d.ts +5 -0
  4. package/dist/sandbox/linux/bubblewrap-policy.js +285 -0
  5. package/dist/sandbox/linux/bubblewrap-probe.d.ts +11 -0
  6. package/dist/sandbox/linux/bubblewrap-probe.js +154 -0
  7. package/dist/sandbox/linux/bubblewrap-sandbox-executor.d.ts +3 -12
  8. package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +10 -632
  9. package/dist/sandbox/linux/bubblewrap-seccomp.d.ts +1 -0
  10. package/dist/sandbox/linux/bubblewrap-seccomp.js +43 -0
  11. package/dist/sandbox/linux/index.d.ts +2 -1
  12. package/dist/sandbox/linux/index.js +2 -1
  13. package/dist/sandbox/linux/sandbox-error.d.ts +4 -0
  14. package/dist/sandbox/linux/sandbox-error.js +14 -0
  15. package/dist/sandbox/linux/sandbox-mounts.d.ts +13 -0
  16. package/dist/sandbox/linux/sandbox-mounts.js +221 -0
  17. package/dist/sandbox/linux/sandbox-process.d.ts +3 -0
  18. package/dist/sandbox/linux/sandbox-process.js +32 -0
  19. package/dist/session/store/jsonl/fork-session.d.ts +19 -0
  20. package/dist/session/store/jsonl/fork-session.js +142 -0
  21. package/dist/session/store/jsonl/images.js +1 -1
  22. package/dist/session/store/jsonl/jsonl-migration.js +2 -2
  23. package/dist/session/store/jsonl/jsonl-store.js +70 -157
  24. package/dist/subagent/session-controller.d.ts +2 -63
  25. package/dist/subagent/session-controller.js +35 -453
  26. package/dist/subagent/task.d.ts +134 -0
  27. package/dist/subagent/task.js +436 -0
  28. package/dist/subagent/turn-contracts.d.ts +64 -0
  29. package/dist/subagent/turn-contracts.js +1 -0
  30. package/package.json +1 -1
@@ -1,6 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { rollbackBoundaryIndex } from '../../rollback.js';
3
- import { inlineMediaHistory } from '../../inline-media.js';
4
3
  import { lstat, mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
5
4
  import { join } from 'node:path';
6
5
  import { isDeepStrictEqual } from 'node:util';
@@ -11,7 +10,7 @@ import { acquireFileLock } from '../../../storage/file-lock.js';
11
10
  import { todoItemsFromSnapshot } from '../../todo.js';
12
11
  import { applyCodeModeStateMutations, parseCodeModeStateMutations, restoreCodeModeState } from '../../code-state.js';
13
12
  import { contextGcBaseFromRecords, contextGcCheckpointIntervalEligible, latestValidContextGcCheckpoint, normalizeContextGcReplacements, sameContextGcBase, validateContextGcCheckpoint } from '../../context-gc-checkpoint.js';
14
- import { copyToolResultResources, recordToolResources, readToolResultResource, writeToolResultResource } from '../../tool-result-resources.js';
13
+ import { recordToolResources, readToolResultResource, writeToolResultResource } from '../../tool-result-resources.js';
15
14
  import { beginTreeDeleteTransaction, finishTreeDelete, finishTreeDeletePreparation, readTreeDeleteTransaction, recoverSessionStorageTransaction, stageTreeDelete } from './transaction-recovery.js';
16
15
  import { extensionCheckpointFromPayload, indexExtensionCheckpoint, restoreExtensionCheckpoint, updateSessionCurrentState } from '../current-state.js';
17
16
  import { decodeSessionListCursor, encodeSessionListCursor, mergeSessionDerivedCache, normalizeSessionSource, persistFormatSelection, readSessionIndex, restoreSessionIndexMeta, sessionListFilter, sessionMatchesFilter, sessionTreeIds, upgradeSessionIndex } from './directory-index.js';
@@ -20,9 +19,9 @@ import { prepareJsonlV2Generation } from './jsonl-migration.js';
20
19
  import { syncJsonlDirectory } from './fs-durability.js';
21
20
  import { withSessionReadDrain, withSessionReadPin } from './read-pins.js';
22
21
  import { deriveExecutionState, executionModelFromRecord, isCompactCheckpoint, isNativeUserTurn, sameResumeIndex, userMessagePreviewFromRecord } from '../execution-state.js';
23
- import { forkedPayload, stageSessionSegments } from './history.js';
24
- import { MAX_INPUT_IMAGES, copyGeneratedImages, generatedImageFileNames, inputImageReference, inputImageReferences, readInputImageBytes } from './images.js';
25
- import { persistResource, setResourceUrl, readResource, copyResources, resourceFiles } from './resources.js';
22
+ import { forkSessionOperation } from './fork-session.js';
23
+ import { MAX_INPUT_IMAGES, inputImageReference, inputImageReferences, readInputImageBytes } from './images.js';
24
+ import { persistResource, setResourceUrl, readResource, resourceFiles } from './resources.js';
26
25
  import { CONTEXTUAL_WORLD_STATE_FILE, openJsonlIndex, reclaimUnpublishedSessions, recoverContextualWorldStateTransactions, recoverJsonlTail, sessionDirectoryExists } from './open-recovery.js';
27
26
  import { JsonlStorePool } from './store-pool.js';
28
27
  import { acquireTreeMaintenance } from './tree-maintenance.js';
@@ -606,6 +605,7 @@ export class JsonlSessionStore {
606
605
  throw new AgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
607
606
  const sourceRoot = join(this.#shared.root, 'sessions', sourceSessionId);
608
607
  const release = await acquireFileLock(join(sourceRoot, 'lock'));
608
+ let sourceFailed = false;
609
609
  try {
610
610
  await this.#refreshIndex();
611
611
  const source = this.#shared.index.sessions.find((item) => item.id === sourceSessionId);
@@ -615,163 +615,76 @@ export class JsonlSessionStore {
615
615
  await preflightV1Session(sourceRoot);
616
616
  await this.#ensureRootV2();
617
617
  const records = await this.#readRecords(sourceSessionId);
618
- const boundaryIndex = input.boundaryTurnId === null
619
- ? -1
620
- : records.findLastIndex((record) => record.turnId === input.boundaryTurnId);
621
- if (input.boundaryTurnId !== null && boundaryIndex < 0)
622
- throw new AgentError('MAR_AGENT_REWIND_TARGET_INVALID', 'Session rewind target was not found.');
623
- const createdAt = new Date().toISOString();
624
- const target = {
625
- id: randomUUID(),
626
- title: input.title,
627
- workspace: source.workspace,
628
- createdAt,
629
- lastActivityAt: createdAt,
630
- source: { type: 'user' },
631
- storage: { encoding: 2, generation: randomUUID() },
632
- nextSequence: 1,
633
- automaticTitlePending: false,
634
- resume: {
635
- version: 1,
636
- userTurns: 0,
637
- todoRevision: 0,
638
- executionModelIndexed: true,
639
- firstUserMessageIndexed: true
618
+ let publicationConfirmed = false;
619
+ return await forkSessionOperation(source, records, input, sourceRoot, this.#sessionDirectory(sourceSessionId), {
620
+ begin: async (target) => {
621
+ const publication = await this.#beginUnpublishedSession(target.id);
622
+ this.#shared.segments.set(target.id, 1);
623
+ this.#shared.pendingSessions.set(target.id, target);
624
+ return publication;
640
625
  },
641
- segments: []
642
- };
643
- const publication = await this.#beginUnpublishedSession(target.id);
644
- this.#shared.segments.set(target.id, 1);
645
- this.#shared.pendingSessions.set(target.id, target);
646
- let discard = false;
647
- try {
648
- await mkdir(join(publication.directory, 'v2'), { mode: 0o700 });
649
- await mkdir(this.#sessionDirectory(target.id), { mode: 0o700 });
650
- await syncJsonlDirectory(join(publication.directory, 'v2'));
651
- await syncJsonlDirectory(publication.directory);
652
- const copied = [
653
- {
654
- recordId: randomUUID(),
655
- sequence: 1,
656
- timestamp: createdAt,
657
- sessionId: target.id,
658
- type: 'session.created',
659
- payload: {
660
- title: target.title,
661
- workspace: target.workspace,
662
- automaticTitle: false,
663
- source: target.source
664
- }
626
+ publish: async (target, copied) => {
627
+ this.#shared.segments.set(target.id, target.segments.length);
628
+ for (const record of copied)
629
+ this.#applyRecordToResumeIndex(target, record);
630
+ this.#shared.pendingSessions.delete(target.id);
631
+ this.#shared.index = {
632
+ version: 2,
633
+ revision: this.#shared.index.revision + 1,
634
+ sessions: [target, ...this.#shared.index.sessions]
635
+ };
636
+ this.#shared.pendingPublishIds.add(target.id);
637
+ this.#markIndexDirty(target.id);
638
+ try {
639
+ await this.#saveIndex(undefined, [target.id], () => {
640
+ publicationConfirmed = true;
641
+ });
665
642
  }
666
- ];
667
- const retained = input.boundaryTurnId === null ? [] : records.slice(1, boundaryIndex + 1);
668
- const inlineState = inlineMediaHistory(retained).state;
669
- const stateAnchor = inlineState &&
670
- retained.findLast((record) => record.type === 'resource.window' || record.type === 'compact.completed');
671
- const forkIdentities = new Map();
672
- for (const record of retained) {
673
- if (record.type === 'context.gc.completed' || record.type === 'responses.continuation')
674
- continue;
675
- const identity = { recordId: randomUUID(), sequence: copied.length + 1 };
676
- forkIdentities.set(record.recordId, identity);
677
- copied.push({
678
- ...identity,
679
- sessionId: target.id,
680
- type: record.type,
681
- payload: forkedPayload(record.type, record === stateAnchor
682
- ? record.type === 'resource.window'
683
- ? inlineState
684
- : {
685
- ...record.payload,
686
- inlineMediaState: inlineState
687
- }
688
- : record.payload, sourceSessionId, target.id, input.title, forkIdentities),
689
- ...(record.executionId === undefined ? {} : { executionId: record.executionId }),
690
- ...(record.turnId === undefined ? {} : { turnId: record.turnId }),
691
- timestamp: record.timestamp
692
- });
693
- }
694
- // A fork is unpublished until every segment and referenced image is durable.
695
- const staged = await stageSessionSegments(this.#sessionDirectory(target.id), copied, 'fork');
696
- for (const file of staged.files)
697
- await rename(file.temporaryPath, file.path);
698
- target.segments = staged.segments;
699
- target.nextSequence = copied.length + 1;
700
- this.#shared.segments.set(target.id, staged.segments.length);
701
- for (const record of copied)
702
- this.#applyRecordToResumeIndex(target, record);
703
- await copyToolResultResources(this.#sessionDirectory(sourceSessionId), this.#sessionDirectory(target.id), copied);
704
- await copyGeneratedImages(sourceRoot, publication.directory, generatedImageFileNames(retained));
705
- await copyResources(this.#sessionDirectory(sourceSessionId), this.#sessionDirectory(target.id), retained);
706
- for (const path of [
707
- join(this.#sessionDirectory(target.id), 'resources'),
708
- join(this.#sessionDirectory(target.id), 'tool_results'),
709
- join(this.#sessionRoot(target.id), 'generated_images')
710
- ])
711
- if (await sessionDirectoryExists(path))
712
- await syncJsonlDirectory(path);
713
- await syncJsonlDirectory(this.#sessionDirectory(target.id));
714
- await syncJsonlDirectory(this.#sessionRoot(target.id));
715
- target.lastActivityAt = target.createdAt;
716
- this.#shared.pendingSessions.delete(target.id);
717
- this.#shared.index = {
718
- version: 2,
719
- revision: this.#shared.index.revision + 1,
720
- sessions: [target, ...this.#shared.index.sessions]
721
- };
722
- this.#shared.pendingPublishIds.add(target.id);
723
- this.#markIndexDirty(target.id);
724
- let persisted = false;
725
- try {
726
- await this.#saveIndex(undefined, [target.id], () => {
727
- persisted = true;
728
- });
729
- }
730
- catch (error) {
731
- if (!persisted)
732
- throw error;
733
- }
734
- await rm(join(publication.directory, 'publication-pending'), { force: true });
735
- return {
736
- id: target.id,
737
- title: target.title,
738
- workspace: target.workspace,
739
- createdAt: target.createdAt,
740
- lastActivityAt: target.createdAt,
741
- source: target.source
742
- };
743
- }
744
- catch (error) {
745
- this.#shared.pendingSessions.delete(target.id);
746
- const disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
747
- if (disk?.sessions.some((session) => session.id === target.id)) {
748
- this.#shared.migrationFailures.set(target.id, { error, unreadable: true });
749
- throw error;
750
- }
751
- const publishedIndex = this.#shared.index.sessions.findIndex((item) => item.id === target.id);
752
- if (publishedIndex >= 0) {
753
- this.#shared.index.sessions.splice(publishedIndex, 1);
754
- this.#shared.index.revision++;
755
- this.#shared.pendingPublishIds.delete(target.id);
756
- this.#shared.dirtySessionVersions.delete(target.id);
757
- this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
758
- }
759
- this.#shared.segments.delete(target.id);
760
- discard = true;
761
- throw error;
762
- }
763
- finally {
764
- try {
765
- await publication.release();
766
- }
767
- finally {
768
- if (discard)
769
- await rm(publication.directory, { recursive: true, force: true });
643
+ catch (error) {
644
+ if (!publicationConfirmed)
645
+ throw error;
646
+ }
647
+ },
648
+ reject: async (target, error) => {
649
+ this.#shared.pendingSessions.delete(target.id);
650
+ if (publicationConfirmed) {
651
+ this.#shared.migrationFailures.set(target.id, { error, unreadable: true });
652
+ return false;
653
+ }
654
+ let disk;
655
+ try {
656
+ disk = await readSessionIndex(join(this.#shared.root, 'sessions', 'index.json'));
657
+ }
658
+ catch {
659
+ this.#shared.migrationFailures.set(target.id, { error, unreadable: true });
660
+ return false;
661
+ }
662
+ if (!disk || disk.sessions.some((session) => session.id === target.id)) {
663
+ this.#shared.migrationFailures.set(target.id, { error, unreadable: true });
664
+ return false;
665
+ }
666
+ const publishedIndex = this.#shared.index.sessions.findIndex((item) => item.id === target.id);
667
+ if (publishedIndex >= 0) {
668
+ this.#shared.index.sessions.splice(publishedIndex, 1);
669
+ this.#shared.index.revision++;
670
+ this.#shared.pendingPublishIds.delete(target.id);
671
+ this.#shared.dirtySessionVersions.delete(target.id);
672
+ this.#shared.indexDirty = this.#shared.dirtySessionVersions.size > 0;
673
+ }
674
+ this.#shared.segments.delete(target.id);
675
+ return true;
770
676
  }
771
- }
677
+ });
678
+ }
679
+ catch (error) {
680
+ sourceFailed = true;
681
+ throw error;
772
682
  }
773
683
  finally {
774
- await release();
684
+ if (sourceFailed)
685
+ await release().catch(() => undefined);
686
+ else
687
+ await release();
775
688
  }
776
689
  });
777
690
  }
@@ -1,69 +1,9 @@
1
1
  import { type ToolWaitInterrupt } from '../runtime/wait.js';
2
- import type { AgentReasoningEffort } from '../model/configuration.js';
3
- import type { ExecutionResult } from '../runtime/contracts.js';
4
- import type { AgentEvent } from '../runtime/events.js';
5
2
  import type { SessionSource } from '../session/types.js';
6
3
  import type { SubagentManyOutput, SubagentManyOutputOptions } from './contracts.js';
7
4
  import type { SubagentController, SubagentMessageOptions, SubagentOutputOptions, SubagentRunOptions, SubagentTaskInput, SubagentTaskSnapshot } from './contracts.js';
8
- export interface SubagentModelOption {
9
- readonly id: string;
10
- readonly name: string;
11
- readonly conversationModel?: boolean;
12
- readonly reasoningEfforts: readonly AgentReasoningEffort[];
13
- readonly defaultReasoningEffort: AgentReasoningEffort;
14
- }
15
- export interface SubagentTurnHandle extends AsyncIterable<AgentEvent> {
16
- readonly executionId: string;
17
- readonly turnId: string;
18
- /** True only after the child terminal event was durably appended. */
19
- readonly persistedEvents?: boolean;
20
- result(): Promise<ExecutionResult>;
21
- cancel(): void;
22
- enqueueMessage(message: string, delivery?: SubagentMessageDelivery): boolean;
23
- }
24
- /** Caller-owned correlation is opaque to Subagent; the adapter restores it at delivery. */
25
- export interface SubagentOrigin {
26
- readonly signal: AbortSignal;
27
- readonly correlation: unknown;
28
- }
29
- export interface SubagentMessageDelivery {
30
- readonly messageId: string;
31
- readonly origin?: SubagentOrigin;
32
- readonly signal?: AbortSignal;
33
- applied(): void;
34
- settled?(status: 'cancelled' | 'failed'): void;
35
- }
36
- export interface SubagentMailboxMessage {
37
- readonly text: string;
38
- readonly delivery?: SubagentMessageDelivery;
39
- }
40
- export interface SubagentParentExecution {
41
- readonly executionId: string;
42
- readonly modelId: string;
43
- readonly reasoningEffort: AgentReasoningEffort;
44
- readonly models: ReadonlyMap<string, SubagentModelOption>;
45
- emitTerminal(snapshot: SubagentTaskSnapshot): Promise<void>;
46
- startTurn(input: {
47
- readonly sessionId: string;
48
- readonly prompt: string;
49
- readonly modelId: string;
50
- readonly reasoningEffort: AgentReasoningEffort;
51
- readonly role: SubagentTaskInput['role'];
52
- readonly initialMailbox: readonly SubagentMailboxMessage[];
53
- readonly turnId: string;
54
- readonly delivery?: SubagentMessageDelivery;
55
- readonly origin?: SubagentOrigin;
56
- }): Promise<SubagentTurnHandle>;
57
- }
58
- /** A native operation has its own provenance even when no parent Execution is active. */
59
- export interface SubagentParentOperation extends Omit<SubagentParentExecution, 'executionId'> {
60
- readonly operationId: string;
61
- readonly executionId?: string;
62
- readonly ownerInstanceId?: string;
63
- readonly extensionId?: string;
64
- readonly signal: AbortSignal;
65
- readonly origin?: SubagentOrigin;
66
- }
5
+ import type { SubagentParentExecution, SubagentParentOperation } from './turn-contracts.js';
6
+ export type { SubagentModelOption, SubagentTurnHandle, SubagentOrigin, SubagentMessageDelivery, SubagentMailboxMessage, SubagentParentExecution, SubagentParentOperation } from './turn-contracts.js';
67
7
  interface SubagentHistoryRecord {
68
8
  readonly type: string;
69
9
  readonly payload: unknown;
@@ -145,4 +85,3 @@ export declare class SubagentSessionController implements SubagentController {
145
85
  }[];
146
86
  dispose(): Promise<void>;
147
87
  }
148
- export {};