agent-relay-server 0.17.0 → 0.19.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/docs/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Relay API",
5
- "version": "0.16.0",
5
+ "version": "0.17.0",
6
6
  "description": "Real-time message bus for inter-agent communication. Agent-first: this spec is designed for machine consumption — agents can self-discover the full API surface via GET /api/spec.",
7
7
  "license": {
8
8
  "name": "MIT",
@@ -3818,6 +3818,58 @@
3818
3818
  ]
3819
3819
  }
3820
3820
  },
3821
+ "/api/workspaces/actions/cleanup-stale": {
3822
+ "post": {
3823
+ "operationId": "postWorkspaceCleanupStale",
3824
+ "summary": "Post Workspace Cleanup Stale",
3825
+ "tags": [
3826
+ "Other"
3827
+ ],
3828
+ "requestBody": {
3829
+ "required": true,
3830
+ "content": {
3831
+ "application/json": {
3832
+ "schema": {
3833
+ "type": "object",
3834
+ "properties": {
3835
+ "repoRoot": {
3836
+ "type": "string"
3837
+ },
3838
+ "dryRun": {
3839
+ "type": "string"
3840
+ },
3841
+ "landedOnly": {
3842
+ "type": "string"
3843
+ },
3844
+ "offlineOwnerOnly": {
3845
+ "type": "string"
3846
+ }
3847
+ }
3848
+ }
3849
+ }
3850
+ }
3851
+ },
3852
+ "responses": {
3853
+ "200": {
3854
+ "description": "Success",
3855
+ "content": {
3856
+ "application/json": {}
3857
+ }
3858
+ }
3859
+ },
3860
+ "security": [
3861
+ {
3862
+ "bearerAuth": []
3863
+ },
3864
+ {
3865
+ "tokenHeader": []
3866
+ },
3867
+ {
3868
+ "tokenQuery": []
3869
+ }
3870
+ ]
3871
+ }
3872
+ },
3821
3873
  "/api/workspaces/{id}": {
3822
3874
  "get": {
3823
3875
  "operationId": "getWorkspaceById",
@@ -4005,6 +4057,54 @@
4005
4057
  ]
4006
4058
  }
4007
4059
  },
4060
+ "/api/workspaces/{id}/diagnostics": {
4061
+ "get": {
4062
+ "operationId": "getWorkspaceDiagnostics",
4063
+ "summary": "Get Workspace Diagnostics",
4064
+ "tags": [
4065
+ "Other"
4066
+ ],
4067
+ "parameters": [
4068
+ {
4069
+ "name": "id",
4070
+ "in": "path",
4071
+ "required": true,
4072
+ "schema": {
4073
+ "type": "string"
4074
+ }
4075
+ }
4076
+ ],
4077
+ "responses": {
4078
+ "200": {
4079
+ "description": "Success",
4080
+ "content": {
4081
+ "application/json": {}
4082
+ }
4083
+ },
4084
+ "404": {
4085
+ "description": "Not found",
4086
+ "content": {
4087
+ "application/json": {
4088
+ "schema": {
4089
+ "$ref": "#/components/schemas/Error"
4090
+ }
4091
+ }
4092
+ }
4093
+ }
4094
+ },
4095
+ "security": [
4096
+ {
4097
+ "bearerAuth": []
4098
+ },
4099
+ {
4100
+ "tokenHeader": []
4101
+ },
4102
+ {
4103
+ "tokenQuery": []
4104
+ }
4105
+ ]
4106
+ }
4107
+ },
4008
4108
  "/api/workspaces/{id}/diff": {
4009
4109
  "get": {
4010
4110
  "operationId": "getWorkspaceDiff",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-server",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Lightweight HTTP message relay for inter-agent communication across machines",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "CONTRIBUTING.md"
34
34
  ],
35
35
  "dependencies": {
36
- "agent-relay-sdk": "0.2.8"
36
+ "agent-relay-sdk": "0.2.10"
37
37
  },
38
38
  "scripts": {
39
39
  "prepack": "bun run build:dashboard:bundle >&2",
package/public/index.html CHANGED
@@ -10816,6 +10816,25 @@ var PAIR_STATUS_COLORS = {
10816
10816
  expired: "bg-red-500/20 text-red-400"
10817
10817
  };
10818
10818
  //#endregion
10819
+ //#region ../sdk/src/types.ts
10820
+ /** True for a non-null, non-array object. The canonical type guard for the whole repo. */
10821
+ function isRecord(value) {
10822
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10823
+ }
10824
+ /**
10825
+ * Narrow `unknown` to a non-empty trimmed string, else `undefined`.
10826
+ * Settled semantics: whitespace-only is treated as empty (returns `undefined`).
10827
+ */
10828
+ function stringValue(value) {
10829
+ if (typeof value !== "string") return void 0;
10830
+ const trimmed = value.trim();
10831
+ return trimmed.length > 0 ? trimmed : void 0;
10832
+ }
10833
+ /** Extract a human-readable message from any thrown value. */
10834
+ function errMessage(error) {
10835
+ return error instanceof Error ? error.message : String(error);
10836
+ }
10837
+ //#endregion
10819
10838
  //#region src/lib/display.ts
10820
10839
  function toTimestamp(value) {
10821
10840
  const ts = typeof value === "number" ? value : new Date(value || 0).getTime();
@@ -10901,7 +10920,7 @@ function isAgentStale(now, agent) {
10901
10920
  if (!agent?.lastSeen || agent.status === "offline") return false;
10902
10921
  if (agent.id === "user" || agent.id === "system") return false;
10903
10922
  const transport = agent.meta?.transport;
10904
- if (isRecord$2(transport) && transport.connected === true) return false;
10923
+ if (isRecord(transport) && transport.connected === true) return false;
10905
10924
  const lastSeenMs = new Date(agent.lastSeen).getTime();
10906
10925
  if (!Number.isFinite(lastSeenMs)) return false;
10907
10926
  return now - lastSeenMs > 6e4;
@@ -11060,7 +11079,7 @@ function messageMatchesChannel(message, channel) {
11060
11079
  }
11061
11080
  function providerRuntimeState(agent) {
11062
11081
  const raw = agent?.meta?.providerState;
11063
- if (!isRecord$2(raw) || typeof raw.state !== "string") return null;
11082
+ if (!isRecord(raw) || typeof raw.state !== "string") return null;
11064
11083
  return {
11065
11084
  state: raw.state,
11066
11085
  reason: typeof raw.reason === "string" ? raw.reason : void 0,
@@ -11073,16 +11092,16 @@ function providerRuntimeState(agent) {
11073
11092
  };
11074
11093
  }
11075
11094
  function providerPendingApproval(value) {
11076
- if (!isRecord$2(value) || typeof value.id !== "string") return void 0;
11077
- const choices = Array.isArray(value.choices) ? value.choices.filter(isRecord$2).map((choice) => ({
11095
+ if (!isRecord(value) || typeof value.id !== "string") return void 0;
11096
+ const choices = Array.isArray(value.choices) ? value.choices.filter(isRecord).map((choice) => ({
11078
11097
  id: choice.id,
11079
11098
  label: typeof choice.label === "string" ? choice.label : String(choice.id || "")
11080
11099
  })).filter((choice) => (choice.id === "approve" || choice.id === "approve-session" || choice.id === "deny" || choice.id === "abort") && Boolean(choice.label)) : [];
11081
- const questions = Array.isArray(value.questions) ? value.questions.filter(isRecord$2).map((q) => ({
11100
+ const questions = Array.isArray(value.questions) ? value.questions.filter(isRecord).map((q) => ({
11082
11101
  question: typeof q.question === "string" ? q.question : "",
11083
11102
  header: typeof q.header === "string" ? q.header : void 0,
11084
11103
  multiSelect: q.multiSelect === true,
11085
- options: Array.isArray(q.options) ? q.options.filter(isRecord$2).map((o) => ({
11104
+ options: Array.isArray(q.options) ? q.options.filter(isRecord).map((o) => ({
11086
11105
  label: typeof o.label === "string" ? o.label : String(o.label ?? ""),
11087
11106
  description: typeof o.description === "string" ? o.description : void 0
11088
11107
  })).filter((o) => Boolean(o.label)) : []
@@ -11110,7 +11129,7 @@ function activeSubagents(agent) {
11110
11129
  label: `Subagent ${index + 1}`
11111
11130
  })) : [];
11112
11131
  }
11113
- return raw.filter(isRecord$2).map((item, index) => {
11132
+ return raw.filter(isRecord).map((item, index) => {
11114
11133
  const id = typeof item.id === "string" && item.id ? item.id : `subagent-${index + 1}`;
11115
11134
  const role = typeof item.role === "string" && item.role ? item.role : void 0;
11116
11135
  return {
@@ -11256,9 +11275,6 @@ function presenceBadges(agent, attention, pair) {
11256
11275
  });
11257
11276
  return badges;
11258
11277
  }
11259
- function isRecord$2(value) {
11260
- return typeof value === "object" && value !== null && !Array.isArray(value);
11261
- }
11262
11278
  function emptyAttention() {
11263
11279
  return {
11264
11280
  unread: 0,
@@ -11525,7 +11541,7 @@ function downloadText(filename, text, type) {
11525
11541
  URL.revokeObjectURL(url);
11526
11542
  }
11527
11543
  //#endregion
11528
- //#region ../sdk/dist/provider-catalog.js
11544
+ //#region ../sdk/src/provider-catalog.ts
11529
11545
  var CLAUDE_LOW_TO_MAX = [
11530
11546
  "low",
11531
11547
  "medium",
@@ -108614,9 +108630,6 @@ function workspaceMode(agent) {
108614
108630
  function recordValue(value) {
108615
108631
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
108616
108632
  }
108617
- function stringValue(value) {
108618
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
108619
- }
108620
108633
  function runtimeBadges(agent) {
108621
108634
  const caps = agent.providerCapabilities;
108622
108635
  const context = agent.context;
@@ -123768,7 +123781,7 @@ function TerminalViewer({ orchestratorId, session, interactive: initialInteracti
123768
123781
  try {
123769
123782
  writeSnapshot(await apiCall("GET", `/orchestrators/${encodeURIComponent(orchestratorId)}/terminal/${encodeURIComponent(session)}`));
123770
123783
  } catch (e) {
123771
- setError(e instanceof Error ? e.message : String(e));
123784
+ setError(errMessage(e));
123772
123785
  } finally {
123773
123786
  inFlightRef.current = false;
123774
123787
  }
@@ -123825,7 +123838,7 @@ function TerminalViewer({ orchestratorId, session, interactive: initialInteracti
123825
123838
  for (const chunk of chunks) inputQueueRef.current = inputQueueRef.current.then(() => apiCall("POST", `/orchestrators/${encodeURIComponent(orchestratorId)}/terminal/${encodeURIComponent(session)}/input`, { data: chunk })).then(() => {
123826
123839
  setError(null);
123827
123840
  }).catch((e) => {
123828
- setError(e instanceof Error ? e.message : String(e));
123841
+ setError(errMessage(e));
123829
123842
  });
123830
123843
  }
123831
123844
  function handleTerminalData(data) {
@@ -124420,7 +124433,7 @@ function useFileRead(orchestratorId, selectedPath) {
124420
124433
  }).catch((e) => {
124421
124434
  if (!cancelled) {
124422
124435
  setFile(null);
124423
- setError(e instanceof Error ? e.message : String(e));
124436
+ setError(errMessage(e));
124424
124437
  }
124425
124438
  }).finally(() => {
124426
124439
  if (!cancelled) setLoading(false);
@@ -124458,7 +124471,7 @@ function useFileListing(orchestratorId, selectedPath, git = false) {
124458
124471
  }).catch((e) => {
124459
124472
  if (!cancelled) {
124460
124473
  setListing(null);
124461
- setError(e instanceof Error ? e.message : String(e));
124474
+ setError(errMessage(e));
124462
124475
  }
124463
124476
  }).finally(() => {
124464
124477
  if (!cancelled) setLoading(false);
@@ -124774,7 +124787,7 @@ function FileBrowser({ overlay = false }) {
124774
124787
  setPathDraft(result.path);
124775
124788
  setReadError("");
124776
124789
  } catch (e) {
124777
- setError(e instanceof Error ? e.message : String(e));
124790
+ setError(errMessage(e));
124778
124791
  } finally {
124779
124792
  setLoading(false);
124780
124793
  }
@@ -128115,7 +128128,7 @@ function LogViewer({ orchestratorId, session, lines = 200 }) {
128115
128128
  setLogLines((await apiCall("GET", `/orchestrators/${encodeURIComponent(orchestratorId)}/logs/${encodeURIComponent(session)}?lines=${lines}${stream === "mirror" ? "&stream=mirror" : ""}`)).lines || []);
128116
128129
  setError(null);
128117
128130
  } catch (e) {
128118
- setError(e instanceof Error ? e.message : String(e));
128131
+ setError(errMessage(e));
128119
128132
  }
128120
128133
  }
128121
128134
  (0, import_react.useEffect)(() => {
@@ -152917,7 +152930,7 @@ function InsightsView() {
152917
152930
  setProjects(obs.projects);
152918
152931
  setNow(Date.now());
152919
152932
  } catch (e) {
152920
- setError(e instanceof Error ? e.message : String(e));
152933
+ setError(errMessage(e));
152921
152934
  }
152922
152935
  }
152923
152936
  (0, import_react.useEffect)(() => {
@@ -152937,7 +152950,7 @@ function InsightsView() {
152937
152950
  setVersion(entry.version);
152938
152951
  } catch (e) {
152939
152952
  setConfig(previous);
152940
- setError(e instanceof Error ? e.message : String(e));
152953
+ setError(errMessage(e));
152941
152954
  } finally {
152942
152955
  setSaving(false);
152943
152956
  }
@@ -154067,7 +154080,7 @@ function AgentDiagnostics({ agent, orchestrators }) {
154067
154080
  });
154068
154081
  const policyName = typeof agent.meta?.policyName === "string" ? agent.meta.policyName : null;
154069
154082
  const profileName = typeof agent.meta?.profile === "string" ? agent.meta.profile : null;
154070
- const agentProfile = isRecord$1(agent.meta?.agentProfile) ? agent.meta.agentProfile : null;
154083
+ const agentProfile = isRecord(agent.meta?.agentProfile) ? agent.meta.agentProfile : null;
154071
154084
  const profileProjection = isProfileProjectionReport(agentProfile?.projection) ? agentProfile.projection : null;
154072
154085
  const managedOrch = orchestrators.find((o) => o.managedAgents.some((m) => m.agentId === agent.id));
154073
154086
  const managedAgent = managedOrch?.managedAgents.find((m) => m.agentId === agent.id);
@@ -154558,11 +154571,8 @@ function CollapsibleSection({ title, expanded, onToggle, children }) {
154558
154571
  })]
154559
154572
  });
154560
154573
  }
154561
- function isRecord$1(value) {
154562
- return typeof value === "object" && value !== null && !Array.isArray(value);
154563
- }
154564
154574
  function isProfileProjectionReport(value) {
154565
- return isRecord$1(value) && typeof value.profileName === "string" && typeof value.provider === "string" && typeof value.base === "string" && Array.isArray(value.entries) && Array.isArray(value.warnings) && Array.isArray(value.unsupported);
154575
+ return isRecord(value) && typeof value.profileName === "string" && typeof value.provider === "string" && typeof value.base === "string" && Array.isArray(value.entries) && Array.isArray(value.warnings) && Array.isArray(value.unsupported);
154566
154576
  }
154567
154577
  function KV({ label, value, className = "", mono = false }) {
154568
154578
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
@@ -155753,9 +155763,6 @@ function orchestratorForAgentTerminal(agent, session, orchestrators) {
155753
155763
  if (!agent) return null;
155754
155764
  return orchestrators.find((orchestrator) => orchestrator.managedAgents.some((managed) => managed.agentId === agent.id || managed.tmuxSession === session)) ?? null;
155755
155765
  }
155756
- function isRecord(value) {
155757
- return typeof value === "object" && value !== null && !Array.isArray(value);
155758
- }
155759
155766
  //#endregion
155760
155767
  //#region src/components/drawers/channel-detail-drawer.tsx
155761
155768
  function ChannelDetailDrawer() {
@@ -156467,7 +156474,7 @@ function DirectoryBrowserDialog({ open, onOpenChange, onSelect, orchestratorId,
156467
156474
  const query = path ? `?path=${encodeURIComponent(path)}` : "";
156468
156475
  setListing(await apiCall("GET", `/orchestrators/${encodeURIComponent(orchestratorId)}/directories${query}`));
156469
156476
  } catch (e) {
156470
- setError(e instanceof Error ? e.message : String(e));
156477
+ setError(errMessage(e));
156471
156478
  } finally {
156472
156479
  setLoading(false);
156473
156480
  }
@@ -156491,7 +156498,7 @@ function DirectoryBrowserDialog({ open, onOpenChange, onSelect, orchestratorId,
156491
156498
  setCreating(false);
156492
156499
  setNewDirName("");
156493
156500
  } catch (e) {
156494
- setCreateError(e instanceof Error ? e.message : String(e));
156501
+ setCreateError(errMessage(e));
156495
156502
  }
156496
156503
  }
156497
156504
  function handleSelect() {
package/public/sw.js CHANGED
@@ -1,4 +1,4 @@
1
- const CACHE_NAME = "agent-relay-dashboard-v1";
1
+ const CACHE_NAME = "agent-relay-dashboard-v2";
2
2
  const scopeUrl = new URL(self.registration.scope);
3
3
  const scopePath = scopeUrl.pathname.endsWith("/") ? scopeUrl.pathname : `${scopeUrl.pathname}/`;
4
4
  const appUrl = (path) => new URL(path, self.registration.scope).toString();
@@ -11,10 +11,30 @@ const APP_SHELL = [
11
11
  appUrl("icons/agent-relay-512.png"),
12
12
  ];
13
13
 
14
+ // The server may send the shell brotli/gzip-encoded. fetch() exposes the body
15
+ // already decoded but leaves Content-Encoding / Content-Length headers on the
16
+ // response — caching that verbatim risks a double-decode or
17
+ // ERR_CONTENT_LENGTH_MISMATCH on replay. Re-wrap with those headers stripped so
18
+ // the cached copy is clean identity bytes.
19
+ async function cacheNormalized(cache, key, response) {
20
+ const body = await response.clone().arrayBuffer();
21
+ const headers = new Headers(response.headers);
22
+ headers.delete("Content-Encoding");
23
+ headers.delete("Content-Length");
24
+ await cache.put(key, new Response(body, {
25
+ status: response.status,
26
+ statusText: response.statusText,
27
+ headers,
28
+ }));
29
+ }
30
+
14
31
  self.addEventListener("install", (event) => {
15
32
  event.waitUntil(
16
33
  caches.open(CACHE_NAME)
17
- .then((cache) => cache.addAll(APP_SHELL))
34
+ .then((cache) => Promise.all(APP_SHELL.map(async (href) => {
35
+ const response = await fetch(href, { cache: "reload" });
36
+ if (response.ok) await cacheNormalized(cache, href, response);
37
+ })))
18
38
  .then(() => self.skipWaiting()),
19
39
  );
20
40
  });
@@ -45,20 +65,35 @@ self.addEventListener("fetch", (event) => {
45
65
  return;
46
66
  }
47
67
 
68
+ // Stale-while-revalidate for the app shell and SPA navigations: serve the
69
+ // cached bundle instantly (the ~10 MB unminified shell never blocks the
70
+ // network on a slow/high-latency link) and refresh it in the background.
71
+ // SPA route navigations all resolve to index.html, so key them there to avoid
72
+ // fragmenting the cache by query string / deep-link path.
73
+ const isNavigation = request.mode === "navigate";
74
+ if (isNavigation || APP_SHELL.includes(url.href)) {
75
+ event.respondWith(staleWhileRevalidate(request, isNavigation ? appUrl("index.html") : request));
76
+ return;
77
+ }
78
+
79
+ // Other same-scope assets: network-first, fall back to cache when offline.
48
80
  event.respondWith(
49
- fetch(request)
50
- .then((response) => {
51
- if (response.ok && APP_SHELL.includes(url.href)) {
52
- const copy = response.clone();
53
- caches.open(CACHE_NAME).then((cache) => cache.put(request, copy));
54
- }
55
- return response;
56
- })
57
- .catch(async () => {
58
- const cached = await caches.match(request);
59
- if (cached) return cached;
60
- if (request.mode === "navigate") return caches.match(appUrl("index.html"));
61
- throw new Error("offline");
62
- }),
81
+ fetch(request).catch(() => caches.match(request).then((c) => {
82
+ if (c) return c;
83
+ throw new Error("offline");
84
+ })),
63
85
  );
64
86
  });
87
+
88
+ async function staleWhileRevalidate(request, cacheKey) {
89
+ const cache = await caches.open(CACHE_NAME);
90
+ const cached = await cache.match(cacheKey);
91
+ const network = fetch(request)
92
+ .then(async (response) => {
93
+ if (response.ok) await cacheNormalized(cache, cacheKey, response);
94
+ return response;
95
+ })
96
+ .catch(() => cached);
97
+ // Return cache immediately when present; otherwise wait for the network.
98
+ return cached || network;
99
+ }
@@ -1,4 +1,5 @@
1
1
  import type { AgentProfile, Message } from "agent-relay-sdk";
2
+ import { isRecord } from "agent-relay-sdk";
2
3
 
3
4
  export type SemanticStatus = "idle" | "busy" | "offline" | "error";
4
5
  type ProviderWorkKind = "provider-turn" | "subagent";
@@ -160,10 +161,6 @@ export const RELAY_CONTEXT = `[agent-relay] You are connected to Agent Relay, a
160
161
 
161
162
  const PROVIDER_MESSAGE_BODY_PREVIEW_CHARS = 4000;
162
163
 
163
- function isRecord(value: unknown): value is Record<string, unknown> {
164
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
165
- }
166
-
167
164
  function attachmentRefs(message: Message): Record<string, unknown>[] {
168
165
  const payloadRefs = message.payload?.attachments;
169
166
  const topLevelRefs = (message as Message & { attachments?: unknown }).attachments;
@@ -1,6 +1,8 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { homedir, hostname } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
+ import { stringValue } from "agent-relay-sdk";
5
+ import { sanitizeFsName } from "agent-relay-sdk/fs-name";
4
6
  import type { ProviderConfig } from "./adapter";
5
7
 
6
8
  interface GlobalRunnerConfig {
@@ -97,7 +99,7 @@ export function providerConfigPublic(config: LoadedProviderConfig): Record<strin
97
99
 
98
100
  export function runnerId(provider: string, cwd: string, label?: string): string {
99
101
  const project = cwd.split("/").filter(Boolean).at(-1) || "workspace";
100
- const cleanLabel = (label || project).replace(/[^a-zA-Z0-9._-]+/g, "-").toLowerCase();
102
+ const cleanLabel = sanitizeFsName(label || project, { replacement: "-", lowercase: true });
101
103
  return `${hostname()}-${provider}-${cleanLabel}-${crypto.randomUUID().slice(0, 8)}`;
102
104
  }
103
105
 
@@ -115,10 +117,6 @@ function readJson(path: string): Record<string, unknown> {
115
117
  }
116
118
  }
117
119
 
118
- function stringValue(value: unknown): string | undefined {
119
- return typeof value === "string" && value.length > 0 ? value : undefined;
120
- }
121
-
122
120
  function positiveInteger(value: unknown): number | undefined {
123
121
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
124
122
  }
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { hostname } from "node:os";
3
+ import { RELAY_TOKEN_HEADER } from "agent-relay-sdk";
3
4
 
4
5
  type Orchestrator = {
5
6
  id: string;
@@ -44,7 +45,7 @@ relayUrl = relayUrl.replace(/\/+$/, "");
44
45
 
45
46
  function headers(): Record<string, string> {
46
47
  const h: Record<string, string> = { "Content-Type": "application/json" };
47
- if (process.env.AGENT_RELAY_TOKEN) h["X-Agent-Relay-Token"] = process.env.AGENT_RELAY_TOKEN;
48
+ if (process.env.AGENT_RELAY_TOKEN) h[RELAY_TOKEN_HEADER] = process.env.AGENT_RELAY_TOKEN;
48
49
  return h;
49
50
  }
50
51