@myagentroam/agent 0.9.116 → 0.9.118
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/index.d.ts +3 -7
- package/dist/index.js +1 -6
- package/dist/model/transport-test.d.ts +3 -0
- package/dist/model/transport-test.js +23 -0
- package/dist/sdk/agent.d.ts +9 -0
- package/dist/sdk/agent.js +27 -20
- package/dist/sdk/types.d.ts +7 -3
- package/dist/session/catalog.d.ts +1 -1
- package/dist/session/catalog.js +3 -2
- package/dist/session/jsonl-store.d.ts +10 -19
- package/dist/session/jsonl-store.js +504 -103
- package/dist/session/transaction-recovery.d.ts +16 -0
- package/dist/session/transaction-recovery.js +135 -0
- package/dist/session/types.d.ts +18 -0
- package/dist/session/types.js +1 -0
- package/dist/tools/agent-cancel.d.ts +1 -1
- package/dist/tools/agent-wait.d.ts +1 -1
- package/dist/tools/exec.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function isUnjournaledTransactionFile(name: string): boolean;
|
|
2
|
+
export interface SessionStorageTransaction {
|
|
3
|
+
readonly version: 1;
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly kind: 'rollback' | 'clear';
|
|
6
|
+
readonly originalSegments: readonly string[];
|
|
7
|
+
readonly stagedSegments: readonly {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly temporary: string;
|
|
10
|
+
}[];
|
|
11
|
+
readonly sidecarBackup: string;
|
|
12
|
+
}
|
|
13
|
+
/** The index's transaction ID, not the journal's existence, decides the commit side. */
|
|
14
|
+
export declare function beginSessionStorageTransaction(directory: string, transaction: SessionStorageTransaction): Promise<void>;
|
|
15
|
+
/** Must run under the corresponding Session writer lock. Safe to repeat after interruption. */
|
|
16
|
+
export declare function recoverSessionStorageTransaction(directory: string, committedTransactionId?: string): Promise<void>;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { lstat, readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { MarAgentError } from '../error.js';
|
|
5
|
+
const JOURNAL = 'storage-transaction.json';
|
|
6
|
+
const SEGMENT = /^events-\d{6}\.jsonl$/u;
|
|
7
|
+
const TRANSACTION_ID = /^[0-9a-f-]{36}$/iu;
|
|
8
|
+
const STAGING_FILE = /^events-\d{6}\.jsonl\.[0-9a-f-]{36}\.rollback-tmp$/iu;
|
|
9
|
+
const JOURNAL_TEMP = /^storage-transaction\.json\.[0-9a-f-]{36}\.tmp$/iu;
|
|
10
|
+
export function isUnjournaledTransactionFile(name) {
|
|
11
|
+
return STAGING_FILE.test(name) || JOURNAL_TEMP.test(name);
|
|
12
|
+
}
|
|
13
|
+
/** The index's transaction ID, not the journal's existence, decides the commit side. */
|
|
14
|
+
export async function beginSessionStorageTransaction(directory, transaction) {
|
|
15
|
+
const temporary = join(directory, `${JOURNAL}.${randomUUID()}.tmp`);
|
|
16
|
+
try {
|
|
17
|
+
await writeFile(temporary, JSON.stringify(transaction), {
|
|
18
|
+
mode: 0o600,
|
|
19
|
+
flag: 'wx',
|
|
20
|
+
flush: true
|
|
21
|
+
});
|
|
22
|
+
await rename(temporary, join(directory, JOURNAL));
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
await rm(temporary, { force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Must run under the corresponding Session writer lock. Safe to repeat after interruption. */
|
|
29
|
+
export async function recoverSessionStorageTransaction(directory, committedTransactionId) {
|
|
30
|
+
const journal = join(directory, JOURNAL);
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = await readFile(journal, 'utf8');
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error.code === 'ENOENT') {
|
|
37
|
+
await removeUnjournaledTransactionFiles(directory);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
let transaction;
|
|
43
|
+
try {
|
|
44
|
+
transaction = JSON.parse(raw);
|
|
45
|
+
if (transaction?.version !== 1 ||
|
|
46
|
+
!TRANSACTION_ID.test(transaction.id) ||
|
|
47
|
+
(transaction.kind !== 'rollback' && transaction.kind !== 'clear') ||
|
|
48
|
+
!Array.isArray(transaction.originalSegments) ||
|
|
49
|
+
!transaction.originalSegments.every((name) => typeof name === 'string' && SEGMENT.test(name)) ||
|
|
50
|
+
!Array.isArray(transaction.stagedSegments) ||
|
|
51
|
+
!transaction.stagedSegments.every((entry) => typeof entry?.path === 'string' &&
|
|
52
|
+
SEGMENT.test(entry.path) &&
|
|
53
|
+
typeof entry.temporary === 'string' &&
|
|
54
|
+
/^events-\d{6}\.jsonl\.[0-9a-f-]{36}\.rollback-tmp$/iu.test(entry.temporary) &&
|
|
55
|
+
entry.temporary.startsWith(`${entry.path}.`)) ||
|
|
56
|
+
typeof transaction.sidecarBackup !== 'string' ||
|
|
57
|
+
!new RegExp(`^context-world-state\\.json\\.\\d+\\.${transaction.id}\\.${transaction.kind}-backup$`, 'u').test(transaction.sidecarBackup))
|
|
58
|
+
throw new Error('invalid session transaction');
|
|
59
|
+
}
|
|
60
|
+
catch (cause) {
|
|
61
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session storage transaction is corrupt.', {
|
|
62
|
+
cause
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const committed = transaction.id === committedTransactionId;
|
|
66
|
+
const originals = new Set(transaction.originalSegments);
|
|
67
|
+
for (const name of transaction.originalSegments) {
|
|
68
|
+
const canonical = join(directory, name);
|
|
69
|
+
const backup = `${canonical}.${transaction.id}.${transaction.kind}-backup`;
|
|
70
|
+
if (!(await exists(backup)))
|
|
71
|
+
continue;
|
|
72
|
+
if (committed)
|
|
73
|
+
await rm(backup, { force: true });
|
|
74
|
+
else {
|
|
75
|
+
await rm(canonical, { force: true });
|
|
76
|
+
await rename(backup, canonical);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!committed)
|
|
80
|
+
for (const entry of transaction.stagedSegments)
|
|
81
|
+
if (!originals.has(entry.path))
|
|
82
|
+
await rm(join(directory, entry.path), { force: true });
|
|
83
|
+
for (const entry of transaction.stagedSegments)
|
|
84
|
+
await rm(join(directory, entry.temporary), { force: true });
|
|
85
|
+
const sidecar = join(directory, 'context-world-state.json');
|
|
86
|
+
const backup = join(directory, transaction.sidecarBackup);
|
|
87
|
+
if (await exists(backup)) {
|
|
88
|
+
if (committed)
|
|
89
|
+
await rm(backup, { force: true });
|
|
90
|
+
else {
|
|
91
|
+
await rm(sidecar, { force: true });
|
|
92
|
+
await rename(backup, sidecar);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const folder of ['input_images', 'generated_images']) {
|
|
96
|
+
const path = join(directory, folder);
|
|
97
|
+
let names;
|
|
98
|
+
try {
|
|
99
|
+
names = await readdir(path);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (error.code === 'ENOENT')
|
|
103
|
+
continue;
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
const suffix = `.${transaction.id}.rollback-trash`;
|
|
107
|
+
for (const name of names) {
|
|
108
|
+
if (!name.startsWith('.') || !name.endsWith(suffix))
|
|
109
|
+
continue;
|
|
110
|
+
const trash = join(path, name);
|
|
111
|
+
if (committed)
|
|
112
|
+
await rm(trash, { force: true });
|
|
113
|
+
else
|
|
114
|
+
await rename(trash, join(path, name.slice(1, -suffix.length)));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
await rm(journal);
|
|
118
|
+
await removeUnjournaledTransactionFiles(directory);
|
|
119
|
+
}
|
|
120
|
+
async function removeUnjournaledTransactionFiles(directory) {
|
|
121
|
+
for (const name of await readdir(directory))
|
|
122
|
+
if (isUnjournaledTransactionFile(name))
|
|
123
|
+
await rm(join(directory, name), { force: true });
|
|
124
|
+
}
|
|
125
|
+
async function exists(path) {
|
|
126
|
+
try {
|
|
127
|
+
await lstat(path);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (error.code === 'ENOENT')
|
|
132
|
+
return false;
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Public session provenance; storage may persist additional private metadata. */
|
|
2
|
+
export type SessionSource = {
|
|
3
|
+
readonly type: 'user';
|
|
4
|
+
} | {
|
|
5
|
+
readonly type: 'subagent';
|
|
6
|
+
readonly parentSessionId: string;
|
|
7
|
+
readonly rootSessionId: string;
|
|
8
|
+
readonly parentExecutionId: string;
|
|
9
|
+
readonly role: 'general-purpose' | 'explore';
|
|
10
|
+
readonly description: string;
|
|
11
|
+
};
|
|
12
|
+
export interface SessionListInput {
|
|
13
|
+
readonly limit?: number;
|
|
14
|
+
readonly cursor?: string;
|
|
15
|
+
readonly source?: SessionSource['type'];
|
|
16
|
+
readonly parentSessionId?: string;
|
|
17
|
+
readonly rootSessionId?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,5 +3,5 @@ import type { ToolRuntimeContext } from './runtime-context.js';
|
|
|
3
3
|
export declare const agentCancelToolDefinition: ClientToolDefinition;
|
|
4
4
|
export declare function executeAgentCancel(arguments_: unknown, context: ToolRuntimeContext): Promise<{
|
|
5
5
|
content: string;
|
|
6
|
-
data: import("../
|
|
6
|
+
data: import("../subagent/scheduler.js").SubagentTaskSnapshot;
|
|
7
7
|
}>;
|
|
@@ -3,5 +3,5 @@ import type { ToolRuntimeContext } from './runtime-context.js';
|
|
|
3
3
|
export declare const agentWaitToolDefinition: ClientToolDefinition;
|
|
4
4
|
export declare function executeAgentWait(arguments_: unknown, context: ToolRuntimeContext): Promise<{
|
|
5
5
|
content: string;
|
|
6
|
-
data: import("../
|
|
6
|
+
data: import("../subagent/scheduler.js").SubagentTaskSnapshot;
|
|
7
7
|
}>;
|
package/dist/tools/exec.js
CHANGED
|
@@ -6,7 +6,7 @@ import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
|
6
6
|
export const execToolDefinition = {
|
|
7
7
|
name: 'exec',
|
|
8
8
|
parallelSafety: 'safe',
|
|
9
|
-
description: 'Unrestricted general system execution. Providing command starts any platform-native command, script, text/file tool, builder, generator, network client, or program in workspace/default cwd; action may be omitted for start. poll waits up to yieldMs for new output or termination and returns incremental
|
|
9
|
+
description: 'Unrestricted general system execution. Providing command starts any platform-native command, script, text/file tool, builder, generator, network client, or program in workspace/default cwd; action may be omitted for start. poll waits up to yieldMs for new output or termination and returns incremental stdout/stderr while running; after termination, poll returns a bounded cached result with earlier output for up to five minutes while the Session remains hosted. write sends stdin to running processes; cancel terminates a running process or removes a completed result. Returns status, processId, stdout/stderr, cumulative stdoutBytes/stderrBytes, per-result dropped bytes, exitCode, and truncated; a completed status does not imply exitCode 0. Always inspect stderr/exitCode and consume terminal output or cancel.',
|
|
10
10
|
outputSchema: {
|
|
11
11
|
type: 'object',
|
|
12
12
|
required: ['content', 'data'],
|