agent-relay-server 0.4.10 → 0.4.11

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/README.md CHANGED
@@ -224,6 +224,9 @@ time, it starts a new thread by default to avoid surprising cwd-based attachment
224
224
  to an unrelated loaded session. Use `codex-relay --thread-mode auto` or
225
225
  `AGENT_RELAY_CODEX_FALLBACK_THREAD_MODE=auto` when you deliberately want the
226
226
  fallback sidecar to attach to the newest loaded thread for the current cwd.
227
+ The lower-level sidecar also defaults to `CODEX_THREAD_MODE=start`; `auto` is an
228
+ explicit opt-in because it may deliver relay messages into an already-open Codex
229
+ session for the same directory.
227
230
 
228
231
  ### Codex approval mode
229
232
 
package/codex/README.md CHANGED
@@ -12,9 +12,9 @@ This sidecar connects to a Codex app-server session and to Agent Relay, then del
12
12
 
13
13
  ## Current behavior
14
14
 
15
- - attaches to a loaded thread for the current `cwd` when one exists
16
- - otherwise resumes the newest thread for the current `cwd`
17
- - otherwise creates a new thread
15
+ - starts a new thread by default
16
+ - resumes the actual launched thread when the SessionStart hook provides a thread id
17
+ - only attaches to loaded/latest same-cwd threads when `CODEX_THREAD_MODE=auto`
18
18
  - registers a relay agent with `client: codex-live`
19
19
  - marks the relay agent `ready=true` once app-server + thread are attached
20
20
  - polls relay inbox and delivers messages into the live thread
@@ -131,6 +131,6 @@ startup in time.
131
131
 
132
132
  Current sidecar behavior is stable for live delivery. Remaining gaps are advanced policies such as batching by sender, message prioritization queues, and more nuanced retry/backoff behavior.
133
133
 
134
- - `CODEX_THREAD_MODE=auto` will attach to an already loaded thread for the same `cwd`. That is what you want for real live control, but it also means the sidecar can attach to your current interactive Codex session if one is already open.
135
- - For isolated testing, set `CODEX_THREAD_MODE=start` so the sidecar always creates its own thread.
134
+ - `CODEX_THREAD_MODE=start` is the safe default: the sidecar creates its own thread unless the hook supplied an explicit thread id.
135
+ - `CODEX_THREAD_MODE=auto` will attach to an already loaded thread for the same `cwd`. That can be useful for advanced live control, but it also means relay messages can enter your current interactive Codex session if one is already open.
136
136
  - A brand-new thread is not materialized for `includeTurns` reads until the first turn starts. That is an app-server behavior, not a relay bug.
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { loadConfig, parseThreadMode } from "./live-sidecar";
3
+
4
+ describe("codex live sidecar config", () => {
5
+ it("defaults to starting an isolated thread", () => {
6
+ const config = loadConfig({
7
+ CODEX_LIVE_CWD: "/tmp/agent-relay-test",
8
+ });
9
+
10
+ expect(config.threadMode).toBe("start");
11
+ });
12
+
13
+ it("only accepts known thread attachment modes", () => {
14
+ expect(parseThreadMode("auto")).toBe("auto");
15
+ expect(parseThreadMode("resume")).toBe("resume");
16
+ expect(parseThreadMode("start")).toBe("start");
17
+ expect(parseThreadMode("latest")).toBe("start");
18
+ expect(parseThreadMode(undefined)).toBe("start");
19
+ });
20
+ });
@@ -572,38 +572,43 @@ function describeError(error: unknown): string {
572
572
  return error instanceof Error ? error.message : String(error);
573
573
  }
574
574
 
575
- function envNumber(name: string, fallback: number): number {
576
- const raw = process.env[name];
575
+ function envNumber(env: NodeJS.ProcessEnv, name: string, fallback: number): number {
576
+ const raw = env[name];
577
577
  if (!raw) return fallback;
578
578
  const parsed = Number(raw);
579
579
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
580
580
  }
581
581
 
582
- function loadConfig(): Config {
583
- const cwd = process.env.CODEX_LIVE_CWD || process.cwd();
584
- const capabilities = (process.env.AGENT_RELAY_CAPS || "chat")
582
+ export function parseThreadMode(raw: string | undefined): Config["threadMode"] {
583
+ if (raw === "auto" || raw === "resume" || raw === "start") return raw;
584
+ return "start";
585
+ }
586
+
587
+ export function loadConfig(env: NodeJS.ProcessEnv = process.env): Config {
588
+ const cwd = env.CODEX_LIVE_CWD || process.cwd();
589
+ const capabilities = (env.AGENT_RELAY_CAPS || "chat")
585
590
  .split(",")
586
591
  .map((value) => value.trim())
587
592
  .filter(Boolean);
588
593
 
589
594
  return {
590
- relayUrl: process.env.AGENT_RELAY_URL || "http://127.0.0.1:4850",
591
- appServerUrl: process.env.CODEX_APP_SERVER_URL || "ws://127.0.0.1:4501",
595
+ relayUrl: env.AGENT_RELAY_URL || "http://127.0.0.1:4850",
596
+ appServerUrl: env.CODEX_APP_SERVER_URL || "ws://127.0.0.1:4501",
592
597
  cwd,
593
- rig: process.env.CODEX_LIVE_RIG || "codex-live",
598
+ rig: env.CODEX_LIVE_RIG || "codex-live",
594
599
  capabilities,
595
- tags: ["codex", process.env.CODEX_LIVE_RIG || "codex-live", cwd.split("/").filter(Boolean).at(-1) || "unknown"],
596
- statePath: process.env.CODEX_LIVE_STATE_PATH || resolve(cwd, "codex/runtime/live-state.json"),
597
- pollIntervalMs: envNumber("CODEX_LIVE_POLL_INTERVAL_MS", 2000),
598
- heartbeatIntervalMs: envNumber("CODEX_LIVE_HEARTBEAT_INTERVAL_MS", 30000),
599
- coalesceWindowMs: envNumber("CODEX_LIVE_COALESCE_WINDOW_MS", 600),
600
- reconnectInitialDelayMs: envNumber("CODEX_LIVE_RECONNECT_INITIAL_MS", 1000),
601
- reconnectMaxDelayMs: envNumber("CODEX_LIVE_RECONNECT_MAX_MS", 10000),
602
- threadMode: (process.env.CODEX_THREAD_MODE as Config["threadMode"]) || "auto",
603
- threadId: process.env.CODEX_THREAD_ID || undefined,
604
- model: process.env.CODEX_MODEL || undefined,
605
- approvalPolicy: process.env.CODEX_LIVE_APPROVAL_POLICY || undefined,
606
- sandbox: process.env.CODEX_LIVE_SANDBOX || undefined,
600
+ tags: ["codex", env.CODEX_LIVE_RIG || "codex-live", cwd.split("/").filter(Boolean).at(-1) || "unknown"],
601
+ statePath: env.CODEX_LIVE_STATE_PATH || resolve(cwd, "codex/runtime/live-state.json"),
602
+ pollIntervalMs: envNumber(env, "CODEX_LIVE_POLL_INTERVAL_MS", 2000),
603
+ heartbeatIntervalMs: envNumber(env, "CODEX_LIVE_HEARTBEAT_INTERVAL_MS", 30000),
604
+ coalesceWindowMs: envNumber(env, "CODEX_LIVE_COALESCE_WINDOW_MS", 600),
605
+ reconnectInitialDelayMs: envNumber(env, "CODEX_LIVE_RECONNECT_INITIAL_MS", 1000),
606
+ reconnectMaxDelayMs: envNumber(env, "CODEX_LIVE_RECONNECT_MAX_MS", 10000),
607
+ threadMode: parseThreadMode(env.CODEX_THREAD_MODE),
608
+ threadId: env.CODEX_THREAD_ID || undefined,
609
+ model: env.CODEX_MODEL || undefined,
610
+ approvalPolicy: env.CODEX_LIVE_APPROVAL_POLICY || undefined,
611
+ sandbox: env.CODEX_LIVE_SANDBOX || undefined,
607
612
  };
608
613
  }
609
614
 
@@ -613,7 +618,9 @@ async function main(): Promise<void> {
613
618
  await sidecar.run();
614
619
  }
615
620
 
616
- main().catch((error) => {
617
- console.error(error instanceof Error ? error.stack || error.message : String(error));
618
- process.exit(1);
619
- });
621
+ if (import.meta.main) {
622
+ main().catch((error) => {
623
+ console.error(error instanceof Error ? error.stack || error.message : String(error));
624
+ process.exit(1);
625
+ });
626
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Agent Relay integration for Codex sessions",
5
5
  "author": {
6
6
  "name": "Edin Mujkanovic"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",