@parall/claude-agent 1.36.1 → 1.37.0

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.
Files changed (3) hide show
  1. package/dist/index.js +39 -40
  2. package/package.json +4 -4
  3. package/src/index.ts +44 -43
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 { ParallAgentGateway, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, isPlatformManagedProfile, isPlatformModelOverride, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, initAgentTelemetry, } from '@parall/agent-core';
3
+ import { ParallAgentGateway, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, deriveModelIsPin, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, initAgentTelemetry, } from '@parall/agent-core';
4
4
  import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
5
5
  import { buildClaudeRuntimeKey, contextFilePathForSession, resolveClaudeAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from './config.js';
6
6
  import { ClaudeCodeAdapter } from './dispatch.js';
@@ -81,26 +81,19 @@ async function main() {
81
81
  log: agentLog,
82
82
  });
83
83
  const platformDefaults = await configMgr.fetch();
84
- let platformManaged = isPlatformManagedProfile(me.agent_profile);
85
- // Model precedence: operator override (platform-managed) > env > server floor.
86
- // The server delivers a model floor for Parall-proxy routes even when
87
- // model_management=self, so the CLI never falls back to a built-in default
88
- // the catalog might reject but that floor must lose to an explicit env
89
- // override (env > floor). A profile is an operator-override only when it is
90
- // platform-managed AND not explicitly self-managed: this treats legacy hosted
91
- // agents (model_management=null, resolved to platform server-side) as
92
- // overrides, while excluding local self agents whose delivered model is a
93
- // floor. effort stays an operator override (platform).
94
- let platformModelOverride = isPlatformModelOverride(me.agent_profile);
84
+ // Model precedence: operator PIN (override) > env > server FLOOR. The server
85
+ // now says which it is via model_is_pin (deriveModelIsPin presence-gates the
86
+ // dual-read: old servers omit it fall back to model_management). A PIN beats
87
+ // an explicit env override; a FLOOR loses to env. effort is delivered by the
88
+ // server only when pinned, so we no longer gate it on a local flag.
89
+ const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
95
90
  const resolvedModel = resolveRuntimeModel(platformModelOverride, platformDefaults.model, config.model);
96
- const resolvedEffort = platformManaged
97
- ? (platformDefaults.thinkingEffort ??
98
- (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
99
- : process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined;
91
+ const resolvedEffort = platformDefaults.thinkingEffort ??
92
+ (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
100
93
  if (platformDefaults.model)
101
- agentLog.info(`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'platform-managed' : 'floor/self'})`);
94
+ agentLog.info(`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'pin/override' : 'floor'})`);
102
95
  if (platformDefaults.thinkingEffort)
103
- agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformModelOverride ? 'applied' : 'ignored, model_management=self'})`);
96
+ agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}`);
104
97
  const adapter = new ClaudeCodeAdapter({
105
98
  claudeBin: config.claudeBin,
106
99
  claudeHome: config.claudeHome,
@@ -125,6 +118,32 @@ async function main() {
125
118
  if (resolvedEffort) {
126
119
  adapter.updateConfig({ effort: resolvedEffort });
127
120
  }
121
+ // Shared by onConfigUpdate + onSessionReady. /agents/me is only consumed as
122
+ // deriveModelIsPin's legacy fallback when the server omits model_is_pin
123
+ // (old server) — skip that round trip otherwise.
124
+ const refreshPlatformConfig = async () => {
125
+ const updated = await configMgr.fetch();
126
+ let refreshedProfile;
127
+ if (updated.modelIsPin === undefined) {
128
+ try {
129
+ refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
130
+ .agent_profile;
131
+ }
132
+ catch (err) {
133
+ // configMgr.fetch() degrades to cache on failure; mirror that for the
134
+ // legacy fallback so a transient /agents/me error doesn't reject this
135
+ // config-refresh callback. No profile → deriveModelIsPin treats the
136
+ // delivered model as a floor (safe default).
137
+ agentLog.warn(`platform config refresh: legacy /agents/me fallback failed: ${String(err)}`);
138
+ }
139
+ }
140
+ const isPin = deriveModelIsPin(updated, refreshedProfile);
141
+ const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
142
+ adapter.updateConfig({
143
+ model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
144
+ effort: updated.thinkingEffort ?? localEffort,
145
+ });
146
+ };
128
147
  const gateway = new ParallAgentGateway({
129
148
  accountId: agentUserId,
130
149
  client,
@@ -151,28 +170,8 @@ async function main() {
151
170
  dispatchDeadlineMs: parseDispatchDeadlineMs(process.env.PRLL_DISPATCH_DEADLINE_MS),
152
171
  contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
153
172
  stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
154
- onConfigUpdate: async () => {
155
- const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
156
- platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
157
- platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
158
- const updated = await configMgr.fetch();
159
- const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
160
- adapter.updateConfig({
161
- model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
162
- effort: platformManaged ? (updated.thinkingEffort ?? localEffort) : localEffort,
163
- });
164
- },
165
- onSessionReady: async () => {
166
- const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
167
- platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
168
- platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
169
- const updated = await configMgr.fetch();
170
- const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
171
- adapter.updateConfig({
172
- model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
173
- effort: platformManaged ? (updated.thinkingEffort ?? localEffort) : localEffort,
174
- });
175
- },
173
+ onConfigUpdate: refreshPlatformConfig,
174
+ onSessionReady: refreshPlatformConfig,
176
175
  // Long-lived `claude` subprocesses outlive a single dispatch, so the
177
176
  // gateway's shuttingDown flag alone does not tear them down. Piggyback on
178
177
  // onBeforeDisconnect to close stdin and SIGTERM any survivors after
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/claude-agent",
3
- "version": "1.36.1",
3
+ "version": "1.37.0",
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.36.1",
29
- "@parall/cli": "1.36.1",
30
- "@parall/sdk": "1.36.1"
28
+ "@parall/agent-core": "1.37.0",
29
+ "@parall/sdk": "1.37.0",
30
+ "@parall/cli": "1.37.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.0.0",
package/src/index.ts CHANGED
@@ -7,8 +7,7 @@ import {
7
7
  createLogger,
8
8
  createOtelLogger,
9
9
  childLogger,
10
- isPlatformManagedProfile,
11
- isPlatformModelOverride,
10
+ deriveModelIsPin,
12
11
  resolveRuntimeModel,
13
12
  parseShutdownDeadlineMs,
14
13
  parseForkDeadlineMs,
@@ -112,34 +111,26 @@ async function main() {
112
111
  log: agentLog,
113
112
  });
114
113
  const platformDefaults = await configMgr.fetch();
115
- let platformManaged = isPlatformManagedProfile(me.agent_profile);
116
- // Model precedence: operator override (platform-managed) > env > server floor.
117
- // The server delivers a model floor for Parall-proxy routes even when
118
- // model_management=self, so the CLI never falls back to a built-in default
119
- // the catalog might reject but that floor must lose to an explicit env
120
- // override (env > floor). A profile is an operator-override only when it is
121
- // platform-managed AND not explicitly self-managed: this treats legacy hosted
122
- // agents (model_management=null, resolved to platform server-side) as
123
- // overrides, while excluding local self agents whose delivered model is a
124
- // floor. effort stays an operator override (platform).
125
- let platformModelOverride = isPlatformModelOverride(me.agent_profile);
114
+ // Model precedence: operator PIN (override) > env > server FLOOR. The server
115
+ // now says which it is via model_is_pin (deriveModelIsPin presence-gates the
116
+ // dual-read: old servers omit it fall back to model_management). A PIN beats
117
+ // an explicit env override; a FLOOR loses to env. effort is delivered by the
118
+ // server only when pinned, so we no longer gate it on a local flag.
119
+ const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
126
120
  const resolvedModel = resolveRuntimeModel(
127
121
  platformModelOverride,
128
122
  platformDefaults.model,
129
123
  config.model,
130
124
  );
131
- const resolvedEffort = platformManaged
132
- ? (platformDefaults.thinkingEffort ??
133
- (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
134
- : process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined;
125
+ const resolvedEffort =
126
+ platformDefaults.thinkingEffort ??
127
+ (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
135
128
  if (platformDefaults.model)
136
129
  agentLog.info(
137
- `platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'platform-managed' : 'floor/self'})`,
130
+ `platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'pin/override' : 'floor'})`,
138
131
  );
139
132
  if (platformDefaults.thinkingEffort)
140
- agentLog.info(
141
- `platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformModelOverride ? 'applied' : 'ignored, model_management=self'})`,
142
- );
133
+ agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort}`);
143
134
 
144
135
  const adapter = new ClaudeCodeAdapter({
145
136
  claudeBin: config.claudeBin,
@@ -168,6 +159,36 @@ async function main() {
168
159
  adapter.updateConfig({ effort: resolvedEffort });
169
160
  }
170
161
 
162
+ // Shared by onConfigUpdate + onSessionReady. /agents/me is only consumed as
163
+ // deriveModelIsPin's legacy fallback when the server omits model_is_pin
164
+ // (old server) — skip that round trip otherwise.
165
+ const refreshPlatformConfig = async () => {
166
+ const updated = await configMgr.fetch();
167
+ let refreshedProfile:
168
+ | Awaited<ReturnType<typeof getAgentMeWithLegacyFallback>>['agent_profile']
169
+ | undefined;
170
+ if (updated.modelIsPin === undefined) {
171
+ try {
172
+ refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
173
+ .agent_profile;
174
+ } catch (err) {
175
+ // configMgr.fetch() degrades to cache on failure; mirror that for the
176
+ // legacy fallback so a transient /agents/me error doesn't reject this
177
+ // config-refresh callback. No profile → deriveModelIsPin treats the
178
+ // delivered model as a floor (safe default).
179
+ agentLog.warn(
180
+ `platform config refresh: legacy /agents/me fallback failed: ${String(err)}`,
181
+ );
182
+ }
183
+ }
184
+ const isPin = deriveModelIsPin(updated, refreshedProfile);
185
+ const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
186
+ adapter.updateConfig({
187
+ model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
188
+ effort: updated.thinkingEffort ?? localEffort,
189
+ });
190
+ };
191
+
171
192
  const gateway = new ParallAgentGateway({
172
193
  accountId: agentUserId,
173
194
  client,
@@ -196,28 +217,8 @@ async function main() {
196
217
  contextFilePathForSession(config.stateDir, sessionKey),
197
218
  stepIdFilePathForSession: (sessionKey) =>
198
219
  stepIdFilePathForSession(config.stateDir, sessionKey),
199
- onConfigUpdate: async () => {
200
- const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
201
- platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
202
- platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
203
- const updated = await configMgr.fetch();
204
- const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
205
- adapter.updateConfig({
206
- model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
207
- effort: platformManaged ? (updated.thinkingEffort ?? localEffort) : localEffort,
208
- });
209
- },
210
- onSessionReady: async () => {
211
- const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
212
- platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
213
- platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
214
- const updated = await configMgr.fetch();
215
- const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
216
- adapter.updateConfig({
217
- model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
218
- effort: platformManaged ? (updated.thinkingEffort ?? localEffort) : localEffort,
219
- });
220
- },
220
+ onConfigUpdate: refreshPlatformConfig,
221
+ onSessionReady: refreshPlatformConfig,
221
222
  // Long-lived `claude` subprocesses outlive a single dispatch, so the
222
223
  // gateway's shuttingDown flag alone does not tear them down. Piggyback on
223
224
  // onBeforeDisconnect to close stdin and SIGTERM any survivors after