@parall/codex-agent 1.36.1 → 1.38.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.
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -0
- package/dist/dispatch.d.ts +1 -0
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +5 -0
- package/dist/index.js +40 -42
- package/package.json +4 -4
- package/src/config.ts +12 -0
- package/src/dispatch.ts +6 -0
- package/src/index.ts +44 -44
package/dist/config.d.ts
CHANGED
|
@@ -52,5 +52,13 @@ export declare function resolveWsUrl(apiUrl: string, explicitWsUrl?: string, swi
|
|
|
52
52
|
export declare function buildCodexRuntimeKey(agentUserId: string): string;
|
|
53
53
|
export declare function sessionStateFilePathForRuntime(stateDir: string, runtimeKey: string): string;
|
|
54
54
|
export declare function contextFilePathForSession(stateDir: string, sessionKey: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* PRLL_CONTEXT_DIR root: per-lane dispatch context files, keyed by the
|
|
57
|
+
* canonical lane-key (see @parall/agent-core lane-key.ts). Anchored in the
|
|
58
|
+
* per-agent stateDir — never the workspace. Stable for the app-server's
|
|
59
|
+
* lifetime, which fixes the fork-reads-main-context mismatch of the single
|
|
60
|
+
* PRLL_CONTEXT_FILE under codex's one-process-many-threads model.
|
|
61
|
+
*/
|
|
62
|
+
export declare function dispatchContextDirPath(stateDir: string): string;
|
|
55
63
|
export declare function stepIdFilePathForSession(stateDir: string, sessionKey: string): string;
|
|
56
64
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAcF,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAyC9F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,EACtB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAMR;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAG3F;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAGrF"}
|
package/dist/config.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dispatchLaneContextDir } from '@parall/agent-core';
|
|
1
2
|
import * as os from 'node:os';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
function requireEnv(env, name) {
|
|
@@ -104,6 +105,16 @@ export function contextFilePathForSession(stateDir, sessionKey) {
|
|
|
104
105
|
const fileName = Buffer.from(sessionKey).toString('base64url');
|
|
105
106
|
return path.join(stateDir, 'dispatch-context', `${fileName}.json`);
|
|
106
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* PRLL_CONTEXT_DIR root: per-lane dispatch context files, keyed by the
|
|
110
|
+
* canonical lane-key (see @parall/agent-core lane-key.ts). Anchored in the
|
|
111
|
+
* per-agent stateDir — never the workspace. Stable for the app-server's
|
|
112
|
+
* lifetime, which fixes the fork-reads-main-context mismatch of the single
|
|
113
|
+
* PRLL_CONTEXT_FILE under codex's one-process-many-threads model.
|
|
114
|
+
*/
|
|
115
|
+
export function dispatchContextDirPath(stateDir) {
|
|
116
|
+
return dispatchLaneContextDir(stateDir);
|
|
117
|
+
}
|
|
107
118
|
export function stepIdFilePathForSession(stateDir, sessionKey) {
|
|
108
119
|
const fileName = Buffer.from(sessionKey).toString('base64url');
|
|
109
120
|
return path.join(stateDir, 'step-ids', `${fileName}.txt`);
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ type CodexAppServerAdapterOptions = Pick<CodexAgentConfig, 'approvalPolicy' | 'c
|
|
|
5
5
|
sessionManager: CodexSessionManager;
|
|
6
6
|
log?: GatewayLogger;
|
|
7
7
|
contextFilePath?: string;
|
|
8
|
+
contextDirPath?: string;
|
|
8
9
|
useParallProvider?: boolean;
|
|
9
10
|
};
|
|
10
11
|
export declare class CodexAppServerAdapter implements DispatchAdapter {
|
package/dist/dispatch.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAqCF,qBAAa,qBAAsB,YAAW,eAAe;IA+B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA9BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAMhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/E,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAUvC,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C,QAAQ,CAAC,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,OAAO,GACR,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IA0O7C,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IA+BhG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKhB,IAAI;YAiBI,aAAa;YA2Bb,OAAO;
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../src/dispatch.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,KAAK,4BAA4B,GAAG,IAAI,CACtC,gBAAgB,EACd,gBAAgB,GAChB,UAAU,GACV,WAAW,GACX,OAAO,GACP,iBAAiB,GACjB,SAAS,GACT,cAAc,CACjB,GAAG;IACF,cAAc,EAAE,mBAAmB,CAAC;IACpC,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAqCF,qBAAa,qBAAsB,YAAW,eAAe;IA+B/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IA9BjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa;gBAYQ,IAAI,EAAE,4BAA4B;IAE/D,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAMhF,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/E,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAUvC,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI1C,QAAQ,CAAC,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,OAAO,GACR,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC;IA0O7C,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMjD,WAAW,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IA+BhG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,eAAe;IAIrC,OAAO,CAAC,cAAc;IAKhB,IAAI;YAiBI,aAAa;YA2Bb,OAAO;IAuFrB,OAAO,CAAC,qBAAqB;YAmCf,UAAU;IA2CxB,OAAO,CAAC,iBAAiB;CA2B1B"}
|
package/dist/dispatch.js
CHANGED
|
@@ -448,6 +448,11 @@ export class CodexAppServerAdapter {
|
|
|
448
448
|
if (this.opts.contextFilePath) {
|
|
449
449
|
env.PRLL_CONTEXT_FILE = this.opts.contextFilePath;
|
|
450
450
|
}
|
|
451
|
+
if (this.opts.contextDirPath) {
|
|
452
|
+
// Per-lane dispatch context directory — per-target lookup, so fork
|
|
453
|
+
// threads never read main's context (the PRLL_CONTEXT_FILE pitfall).
|
|
454
|
+
env.PRLL_CONTEXT_DIR = this.opts.contextDirPath;
|
|
455
|
+
}
|
|
451
456
|
// Pin the wiki workspace to the agent workspace (same convention as the
|
|
452
457
|
// OpenClaw runtime). Without this, `parall wiki` resolves mounts relative
|
|
453
458
|
// to the subprocess cwd — a `cd` into any subdirectory would silently
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as os from 'node:os';
|
|
3
|
-
import { ParallAgentGateway, createPlatformConfigManager, createLogger, createOtelLogger, childLogger,
|
|
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
|
-
import { buildCodexRuntimeKey, contextFilePathForSession, resolveCodexAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from './config.js';
|
|
5
|
+
import { buildCodexRuntimeKey, contextFilePathForSession, dispatchContextDirPath, resolveCodexAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from './config.js';
|
|
6
6
|
import { CodexAppServerAdapter } from './dispatch.js';
|
|
7
7
|
import { CodexSessionManager } from './session-manager.js';
|
|
8
8
|
import { ensureCodexWorkspace, ensureParallProvider, ensureWorkspaceTrusted, isParallProxyMode, } from './workspace.js';
|
|
@@ -79,25 +79,18 @@ async function main() {
|
|
|
79
79
|
log: agentLog,
|
|
80
80
|
});
|
|
81
81
|
const platformDefaults = await configMgr.fetch();
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
// the
|
|
87
|
-
|
|
88
|
-
// AND not explicitly self-managed: this treats legacy hosted agents
|
|
89
|
-
// (model_management=null, resolved to platform server-side) as overrides,
|
|
90
|
-
// while excluding local self agents whose delivered model is a floor.
|
|
91
|
-
// reasoning_effort stays an operator override (platform).
|
|
92
|
-
let platformModelOverride = isPlatformModelOverride(me.agent_profile);
|
|
82
|
+
// Model precedence: operator PIN (override) > env > server FLOOR. The server
|
|
83
|
+
// now says which it is via model_is_pin (deriveModelIsPin presence-gates the
|
|
84
|
+
// dual-read: old servers omit it → fall back to model_management). A PIN beats
|
|
85
|
+
// an explicit env override; a FLOOR loses to env. reasoning_effort is delivered
|
|
86
|
+
// by the server only when pinned, so we no longer gate it on a local flag.
|
|
87
|
+
const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
|
|
93
88
|
const resolvedModel = resolveRuntimeModel(platformModelOverride, platformDefaults.model, config.model);
|
|
94
|
-
const resolvedEffort =
|
|
95
|
-
? (platformDefaults.thinkingEffort ?? config.reasoningEffort)
|
|
96
|
-
: config.reasoningEffort;
|
|
89
|
+
const resolvedEffort = platformDefaults.thinkingEffort ?? config.reasoningEffort;
|
|
97
90
|
if (platformDefaults.model)
|
|
98
|
-
agentLog.info(`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? '
|
|
91
|
+
agentLog.info(`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'pin/override' : 'floor'})`);
|
|
99
92
|
if (platformDefaults.thinkingEffort)
|
|
100
|
-
agentLog.info(`platform config: reasoning_effort=${platformDefaults.thinkingEffort}
|
|
93
|
+
agentLog.info(`platform config: reasoning_effort=${platformDefaults.thinkingEffort}`);
|
|
101
94
|
const adapter = new CodexAppServerAdapter({
|
|
102
95
|
codexBin: config.codexBin,
|
|
103
96
|
codexHome: config.codexHome,
|
|
@@ -109,8 +102,34 @@ async function main() {
|
|
|
109
102
|
sessionManager,
|
|
110
103
|
log: agentLog,
|
|
111
104
|
contextFilePath: mainContextFilePath,
|
|
105
|
+
contextDirPath: dispatchContextDirPath(config.stateDir),
|
|
112
106
|
useParallProvider,
|
|
113
107
|
});
|
|
108
|
+
// Shared by onConfigUpdate + onSessionReady. /agents/me is only consumed as
|
|
109
|
+
// deriveModelIsPin's legacy fallback when the server omits model_is_pin
|
|
110
|
+
// (old server) — skip that round trip otherwise.
|
|
111
|
+
const refreshPlatformConfig = async () => {
|
|
112
|
+
const updated = await configMgr.fetch();
|
|
113
|
+
let refreshedProfile;
|
|
114
|
+
if (updated.modelIsPin === undefined) {
|
|
115
|
+
try {
|
|
116
|
+
refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
|
|
117
|
+
.agent_profile;
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
// configMgr.fetch() degrades to cache on failure; mirror that for the
|
|
121
|
+
// legacy fallback so a transient /agents/me error doesn't reject this
|
|
122
|
+
// config-refresh callback. No profile → deriveModelIsPin treats the
|
|
123
|
+
// delivered model as a floor (safe default).
|
|
124
|
+
agentLog.warn(`platform config refresh: legacy /agents/me fallback failed: ${String(err)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const isPin = deriveModelIsPin(updated, refreshedProfile);
|
|
128
|
+
adapter.updateConfig({
|
|
129
|
+
model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
|
|
130
|
+
reasoningEffort: updated.thinkingEffort ?? config.reasoningEffort ?? null,
|
|
131
|
+
});
|
|
132
|
+
};
|
|
114
133
|
const gateway = new ParallAgentGateway({
|
|
115
134
|
accountId: agentUserId,
|
|
116
135
|
client,
|
|
@@ -138,30 +157,9 @@ async function main() {
|
|
|
138
157
|
dispatchDeadlineMs: parseDispatchDeadlineMs(process.env.PRLL_DISPATCH_DEADLINE_MS),
|
|
139
158
|
contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
|
|
140
159
|
stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
145
|
-
const updated = await configMgr.fetch();
|
|
146
|
-
adapter.updateConfig({
|
|
147
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
148
|
-
reasoningEffort: platformManaged
|
|
149
|
-
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
150
|
-
: (config.reasoningEffort ?? null),
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
onSessionReady: async () => {
|
|
154
|
-
const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
155
|
-
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
156
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
157
|
-
const updated = await configMgr.fetch();
|
|
158
|
-
adapter.updateConfig({
|
|
159
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
160
|
-
reasoningEffort: platformManaged
|
|
161
|
-
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
162
|
-
: (config.reasoningEffort ?? null),
|
|
163
|
-
});
|
|
164
|
-
},
|
|
160
|
+
dispatchContextDir: dispatchContextDirPath(config.stateDir),
|
|
161
|
+
onConfigUpdate: refreshPlatformConfig,
|
|
162
|
+
onSessionReady: refreshPlatformConfig,
|
|
165
163
|
onNewSession: () => {
|
|
166
164
|
sessionManager.clearMainThread();
|
|
167
165
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/codex-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Codex CLI bridge runtime for self-hosted Parall agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"smol-toml": "^1.6.1",
|
|
29
|
-
"@parall/agent-core": "1.
|
|
30
|
-
"@parall/
|
|
31
|
-
"@parall/
|
|
29
|
+
"@parall/agent-core": "1.38.0",
|
|
30
|
+
"@parall/cli": "1.38.0",
|
|
31
|
+
"@parall/sdk": "1.38.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^22.0.0",
|
package/src/config.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dispatchLaneContextDir } from '@parall/agent-core';
|
|
1
2
|
import * as os from 'node:os';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
|
|
@@ -155,6 +156,17 @@ export function contextFilePathForSession(stateDir: string, sessionKey: string):
|
|
|
155
156
|
return path.join(stateDir, 'dispatch-context', `${fileName}.json`);
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
/**
|
|
160
|
+
* PRLL_CONTEXT_DIR root: per-lane dispatch context files, keyed by the
|
|
161
|
+
* canonical lane-key (see @parall/agent-core lane-key.ts). Anchored in the
|
|
162
|
+
* per-agent stateDir — never the workspace. Stable for the app-server's
|
|
163
|
+
* lifetime, which fixes the fork-reads-main-context mismatch of the single
|
|
164
|
+
* PRLL_CONTEXT_FILE under codex's one-process-many-threads model.
|
|
165
|
+
*/
|
|
166
|
+
export function dispatchContextDirPath(stateDir: string): string {
|
|
167
|
+
return dispatchLaneContextDir(stateDir);
|
|
168
|
+
}
|
|
169
|
+
|
|
158
170
|
export function stepIdFilePathForSession(stateDir: string, sessionKey: string): string {
|
|
159
171
|
const fileName = Buffer.from(sessionKey).toString('base64url');
|
|
160
172
|
return path.join(stateDir, 'step-ids', `${fileName}.txt`);
|
package/src/dispatch.ts
CHANGED
|
@@ -35,6 +35,7 @@ type CodexAppServerAdapterOptions = Pick<
|
|
|
35
35
|
sessionManager: CodexSessionManager;
|
|
36
36
|
log?: GatewayLogger;
|
|
37
37
|
contextFilePath?: string;
|
|
38
|
+
contextDirPath?: string;
|
|
38
39
|
useParallProvider?: boolean;
|
|
39
40
|
};
|
|
40
41
|
|
|
@@ -497,6 +498,11 @@ export class CodexAppServerAdapter implements DispatchAdapter {
|
|
|
497
498
|
if (this.opts.contextFilePath) {
|
|
498
499
|
env.PRLL_CONTEXT_FILE = this.opts.contextFilePath;
|
|
499
500
|
}
|
|
501
|
+
if (this.opts.contextDirPath) {
|
|
502
|
+
// Per-lane dispatch context directory — per-target lookup, so fork
|
|
503
|
+
// threads never read main's context (the PRLL_CONTEXT_FILE pitfall).
|
|
504
|
+
env.PRLL_CONTEXT_DIR = this.opts.contextDirPath;
|
|
505
|
+
}
|
|
500
506
|
// Pin the wiki workspace to the agent workspace (same convention as the
|
|
501
507
|
// OpenClaw runtime). Without this, `parall wiki` resolves mounts relative
|
|
502
508
|
// to the subprocess cwd — a `cd` into any subdirectory would silently
|
package/src/index.ts
CHANGED
|
@@ -7,8 +7,7 @@ import {
|
|
|
7
7
|
createLogger,
|
|
8
8
|
createOtelLogger,
|
|
9
9
|
childLogger,
|
|
10
|
-
|
|
11
|
-
isPlatformModelOverride,
|
|
10
|
+
deriveModelIsPin,
|
|
12
11
|
resolveRuntimeModel,
|
|
13
12
|
parseShutdownDeadlineMs,
|
|
14
13
|
parseForkDeadlineMs,
|
|
@@ -22,6 +21,7 @@ import { ApiError, ParallClient, ParallWs } from '@parall/sdk';
|
|
|
22
21
|
import {
|
|
23
22
|
buildCodexRuntimeKey,
|
|
24
23
|
contextFilePathForSession,
|
|
24
|
+
dispatchContextDirPath,
|
|
25
25
|
resolveCodexAgentConfig,
|
|
26
26
|
resolveWsUrl,
|
|
27
27
|
sessionStateFilePathForRuntime,
|
|
@@ -111,33 +111,24 @@ async function main() {
|
|
|
111
111
|
log: agentLog,
|
|
112
112
|
});
|
|
113
113
|
const platformDefaults = await configMgr.fetch();
|
|
114
|
-
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
// the
|
|
119
|
-
|
|
120
|
-
// AND not explicitly self-managed: this treats legacy hosted agents
|
|
121
|
-
// (model_management=null, resolved to platform server-side) as overrides,
|
|
122
|
-
// while excluding local self agents whose delivered model is a floor.
|
|
123
|
-
// reasoning_effort stays an operator override (platform).
|
|
124
|
-
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. reasoning_effort is delivered
|
|
118
|
+
// by the server only when pinned, so we no longer gate it on a local flag.
|
|
119
|
+
const platformModelOverride = deriveModelIsPin(platformDefaults, me.agent_profile);
|
|
125
120
|
const resolvedModel = resolveRuntimeModel(
|
|
126
121
|
platformModelOverride,
|
|
127
122
|
platformDefaults.model,
|
|
128
123
|
config.model,
|
|
129
124
|
);
|
|
130
|
-
const resolvedEffort =
|
|
131
|
-
? (platformDefaults.thinkingEffort ?? config.reasoningEffort)
|
|
132
|
-
: config.reasoningEffort;
|
|
125
|
+
const resolvedEffort = platformDefaults.thinkingEffort ?? config.reasoningEffort;
|
|
133
126
|
if (platformDefaults.model)
|
|
134
127
|
agentLog.info(
|
|
135
|
-
`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? '
|
|
128
|
+
`platform config: model=${platformDefaults.model} → resolved=${resolvedModel ?? 'cli-default'} (${platformModelOverride ? 'pin/override' : 'floor'})`,
|
|
136
129
|
);
|
|
137
130
|
if (platformDefaults.thinkingEffort)
|
|
138
|
-
agentLog.info(
|
|
139
|
-
`platform config: reasoning_effort=${platformDefaults.thinkingEffort} (${platformModelOverride ? 'applied' : 'ignored, model_management=self'})`,
|
|
140
|
-
);
|
|
131
|
+
agentLog.info(`platform config: reasoning_effort=${platformDefaults.thinkingEffort}`);
|
|
141
132
|
|
|
142
133
|
const adapter = new CodexAppServerAdapter({
|
|
143
134
|
codexBin: config.codexBin,
|
|
@@ -150,9 +141,39 @@ async function main() {
|
|
|
150
141
|
sessionManager,
|
|
151
142
|
log: agentLog,
|
|
152
143
|
contextFilePath: mainContextFilePath,
|
|
144
|
+
contextDirPath: dispatchContextDirPath(config.stateDir),
|
|
153
145
|
useParallProvider,
|
|
154
146
|
});
|
|
155
147
|
|
|
148
|
+
// Shared by onConfigUpdate + onSessionReady. /agents/me is only consumed as
|
|
149
|
+
// deriveModelIsPin's legacy fallback when the server omits model_is_pin
|
|
150
|
+
// (old server) — skip that round trip otherwise.
|
|
151
|
+
const refreshPlatformConfig = async () => {
|
|
152
|
+
const updated = await configMgr.fetch();
|
|
153
|
+
let refreshedProfile:
|
|
154
|
+
| Awaited<ReturnType<typeof getAgentMeWithLegacyFallback>>['agent_profile']
|
|
155
|
+
| undefined;
|
|
156
|
+
if (updated.modelIsPin === undefined) {
|
|
157
|
+
try {
|
|
158
|
+
refreshedProfile = (await getAgentMeWithLegacyFallback(client, config.orgId))
|
|
159
|
+
.agent_profile;
|
|
160
|
+
} catch (err) {
|
|
161
|
+
// configMgr.fetch() degrades to cache on failure; mirror that for the
|
|
162
|
+
// legacy fallback so a transient /agents/me error doesn't reject this
|
|
163
|
+
// config-refresh callback. No profile → deriveModelIsPin treats the
|
|
164
|
+
// delivered model as a floor (safe default).
|
|
165
|
+
agentLog.warn(
|
|
166
|
+
`platform config refresh: legacy /agents/me fallback failed: ${String(err)}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const isPin = deriveModelIsPin(updated, refreshedProfile);
|
|
171
|
+
adapter.updateConfig({
|
|
172
|
+
model: resolveRuntimeModel(isPin, updated.model, config.model) ?? null,
|
|
173
|
+
reasoningEffort: updated.thinkingEffort ?? config.reasoningEffort ?? null,
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
156
177
|
const gateway = new ParallAgentGateway({
|
|
157
178
|
accountId: agentUserId,
|
|
158
179
|
client,
|
|
@@ -182,30 +203,9 @@ async function main() {
|
|
|
182
203
|
contextFilePathForSession(config.stateDir, sessionKey),
|
|
183
204
|
stepIdFilePathForSession: (sessionKey) =>
|
|
184
205
|
stepIdFilePathForSession(config.stateDir, sessionKey),
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
189
|
-
const updated = await configMgr.fetch();
|
|
190
|
-
adapter.updateConfig({
|
|
191
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
192
|
-
reasoningEffort: platformManaged
|
|
193
|
-
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
194
|
-
: (config.reasoningEffort ?? null),
|
|
195
|
-
});
|
|
196
|
-
},
|
|
197
|
-
onSessionReady: async () => {
|
|
198
|
-
const refreshed = await getAgentMeWithLegacyFallback(client, config.orgId);
|
|
199
|
-
platformManaged = isPlatformManagedProfile(refreshed.agent_profile);
|
|
200
|
-
platformModelOverride = isPlatformModelOverride(refreshed.agent_profile);
|
|
201
|
-
const updated = await configMgr.fetch();
|
|
202
|
-
adapter.updateConfig({
|
|
203
|
-
model: resolveRuntimeModel(platformModelOverride, updated.model, config.model) ?? null,
|
|
204
|
-
reasoningEffort: platformManaged
|
|
205
|
-
? (updated.thinkingEffort ?? config.reasoningEffort)
|
|
206
|
-
: (config.reasoningEffort ?? null),
|
|
207
|
-
});
|
|
208
|
-
},
|
|
206
|
+
dispatchContextDir: dispatchContextDirPath(config.stateDir),
|
|
207
|
+
onConfigUpdate: refreshPlatformConfig,
|
|
208
|
+
onSessionReady: refreshPlatformConfig,
|
|
209
209
|
onNewSession: () => {
|
|
210
210
|
sessionManager.clearMainThread();
|
|
211
211
|
},
|