replicas-engine 0.1.636 → 0.1.638

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.
@@ -89,8 +89,8 @@ var REPLICAS_RUNTIME_ENV_ALIASES = {
89
89
  slackChannelId: ["REPLICAS_SLACK_CHANNEL_ID", "SLACK_CHANNEL_ID"],
90
90
  slackThreadTs: ["REPLICAS_SLACK_THREAD_TS", "SLACK_THREAD_TS"]
91
91
  };
92
- function readReplicasRuntimeEnv(readEnv2, [namespacedKey, legacyKey]) {
93
- return readEnv2(namespacedKey) ?? readEnv2(legacyKey);
92
+ function readReplicasRuntimeEnv(readEnv, [namespacedKey, legacyKey]) {
93
+ return readEnv(namespacedKey) ?? readEnv(legacyKey);
94
94
  }
95
95
  function shellQuotePosix(value) {
96
96
  return `'${value.split("'").join("'\\''")}'`;
@@ -243,6 +243,7 @@ var headlessAgentOutputFileSchema = z.object({
243
243
  path: z.string().min(1),
244
244
  uploadUrl: z.url(),
245
245
  contentType: z.string().min(1),
246
+ minChars: z.number().int().positive().optional(),
246
247
  maxChars: z.number().int().positive().optional()
247
248
  });
248
249
  var headlessAgentRequestSchema = z.discriminatedUnion("mode", [
@@ -5643,150 +5644,19 @@ async function putPresignedFile(urlValue, filePath, size, contentType) {
5643
5644
  });
5644
5645
  }
5645
5646
 
5646
- // src/engine-env.ts
5647
- import { readFileSync as readFileSync2 } from "fs";
5648
- import { homedir as homedir2 } from "os";
5649
- import { join as join2 } from "path";
5650
-
5651
- // src/runtime-env-loader.ts
5652
- import { readFileSync } from "fs";
5653
- import { homedir } from "os";
5654
- import { join } from "path";
5655
- function loadRuntimeEnvFile() {
5656
- let content;
5657
- try {
5658
- content = readFileSync(join(homedir(), ".replicas", "runtime-env.sh"), "utf-8");
5659
- } catch {
5660
- return;
5661
- }
5662
- for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
5663
- process.env[key] = value;
5664
- }
5665
- }
5666
-
5667
- // src/utils/type-guards.ts
5668
- function isRecord4(value) {
5669
- return typeof value === "object" && value !== null;
5670
- }
5671
-
5672
- // src/engine-env.ts
5673
- var SANDBOX_IMAGE_VERSION_FILE = "/usr/local/lib/replicas-sandbox-image-version";
5674
- function readEnv(name) {
5675
- const value = process.env[name]?.trim();
5676
- return value ? value : void 0;
5677
- }
5678
- function readSandboxImageVersion() {
5679
- const environmentVersion = readEnv("REPLICAS_SANDBOX_IMAGE_VERSION");
5680
- if (environmentVersion) return environmentVersion;
5681
- try {
5682
- return readFileSync2(SANDBOX_IMAGE_VERSION_FILE, "utf8").trim() || "development";
5683
- } catch {
5684
- return "development";
5685
- }
5686
- }
5687
- function parsePort(value) {
5688
- if (!value) {
5689
- return 3737;
5690
- }
5691
- const parsed = Number(value);
5692
- if (!Number.isInteger(parsed) || parsed <= 0) {
5693
- throw new Error("Invalid engine environment: REPLICAS_ENGINE_PORT must be a positive integer");
5694
- }
5695
- return parsed;
5696
- }
5697
- function requireDefined(value, name) {
5698
- if (value === void 0 || value === null) {
5699
- throw new Error(`Invalid engine environment: ${name} is required`);
5700
- }
5701
- return value;
5702
- }
5703
- function requireValidURL(value, name) {
5704
- try {
5705
- new URL(value);
5706
- return value;
5707
- } catch {
5708
- throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
5709
- }
5710
- }
5711
- function parseClaudeAuthMethod(value) {
5712
- if (value === "oauth" || value === "api_key" || value === "bedrock" || value === "foundry") {
5713
- return value;
5714
- }
5715
- return void 0;
5716
- }
5717
- function parseCodexAuthMethod(value) {
5718
- if (value === "oauth" || value === "api_key" || value === "foundry") {
5719
- return value;
5720
- }
5721
- return void 0;
5722
- }
5723
- function parseAgentCredentialSnapshots(value) {
5724
- if (!value) return {};
5725
- try {
5726
- const parsed = JSON.parse(value);
5727
- if (!isRecord4(parsed)) return {};
5728
- const snapshots = {};
5729
- for (const [provider, snapshot] of Object.entries(parsed)) {
5730
- if (!isValidAgentProvider(provider)) continue;
5731
- const parsedSnapshot = agentCredentialSnapshotSchema.safeParse(snapshot);
5732
- if (parsedSnapshot.success) snapshots[provider] = parsedSnapshot.data;
5733
- }
5734
- return snapshots;
5735
- } catch {
5736
- return {};
5737
- }
5738
- }
5739
- var IS_WARMING_MODE = process.argv.includes("--warming");
5740
- function loadEngineEnv() {
5741
- loadRuntimeEnvFile();
5742
- const HOME_DIR = homedir2();
5743
- const env = {
5744
- // Defined: always available
5745
- REPLICAS_ENGINE_SECRET: requireDefined(readEnv("REPLICAS_ENGINE_SECRET"), "REPLICAS_ENGINE_SECRET"),
5746
- REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
5747
- REPLICAS_MONOLITH_URL: requireValidURL(
5748
- requireDefined(readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.monolithUrl), "REPLICAS_MONOLITH_URL"),
5749
- "REPLICAS_MONOLITH_URL"
5750
- ),
5751
- HOME_DIR,
5752
- WORKSPACE_ROOT: join2(HOME_DIR, "workspaces"),
5753
- REPLICAS_SANDBOX_IMAGE_VERSION: readSandboxImageVersion(),
5754
- // Runtime: may not be set during warming
5755
- REPLICAS_WORKSPACE_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.workspaceId),
5756
- REPLICAS_LINEAR_SESSION_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearSessionId),
5757
- REPLICAS_LINEAR_ACCESS_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearAccessToken),
5758
- REPLICAS_SLACK_BOT_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackBotToken),
5759
- REPLICAS_SLACK_CHANNEL_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackChannelId),
5760
- REPLICAS_SLACK_THREAD_TS: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackThreadTs),
5761
- ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
5762
- OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
5763
- CURSOR_API_KEY: readEnv("CURSOR_API_KEY"),
5764
- CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
5765
- AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
5766
- AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
5767
- AWS_REGION: readEnv("AWS_REGION"),
5768
- ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION: readEnv("ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION"),
5769
- REPLICAS_CLAUDE_AUTH_METHOD: parseClaudeAuthMethod(readEnv("REPLICAS_CLAUDE_AUTH_METHOD")),
5770
- REPLICAS_CODEX_AUTH_METHOD: parseCodexAuthMethod(readEnv("REPLICAS_CODEX_AUTH_METHOD")),
5771
- REPLICAS_AGENT_CREDENTIALS: parseAgentCredentialSnapshots(readEnv("REPLICAS_AGENT_CREDENTIALS")),
5772
- REPLICAS_ENV_SYSTEM_PROMPT: readEnv("REPLICAS_ENV_SYSTEM_PROMPT"),
5773
- REPLICAS_ENV_START_HOOK: readEnv("REPLICAS_ENV_START_HOOK"),
5774
- REPLICAS_DISABLE_AUTO_START_HOOKS: readEnv("REPLICAS_DISABLE_AUTO_START_HOOKS")?.toLowerCase() === "true",
5775
- REPLICAS_ENGINE_DEFER_INITIALIZATION: readEnv("REPLICAS_ENGINE_DEFER_INITIALIZATION")?.toLowerCase() === "true"
5776
- };
5777
- if (!IS_WARMING_MODE && !env.REPLICAS_WORKSPACE_ID) {
5778
- console.error("REPLICAS_WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
5647
+ // src/utils/codex-agent-env.ts
5648
+ function buildCodexAgentEnv(source = process.env) {
5649
+ const env = Object.fromEntries(
5650
+ Object.entries(source).filter((entry) => typeof entry[1] === "string")
5651
+ );
5652
+ if (env.REPLICAS_CODEX_AUTH_METHOD === "oauth" || env.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
5653
+ delete env.OPENAI_API_KEY;
5779
5654
  }
5655
+ delete env.GH_TOKEN;
5656
+ delete env.GITHUB_TOKEN;
5657
+ delete env.GH_CONFIG_DIR;
5780
5658
  return env;
5781
5659
  }
5782
- var ENGINE_ENV = loadEngineEnv();
5783
- function setAgentCredentialSnapshot(provider, snapshot) {
5784
- ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS = {
5785
- ...ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS,
5786
- [provider]: snapshot
5787
- };
5788
- process.env.REPLICAS_AGENT_CREDENTIALS = JSON.stringify(ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS);
5789
- }
5790
5660
 
5791
5661
  // src/utils/exec.ts
5792
5662
  import { exec, execFile } from "child_process";
@@ -5988,61 +5858,6 @@ var AspClient = class {
5988
5858
  }
5989
5859
  };
5990
5860
 
5991
- // src/utils/codex-agent-env.ts
5992
- function buildCodexAgentEnv(source = process.env) {
5993
- const env = Object.fromEntries(
5994
- Object.entries(source).filter((entry) => typeof entry[1] === "string")
5995
- );
5996
- if (env.REPLICAS_CODEX_AUTH_METHOD === "oauth" || env.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
5997
- delete env.OPENAI_API_KEY;
5998
- }
5999
- delete env.GH_TOKEN;
6000
- delete env.GITHUB_TOKEN;
6001
- delete env.GH_CONFIG_DIR;
6002
- return env;
6003
- }
6004
-
6005
- // src/utils/agent-env.ts
6006
- function resolveClaudeAuthMethodForMessage(env = ENGINE_ENV) {
6007
- const method = env.REPLICAS_CLAUDE_AUTH_METHOD;
6008
- if (method && method !== "none") {
6009
- return method;
6010
- }
6011
- if (env.CLAUDE_CODE_USE_BEDROCK === "1") return "bedrock";
6012
- if (env.ANTHROPIC_API_KEY) return "api_key";
6013
- return "unknown";
6014
- }
6015
- function buildClaudeAgentEnv(overrides) {
6016
- const env = { ...process.env };
6017
- if (overrides) {
6018
- Object.assign(env, overrides);
6019
- }
6020
- const isBedrock = isClaudeBedrockEnv(env);
6021
- if (shouldStripAnthropicApiKey(isBedrock)) {
6022
- env.ANTHROPIC_API_KEY = void 0;
6023
- }
6024
- if (isBedrock) {
6025
- env.CLAUDE_CODE_USE_BEDROCK = "1";
6026
- env.CLAUDE_CODE_USE_MANTLE = "1";
6027
- env.ANTHROPIC_DEFAULT_OPUS_MODEL = CLAUDE_OPUS_4_8_BEDROCK_MODEL;
6028
- env.ANTHROPIC_DEFAULT_SONNET_MODEL = CLAUDE_SONNET_5_BEDROCK_MODEL;
6029
- env.ANTHROPIC_DEFAULT_HAIKU_MODEL = CLAUDE_HAIKU_4_5_BEDROCK_MODEL;
6030
- }
6031
- env.GH_TOKEN = void 0;
6032
- env.GITHUB_TOKEN = void 0;
6033
- env.GH_CONFIG_DIR = void 0;
6034
- env.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD = "1";
6035
- env.CLAUDE_CODE_DISABLE_AUTO_MEMORY = "1";
6036
- return env;
6037
- }
6038
- function shouldStripAnthropicApiKey(isBedrock) {
6039
- const method = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
6040
- return method === "oauth" || method === "bedrock" || method === "foundry" || isBedrock;
6041
- }
6042
- function isClaudeBedrockEnv(env) {
6043
- return ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock" || env.REPLICAS_CLAUDE_AUTH_METHOD === "bedrock" || env.CLAUDE_CODE_USE_BEDROCK === "1";
6044
- }
6045
-
6046
5861
  // src/managers/codex-asp/app-server-process.ts
6047
5862
  var DEFAULT_CODEX_BINARY = "codex";
6048
5863
  var DEFAULT_CODEX_ARGS = [
@@ -6059,7 +5874,7 @@ var DEFAULT_CODEX_ARGS = [
6059
5874
  var MIN_CODEX_CLI_VERSION = "0.144.6";
6060
5875
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
6061
5876
  var codexCliVersionEnsured = null;
6062
- var ENGINE_PACKAGE_VERSION = "0.1.636";
5877
+ var ENGINE_PACKAGE_VERSION = "0.1.638";
6063
5878
  var INITIALIZE_METHOD = "initialize";
6064
5879
  var INITIALIZED_NOTIFICATION = "initialized";
6065
5880
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -6072,26 +5887,26 @@ var AppServerProcess = class {
6072
5887
  child = null;
6073
5888
  client = null;
6074
5889
  shuttingDown = false;
6075
- constructor(options = {}) {
5890
+ constructor(options) {
6076
5891
  this.binary = options.binary ?? DEFAULT_CODEX_BINARY;
6077
- const baseArgs = options.args ?? (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry" ? [
5892
+ const baseArgs = options.args ?? (options.env.REPLICAS_CODEX_AUTH_METHOD === "foundry" ? [
6078
5893
  ...DEFAULT_CODEX_ARGS,
6079
5894
  "-c",
6080
- `model=${JSON.stringify(process.env.CODEX_FOUNDRY_MODEL)}`,
5895
+ `model=${JSON.stringify(options.env.CODEX_FOUNDRY_MODEL)}`,
6081
5896
  "-c",
6082
5897
  'model_provider="azure"',
6083
5898
  "-c",
6084
5899
  'model_providers.azure.name="Azure OpenAI"',
6085
5900
  "-c",
6086
- `model_providers.azure.base_url=${JSON.stringify(process.env.CODEX_FOUNDRY_BASE_URL)}`,
5901
+ `model_providers.azure.base_url=${JSON.stringify(options.env.CODEX_FOUNDRY_BASE_URL)}`,
6087
5902
  "-c",
6088
5903
  'model_providers.azure.env_key="AZURE_OPENAI_API_KEY"',
6089
5904
  "-c",
6090
5905
  'model_providers.azure.wire_api="responses"'
6091
5906
  ] : DEFAULT_CODEX_ARGS);
6092
5907
  this.args = [...baseArgs, ...(options.configOverrides ?? []).flatMap((override) => ["-c", override])];
6093
- this.env = options.env ?? buildCodexAgentEnv();
6094
- this.cwd = options.cwd ?? ENGINE_ENV.WORKSPACE_ROOT;
5908
+ this.env = options.env;
5909
+ this.cwd = options.cwd;
6095
5910
  }
6096
5911
  on(event, listener) {
6097
5912
  this.emitter.on(event, listener);
@@ -6213,12 +6028,12 @@ var AppServerProcess = class {
6213
6028
  console.warn(`[AppServerProcess] upgraded codex CLI to ${MIN_CODEX_CLI_VERSION}`);
6214
6029
  }
6215
6030
  async loginWithConfiguredApiKey(client) {
6216
- if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD !== "api_key" || !ENGINE_ENV.OPENAI_API_KEY) {
6031
+ if (this.env.REPLICAS_CODEX_AUTH_METHOD !== "api_key" || !this.env.OPENAI_API_KEY) {
6217
6032
  return;
6218
6033
  }
6219
6034
  const params = {
6220
6035
  type: "apiKey",
6221
- apiKey: ENGINE_ENV.OPENAI_API_KEY
6036
+ apiKey: this.env.OPENAI_API_KEY
6222
6037
  };
6223
6038
  await client.request(ACCOUNT_LOGIN_START_METHOD, params);
6224
6039
  }
@@ -6237,6 +6052,43 @@ var AppServerProcess = class {
6237
6052
  }
6238
6053
  };
6239
6054
 
6055
+ // src/managers/codex-asp/notification-dispatch.ts
6056
+ var TURN_STARTED_METHOD = "turn/started";
6057
+ var TURN_COMPLETED_METHOD = "turn/completed";
6058
+ var TURN_PLAN_UPDATED_METHOD = "turn/plan/updated";
6059
+ var THREAD_GOAL_UPDATED_METHOD = "thread/goal/updated";
6060
+ var THREAD_GOAL_CLEARED_METHOD = "thread/goal/cleared";
6061
+ var ITEM_STARTED_METHOD = "item/started";
6062
+ var ITEM_COMPLETED_METHOD = "item/completed";
6063
+ var AGENT_MESSAGE_DELTA_METHOD = "item/agentMessage/delta";
6064
+ var REASONING_SUMMARY_TEXT_DELTA_METHOD = "item/reasoning/summaryTextDelta";
6065
+ var REASONING_TEXT_DELTA_METHOD = "item/reasoning/textDelta";
6066
+ var REASONING_SUMMARY_PART_ADDED_METHOD = "item/reasoning/summaryPartAdded";
6067
+ var COMMAND_EXECUTION_OUTPUT_DELTA_METHOD = "item/commandExecution/outputDelta";
6068
+ var FILE_CHANGE_OUTPUT_DELTA_METHOD = "item/fileChange/outputDelta";
6069
+ var ACCOUNT_RATE_LIMITS_UPDATED_METHOD = "account/rateLimits/updated";
6070
+ var THREAD_TOKEN_USAGE_UPDATED_METHOD = "thread/tokenUsage/updated";
6071
+ var THREAD_COMPACTED_METHOD = "thread/compacted";
6072
+ function dispatchAspNotification(notification, handlers) {
6073
+ const handler = handlers[notification.method];
6074
+ if (!handler) return;
6075
+ handler(notification);
6076
+ }
6077
+ function recoverCompletedTurn(turn, completedItems, agentMessageDeltas) {
6078
+ const items = turn.items.length > 0 ? [...turn.items] : [];
6079
+ const itemIds = new Set(items.map((item) => item.id));
6080
+ for (const item of completedItems) {
6081
+ if (itemIds.has(item.id)) continue;
6082
+ items.push(item);
6083
+ itemIds.add(item.id);
6084
+ }
6085
+ for (const [itemId, text] of agentMessageDeltas) {
6086
+ if (itemIds.has(itemId)) continue;
6087
+ items.push({ type: "agentMessage", id: itemId, text, phase: null, memoryCitation: null });
6088
+ }
6089
+ return items.length > 0 ? { ...turn, items, itemsView: "full" } : turn;
6090
+ }
6091
+
6240
6092
  export {
6241
6093
  isRecord,
6242
6094
  TIMEOUT,
@@ -6249,6 +6101,7 @@ export {
6249
6101
  VALID_THINKING_LEVELS,
6250
6102
  codexReasoningEffortForThinkingLevel,
6251
6103
  detectAgentQuotaLimit,
6104
+ agentCredentialSnapshotSchema,
6252
6105
  isAgentChatTurnActivityRecord,
6253
6106
  isAgentChatSkillActivityRecord,
6254
6107
  isAgentChatMcpActivityRecord,
@@ -6277,6 +6130,9 @@ export {
6277
6130
  CLAUDE_HAIKU_4_5_MODEL,
6278
6131
  CLAUDE_FABLE_5_BEDROCK_MODEL,
6279
6132
  CLAUDE_OPUS_5_BEDROCK_MODEL,
6133
+ CLAUDE_OPUS_4_8_BEDROCK_MODEL,
6134
+ CLAUDE_SONNET_5_BEDROCK_MODEL,
6135
+ CLAUDE_HAIKU_4_5_BEDROCK_MODEL,
6280
6136
  DEFAULT_CLAUDE_MODEL,
6281
6137
  DEFAULT_CODEX_MODEL,
6282
6138
  DEFAULT_CURSOR_MODEL,
@@ -6301,7 +6157,10 @@ export {
6301
6157
  clampTokensToWindow,
6302
6158
  buildCodexTokenUsageContextUsagePayload,
6303
6159
  SANDBOX_PATHS,
6160
+ REPLICAS_RUNTIME_ENV_ALIASES,
6161
+ readReplicasRuntimeEnv,
6304
6162
  shellQuotePosix,
6163
+ parsePosixEnvFile,
6305
6164
  GIT_CREDENTIAL_HELPER_FILENAME,
6306
6165
  GITHUB_CREDENTIAL_REFRESH_PATH,
6307
6166
  GITLAB_CREDENTIAL_REFRESH_PATH,
@@ -6382,14 +6241,27 @@ export {
6382
6241
  isUnsafeMemoryOutput,
6383
6242
  isSkillRegistryManifest,
6384
6243
  putPresignedFile,
6385
- isRecord4 as isRecord2,
6386
- IS_WARMING_MODE,
6387
- ENGINE_ENV,
6388
- setAgentCredentialSnapshot,
6389
- resolveClaudeAuthMethodForMessage,
6390
- buildClaudeAgentEnv,
6244
+ buildCodexAgentEnv,
6391
6245
  execAsync,
6392
6246
  execFileAsync,
6393
6247
  SUBPROCESS_MAX_BUFFER,
6394
- AppServerProcess
6248
+ AppServerProcess,
6249
+ TURN_STARTED_METHOD,
6250
+ TURN_COMPLETED_METHOD,
6251
+ TURN_PLAN_UPDATED_METHOD,
6252
+ THREAD_GOAL_UPDATED_METHOD,
6253
+ THREAD_GOAL_CLEARED_METHOD,
6254
+ ITEM_STARTED_METHOD,
6255
+ ITEM_COMPLETED_METHOD,
6256
+ AGENT_MESSAGE_DELTA_METHOD,
6257
+ REASONING_SUMMARY_TEXT_DELTA_METHOD,
6258
+ REASONING_TEXT_DELTA_METHOD,
6259
+ REASONING_SUMMARY_PART_ADDED_METHOD,
6260
+ COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
6261
+ FILE_CHANGE_OUTPUT_DELTA_METHOD,
6262
+ ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
6263
+ THREAD_TOKEN_USAGE_UPDATED_METHOD,
6264
+ THREAD_COMPACTED_METHOD,
6265
+ dispatchAspNotification,
6266
+ recoverCompletedTurn
6395
6267
  };
@@ -2,10 +2,12 @@
2
2
  import {
3
3
  AGENT,
4
4
  AppServerProcess,
5
+ buildCodexAgentEnv,
5
6
  headlessAgentRequestSchema,
6
7
  isUnsafeMemoryOutput,
7
- putPresignedFile
8
- } from "./chunk-3CX4NHQA.js";
8
+ putPresignedFile,
9
+ recoverCompletedTurn
10
+ } from "./chunk-Z4OLZBZN.js";
9
11
 
10
12
  // src/headless-agent.ts
11
13
  import { createHash } from "crypto";
@@ -57,7 +59,7 @@ async function publishFilesystemOutputs(request) {
57
59
  for (const output of request.outputFiles) {
58
60
  const filePath = resolveFile(request.workingDirectory, output.path);
59
61
  const content = (await readFile(filePath, "utf8")).trim();
60
- if (isUnsafeMemoryOutput(content, request.sensitiveValues, output.maxChars)) {
62
+ if (output.minChars !== void 0 && content.length < output.minChars || isUnsafeMemoryOutput(content, request.sensitiveValues, output.maxChars)) {
61
63
  throw new Error(`Headless agent output failed validation: ${output.path}`);
62
64
  }
63
65
  await writeFile(filePath, content, { mode: 384 });
@@ -120,15 +122,32 @@ async function runClaude(request) {
120
122
  }
121
123
  function runCodexTurn(client, params, timeoutMs) {
122
124
  return new Promise((resolve, reject) => {
125
+ const completedItems = [];
126
+ const messageDeltas = /* @__PURE__ */ new Map();
123
127
  const cleanup = () => {
124
128
  clearTimeout(timeout);
125
129
  client.off("notification", onNotification);
126
130
  client.off("dispose", onDispose);
127
131
  };
128
132
  const onNotification = (notification) => {
133
+ if (notification.method === "item/completed") {
134
+ if (notification.params.threadId !== params.threadId || notification.params.item.type !== "agentMessage") return;
135
+ completedItems.push(notification.params.item);
136
+ return;
137
+ }
138
+ if (notification.method === "item/agentMessage/delta") {
139
+ if (notification.params.threadId !== params.threadId) return;
140
+ messageDeltas.set(
141
+ notification.params.itemId,
142
+ (messageDeltas.get(notification.params.itemId) ?? "") + notification.params.delta
143
+ );
144
+ return;
145
+ }
129
146
  if (notification.method !== "turn/completed" || notification.params.threadId !== params.threadId) return;
147
+ const turn = recoverCompletedTurn(notification.params.turn, completedItems, messageDeltas);
148
+ const message = turn.items.findLast((item) => item.type === "agentMessage")?.text ?? null;
130
149
  cleanup();
131
- resolve(notification.params.turn);
150
+ resolve({ turn, message });
132
151
  };
133
152
  const onDispose = (error) => {
134
153
  cleanup();
@@ -149,6 +168,7 @@ function runCodexTurn(client, params, timeoutMs) {
149
168
  async function runCodex(request) {
150
169
  const appServer = new AppServerProcess({
151
170
  cwd: request.workingDirectory,
171
+ env: buildCodexAgentEnv(),
152
172
  configOverrides: ["shell_environment_policy.inherit=none", "tools.web_search=false"]
153
173
  });
154
174
  try {
@@ -162,24 +182,19 @@ async function runCodex(request) {
162
182
  approvalPolicy: "never",
163
183
  approvalsReviewer: "user",
164
184
  sandbox: request.mode === "filesystem" ? "workspace-write" : "read-only",
165
- ephemeral: true,
166
- environments: [],
167
- dynamicTools: [],
168
- selectedCapabilityRoots: []
185
+ ephemeral: true
169
186
  });
170
- const turn = await runCodexTurn(client, {
187
+ const { turn, message } = await runCodexTurn(client, {
171
188
  threadId: thread.thread.id,
172
189
  input: [{ type: "text", text: request.prompt, text_elements: [] }],
173
190
  ...request.mode === "structured" ? { outputSchema: request.outputSchema } : {},
174
191
  approvalPolicy: "never",
175
- approvalsReviewer: "user",
176
- environments: []
192
+ approvalsReviewer: "user"
177
193
  }, request.timeoutSeconds * 1e3);
178
194
  if (turn.status === "failed") throw new Error(turn.error?.message ?? "Codex ASP turn failed");
179
- const message = turn.items.findLast((item) => item.type === "agentMessage");
180
- if (!message || message.type !== "agentMessage") throw new Error("Codex ASP returned no final message");
181
- if (request.mode === "filesystem") return message.text;
182
- return JSON.parse(message.text);
195
+ if (!message) throw new Error("Codex ASP returned no final message");
196
+ if (request.mode === "filesystem") return message;
197
+ return JSON.parse(message);
183
198
  } finally {
184
199
  await appServer.stop();
185
200
  }