Skip to content

Commit 258adde

Browse files
authored
feat: sync reviewed 0.5.5 runtime improvements (MiniMax-AI#367)
Preserve public privacy defaults and distribution boundaries while porting compaction, Bash timeout, memory output and update-proxy improvements. Record selective provenance without advancing the full source baseline. Assisted-by: codex-cli reason:public-source-sync-0.5.5
1 parent 4198174 commit 258adde

40 files changed

Lines changed: 7317 additions & 138 deletions

‎docs/source-sync-0.5.5.md‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Reviewed source update for 0.5.5
2+
3+
This update ports the public-compatible 0.5.5 behavior from source revision
4+
`d28ae33c08a907f5e1ef17d70725eea0d0c667a0` onto the existing public distribution.
5+
It preserves public fixes and distribution adaptations rather than replacing the
6+
repository with a product build's source tree.
7+
8+
## Included behavior
9+
10+
- Managed foreground Bash defaults to a one-hour total timeout and caps larger
11+
requests at one hour. The 60-second foreground yield preserves the running
12+
process and its original deadline. Explicit background tasks use a one-hour
13+
runtime watchdog by default; explicit command timeouts remain separate.
14+
- Automatic context compaction reserves output space before reaching the context
15+
limit. Checkpoint output scales with the model window; reasoning-only output
16+
exhaustion advances to a smaller candidate. Provider errors get one bounded
17+
logical retry. Automatic failures retain the original history; valid manual
18+
checkpoints are committed even when a local next-request estimate rejects them.
19+
- Update downloads reuse the TUI's proxy and loopback-bypass policy and load
20+
their network dependency lazily. Existing public installation ownership and
21+
registry selection remain intact.
22+
- Memory-tool results have a 16 KiB model-facing limit with a head/tail preview
23+
and guidance for reading more. This does not upload memory or change its storage.
24+
25+
The root and TUI source versions are 0.5.5. This source update does not republish
26+
the existing npm package or move an existing release tag.
27+
28+
## Privacy and publication decisions
29+
30+
| Surface | Decision |
31+
| --- | --- |
32+
| Usage, metrics and diagnostics | Keep the public independent opt-ins, disabled defaults, and `DO_NOT_TRACK` / `MCODE_DISABLE_TELEMETRY` overrides. |
33+
| Evaluation capture and data contribution | Do not import automatic capture wiring, evaluation payload/transport expansions, or default-enabled contribution behavior. |
34+
| Workspace collection and indexing | Keep snapshot collection, archive creation, background upload/retry and semantic-index activation excluded. |
35+
| Feedback and automatic error reports | Keep the public reviewed-text/count-only feedback projection and allowlisted diagnostic schemas; no raw conversations, tool output or workspace files. |
36+
| Compaction observations | Import only local content-free count/budget/outcome facts; preserve the existing public telemetry consent boundary. |
37+
| Managed account, BYOK, plugins, connectors, search and user-requested deployments | Preserve supported public clients and behavior. No private endpoints, generated service contracts or new cloud authorization dependencies are introduced. |
38+
39+
The reviewed update is selective. The older `release/extraction.json`
40+
`sourceRevision` remains the base for future three-way comparisons: changing it
41+
would incorrectly mark the remaining runtime ownership migrations, service
42+
integrations and source-tree moves as synchronized. Those changes need their own
43+
public dependency and privacy review. Private candidate reports remain outside
44+
this repository and are not publication artifacts.
45+
46+
## Validation boundary
47+
48+
Imported tests exercise compaction failure/recovery, budget boundaries and real
49+
Bash execution using synthetic data. Public privacy tests inspect the outgoing
50+
telemetry/diagnostic data, including the final feedback archive. The repository's
51+
full verifier additionally checks source export, types, build boundaries, TUI,
52+
headless BYOK, ACP, permissions and platform-applicable sandbox behavior.
53+
54+
Offline tests are not evidence of live-service ingestion, model quality or
55+
Windows/Linux runtime acceptance. Actual check results belong in the pull
56+
request's validation record.

‎docs/source-sync.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ Output includes `report.json`, `candidates/`, and `.private-review`. Candidates
2424
5. Scan complete history and current source before creating the public PR. Include public changes, validation results, and capability descriptions, never private review reports.
2525

2626
After accepted public changes are ported back, subsequent three-way comparisons should show them as synchronized or cleanly mergeable while retaining standalone adaptations. Synchronization is not a blind overwrite: conflicts, missing source, and new files require maintainer judgment.
27+
28+
## Selective release updates
29+
30+
A bounded release update can port reviewed behavior without adopting unrelated
31+
runtime ownership migrations or private service integrations. Keep the existing
32+
three-way baseline until the entire target revision has been reviewed; record
33+
the selected revision, included behavior and excluded boundaries separately.
34+
See the [0.5.5 review](source-sync-0.5.5.md) for the current selective update.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "minimax-code",
3-
"version": "0.5.4",
3+
"version": "0.5.5",
44
"private": true,
55
"type": "module",
66
"description": "Standalone MiniMax Code TUI with managed accounts, BYOK models, cloud tools, plugins and ACP.",

‎packages/agent-modules/context-manager/src/provider-budget.ts‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { DEFAULT_CONTEXT_MANAGER_SETTINGS } from './settings.js';
22

33
const PROVIDER_INPUT_RATIO = 0.95;
4+
/** Integer percent keeps the trigger exact (0.95 is not exact in binary floating point). */
5+
const AUTOMATIC_TRIGGER_PERCENT = 95;
46

57
export function resolveDynamicMaxTokens(input: {
68
readonly contextWindow: number;
@@ -20,9 +22,13 @@ export function resolveCompactionTokenBudget(input: {
2022
}): { readonly providerInputLimit: number; readonly automaticTriggerAt: number } {
2123
const configuredOutput = positive(input.configuredMaxOutputTokens);
2224
const { reserveTokens, safetyMarginTokens } = DEFAULT_CONTEXT_MANAGER_SETTINGS;
23-
const fullOutputInputBudget = input.contextWindow - configuredOutput - safetyMarginTokens;
24-
const effectiveOutput =
25-
fullOutputInputBudget >= reserveTokens ? configuredOutput : outputFloor(configuredOutput);
25+
// Admission mirrors resolveDynamicMaxTokens: a real Provider request shrinks
26+
// its output budget down to the dynamic floor when input is large, so the
27+
// hard input limit reserves the floor instead of the full configured output.
28+
// Reserving the full output here rejects requests the Provider would accept
29+
// (e.g. 200K-window models with 128K configured output collapsed the input
30+
// budget to ~70K and wedged sessions whose fixed prompt exceeded it).
31+
const effectiveOutput = outputFloor(configuredOutput);
2632
const providerInputLimit = Math.max(
2733
1,
2834
Math.min(
@@ -31,13 +37,18 @@ export function resolveCompactionTokenBudget(input: {
3137
input.contextWindow - effectiveOutput - safetyMarginTokens,
3238
),
3339
);
34-
const proactiveReserve = Math.min(reserveTokens * 2, Math.floor(input.contextWindow / 4));
40+
// The automatic trigger reserves the configured output, capped at a quarter
41+
// of the window, and compacts at 95% of the remainder. Large windows then
42+
// start compaction while the main and checkpoint requests still have their
43+
// configured output room; small windows are not collapsed by a large output
44+
// limit. providerInputLimit stays the upper bound.
45+
const outputReserve = Math.min(configuredOutput, Math.floor(input.contextWindow / 4));
46+
const outputReservedTrigger = Math.floor(
47+
((input.contextWindow - outputReserve) * AUTOMATIC_TRIGGER_PERCENT) / 100,
48+
);
3549
return {
3650
providerInputLimit,
37-
automaticTriggerAt: Math.min(
38-
providerInputLimit,
39-
Math.max(1, input.contextWindow - proactiveReserve),
40-
),
51+
automaticTriggerAt: Math.min(providerInputLimit, Math.max(1, outputReservedTrigger)),
4152
};
4253
}
4354

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import {
4+
resolveCompactionTokenBudget,
5+
resolveDynamicMaxTokens,
6+
} from '../src/provider-budget.js';
7+
8+
describe('resolveDynamicMaxTokens', () => {
9+
it('shrinks a Spark output budget from the complete Provider input footprint', () => {
10+
expect(
11+
resolveDynamicMaxTokens({
12+
contextWindow: 128_000,
13+
configuredMaxTokens: 128_000,
14+
estimatedContextTokens: 100_000,
15+
}),
16+
).toBe(25_952);
17+
});
18+
});
19+
20+
describe('resolveCompactionTokenBudget', () => {
21+
it.each([
22+
[200_000, 181_568],
23+
[400_000, 380_000],
24+
[512_000, 486_400],
25+
[1_000_000, 950_000],
26+
] as const)('caps a %i-token context at the conservative Provider limit', (contextWindow, expected) => {
27+
expect(
28+
resolveCompactionTokenBudget({
29+
contextWindow,
30+
configuredMaxOutputTokens: 16_384,
31+
}).providerInputLimit,
32+
).toBe(expected);
33+
});
34+
35+
it.each([
36+
['1M context', 1_000_000, 128_000, 950_000, 828_400],
37+
['512K context', 512_000, 128_000, 486_400, 364_800],
38+
['roomy 400K context', 400_000, 128_000, 380_000, 285_000],
39+
['gpt-5.4 output floor', 272_000, 128_000, 253_568, 193_800],
40+
['MiniMax-M2.7 window', 200_000, 128_000, 181_568, 142_500],
41+
['256K relay window', 256_000, 128_000, 237_568, 182_400],
42+
['Spark dynamic fallback', 128_000, 128_000, 109_568, 91_200],
43+
['1M context with a small output limit', 1_000_000, 32_000, 950_000, 919_600],
44+
['64K context capped by the hard limit', 64_000, 128_000, 45_568, 45_568],
45+
['caller-limited output', 65_536, 8_192, 49_152, 49_152],
46+
] as const)(
47+
'resolves the shared input limit and automatic trigger for %s',
48+
(_case, contextWindow, configuredMaxOutputTokens, providerInputLimit, automaticTriggerAt) => {
49+
expect(
50+
resolveCompactionTokenBudget({ contextWindow, configuredMaxOutputTokens }),
51+
).toEqual({ providerInputLimit, automaticTriggerAt });
52+
},
53+
);
54+
55+
it.each([
56+
['65K context', 65_536, 46_694],
57+
['Spark', 128_000, 106_035],
58+
['large context', 272_000, 242_835],
59+
] as const)(
60+
'reserves a small configured output below the window-quarter cap for %s',
61+
(_case, contextWindow, automaticTriggerAt) => {
62+
expect(
63+
resolveCompactionTokenBudget({
64+
contextWindow,
65+
configuredMaxOutputTokens: 16_384,
66+
}).automaticTriggerAt,
67+
).toBe(automaticTriggerAt);
68+
},
69+
);
70+
71+
it('leaves the configured output room when a large window reaches the trigger', () => {
72+
const contextWindow = 1_000_000;
73+
const configuredMaxTokens = 128_000;
74+
const { automaticTriggerAt } = resolveCompactionTokenBudget({
75+
contextWindow,
76+
configuredMaxOutputTokens: configuredMaxTokens,
77+
});
78+
79+
expect(
80+
resolveDynamicMaxTokens({
81+
contextWindow,
82+
configuredMaxTokens,
83+
estimatedContextTokens: automaticTriggerAt,
84+
}),
85+
).toBe(configuredMaxTokens);
86+
});
87+
88+
it.each([Number.NaN, 0])('ignores an invalid configured output limit: %s', (configuredMaxOutputTokens) => {
89+
expect(
90+
resolveCompactionTokenBudget({
91+
contextWindow: 65_536,
92+
configuredMaxOutputTokens,
93+
}).providerInputLimit,
94+
).toBe(49_152);
95+
});
96+
97+
it('clamps an invalidly small context to one token', () => {
98+
expect(
99+
resolveCompactionTokenBudget({
100+
contextWindow: 1,
101+
configuredMaxOutputTokens: 128_000,
102+
}),
103+
).toEqual({ providerInputLimit: 1, automaticTriggerAt: 1 });
104+
});
105+
});

‎packages/agent-tools/src/desktop/builtin-defs.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,13 @@ export const LocalBashToolDef = {
129129
Type.Number({
130130
exclusiveMinimum: 0,
131131
description:
132-
'Total command timeout in seconds. Foreground-only: default 120s, max 300s. Foreground with automatic backgrounding: default/max 600s, including foreground time. Explicit background: uses the specified timeout, or a 30-minute limit if omitted.',
132+
'Total command timeout in seconds. Foreground-only: default 120s, max 300s. Foreground with automatic backgrounding: default/max 3600s total, including foreground time. Explicit background: uses the specified timeout, or a 1-hour runtime limit if omitted. Backgrounding does not reset the timeout.',
133133
}),
134134
),
135135
run_in_background: Type.Optional(
136136
Type.Boolean({
137-
description: 'Set to true to run this command in the background.',
137+
description:
138+
'Start in the background and return a task id immediately. Foreground commands may also return a task id after 60s without restarting the process.',
138139
}),
139140
),
140141
}),

‎packages/agent-tools/src/desktop/local-bash-contract.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function createLocalBashToolDefinition(
3030
const base = Clone(LocalBashToolDef.schema);
3131
const schema = capabilities.background ? base : Type.Omit(base, ['run_in_background']);
3232
schema.properties.timeout.description = capabilities.background
33-
? `Total command timeout in seconds. Foreground with automatic backgrounding: default/max ${MAX_MANAGED_BASH_TIMEOUT_SECONDS}s, including foreground time. Explicit background: uses the specified timeout, or a 30-minute limit if omitted.`
33+
? `Total command timeout in seconds. Foreground with automatic backgrounding: default/max ${MAX_MANAGED_BASH_TIMEOUT_SECONDS}s, including foreground time. Explicit background: uses the specified timeout, or a 1-hour runtime limit if omitted.`
3434
: `Timeout in seconds. Foreground: default ${DEFAULT_FOREGROUND_BASH_TIMEOUT_SECONDS}s; values above ${MAX_FOREGROUND_BASH_TIMEOUT_SECONDS}s are capped.`;
3535
return {
3636
...LocalBashToolDef,

‎packages/agent-tools/src/desktop/local-bash-timing.ts‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { ToolResult } from '@mavis/agent-core/tools';
22

33
export const DEFAULT_FOREGROUND_BASH_TIMEOUT_SECONDS = 120;
44
export const MAX_FOREGROUND_BASH_TIMEOUT_SECONDS = 300;
5-
export const MAX_MANAGED_BASH_TIMEOUT_SECONDS = 600;
5+
export const MAX_MANAGED_BASH_TIMEOUT_SECONDS = 3_600;
66
export const MAX_BASH_TIMEOUT_SECONDS = 2_147_483;
77
export const DEFAULT_FOREGROUND_BASH_SOFT_YIELD_MS = 60_000;
88

@@ -17,27 +17,38 @@ export function resolveLocalBashTiming(
1717
timeout: number | undefined,
1818
mode: 'direct_foreground' | 'managed_foreground' | 'explicit_background',
1919
): LocalBashTiming {
20-
if (
20+
const normalizedTimeout =
21+
mode === 'managed_foreground' &&
2122
timeout !== undefined &&
22-
(!Number.isFinite(timeout) || timeout <= 0 || timeout > MAX_BASH_TIMEOUT_SECONDS)
23+
(!Number.isFinite(timeout) || timeout <= 0)
24+
? undefined
25+
: timeout;
26+
if (
27+
normalizedTimeout !== undefined &&
28+
(!Number.isFinite(normalizedTimeout) ||
29+
normalizedTimeout <= 0 ||
30+
(mode !== 'managed_foreground' && normalizedTimeout > MAX_BASH_TIMEOUT_SECONDS))
2331
) {
2432
throw new Error(
2533
`timeout must be a finite positive number of seconds, at most ${MAX_BASH_TIMEOUT_SECONDS}.`,
2634
);
2735
}
2836
const commandTimeoutSeconds =
2937
mode === 'explicit_background'
30-
? timeout
38+
? normalizedTimeout
3139
: mode === 'managed_foreground'
32-
? Math.min(timeout ?? MAX_MANAGED_BASH_TIMEOUT_SECONDS, MAX_MANAGED_BASH_TIMEOUT_SECONDS)
40+
? Math.min(
41+
normalizedTimeout ?? MAX_MANAGED_BASH_TIMEOUT_SECONDS,
42+
MAX_MANAGED_BASH_TIMEOUT_SECONDS,
43+
)
3344
: Math.min(
34-
timeout ?? DEFAULT_FOREGROUND_BASH_TIMEOUT_SECONDS,
45+
normalizedTimeout ?? DEFAULT_FOREGROUND_BASH_TIMEOUT_SECONDS,
3546
MAX_FOREGROUND_BASH_TIMEOUT_SECONDS,
3647
);
3748
return {
3849
commandTimeoutSeconds,
39-
...(timeout !== undefined && timeout !== commandTimeoutSeconds
40-
? { requestedTimeoutSeconds: timeout }
50+
...(normalizedTimeout !== undefined && normalizedTimeout !== commandTimeoutSeconds
51+
? { requestedTimeoutSeconds: normalizedTimeout }
4152
: {}),
4253
};
4354
}

‎packages/agent-tools/src/desktop/local-memory.ts‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { bindTool, type ToolImpl, type ToolResult } from '@mavis/agent-core/tools';
2+
import { MEMORY_TOOL_OUTPUT_MAX_BYTES } from '@mavis/shared/memory-limits';
23

34
import { LocalMemoryToolDef, type LocalMemoryToolInput } from './builtin-defs.js';
5+
import {
6+
applyDesktopTextLimit,
7+
limitDesktopHeadTailLines,
8+
} from './output-limit.js';
49
import type { LocalMemoryAdapter, LocalRuntimeToolContext } from './types.js';
510

611
@bindTool(LocalMemoryToolDef)
@@ -17,11 +22,19 @@ export class LocalMemoryTool implements ToolImpl<
1722
): Promise<ToolResult> {
1823
if (signal?.aborted) throw new Error('Operation aborted');
1924
const result = await this.adapter.execute(ctx, input, signal);
20-
return {
25+
const toolResult: ToolResult = {
2126
tool_name: LocalMemoryToolDef.name,
2227
text: result.text,
2328
content: [{ type: 'text', text: result.text }],
2429
details: { kind: 'memory', ...(result.details ?? {}) },
2530
};
31+
return applyDesktopTextLimit(
32+
toolResult,
33+
limitDesktopHeadTailLines(result.text, {
34+
maxBytes: MEMORY_TOOL_OUTPUT_MAX_BYTES,
35+
notice: () =>
36+
'[Memory output truncated. Narrow the memory search query or use the read tool with a file path and offset/limit to inspect more.]',
37+
}),
38+
);
2639
}
2740
}

‎packages/agent-tools/src/desktop/local-pi-tools.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ export class LocalBashTool implements ToolImpl<
456456
workspaceRoot: this.workspaceRoot,
457457
runtime: this.hostTrashRuntime,
458458
envPolicy: this.envPolicy,
459-
timeoutSeconds: resolveForegroundTimeout(input),
459+
timeoutSeconds: resolveForegroundTimeout({ timeout: timing.commandTimeoutSeconds }),
460460
...(signal ? { signal } : {}),
461461
});
462462
if (hostTrashResult) {
@@ -505,7 +505,7 @@ export class LocalBashTool implements ToolImpl<
505505
) {
506506
const managed = await this.backgroundAdapter.runManagedForeground(
507507
ctx,
508-
rest,
508+
foregroundInput,
509509
DEFAULT_FOREGROUND_BASH_SOFT_YIELD_MS,
510510
signal,
511511
);

0 commit comments

Comments
 (0)