@myagentroam/agent 0.11.34 → 0.11.35
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/session/store/jsonl/fork-session.d.ts +19 -0
- package/dist/session/store/jsonl/fork-session.js +142 -0
- package/dist/session/store/jsonl/jsonl-migration.js +1 -1
- package/dist/session/store/jsonl/jsonl-store.js +70 -157
- package/dist/subagent/session-controller.d.ts +2 -63
- package/dist/subagent/session-controller.js +35 -453
- package/dist/subagent/task.d.ts +134 -0
- package/dist/subagent/task.js +436 -0
- package/dist/subagent/turn-contracts.d.ts +64 -0
- package/dist/subagent/turn-contracts.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SessionMeta, SessionRecord } from '../types.js';
|
|
2
|
+
export declare function forkSessionOperation(source: SessionMeta, records: readonly SessionRecord[], input: {
|
|
3
|
+
readonly boundaryTurnId: string | null;
|
|
4
|
+
readonly title: string;
|
|
5
|
+
}, sourceRoot: string, sourceDirectory: string, owner: {
|
|
6
|
+
begin(target: SessionMeta): Promise<{
|
|
7
|
+
directory: string;
|
|
8
|
+
release(): Promise<void>;
|
|
9
|
+
}>;
|
|
10
|
+
publish(target: SessionMeta, copied: readonly SessionRecord[]): Promise<void>;
|
|
11
|
+
reject(target: SessionMeta, error: unknown): Promise<boolean>;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
workspace: string;
|
|
16
|
+
createdAt: string;
|
|
17
|
+
lastActivityAt: string;
|
|
18
|
+
source: import("../index.js").SessionSource | undefined;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, rename, rm } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { AgentError } from '../../../error.js';
|
|
5
|
+
import { inlineMediaHistory } from '../../inline-media.js';
|
|
6
|
+
import { copyToolResultResources } from '../../tool-result-resources.js';
|
|
7
|
+
import { syncJsonlDirectory } from './fs-durability.js';
|
|
8
|
+
import { forkedPayload, stageSessionSegments } from './history.js';
|
|
9
|
+
import { copyGeneratedImages, generatedImageFileNames } from './images.js';
|
|
10
|
+
import { sessionDirectoryExists } from './open-recovery.js';
|
|
11
|
+
import { copyResources } from './resources.js';
|
|
12
|
+
export async function forkSessionOperation(source, records, input, sourceRoot, sourceDirectory, owner) {
|
|
13
|
+
const sourceSessionId = source.id;
|
|
14
|
+
const boundaryIndex = input.boundaryTurnId === null
|
|
15
|
+
? -1
|
|
16
|
+
: records.findLastIndex((record) => record.turnId === input.boundaryTurnId);
|
|
17
|
+
if (input.boundaryTurnId !== null && boundaryIndex < 0)
|
|
18
|
+
throw new AgentError('MAR_AGENT_REWIND_TARGET_INVALID', 'Session rewind target was not found.');
|
|
19
|
+
const createdAt = new Date().toISOString();
|
|
20
|
+
const targetId = randomUUID();
|
|
21
|
+
const generation = randomUUID();
|
|
22
|
+
const target = {
|
|
23
|
+
id: targetId,
|
|
24
|
+
title: input.title,
|
|
25
|
+
workspace: source.workspace,
|
|
26
|
+
createdAt,
|
|
27
|
+
lastActivityAt: createdAt,
|
|
28
|
+
source: { type: 'user' },
|
|
29
|
+
storage: { encoding: 2, generation },
|
|
30
|
+
nextSequence: 1,
|
|
31
|
+
automaticTitlePending: false,
|
|
32
|
+
resume: {
|
|
33
|
+
version: 1,
|
|
34
|
+
userTurns: 0,
|
|
35
|
+
todoRevision: 0,
|
|
36
|
+
executionModelIndexed: true,
|
|
37
|
+
firstUserMessageIndexed: true
|
|
38
|
+
},
|
|
39
|
+
segments: []
|
|
40
|
+
};
|
|
41
|
+
const publication = await owner.begin(target);
|
|
42
|
+
const targetDirectory = join(publication.directory, 'v2', generation);
|
|
43
|
+
let discard = false;
|
|
44
|
+
let failed = false;
|
|
45
|
+
try {
|
|
46
|
+
await mkdir(join(publication.directory, 'v2'), { mode: 0o700 });
|
|
47
|
+
await mkdir(targetDirectory, { mode: 0o700 });
|
|
48
|
+
await syncJsonlDirectory(join(publication.directory, 'v2'));
|
|
49
|
+
await syncJsonlDirectory(publication.directory);
|
|
50
|
+
const copied = [
|
|
51
|
+
{
|
|
52
|
+
recordId: randomUUID(),
|
|
53
|
+
sequence: 1,
|
|
54
|
+
timestamp: createdAt,
|
|
55
|
+
sessionId: target.id,
|
|
56
|
+
type: 'session.created',
|
|
57
|
+
payload: {
|
|
58
|
+
title: target.title,
|
|
59
|
+
workspace: target.workspace,
|
|
60
|
+
automaticTitle: false,
|
|
61
|
+
source: target.source
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
const retained = input.boundaryTurnId === null ? [] : records.slice(1, boundaryIndex + 1);
|
|
66
|
+
const inlineState = inlineMediaHistory(retained).state;
|
|
67
|
+
const stateAnchor = inlineState &&
|
|
68
|
+
retained.findLast((record) => record.type === 'resource.window' || record.type === 'compact.completed');
|
|
69
|
+
const forkIdentities = new Map();
|
|
70
|
+
for (const record of retained) {
|
|
71
|
+
if (record.type === 'context.gc.completed' || record.type === 'responses.continuation')
|
|
72
|
+
continue;
|
|
73
|
+
const identity = { recordId: randomUUID(), sequence: copied.length + 1 };
|
|
74
|
+
forkIdentities.set(record.recordId, identity);
|
|
75
|
+
copied.push({
|
|
76
|
+
...identity,
|
|
77
|
+
sessionId: target.id,
|
|
78
|
+
type: record.type,
|
|
79
|
+
payload: forkedPayload(record.type, record === stateAnchor
|
|
80
|
+
? record.type === 'resource.window'
|
|
81
|
+
? inlineState
|
|
82
|
+
: {
|
|
83
|
+
...record.payload,
|
|
84
|
+
inlineMediaState: inlineState
|
|
85
|
+
}
|
|
86
|
+
: record.payload, sourceSessionId, target.id, input.title, forkIdentities),
|
|
87
|
+
...(record.executionId === undefined ? {} : { executionId: record.executionId }),
|
|
88
|
+
...(record.turnId === undefined ? {} : { turnId: record.turnId }),
|
|
89
|
+
timestamp: record.timestamp
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// A fork is unpublished until every segment and referenced image is durable.
|
|
93
|
+
const staged = await stageSessionSegments(targetDirectory, copied, 'fork');
|
|
94
|
+
for (const file of staged.files)
|
|
95
|
+
await rename(file.temporaryPath, file.path);
|
|
96
|
+
target.segments = staged.segments;
|
|
97
|
+
target.nextSequence = copied.length + 1;
|
|
98
|
+
await copyToolResultResources(sourceDirectory, targetDirectory, copied);
|
|
99
|
+
await copyGeneratedImages(sourceRoot, publication.directory, generatedImageFileNames(retained));
|
|
100
|
+
await copyResources(sourceDirectory, targetDirectory, retained);
|
|
101
|
+
for (const path of [
|
|
102
|
+
join(targetDirectory, 'resources'),
|
|
103
|
+
join(targetDirectory, 'tool_results'),
|
|
104
|
+
join(publication.directory, 'generated_images')
|
|
105
|
+
])
|
|
106
|
+
if (await sessionDirectoryExists(path))
|
|
107
|
+
await syncJsonlDirectory(path);
|
|
108
|
+
await syncJsonlDirectory(targetDirectory);
|
|
109
|
+
await syncJsonlDirectory(publication.directory);
|
|
110
|
+
target.lastActivityAt = target.createdAt;
|
|
111
|
+
await owner.publish(target, copied);
|
|
112
|
+
await rm(join(publication.directory, 'publication-pending'), { force: true });
|
|
113
|
+
return {
|
|
114
|
+
id: target.id,
|
|
115
|
+
title: target.title,
|
|
116
|
+
workspace: target.workspace,
|
|
117
|
+
createdAt: target.createdAt,
|
|
118
|
+
lastActivityAt: target.createdAt,
|
|
119
|
+
source: target.source
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
failed = true;
|
|
124
|
+
discard = await owner.reject(target, error).catch(() => false);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
const cleanup = async () => {
|
|
129
|
+
try {
|
|
130
|
+
await publication.release();
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
if (discard)
|
|
134
|
+
await rm(publication.directory, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
if (failed)
|
|
138
|
+
await cleanup().catch(() => undefined);
|
|
139
|
+
else
|
|
140
|
+
await cleanup();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -28,7 +28,7 @@ export async function prepareJsonlV2Generation(input) {
|
|
|
28
28
|
if (!line)
|
|
29
29
|
continue;
|
|
30
30
|
const record = decodeJsonlRecord(line, 1);
|
|
31
|
-
if (record.sessionId !== input.sessionId
|
|
31
|
+
if (record.sessionId !== input.sessionId)
|
|
32
32
|
throw corruptHistory();
|
|
33
33
|
firstSequence ??= record.sequence;
|
|
34
34
|
lastSequence = record.sequence;
|
|
@@ -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 {
|
|
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 {
|
|
24
|
-
import { MAX_INPUT_IMAGES,
|
|
25
|
-
import { persistResource, setResourceUrl, readResource,
|
|
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
|
-
|
|
619
|
-
|
|
620
|
-
:
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
{
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if (
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9
|
-
|
|
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 {};
|