@parall/claude-agent 1.48.0 → 1.50.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 +36 -22
  2. package/package.json +4 -4
  3. package/src/index.ts +41 -24
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, capabilityBinDir, configureHttpKeepAlive, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, deriveModelIsPin, materializeChannelCapabilities, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, initAgentTelemetry, } from '@parall/agent-core';
3
+ import { ParallAgentGateway, capabilityBinDir, configureHttpKeepAlive, createPlatformConfigManager, createLogger, createOtelLogger, childLogger, deriveModelIsPin, materializeChannelCapabilities, resolveRuntimeModel, parseShutdownDeadlineMs, parseForkDeadlineMs, parseDispatchDeadlineMs, parseProviderConfig, clearAllProviderCreds, llmSource, identityFromMe, initAgentTelemetry, } 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';
@@ -17,7 +17,7 @@ async function getAgentMeWithLegacyFallback(client, orgId) {
17
17
  throw err;
18
18
  }
19
19
  const user = await client.getMe();
20
- return { ...user, agent_profile: null };
20
+ return { ...user, agent_profile: null, public_profile: null };
21
21
  }
22
22
  }
23
23
  function resolveProviderEnv() {
@@ -65,11 +65,14 @@ async function main() {
65
65
  activeLog = agentLog;
66
66
  // Shared by the initial workspace write and the config-refresh rewrite of
67
67
  // .parall/system-prompt.md — both need identity + capability fragments.
68
- const agentIdentity = {
69
- userId: agentUserId,
70
- displayName: me.display_name,
71
- description: me.agent_profile?.description ?? undefined,
72
- };
68
+ // Mutable on purpose: refreshPlatformConfig refetches it (see
69
+ // identityFromMe) so profile edits reach the next activation.
70
+ let agentIdentity = identityFromMe(me);
71
+ let lastIdentitySnapshot = JSON.stringify(agentIdentity);
72
+ // Last successful /agents/me profile — deriveModelIsPin's legacy fallback
73
+ // (old servers omit model_is_pin) must not flip a pinned model to floor
74
+ // just because one refresh round-trip failed.
75
+ let lastKnownAgentProfile = me.agent_profile;
73
76
  const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
74
77
  const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
75
78
  const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, agentLog);
@@ -147,21 +150,25 @@ async function main() {
147
150
  // (old server) — skip that round trip otherwise.
148
151
  const refreshPlatformConfig = async () => {
149
152
  const updated = await configMgr.fetch();
150
- let refreshedProfile;
151
- if (updated.modelIsPin === undefined) {
152
- try {
153
- refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
154
- .agent_profile;
155
- }
156
- catch (err) {
157
- // configMgr.fetch() degrades to cache on failure; mirror that for the
158
- // legacy fallback so a transient /agents/me error doesn't reject this
159
- // config-refresh callback. No profile → deriveModelIsPin treats the
160
- // delivered model as a floor (safe default).
161
- agentLog.warn(`platform config refresh: legacy /agents/me fallback failed: ${String(err)}`);
162
- }
153
+ // Unconditional /agents/me refetch: identity (title / public
154
+ // description / private instructions) rides the same
155
+ // agent_config.update nudge as model config. Failure degrades to the
156
+ // last-known-good identity, mirroring configMgr.fetch()'s cache
157
+ // fallback, so a transient error never rejects this callback. No
158
+ // profile → deriveModelIsPin treats the delivered model as a floor
159
+ // (safe default).
160
+ let refreshedMe;
161
+ try {
162
+ refreshedMe = await getAgentMeWithLegacyFallback(client, config.orgId);
163
+ }
164
+ catch (err) {
165
+ agentLog.warn(`platform config refresh: /agents/me refetch failed (keeping last-known identity): ${String(err)}`);
166
+ }
167
+ if (refreshedMe) {
168
+ agentIdentity = identityFromMe(refreshedMe);
169
+ lastKnownAgentProfile = refreshedMe.agent_profile;
163
170
  }
164
- const isPin = deriveModelIsPin(updated, refreshedProfile);
171
+ const isPin = deriveModelIsPin(updated, lastKnownAgentProfile);
165
172
  const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
166
173
  adapter.updateConfig({
167
174
  model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
@@ -196,8 +203,15 @@ async function main() {
196
203
  promptWritten = false;
197
204
  agentLog.warn(`system prompt refresh write failed (retrying next refresh): ${String(err)}`);
198
205
  }
199
- if (promptWritten && joinedFragments !== lastCapabilityFragments) {
206
+ // Identity changes ride the same lazy-respawn mechanism as capability
207
+ // fragments: the live child loaded its prompt at spawn, so a changed
208
+ // identity marks it for an out-of-turn --resume respawn and the next
209
+ // activation runs with the new prompt.
210
+ const identitySnapshot = JSON.stringify(agentIdentity);
211
+ if (promptWritten &&
212
+ (joinedFragments !== lastCapabilityFragments || identitySnapshot !== lastIdentitySnapshot)) {
200
213
  lastCapabilityFragments = joinedFragments;
214
+ lastIdentitySnapshot = identitySnapshot;
201
215
  adapter.requestProcessRestart();
202
216
  }
203
217
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/claude-agent",
3
- "version": "1.48.0",
3
+ "version": "1.50.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/cli": "1.48.0",
29
- "@parall/agent-core": "1.48.0",
30
- "@parall/sdk": "1.48.0"
28
+ "@parall/agent-core": "1.50.0",
29
+ "@parall/cli": "1.50.0",
30
+ "@parall/sdk": "1.50.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.0.0",
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  parseProviderConfig,
19
19
  clearAllProviderCreds,
20
20
  llmSource,
21
+ identityFromMe,
21
22
  initAgentTelemetry,
22
23
  } from '@parall/agent-core';
23
24
  import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
@@ -45,10 +46,12 @@ async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string)
45
46
  throw err;
46
47
  }
47
48
  const user = await client.getMe();
48
- return { ...user, agent_profile: null };
49
+ return { ...user, agent_profile: null, public_profile: null };
49
50
  }
50
51
  }
51
52
 
53
+ type AgentMe = Awaited<ReturnType<typeof getAgentMeWithLegacyFallback>>;
54
+
52
55
  function resolveProviderEnv(): void {
53
56
  const pc = parseProviderConfig(process.env);
54
57
  if (!pc) return;
@@ -97,11 +100,14 @@ async function main() {
97
100
  activeLog = agentLog;
98
101
  // Shared by the initial workspace write and the config-refresh rewrite of
99
102
  // .parall/system-prompt.md — both need identity + capability fragments.
100
- const agentIdentity = {
101
- userId: agentUserId,
102
- displayName: me.display_name,
103
- description: me.agent_profile?.description ?? undefined,
104
- };
103
+ // Mutable on purpose: refreshPlatformConfig refetches it (see
104
+ // identityFromMe) so profile edits reach the next activation.
105
+ let agentIdentity = identityFromMe(me);
106
+ let lastIdentitySnapshot = JSON.stringify(agentIdentity);
107
+ // Last successful /agents/me profile — deriveModelIsPin's legacy fallback
108
+ // (old servers omit model_is_pin) must not flip a pinned model to floor
109
+ // just because one refresh round-trip failed.
110
+ let lastKnownAgentProfile = me.agent_profile;
105
111
  const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
106
112
  const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
107
113
  const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, agentLog);
@@ -192,24 +198,26 @@ async function main() {
192
198
  // (old server) — skip that round trip otherwise.
193
199
  const refreshPlatformConfig = async () => {
194
200
  const updated = await configMgr.fetch();
195
- let refreshedProfile:
196
- | Awaited<ReturnType<typeof getAgentMeWithLegacyFallback>>['agent_profile']
197
- | undefined;
198
- if (updated.modelIsPin === undefined) {
199
- try {
200
- refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
201
- .agent_profile;
202
- } catch (err) {
203
- // configMgr.fetch() degrades to cache on failure; mirror that for the
204
- // legacy fallback so a transient /agents/me error doesn't reject this
205
- // config-refresh callback. No profile → deriveModelIsPin treats the
206
- // delivered model as a floor (safe default).
207
- agentLog.warn(
208
- `platform config refresh: legacy /agents/me fallback failed: ${String(err)}`,
209
- );
210
- }
201
+ // Unconditional /agents/me refetch: identity (title / public
202
+ // description / private instructions) rides the same
203
+ // agent_config.update nudge as model config. Failure degrades to the
204
+ // last-known-good identity, mirroring configMgr.fetch()'s cache
205
+ // fallback, so a transient error never rejects this callback. No
206
+ // profile deriveModelIsPin treats the delivered model as a floor
207
+ // (safe default).
208
+ let refreshedMe: AgentMe | undefined;
209
+ try {
210
+ refreshedMe = await getAgentMeWithLegacyFallback(client, config.orgId);
211
+ } catch (err) {
212
+ agentLog.warn(
213
+ `platform config refresh: /agents/me refetch failed (keeping last-known identity): ${String(err)}`,
214
+ );
215
+ }
216
+ if (refreshedMe) {
217
+ agentIdentity = identityFromMe(refreshedMe);
218
+ lastKnownAgentProfile = refreshedMe.agent_profile;
211
219
  }
212
- const isPin = deriveModelIsPin(updated, refreshedProfile);
220
+ const isPin = deriveModelIsPin(updated, lastKnownAgentProfile);
213
221
  const localEffort = process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || null;
214
222
  adapter.updateConfig({
215
223
  model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
@@ -243,8 +251,17 @@ async function main() {
243
251
  promptWritten = false;
244
252
  agentLog.warn(`system prompt refresh write failed (retrying next refresh): ${String(err)}`);
245
253
  }
246
- if (promptWritten && joinedFragments !== lastCapabilityFragments) {
254
+ // Identity changes ride the same lazy-respawn mechanism as capability
255
+ // fragments: the live child loaded its prompt at spawn, so a changed
256
+ // identity marks it for an out-of-turn --resume respawn and the next
257
+ // activation runs with the new prompt.
258
+ const identitySnapshot = JSON.stringify(agentIdentity);
259
+ if (
260
+ promptWritten &&
261
+ (joinedFragments !== lastCapabilityFragments || identitySnapshot !== lastIdentitySnapshot)
262
+ ) {
247
263
  lastCapabilityFragments = joinedFragments;
264
+ lastIdentitySnapshot = identitySnapshot;
248
265
  adapter.requestProcessRestart();
249
266
  }
250
267
  };