@myagentroam/agent 0.9.173 → 0.9.174
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 -1
- package/dist/agent-core/extensions/model-request.js +7 -1
- package/dist/agent-core/model/anthropic-messages.js +2 -1
- package/dist/agent-core/model/catalog-file.d.ts +0 -2
- package/dist/agent-core/model/catalog-file.js +7 -0
- package/dist/agent-core/model/configuration.d.ts +0 -1
- package/dist/agent-core/model/configuration.js +0 -1
- package/dist/agent-core/model/contracts.d.ts +6 -0
- package/dist/agent-core/model/openai-responses.js +24 -24
- package/dist/agent-core/prompts/compact.d.ts +0 -1
- package/dist/agent-core/prompts/compact.js +0 -56
- package/dist/agent-core/prompts/index.d.ts +0 -1
- package/dist/agent-core/prompts/index.js +2 -9
- package/dist/agent-core/runtime/compaction/history.d.ts +1 -2
- package/dist/agent-core/runtime/compaction/history.js +4 -4
- package/dist/agent-core/sdk/session.js +7 -11
- package/dist/agent-core/tools/agent/agent-start.js +3 -1
- package/dist/agent-core/tools/code-mode/index.js +10 -5
- package/dist/agent-core/tools/definition-projection.d.ts +7 -0
- package/dist/agent-core/tools/definition-projection.js +26 -0
- package/dist/agent-core/tools/mcp/tool-search.js +12 -4
- package/dist/cli/main.js +6 -4
- package/package.json +1 -1
|
@@ -24,7 +24,7 @@ export interface CoreCompactContext {
|
|
|
24
24
|
readonly messages: readonly CoreCompactMessage[];
|
|
25
25
|
readonly focus?: string;
|
|
26
26
|
readonly summaryTokenBudget: number;
|
|
27
|
-
/** Return the Core
|
|
27
|
+
/** Return the Core's default structured handoff contract, independent of model configuration. */
|
|
28
28
|
readonly getPrompt: () => string;
|
|
29
29
|
/** Private, bounded telemetry only; reporting never changes the generation result. */
|
|
30
30
|
readonly reportDiagnostic?: (diagnostic: CoreCompactDiagnostic) => Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
3
|
import { resolveModelTextBlocks } from '../model/text-blocks.js';
|
|
4
|
+
import { orderToolDefinitions, stableToolDefinition } from '../tools/definition-projection.js';
|
|
4
5
|
import { MarAgentError } from '../error.js';
|
|
5
6
|
/** Only actual SDK model dispatch records snapshots; public views carry no raw payload authority. */
|
|
6
7
|
export class ExtensionRequestSnapshots {
|
|
@@ -151,6 +152,11 @@ export class ExtensionRequestBridge {
|
|
|
151
152
|
};
|
|
152
153
|
});
|
|
153
154
|
const { toolChoice: _toolChoice, reasoningEffort: _reasoningEffort, images: _images, systemBlocks: _systemBlocks, ...retained } = this.original;
|
|
155
|
+
// Middleware selects declarations; it must not reorder a retained discovery prefix.
|
|
156
|
+
const order = new Map(this.original.tools.map((tool, index) => [tool.name, index]));
|
|
157
|
+
const tools = orderToolDefinitions(structuredClone(view.tools))
|
|
158
|
+
.sort((left, right) => (order.get(left.name) ?? order.size) - (order.get(right.name) ?? order.size))
|
|
159
|
+
.map(stableToolDefinition);
|
|
154
160
|
return {
|
|
155
161
|
...retained,
|
|
156
162
|
system: view.system,
|
|
@@ -158,7 +164,7 @@ export class ExtensionRequestBridge {
|
|
|
158
164
|
? {}
|
|
159
165
|
: { systemBlocks: resolveModelTextBlocks(view.system, view.systemBlocks) }),
|
|
160
166
|
messages,
|
|
161
|
-
tools
|
|
167
|
+
tools,
|
|
162
168
|
...(view.toolChoice ? { toolChoice: view.toolChoice } : {}),
|
|
163
169
|
...(view.reasoningEffort ? { reasoningEffort: view.reasoningEffort } : {}),
|
|
164
170
|
...(view.images ? { images: structuredClone(view.images) } : {})
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { observationModelParts } from '../tools/code-mode/observations.js';
|
|
2
|
+
import { stableToolSchema } from '../tools/definition-projection.js';
|
|
2
3
|
import { randomUUID } from 'node:crypto';
|
|
3
4
|
import { MarAgentError } from '../error.js';
|
|
4
5
|
import { resolveModelDefaultReasoningEffort } from './configuration.js';
|
|
@@ -97,7 +98,7 @@ export class AnthropicMessagesAdapter {
|
|
|
97
98
|
: request.tools.map((tool) => ({
|
|
98
99
|
name: tool.name,
|
|
99
100
|
description: tool.description,
|
|
100
|
-
input_schema: tool.inputSchema
|
|
101
|
+
input_schema: stableToolSchema(tool.inputSchema)
|
|
101
102
|
}));
|
|
102
103
|
const response = await fetchModelResponse(`${this.configuration.baseUrl.replace(/\/$/, '')}/v1/messages`, {
|
|
103
104
|
method: 'POST',
|
|
@@ -28,7 +28,6 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
28
28
|
defaultReasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max" | "ultra" | undefined;
|
|
29
29
|
titleGeneration: boolean;
|
|
30
30
|
codeMode: boolean;
|
|
31
|
-
highDensityCompaction: boolean;
|
|
32
31
|
fastMode?: boolean | undefined;
|
|
33
32
|
serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
|
|
34
33
|
hostedWebSearch: boolean;
|
|
@@ -55,7 +54,6 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
55
54
|
defaultReasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max" | "ultra" | undefined;
|
|
56
55
|
titleGeneration: boolean;
|
|
57
56
|
codeMode: boolean;
|
|
58
|
-
highDensityCompaction: boolean;
|
|
59
57
|
fastMode?: boolean | undefined;
|
|
60
58
|
serviceTier?: "default" | "auto" | "flex" | "priority" | "fast" | "ultrafast" | undefined;
|
|
61
59
|
hostedWebSearch: boolean;
|
|
@@ -52,6 +52,13 @@ function parseCliModelCatalog(input, options = {}) {
|
|
|
52
52
|
return parseModelCatalog(input, options);
|
|
53
53
|
const externalCredentialModels = new Set();
|
|
54
54
|
const normalizedModels = input.models.map((model, index) => {
|
|
55
|
+
if (isRecord(model) && Object.hasOwn(model, 'highDensityCompaction')) {
|
|
56
|
+
if (typeof model.highDensityCompaction !== 'boolean')
|
|
57
|
+
throw invalidCatalog();
|
|
58
|
+
const { highDensityCompaction: _compaction, ...configuration } = model;
|
|
59
|
+
void _compaction;
|
|
60
|
+
model = configuration;
|
|
61
|
+
}
|
|
55
62
|
if (isRecord(model) && Object.hasOwn(model, 'responsesEncoding')) {
|
|
56
63
|
if (model.protocol !== 'OPENAI_RESPONSES' ||
|
|
57
64
|
(model.responsesEncoding !== 'STANDARD' && model.responsesEncoding !== 'LITE'))
|
|
@@ -69,7 +69,6 @@ declare const rawModelSchema: z.ZodObject<{
|
|
|
69
69
|
}>>;
|
|
70
70
|
titleGeneration: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
71
71
|
codeMode: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
72
|
-
highDensityCompaction: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
73
72
|
fastMode: z.ZodOptional<z.ZodBoolean>;
|
|
74
73
|
serviceTier: z.ZodOptional<z.ZodEnum<{
|
|
75
74
|
default: "default";
|
|
@@ -49,7 +49,6 @@ const rawModelSchema = z
|
|
|
49
49
|
defaultReasoningEffort: marAgentReasoningEffortSchema.optional(),
|
|
50
50
|
titleGeneration: z.boolean().optional().default(false),
|
|
51
51
|
codeMode: z.boolean().optional().default(false),
|
|
52
|
-
highDensityCompaction: z.boolean().optional().default(false),
|
|
53
52
|
fastMode: z.boolean().optional(),
|
|
54
53
|
serviceTier: z.enum(['auto', 'default', 'flex', 'priority', 'fast', 'ultrafast']).optional(),
|
|
55
54
|
hostedWebSearch: z.boolean(),
|
|
@@ -51,6 +51,12 @@ export interface ModelAttemptDiagnostic {
|
|
|
51
51
|
connectionId?: string;
|
|
52
52
|
connectionReused?: boolean;
|
|
53
53
|
proxyType?: 'DIRECT' | 'SOCKS5';
|
|
54
|
+
/** Hashes of the lowered full logical request; never include credentials or raw bodies. */
|
|
55
|
+
requestInstructionsHash?: string;
|
|
56
|
+
requestToolsHash?: string;
|
|
57
|
+
requestPropertiesHash?: string;
|
|
58
|
+
requestInputHash?: string;
|
|
59
|
+
requestInputItems?: number;
|
|
54
60
|
/** Actual serialized WebSocket request size, including inline image Base64. */
|
|
55
61
|
requestBytes?: number;
|
|
56
62
|
imageCount?: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { observationModelParts } from '../tools/code-mode/observations.js';
|
|
2
|
+
import { stableToolSchema } from '../tools/definition-projection.js';
|
|
2
3
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
4
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
5
|
import { describeMarAgentError, MarAgentError } from '../error.js';
|
|
@@ -89,6 +90,15 @@ export class OpenAiResponsesAdapter {
|
|
|
89
90
|
const attemptContinuation = useContinuation;
|
|
90
91
|
const attemptCredentialReason = credentialReason;
|
|
91
92
|
const attemptTransport = this.configuration.responsesTransport?.transport === 'WEBSOCKET' ? 'WEBSOCKET' : 'HTTP';
|
|
93
|
+
const requestPrefixDiagnostic = request.onAttemptDiagnostic
|
|
94
|
+
? {
|
|
95
|
+
requestInstructionsHash: hashResponsesValue(prepared.fullBody.instructions),
|
|
96
|
+
requestToolsHash: hashResponsesValue(prepared.fullBody.tools),
|
|
97
|
+
requestPropertiesHash: hashResponsesValue({ ...prepared.fullBody, input: undefined }),
|
|
98
|
+
requestInputHash: hashResponsesValue(prepared.fullBody.input),
|
|
99
|
+
requestInputItems: prepared.fullBody.input.length
|
|
100
|
+
}
|
|
101
|
+
: {};
|
|
92
102
|
const prelude = [];
|
|
93
103
|
let sawSemanticEvent = false;
|
|
94
104
|
let firstSemanticEventType;
|
|
@@ -100,7 +110,8 @@ export class OpenAiResponsesAdapter {
|
|
|
100
110
|
attempt: attemptNumber,
|
|
101
111
|
maxAttempts,
|
|
102
112
|
continuation: attemptContinuation,
|
|
103
|
-
credentialReason: attemptCredentialReason
|
|
113
|
+
credentialReason: attemptCredentialReason,
|
|
114
|
+
...requestPrefixDiagnostic
|
|
104
115
|
});
|
|
105
116
|
try {
|
|
106
117
|
for await (const event of this.startAttempt(request, signal, requestBody, useContinuation, credentialReason, turn)) {
|
|
@@ -130,6 +141,7 @@ export class OpenAiResponsesAdapter {
|
|
|
130
141
|
maxAttempts,
|
|
131
142
|
continuation: attemptContinuation,
|
|
132
143
|
credentialReason: attemptCredentialReason,
|
|
144
|
+
...requestPrefixDiagnostic,
|
|
133
145
|
semanticEventObserved: sawSemanticEvent,
|
|
134
146
|
...(firstSemanticEventType === undefined ? {} : { firstSemanticEventType }),
|
|
135
147
|
...turn.connectionDiagnostic(),
|
|
@@ -146,6 +158,7 @@ export class OpenAiResponsesAdapter {
|
|
|
146
158
|
maxAttempts,
|
|
147
159
|
continuation: attemptContinuation,
|
|
148
160
|
credentialReason: attemptCredentialReason,
|
|
161
|
+
...requestPrefixDiagnostic,
|
|
149
162
|
semanticEventObserved: sawSemanticEvent,
|
|
150
163
|
...(firstSemanticEventType === undefined ? {} : { firstSemanticEventType }),
|
|
151
164
|
...turn.connectionDiagnostic(),
|
|
@@ -651,7 +664,7 @@ class OpenAiResponsesTurnSession {
|
|
|
651
664
|
if (event.type === 'response.started' && event.responseId !== 'unknown')
|
|
652
665
|
responseId = event.responseId;
|
|
653
666
|
else if (event.type === 'response.item')
|
|
654
|
-
outputItems.push(event.item);
|
|
667
|
+
outputItems.push(JSON.parse(JSON.stringify(event.item)));
|
|
655
668
|
else if (event.type === 'text.delta' ||
|
|
656
669
|
event.type === 'output.delta' ||
|
|
657
670
|
event.type === 'text.completed' ||
|
|
@@ -706,7 +719,8 @@ class OpenAiResponsesTurnSession {
|
|
|
706
719
|
invalidateResponsesWebSocket(this.state, false);
|
|
707
720
|
clearResponsesContinuation(this.state);
|
|
708
721
|
}
|
|
709
|
-
|
|
722
|
+
// The continuation baseline must not share mutable schemas or items with callers.
|
|
723
|
+
const fullBody = JSON.parse(JSON.stringify(responsesRequestBody(this.adapter.configuration, request, request.messages)));
|
|
710
724
|
if (responsesContinuationEnabled(this.adapter.configuration)) {
|
|
711
725
|
const incremental = incrementalResponsesInput(this.state, fullBody);
|
|
712
726
|
if (incremental !== undefined) {
|
|
@@ -875,7 +889,7 @@ function responsesRequestBody(configuration, request, messages) {
|
|
|
875
889
|
type: 'tool_search',
|
|
876
890
|
execution: 'client',
|
|
877
891
|
description: tool.description,
|
|
878
|
-
parameters: strictFunctionSchema(tool.inputSchema)
|
|
892
|
+
parameters: stableToolSchema(strictFunctionSchema(stableToolSchema(tool.inputSchema)))
|
|
879
893
|
}
|
|
880
894
|
: responsesFunctionTool(tool));
|
|
881
895
|
if (configuration.responsesToolNamespace && tools.length > 0) {
|
|
@@ -948,27 +962,13 @@ function incrementalResponsesInput(state, current) {
|
|
|
948
962
|
if (current.input.length < baseline.length)
|
|
949
963
|
return undefined;
|
|
950
964
|
for (let index = 0; index < baseline.length; index++)
|
|
951
|
-
if (
|
|
965
|
+
if (JSON.stringify(baseline[index]) !== JSON.stringify(current.input[index]))
|
|
952
966
|
return undefined;
|
|
953
967
|
return current.input.slice(baseline.length);
|
|
954
968
|
}
|
|
955
969
|
function responsesContinuationPropertiesMatch(previous, current) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
'service_tier',
|
|
959
|
-
'instructions',
|
|
960
|
-
'tools',
|
|
961
|
-
'tool_choice',
|
|
962
|
-
'max_output_tokens',
|
|
963
|
-
'parallel_tool_calls',
|
|
964
|
-
'reasoning',
|
|
965
|
-
'store',
|
|
966
|
-
'stream',
|
|
967
|
-
'include',
|
|
968
|
-
'prompt_cache_key',
|
|
969
|
-
'text'
|
|
970
|
-
];
|
|
971
|
-
return properties.every((property) => isDeepStrictEqual(previous[property], current[property]));
|
|
970
|
+
return (JSON.stringify({ ...previous, input: undefined }) ===
|
|
971
|
+
JSON.stringify({ ...current, input: undefined }));
|
|
972
972
|
}
|
|
973
973
|
function clearResponsesContinuation(state) {
|
|
974
974
|
delete state.lastRequest;
|
|
@@ -1508,11 +1508,11 @@ function responsesHeaders(credential, promptCacheKey, turnState) {
|
|
|
1508
1508
|
authorization: `Bearer ${credential.bearer.reveal()}`,
|
|
1509
1509
|
'content-type': 'application/json',
|
|
1510
1510
|
accept: 'text/event-stream',
|
|
1511
|
+
'x-client-request-id': randomUUID(),
|
|
1511
1512
|
...(promptCacheKey
|
|
1512
1513
|
? {
|
|
1513
1514
|
'session-id': promptCacheKey,
|
|
1514
|
-
'thread-id': promptCacheKey
|
|
1515
|
-
'x-client-request-id': promptCacheKey
|
|
1515
|
+
'thread-id': promptCacheKey
|
|
1516
1516
|
}
|
|
1517
1517
|
: {})
|
|
1518
1518
|
});
|
|
@@ -1927,7 +1927,7 @@ function responsesFunctionTool(tool) {
|
|
|
1927
1927
|
type: 'function',
|
|
1928
1928
|
name: tool.name,
|
|
1929
1929
|
description: tool.description,
|
|
1930
|
-
parameters: strict ? strictFunctionSchema(tool.inputSchema) : tool.inputSchema,
|
|
1930
|
+
parameters: stableToolSchema(strict ? strictFunctionSchema(stableToolSchema(tool.inputSchema)) : tool.inputSchema),
|
|
1931
1931
|
strict
|
|
1932
1932
|
};
|
|
1933
1933
|
}
|
|
@@ -24,59 +24,3 @@ Remove aggressively:
|
|
|
24
24
|
|
|
25
25
|
Use compact Markdown with these headings when applicable: Objective, Instructions and constraints, Decisions and facts, Completed work, Verification and evidence, Active state, Open issues and risks, Next action. Omit empty headings. Prefer precise paths, IDs, error codes, and short evidence over narrative. Output only the handoff.`;
|
|
26
26
|
}
|
|
27
|
-
export function highDensityCompactionPrompt() {
|
|
28
|
-
return `Compile the visible conversation into Textual Continuation IR that lets the next agent continue correctly after the transcript is discarded. Transfer state; do not recap, address the user, call tools, advance the task, or invent facts.
|
|
29
|
-
|
|
30
|
-
Optimize for continuation fidelity first and density second. Prefer sufficient continuation state over brevity; never omit information required to resume correctly.
|
|
31
|
-
|
|
32
|
-
## Output contract
|
|
33
|
-
Use these English section names when applicable; omit empty sections:
|
|
34
|
-
1. Goal contract
|
|
35
|
-
2. Current state
|
|
36
|
-
3. Settled matters
|
|
37
|
-
4. Necessary evidence
|
|
38
|
-
5. Open loops
|
|
39
|
-
|
|
40
|
-
IR grammar and vocabulary are English: headings, keys, enums, state atoms, and control terms. Natural-language values may follow the task's dominant language. Preserve exact user-designated text and established domain terms; do not translate identifiers or invent localized IR terminology.
|
|
41
|
-
|
|
42
|
-
Prefer records over prose:
|
|
43
|
-
<object> | <key>=<value> | <key>=<value>
|
|
44
|
-
<event/condition> -> <object>.<key>=<value> | <effect>
|
|
45
|
-
|
|
46
|
-
Use | for parallel facts, = for current state, and -> only for causality, invalidation, or transition. Keep enums lowercase and semantic: required, forbidden, pending; never YES/NO. Omit empty or irrelevant unknown fields. Keep pending, not run, unverified, and failed distinct. Use a sentence only when records cannot express a multi-object cause, conflict, authorization, or safety boundary unambiguously.
|
|
47
|
-
|
|
48
|
-
Examples:
|
|
49
|
-
src/discount.js | cause=verified | edit=pending | tests=not run
|
|
50
|
-
patch(src/discount.js) -> prior_read=stale | next=re-evidence
|
|
51
|
-
authorization | action=<exact> | scope=<exact> | lifetime=<exact> | status=active
|
|
52
|
-
|
|
53
|
-
## Compiler
|
|
54
|
-
1. Resolve intent. The latest user correction overrides older intent. Extract the primary objective, current deliverable, completion criteria, non-goals, and boundaries.
|
|
55
|
-
2. Reduce time. Convert before -> event -> after into the latest evidenced state. Source mutation or base/branch change makes only affected evidence stale. History replacement invalidates Responses continuation, not factual evidence. Without an invalidating event, a verified claim remains current.
|
|
56
|
-
3. Build objects. Emit one current record per file, symbol, feature, migration, test, worktree axis, selected Skill, Todo/plan item, external decision, or external side effect. Deduplicate equivalent facts.
|
|
57
|
-
4. Separate status axes when needed:
|
|
58
|
-
- completion=pending|in_progress|completed|blocked
|
|
59
|
-
- epistemic=observed|verified|inferred|proposed|disproved
|
|
60
|
-
- freshness=current|stale|superseded
|
|
61
|
-
- scope=turn|worktree|base|branch|external
|
|
62
|
-
5. Bind evidence to the claim it proves. Prefer a verified conclusion over raw snapshots or intermediate hypotheses.
|
|
63
|
-
6. Select under budget. Protect, in order: objective, progress, boundaries and authorization, non-repeatable side effects, open loops, then necessary evidence. Remove provenance and recoverable detail only after those remain sufficient.
|
|
64
|
-
|
|
65
|
-
## Retention rules
|
|
66
|
-
- Preserve active caller/user instructions outside filesystem-loaded AGENTS.md, exact authorization boundaries, confirmed decisions and exclusions, completed edits and side effects, verification actually run, reproducible failures, failed approaches that constrain the next step, unresolved risks, and the smallest established next action.
|
|
67
|
-
- Authorization is valid only for its exact action, scope, and lifetime in the active request. Completed or superseded scopes cannot revive it. Object state, completion, tool availability, and convenience never imply permission.
|
|
68
|
-
- Preserve decisive values, or an exact artifact path/command that deterministically recovers them, when a result controls later work. Counts or schemas alone are insufficient.
|
|
69
|
-
- Preserve paths, symbols, APIs, tools, models, providers, JSON keys, protocol fields, commands, arguments, error codes, commit hashes, call IDs, sequences, versions, numbers, and user-designated text verbatim.
|
|
70
|
-
- Preserve selected Skill names with only continuation-critical constraints. Preserve Todo/plan revision, item/status, and current minimum step.
|
|
71
|
-
- Keep observed HEAD, validated base, target commit, and current worktree as separate axes. Evidence updates only what it directly proves; cross-axis, cross-base, and cross-branch inference remains unverified.
|
|
72
|
-
- If evidence conflicts, use state=conflict | candidates=<short values> | next=re-evidence. Never choose a side without evidence.
|
|
73
|
-
|
|
74
|
-
## Exclusions
|
|
75
|
-
Remove greetings, progress chatter, chronology that does not affect current state, duplicate facts, superseded hypotheses without remaining constraints, long logs, source bodies, verbose payloads, cheap-to-recover content, local-only integrity hashes, hidden reasoning, secrets, credentials, and unrelated content.
|
|
76
|
-
|
|
77
|
-
Remove user/project/directory AGENTS.md text and constraints derived only from those files; the next Execution reloads them. Remove retained process/Subagent inventory, IDs, status, commands, cwd, and reuse instructions; Runtime reloads them.
|
|
78
|
-
|
|
79
|
-
Before emitting, verify that objective, current progress, authorization/boundaries, completed versus unverified work, decisive evidence, open loops, and next action are explicit and non-contradictory.
|
|
80
|
-
|
|
81
|
-
Output only compact Markdown IR.`;
|
|
82
|
-
}
|
|
@@ -13,7 +13,6 @@ interface SystemPromptInput {
|
|
|
13
13
|
workspace: string;
|
|
14
14
|
tools: readonly string[];
|
|
15
15
|
directTools?: readonly string[];
|
|
16
|
-
highDensityCompaction?: boolean;
|
|
17
16
|
extension?: string | undefined;
|
|
18
17
|
}
|
|
19
18
|
export declare function buildSystemPrompt(input: SystemPromptInput): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { renderPromptSections } from '../extensions/prompt-composition.js';
|
|
2
|
-
import { compactionPrompt
|
|
2
|
+
import { compactionPrompt } from './compact.js';
|
|
3
3
|
import { environmentPrompt, identityPrompt, instructionPriorityPrompt, workspaceDisciplinePrompt } from './core.js';
|
|
4
4
|
import { modePrompt } from './modes.js';
|
|
5
5
|
import { outputStylePrompt } from './output.js';
|
|
@@ -36,14 +36,7 @@ export function buildSystemPromptSections(input) {
|
|
|
36
36
|
questionAvailable: toolNames.has('question')
|
|
37
37
|
})
|
|
38
38
|
],
|
|
39
|
-
[
|
|
40
|
-
'compaction',
|
|
41
|
-
input.mode === 'compact'
|
|
42
|
-
? input.highDensityCompaction
|
|
43
|
-
? highDensityCompactionPrompt()
|
|
44
|
-
: compactionPrompt()
|
|
45
|
-
: ''
|
|
46
|
-
],
|
|
39
|
+
['compaction', input.mode === 'compact' ? compactionPrompt() : ''],
|
|
47
40
|
['subagent', toolNames.has('agent_start') ? subagentPrompt : ''],
|
|
48
41
|
[
|
|
49
42
|
'caller-instructions',
|
|
@@ -3,9 +3,8 @@ import type { CompactHistoryMessage, CompactUserInput } from '../../session/json
|
|
|
3
3
|
export declare const DEFAULT_COMPACTION_FOCUS = "Create a durable continuation state for the next model invocation.";
|
|
4
4
|
export declare function buildNativeCompactionMessages(messages: readonly ModelMessage[], input?: {
|
|
5
5
|
focus?: string;
|
|
6
|
-
highDensityCompaction?: boolean;
|
|
7
6
|
}): ModelMessage[];
|
|
8
|
-
export declare function buildCompactionMessages(evidence: string
|
|
7
|
+
export declare function buildCompactionMessages(evidence: string): ModelMessage[];
|
|
9
8
|
export declare function buildCompactionInput(messages: readonly ModelMessage[], input: {
|
|
10
9
|
focus?: string;
|
|
11
10
|
maxTokens: number;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { countModelTokens, truncateModelText } from '../token-budget.js';
|
|
2
|
-
import { compactionPrompt
|
|
2
|
+
import { compactionPrompt } from '../../prompts/compact.js';
|
|
3
3
|
export const DEFAULT_COMPACTION_FOCUS = 'Create a durable continuation state for the next model invocation.';
|
|
4
4
|
export function buildNativeCompactionMessages(messages, input = {}) {
|
|
5
5
|
const focus = input.focus?.trim();
|
|
6
|
-
const contract =
|
|
6
|
+
const contract = compactionPrompt();
|
|
7
7
|
return [
|
|
8
8
|
...messages
|
|
9
9
|
.filter((message) => message.contextKind !== 'private')
|
|
@@ -21,13 +21,13 @@ export function buildNativeCompactionMessages(messages, input = {}) {
|
|
|
21
21
|
}
|
|
22
22
|
];
|
|
23
23
|
}
|
|
24
|
-
export function buildCompactionMessages(evidence
|
|
24
|
+
export function buildCompactionMessages(evidence) {
|
|
25
25
|
return [
|
|
26
26
|
{ role: 'user', content: evidence, contextKind: 'contextual' },
|
|
27
27
|
{
|
|
28
28
|
role: 'user',
|
|
29
29
|
contextKind: 'compact_control',
|
|
30
|
-
content:
|
|
30
|
+
content: compactionPrompt()
|
|
31
31
|
}
|
|
32
32
|
];
|
|
33
33
|
}
|
|
@@ -109,7 +109,6 @@ export function createSessionOpener(services) {
|
|
|
109
109
|
.filter((tool) => !tool.name.startsWith('mcp__') &&
|
|
110
110
|
allowsDirectTool(tool, availableTools.some((candidate) => candidate.name === 'code_exec')))
|
|
111
111
|
.map((tool) => tool.name),
|
|
112
|
-
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
113
112
|
extension: [
|
|
114
113
|
executionSystemInstruction,
|
|
115
114
|
skillCatalog,
|
|
@@ -1031,7 +1030,6 @@ export function createSessionOpener(services) {
|
|
|
1031
1030
|
if (!coreExtensions.hooks.hasInterceptors('compact.generate'))
|
|
1032
1031
|
return undefined;
|
|
1033
1032
|
const summaryTokenBudget = Math.min(10_000, selectedModel.maxOutputTokens, Math.max(1, Math.floor(selectedModel.contextWindowTokens / 4)));
|
|
1034
|
-
const highDensityCompaction = selectedModel.highDensityCompaction;
|
|
1035
1033
|
let diagnosticReports = 0;
|
|
1036
1034
|
let acceptsDiagnostics = true;
|
|
1037
1035
|
try {
|
|
@@ -1041,7 +1039,7 @@ export function createSessionOpener(services) {
|
|
|
1041
1039
|
messages: compactExtensionMessages(history),
|
|
1042
1040
|
...(focus === undefined ? {} : { focus }),
|
|
1043
1041
|
summaryTokenBudget,
|
|
1044
|
-
getPrompt: () => buildCompactionMessages(''
|
|
1042
|
+
getPrompt: () => buildCompactionMessages('')[1].content,
|
|
1045
1043
|
reportDiagnostic: async (value) => {
|
|
1046
1044
|
if (!acceptsDiagnostics || ++diagnosticReports > 8)
|
|
1047
1045
|
return;
|
|
@@ -1082,17 +1080,16 @@ export function createSessionOpener(services) {
|
|
|
1082
1080
|
const compactHistory = [...messages];
|
|
1083
1081
|
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
1084
1082
|
const nativeMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1085
|
-
focus: compactFocus
|
|
1086
|
-
highDensityCompaction: selectedModel.highDensityCompaction
|
|
1083
|
+
focus: compactFocus
|
|
1087
1084
|
});
|
|
1088
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''
|
|
1085
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''), executionTools);
|
|
1089
1086
|
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
1090
1087
|
if (compactInputTokens <= 0)
|
|
1091
1088
|
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
1092
1089
|
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1093
1090
|
focus: compactFocus,
|
|
1094
1091
|
maxTokens: compactInputTokens
|
|
1095
|
-
})
|
|
1092
|
+
}));
|
|
1096
1093
|
const useNative = shouldUseNativeCompaction({
|
|
1097
1094
|
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeMessages, executionTools),
|
|
1098
1095
|
contextWindowTokens: selectedModel.contextWindowTokens,
|
|
@@ -1138,10 +1135,9 @@ export function createSessionOpener(services) {
|
|
|
1138
1135
|
const compactSystemPrompt = await operation((call) => coreExtensions.compose(promptComposition(executionTools, 'run'), call));
|
|
1139
1136
|
const projectedHistory = normalizeMessagesForModel(insertContextualWorldState(compactHistory, contextualWorldState.entries), { supportsImages: false });
|
|
1140
1137
|
const nativeCompactMessages = buildNativeCompactionMessages(projectedHistory, {
|
|
1141
|
-
...(input.focus === undefined ? {} : { focus: input.focus })
|
|
1142
|
-
highDensityCompaction: selectedModel.highDensityCompaction
|
|
1138
|
+
...(input.focus === undefined ? {} : { focus: input.focus })
|
|
1143
1139
|
});
|
|
1144
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''
|
|
1140
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''), executionTools);
|
|
1145
1141
|
const compactInputTokens = Math.max(0, selectedModel.contextWindowTokens - compactOverheadTokens);
|
|
1146
1142
|
let usingNativeMessages = shouldUseNativeCompaction({
|
|
1147
1143
|
estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeCompactMessages, executionTools),
|
|
@@ -1153,7 +1149,7 @@ export function createSessionOpener(services) {
|
|
|
1153
1149
|
const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
|
|
1154
1150
|
...(input.focus === undefined ? {} : { focus: input.focus }),
|
|
1155
1151
|
maxTokens: Math.max(1, compactInputTokens)
|
|
1156
|
-
})
|
|
1152
|
+
}));
|
|
1157
1153
|
let compactMessages = usingNativeMessages
|
|
1158
1154
|
? nativeCompactMessages
|
|
1159
1155
|
: fallbackMessages();
|
|
@@ -31,7 +31,9 @@ export const agentStartToolDefinition = {
|
|
|
31
31
|
export function agentStartToolDefinitionWithModels(models) {
|
|
32
32
|
if (models.length === 0)
|
|
33
33
|
return agentStartToolDefinition;
|
|
34
|
-
const modelLines = models
|
|
34
|
+
const modelLines = [...models]
|
|
35
|
+
.sort((left, right) => (left.id < right.id ? -1 : left.id > right.id ? 1 : 0))
|
|
36
|
+
.map((model) => {
|
|
35
37
|
const efforts = model.reasoningEfforts.length === 0
|
|
36
38
|
? ''
|
|
37
39
|
: `; reasoning efforts: ${model.reasoningEfforts.join(', ')}`;
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
7
7
|
import { MarAgentError, describeMarAgentError } from '../../error.js';
|
|
8
8
|
import { directLocalProcessExecutor, signalProcessTree } from '../../host/local-process-executor.js';
|
|
9
9
|
import { allowsDirectTool, allowsToolCaller } from '../callers.js';
|
|
10
|
+
import { orderToolDefinitions, stableToolSchema, stableToolDefinition } from '../definition-projection.js';
|
|
10
11
|
import { CodeCells } from './cells.js';
|
|
11
12
|
import { newObservationId, renderObservations } from './observations.js';
|
|
12
13
|
import { parseCodeModeStateMutations } from './state.js';
|
|
@@ -100,16 +101,18 @@ export const codeExecWaitToolDefinition = {
|
|
|
100
101
|
/** Deferred definitions travel in search results, not in the stable Code Mode description. */
|
|
101
102
|
export function projectCodeModeTools(tools, residentTools = tools) {
|
|
102
103
|
const codeModeEnabled = tools.some((tool) => tool.name === 'code_exec' && allowsToolCaller(tool, 'direct'));
|
|
103
|
-
const direct = tools
|
|
104
|
+
const direct = tools
|
|
105
|
+
.filter((tool) => allowsDirectTool(tool, codeModeEnabled))
|
|
106
|
+
.map(stableToolDefinition);
|
|
104
107
|
if (!codeModeEnabled)
|
|
105
108
|
return direct;
|
|
106
|
-
const programmatic = residentTools.filter((tool) => allowsToolCaller(tool, 'programmatic'));
|
|
109
|
+
const programmatic = orderToolDefinitions(residentTools.filter((tool) => allowsToolCaller(tool, 'programmatic')));
|
|
107
110
|
const directory = JSON.stringify({
|
|
108
111
|
callableNames: programmatic.map((tool) => tool.name),
|
|
109
112
|
programmaticOnly: programmatic.map((tool) => ({
|
|
110
113
|
name: tool.name,
|
|
111
114
|
description: tool.description,
|
|
112
|
-
inputSchema: tool.inputSchema,
|
|
115
|
+
inputSchema: stableToolSchema(tool.inputSchema),
|
|
113
116
|
inputMode: tool.inputMode ?? 'json'
|
|
114
117
|
}))
|
|
115
118
|
});
|
|
@@ -129,14 +132,16 @@ export function projectCodeModeSearchResult(message, codeModeEnabled) {
|
|
|
129
132
|
if (!codeModeEnabled)
|
|
130
133
|
return {
|
|
131
134
|
...message,
|
|
132
|
-
toolSearchTools: message.toolSearchTools
|
|
135
|
+
toolSearchTools: message.toolSearchTools
|
|
136
|
+
.filter((tool) => allowsToolCaller(tool, 'direct'))
|
|
137
|
+
.map(stableToolDefinition)
|
|
133
138
|
};
|
|
134
139
|
const tools = message.toolSearchTools.map((tool) => ({
|
|
135
140
|
name: tool.name,
|
|
136
141
|
description: allowsToolCaller(tool, 'programmatic')
|
|
137
142
|
? `Call only as tools.${tool.name} inside code_exec, never as a direct model tool.\n${tool.description}`
|
|
138
143
|
: tool.description,
|
|
139
|
-
inputSchema: tool.inputSchema,
|
|
144
|
+
inputSchema: stableToolSchema(tool.inputSchema),
|
|
140
145
|
inputMode: tool.inputMode ?? 'json',
|
|
141
146
|
caller: allowsToolCaller(tool, 'programmatic') ? 'programmatic' : 'direct'
|
|
142
147
|
}));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ClientToolDefinition } from './contracts.js';
|
|
2
|
+
/** Stable model declarations, not a serializer for historical messages or tool results. */
|
|
3
|
+
export declare function stableToolSchema<T>(schema: T): T;
|
|
4
|
+
export declare function stableToolDefinition(definition: ClientToolDefinition): ClientToolDefinition;
|
|
5
|
+
export declare function orderToolDefinitions<T extends {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
}>(definitions: readonly T[]): T[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Stable model declarations, not a serializer for historical messages or tool results. */
|
|
2
|
+
export function stableToolSchema(schema) {
|
|
3
|
+
return stableSchemaValue(schema);
|
|
4
|
+
}
|
|
5
|
+
function stableSchemaValue(value) {
|
|
6
|
+
if (Array.isArray(value))
|
|
7
|
+
return value.map(stableSchemaValue);
|
|
8
|
+
if (value === null || typeof value !== 'object')
|
|
9
|
+
return value;
|
|
10
|
+
const prototype = Object.getPrototypeOf(value);
|
|
11
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
12
|
+
return value;
|
|
13
|
+
const fields = value;
|
|
14
|
+
return Object.fromEntries(Object.keys(fields)
|
|
15
|
+
.sort()
|
|
16
|
+
.map((key) => [key, stableSchemaValue(fields[key])]));
|
|
17
|
+
}
|
|
18
|
+
export function stableToolDefinition(definition) {
|
|
19
|
+
return {
|
|
20
|
+
...definition,
|
|
21
|
+
inputSchema: stableToolSchema(definition.inputSchema)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function orderToolDefinitions(definitions) {
|
|
25
|
+
return [...definitions].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
|
|
26
|
+
}
|
|
@@ -2,6 +2,7 @@ import { MarAgentError } from '../../error.js';
|
|
|
2
2
|
import { countModelTokens } from '../../runtime/token-budget.js';
|
|
3
3
|
import { projectCodeModeSearchResult, projectCodeModeTools } from '../code-mode/index.js';
|
|
4
4
|
import { assertMcpToolCatalog } from './catalog.js';
|
|
5
|
+
import { orderToolDefinitions, stableToolDefinition } from '../definition-projection.js';
|
|
5
6
|
export const TOOL_SEARCH_LIMITS = Object.freeze({
|
|
6
7
|
defaultLimit: 5,
|
|
7
8
|
maximumLimit: 20,
|
|
@@ -65,7 +66,11 @@ export class DeferredMcpRegistry {
|
|
|
65
66
|
}
|
|
66
67
|
update(catalog, eligible, options = {}) {
|
|
67
68
|
assertMcpToolCatalog(catalog, options);
|
|
68
|
-
this.#catalog = {
|
|
69
|
+
this.#catalog = {
|
|
70
|
+
...catalog,
|
|
71
|
+
servers: [...catalog.servers].sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0),
|
|
72
|
+
tools: catalog.tools.filter(eligible)
|
|
73
|
+
};
|
|
69
74
|
const validSession = new Set(this.#catalog.tools
|
|
70
75
|
.filter((tool) => tool.lifetime === 'session' && tool.exposure === 'deferred')
|
|
71
76
|
.map((tool) => tool.definition.name));
|
|
@@ -128,12 +133,12 @@ export class DeferredMcpRegistry {
|
|
|
128
133
|
});
|
|
129
134
|
}
|
|
130
135
|
projectDirect(base) {
|
|
131
|
-
return [
|
|
136
|
+
return orderToolDefinitions([
|
|
132
137
|
...base,
|
|
133
138
|
...this.#catalog.tools
|
|
134
139
|
.filter((tool) => tool.exposure === 'direct')
|
|
135
140
|
.map((tool) => tool.definition)
|
|
136
|
-
];
|
|
141
|
+
]).map(stableToolDefinition);
|
|
137
142
|
}
|
|
138
143
|
project(base, selection = this.#selected, executionSelection = this.#executionSelected) {
|
|
139
144
|
const deferred = new Map(this.#catalog.tools
|
|
@@ -145,7 +150,10 @@ export class DeferredMcpRegistry {
|
|
|
145
150
|
.map((name) => deferred.get(name))
|
|
146
151
|
.filter((tool) => tool?.lifetime === 'execution')
|
|
147
152
|
];
|
|
148
|
-
return [
|
|
153
|
+
return [
|
|
154
|
+
...this.projectDirect(base),
|
|
155
|
+
...active.map((tool) => stableToolDefinition(tool.definition))
|
|
156
|
+
];
|
|
149
157
|
}
|
|
150
158
|
search(query, limit) {
|
|
151
159
|
const exact = this.#catalog.tools.find((tool) => tool.definition.name === query);
|
package/dist/cli/main.js
CHANGED
|
@@ -20,7 +20,7 @@ Usage:
|
|
|
20
20
|
maragent run <prompt> [--reasoning-effort EFFORT] [--format text|json|stream-json] [--codex-auth-file PATH]
|
|
21
21
|
maragent resume [sessionId] [--reasoning-effort EFFORT] [--codex-auth-file PATH]
|
|
22
22
|
maragent sessions list|delete <sessionId>
|
|
23
|
-
maragent models list|add|edit|remove|test [id] [--default-reasoning-effort EFFORT] [--code-mode|--no-code-mode] [--
|
|
23
|
+
maragent models list|add|edit|remove|test [id] [--default-reasoning-effort EFFORT] [--code-mode|--no-code-mode] [--fast-mode|--no-fast-mode] [--codex-auth-file PATH]
|
|
24
24
|
`;
|
|
25
25
|
function takeOption(arguments_, name) {
|
|
26
26
|
const index = arguments_.indexOf(name);
|
|
@@ -63,6 +63,9 @@ async function readApiKey() {
|
|
|
63
63
|
return value.trim();
|
|
64
64
|
}
|
|
65
65
|
async function modelsCommand(home, arguments_, codexAuthFile) {
|
|
66
|
+
if (arguments_.includes('--high-density-compaction') ||
|
|
67
|
+
arguments_.includes('--no-high-density-compaction'))
|
|
68
|
+
throw new MarAgentError('MAR_AGENT_CLI_ARGUMENT_INVALID', 'High-density compaction is no longer a model option.');
|
|
66
69
|
if (arguments_.includes('--responses-encoding'))
|
|
67
70
|
throw new MarAgentError('MAR_AGENT_CLI_ARGUMENT_INVALID', 'Responses encoding is no longer configurable.');
|
|
68
71
|
const action = arguments_[1];
|
|
@@ -164,8 +167,8 @@ async function modelsCommand(home, arguments_, codexAuthFile) {
|
|
|
164
167
|
: required(existing?.apiKey?.reveal(), '--api-key-stdin'))
|
|
165
168
|
}),
|
|
166
169
|
modelId: required(option('--model', existing?.modelId), '--model'),
|
|
167
|
-
contextWindowTokens: integer('--context', existing?.contextWindowTokens ??
|
|
168
|
-
maxOutputTokens: integer('--max-output', existing?.maxOutputTokens ??
|
|
170
|
+
contextWindowTokens: integer('--context', existing?.contextWindowTokens ?? 256_000),
|
|
171
|
+
maxOutputTokens: integer('--max-output', existing?.maxOutputTokens ?? 32_000),
|
|
169
172
|
inputCapabilities: booleanFlag(arguments_, '--image', '--no-image', existing?.inputCapabilities.includes('IMAGE') ?? false)
|
|
170
173
|
? ['TEXT', 'IMAGE']
|
|
171
174
|
: ['TEXT'],
|
|
@@ -179,7 +182,6 @@ async function modelsCommand(home, arguments_, codexAuthFile) {
|
|
|
179
182
|
: parseReasoningEffort(defaultReasoningEffortOption, '--default-reasoning-effort'),
|
|
180
183
|
titleGeneration: existing?.titleGeneration ?? false,
|
|
181
184
|
codeMode: booleanFlag(arguments_, '--code-mode', '--no-code-mode', existing?.codeMode ?? false),
|
|
182
|
-
highDensityCompaction: booleanFlag(arguments_, '--high-density-compaction', '--no-high-density-compaction', existing?.highDensityCompaction ?? false),
|
|
183
185
|
...(credential === 'codex-auth-file' && fastMode ? { fastMode: true } : {}),
|
|
184
186
|
...(protocol === 'OPENAI_RESPONSES' && existing?.serviceTier !== undefined
|
|
185
187
|
? {
|