@myagentroam/agent 0.10.7 → 0.10.8
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/extensions/compaction.d.ts +1 -0
- package/dist/agent-core/extensions/model-request.js +1 -1
- package/dist/agent-core/extensions/session-messages.d.ts +1 -1
- package/dist/agent-core/host/contracts.d.ts +2 -0
- package/dist/agent-core/host/local-agent-host.d.ts +2 -0
- package/dist/agent-core/host/local-agent-host.js +2 -0
- package/dist/agent-core/model/anthropic-messages.js +10 -2
- package/dist/agent-core/model/contracts.d.ts +8 -0
- package/dist/agent-core/model/openai-responses.js +8 -2
- package/dist/agent-core/model/usage-observer.d.ts +31 -0
- package/dist/agent-core/model/usage-observer.js +82 -0
- package/dist/agent-core/runtime/events.d.ts +2 -0
- package/dist/agent-core/sdk/agent.js +9 -1
- package/dist/agent-core/sdk/extension-models.d.ts +1 -1
- package/dist/agent-core/sdk/extension-models.js +9 -1
- package/dist/agent-core/sdk/session.js +31 -3
- package/dist/agent-core/session/catalog.d.ts +1 -0
- package/dist/agent-core/session/catalog.js +1 -0
- package/dist/agent-core/session/jsonl-store.d.ts +9 -0
- package/dist/agent-core/session/jsonl-store.js +24 -0
- package/dist/agent-core/session/tool-result-resources.d.ts +26 -0
- package/dist/agent-core/session/tool-result-resources.js +285 -0
- package/dist/agent-core/session/transaction-recovery.js +1 -1
- package/dist/agent-core/tools/code-mode/dispatch.js +5 -0
- package/dist/agent-core/tools/code-mode/index.js +7 -1
- package/dist/agent-core/tools/code-mode/observations.d.ts +1 -0
- package/dist/agent-core/tools/contracts.d.ts +2 -0
- package/dist/agent-core/tools/execution.js +11 -2
- package/dist/agent-core/tools/file-change-diff.d.ts +10 -0
- package/dist/agent-core/tools/file-change-diff.js +139 -0
- package/dist/agent-core/tools/local/apply-patch.js +19 -8
- package/dist/agent-core/tools/result-extensions.d.ts +46 -0
- package/dist/agent-core/tools/result-extensions.js +134 -0
- package/dist/agent-core/tools/runtime-context.d.ts +1 -0
- package/dist/agent-core/tools/runtime.js +6 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/shared/auto-title.d.ts +2 -0
- package/dist/shared/auto-title.js +6 -0
- package/dist/shared/model-text.d.ts +2 -0
- package/dist/shared/model-text.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ToolExecutionResult } from './contracts.js';
|
|
3
|
+
export declare const fileChangesExtensionSchema: z.ZodObject<{
|
|
4
|
+
type: z.ZodLiteral<"file_changes">;
|
|
5
|
+
version: z.ZodLiteral<1>;
|
|
6
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
7
|
+
changeId: z.ZodString;
|
|
8
|
+
path: z.ZodString;
|
|
9
|
+
change: z.ZodEnum<{
|
|
10
|
+
added: "added";
|
|
11
|
+
modified: "modified";
|
|
12
|
+
deleted: "deleted";
|
|
13
|
+
}>;
|
|
14
|
+
additions: z.ZodNullable<z.ZodNumber>;
|
|
15
|
+
deletions: z.ZodNullable<z.ZodNumber>;
|
|
16
|
+
diff: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
17
|
+
status: z.ZodLiteral<"available">;
|
|
18
|
+
resourceRef: z.ZodString;
|
|
19
|
+
format: z.ZodLiteral<"unified-diff">;
|
|
20
|
+
byteSize: z.ZodNumber;
|
|
21
|
+
sha256: z.ZodString;
|
|
22
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
23
|
+
status: z.ZodLiteral<"unavailable">;
|
|
24
|
+
reason: z.ZodEnum<{
|
|
25
|
+
"unsupported-content": "unsupported-content";
|
|
26
|
+
"limit-exceeded": "limit-exceeded";
|
|
27
|
+
"capture-failed": "capture-failed";
|
|
28
|
+
"storage-failed": "storage-failed";
|
|
29
|
+
}>;
|
|
30
|
+
}, z.core.$strip>], "status">;
|
|
31
|
+
}, z.core.$strip>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
export type ToolResultExtension = z.infer<typeof fileChangesExtensionSchema>;
|
|
34
|
+
export type FileChangeEvidence = ToolResultExtension['entries'][number];
|
|
35
|
+
export type AvailableToolResultResource = Extract<FileChangeEvidence['diff'], {
|
|
36
|
+
status: 'available';
|
|
37
|
+
}>;
|
|
38
|
+
export type ToolResultResourceWriter = (text: string) => Promise<AvailableToolResultResource>;
|
|
39
|
+
export declare function parseToolResultExtensions(value: unknown): ToolResultExtension[] | undefined;
|
|
40
|
+
export declare function failedToolResultExtensions(error: unknown): ToolResultExtension[] | undefined;
|
|
41
|
+
/** Reserve a complete invocation's descriptors before any leaf commits, including wrapped calls. */
|
|
42
|
+
export declare function reserveFileChangePaths(paths: readonly string[]): void;
|
|
43
|
+
/** Only the SDK's real file commit calls this producer; arbitrary result fields are ignored. */
|
|
44
|
+
export declare function captureFileChange(path: string, before?: Buffer, after?: Buffer): Promise<void>;
|
|
45
|
+
/** Own a physical invocation, including all real leaf effects retained across wrappers. */
|
|
46
|
+
export declare function withToolResultExtensions(write: ToolResultResourceWriter | undefined, run: () => Promise<ToolExecutionResult>): Promise<ToolExecutionResult>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { MarAgentError } from '../error.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { createFileDiff, FileDiffLimitError } from './file-change-diff.js';
|
|
6
|
+
const diffSchema = z.discriminatedUnion('status', [
|
|
7
|
+
z.object({
|
|
8
|
+
status: z.literal('available'),
|
|
9
|
+
resourceRef: z.string().uuid(),
|
|
10
|
+
format: z.literal('unified-diff'),
|
|
11
|
+
byteSize: z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.nonnegative()
|
|
15
|
+
.max(16 * 1024 * 1024),
|
|
16
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/u)
|
|
17
|
+
}),
|
|
18
|
+
z.object({
|
|
19
|
+
status: z.literal('unavailable'),
|
|
20
|
+
reason: z.enum(['unsupported-content', 'limit-exceeded', 'capture-failed', 'storage-failed'])
|
|
21
|
+
})
|
|
22
|
+
]);
|
|
23
|
+
export const fileChangesExtensionSchema = z.object({
|
|
24
|
+
type: z.literal('file_changes'),
|
|
25
|
+
version: z.literal(1),
|
|
26
|
+
entries: z
|
|
27
|
+
.array(z.object({
|
|
28
|
+
changeId: z.string().uuid(),
|
|
29
|
+
path: z.string().min(1).max(8192),
|
|
30
|
+
change: z.enum(['added', 'modified', 'deleted']),
|
|
31
|
+
additions: z.number().int().nonnegative().nullable(),
|
|
32
|
+
deletions: z.number().int().nonnegative().nullable(),
|
|
33
|
+
diff: diffSchema
|
|
34
|
+
}))
|
|
35
|
+
.max(200)
|
|
36
|
+
});
|
|
37
|
+
export function parseToolResultExtensions(value) {
|
|
38
|
+
if (!Array.isArray(value) || value.length > 16)
|
|
39
|
+
return undefined;
|
|
40
|
+
const extensions = [];
|
|
41
|
+
const ids = new Set();
|
|
42
|
+
for (const input of value) {
|
|
43
|
+
const parsed = fileChangesExtensionSchema.safeParse(input);
|
|
44
|
+
if (!parsed.success || extensions.some((entry) => entry.type === parsed.data.type))
|
|
45
|
+
continue;
|
|
46
|
+
if (new Set(parsed.data.entries.map((entry) => entry.changeId)).size !==
|
|
47
|
+
parsed.data.entries.length ||
|
|
48
|
+
parsed.data.entries.some((entry) => ids.has(entry.changeId)))
|
|
49
|
+
continue;
|
|
50
|
+
parsed.data.entries.forEach((entry) => ids.add(entry.changeId));
|
|
51
|
+
extensions.push(parsed.data);
|
|
52
|
+
}
|
|
53
|
+
return extensions.length && Buffer.byteLength(JSON.stringify(extensions)) <= 1024 * 1024
|
|
54
|
+
? extensions
|
|
55
|
+
: undefined;
|
|
56
|
+
}
|
|
57
|
+
const capture = new AsyncLocalStorage();
|
|
58
|
+
const failures = new WeakMap();
|
|
59
|
+
export function failedToolResultExtensions(error) {
|
|
60
|
+
return error !== null && typeof error === 'object' ? failures.get(error) : undefined;
|
|
61
|
+
}
|
|
62
|
+
/** Reserve a complete invocation's descriptors before any leaf commits, including wrapped calls. */
|
|
63
|
+
export function reserveFileChangePaths(paths) {
|
|
64
|
+
const context = capture.getStore();
|
|
65
|
+
const entries = (context?.reservedEntries ?? 0) + paths.length;
|
|
66
|
+
const bytes = (context?.descriptorBytes ?? 256) +
|
|
67
|
+
paths.reduce((sum, path) => sum + Buffer.byteLength(JSON.stringify(path)) + 512, 0);
|
|
68
|
+
if (entries > 200 || bytes > 1024 * 1024 || paths.some((path) => path.length > 8192))
|
|
69
|
+
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Patch paths exceed the file evidence descriptor limit.');
|
|
70
|
+
if (context) {
|
|
71
|
+
context.reservedEntries = entries;
|
|
72
|
+
context.descriptorBytes = bytes;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Only the SDK's real file commit calls this producer; arbitrary result fields are ignored. */
|
|
76
|
+
export async function captureFileChange(path, before, after) {
|
|
77
|
+
const context = capture.getStore();
|
|
78
|
+
if (!context)
|
|
79
|
+
return;
|
|
80
|
+
const entry = {
|
|
81
|
+
changeId: randomUUID(),
|
|
82
|
+
path,
|
|
83
|
+
change: before === undefined ? 'added' : after === undefined ? 'deleted' : 'modified',
|
|
84
|
+
additions: null,
|
|
85
|
+
deletions: null,
|
|
86
|
+
diff: { status: 'unavailable', reason: 'capture-failed' }
|
|
87
|
+
};
|
|
88
|
+
context.entries.push(entry);
|
|
89
|
+
try {
|
|
90
|
+
const diff = createFileDiff(path, before, after);
|
|
91
|
+
if (!diff) {
|
|
92
|
+
entry.diff = { status: 'unavailable', reason: 'unsupported-content' };
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
entry.additions = diff.additions;
|
|
96
|
+
entry.deletions = diff.deletions;
|
|
97
|
+
context.bytes += Buffer.byteLength(diff.text);
|
|
98
|
+
if (context.bytes > 32 * 1024 * 1024)
|
|
99
|
+
entry.diff = { status: 'unavailable', reason: 'limit-exceeded' };
|
|
100
|
+
else if (context.write)
|
|
101
|
+
entry.diff = await context.write(diff.text);
|
|
102
|
+
else
|
|
103
|
+
entry.diff = { status: 'unavailable', reason: 'storage-failed' };
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
entry.diff = {
|
|
107
|
+
status: 'unavailable',
|
|
108
|
+
reason: error instanceof FileDiffLimitError ? 'limit-exceeded' : 'storage-failed'
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Own a physical invocation, including all real leaf effects retained across wrappers. */
|
|
113
|
+
export async function withToolResultExtensions(write, run) {
|
|
114
|
+
const context = {
|
|
115
|
+
entries: [],
|
|
116
|
+
bytes: 0,
|
|
117
|
+
reservedEntries: 0,
|
|
118
|
+
descriptorBytes: 256,
|
|
119
|
+
...(write ? { write } : {})
|
|
120
|
+
};
|
|
121
|
+
return capture.run(context, async () => {
|
|
122
|
+
const extensions = () => parseToolResultExtensions([{ type: 'file_changes', version: 1, entries: context.entries }]);
|
|
123
|
+
try {
|
|
124
|
+
const { resultExtensions: _ignored, ...result } = await run();
|
|
125
|
+
const resultExtensions = context.entries.length ? extensions() : undefined;
|
|
126
|
+
return resultExtensions ? { ...result, resultExtensions } : result;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (context.entries.length && error !== null && typeof error === 'object')
|
|
130
|
+
failures.set(error, extensions());
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
@@ -46,6 +46,7 @@ export interface ToolRuntimeContext {
|
|
|
46
46
|
executionId: string;
|
|
47
47
|
modelId?: string;
|
|
48
48
|
signal: AbortSignal;
|
|
49
|
+
writeToolResultResource?: import('./result-extensions.js').ToolResultResourceWriter;
|
|
49
50
|
codeMode?: import('./contracts.js').ToolExecutionContext['codeMode'];
|
|
50
51
|
skills: ReadonlyMap<string, AgentSkill>;
|
|
51
52
|
recentImages?: readonly ToolRuntimeImage[];
|
|
@@ -3,10 +3,13 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { AGENT_TOOL_HANDLERS, BUILTIN_TOOL_DEFINITIONS } from './registry.js';
|
|
4
4
|
import { normalizeToolInput } from './input.js';
|
|
5
5
|
import { validateToolResult } from './output-projection.js';
|
|
6
|
+
import { withToolResultExtensions } from './result-extensions.js';
|
|
6
7
|
export async function executeRegisteredTool(name, arguments_, callId, context, caller = 'direct') {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
return withToolResultExtensions(context.writeToolResultResource, async () => {
|
|
9
|
+
if (context.invokeTool)
|
|
10
|
+
return validateToolResult(await context.invokeTool({ name, arguments: arguments_, callId }, context, caller));
|
|
11
|
+
return validateToolResult(await executeCapturedTool(AGENT_TOOL_HANDLERS.has(name) ? 'builtin' : name.startsWith('mcp__') ? 'mcp' : 'host', { name, arguments: arguments_, callId }, context));
|
|
12
|
+
});
|
|
10
13
|
}
|
|
11
14
|
/** Invoke an already captured source; names never reselect a different backend. */
|
|
12
15
|
export async function executeCapturedTool(kind, call, context) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { MarAgentError } from './agent-core/error.js';
|
|
2
2
|
export { MAR_AGENT_HOST_API_VERSION, negotiateHost, type HostDescription, type MarAgentHostCapability } from './agent-core/host/contracts.js';
|
|
3
|
+
export type { ToolResultExtension, FileChangeEvidence } from './agent-core/tools/result-extensions.js';
|
|
4
|
+
export { parseToolResultExtensions } from './agent-core/tools/result-extensions.js';
|
|
5
|
+
export type { ToolResultResourceInput, ToolResultResourcePage } from './agent-core/session/tool-result-resources.js';
|
|
3
6
|
export type { HostExecutionExtensions, HostSessionResourceSnapshot, HostSkill, MarAgentHost } from './agent-core/host/contracts.js';
|
|
4
7
|
export { LocalAgentHost, selectExecutionShell, type LocalAgentExecutionExtensions, type LocalAgentExecutionMcpBinding, type LocalAgentMcpBinding } from './agent-core/host/local-agent-host.js';
|
|
5
8
|
export type { LocalProcessExecutor, LocalProcessSpawnRequest } from './agent-core/host/local-process-executor.js';
|
|
@@ -41,3 +44,4 @@ export type { ApplyPatchFileResult, ApplyPatchResult, ApplyPatchPartialResult, C
|
|
|
41
44
|
export { MCP_DEFINITION_LIMITS, assertMcpToolCatalog, assertMcpToolDefinition } from './agent-core/tools/mcp/catalog.js';
|
|
42
45
|
export type { WorkspacePathMount } from './agent-core/tools/shared/path-resolver.js';
|
|
43
46
|
export type { CodeModeEngine, CodeModeEngineFactory, CreateCodeModeEngine } from './agent-core/tools/code-mode/engine.js';
|
|
47
|
+
export type { ModelRequestUsage, ModelUsageObservation, ModelUsageObserver } from './agent-core/model/usage-observer.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { MarAgentError } from './agent-core/error.js';
|
|
2
2
|
export { MAR_AGENT_HOST_API_VERSION, negotiateHost } from './agent-core/host/contracts.js';
|
|
3
|
+
export { parseToolResultExtensions } from './agent-core/tools/result-extensions.js';
|
|
3
4
|
export { LocalAgentHost, selectExecutionShell } from './agent-core/host/local-agent-host.js';
|
|
4
5
|
export { SecretValue, marAgentReasoningEffortSchema, parseModelCatalog, resolveModelDefaultReasoningEffort } from './agent-core/model/configuration.js';
|
|
5
6
|
export { testMarAgentModelTransport } from './agent-core/model/transport-test.js';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type MarAgentModelConfiguration } from '../agent-core/model/configuration.js';
|
|
2
2
|
export interface GenerateSessionTitleInput {
|
|
3
|
+
readonly onModelUsage?: (usage: import('../agent-core/model/usage-observer.js').ModelRequestUsage) => Promise<void> | void;
|
|
4
|
+
readonly onModelUsageFailure?: () => void;
|
|
3
5
|
readonly models: readonly MarAgentModelConfiguration[];
|
|
4
6
|
readonly currentModelId: string;
|
|
5
7
|
readonly prompt: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { MarAgentError } from '../agent-core/error.js';
|
|
2
3
|
import { AnthropicMessagesAdapter } from '../agent-core/model/anthropic-messages.js';
|
|
3
4
|
import { resolveModelDefaultReasoningEffort } from '../agent-core/model/configuration.js';
|
|
@@ -38,6 +39,11 @@ export async function generateSessionTitle(input) {
|
|
|
38
39
|
try {
|
|
39
40
|
for await (const event of adapter.start({
|
|
40
41
|
retryState: { attempts: 0, maxAttempts: 1 },
|
|
42
|
+
usageRequestId: randomUUID(),
|
|
43
|
+
...(input.onModelUsage === undefined ? {} : { onModelUsage: input.onModelUsage }),
|
|
44
|
+
...(input.onModelUsageFailure === undefined
|
|
45
|
+
? {}
|
|
46
|
+
: { onModelUsageFailure: input.onModelUsageFailure }),
|
|
41
47
|
system: defaultLanguage
|
|
42
48
|
? `${sessionTitlePrompt}\n- If the user message does not establish a language, use ${JSON.stringify(defaultLanguage)} as the default language.`
|
|
43
49
|
: sessionTitlePrompt,
|
|
@@ -2,6 +2,8 @@ import { type MarAgentModelConfiguration, type MarAgentReasoningEffort } from '.
|
|
|
2
2
|
import type { ModelAttemptDiagnostic, ModelUsage } from '../agent-core/model/contracts.js';
|
|
3
3
|
import type { CoreCompactMessage } from '../agent-core/extensions/compaction.js';
|
|
4
4
|
export interface GenerateModelTextInput {
|
|
5
|
+
readonly onModelUsage?: (usage: import('../agent-core/model/usage-observer.js').ModelRequestUsage) => Promise<void> | void;
|
|
6
|
+
readonly onModelUsageFailure?: () => void;
|
|
5
7
|
readonly model: MarAgentModelConfiguration;
|
|
6
8
|
readonly system: string;
|
|
7
9
|
readonly messages: readonly CoreCompactMessage[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { MarAgentError } from '../agent-core/error.js';
|
|
2
3
|
import { AnthropicMessagesAdapter } from '../agent-core/model/anthropic-messages.js';
|
|
3
4
|
import { OpenAiResponsesAdapter } from '../agent-core/model/openai-responses.js';
|
|
@@ -16,6 +17,11 @@ export async function generateModelText(input) {
|
|
|
16
17
|
try {
|
|
17
18
|
for await (const event of adapter.start({
|
|
18
19
|
retryState: { attempts: 0, maxAttempts: 1 },
|
|
20
|
+
usageRequestId: randomUUID(),
|
|
21
|
+
...(input.onModelUsage === undefined ? {} : { onModelUsage: input.onModelUsage }),
|
|
22
|
+
...(input.onModelUsageFailure === undefined
|
|
23
|
+
? {}
|
|
24
|
+
: { onModelUsageFailure: input.onModelUsageFailure }),
|
|
19
25
|
system: input.system,
|
|
20
26
|
messages: input.messages,
|
|
21
27
|
tools: [],
|