@parall/claude-agent 1.58.0 → 1.58.2

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.
@@ -10,6 +10,8 @@ type ClaudeCodeAdapterOptions = Pick<ClaudeAgentConfig, 'additionalDirs' | 'allo
10
10
  orgId: string;
11
11
  /** Catalog context size for the selected model. */
12
12
  contextWindow?: number;
13
+ /** Catalog max output tokens for the selected model (input-budget subtrahend). */
14
+ maxTokens?: number;
13
15
  contextFilePathForSession?: (sessionKey: string) => string;
14
16
  /** @deprecated Use contextFilePathForSession. */
15
17
  stepIdFilePathForSession?: (sessionKey: string) => string;
@@ -41,6 +43,7 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
41
43
  private _model;
42
44
  private _effortLevel;
43
45
  private _contextWindow;
46
+ private _maxTokens;
44
47
  constructor(opts: ClaudeCodeAdapterOptions);
45
48
  get currentModel(): string | undefined;
46
49
  get currentEffort(): string | undefined;
@@ -48,6 +51,7 @@ export declare class ClaudeCodeAdapter implements DispatchAdapter {
48
51
  model?: string | null;
49
52
  effort?: string | null;
50
53
  contextWindow?: number | null;
54
+ maxTokens?: number | null;
51
55
  }): void;
52
56
  requestProcessRestart(): void;
53
57
  enqueueDuringDispatch(sessionKey: string, body: string, inputLifecycle?: DispatchInputLifecycle): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"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"}
package/dist/dispatch.js CHANGED
@@ -36,10 +36,12 @@ export class ClaudeCodeAdapter {
36
36
  _model;
37
37
  _effortLevel;
38
38
  _contextWindow;
39
+ _maxTokens;
39
40
  constructor(opts) {
40
41
  this.opts = opts;
41
42
  this._model = opts.model;
42
43
  this._contextWindow = opts.contextWindow;
44
+ this._maxTokens = opts.maxTokens;
43
45
  }
44
46
  get currentModel() {
45
47
  return this._model;
@@ -51,13 +53,16 @@ export class ClaudeCodeAdapter {
51
53
  const modelChanged = config.model !== undefined && config.model !== this._model;
52
54
  const effortChanged = config.effort !== undefined && config.effort !== this._effortLevel;
53
55
  const contextWindowChanged = config.contextWindow !== undefined && config.contextWindow !== this._contextWindow;
56
+ const maxTokensChanged = config.maxTokens !== undefined && config.maxTokens !== this._maxTokens;
54
57
  if (modelChanged)
55
58
  this._model = config.model ?? undefined;
56
59
  if (effortChanged)
57
60
  this._effortLevel = config.effort ?? undefined;
58
61
  if (contextWindowChanged)
59
62
  this._contextWindow = config.contextWindow ?? undefined;
60
- if (modelChanged || effortChanged || contextWindowChanged) {
63
+ if (maxTokensChanged)
64
+ this._maxTokens = config.maxTokens ?? undefined;
65
+ if (modelChanged || effortChanged || contextWindowChanged || maxTokensChanged) {
61
66
  this.requestProcessRestart();
62
67
  }
63
68
  }
@@ -513,11 +518,12 @@ export class ClaudeCodeAdapter {
513
518
  const env = buildSpawnEnv(process.env, this.opts.claudeHome, this.buildPlaceholderContext(sessionKey), {
514
519
  allowApiKey: this.opts.allowApiKey,
515
520
  contextWindow: this._contextWindow,
521
+ maxTokens: this._maxTokens,
516
522
  effortLevel: this._effortLevel,
517
523
  wikiMountRoot: this.opts.workspaceDir,
518
524
  capabilityBinDir: this.opts.capabilityBinDir,
519
525
  });
520
- log?.info(`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || 'default'}, context=${this._contextWindow || 'cli-default'}, effort=${this._effortLevel || 'default'}, mode=${this.opts.permissionMode})`);
526
+ log?.info(`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || 'default'}, context=${this._contextWindow || 'cli-default'}, maxOut=${this._maxTokens || 'cli-default'}, effort=${this._effortLevel || 'default'}, mode=${this.opts.permissionMode})`);
521
527
  const proc = spawn(IS_WIN32 ? quoteWin32Arg(this.opts.claudeBin) : this.opts.claudeBin, IS_WIN32 ? args.map(quoteWin32Arg) : args, {
522
528
  cwd: this.opts.workspaceDir,
523
529
  env,
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import * as os from 'node:os';
3
- import { capabilityBinDir, childLogger, clearAllProviderCreds, configureHttpKeepAlive, createLogger, createOtelLogger, createPlatformConfigManager, deriveModelIsPin, identityFromMe, initAgentTelemetry, llmSource, materializeChannelCapabilities, ParallAgentGateway, parseDispatchDeadlineMs, parseForkDeadlineMs, parseProviderConfig, parseShutdownDeadlineMs, resolveRuntimeContextWindow, resolveRuntimeModel, } from '@parall/agent-core';
3
+ import { capabilityBinDir, childLogger, clearAllProviderCreds, configureHttpKeepAlive, createLogger, createOtelLogger, createPlatformConfigManager, deriveModelIsPin, identityFromMe, initAgentTelemetry, llmSource, materializeChannelCapabilities, ParallAgentGateway, parseDispatchDeadlineMs, parseForkDeadlineMs, parseProviderConfig, parseShutdownDeadlineMs, resolveRuntimeContextWindow, resolveRuntimeMaxTokens, resolveRuntimeModel, } from '@parall/agent-core';
4
4
  import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
5
5
  import { buildClaudeRuntimeKey, contextFilePathForSession, dispatchContextDirPath, resolveClaudeAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from './config.js';
6
6
  import { ClaudeCodeAdapter } from './dispatch.js';
@@ -113,6 +113,7 @@ async function main() {
113
113
  const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
114
114
  const resolvedModel = resolveRuntimeModel(platformModelOverride, platformDefaults.model, config.model);
115
115
  const resolvedContextWindow = resolveRuntimeContextWindow(resolvedModel, platformDefaults, activeLLMSource);
116
+ const resolvedMaxTokens = resolveRuntimeMaxTokens(resolvedModel, platformDefaults, activeLLMSource);
116
117
  const resolvedEffort = platformDefaults.thinkingEffort ??
117
118
  (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
118
119
  if (platformDefaults.model)
@@ -121,12 +122,15 @@ async function main() {
121
122
  agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}`);
122
123
  if (resolvedContextWindow)
123
124
  agentLog.info(`platform config: context_window=${resolvedContextWindow}`);
125
+ if (resolvedMaxTokens)
126
+ agentLog.info(`platform config: max_tokens=${resolvedMaxTokens}`);
124
127
  const adapter = new ClaudeCodeAdapter({
125
128
  claudeBin: config.claudeBin,
126
129
  claudeHome: config.claudeHome,
127
130
  workspaceDir: config.workspaceDir,
128
131
  model: resolvedModel,
129
132
  contextWindow: resolvedContextWindow,
133
+ maxTokens: resolvedMaxTokens,
130
134
  permissionMode: config.permissionMode,
131
135
  allowedTools: config.allowedTools,
132
136
  disallowedTools: config.disallowedTools,
@@ -179,6 +183,7 @@ async function main() {
179
183
  adapter.updateConfig({
180
184
  model,
181
185
  contextWindow: resolveRuntimeContextWindow(model, updated, activeLLMSource) ?? null,
186
+ maxTokens: resolveRuntimeMaxTokens(model, updated, activeLLMSource) ?? null,
182
187
  effort: updated.thinkingEffort ?? localEffort,
183
188
  });
184
189
  // Channel capabilities heat-update with the config: re-materialize the
@@ -2,6 +2,7 @@ import type { DispatchOpts } from '@parall/agent-core';
2
2
  export declare function buildSpawnEnv(parentEnv: NodeJS.ProcessEnv, claudeHome: string, context: DispatchOpts['context'], opts: {
3
3
  allowApiKey: boolean;
4
4
  contextWindow?: number;
5
+ maxTokens?: number;
5
6
  effortLevel?: string;
6
7
  wikiMountRoot?: string;
7
8
  capabilityBinDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"spawn-env.d.ts","sourceRoot":"","sources":["../src/spawn-env.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,CAAC,UAAU,EAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,EAChC,IAAI,EAAE;IACJ,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GACA,MAAM,CAAC,UAAU,CA8DnB"}
1
+ {"version":3,"file":"spawn-env.d.ts","sourceRoot":"","sources":["../src/spawn-env.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,CAAC,UAAU,EAC5B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,EAChC,IAAI,EAAE;IACJ,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GACA,MAAM,CAAC,UAAU,CAiFnB"}
package/dist/spawn-env.js CHANGED
@@ -35,10 +35,27 @@ export function buildSpawnEnv(parentEnv, claudeHome, context, opts) {
35
35
  if (typeof opts.contextWindow === 'number' &&
36
36
  Number.isSafeInteger(opts.contextWindow) &&
37
37
  opts.contextWindow > 0) {
38
- // Claude Code otherwise assumes 200k for an unrecognized model ID. Its
39
- // own auto-compaction policy reserves the output buffer before this
40
- // declared boundary; Parall supplies the model fact, not a second ratio.
41
- result.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(opts.contextWindow);
38
+ // Claude Code otherwise assumes 200k for an unrecognized model ID.
39
+ //
40
+ // Declared as the model's INPUT budget (context_window - max_tokens; both
41
+ // raw catalog facts), not the full window. The upstream validates
42
+ // input + max_tokens <= context_window, while the CLI requests up to its
43
+ // own output default (32k) yet reserves at most 20k below this declared
44
+ // boundary before auto-compacting (2.1.251) — so a session declared the
45
+ // full window can grow into a band the provider already rejects but the
46
+ // CLI still considers legal: it retries forever, auto-compact never
47
+ // fires, and once past the boundary the compaction call itself is
48
+ // over-limit (the ParallSRE 08-31 lockup). Subtracting the catalog
49
+ // max_tokens keeps the compaction trigger strictly inside what the
50
+ // provider accepts.
51
+ let inputBudget = opts.contextWindow;
52
+ if (typeof opts.maxTokens === 'number' &&
53
+ Number.isSafeInteger(opts.maxTokens) &&
54
+ opts.maxTokens > 0 &&
55
+ opts.maxTokens < opts.contextWindow) {
56
+ inputBudget = opts.contextWindow - opts.maxTokens;
57
+ }
58
+ result.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(inputBudget);
42
59
  }
43
60
  // Channel-capability shims resolve ahead of any globally-installed CLI of
44
61
  // the same name (the shim owns auth; the real binary is found further down
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/claude-agent",
3
- "version": "1.58.0",
3
+ "version": "1.58.2",
4
4
  "description": "Claude Code bridge runtime for self-hosted Parall agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,9 +25,9 @@
25
25
  "src"
26
26
  ],
27
27
  "dependencies": {
28
- "@parall/agent-core": "1.58.0",
29
- "@parall/cli": "1.58.0",
30
- "@parall/sdk": "1.58.0"
28
+ "@parall/agent-core": "1.58.2",
29
+ "@parall/cli": "1.58.2",
30
+ "@parall/sdk": "1.58.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.0.0",
package/src/dispatch.ts CHANGED
@@ -47,6 +47,8 @@ type ClaudeCodeAdapterOptions = Pick<
47
47
  orgId: string;
48
48
  /** Catalog context size for the selected model. */
49
49
  contextWindow?: number;
50
+ /** Catalog max output tokens for the selected model (input-budget subtrahend). */
51
+ maxTokens?: number;
50
52
  contextFilePathForSession?: (sessionKey: string) => string;
51
53
  /** @deprecated Use contextFilePathForSession. */
52
54
  stepIdFilePathForSession?: (sessionKey: string) => string;
@@ -113,10 +115,12 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
113
115
  private _model: string | undefined;
114
116
  private _effortLevel: string | undefined;
115
117
  private _contextWindow: number | undefined;
118
+ private _maxTokens: number | undefined;
116
119
 
117
120
  constructor(private readonly opts: ClaudeCodeAdapterOptions) {
118
121
  this._model = opts.model;
119
122
  this._contextWindow = opts.contextWindow;
123
+ this._maxTokens = opts.maxTokens;
120
124
  }
121
125
 
122
126
  get currentModel(): string | undefined {
@@ -129,15 +133,18 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
129
133
  model?: string | null;
130
134
  effort?: string | null;
131
135
  contextWindow?: number | null;
136
+ maxTokens?: number | null;
132
137
  }): void {
133
138
  const modelChanged = config.model !== undefined && config.model !== this._model;
134
139
  const effortChanged = config.effort !== undefined && config.effort !== this._effortLevel;
135
140
  const contextWindowChanged =
136
141
  config.contextWindow !== undefined && config.contextWindow !== this._contextWindow;
142
+ const maxTokensChanged = config.maxTokens !== undefined && config.maxTokens !== this._maxTokens;
137
143
  if (modelChanged) this._model = config.model ?? undefined;
138
144
  if (effortChanged) this._effortLevel = config.effort ?? undefined;
139
145
  if (contextWindowChanged) this._contextWindow = config.contextWindow ?? undefined;
140
- if (modelChanged || effortChanged || contextWindowChanged) {
146
+ if (maxTokensChanged) this._maxTokens = config.maxTokens ?? undefined;
147
+ if (modelChanged || effortChanged || contextWindowChanged || maxTokensChanged) {
141
148
  this.requestProcessRestart();
142
149
  }
143
150
  }
@@ -664,6 +671,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
664
671
  {
665
672
  allowApiKey: this.opts.allowApiKey,
666
673
  contextWindow: this._contextWindow,
674
+ maxTokens: this._maxTokens,
667
675
  effortLevel: this._effortLevel,
668
676
  wikiMountRoot: this.opts.workspaceDir,
669
677
  capabilityBinDir: this.opts.capabilityBinDir,
@@ -671,7 +679,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
671
679
  );
672
680
 
673
681
  log?.info(
674
- `spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || 'default'}, context=${this._contextWindow || 'cli-default'}, effort=${this._effortLevel || 'default'}, mode=${this.opts.permissionMode})`,
682
+ `spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || 'default'}, context=${this._contextWindow || 'cli-default'}, maxOut=${this._maxTokens || 'cli-default'}, effort=${this._effortLevel || 'default'}, mode=${this.opts.permissionMode})`,
675
683
  );
676
684
 
677
685
  const proc = spawn(
package/src/index.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  parseProviderConfig,
21
21
  parseShutdownDeadlineMs,
22
22
  resolveRuntimeContextWindow,
23
+ resolveRuntimeMaxTokens,
23
24
  resolveRuntimeModel,
24
25
  } from '@parall/agent-core';
25
26
  import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
@@ -159,6 +160,11 @@ async function main() {
159
160
  platformDefaults,
160
161
  activeLLMSource,
161
162
  );
163
+ const resolvedMaxTokens = resolveRuntimeMaxTokens(
164
+ resolvedModel,
165
+ platformDefaults,
166
+ activeLLMSource,
167
+ );
162
168
  const resolvedEffort =
163
169
  platformDefaults.thinkingEffort ??
164
170
  (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
@@ -170,6 +176,7 @@ async function main() {
170
176
  agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}`);
171
177
  if (resolvedContextWindow)
172
178
  agentLog.info(`platform config: context_window=${resolvedContextWindow}`);
179
+ if (resolvedMaxTokens) agentLog.info(`platform config: max_tokens=${resolvedMaxTokens}`);
173
180
 
174
181
  const adapter = new ClaudeCodeAdapter({
175
182
  claudeBin: config.claudeBin,
@@ -177,6 +184,7 @@ async function main() {
177
184
  workspaceDir: config.workspaceDir,
178
185
  model: resolvedModel,
179
186
  contextWindow: resolvedContextWindow,
187
+ maxTokens: resolvedMaxTokens,
180
188
  permissionMode: config.permissionMode,
181
189
  allowedTools: config.allowedTools,
182
190
  disallowedTools: config.disallowedTools,
@@ -233,6 +241,7 @@ async function main() {
233
241
  adapter.updateConfig({
234
242
  model,
235
243
  contextWindow: resolveRuntimeContextWindow(model, updated, activeLLMSource) ?? null,
244
+ maxTokens: resolveRuntimeMaxTokens(model, updated, activeLLMSource) ?? null,
236
245
  effort: updated.thinkingEffort ?? localEffort,
237
246
  });
238
247
  // Channel capabilities heat-update with the config: re-materialize the
package/src/spawn-env.ts CHANGED
@@ -8,6 +8,7 @@ export function buildSpawnEnv(
8
8
  opts: {
9
9
  allowApiKey: boolean;
10
10
  contextWindow?: number;
11
+ maxTokens?: number;
11
12
  effortLevel?: string;
12
13
  wikiMountRoot?: string;
13
14
  capabilityBinDir?: string;
@@ -50,10 +51,29 @@ export function buildSpawnEnv(
50
51
  Number.isSafeInteger(opts.contextWindow) &&
51
52
  opts.contextWindow > 0
52
53
  ) {
53
- // Claude Code otherwise assumes 200k for an unrecognized model ID. Its
54
- // own auto-compaction policy reserves the output buffer before this
55
- // declared boundary; Parall supplies the model fact, not a second ratio.
56
- result.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(opts.contextWindow);
54
+ // Claude Code otherwise assumes 200k for an unrecognized model ID.
55
+ //
56
+ // Declared as the model's INPUT budget (context_window - max_tokens; both
57
+ // raw catalog facts), not the full window. The upstream validates
58
+ // input + max_tokens <= context_window, while the CLI requests up to its
59
+ // own output default (32k) yet reserves at most 20k below this declared
60
+ // boundary before auto-compacting (2.1.251) — so a session declared the
61
+ // full window can grow into a band the provider already rejects but the
62
+ // CLI still considers legal: it retries forever, auto-compact never
63
+ // fires, and once past the boundary the compaction call itself is
64
+ // over-limit (the ParallSRE 08-31 lockup). Subtracting the catalog
65
+ // max_tokens keeps the compaction trigger strictly inside what the
66
+ // provider accepts.
67
+ let inputBudget = opts.contextWindow;
68
+ if (
69
+ typeof opts.maxTokens === 'number' &&
70
+ Number.isSafeInteger(opts.maxTokens) &&
71
+ opts.maxTokens > 0 &&
72
+ opts.maxTokens < opts.contextWindow
73
+ ) {
74
+ inputBudget = opts.contextWindow - opts.maxTokens;
75
+ }
76
+ result.CLAUDE_CODE_MAX_CONTEXT_TOKENS = String(inputBudget);
57
77
  }
58
78
  // Channel-capability shims resolve ahead of any globally-installed CLI of
59
79
  // the same name (the shim owns auth; the real binary is found further down