@myagentroam/agent 0.11.13 → 0.11.15
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/agent-core/host/contracts.d.ts +2 -2
- package/dist/agent-core/host/contracts.js +1 -2
- package/dist/agent-core/host/local-agent-host.js +1 -2
- package/dist/agent-core/runtime/compaction/requests.d.ts +1 -1
- package/dist/agent-core/runtime/compaction/retained-context.js +1 -1
- package/dist/agent-core/runtime/compaction/smart.d.ts +1 -1
- package/dist/agent-core/runtime/compaction/smart.js +1 -1
- package/dist/agent-core/runtime/context/gc-runtime.d.ts +2 -2
- package/dist/agent-core/runtime/context/gc-runtime.js +9 -6
- package/dist/agent-core/runtime/context/gc.js +43 -29
- package/dist/agent-core/runtime/context/projection.d.ts +1 -1
- package/dist/agent-core/runtime/context/projection.js +4 -4
- package/dist/agent-core/runtime/context/restore.d.ts +3 -2
- package/dist/agent-core/runtime/context/restore.js +2 -3
- package/dist/agent-core/runtime/context/usage.js +1 -1
- package/dist/agent-core/runtime/context/world-state.d.ts +1 -1
- package/dist/agent-core/runtime/context/world-state.js +1 -1
- package/dist/agent-core/runtime/execution-handle.d.ts +12 -0
- package/dist/agent-core/runtime/execution-handle.js +1 -0
- package/dist/agent-core/sdk/agent.js +140 -63
- package/dist/agent-core/sdk/session.d.ts +3 -3
- package/dist/agent-core/sdk/session.js +3 -1
- package/dist/agent-core/sdk/subagent-backend.d.ts +2 -2
- package/dist/agent-core/sdk/types.d.ts +6 -13
- package/dist/agent-core/session/catalog.d.ts +8 -2
- package/dist/agent-core/session/catalog.js +48 -10
- package/dist/agent-core/session/context-gc-checkpoint.d.ts +4 -2
- package/dist/agent-core/session/context-gc-checkpoint.js +15 -7
- package/dist/agent-core/session/store/contracts.d.ts +148 -0
- package/dist/agent-core/session/store/contracts.js +1 -0
- package/dist/agent-core/session/store/execution-state.js +0 -12
- package/dist/agent-core/session/store/jsonl-store.d.ts +7 -30
- package/dist/agent-core/session/store/jsonl-store.js +133 -47
- package/dist/agent-core/session/store/types.d.ts +0 -3
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { CoreCheckpoint, CoreJsonValue } from '../../extensions/data.js';
|
|
2
|
+
import type { ModelMessage, ModelUsage } from '../../model/contracts.js';
|
|
3
|
+
import type { EnvironmentContextState } from '../../runtime/context/contracts.js';
|
|
4
|
+
import type { CodeModeStateEntry } from '../../tools/code-mode/state.js';
|
|
5
|
+
import type { AvailableToolResultResource } from '../../tools/result-extensions.js';
|
|
6
|
+
import type { MarAgentSessionPage, MarAgentSessionSummary } from '../catalog.js';
|
|
7
|
+
import type { ContextGcCheckpointDraft } from '../context-gc-checkpoint.js';
|
|
8
|
+
import type { ToolResultResourceInput, ToolResultResourcePage } from '../tool-result-resources.js';
|
|
9
|
+
import type { SessionListInput, SessionSource, SessionTitleUpdateInput } from '../types.js';
|
|
10
|
+
import type { CompactHistoryMessage, RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionRecord } from './types.js';
|
|
11
|
+
export type { CompactHistoryMessage, CompactUserInput, RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionRecord } from './types.js';
|
|
12
|
+
export type { CodeModeStateEntry } from '../../tools/code-mode/state.js';
|
|
13
|
+
export type { TodoSnapshot, TodoItem } from '../../tools/contracts.js';
|
|
14
|
+
export type { CodeToolCallRecord, CodeObservation } from '../../tools/code-mode/observations.js';
|
|
15
|
+
export type { ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock } from '../../model/contracts.js';
|
|
16
|
+
export type { EnvironmentContextState } from '../../runtime/context/contracts.js';
|
|
17
|
+
export type { ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement } from '../context-gc-checkpoint.js';
|
|
18
|
+
export type { ContextGcWebToolName } from '../context-gc-replacements.js';
|
|
19
|
+
export type { ContextGcSubagentToolName } from '../context-gc-subagent.js';
|
|
20
|
+
export type { AvailableToolResultResource } from '../../tools/result-extensions.js';
|
|
21
|
+
/** Logical Session identity, without a physical index or recovery layout. */
|
|
22
|
+
export interface SessionStoreSession {
|
|
23
|
+
id: string;
|
|
24
|
+
title: string;
|
|
25
|
+
workspace: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
lastActivityAt: string;
|
|
28
|
+
source?: SessionSource | undefined;
|
|
29
|
+
}
|
|
30
|
+
export interface SessionRecordInput {
|
|
31
|
+
type: string;
|
|
32
|
+
payload: unknown;
|
|
33
|
+
executionId?: string;
|
|
34
|
+
turnId?: string;
|
|
35
|
+
timestamp?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface SessionStoreCompactInput {
|
|
38
|
+
summary: string;
|
|
39
|
+
replacementHistory?: readonly CompactHistoryMessage[];
|
|
40
|
+
retainedModelContext?: readonly ModelMessage[];
|
|
41
|
+
pendingInputs?: readonly SessionRecord[];
|
|
42
|
+
snapshotRecordId?: string;
|
|
43
|
+
snapshotMessageCount?: number;
|
|
44
|
+
environment?: EnvironmentContextState;
|
|
45
|
+
automatic?: boolean;
|
|
46
|
+
modelId?: string;
|
|
47
|
+
contextWindowTokens?: number;
|
|
48
|
+
usage?: ModelUsage;
|
|
49
|
+
executionId?: string;
|
|
50
|
+
turnId?: string;
|
|
51
|
+
}
|
|
52
|
+
/** Store-issued ownership spanning SDK cleanup and the final durable mutation. */
|
|
53
|
+
export interface SessionStoreMaintenance {
|
|
54
|
+
readonly sessionIds: readonly string[];
|
|
55
|
+
/** Idempotent; releases maintenance only, never another owner's Execution/retained references. */
|
|
56
|
+
release(): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Session persistence port. Implementations preserve record order, committed-resource
|
|
60
|
+
* visibility and the existing per-Session writer/checkpoint atomic boundaries.
|
|
61
|
+
* Owned handles are closed by their creator; injected instances are borrowed.
|
|
62
|
+
*/
|
|
63
|
+
export interface SessionStore {
|
|
64
|
+
createSession(input: {
|
|
65
|
+
title?: string;
|
|
66
|
+
workspace: string;
|
|
67
|
+
source?: SessionSource;
|
|
68
|
+
}): Promise<SessionStoreSession>;
|
|
69
|
+
getSession(sessionId: string): Promise<MarAgentSessionSummary & {
|
|
70
|
+
automaticTitlePending: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
list(input?: SessionListInput): Promise<MarAgentSessionPage>;
|
|
73
|
+
listSubagentChildren(parentSessionId: string): Promise<Array<MarAgentSessionSummary & {
|
|
74
|
+
source: Extract<SessionSource, {
|
|
75
|
+
type: 'subagent';
|
|
76
|
+
}>;
|
|
77
|
+
}>>;
|
|
78
|
+
executionConfiguration(sessionId: string): Promise<{
|
|
79
|
+
readonly modelId: string;
|
|
80
|
+
readonly modelName?: string;
|
|
81
|
+
readonly reasoningEffort?: string;
|
|
82
|
+
} | undefined>;
|
|
83
|
+
firstUserMessagePreview(sessionId: string): Promise<string | undefined>;
|
|
84
|
+
sessionTree(sessionId: string): Promise<readonly string[]>;
|
|
85
|
+
updateTitle(sessionId: string, title: string, input?: SessionTitleUpdateInput, owner?: object): Promise<boolean>;
|
|
86
|
+
append(sessionId: string, input: SessionRecordInput, options?: {
|
|
87
|
+
readonly signal?: AbortSignal;
|
|
88
|
+
}): Promise<SessionRecord>;
|
|
89
|
+
read(sessionId: string): Promise<SessionRecord[]>;
|
|
90
|
+
readPage(sessionId: string, input?: {
|
|
91
|
+
limit?: number;
|
|
92
|
+
beforeSequence?: number;
|
|
93
|
+
}): Promise<{
|
|
94
|
+
records: SessionRecord[];
|
|
95
|
+
previousBeforeSequence?: number;
|
|
96
|
+
}>;
|
|
97
|
+
readExecutionState(sessionId: string): Promise<SessionExecutionState>;
|
|
98
|
+
userTurnCount(sessionId: string): Promise<number>;
|
|
99
|
+
readContextualWorldState(sessionId: string): Promise<unknown | undefined>;
|
|
100
|
+
writeContextualWorldState(sessionId: string, state: unknown): Promise<void>;
|
|
101
|
+
readCodeModeState(sessionId: string): Promise<CodeModeStateEntry[]>;
|
|
102
|
+
commitCodeModeState(sessionId: string, mutations: unknown, input: {
|
|
103
|
+
readonly executionId: string;
|
|
104
|
+
readonly turnId: string;
|
|
105
|
+
readonly expectedState?: readonly CodeModeStateEntry[];
|
|
106
|
+
}): Promise<CodeModeStateEntry[]>;
|
|
107
|
+
readExtensionCheckpoint(sessionId: string, extensionId: string, key: string): Promise<CoreCheckpoint>;
|
|
108
|
+
writeExtensionCheckpoint(sessionId: string, extensionId: string, key: string, value: CoreJsonValue | undefined, expectedRevision: number | undefined, input: {
|
|
109
|
+
owner: object;
|
|
110
|
+
signal: AbortSignal;
|
|
111
|
+
executionId?: string;
|
|
112
|
+
turnId?: string;
|
|
113
|
+
}): Promise<CoreCheckpoint>;
|
|
114
|
+
compact(sessionId: string, input: SessionStoreCompactInput, options?: {
|
|
115
|
+
readonly signal?: AbortSignal;
|
|
116
|
+
}): Promise<SessionRecord>;
|
|
117
|
+
commitContextGc(sessionId: string, draft: ContextGcCheckpointDraft, planningRecords?: readonly SessionRecord[]): Promise<SessionRecord>;
|
|
118
|
+
persistInputImages(sessionId: string, images: readonly SessionInputImage[]): Promise<SessionInputImageMetadata[]>;
|
|
119
|
+
readInputImages(sessionId: string, value: unknown): Promise<RestoredSessionInputImage[]>;
|
|
120
|
+
readInputImage(sessionId: string, input: {
|
|
121
|
+
readonly sequence: number;
|
|
122
|
+
readonly imageIndex: number;
|
|
123
|
+
}): Promise<SessionInputImageData | undefined>;
|
|
124
|
+
writeToolResultResource(sessionId: string, text: string): Promise<AvailableToolResultResource>;
|
|
125
|
+
readToolResultResource(sessionId: string, input: ToolResultResourceInput): Promise<ToolResultResourcePage>;
|
|
126
|
+
/** One main Execution per Session; an owner may reuse its healthy retained writer. */
|
|
127
|
+
acquireSessionLease(sessionId: string, owner?: object): Promise<() => Promise<void>>;
|
|
128
|
+
/** Native writes join the same owner's writer, without admitting another Execution. */
|
|
129
|
+
acquireSessionWriteLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
|
|
130
|
+
/** Retention requires the originating owner to hold an active Execution lease. */
|
|
131
|
+
retainSessionLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
|
|
132
|
+
hasRetainedSessionLease(sessionId: string, owner: object): boolean;
|
|
133
|
+
/** Conflicts fail before cleanup; delete includes the Store's current Session tree. */
|
|
134
|
+
acquireSessionMaintenance(sessionId: string, kind: 'clear' | 'delete', owner?: object): Promise<SessionStoreMaintenance>;
|
|
135
|
+
forkSession(sessionId: string, input: {
|
|
136
|
+
readonly boundaryTurnId: string | null;
|
|
137
|
+
readonly title: string;
|
|
138
|
+
}): Promise<SessionStoreSession>;
|
|
139
|
+
rollbackSession(sessionId: string, input: {
|
|
140
|
+
readonly boundaryTurnId: string | null;
|
|
141
|
+
}): Promise<MarAgentSessionSummary>;
|
|
142
|
+
clearSession(sessionId: string, maintenance?: SessionStoreMaintenance): Promise<MarAgentSessionSummary>;
|
|
143
|
+
delete(sessionId: string, maintenance?: SessionStoreMaintenance): Promise<{
|
|
144
|
+
readonly deleted: boolean;
|
|
145
|
+
}>;
|
|
146
|
+
/** Stop using the handle and release its leases before closing it. Never preempts other owners. */
|
|
147
|
+
close(): Promise<void>;
|
|
148
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { todoItemsFromSnapshot } from '../../tools/agent/todo.js';
|
|
2
|
-
import { contextGcBaseSequence, latestValidContextGcCheckpoint } from '../context-gc-checkpoint.js';
|
|
3
2
|
export function deriveExecutionState(records) {
|
|
4
3
|
let automaticTitle = false;
|
|
5
4
|
let sawUserTurn = false;
|
|
@@ -36,7 +35,6 @@ export function deriveExecutionState(records) {
|
|
|
36
35
|
executionModel = candidate;
|
|
37
36
|
}
|
|
38
37
|
const boundary = records.findLastIndex(isCompactCheckpoint);
|
|
39
|
-
const checkpoint = latestValidContextGcCheckpoint(records);
|
|
40
38
|
return {
|
|
41
39
|
automaticTitlePending: automaticTitle && !sawUserTurn,
|
|
42
40
|
todo: { revision: todoRevision, items: todoItems },
|
|
@@ -45,13 +43,6 @@ export function deriveExecutionState(records) {
|
|
|
45
43
|
version: 1,
|
|
46
44
|
userTurns,
|
|
47
45
|
...(compactSequence === undefined ? {} : { compactSequence }),
|
|
48
|
-
...(checkpoint === undefined
|
|
49
|
-
? {}
|
|
50
|
-
: {
|
|
51
|
-
gcSequence: checkpoint.record.sequence,
|
|
52
|
-
gcGeneration: checkpoint.payload.generation,
|
|
53
|
-
gcBaseSequence: contextGcBaseSequence(checkpoint.payload.base)
|
|
54
|
-
}),
|
|
55
46
|
...(todoSequence === undefined ? {} : { todoSequence }),
|
|
56
47
|
todoRevision,
|
|
57
48
|
executionModelIndexed: true,
|
|
@@ -170,9 +161,6 @@ export function sameResumeIndex(left, right) {
|
|
|
170
161
|
return (left?.version === right.version &&
|
|
171
162
|
left.userTurns === right.userTurns &&
|
|
172
163
|
left.compactSequence === right.compactSequence &&
|
|
173
|
-
left.gcSequence === right.gcSequence &&
|
|
174
|
-
left.gcGeneration === right.gcGeneration &&
|
|
175
|
-
left.gcBaseSequence === right.gcBaseSequence &&
|
|
176
164
|
left.todoSequence === right.todoSequence &&
|
|
177
165
|
left.todoRevision === right.todoRevision &&
|
|
178
166
|
left.executionModelIndexed === right.executionModelIndexed &&
|
|
@@ -1,24 +1,15 @@
|
|
|
1
|
+
import type { SessionStore, SessionStoreMaintenance, SessionRecordInput, SessionStoreCompactInput } from './contracts.js';
|
|
1
2
|
import { type CoreCheckpoint, type CoreJsonValue } from '../../extensions/data.js';
|
|
2
|
-
import type { ModelMessage, ModelUsage } from '../../model/contracts.js';
|
|
3
|
-
import type { EnvironmentContextState } from '../../runtime/context/contracts.js';
|
|
4
3
|
import { type CodeModeStateEntry } from '../../tools/code-mode/state.js';
|
|
5
4
|
import { type ContextGcCheckpointDraft } from '../context-gc-checkpoint.js';
|
|
6
5
|
import { type ToolResultResourceInput } from '../tool-result-resources.js';
|
|
7
6
|
import type { SessionListInput, SessionSource, SessionTitleUpdateInput } from '../types.js';
|
|
8
|
-
import type {
|
|
9
|
-
interface SessionRecordInput {
|
|
10
|
-
type: string;
|
|
11
|
-
payload: unknown;
|
|
12
|
-
executionId?: string;
|
|
13
|
-
turnId?: string;
|
|
14
|
-
timestamp?: string;
|
|
15
|
-
}
|
|
7
|
+
import type { RestoredSessionInputImage, SessionExecutionState, SessionInputImage, SessionInputImageData, SessionInputImageMetadata, SessionMeta, SessionRecord } from './types.js';
|
|
16
8
|
/** SDK-owned JSONL history with per-HOME in-process sharing and cross-process file locks. */
|
|
17
|
-
export declare class JsonlSessionStore {
|
|
9
|
+
export declare class JsonlSessionStore implements SessionStore {
|
|
18
10
|
#private;
|
|
19
11
|
private constructor();
|
|
20
12
|
static open(home: string): Promise<JsonlSessionStore>;
|
|
21
|
-
/** Append the durable creation record before making this Session visible in the index. */
|
|
22
13
|
createSession(input: {
|
|
23
14
|
title?: string;
|
|
24
15
|
workspace: string;
|
|
@@ -65,7 +56,7 @@ export declare class JsonlSessionStore {
|
|
|
65
56
|
}>;
|
|
66
57
|
updateTitle(sessionId: string, title: string, input?: SessionTitleUpdateInput, owner?: object): Promise<boolean>;
|
|
67
58
|
/** Reset history with the same recovery journal while preserving the Session identity. */
|
|
68
|
-
clearSession(sessionId: string): Promise<{
|
|
59
|
+
clearSession(sessionId: string, maintenance?: SessionStoreMaintenance): Promise<{
|
|
69
60
|
id: string;
|
|
70
61
|
title: string;
|
|
71
62
|
workspace: string;
|
|
@@ -110,26 +101,13 @@ export declare class JsonlSessionStore {
|
|
|
110
101
|
records: SessionRecord[];
|
|
111
102
|
previousBeforeSequence?: number;
|
|
112
103
|
}>;
|
|
113
|
-
compact(sessionId: string, input: {
|
|
114
|
-
summary: string;
|
|
115
|
-
replacementHistory?: readonly CompactHistoryMessage[];
|
|
116
|
-
retainedModelContext?: readonly ModelMessage[];
|
|
117
|
-
pendingInputs?: readonly SessionRecord[];
|
|
118
|
-
snapshotRecordId?: string;
|
|
119
|
-
snapshotMessageCount?: number;
|
|
120
|
-
environment?: EnvironmentContextState;
|
|
121
|
-
automatic?: boolean;
|
|
122
|
-
modelId?: string;
|
|
123
|
-
contextWindowTokens?: number;
|
|
124
|
-
usage?: ModelUsage;
|
|
125
|
-
executionId?: string;
|
|
126
|
-
turnId?: string;
|
|
127
|
-
}, options?: {
|
|
104
|
+
compact(sessionId: string, input: SessionStoreCompactInput, options?: {
|
|
128
105
|
readonly signal?: AbortSignal;
|
|
129
106
|
}): Promise<SessionRecord>;
|
|
130
107
|
/** A warm cell retains physical writer ownership between Executions of the same Agent. */
|
|
131
108
|
acquireSessionLease(sessionId: string, owner?: object): Promise<() => Promise<void>>;
|
|
132
109
|
hasRetainedSessionLease(sessionId: string, owner: object): boolean;
|
|
110
|
+
acquireSessionMaintenance(sessionId: string, kind: 'clear' | 'delete', owner?: object): Promise<SessionStoreMaintenance>;
|
|
133
111
|
/** Native writes join their Agent's sole writer, without admitting another Execution. */
|
|
134
112
|
acquireSessionWriteLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
|
|
135
113
|
retainSessionLease(sessionId: string, owner: object): Promise<() => Promise<void>>;
|
|
@@ -178,9 +156,8 @@ export declare class JsonlSessionStore {
|
|
|
178
156
|
/** Counts native input records, not the post-Compact model context. */
|
|
179
157
|
userTurnCount(sessionId: string): Promise<number>;
|
|
180
158
|
firstUserMessagePreview(sessionId: string): Promise<string | undefined>;
|
|
181
|
-
delete(sessionId: string): Promise<{
|
|
159
|
+
delete(sessionId: string, maintenance?: SessionStoreMaintenance): Promise<{
|
|
182
160
|
readonly deleted: boolean;
|
|
183
161
|
}>;
|
|
184
162
|
close(): Promise<void>;
|
|
185
163
|
}
|
|
186
|
-
export {};
|
|
@@ -7,7 +7,7 @@ import { cloneCoreJson } from '../../extensions/data.js';
|
|
|
7
7
|
import { acquireFileLock } from '../../storage/file-lock.js';
|
|
8
8
|
import { todoItemsFromSnapshot } from '../../tools/agent/todo.js';
|
|
9
9
|
import { applyCodeModeStateMutations, parseCodeModeStateMutations, restoreCodeModeState } from '../../tools/code-mode/state.js';
|
|
10
|
-
import { contextGcBaseFromRecords,
|
|
10
|
+
import { contextGcBaseFromRecords, contextGcCheckpointIntervalEligible, latestValidContextGcCheckpoint, normalizeContextGcReplacements, sameContextGcBase, validateContextGcCheckpoint } from '../context-gc-checkpoint.js';
|
|
11
11
|
import { bindToolResultResources, cleanupUnreferencedToolResources, completeToolResultResources, copyToolResultResources, readToolResultResource, toolResultResourceFiles, writeToolResultResource } from '../tool-result-resources.js';
|
|
12
12
|
import { beginSessionStorageTransaction, isUnjournaledTransactionFile, recoverSessionStorageTransaction } from '../transaction-recovery.js';
|
|
13
13
|
import { extensionCheckpointFromPayload, indexExtensionCheckpoint, restoreExtensionCheckpoint, updateSessionCurrentState } from './current-state.js';
|
|
@@ -23,6 +23,7 @@ export class JsonlSessionStore {
|
|
|
23
23
|
static #instances = new Map();
|
|
24
24
|
static #opening = new Map();
|
|
25
25
|
#shared;
|
|
26
|
+
#maintenance = new WeakMap();
|
|
26
27
|
#leaseClosed = false;
|
|
27
28
|
constructor(shared) {
|
|
28
29
|
this.#shared = shared;
|
|
@@ -283,9 +284,22 @@ export class JsonlSessionStore {
|
|
|
283
284
|
}
|
|
284
285
|
return { directory, release };
|
|
285
286
|
}
|
|
286
|
-
/** Append the durable creation record before making this Session visible in the index. */
|
|
287
287
|
async createSession(input) {
|
|
288
288
|
this.#assertOpen();
|
|
289
|
+
const source = normalizeSessionSource(input.source);
|
|
290
|
+
if (source.type !== 'subagent')
|
|
291
|
+
return this.#createSession(input, source);
|
|
292
|
+
// Publish under the parent's existing serial domain so tree admission cannot miss a child.
|
|
293
|
+
return this.#serializeRecordOperation(source.parentSessionId, async () => {
|
|
294
|
+
this.#assertOpen();
|
|
295
|
+
if (this.#shared.writerLeases.get(source.parentSessionId)?.maintenance)
|
|
296
|
+
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Session is under maintenance.');
|
|
297
|
+
await this.getSession(source.parentSessionId);
|
|
298
|
+
return this.#createSession(input, source);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/** Append the durable creation record before making this Session visible in the index. */
|
|
302
|
+
async #createSession(input, source) {
|
|
289
303
|
const id = randomUUID();
|
|
290
304
|
const now = new Date().toISOString();
|
|
291
305
|
const meta = {
|
|
@@ -294,7 +308,7 @@ export class JsonlSessionStore {
|
|
|
294
308
|
workspace: input.workspace,
|
|
295
309
|
createdAt: now,
|
|
296
310
|
lastActivityAt: now,
|
|
297
|
-
source
|
|
311
|
+
source,
|
|
298
312
|
nextSequence: 1,
|
|
299
313
|
automaticTitlePending: input.title === undefined,
|
|
300
314
|
resume: {
|
|
@@ -697,9 +711,11 @@ export class JsonlSessionStore {
|
|
|
697
711
|
}
|
|
698
712
|
}
|
|
699
713
|
/** Reset history with the same recovery journal while preserving the Session identity. */
|
|
700
|
-
async clearSession(sessionId) {
|
|
714
|
+
async clearSession(sessionId, maintenance) {
|
|
701
715
|
this.#assertOpen();
|
|
702
|
-
const
|
|
716
|
+
const holding = maintenance ?? (await this.acquireSessionMaintenance(sessionId, 'clear'));
|
|
717
|
+
this.#assertMaintenance(sessionId, 'clear', holding);
|
|
718
|
+
let failed = false;
|
|
703
719
|
try {
|
|
704
720
|
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
705
721
|
if (!meta)
|
|
@@ -726,8 +742,18 @@ export class JsonlSessionStore {
|
|
|
726
742
|
];
|
|
727
743
|
return await this.#replaceHistory(meta, retained, { kind: 'clear', clearedAt });
|
|
728
744
|
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
failed = true;
|
|
747
|
+
throw error;
|
|
748
|
+
}
|
|
729
749
|
finally {
|
|
730
|
-
|
|
750
|
+
if (!maintenance) {
|
|
751
|
+
const releasing = holding.release();
|
|
752
|
+
if (failed)
|
|
753
|
+
await releasing.catch(() => undefined);
|
|
754
|
+
else
|
|
755
|
+
await releasing;
|
|
756
|
+
}
|
|
731
757
|
}
|
|
732
758
|
}
|
|
733
759
|
/** Called only while rollback or clear holds the maintenance lease. */
|
|
@@ -1123,14 +1149,9 @@ export class JsonlSessionStore {
|
|
|
1123
1149
|
records.at(-1)?.sessionId !== sessionId ||
|
|
1124
1150
|
!sameContextGcBase(contextGcBaseFromRecords(records, boundarySequence), draft.base))
|
|
1125
1151
|
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC planning boundary is invalid.');
|
|
1126
|
-
const previous = latestValidContextGcCheckpoint(records, boundarySequence
|
|
1127
|
-
if (previous)
|
|
1128
|
-
|
|
1129
|
-
if (draft.trigger.normalRolloutOrdinal - previous.payload.trigger.normalRolloutOrdinal < 2 ||
|
|
1130
|
-
draft.trigger.contextInputTokens - previous.payload.trigger.contextInputTokens <
|
|
1131
|
-
minimumUsageGrowth)
|
|
1132
|
-
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint interval validation failed.');
|
|
1133
|
-
}
|
|
1152
|
+
const previous = latestValidContextGcCheckpoint(records, boundarySequence);
|
|
1153
|
+
if (!contextGcCheckpointIntervalEligible(draft.trigger, previous?.payload.trigger))
|
|
1154
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint interval validation failed.');
|
|
1134
1155
|
const plannedReplacements = normalizeContextGcReplacements(draft.replacements);
|
|
1135
1156
|
if (!plannedReplacements || plannedReplacements.length === 0)
|
|
1136
1157
|
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint must contain a replacement.');
|
|
@@ -1236,7 +1257,7 @@ export class JsonlSessionStore {
|
|
|
1236
1257
|
this.#assertOpen();
|
|
1237
1258
|
let lease = this.#shared.writerLeases.get(sessionId);
|
|
1238
1259
|
if (lease) {
|
|
1239
|
-
if (lease.executing || owner === undefined || lease.owner !== owner)
|
|
1260
|
+
if (lease.maintenance || lease.executing || owner === undefined || lease.owner !== owner)
|
|
1240
1261
|
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
|
|
1241
1262
|
if (lease.appendFailure)
|
|
1242
1263
|
throw lease.appendFailure.error;
|
|
@@ -1262,12 +1283,89 @@ export class JsonlSessionStore {
|
|
|
1262
1283
|
const lease = this.#shared.writerLeases.get(sessionId);
|
|
1263
1284
|
return lease?.owner === owner && lease.retained > 0;
|
|
1264
1285
|
}
|
|
1286
|
+
async acquireSessionMaintenance(sessionId, kind, owner) {
|
|
1287
|
+
this.#assertOpen();
|
|
1288
|
+
const acquired = new Map();
|
|
1289
|
+
let sessionIds = [];
|
|
1290
|
+
let released = false;
|
|
1291
|
+
const holding = Object.freeze({
|
|
1292
|
+
get sessionIds() {
|
|
1293
|
+
return sessionIds;
|
|
1294
|
+
},
|
|
1295
|
+
release: async () => {
|
|
1296
|
+
if (released)
|
|
1297
|
+
return;
|
|
1298
|
+
released = true;
|
|
1299
|
+
this.#maintenance.delete(holding);
|
|
1300
|
+
let failure;
|
|
1301
|
+
for (const [id, writer] of [...acquired].reverse()) {
|
|
1302
|
+
try {
|
|
1303
|
+
await this.#serializeRecordOperation(id, async () => {
|
|
1304
|
+
delete writer.maintenance;
|
|
1305
|
+
await this.#releaseUnusedWriter(id, writer);
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
catch (error) {
|
|
1309
|
+
failure ??= { error };
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
if (failure)
|
|
1313
|
+
throw failure.error;
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
try {
|
|
1317
|
+
// Re-read membership after acquiring writers; never hand the SDK a pre-lock tree snapshot.
|
|
1318
|
+
for (;;) {
|
|
1319
|
+
const tree = kind === 'delete' ? await this.sessionTree(sessionId) : [sessionId];
|
|
1320
|
+
for (const id of tree.toReversed()) {
|
|
1321
|
+
if (acquired.has(id))
|
|
1322
|
+
continue;
|
|
1323
|
+
await this.#serializeRecordOperation(id, async () => {
|
|
1324
|
+
this.#assertOpen();
|
|
1325
|
+
let writer = this.#shared.writerLeases.get(id);
|
|
1326
|
+
if (writer &&
|
|
1327
|
+
(writer.maintenance ||
|
|
1328
|
+
owner === undefined ||
|
|
1329
|
+
writer.owner !== owner ||
|
|
1330
|
+
(kind === 'clear' && writer.executing)))
|
|
1331
|
+
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
|
|
1332
|
+
if (!writer) {
|
|
1333
|
+
// Deleting a stale index entry must not recreate its missing directory.
|
|
1334
|
+
const release = kind === 'delete' && !(await sessionDirectoryExists(this.#sessionDirectory(id)))
|
|
1335
|
+
? async () => { }
|
|
1336
|
+
: await this.#acquireSessionLease(id);
|
|
1337
|
+
writer = { owner, executing: false, retained: 0, release };
|
|
1338
|
+
this.#shared.writerLeases.set(id, writer);
|
|
1339
|
+
}
|
|
1340
|
+
writer.maintenance = holding;
|
|
1341
|
+
acquired.set(id, writer);
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
const current = kind === 'clear' ? tree : await this.sessionTree(sessionId);
|
|
1345
|
+
if (current.every((id) => acquired.has(id))) {
|
|
1346
|
+
sessionIds = Object.freeze(current);
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
this.#maintenance.set(holding, { sessionId, kind });
|
|
1351
|
+
return holding;
|
|
1352
|
+
}
|
|
1353
|
+
catch (error) {
|
|
1354
|
+
await holding.release().catch(() => undefined);
|
|
1355
|
+
throw error;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
#assertMaintenance(sessionId, kind, holding) {
|
|
1359
|
+
const current = this.#maintenance.get(holding);
|
|
1360
|
+
if (current?.sessionId !== sessionId || current.kind !== kind)
|
|
1361
|
+
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Session maintenance ownership is invalid.');
|
|
1362
|
+
}
|
|
1265
1363
|
/** Native writes join their Agent's sole writer, without admitting another Execution. */
|
|
1266
1364
|
async acquireSessionWriteLease(sessionId, owner) {
|
|
1267
1365
|
return this.#serializeRecordOperation(sessionId, async () => {
|
|
1268
1366
|
this.#assertOpen();
|
|
1269
1367
|
let lease = this.#shared.writerLeases.get(sessionId);
|
|
1270
|
-
if (lease && lease.owner !== owner)
|
|
1368
|
+
if (lease && (lease.maintenance || lease.owner !== owner))
|
|
1271
1369
|
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Session already has a writer.');
|
|
1272
1370
|
if (lease?.appendFailure)
|
|
1273
1371
|
throw lease.appendFailure.error;
|
|
@@ -1291,7 +1389,7 @@ export class JsonlSessionStore {
|
|
|
1291
1389
|
async retainSessionLease(sessionId, owner) {
|
|
1292
1390
|
return this.#serializeRecordOperation(sessionId, async () => {
|
|
1293
1391
|
const lease = this.#shared.writerLeases.get(sessionId);
|
|
1294
|
-
if (!lease || !lease.executing || lease.owner !== owner)
|
|
1392
|
+
if (!lease || lease.maintenance || !lease.executing || lease.owner !== owner)
|
|
1295
1393
|
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', 'Retained work requires its originating Session writer.');
|
|
1296
1394
|
lease.retained++;
|
|
1297
1395
|
let released = false;
|
|
@@ -1305,7 +1403,7 @@ export class JsonlSessionStore {
|
|
|
1305
1403
|
});
|
|
1306
1404
|
}
|
|
1307
1405
|
async #releaseUnusedWriter(sessionId, lease) {
|
|
1308
|
-
if (lease.executing || lease.retained)
|
|
1406
|
+
if (lease.maintenance || lease.executing || lease.retained)
|
|
1309
1407
|
return;
|
|
1310
1408
|
try {
|
|
1311
1409
|
await lease.release();
|
|
@@ -1472,20 +1570,8 @@ export class JsonlSessionStore {
|
|
|
1472
1570
|
else
|
|
1473
1571
|
resume.reasoningEffort = executionModel.reasoningEffort;
|
|
1474
1572
|
}
|
|
1475
|
-
if (isCompactCheckpoint(record))
|
|
1573
|
+
if (isCompactCheckpoint(record))
|
|
1476
1574
|
resume.compactSequence = record.sequence;
|
|
1477
|
-
delete resume.gcSequence;
|
|
1478
|
-
delete resume.gcGeneration;
|
|
1479
|
-
delete resume.gcBaseSequence;
|
|
1480
|
-
}
|
|
1481
|
-
else {
|
|
1482
|
-
const checkpoint = parseContextGcCheckpoint(record);
|
|
1483
|
-
if (checkpoint) {
|
|
1484
|
-
resume.gcSequence = record.sequence;
|
|
1485
|
-
resume.gcGeneration = checkpoint.generation;
|
|
1486
|
-
resume.gcBaseSequence = contextGcBaseSequence(checkpoint.base);
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
1575
|
if (record.type !== 'todo.updated' || !todoItemsFromSnapshot(record.payload))
|
|
1490
1576
|
return;
|
|
1491
1577
|
resume.todoSequence = record.sequence;
|
|
@@ -1723,22 +1809,12 @@ export class JsonlSessionStore {
|
|
|
1723
1809
|
throw error;
|
|
1724
1810
|
}
|
|
1725
1811
|
}
|
|
1726
|
-
async delete(sessionId) {
|
|
1812
|
+
async delete(sessionId, maintenance) {
|
|
1727
1813
|
this.#assertOpen();
|
|
1728
|
-
await this
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
const releases = [];
|
|
1733
|
-
try {
|
|
1734
|
-
for (const id of tree.toReversed())
|
|
1735
|
-
if (await sessionDirectoryExists(join(this.#shared.root, 'sessions', id)))
|
|
1736
|
-
releases.push(await this.acquireSessionLease(id));
|
|
1737
|
-
}
|
|
1738
|
-
catch (error) {
|
|
1739
|
-
await Promise.allSettled(releases.toReversed().map((release) => release()));
|
|
1740
|
-
throw error;
|
|
1741
|
-
}
|
|
1814
|
+
const holding = maintenance ?? (await this.acquireSessionMaintenance(sessionId, 'delete'));
|
|
1815
|
+
this.#assertMaintenance(sessionId, 'delete', holding);
|
|
1816
|
+
const tree = holding.sessionIds;
|
|
1817
|
+
let failed = false;
|
|
1742
1818
|
try {
|
|
1743
1819
|
const deleted = await sessionDirectoryExists(join(this.#shared.root, 'sessions', sessionId));
|
|
1744
1820
|
for (const id of tree.toReversed()) {
|
|
@@ -1751,8 +1827,18 @@ export class JsonlSessionStore {
|
|
|
1751
1827
|
await this.#saveIndex(tree);
|
|
1752
1828
|
return { deleted };
|
|
1753
1829
|
}
|
|
1830
|
+
catch (error) {
|
|
1831
|
+
failed = true;
|
|
1832
|
+
throw error;
|
|
1833
|
+
}
|
|
1754
1834
|
finally {
|
|
1755
|
-
|
|
1835
|
+
if (!maintenance) {
|
|
1836
|
+
const releasing = holding.release();
|
|
1837
|
+
if (failed)
|
|
1838
|
+
await releasing.catch(() => undefined);
|
|
1839
|
+
else
|
|
1840
|
+
await releasing;
|
|
1841
|
+
}
|
|
1756
1842
|
}
|
|
1757
1843
|
}
|
|
1758
1844
|
#assertOpen() {
|
|
@@ -58,9 +58,6 @@ export interface SessionMeta {
|
|
|
58
58
|
version: 1;
|
|
59
59
|
userTurns?: number;
|
|
60
60
|
compactSequence?: number;
|
|
61
|
-
gcSequence?: number;
|
|
62
|
-
gcGeneration?: number;
|
|
63
|
-
gcBaseSequence?: number;
|
|
64
61
|
todoSequence?: number;
|
|
65
62
|
todoRevision: number;
|
|
66
63
|
executionModelIndexed?: true;
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export type { CoreProcessesApi, CoreProcessesBackend, CoreProcessInput, CoreProc
|
|
|
41
41
|
export type { CreateMarAgentOptions, CreateSessionInput, ExecutionHandle, CompactInput, SteerInput, SteerResult, MarAgent, MarAgentSession, SessionTitleUpdateInput } from './agent-core/sdk/types.js';
|
|
42
42
|
export { openMarAgentSessionCatalog, type MarAgentContextUsage, type MarAgentHistoryEntry, type MarAgentHistoryPage, type MarAgentSessionCatalog, type MarAgentSessionDeleteResult, type MarAgentSessionImage, type MarAgentSessionPage, type MarAgentSessionSummary } from './agent-core/session/catalog.js';
|
|
43
43
|
export type { SessionListInput, SessionSource } from './agent-core/session/types.js';
|
|
44
|
+
export type { SessionStore, SessionStoreMaintenance, SessionStoreSession, SessionRecordInput, SessionStoreCompactInput, SessionRecord, SessionExecutionState, CompactHistoryMessage, CompactUserInput, SessionInputImage, SessionInputImageMetadata, SessionInputImageData, RestoredSessionInputImage, CodeModeStateEntry, TodoSnapshot, TodoItem, CodeToolCallRecord, CodeObservation, ModelMessage, ModelUsage, ModelInputMetadata, ModelTextBlock, ModelContextualBlock, EnvironmentContextState, ContextGcCheckpointDraft, ContextGcBase, ContextGcPlatform, ContextGcEconomicsPolicy, ContextGcMetrics, ContextGcReplacement, ContextGcTarget, ContextGcReadItemReplacement, ContextGcWebToolName, ContextGcSubagentToolName, AvailableToolResultResource } from './agent-core/session/store/contracts.js';
|
|
45
|
+
export type { OpenMarAgentSessionCatalogInput } from './agent-core/session/catalog.js';
|
|
44
46
|
export type { ApplyPatchFileResult, ApplyPatchResult, ApplyPatchPartialResult, ClientToolDefinition, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolCaller, ToolExecutionContext, ToolExecutionResult } from './agent-core/tools/contracts.js';
|
|
45
47
|
export { MCP_DEFINITION_LIMITS, assertMcpToolCatalog, assertMcpToolDefinition } from './agent-core/tools/mcp/catalog.js';
|
|
46
48
|
export type { WorkspacePathMount } from './agent-core/tools/shared/path-resolver.js';
|