@myagentroam/agent 0.9.74 → 0.9.76
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/cli/main.js +2 -1
- package/dist/model/catalog-file.d.ts +2 -0
- package/dist/model/configuration.d.ts +1 -0
- package/dist/model/configuration.js +1 -0
- package/dist/prompts/compact.d.ts +1 -0
- package/dist/prompts/compact.js +66 -0
- package/dist/prompts/index.d.ts +2 -1
- package/dist/prompts/index.js +7 -3
- package/dist/prompts/output.d.ts +1 -1
- package/dist/prompts/output.js +1 -1
- package/dist/prompts/workflow.js +1 -1
- package/dist/runtime/compact.d.ts +1 -1
- package/dist/runtime/compact.js +6 -3
- package/dist/runtime/token-budget.d.ts +5 -1
- package/dist/runtime/token-budget.js +3 -3
- package/dist/sdk/agent.js +19 -8
- package/dist/tools/local-registry.js +76 -1
- package/dist/tools/read.js +1 -1
- package/package.json +2 -1
package/dist/cli/main.js
CHANGED
|
@@ -19,7 +19,7 @@ Usage:
|
|
|
19
19
|
maragent run <prompt> [--reasoning-effort EFFORT] [--format text|json|stream-json] [--codex-auth-file PATH]
|
|
20
20
|
maragent resume [sessionId] [--reasoning-effort EFFORT] [--codex-auth-file PATH]
|
|
21
21
|
maragent sessions list|delete <sessionId>
|
|
22
|
-
maragent models list|add|edit|remove|test [id] [--default-reasoning-effort EFFORT] [--code-mode|--no-code-mode] [--responses-encoding standard|lite] [--codex-auth-file PATH]
|
|
22
|
+
maragent models list|add|edit|remove|test [id] [--default-reasoning-effort EFFORT] [--code-mode|--no-code-mode] [--high-density-compaction|--no-high-density-compaction] [--responses-encoding standard|lite] [--codex-auth-file PATH]
|
|
23
23
|
`;
|
|
24
24
|
function takeOption(arguments_, name) {
|
|
25
25
|
const index = arguments_.indexOf(name);
|
|
@@ -181,6 +181,7 @@ async function modelsCommand(home, arguments_, codexAuthFile) {
|
|
|
181
181
|
: parseReasoningEffort(defaultReasoningEffortOption, '--default-reasoning-effort'),
|
|
182
182
|
titleGeneration: existing?.titleGeneration ?? false,
|
|
183
183
|
codeMode: booleanFlag(arguments_, '--code-mode', '--no-code-mode', existing?.codeMode ?? false),
|
|
184
|
+
highDensityCompaction: booleanFlag(arguments_, '--high-density-compaction', '--no-high-density-compaction', existing?.highDensityCompaction ?? false),
|
|
184
185
|
hostedWebSearch: booleanFlag(arguments_, '--web-search', '--no-web-search', existing?.hostedWebSearch ?? false),
|
|
185
186
|
...(responsesTransport === undefined ? {} : { responsesTransport }),
|
|
186
187
|
...(responsesEncoding === undefined ? {} : { responsesEncoding }),
|
|
@@ -27,6 +27,7 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
27
27
|
defaultReasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max" | "ultra" | undefined;
|
|
28
28
|
titleGeneration: boolean;
|
|
29
29
|
codeMode: boolean;
|
|
30
|
+
highDensityCompaction: boolean;
|
|
30
31
|
hostedWebSearch: boolean;
|
|
31
32
|
responsesEncoding?: "STANDARD" | "LITE" | undefined;
|
|
32
33
|
enabled: boolean;
|
|
@@ -50,6 +51,7 @@ export declare function serializeModel(model: CliModelConfiguration): {
|
|
|
50
51
|
defaultReasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max" | "ultra" | undefined;
|
|
51
52
|
titleGeneration: boolean;
|
|
52
53
|
codeMode: boolean;
|
|
54
|
+
highDensityCompaction: boolean;
|
|
53
55
|
hostedWebSearch: boolean;
|
|
54
56
|
responsesEncoding?: "STANDARD" | "LITE" | undefined;
|
|
55
57
|
enabled: boolean;
|
|
@@ -78,6 +78,7 @@ declare const rawModelSchema: z.ZodObject<{
|
|
|
78
78
|
}>>;
|
|
79
79
|
titleGeneration: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
80
80
|
codeMode: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
81
|
+
highDensityCompaction: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
81
82
|
hostedWebSearch: z.ZodBoolean;
|
|
82
83
|
responsesTransport: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
83
84
|
transport: z.ZodLiteral<"HTTP">;
|
|
@@ -49,6 +49,7 @@ 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),
|
|
52
53
|
hostedWebSearch: z.boolean(),
|
|
53
54
|
responsesTransport: rawResponsesTransportSchema.optional(),
|
|
54
55
|
responsesEncoding: z.enum(['STANDARD', 'LITE']).optional(),
|
package/dist/prompts/compact.js
CHANGED
|
@@ -23,3 +23,69 @@ Remove aggressively:
|
|
|
23
23
|
|
|
24
24
|
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.`;
|
|
25
25
|
}
|
|
26
|
+
export function highDensityCompactionPrompt() {
|
|
27
|
+
return `将 visible conversation 编译为供下一 Agent 直接续作的 Textual Continuation IR;原 transcript 将丢弃。This is factual state transfer, not recap, user reply, or new work. 不调用工具、不推进任务、不虚构完成。
|
|
28
|
+
|
|
29
|
+
目标:在 handoff budget 内最大化 continuation accuracy、信息密度、可恢复性。Token reduction 仅在不损害续作后有价值;必要时约 10K tokens 可接受。
|
|
30
|
+
|
|
31
|
+
IR 不是 prose summary。默认使用最短且无歧义的事实短语、状态原子、精确引用;仅在短语无法说清因果、冲突或边界时使用完整句。优先两种形式:
|
|
32
|
+
<object> | <key>=<value> | <key>=<value>
|
|
33
|
+
<event/condition> -> <effect> | <effect>
|
|
34
|
+
例如:
|
|
35
|
+
src/discount.js | cause=verified | edit=pending | comment=required | tests=not run
|
|
36
|
+
patch(src/discount.js) -> prior_read=stale | next=re-evidence
|
|
37
|
+
branch changed -> inherited_evidence=unverified
|
|
38
|
+
|
|
39
|
+
语法:
|
|
40
|
+
- | 并列同一 object 的独立事实;= 表示 current fact/state/constraint;-> 仅表示 cause、invalidation、transition。
|
|
41
|
+
- key 使用最短且无歧义的 established term;value 可为状态原子或短语;enum 默认 lowercase。
|
|
42
|
+
- 使用 required/forbidden/pending 等语义值,不写 YES/NO。省略无续作价值的 unknown 和空字段。
|
|
43
|
+
- 同一 key 只保留已归约的 current value。无法消解:state=conflict | candidates=<short values> | next=re-evidence;不得任选一方。
|
|
44
|
+
- transition effect 优先 <object>.<key>=<value>;object 已唯一明确时可省略,不得省略到歧义。
|
|
45
|
+
- exact path/symbol/ID/command/number/user-designated text 原样保留。值含 |、换行或需逐字保存时,使用紧邻 record 的 Markdown code span/block,不发明 escaping protocol。
|
|
46
|
+
- pending、not run、unverified、failed 不得互换。
|
|
47
|
+
|
|
48
|
+
按需覆盖五类信息职责,空块省略。双语名称仅解释职责;输出标题只选当前任务合适的一种语言,不同时复制两套。
|
|
49
|
+
|
|
50
|
+
1. 目标契约 / Goal contract
|
|
51
|
+
- 主目标、当前交付、完成标准、非目标/边界。
|
|
52
|
+
- direct user/caller authorization、prohibition、exclusion 保留 exact action/scope,不概括成更宽泛边界。
|
|
53
|
+
|
|
54
|
+
2. 当前状态 / Current state
|
|
55
|
+
- 对象:file、symbol、feature、migration、test、worktree、process、subagent、selected Skill、Todo/plan、approval、external side effect。
|
|
56
|
+
- 分离 completion(pending / in_progress / completed / blocked)、epistemic(observed / verified / inferred / proposed / disproved)、freshness(current / stale / superseded)、scope(turn / worktree / base / branch / external system);仅在消歧时标注。
|
|
57
|
+
- 明确 completed、not started、unverified、active。相同精度下选择更短状态原子;中文、English 均可,如 根因已证、edit=pending、tests=not run。
|
|
58
|
+
- selected Skill | 保留仍适用的 skill name + 续作必需约束;Todo/plan | 保留 revision、item/status、当前最小 step。
|
|
59
|
+
- verified claim 后无 source mutation/base/branch change 等 invalidating event:freshness=current | re-diagnosis=not needed。为 patch 获取当前行上下文的 targeted reread 仍可保留,不等同重新调查已证结论。
|
|
60
|
+
|
|
61
|
+
3. 已定事项 / Settled matters
|
|
62
|
+
- confirmed decision/interface/constraint + 续作仍需的最短理由。
|
|
63
|
+
- disproved/rejected direction + scope/evidence。
|
|
64
|
+
- recovery path、event shape、implementation option、next action 未经 direct evidence 前保持 proposed/unverified。
|
|
65
|
+
|
|
66
|
+
4. 必要证据 / Necessary evidence
|
|
67
|
+
- 仅保留不可廉价恢复、决定后续判断、记录不可重复 side effect,或精确值影响 correctness 的 evidence;紧邻 claim,绑定 scope/freshness。
|
|
68
|
+
- completed check/result 若决定后续判断:保留 decisive values,或可确定恢复这些值的 exact artifact path/command;不得只留 count/schema。
|
|
69
|
+
- path、symbol/class/function/variable、API/tool/model/provider、JSON key/enum/protocol field、command/arguments、error code、commit hash、callId、sequence、version、number、用户指定原文:原样保留,不翻译、不猜测。
|
|
70
|
+
- 下一 Agent 无法使用、仅供 local storage validation 的 integrity hash:删除。
|
|
71
|
+
|
|
72
|
+
5. 未闭环 / Open loops
|
|
73
|
+
- unresolved、unverified、blocker、pending approval、活动 process/subagent、Todo/plan current step、仍需 evidence。
|
|
74
|
+
- 只保留已确定的最小 next action + preconditions;不复制可重算的长 plan。
|
|
75
|
+
|
|
76
|
+
编译规则:
|
|
77
|
+
1. latest user intent 定目标;newer correction 覆盖 older intent。
|
|
78
|
+
2. 归约 before -> event -> after;source mutation 或 base/branch change 后 affected read/conclusion stale,除非已有 newer evidence;history replacement 仅使 Responses continuation invalid,不使 factual evidence 自动失效;无 invalidating event 的 verified claim 保持 current;current 取最后已证 after-state 或 later direct observation。
|
|
79
|
+
3. 每个 continuation object 一条 current record;等价事实去重。
|
|
80
|
+
4. 仅保留仍约束 open work 的 settled decision/exclusion。
|
|
81
|
+
5. evidence 绑定 claim;verified conclusion 优先于 raw snapshot/intermediate hypothesis。
|
|
82
|
+
6. 预算受压时依次保护:目标、当前进度、边界、不可重复副作用、未闭环、必要证据;再删 provenance/可恢复实现细节。
|
|
83
|
+
|
|
84
|
+
observed HEAD、validated base、target commit、current worktree 不得折叠;evidence 只更新直接证明的 axis。跨 axis/base/branch 推导无 direct evidence 时保持 unverified。状态冲突无法归约:保留 conflict + re-evidence,不替模型选择。
|
|
85
|
+
|
|
86
|
+
语言:标题/一般叙述跟随 latest active user instructions 和当前任务主语言;每条 record 按局部精度与密度选择中文、English 或 mixed phrasing。保留 established term/exact identifier,不为语言统一展开或翻译。English codebase 不等于 English handoff。
|
|
87
|
+
|
|
88
|
+
删除 greetings、progress chatter、过程叙事、重复事实、无剩余约束的 superseded hypothesis、长日志、source body、verbose payload、可从精确 path/command 廉价恢复的正文。删除 user/project/directory AGENTS.md 正文及仅由这些文件派生的 constraint,包括其中 exclusions;下一 Execution 会重新加载并整体替换。不得保留 hidden reasoning、secret、credential、无关内容。
|
|
89
|
+
|
|
90
|
+
只输出 compact Markdown IR。`;
|
|
91
|
+
}
|
package/dist/prompts/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ExecutionMode } from '../sdk/types.js';
|
|
|
2
2
|
import { type ExecutionBudgetPromptState } from './execution-budget.js';
|
|
3
3
|
import { type RetainedSessionResources } from './resources.js';
|
|
4
4
|
import { type CurrentAgentModel, type SubagentModelOption } from './subagent.js';
|
|
5
|
-
export declare const MAR_AGENT_PROMPT_VERSION = "1.
|
|
5
|
+
export declare const MAR_AGENT_PROMPT_VERSION = "1.47";
|
|
6
6
|
export declare function buildSystemPrompt(input: {
|
|
7
7
|
mode: ExecutionMode;
|
|
8
8
|
platform: string;
|
|
@@ -18,5 +18,6 @@ export declare function buildSystemPrompt(input: {
|
|
|
18
18
|
subagentModels?: readonly SubagentModelOption[];
|
|
19
19
|
retainedSessionResources?: RetainedSessionResources;
|
|
20
20
|
executionBudget?: ExecutionBudgetPromptState;
|
|
21
|
+
highDensityCompaction?: boolean;
|
|
21
22
|
extension?: string | undefined;
|
|
22
23
|
}): string;
|
package/dist/prompts/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compactionPrompt } from './compact.js';
|
|
1
|
+
import { compactionPrompt, highDensityCompactionPrompt } from './compact.js';
|
|
2
2
|
import { environmentPrompt, identityPrompt, instructionPriorityPrompt, workspaceDisciplinePrompt } from './core.js';
|
|
3
3
|
import { executionBudgetPrompt } from './execution-budget.js';
|
|
4
4
|
import { modePrompt } from './modes.js';
|
|
@@ -6,7 +6,7 @@ import { outputStylePrompt } from './output.js';
|
|
|
6
6
|
import { retainedSessionResourcesPrompt } from './resources.js';
|
|
7
7
|
import { subagentModelOptionsPrompt, subagentPrompt, currentAgentModelPrompt } from './subagent.js';
|
|
8
8
|
import { interactionPrompt, longRunningPrompt, safetyPrompt, toolUsagePrompt, workflowPrompt } from './workflow.js';
|
|
9
|
-
export const MAR_AGENT_PROMPT_VERSION = '1.
|
|
9
|
+
export const MAR_AGENT_PROMPT_VERSION = '1.47';
|
|
10
10
|
export function buildSystemPrompt(input) {
|
|
11
11
|
const toolNames = new Set(input.tools);
|
|
12
12
|
const hasLongRunningCapability = [
|
|
@@ -36,7 +36,11 @@ export function buildSystemPrompt(input) {
|
|
|
36
36
|
questionAvailable: toolNames.has('question'),
|
|
37
37
|
forceFinalize: input.executionBudget?.stage === 'exhausted'
|
|
38
38
|
}),
|
|
39
|
-
input.mode === 'compact'
|
|
39
|
+
input.mode === 'compact'
|
|
40
|
+
? input.highDensityCompaction
|
|
41
|
+
? highDensityCompactionPrompt()
|
|
42
|
+
: compactionPrompt()
|
|
43
|
+
: '',
|
|
40
44
|
toolNames.has('agent_start') ? subagentPrompt : '',
|
|
41
45
|
toolNames.has('agent_start') ? currentAgentModelPrompt(input.currentAgentModel) : '',
|
|
42
46
|
toolNames.has('agent_start') ? subagentModelOptionsPrompt(input.subagentModels ?? []) : '',
|
package/dist/prompts/output.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const outputStylePrompt = "# Output and communication style\nBe direct, natural, and concise.
|
|
1
|
+
export declare const outputStylePrompt = "# Output and communication style\nBe direct, natural, and concise. Default to a brief teammate update rather than a report; expand when the user requests detail or when complexity and multiple distinct findings need grouping or explanation. Lead with the result and report only details that materially support or qualify it, including actual verification, material risks, and unfinished work when relevant. Use plain sentences or a short list for simple results. Avoid unnecessary repetition, repeating progress, dumping logs, or adding empty sections. For a requested review, lead with actionable findings ordered by severity and file evidence; if none were found, say so and note validation gaps. Preserve exact paths, identifiers, error codes, citations, and useful line locations when they are evidence. Never expose hidden reasoning.";
|
|
2
2
|
export declare const modelOutputContinuationMessage = "Continue the previous response from exactly where it stopped. Do not repeat completed content.";
|
package/dist/prompts/output.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const outputStylePrompt =
|
|
1
|
+
export const outputStylePrompt = '# Output and communication style\nBe direct, natural, and concise. Default to a brief teammate update rather than a report; expand when the user requests detail or when complexity and multiple distinct findings need grouping or explanation. Lead with the result and report only details that materially support or qualify it, including actual verification, material risks, and unfinished work when relevant. Use plain sentences or a short list for simple results. Avoid unnecessary repetition, repeating progress, dumping logs, or adding empty sections. For a requested review, lead with actionable findings ordered by severity and file evidence; if none were found, say so and note validation gaps. Preserve exact paths, identifiers, error codes, citations, and useful line locations when they are evidence. Never expose hidden reasoning.';
|
|
2
2
|
export const modelOutputContinuationMessage = 'Continue the previous response from exactly where it stopped. Do not repeat completed content.';
|
package/dist/prompts/workflow.js
CHANGED
|
@@ -10,7 +10,7 @@ export function toolUsagePrompt(tools) {
|
|
|
10
10
|
if (names.has('exec'))
|
|
11
11
|
clauses.push('Use exec for platform-native commands, scripts, verification, and mechanical edits. Prefer rg or rg --files for search. Batch independent lookups and already-decided commands, preserving failure ordering. Use scripts for mechanical substitutions instead of reproducing long unchanged text in a patch; inspect actual effects afterward.');
|
|
12
12
|
if (names.has('read'))
|
|
13
|
-
clauses.push('Use read to batch known files and ranges. Batch only already-located, bounded ranges that are likely to fit together; for large files or documents, locate relevant sections before reading them. Read only what can affect the next decision, continue only relevant incomplete results using returned metadata, and avoid rereading unchanged content.');
|
|
13
|
+
clauses.push('Use read to batch known files and ranges. Batch only already-located, bounded ranges that are likely to fit together; for large files or documents, locate relevant sections before reading them. Read only what can affect the next decision, continue only relevant incomplete results using returned metadata, and avoid rereading unchanged content. Do not edit from an incomplete oversized-line preview. Obtain exact source with exec; if it still cannot fit, use a preconditioned deterministic replacement and verify the result.');
|
|
14
14
|
if (names.has('apply_patch'))
|
|
15
15
|
clauses.push('Prefer apply_patch for precise local edits. After a conflict, use the reported evidence to refresh only the affected context before retrying.');
|
|
16
16
|
if (names.has('apply_patch') || names.has('exec'))
|
|
@@ -22,7 +22,7 @@ export declare class CompactionOperation {
|
|
|
22
22
|
private report;
|
|
23
23
|
}
|
|
24
24
|
export declare const DEFAULT_COMPACTION_FOCUS = "Create a durable continuation state for the next model invocation.";
|
|
25
|
-
export declare function buildCompactionMessages(evidence: string): ModelMessage[];
|
|
25
|
+
export declare function buildCompactionMessages(evidence: string, highDensityCompaction?: boolean): ModelMessage[];
|
|
26
26
|
export declare function buildCompactionInput(messages: readonly ModelMessage[], input: {
|
|
27
27
|
focus?: string;
|
|
28
28
|
maxTokens: number;
|
package/dist/runtime/compact.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MarAgentError } from '../error.js';
|
|
2
2
|
import { countModelTokens, truncateModelText } from './token-budget.js';
|
|
3
|
-
import { compactionPrompt } from '../prompts/compact.js';
|
|
3
|
+
import { compactionPrompt, highDensityCompactionPrompt } from '../prompts/compact.js';
|
|
4
4
|
const COMPACTION_TIMEOUT_MS = 600_000;
|
|
5
5
|
const COMPACTION_PROGRESS_INTERVAL_MS = 30_000;
|
|
6
6
|
/** One deadline spans all model attempts and recovery waits for a single compaction. */
|
|
@@ -91,10 +91,13 @@ export class CompactionOperation {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
export const DEFAULT_COMPACTION_FOCUS = 'Create a durable continuation state for the next model invocation.';
|
|
94
|
-
export function buildCompactionMessages(evidence) {
|
|
94
|
+
export function buildCompactionMessages(evidence, highDensityCompaction = false) {
|
|
95
95
|
return [
|
|
96
96
|
{ role: 'user', content: evidence },
|
|
97
|
-
{
|
|
97
|
+
{
|
|
98
|
+
role: 'user',
|
|
99
|
+
content: highDensityCompaction ? highDensityCompactionPrompt() : compactionPrompt()
|
|
100
|
+
}
|
|
98
101
|
];
|
|
99
102
|
}
|
|
100
103
|
export function buildCompactionInput(messages, input) {
|
|
@@ -2,8 +2,12 @@ export declare const MODEL_TOKEN_ESTIMATOR: "UTF8_BYTES_V1";
|
|
|
2
2
|
/** Local budget estimate only; provider usage remains authoritative. */
|
|
3
3
|
export declare function countModelTokens(value: string): number;
|
|
4
4
|
export declare function modelTokenBudgetBytes(maximumTokens: number): number;
|
|
5
|
-
export declare function truncateModelText(value: string, maximumTokens: number, omittedLabel?: string
|
|
5
|
+
export declare function truncateModelText(value: string, maximumTokens: number, omittedLabel?: string, reported?: {
|
|
6
|
+
readonly originalTokenCount?: number;
|
|
7
|
+
readonly totalLines?: number;
|
|
8
|
+
}): {
|
|
6
9
|
content: string;
|
|
7
10
|
truncated: boolean;
|
|
8
11
|
omittedTokens: number;
|
|
9
12
|
};
|
|
13
|
+
export declare function countTextLines(value: string): number;
|
|
@@ -7,13 +7,13 @@ export function countModelTokens(value) {
|
|
|
7
7
|
export function modelTokenBudgetBytes(maximumTokens) {
|
|
8
8
|
return Math.max(0, Math.floor(maximumTokens)) * BYTES_PER_TOKEN;
|
|
9
9
|
}
|
|
10
|
-
export function truncateModelText(value, maximumTokens, omittedLabel = 'tool output') {
|
|
10
|
+
export function truncateModelText(value, maximumTokens, omittedLabel = 'tool output', reported) {
|
|
11
11
|
const tokens = countModelTokens(value);
|
|
12
12
|
if (tokens <= maximumTokens)
|
|
13
13
|
return { content: value, truncated: false, omittedTokens: 0 };
|
|
14
14
|
const maximumBytes = modelTokenBudgetBytes(maximumTokens);
|
|
15
15
|
const bytes = Buffer.from(value, 'utf8');
|
|
16
|
-
const warning = `Warning: truncated output (original token count: ${tokens})\nTotal output lines: ${
|
|
16
|
+
const warning = `Warning: truncated output (original token count: ${reported?.originalTokenCount ?? tokens})\nTotal output lines: ${reported?.totalLines ?? countTextLines(value)}\n\n`;
|
|
17
17
|
let retainedBytes = Math.max(0, maximumBytes - 16 * BYTES_PER_TOKEN);
|
|
18
18
|
for (let attempt = 0; attempt < 8; attempt++) {
|
|
19
19
|
let head = Math.ceil(retainedBytes / 2);
|
|
@@ -48,7 +48,7 @@ export function truncateModelText(value, maximumTokens, omittedLabel = 'tool out
|
|
|
48
48
|
omittedTokens: tokens
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
export function countTextLines(value) {
|
|
52
52
|
let lines = value.length === 0 ? 0 : 1;
|
|
53
53
|
for (let index = 0; index < value.length; index++)
|
|
54
54
|
if (value.charCodeAt(index) === 10)
|
package/dist/sdk/agent.js
CHANGED
|
@@ -12,7 +12,7 @@ import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
|
12
12
|
import { RolloutBudget, resolveRolloutBudgetOptions } from '../runtime/rollout-budget.js';
|
|
13
13
|
import { ContextGcRuntime } from '../runtime/context-gc-runtime.js';
|
|
14
14
|
import { buildContextProjection } from '../runtime/context-projection.js';
|
|
15
|
-
import { countModelTokens, truncateModelText } from '../runtime/token-budget.js';
|
|
15
|
+
import { countModelTokens, countTextLines, truncateModelText } from '../runtime/token-budget.js';
|
|
16
16
|
import { TOOL_EXECUTION_LIMITS } from '../tools/execution-limits.js';
|
|
17
17
|
import { DEFAULT_COMPACTION_FOCUS, CompactionOperation, buildCompactionInput, buildCompactionMessages, buildCompactedHistory, compactedHistoryMessages, continuationMessage } from '../runtime/compact.js';
|
|
18
18
|
import { buildSystemPrompt, MAR_AGENT_PROMPT_VERSION } from '../prompts/index.js';
|
|
@@ -486,6 +486,7 @@ export async function createMarAgent(options) {
|
|
|
486
486
|
}))
|
|
487
487
|
: [],
|
|
488
488
|
retainedSessionResources,
|
|
489
|
+
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
489
490
|
...(rolloutBudget?.active
|
|
490
491
|
? {
|
|
491
492
|
executionBudget: {
|
|
@@ -504,14 +505,14 @@ export async function createMarAgent(options) {
|
|
|
504
505
|
});
|
|
505
506
|
const initialSystemPrompt = buildExecutionSystemPrompt();
|
|
506
507
|
if (mode === 'compact') {
|
|
507
|
-
const compactOverheadTokens = estimatedRequestTokens(initialSystemPrompt, buildCompactionMessages(''), []);
|
|
508
|
+
const compactOverheadTokens = estimatedRequestTokens(initialSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), []);
|
|
508
509
|
const compactInputTokens = selectedModel.contextWindowTokens - compactOverheadTokens;
|
|
509
510
|
if (compactInputTokens <= 0)
|
|
510
511
|
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
511
512
|
messages.splice(0, messages.length, ...buildCompactionMessages(buildCompactionInput(messages, {
|
|
512
513
|
focus: input.prompt,
|
|
513
514
|
maxTokens: compactInputTokens
|
|
514
|
-
})));
|
|
515
|
+
}), selectedModel.highDensityCompaction));
|
|
515
516
|
}
|
|
516
517
|
await store.append(sessionId, {
|
|
517
518
|
type: 'execution.header',
|
|
@@ -539,9 +540,10 @@ export async function createMarAgent(options) {
|
|
|
539
540
|
platform: description.platform,
|
|
540
541
|
workspace: logicalWorkspace,
|
|
541
542
|
tools: [],
|
|
543
|
+
highDensityCompaction: selectedModel.highDensityCompaction,
|
|
542
544
|
extension: options.systemInstruction
|
|
543
545
|
});
|
|
544
|
-
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages(''), []);
|
|
546
|
+
const compactOverheadTokens = estimatedRequestTokens(compactSystemPrompt, buildCompactionMessages('', selectedModel.highDensityCompaction), []);
|
|
545
547
|
const compactInputTokens = Math.max(0, selectedModel.contextWindowTokens - compactOverheadTokens);
|
|
546
548
|
if (compactInputTokens === 0)
|
|
547
549
|
throw new MarAgentError('MAR_AGENT_CONTEXT_LIMIT', 'Compaction prompt exceeds the selected model context window.');
|
|
@@ -561,7 +563,7 @@ export async function createMarAgent(options) {
|
|
|
561
563
|
for await (const event of operation.start(selected, {
|
|
562
564
|
retryState: compactionRetryState,
|
|
563
565
|
system: compactSystemPrompt,
|
|
564
|
-
messages: buildCompactionMessages(compactSource),
|
|
566
|
+
messages: buildCompactionMessages(compactSource, selectedModel.highDensityCompaction),
|
|
565
567
|
tools: [],
|
|
566
568
|
allowTools: false,
|
|
567
569
|
promptCacheKey: sessionId,
|
|
@@ -930,7 +932,7 @@ export async function createMarAgent(options) {
|
|
|
930
932
|
}
|
|
931
933
|
})
|
|
932
934
|
});
|
|
933
|
-
const modelOutput = boundedModelToolOutput(output.content);
|
|
935
|
+
const modelOutput = boundedModelToolOutput(call.name, output.content, output.data);
|
|
934
936
|
const eventSummary = output.content.slice(0, AGENT_EXECUTION_POLICY.toolEventSummaryCharacters);
|
|
935
937
|
const structuredData = structuredToolEventData(call.name, output.data);
|
|
936
938
|
const artifacts = structuredToolArtifacts(call.name, output.artifacts);
|
|
@@ -1660,8 +1662,17 @@ function estimatedRequestTokens(system, messages, tools, images) {
|
|
|
1660
1662
|
return (countModelTokens(`${system}${stableJson(textMessages)}${stableJson(tools)}`) +
|
|
1661
1663
|
transientImageCount * AGENT_EXECUTION_POLICY.estimatedTokensPerImage);
|
|
1662
1664
|
}
|
|
1663
|
-
function boundedModelToolOutput(value) {
|
|
1664
|
-
const
|
|
1665
|
+
function boundedModelToolOutput(toolName, value, data) {
|
|
1666
|
+
const execDiagnostics = toolName === 'exec' &&
|
|
1667
|
+
isRecord(data) &&
|
|
1668
|
+
typeof data.stdout === 'string' &&
|
|
1669
|
+
typeof data.stderr === 'string'
|
|
1670
|
+
? {
|
|
1671
|
+
originalTokenCount: countModelTokens(data.stdout) + countModelTokens(data.stderr),
|
|
1672
|
+
totalLines: countTextLines(data.stdout) + countTextLines(data.stderr)
|
|
1673
|
+
}
|
|
1674
|
+
: undefined;
|
|
1675
|
+
const result = truncateModelText(value, AGENT_EXECUTION_POLICY.modelToolOutputTokens, 'tool output', execDiagnostics);
|
|
1665
1676
|
return { content: result.content, truncated: result.truncated };
|
|
1666
1677
|
}
|
|
1667
1678
|
function stableJson(value) {
|
|
@@ -208,6 +208,30 @@ function boundedUtf8Prefix(value, maximumBytes) {
|
|
|
208
208
|
}
|
|
209
209
|
return { value: `${result}${marker}`, truncated: true };
|
|
210
210
|
}
|
|
211
|
+
function oversizedLinePreview(value, retainedBytes, lineNumber) {
|
|
212
|
+
const bytes = Buffer.from(value, 'utf8');
|
|
213
|
+
if (retainedBytes >= bytes.length)
|
|
214
|
+
return { value, shownBytes: bytes.length, omittedBytes: 0 };
|
|
215
|
+
const headTarget = Math.floor(retainedBytes / 2);
|
|
216
|
+
const tailTarget = retainedBytes - headTarget;
|
|
217
|
+
let head = Math.min(headTarget, bytes.length);
|
|
218
|
+
while (head > 0 && isUtf8ContinuationByte(bytes[head]))
|
|
219
|
+
head--;
|
|
220
|
+
let tail = Math.max(head, bytes.length - tailTarget);
|
|
221
|
+
while (tail < bytes.length && isUtf8ContinuationByte(bytes[tail]))
|
|
222
|
+
tail++;
|
|
223
|
+
const shownBytes = head + bytes.length - tail;
|
|
224
|
+
const omittedBytes = bytes.length - shownBytes;
|
|
225
|
+
const marker = `...[${omittedBytes} bytes omitted from line ${lineNumber}]...`;
|
|
226
|
+
return {
|
|
227
|
+
value: `${bytes.toString('utf8', 0, head)}${marker}${bytes.toString('utf8', tail)}`,
|
|
228
|
+
shownBytes,
|
|
229
|
+
omittedBytes
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function isUtf8ContinuationByte(value) {
|
|
233
|
+
return value !== undefined && (value & 0xc0) === 0x80;
|
|
234
|
+
}
|
|
211
235
|
function formatBatchReadResult(result, index, maximumBytes) {
|
|
212
236
|
const visiblePath = boundedUtf8Prefix(result.path, 128);
|
|
213
237
|
const path = escapeAttribute(visiblePath.value);
|
|
@@ -265,8 +289,59 @@ function formatBatchReadResult(result, index, maximumBytes) {
|
|
|
265
289
|
high = middle - 1;
|
|
266
290
|
}
|
|
267
291
|
const content = render(low);
|
|
268
|
-
if (Buffer.byteLength(content) <= maximumBytes)
|
|
292
|
+
if (low > 0 && Buffer.byteLength(content) <= maximumBytes)
|
|
269
293
|
return { content, previewComplete: low === lines.length };
|
|
294
|
+
if (lines.length > 0) {
|
|
295
|
+
const lineNumber = result.startLine;
|
|
296
|
+
const prefix = `${lineNumber}\t`;
|
|
297
|
+
const formattedLine = lines[0];
|
|
298
|
+
const sourceLine = formattedLine.startsWith(prefix)
|
|
299
|
+
? formattedLine.slice(prefix.length)
|
|
300
|
+
: formattedLine;
|
|
301
|
+
const sourceLineBytes = Buffer.byteLength(sourceLine);
|
|
302
|
+
const renderOversizedLine = (retainedBytes) => {
|
|
303
|
+
const preview = oversizedLinePreview(sourceLine, retainedBytes, lineNumber);
|
|
304
|
+
const metadata = {
|
|
305
|
+
path: visiblePath.value,
|
|
306
|
+
...(visiblePath.truncated ? { pathTruncated: true } : {}),
|
|
307
|
+
encoding: result.encoding,
|
|
308
|
+
newline: result.newline,
|
|
309
|
+
startLine: lineNumber,
|
|
310
|
+
endLine: lineNumber,
|
|
311
|
+
eof: false,
|
|
312
|
+
truncated: true,
|
|
313
|
+
previewComplete: false,
|
|
314
|
+
oversizedLine: {
|
|
315
|
+
line: lineNumber,
|
|
316
|
+
bytes: sourceLineBytes,
|
|
317
|
+
shownBytes: preview.shownBytes,
|
|
318
|
+
omittedBytes: preview.omittedBytes
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
return [
|
|
322
|
+
`<read_result index="${index}" path="${path}"${pathTruncatedAttribute}>`,
|
|
323
|
+
`${prefix}${preview.value}`,
|
|
324
|
+
`<read_metadata>${JSON.stringify(metadata)}</read_metadata>`,
|
|
325
|
+
'</read_result>'
|
|
326
|
+
].join('\n');
|
|
327
|
+
};
|
|
328
|
+
let minimum = renderOversizedLine(0);
|
|
329
|
+
if (Buffer.byteLength(minimum) <= maximumBytes) {
|
|
330
|
+
let retainedLow = 0;
|
|
331
|
+
let retainedHigh = sourceLineBytes;
|
|
332
|
+
while (retainedLow < retainedHigh) {
|
|
333
|
+
const middle = Math.ceil((retainedLow + retainedHigh) / 2);
|
|
334
|
+
const candidate = renderOversizedLine(middle);
|
|
335
|
+
if (Buffer.byteLength(candidate) <= maximumBytes) {
|
|
336
|
+
retainedLow = middle;
|
|
337
|
+
minimum = candidate;
|
|
338
|
+
}
|
|
339
|
+
else
|
|
340
|
+
retainedHigh = middle - 1;
|
|
341
|
+
}
|
|
342
|
+
return { content: minimum, previewComplete: false };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
270
345
|
return {
|
|
271
346
|
content: `<read_error index="${index}" code="MAR_AGENT_TOOL_OUTPUT_LIMIT">Model-visible read metadata exceeds this item's output share.</read_error>`,
|
|
272
347
|
previewComplete: false
|
package/dist/tools/read.js
CHANGED
|
@@ -46,7 +46,7 @@ export const readToolDefinition = {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
|
-
description: `Read one or more known text files/ranges. Strict UTF-8 with optional BOM is the default; BOM-declared UTF-16LE/UTF-16BE is supported. Invalid text returns an item error instead of replacement characters. Always pass reads; use one item for a single file and up to ${TOOL_EXECUTION_LIMITS.readMaxBatchItems} items for a batch. Batch only already-located, bounded ranges whose combined content is likely to fit the model-visible output budget; for exploration, locate relevant files, symbols, or headings first, then read the smallest useful ranges. Results retain input order, use 1-based line numbers, and include <read_metadata> with path, encoding, newline, exact visible range, eof, truncation, nextOffset, and whether previewComplete. Items fail independently and run with bounded concurrency. Each item returns at most ${TOOL_EXECUTION_LIMITS.readMaxLines} lines/${TOOL_EXECUTION_LIMITS.readMaxBytes} bytes; the structured call shares a ${TOOL_EXECUTION_LIMITS.readMaxBatchBytes}-byte budget, while ordinary model-visible content fairly shares the common tool-output budget across all items. Structured data.results items provide text as decoded source for the returned range, preserving line endings and excluding BOM; content is numbered display text. Large files support bounded range reads. If previewComplete is false, continue only the still-relevant item from nextOffset. Relative paths use the workspace; absolute paths are allowed. Prefer exec with rg for search and read for known files.`,
|
|
49
|
+
description: `Read one or more known text files/ranges. Strict UTF-8 with optional BOM is the default; BOM-declared UTF-16LE/UTF-16BE is supported. Invalid text returns an item error instead of replacement characters. Always pass reads; use one item for a single file and up to ${TOOL_EXECUTION_LIMITS.readMaxBatchItems} items for a batch. Batch only already-located, bounded ranges whose combined content is likely to fit the model-visible output budget; for exploration, locate relevant files, symbols, or headings first, then read the smallest useful ranges. Results retain input order, use 1-based line numbers, and include <read_metadata> with path, encoding, newline, exact visible range, eof, truncation, nextOffset, and whether previewComplete. Items fail independently and run with bounded concurrency. Each item returns at most ${TOOL_EXECUTION_LIMITS.readMaxLines} lines/${TOOL_EXECUTION_LIMITS.readMaxBytes} bytes; the structured call shares a ${TOOL_EXECUTION_LIMITS.readMaxBatchBytes}-byte budget, while ordinary model-visible content fairly shares the common tool-output budget across all items. Structured data.results items provide text as decoded source for the returned range, preserving line endings and excluding BOM; content is numbered display text. Large files support bounded range reads. If previewComplete is false and nextOffset is present, continue only the still-relevant item from nextOffset. An oversized single line instead returns a head/tail preview with no line continuation cursor; use exec to obtain exact source before editing omitted content. Relative paths use the workspace; absolute paths are allowed. Prefer exec with rg for search and read for known files.`,
|
|
50
50
|
inputSchema: {
|
|
51
51
|
type: 'object',
|
|
52
52
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myagentroam/agent",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.76",
|
|
4
4
|
"description": "Embeddable MAR coding agent SDK and CLI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"build": "node ../scripts/clean-build-output.mjs dist && tsc -p tsconfig.json",
|
|
39
39
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
40
|
"test:unit": "vitest run --config vitest.config.ts test/unit",
|
|
41
|
+
"benchmark:compaction": "node test/e2e/compaction-benchmark.mjs",
|
|
41
42
|
"test:performance": "vitest run --config vitest.performance.config.ts",
|
|
42
43
|
"test:memory": "node --expose-gc ./node_modules/vitest/vitest.mjs run --config vitest.memory.config.ts",
|
|
43
44
|
"test:e2e": "vitest run --config vitest.config.ts test/e2e --no-file-parallelism",
|