@copilotkit/core 1.78.0 → 1.79.1-canary.1792034358

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/index.cjs CHANGED
@@ -26,6 +26,15 @@ function ɵisHttpAgent(agent) {
26
26
 
27
27
  //#endregion
28
28
  //#region src/utils/connect-replay.ts
29
+ const connectRunErrorPhases = /* @__PURE__ */ new WeakMap();
30
+ /**
31
+ * The phase in which a connection received `event`, as recorded when it
32
+ * arrived. Events that did not come through a connection with replay
33
+ * boundaries report `unknown`.
34
+ */
35
+ function ɵgetConnectRunErrorPhase(event) {
36
+ return connectRunErrorPhases.get(event) ?? "unknown";
37
+ }
29
38
  /**
30
39
  * Runs an agent's `connect()` stream through the AbstractAgent apply pipeline
31
40
  * with the `verifyEvents` step omitted.
@@ -80,6 +89,7 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
80
89
  let result;
81
90
  const previousMessageIds = new Set(agent.messages.map((m) => m.id));
82
91
  let isReplaying = true;
92
+ let reportsReplayPhase = false;
83
93
  const liveErrors = /* @__PURE__ */ new WeakSet();
84
94
  const subscribers = [
85
95
  {
@@ -127,15 +137,19 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
127
137
  };
128
138
  const lifecycle = {
129
139
  onReplayStarted: () => {
140
+ reportsReplayPhase = true;
130
141
  isReplaying = true;
131
142
  agent.isRunning = true;
132
143
  },
133
144
  onReplayFinished: () => {
145
+ reportsReplayPhase = true;
134
146
  isReplaying = false;
135
147
  }
136
148
  };
137
149
  const source$ = (0, rxjs.defer)(() => new _ag_ui_client.CompatibilityBoundary().run(input, { run: () => connect ? connect(input, lifecycle) : self.connect(input) })).pipe((0, rxjs_operators.tap)((event) => {
138
- if (!isReplaying && event.type === _ag_ui_client.EventType.RUN_ERROR) liveErrors.add(event);
150
+ if (event.type !== _ag_ui_client.EventType.RUN_ERROR) return;
151
+ if (!isReplaying) liveErrors.add(event);
152
+ if (reportsReplayPhase) connectRunErrorPhases.set(event, isReplaying ? "replay" : "live");
139
153
  }), (0, _ag_ui_client.transformChunks)(self.debugLogger), (0, rxjs_operators.takeUntil)(activeRunDetach$));
140
154
  const applied$ = self.apply(input, source$, subscribers);
141
155
  await (0, rxjs.lastValueFrom)(self.processApplyEvents(input, applied$, subscribers).pipe((0, rxjs_operators.catchError)((error) => {
@@ -302,6 +316,20 @@ var AgentThreadLockedError = class extends Error {
302
316
  }
303
317
  };
304
318
  /**
319
+ * The gateway could not replay a live run's events, so the client cannot
320
+ * verify the run it is following. The run itself may still be going on the
321
+ * server; reconnecting to the thread shows its real state.
322
+ */
323
+ var IntelligenceReplayFailedError = class extends Error {
324
+ code = "INTELLIGENCE_REPLAY_FAILED";
325
+ constructor(threadId, runId) {
326
+ super("The run's events could not be replayed. Reconnect to the thread to check the run's status.");
327
+ this.threadId = threadId;
328
+ this.runId = runId;
329
+ this.name = "IntelligenceReplayFailedError";
330
+ }
331
+ };
332
+ /**
305
333
  * Type guard for {@link RunCompletionAware}. Returns true when `agent` exposes
306
334
  * an `activeRunCompletionPromise` property, so callers can await an in-flight
307
335
  * run without an `as unknown as` cast. Returns false for agents that don't
@@ -627,6 +655,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
627
655
  };
628
656
  const replayFailed$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, REPLAY_FAILED_EVENT)), (0, rxjs_operators.tap)(() => {
629
657
  controlCursor.replayFailed = true;
658
+ if (options.streamMode === "run") throw new IntelligenceReplayFailedError(credentials.threadId, credentials.runId);
630
659
  }));
631
660
  const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT, controlCursor).pipe((0, rxjs_operators.tap)(() => {
632
661
  replayFinished = true;
@@ -1104,7 +1133,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1104
1133
  ...this.headers,
1105
1134
  "Content-Type": "application/json"
1106
1135
  });
1107
- fetch(this.singleEndpointUrl, {
1136
+ this.fetch(this.singleEndpointUrl, {
1108
1137
  method: "POST",
1109
1138
  headers,
1110
1139
  body: JSON.stringify({
@@ -1115,7 +1144,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1115
1144
  },
1116
1145
  ...runId === void 0 ? {} : { body: { runId } }
1117
1146
  }),
1118
- ...this.credentials ? { credentials: this.credentials } : {}
1147
+ ...this.credentials ? { credentials: this.credentials } : {},
1148
+ ɵruntimeRequest: { nonCritical: true }
1119
1149
  }).catch((error) => {
1120
1150
  console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
1121
1151
  });
@@ -1126,14 +1156,15 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1126
1156
  const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
1127
1157
  const base = new URL(this.runtimeUrl, origin);
1128
1158
  const stopUrl = new URL(stopPath, base);
1129
- fetch(stopUrl.toString(), {
1159
+ this.fetch(stopUrl.toString(), {
1130
1160
  method: "POST",
1131
1161
  headers: {
1132
1162
  "Content-Type": "application/json",
1133
1163
  ...this.headers
1134
1164
  },
1135
1165
  ...runId === void 0 ? {} : { body: JSON.stringify({ runId }) },
1136
- ...this.credentials ? { credentials: this.credentials } : {}
1166
+ ...this.credentials ? { credentials: this.credentials } : {},
1167
+ ɵruntimeRequest: { nonCritical: true }
1137
1168
  }).catch((error) => {
1138
1169
  console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
1139
1170
  });
@@ -1549,6 +1580,183 @@ async function createSingleRouteResourceRequest(input, init, runtimeUrl) {
1549
1580
  };
1550
1581
  }
1551
1582
 
1583
+ //#endregion
1584
+ //#region src/core/header-source.ts
1585
+ var CopilotKitHeaderResolutionError = class extends Error {
1586
+ name = "CopilotKitHeaderResolutionError";
1587
+ constructor(cause) {
1588
+ super("[CopilotKit] Failed to resolve request headers", { cause });
1589
+ }
1590
+ };
1591
+ function isHeaderResolutionError(error) {
1592
+ let current = error;
1593
+ for (let depth = 0; depth < 5 && current; depth++) {
1594
+ if (current instanceof CopilotKitHeaderResolutionError) return true;
1595
+ current = current.cause;
1596
+ }
1597
+ return false;
1598
+ }
1599
+ function isPromiseLike(value) {
1600
+ return typeof value === "object" && value !== null && typeof value.then === "function";
1601
+ }
1602
+ /**
1603
+ * Normalize a header map to a `Record<string, string>` with no `null` or
1604
+ * `undefined` values. Dropping an entry is how a header is cleared.
1605
+ */
1606
+ function normalizeHeaders(headers) {
1607
+ return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
1608
+ }
1609
+ /** Same keys, same values (order-independent). */
1610
+ function shallowEqualRecord(a, b) {
1611
+ const aKeys = Object.keys(a);
1612
+ const bKeys = Object.keys(b);
1613
+ if (aKeys.length !== bKeys.length) return false;
1614
+ return aKeys.every((key) => a[key] === b[key]);
1615
+ }
1616
+ function isHeaderRecordInput(value) {
1617
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1618
+ }
1619
+ /**
1620
+ * Owns the headers source for one core. Resolution is synchronous for a
1621
+ * record or a sync builder, so those callers never pay an extra await.
1622
+ */
1623
+ var HeaderSourceResolver = class {
1624
+ source = {};
1625
+ sourceGeneration = 0;
1626
+ snapshot = {};
1627
+ inFlight;
1628
+ constructor(onFailure) {
1629
+ this.onFailure = onFailure;
1630
+ }
1631
+ /** The last resolved headers. Not necessarily current for a builder. */
1632
+ get headers() {
1633
+ return this.snapshot;
1634
+ }
1635
+ /** Bumped on every accepted `setSource`, never by a new token. */
1636
+ get generation() {
1637
+ return this.sourceGeneration;
1638
+ }
1639
+ /**
1640
+ * Returns false when a builder with the same identity is set again, or
1641
+ * when a record replaces another record with equal normalized values (a
1642
+ * caller re-passing an equivalent literal on every re-render must not
1643
+ * bump the generation). A record replacing a builder, a builder replacing
1644
+ * a record, and a new builder function all still count as a change.
1645
+ */
1646
+ setSource(source) {
1647
+ if (typeof source === "function" && source === this.source) return false;
1648
+ const nextSnapshot = typeof source === "function" ? {} : normalizeHeaders(source);
1649
+ if (typeof source !== "function" && typeof this.source !== "function" && shallowEqualRecord(nextSnapshot, this.snapshot)) return false;
1650
+ this.source = source;
1651
+ this.sourceGeneration += 1;
1652
+ this.inFlight = void 0;
1653
+ this.snapshot = nextSnapshot;
1654
+ return true;
1655
+ }
1656
+ resolve() {
1657
+ const source = this.source;
1658
+ if (typeof source !== "function") return this.snapshot;
1659
+ const generation = this.sourceGeneration;
1660
+ if (this.inFlight?.generation === generation) return this.inFlight.promise;
1661
+ let value;
1662
+ try {
1663
+ value = source();
1664
+ } catch (error) {
1665
+ throw this.fail(error);
1666
+ }
1667
+ if (!isPromiseLike(value)) return this.accept(value, generation);
1668
+ const promise = Promise.resolve(value).then((resolved) => this.accept(resolved, generation), (error) => {
1669
+ throw this.fail(error);
1670
+ }).finally(() => {
1671
+ if (this.inFlight?.promise === promise) this.inFlight = void 0;
1672
+ });
1673
+ this.inFlight = {
1674
+ generation,
1675
+ promise
1676
+ };
1677
+ return promise;
1678
+ }
1679
+ accept(value, generation) {
1680
+ if (!isHeaderRecordInput(value)) throw this.fail(/* @__PURE__ */ new TypeError("headers builder must return an object of header values"));
1681
+ const normalized = normalizeHeaders(value);
1682
+ if (generation === this.sourceGeneration) {
1683
+ if (!shallowEqualRecord(normalized, this.snapshot)) this.snapshot = normalized;
1684
+ return this.snapshot;
1685
+ }
1686
+ return normalized;
1687
+ }
1688
+ fail(cause) {
1689
+ if (cause instanceof CopilotKitHeaderResolutionError) return cause;
1690
+ const error = new CopilotKitHeaderResolutionError(cause);
1691
+ this.onFailure(error);
1692
+ return error;
1693
+ }
1694
+ };
1695
+ const PROTOCOL_HEADERS = new Set(["content-type", "accept"]);
1696
+ /**
1697
+ * Put fresh core headers on top of a request's headers, keeping the input's
1698
+ * shape. Core beats an agent's own headers (#5635). A site's Content-Type and
1699
+ * Accept are never overridden, matching every site's existing spread order.
1700
+ */
1701
+ function ɵoverlayCoreHeaders(existing, core) {
1702
+ if (existing instanceof Headers) {
1703
+ const headers = new Headers(existing);
1704
+ for (const [key, value] of Object.entries(core)) {
1705
+ if (PROTOCOL_HEADERS.has(key.toLowerCase()) && headers.has(key)) continue;
1706
+ headers.set(key, value);
1707
+ }
1708
+ return headers;
1709
+ }
1710
+ const base = Array.isArray(existing) ? Object.fromEntries(existing) : { ...existing };
1711
+ const keyByLower = new Map(Object.keys(base).map((k) => [k.toLowerCase(), k]));
1712
+ for (const [key, value] of Object.entries(core)) {
1713
+ const existingKey = keyByLower.get(key.toLowerCase());
1714
+ if (existingKey !== void 0) {
1715
+ if (PROTOCOL_HEADERS.has(key.toLowerCase())) continue;
1716
+ delete base[existingKey];
1717
+ }
1718
+ base[key] = value;
1719
+ }
1720
+ return base;
1721
+ }
1722
+ /** Reject with the signal's AbortError if it aborts before `value` settles. */
1723
+ async function abortable(value, signal) {
1724
+ if (!signal || !isPromiseLike(value)) return value;
1725
+ if (signal.aborted) throw abortError(signal);
1726
+ return new Promise((resolve, reject) => {
1727
+ const onAbort = () => reject(abortError(signal));
1728
+ signal.addEventListener("abort", onAbort, { once: true });
1729
+ Promise.resolve(value).then((v) => {
1730
+ signal.removeEventListener("abort", onAbort);
1731
+ resolve(v);
1732
+ }, (e) => {
1733
+ signal.removeEventListener("abort", onAbort);
1734
+ reject(e);
1735
+ });
1736
+ });
1737
+ }
1738
+ function abortError(signal) {
1739
+ return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
1740
+ }
1741
+ /**
1742
+ * Add default headers (e.g. the public API key) to a source, only where the
1743
+ * source left the key unset or empty. The single shared replacement for the
1744
+ * React, Vue and Angular providers' own merges.
1745
+ */
1746
+ function ɵwithHeaderDefaults(source, defaults) {
1747
+ if (Object.keys(defaults).length === 0) return source;
1748
+ const fill = (headers) => {
1749
+ const out = { ...headers };
1750
+ for (const [key, value] of Object.entries(defaults)) if (!out[key]) out[key] = value;
1751
+ return out;
1752
+ };
1753
+ if (typeof source !== "function") return fill(source);
1754
+ return (() => {
1755
+ const value = source();
1756
+ return isPromiseLike(value) ? Promise.resolve(value).then((resolved) => isHeaderRecordInput(resolved) ? fill(resolved) : resolved) : isHeaderRecordInput(value) ? fill(value) : value;
1757
+ });
1758
+ }
1759
+
1552
1760
  //#endregion
1553
1761
  //#region src/core/agent-registry.ts
1554
1762
  /** Maximum wait for optional Inspector metadata before degrading to absence. */
@@ -1883,27 +2091,83 @@ var AgentRegistry = class {
1883
2091
  console.warn(`Agent ${id} not found`);
1884
2092
  }
1885
2093
  /**
1886
- * Apply current core headers to an agent, merged ON TOP of the agent's own
1887
- * construction-time headers (the per-agent baseline in `agentOwnHeaders`).
1888
- * Core wins on a key conflict. Non-`HttpAgent` agents are left untouched
1889
- * because only `HttpAgent` carries a `headers` field. See #5635.
2094
+ * Shared core-and-own-header merge for a single agent. Captures the
2095
+ * agent's construction-time headers once (the per-agent baseline in
2096
+ * `agentOwnHeaders`), then either keeps only that baseline — a
2097
+ * `ProxiedCopilotRuntimeAgent`, whose core headers are added by
2098
+ * `ɵruntimeFetch` when each request is actually sent instead, so a key the
2099
+ * builder stops returning can never ride along from a stale copy baked
2100
+ * onto the agent (see #1937) — or merges `coreHeaders` on top of it (any
2101
+ * other `HttpAgent`; core wins on a key conflict, see #5635).
2102
+ */
2103
+ applyHeaderRecordToAgent(agent, coreHeaders) {
2104
+ if (!this.agentOwnHeaders.has(agent)) this.agentOwnHeaders.set(agent, { ...agent.headers });
2105
+ const own = this.agentOwnHeaders.get(agent);
2106
+ if (agent instanceof ProxiedCopilotRuntimeAgent) {
2107
+ agent.headers = { ...own };
2108
+ this.applyRuntimeFetchToAgent(agent);
2109
+ return;
2110
+ }
2111
+ agent.headers = {
2112
+ ...own,
2113
+ ...coreHeaders
2114
+ };
2115
+ }
2116
+ /**
2117
+ * Apply the last resolved header snapshot to an agent, merged ON TOP of
2118
+ * the agent's own construction-time headers. Non-`HttpAgent` agents are
2119
+ * left untouched because only `HttpAgent` carries a `headers` field. See
2120
+ * #5635.
2121
+ *
2122
+ * Never invokes the headers builder — safe to call from anywhere (dev-only
2123
+ * registration helpers, a React effect that re-runs on every render)
2124
+ * without risking a synchronous throw or an unhandled async rejection from
2125
+ * a user-supplied builder. Use `prepareAgentHeadersForRun` (friends-only)
2126
+ * on the run/connect path, where a builder failure can be awaited and
2127
+ * reported once.
1890
2128
  */
1891
2129
  applyHeadersToAgent(agent) {
1892
- if (ɵisHttpAgent(agent)) {
1893
- if (!this.agentOwnHeaders.has(agent)) this.agentOwnHeaders.set(agent, { ...agent.headers });
1894
- agent.headers = {
1895
- ...this.agentOwnHeaders.get(agent),
1896
- ...this.core.headers
1897
- };
1898
- }
2130
+ if (!ɵisHttpAgent(agent)) return;
2131
+ const friends = this.core;
2132
+ this.applyHeaderRecordToAgent(agent, friends.headers);
1899
2133
  }
1900
2134
  /**
1901
- * Apply current headers to all agents
2135
+ * Apply the last resolved header snapshot to every agent, without
2136
+ * triggering a builder call per agent. Used by `initialize` and
2137
+ * `setHeaders`; a run re-applies with fresh headers anyway (see
2138
+ * `prepareAgentHeadersForRun`).
1902
2139
  */
1903
2140
  applyHeadersToAgents(agents) {
2141
+ const friends = this.core;
1904
2142
  Object.values(agents).forEach((agent) => {
1905
- this.applyHeadersToAgent(agent);
2143
+ if (ɵisHttpAgent(agent)) this.applyHeaderRecordToAgent(agent, friends.headers);
2144
+ });
2145
+ }
2146
+ /**
2147
+ * Resolve headers fresh and apply them to `agent` right before a run or
2148
+ * connect actually sends (#1937) — the resolving counterpart to
2149
+ * `applyHeadersToAgent`. Friends-only: only the run handler should call
2150
+ * this, since resolving can invoke a user-supplied builder that throws
2151
+ * synchronously or returns a rejecting promise. Resolution is synchronous
2152
+ * for a record or a sync builder; this returns a promise only when an
2153
+ * async builder must be awaited first, and callers that need the write to
2154
+ * have landed before continuing must await a returned promise.
2155
+ *
2156
+ * A `ProxiedCopilotRuntimeAgent` never invokes the builder here: its core
2157
+ * headers are added by `ɵruntimeFetch` at send time instead, so only its
2158
+ * own headers are (re)applied.
2159
+ */
2160
+ prepareAgentHeadersForRun(agent) {
2161
+ if (!ɵisHttpAgent(agent)) return;
2162
+ if (agent instanceof ProxiedCopilotRuntimeAgent) {
2163
+ this.applyHeaderRecordToAgent(agent, {});
2164
+ return;
2165
+ }
2166
+ const resolved = this.core.resolveHeaders();
2167
+ if (isPromiseLike(resolved)) return Promise.resolve(resolved).then((headers) => {
2168
+ this.applyHeaderRecordToAgent(agent, headers);
1906
2169
  });
2170
+ this.applyHeaderRecordToAgent(agent, resolved);
1907
2171
  }
1908
2172
  /**
1909
2173
  * Apply current credentials to an agent
@@ -1964,6 +2228,13 @@ var AgentRegistry = class {
1964
2228
  }
1965
2229
  createRuntimeFetch() {
1966
2230
  if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
2231
+ const friends = this.core;
2232
+ const coreHeaders = await abortable(friends.resolveHeaders(), init?.signal);
2233
+ const requestHeaders = ɵoverlayCoreHeaders(init?.headers ?? (input instanceof Request ? input.headers : void 0), coreHeaders);
2234
+ init = {
2235
+ ...init,
2236
+ headers: requestHeaders
2237
+ };
1967
2238
  const meta = () => runtimeRequestMeta(init);
1968
2239
  const watchdog = this.armRuntimeRequestWatchdog(meta());
1969
2240
  try {
@@ -2033,7 +2304,15 @@ var AgentRegistry = class {
2033
2304
  const headersGeneration = this.inspectorMetadataHeadersGeneration;
2034
2305
  const credentialsGeneration = this.inspectorMetadataCredentialsGeneration;
2035
2306
  const friends = this.core;
2036
- const headers = { ...friends.headers };
2307
+ let headers;
2308
+ try {
2309
+ const resolved = friends.resolveHeaders();
2310
+ headers = { ...isPromiseLike(resolved) ? await resolved : resolved };
2311
+ } catch {
2312
+ if (generation === this.inspectorMetadataGeneration) this.setInspectorMetadata(void 0);
2313
+ return;
2314
+ }
2315
+ if (generation !== this.inspectorMetadataGeneration) return;
2037
2316
  const credentials = friends.credentials;
2038
2317
  const abortController = new AbortController();
2039
2318
  this.inspectorMetadataAbortController = abortController;
@@ -2194,6 +2473,10 @@ var AgentRegistry = class {
2194
2473
  async markRuntimeUnreachable(error) {
2195
2474
  this.setRuntimeConnectionStatus(CopilotKitCoreRuntimeConnectionStatus.Error);
2196
2475
  await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Error);
2476
+ if (isHeaderResolutionError(error)) {
2477
+ _copilotkit_shared.logger.warn(`Could not resolve request headers for the identification request (${this._runtimeUrl}/info). Check the headers builder passed to CopilotKit.`);
2478
+ return;
2479
+ }
2197
2480
  const runtimeStatus = isRuntimeInfoRequestError(error) ? error.runtimeInfoStatus : void 0;
2198
2481
  _copilotkit_shared.logger.warn(runtimeStatus === void 0 ? `Runtime did not answer the identification request (${this._runtimeUrl}/info): ${error.message}. The runtime appears to be unreachable.` : `Runtime answered the identification request with status ${runtimeStatus} (${this._runtimeUrl}/info): ${error.message}. The runtime is reachable but refused the request — check credentials and authorisation before addresses and ports.`);
2199
2482
  await this.core.emitError({
@@ -2454,9 +2737,10 @@ var AgentRegistry = class {
2454
2737
  }
2455
2738
  }
2456
2739
  async fetchRuntimeInfo(runtimeUrl, runtimeTransport, signal) {
2457
- const baseHeaders = this.core.headers;
2458
- const credentials = this.core.credentials;
2459
- const headers = { ...baseHeaders };
2740
+ const friends = this.core;
2741
+ const credentials = friends.credentials;
2742
+ const resolved = friends.resolveHeaders();
2743
+ const headers = { ...isPromiseLike(resolved) ? await abortable(resolved, signal) : resolved };
2460
2744
  if (runtimeTransport === "single") return {
2461
2745
  runtimeInfo: await this.fetchRuntimeInfoSingle(this.singleEndpointUrlFor(runtimeUrl), headers, credentials, signal),
2462
2746
  resolvedTransport: "single"
@@ -2744,18 +3028,19 @@ var SuggestionEngine = class {
2744
3028
  const seededState = JSON.parse(JSON.stringify(suggestionsConsumerAgent.state ?? {}));
2745
3029
  const useStateless = this.core.suggestions === true && this.core.runtimeTransport !== "single";
2746
3030
  let suggestionAgent;
3031
+ let statelessAgent;
2747
3032
  if (useStateless) {
2748
3033
  const suggestUrl = `${this.core.runtimeUrl}/agent/${encodeURIComponent(resolvedProviderAgentId)}/suggest`;
2749
3034
  const credentials = this.core.credentials;
2750
- suggestionAgent = new _ag_ui_client.HttpAgent({
3035
+ statelessAgent = new _ag_ui_client.HttpAgent({
2751
3036
  agentId: resolvedProviderAgentId,
2752
3037
  url: suggestUrl,
2753
- headers: { ...this.core.headers },
2754
3038
  ...credentials ? { fetch: (url, requestInit) => fetch(url, {
2755
3039
  ...requestInit,
2756
3040
  credentials
2757
3041
  }) } : {}
2758
3042
  });
3043
+ suggestionAgent = statelessAgent;
2759
3044
  } else {
2760
3045
  suggestionAgent = suggestionsProviderAgent.clone();
2761
3046
  if (suggestionAgent instanceof ProxiedCopilotRuntimeAgent) suggestionAgent.messageFilter = void 0;
@@ -2768,6 +3053,9 @@ var SuggestionEngine = class {
2768
3053
  suggestionAgent.abortRun();
2769
3054
  } };
2770
3055
  this._runningSuggestions[consumerAgentId] = [...this._runningSuggestions[consumerAgentId] ?? [], runHandle];
3056
+ if (statelessAgent) statelessAgent.headers = { ...await this.core.resolveHeaders() };
3057
+ else await this.core.prepareAgentHeadersForRun(suggestionAgent);
3058
+ if (aborted) return;
2771
3059
  suggestionAgent.addMessage({
2772
3060
  id: suggestionId,
2773
3061
  role: "user",
@@ -3514,7 +3802,8 @@ var RunHandler = class {
3514
3802
  if (typeof cursorAware.clearReconnectCursor === "function") cursorAware.clearReconnectCursor(incomingThreadId);
3515
3803
  }
3516
3804
  }
3517
- this._internal.applyHeadersToAgent(agent);
3805
+ const headersApplied = this._internal.prepareAgentHeadersForRun(agent);
3806
+ if (headersApplied) await headersApplied;
3518
3807
  await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
3519
3808
  copilotkit: this.core,
3520
3809
  agent
@@ -3527,7 +3816,7 @@ var RunHandler = class {
3527
3816
  forwardedProps: this._internal.properties,
3528
3817
  tools: this.buildFrontendTools(agent.agentId),
3529
3818
  context: this._internal.getContextForAgent(agent.agentId)
3530
- }, this.createAgentErrorSubscriber(agent));
3819
+ }, this.createAgentErrorSubscriber(agent, "connect"));
3531
3820
  if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
3532
3821
  const controller = new AbortController();
3533
3822
  const replay = this._interactionAbortControllers.get(agent) ?? {
@@ -3578,7 +3867,16 @@ var RunHandler = class {
3578
3867
  */
3579
3868
  async runAgent({ agent, forwardedProps, resume, runId }, continuationHandoff) {
3580
3869
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
3581
- this._internal.applyHeadersToAgent(agent);
3870
+ try {
3871
+ const headersApplied = this._internal.prepareAgentHeadersForRun(agent);
3872
+ if (headersApplied) await headersApplied;
3873
+ } catch {
3874
+ continuationHandoff?.cancel();
3875
+ return {
3876
+ result: void 0,
3877
+ newMessages: []
3878
+ };
3879
+ }
3582
3880
  if (agent.detachActiveRun) try {
3583
3881
  await agent.detachActiveRun();
3584
3882
  } catch (error) {
@@ -3609,7 +3907,7 @@ var RunHandler = class {
3609
3907
  this._runDepth++;
3610
3908
  try {
3611
3909
  let logicalRunId = resumedRunId ?? runId;
3612
- const agentSubscriber = this.createAgentErrorSubscriber(agent);
3910
+ const agentSubscriber = this.createAgentErrorSubscriber(agent, "run");
3613
3911
  let started = false;
3614
3912
  const onRunStartedEvent = agentSubscriber.onRunStartedEvent;
3615
3913
  const onRunInitialized = agentSubscriber.onRunInitialized;
@@ -4114,7 +4412,7 @@ var RunHandler = class {
4114
4412
  /**
4115
4413
  * Create an agent error subscriber
4116
4414
  */
4117
- createAgentErrorSubscriber(agent) {
4415
+ createAgentErrorSubscriber(agent, stream) {
4118
4416
  const emitAgentError = async (error, code, extraContext = {}) => {
4119
4417
  const context = { ...extraContext };
4120
4418
  if (agent.agentId) context.agentId = agent.agentId;
@@ -4137,7 +4435,8 @@ var RunHandler = class {
4137
4435
  await emitAgentError(rawError, CopilotKitCoreErrorCode.AGENT_RUN_ERROR_EVENT, {
4138
4436
  source: "onRunErrorEvent",
4139
4437
  event,
4140
- runtimeErrorCode: event?.code
4438
+ runtimeErrorCode: event?.code,
4439
+ phase: stream === "run" ? "live" : ɵgetConnectRunErrorPhase(event)
4141
4440
  });
4142
4441
  }
4143
4442
  };
@@ -4745,6 +5044,9 @@ var TrajectoryConnection = class {
4745
5044
  stop() {
4746
5045
  const session = this.session;
4747
5046
  if (!session) return;
5047
+ const collector = session.collector;
5048
+ session.collector = void 0;
5049
+ collector?.stop();
4748
5050
  if (session.ready && session.connection) this.flush(session, session.connection);
4749
5051
  this.end(session, {
4750
5052
  status: "error",
@@ -4844,18 +5146,19 @@ var TrajectoryConnection = class {
4844
5146
  } finally {
4845
5147
  if (socket) {
4846
5148
  socket.off(connection.socketRefs);
5149
+ socket.connect = () => void 0;
4847
5150
  socket.disconnect();
4848
5151
  }
4849
5152
  }
4850
5153
  }
4851
5154
  fail(session, connection, code, retryable = true) {
4852
5155
  if (!this.current(session, connection)) return;
4853
- session.collector?.stop();
4854
- session.collector = void 0;
4855
5156
  if (session.ready && session.started) session.promise = new Promise((resolve) => {
4856
5157
  session.resolve = resolve;
4857
5158
  });
4858
5159
  session.ready = false;
5160
+ session.collector?.stop();
5161
+ session.collector = void 0;
4859
5162
  this.discardQueue(session);
4860
5163
  session.linkedThreads.clear();
4861
5164
  for (const pending of connection.pending) pending.finish("PERSISTENCE_UNKNOWN");
@@ -4899,12 +5202,15 @@ var TrajectoryConnection = class {
4899
5202
  if (!this.current(session, connection)) return;
4900
5203
  }
4901
5204
  const rest = transport === "rest";
5205
+ const resolved = this.core.resolveHeaders();
5206
+ const coreHeaders = isPromiseLike(resolved) ? await abortable(resolved, connection.abort.signal) : resolved;
5207
+ if (!this.current(session, connection)) return;
4902
5208
  const response = await fetch(rest ? `${runtimeUrl}/trajectory/${encodeURIComponent(session.trajectoryId)}/connect` : this.core.ɵruntimeEndpointUrl ?? runtimeUrl, {
4903
5209
  method: "POST",
4904
5210
  redirect: "error",
4905
5211
  signal: connection.abort.signal,
4906
5212
  headers: {
4907
- ...this.core.headers,
5213
+ ...coreHeaders,
4908
5214
  "Content-Type": "application/json"
4909
5215
  },
4910
5216
  credentials: this.core.credentials,
@@ -5013,7 +5319,11 @@ var TrajectoryConnection = class {
5013
5319
  return connection.socket?.isConnected() === true && connection.channel?.state === "joined";
5014
5320
  }
5015
5321
  send(session, connection, event) {
5016
- if (!this.current(session, connection) || !session.ready) return;
5322
+ if (!this.current(session, connection)) return;
5323
+ if (!session.ready) {
5324
+ this.addDropped(session, 1, false);
5325
+ return;
5326
+ }
5017
5327
  if (!this.connected(connection)) {
5018
5328
  this.addDropped(session, 1);
5019
5329
  this.fail(session, connection, "CONNECTION_LOST");
@@ -5182,7 +5492,7 @@ var LearningBridge = class {
5182
5492
  });
5183
5493
  }
5184
5494
  if (config.sink === void 0) {
5185
- if (options.learningContainerIds !== void 0) console.warn("[CopilotKit] learningContainerIds is supported only with a custom sink. Authenticated Trajectory capture does not assign Learning Containers; remove learningContainerIds from the capture options.");
5495
+ if (options.learningContainerIds !== void 0) console.warn("[CopilotKit] learningContainerIds is supported only with a custom sink. Authenticated Trajectory capture ignores it; assign Learning Spaces on the server with getTrajectoryLearningContainerIds on CopilotKitIntelligence, and remove learningContainerIds from the capture options.");
5186
5496
  this.stopLegacy();
5187
5497
  return this.connection.start(options.trajectoryId, config);
5188
5498
  }
@@ -6491,6 +6801,12 @@ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode)
6491
6801
  CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
6492
6802
  CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
6493
6803
  CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
6804
+ /**
6805
+ * An agent emitted RUN_ERROR. `context.phase` (`RunErrorPhase`) is
6806
+ * `"replay"` when the error belongs to stored thread history replayed on
6807
+ * connect, `"live"` when the run is happening now, and `"unknown"` when the
6808
+ * transport cannot tell. Show a live-failure notice only for `"live"`.
6809
+ */
6494
6810
  CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
6495
6811
  CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
6496
6812
  CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
@@ -6519,6 +6835,11 @@ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode)
6519
6835
  CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
6520
6836
  CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
6521
6837
  CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
6838
+ /**
6839
+ * The `headers` builder threw, rejected, or returned something other than
6840
+ * an object. The request was not sent. `error.cause` is the builder's error.
6841
+ */
6842
+ CopilotKitCoreErrorCode["HEADER_RESOLUTION_FAILED"] = "header_resolution_failed";
6522
6843
  return CopilotKitCoreErrorCode;
6523
6844
  }({});
6524
6845
  /**
@@ -6541,17 +6862,8 @@ let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitC
6541
6862
  CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
6542
6863
  return CopilotKitCoreRuntimeConnectionStatus;
6543
6864
  }({});
6544
- /**
6545
- * Normalize a header map to the internal invariant: a `Record<string, string>`
6546
- * with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
6547
- * are dropped (this is how a header is cleared). Shared by the constructor and
6548
- * `setHeaders` so both write paths into `_headers` enforce the same invariant.
6549
- */
6550
- function normalizeHeaders(headers) {
6551
- return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
6552
- }
6553
6865
  var CopilotKitCore = class {
6554
- _headers;
6866
+ headerSource;
6555
6867
  _credentials;
6556
6868
  _messageFilter;
6557
6869
  _properties;
@@ -6582,7 +6894,14 @@ var CopilotKitCore = class {
6582
6894
  */
6583
6895
  previousAgentIds = /* @__PURE__ */ new Set();
6584
6896
  constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug, learning }) {
6585
- this._headers = normalizeHeaders(headers);
6897
+ this.headerSource = new HeaderSourceResolver((error) => {
6898
+ this.emitError({
6899
+ error,
6900
+ code: CopilotKitCoreErrorCode.HEADER_RESOLUTION_FAILED,
6901
+ context: { source: "headers" }
6902
+ });
6903
+ });
6904
+ this.headerSource.setSource(headers);
6586
6905
  this._credentials = credentials;
6587
6906
  this._messageFilter = messageFilter;
6588
6907
  this._properties = properties;
@@ -6640,6 +6959,7 @@ var CopilotKitCore = class {
6640
6959
  * Internal method used by delegate classes to emit errors
6641
6960
  */
6642
6961
  async emitError({ error, code, context = {} }) {
6962
+ if (code !== CopilotKitCoreErrorCode.HEADER_RESOLUTION_FAILED && isHeaderResolutionError(error)) return;
6643
6963
  await this.notifySubscribers((subscriber) => subscriber.onError?.({
6644
6964
  copilotkit: this,
6645
6965
  error,
@@ -6699,8 +7019,24 @@ var CopilotKitCore = class {
6699
7019
  get runtimeVersion() {
6700
7020
  return this.agentRegistry.runtimeVersion;
6701
7021
  }
7022
+ /**
7023
+ * The last resolved headers. With a builder this is the value from the most
7024
+ * recent request, not necessarily current; call `resolveHeaders()` for that.
7025
+ */
6702
7026
  get headers() {
6703
- return this._headers;
7027
+ return this.headerSource.headers;
7028
+ }
7029
+ /**
7030
+ * Resolve the current headers. Synchronous for a record or a sync builder,
7031
+ * a promise for an async builder. Concurrent calls share one builder call.
7032
+ * The returned object is shared; copy it before modifying.
7033
+ */
7034
+ resolveHeaders() {
7035
+ return this.headerSource.resolve();
7036
+ }
7037
+ /** Changes only on `setHeaders` or a new source, never on a new token. */
7038
+ get ɵheadersGeneration() {
7039
+ return this.headerSource.generation;
6704
7040
  }
6705
7041
  get credentials() {
6706
7042
  return this._credentials;
@@ -6841,9 +7177,17 @@ var CopilotKitCore = class {
6841
7177
  * with, set it at the provider/core level instead of on the agent, or update
6842
7178
  * it on the agent directly. The clear-on-logout pattern above is for
6843
7179
  * core-level headers.
7180
+ *
7181
+ * Pass a function to have headers evaluated when each request is sent
7182
+ * (sync or async). Setting the same function again is a no-op. A new token
7183
+ * from the builder doesn't notify `onHeadersChanged`. On a user switch,
7184
+ * call `setHeaders` with a NEW function (or a record), or remount.
7185
+ *
7186
+ * Passing a record equal (by value) to the currently applied record is
7187
+ * also a no-op — safe to call on every render with a fresh object literal.
6844
7188
  */
6845
7189
  setHeaders(headers) {
6846
- this._headers = normalizeHeaders(headers);
7190
+ if (!this.headerSource.setSource(headers)) return;
6847
7191
  if (this._memoryStore) this.syncMemoryContext();
6848
7192
  this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
6849
7193
  this.agentRegistry.handleHeadersChanged();
@@ -6990,8 +7334,8 @@ var CopilotKitCore = class {
6990
7334
  return this.learningBridge.registerOpenThread(params);
6991
7335
  }
6992
7336
  /**
6993
- * Re-apply the current headers to a single agent (delegated to
6994
- * AgentRegistry). Core headers are merged on top of the agent's own
7337
+ * Re-apply the last resolved header snapshot to a single agent (delegated
7338
+ * to AgentRegistry). Core headers are merged on top of the agent's own
6995
7339
  * construction-time headers rather than replacing them, so headers
6996
7340
  * configured directly on an `HttpAgent` (e.g. an `Authorization` for a
6997
7341
  * self-hosted backend) survive header updates instead of being silently
@@ -7002,11 +7346,31 @@ var CopilotKitCore = class {
7002
7346
  * afterwards is `setHeaders` (which re-applies to every agent), not mutating
7003
7347
  * `agent.headers` directly — a direct mutation is overwritten on the next
7004
7348
  * re-apply.
7349
+ *
7350
+ * A `ProxiedCopilotRuntimeAgent` keeps only its own construction-time
7351
+ * headers here — core headers are added by `ɵruntimeFetch` when each
7352
+ * request is sent (see #1937), so `agent.headers` never carries a stale
7353
+ * copy of a core header the builder has since stopped returning.
7354
+ *
7355
+ * Never invokes the headers builder (unlike the run/connect path's
7356
+ * internal `prepareAgentHeadersForRun`): safe to call from a dev-only
7357
+ * registration helper or a React effect that re-runs on every render
7358
+ * without risking a synchronous throw or an unhandled async rejection from
7359
+ * a user-supplied builder.
7005
7360
  */
7006
7361
  applyHeadersToAgent(agent) {
7007
7362
  this.agentRegistry.applyHeadersToAgent(agent);
7008
7363
  }
7009
7364
  /**
7365
+ * Resolve headers fresh and apply them to `agent` right before a run or
7366
+ * connect actually sends (#1937). Friends-only (delegated to
7367
+ * AgentRegistry) — the run handler is the sole caller, since resolving can
7368
+ * invoke a user-supplied builder that throws or rejects.
7369
+ */
7370
+ prepareAgentHeadersForRun(agent) {
7371
+ return this.agentRegistry.prepareAgentHeadersForRun(agent);
7372
+ }
7373
+ /**
7010
7374
  * Context management (delegated to ContextStore).
7011
7375
  * Pass `agentIds` to restrict the entry to runs of specific agents;
7012
7376
  * omit it for context every agent should receive.
@@ -7066,16 +7430,20 @@ var CopilotKitCore = class {
7066
7430
  /**
7067
7431
  * Pushes the current runtime wiring into the memory store. When the runtime
7068
7432
  * is connected and both the intelligence WebSocket URL and runtime URL are
7069
- * available, the store receives a context (runtime URL, WebSocket URL, and a
7070
- * copy of the current headers); otherwise its context is cleared. No-op when
7071
- * the store has not been created yet.
7433
+ * available, the store receives a context (runtime URL, WebSocket URL);
7434
+ * otherwise its context is cleared. No-op when the store has not been
7435
+ * created yet.
7436
+ *
7437
+ * Headers are deliberately NOT part of this context: the store's `fetch` is
7438
+ * `ɵruntimeFetch` (see `ensureMemoryStore`), which already resolves and
7439
+ * overlays the current core headers at send time (#1937) — a header
7440
+ * snapshot copied here would go stale between context syncs.
7072
7441
  */
7073
7442
  syncMemoryContext() {
7074
7443
  if (!this._memoryStore) return;
7075
7444
  if (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected && this.intelligence?.wsUrl && this.runtimeUrl) this._memoryStore.setContext({
7076
7445
  runtimeUrl: this.runtimeUrl,
7077
- wsUrl: this.intelligence.wsUrl,
7078
- headers: { ...this.headers }
7446
+ wsUrl: this.intelligence.wsUrl
7079
7447
  });
7080
7448
  else this._memoryStore.setContext(null);
7081
7449
  }
@@ -8506,8 +8874,10 @@ exports.ContextStore = ContextStore;
8506
8874
  exports.CopilotKitCore = CopilotKitCore;
8507
8875
  exports.CopilotKitCoreErrorCode = CopilotKitCoreErrorCode;
8508
8876
  exports.CopilotKitCoreRuntimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus;
8877
+ exports.CopilotKitHeaderResolutionError = CopilotKitHeaderResolutionError;
8509
8878
  exports.INSPECTOR_THREAD_BRIDGE_PLUGIN_ID = INSPECTOR_THREAD_BRIDGE_PLUGIN_ID;
8510
8879
  exports.IntelligenceAgent = IntelligenceAgent;
8880
+ exports.IntelligenceReplayFailedError = IntelligenceReplayFailedError;
8511
8881
  exports.MEMORY_ERROR_REGISTRY = MEMORY_ERROR_REGISTRY;
8512
8882
  exports.MemoryError = MemoryError;
8513
8883
  exports.ProxiedCopilotRuntimeAgent = ProxiedCopilotRuntimeAgent;
@@ -8579,4 +8949,5 @@ exports.ɵselectThreads = ɵselectThreads;
8579
8949
  exports.ɵselectThreadsError = ɵselectThreadsError;
8580
8950
  exports.ɵselectThreadsIsLoading = ɵselectThreadsIsLoading;
8581
8951
  exports.ɵthreadAdapterEvents = ɵthreadAdapterEvents;
8952
+ exports.ɵwithHeaderDefaults = ɵwithHeaderDefaults;
8582
8953
  //# sourceMappingURL=index.cjs.map