@copilotkit/core 1.77.2 → 1.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1104,7 +1104,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1104
1104
  ...this.headers,
1105
1105
  "Content-Type": "application/json"
1106
1106
  });
1107
- fetch(this.singleEndpointUrl, {
1107
+ this.fetch(this.singleEndpointUrl, {
1108
1108
  method: "POST",
1109
1109
  headers,
1110
1110
  body: JSON.stringify({
@@ -1115,7 +1115,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1115
1115
  },
1116
1116
  ...runId === void 0 ? {} : { body: { runId } }
1117
1117
  }),
1118
- ...this.credentials ? { credentials: this.credentials } : {}
1118
+ ...this.credentials ? { credentials: this.credentials } : {},
1119
+ ɵruntimeRequest: { nonCritical: true }
1119
1120
  }).catch((error) => {
1120
1121
  console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
1121
1122
  });
@@ -1126,14 +1127,15 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1126
1127
  const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
1127
1128
  const base = new URL(this.runtimeUrl, origin);
1128
1129
  const stopUrl = new URL(stopPath, base);
1129
- fetch(stopUrl.toString(), {
1130
+ this.fetch(stopUrl.toString(), {
1130
1131
  method: "POST",
1131
1132
  headers: {
1132
1133
  "Content-Type": "application/json",
1133
1134
  ...this.headers
1134
1135
  },
1135
1136
  ...runId === void 0 ? {} : { body: JSON.stringify({ runId }) },
1136
- ...this.credentials ? { credentials: this.credentials } : {}
1137
+ ...this.credentials ? { credentials: this.credentials } : {},
1138
+ ɵruntimeRequest: { nonCritical: true }
1137
1139
  }).catch((error) => {
1138
1140
  console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
1139
1141
  });
@@ -1549,6 +1551,183 @@ async function createSingleRouteResourceRequest(input, init, runtimeUrl) {
1549
1551
  };
1550
1552
  }
1551
1553
 
1554
+ //#endregion
1555
+ //#region src/core/header-source.ts
1556
+ var CopilotKitHeaderResolutionError = class extends Error {
1557
+ name = "CopilotKitHeaderResolutionError";
1558
+ constructor(cause) {
1559
+ super("[CopilotKit] Failed to resolve request headers", { cause });
1560
+ }
1561
+ };
1562
+ function isHeaderResolutionError(error) {
1563
+ let current = error;
1564
+ for (let depth = 0; depth < 5 && current; depth++) {
1565
+ if (current instanceof CopilotKitHeaderResolutionError) return true;
1566
+ current = current.cause;
1567
+ }
1568
+ return false;
1569
+ }
1570
+ function isPromiseLike(value) {
1571
+ return typeof value === "object" && value !== null && typeof value.then === "function";
1572
+ }
1573
+ /**
1574
+ * Normalize a header map to a `Record<string, string>` with no `null` or
1575
+ * `undefined` values. Dropping an entry is how a header is cleared.
1576
+ */
1577
+ function normalizeHeaders(headers) {
1578
+ return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
1579
+ }
1580
+ /** Same keys, same values (order-independent). */
1581
+ function shallowEqualRecord(a, b) {
1582
+ const aKeys = Object.keys(a);
1583
+ const bKeys = Object.keys(b);
1584
+ if (aKeys.length !== bKeys.length) return false;
1585
+ return aKeys.every((key) => a[key] === b[key]);
1586
+ }
1587
+ function isHeaderRecordInput(value) {
1588
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1589
+ }
1590
+ /**
1591
+ * Owns the headers source for one core. Resolution is synchronous for a
1592
+ * record or a sync builder, so those callers never pay an extra await.
1593
+ */
1594
+ var HeaderSourceResolver = class {
1595
+ source = {};
1596
+ sourceGeneration = 0;
1597
+ snapshot = {};
1598
+ inFlight;
1599
+ constructor(onFailure) {
1600
+ this.onFailure = onFailure;
1601
+ }
1602
+ /** The last resolved headers. Not necessarily current for a builder. */
1603
+ get headers() {
1604
+ return this.snapshot;
1605
+ }
1606
+ /** Bumped on every accepted `setSource`, never by a new token. */
1607
+ get generation() {
1608
+ return this.sourceGeneration;
1609
+ }
1610
+ /**
1611
+ * Returns false when a builder with the same identity is set again, or
1612
+ * when a record replaces another record with equal normalized values (a
1613
+ * caller re-passing an equivalent literal on every re-render must not
1614
+ * bump the generation). A record replacing a builder, a builder replacing
1615
+ * a record, and a new builder function all still count as a change.
1616
+ */
1617
+ setSource(source) {
1618
+ if (typeof source === "function" && source === this.source) return false;
1619
+ const nextSnapshot = typeof source === "function" ? {} : normalizeHeaders(source);
1620
+ if (typeof source !== "function" && typeof this.source !== "function" && shallowEqualRecord(nextSnapshot, this.snapshot)) return false;
1621
+ this.source = source;
1622
+ this.sourceGeneration += 1;
1623
+ this.inFlight = void 0;
1624
+ this.snapshot = nextSnapshot;
1625
+ return true;
1626
+ }
1627
+ resolve() {
1628
+ const source = this.source;
1629
+ if (typeof source !== "function") return this.snapshot;
1630
+ const generation = this.sourceGeneration;
1631
+ if (this.inFlight?.generation === generation) return this.inFlight.promise;
1632
+ let value;
1633
+ try {
1634
+ value = source();
1635
+ } catch (error) {
1636
+ throw this.fail(error);
1637
+ }
1638
+ if (!isPromiseLike(value)) return this.accept(value, generation);
1639
+ const promise = Promise.resolve(value).then((resolved) => this.accept(resolved, generation), (error) => {
1640
+ throw this.fail(error);
1641
+ }).finally(() => {
1642
+ if (this.inFlight?.promise === promise) this.inFlight = void 0;
1643
+ });
1644
+ this.inFlight = {
1645
+ generation,
1646
+ promise
1647
+ };
1648
+ return promise;
1649
+ }
1650
+ accept(value, generation) {
1651
+ if (!isHeaderRecordInput(value)) throw this.fail(/* @__PURE__ */ new TypeError("headers builder must return an object of header values"));
1652
+ const normalized = normalizeHeaders(value);
1653
+ if (generation === this.sourceGeneration) {
1654
+ if (!shallowEqualRecord(normalized, this.snapshot)) this.snapshot = normalized;
1655
+ return this.snapshot;
1656
+ }
1657
+ return normalized;
1658
+ }
1659
+ fail(cause) {
1660
+ if (cause instanceof CopilotKitHeaderResolutionError) return cause;
1661
+ const error = new CopilotKitHeaderResolutionError(cause);
1662
+ this.onFailure(error);
1663
+ return error;
1664
+ }
1665
+ };
1666
+ const PROTOCOL_HEADERS = new Set(["content-type", "accept"]);
1667
+ /**
1668
+ * Put fresh core headers on top of a request's headers, keeping the input's
1669
+ * shape. Core beats an agent's own headers (#5635). A site's Content-Type and
1670
+ * Accept are never overridden, matching every site's existing spread order.
1671
+ */
1672
+ function ɵoverlayCoreHeaders(existing, core) {
1673
+ if (existing instanceof Headers) {
1674
+ const headers = new Headers(existing);
1675
+ for (const [key, value] of Object.entries(core)) {
1676
+ if (PROTOCOL_HEADERS.has(key.toLowerCase()) && headers.has(key)) continue;
1677
+ headers.set(key, value);
1678
+ }
1679
+ return headers;
1680
+ }
1681
+ const base = Array.isArray(existing) ? Object.fromEntries(existing) : { ...existing };
1682
+ const keyByLower = new Map(Object.keys(base).map((k) => [k.toLowerCase(), k]));
1683
+ for (const [key, value] of Object.entries(core)) {
1684
+ const existingKey = keyByLower.get(key.toLowerCase());
1685
+ if (existingKey !== void 0) {
1686
+ if (PROTOCOL_HEADERS.has(key.toLowerCase())) continue;
1687
+ delete base[existingKey];
1688
+ }
1689
+ base[key] = value;
1690
+ }
1691
+ return base;
1692
+ }
1693
+ /** Reject with the signal's AbortError if it aborts before `value` settles. */
1694
+ async function abortable(value, signal) {
1695
+ if (!signal || !isPromiseLike(value)) return value;
1696
+ if (signal.aborted) throw abortError(signal);
1697
+ return new Promise((resolve, reject) => {
1698
+ const onAbort = () => reject(abortError(signal));
1699
+ signal.addEventListener("abort", onAbort, { once: true });
1700
+ Promise.resolve(value).then((v) => {
1701
+ signal.removeEventListener("abort", onAbort);
1702
+ resolve(v);
1703
+ }, (e) => {
1704
+ signal.removeEventListener("abort", onAbort);
1705
+ reject(e);
1706
+ });
1707
+ });
1708
+ }
1709
+ function abortError(signal) {
1710
+ return signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
1711
+ }
1712
+ /**
1713
+ * Add default headers (e.g. the public API key) to a source, only where the
1714
+ * source left the key unset or empty. The single shared replacement for the
1715
+ * React, Vue and Angular providers' own merges.
1716
+ */
1717
+ function ɵwithHeaderDefaults(source, defaults) {
1718
+ if (Object.keys(defaults).length === 0) return source;
1719
+ const fill = (headers) => {
1720
+ const out = { ...headers };
1721
+ for (const [key, value] of Object.entries(defaults)) if (!out[key]) out[key] = value;
1722
+ return out;
1723
+ };
1724
+ if (typeof source !== "function") return fill(source);
1725
+ return (() => {
1726
+ const value = source();
1727
+ return isPromiseLike(value) ? Promise.resolve(value).then((resolved) => isHeaderRecordInput(resolved) ? fill(resolved) : resolved) : isHeaderRecordInput(value) ? fill(value) : value;
1728
+ });
1729
+ }
1730
+
1552
1731
  //#endregion
1553
1732
  //#region src/core/agent-registry.ts
1554
1733
  /** Maximum wait for optional Inspector metadata before degrading to absence. */
@@ -1883,29 +2062,85 @@ var AgentRegistry = class {
1883
2062
  console.warn(`Agent ${id} not found`);
1884
2063
  }
1885
2064
  /**
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.
2065
+ * Shared core-and-own-header merge for a single agent. Captures the
2066
+ * agent's construction-time headers once (the per-agent baseline in
2067
+ * `agentOwnHeaders`), then either keeps only that baseline — a
2068
+ * `ProxiedCopilotRuntimeAgent`, whose core headers are added by
2069
+ * `ɵruntimeFetch` when each request is actually sent instead, so a key the
2070
+ * builder stops returning can never ride along from a stale copy baked
2071
+ * onto the agent (see #1937) — or merges `coreHeaders` on top of it (any
2072
+ * other `HttpAgent`; core wins on a key conflict, see #5635).
2073
+ */
2074
+ applyHeaderRecordToAgent(agent, coreHeaders) {
2075
+ if (!this.agentOwnHeaders.has(agent)) this.agentOwnHeaders.set(agent, { ...agent.headers });
2076
+ const own = this.agentOwnHeaders.get(agent);
2077
+ if (agent instanceof ProxiedCopilotRuntimeAgent) {
2078
+ agent.headers = { ...own };
2079
+ this.applyRuntimeFetchToAgent(agent);
2080
+ return;
2081
+ }
2082
+ agent.headers = {
2083
+ ...own,
2084
+ ...coreHeaders
2085
+ };
2086
+ }
2087
+ /**
2088
+ * Apply the last resolved header snapshot to an agent, merged ON TOP of
2089
+ * the agent's own construction-time headers. Non-`HttpAgent` agents are
2090
+ * left untouched because only `HttpAgent` carries a `headers` field. See
2091
+ * #5635.
2092
+ *
2093
+ * Never invokes the headers builder — safe to call from anywhere (dev-only
2094
+ * registration helpers, a React effect that re-runs on every render)
2095
+ * without risking a synchronous throw or an unhandled async rejection from
2096
+ * a user-supplied builder. Use `prepareAgentHeadersForRun` (friends-only)
2097
+ * on the run/connect path, where a builder failure can be awaited and
2098
+ * reported once.
1890
2099
  */
1891
2100
  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
- }
2101
+ if (!ɵisHttpAgent(agent)) return;
2102
+ const friends = this.core;
2103
+ this.applyHeaderRecordToAgent(agent, friends.headers);
1899
2104
  }
1900
2105
  /**
1901
- * Apply current headers to all agents
2106
+ * Apply the last resolved header snapshot to every agent, without
2107
+ * triggering a builder call per agent. Used by `initialize` and
2108
+ * `setHeaders`; a run re-applies with fresh headers anyway (see
2109
+ * `prepareAgentHeadersForRun`).
1902
2110
  */
1903
2111
  applyHeadersToAgents(agents) {
2112
+ const friends = this.core;
1904
2113
  Object.values(agents).forEach((agent) => {
1905
- this.applyHeadersToAgent(agent);
2114
+ if (ɵisHttpAgent(agent)) this.applyHeaderRecordToAgent(agent, friends.headers);
1906
2115
  });
1907
2116
  }
1908
2117
  /**
2118
+ * Resolve headers fresh and apply them to `agent` right before a run or
2119
+ * connect actually sends (#1937) — the resolving counterpart to
2120
+ * `applyHeadersToAgent`. Friends-only: only the run handler should call
2121
+ * this, since resolving can invoke a user-supplied builder that throws
2122
+ * synchronously or returns a rejecting promise. Resolution is synchronous
2123
+ * for a record or a sync builder; this returns a promise only when an
2124
+ * async builder must be awaited first, and callers that need the write to
2125
+ * have landed before continuing must await a returned promise.
2126
+ *
2127
+ * A `ProxiedCopilotRuntimeAgent` never invokes the builder here: its core
2128
+ * headers are added by `ɵruntimeFetch` at send time instead, so only its
2129
+ * own headers are (re)applied.
2130
+ */
2131
+ prepareAgentHeadersForRun(agent) {
2132
+ if (!ɵisHttpAgent(agent)) return;
2133
+ if (agent instanceof ProxiedCopilotRuntimeAgent) {
2134
+ this.applyHeaderRecordToAgent(agent, {});
2135
+ return;
2136
+ }
2137
+ const resolved = this.core.resolveHeaders();
2138
+ if (isPromiseLike(resolved)) return Promise.resolve(resolved).then((headers) => {
2139
+ this.applyHeaderRecordToAgent(agent, headers);
2140
+ });
2141
+ this.applyHeaderRecordToAgent(agent, resolved);
2142
+ }
2143
+ /**
1909
2144
  * Apply current credentials to an agent
1910
2145
  */
1911
2146
  applyCredentialsToAgent(agent) {
@@ -1964,6 +2199,13 @@ var AgentRegistry = class {
1964
2199
  }
1965
2200
  createRuntimeFetch() {
1966
2201
  if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
2202
+ const friends = this.core;
2203
+ const coreHeaders = await abortable(friends.resolveHeaders(), init?.signal);
2204
+ const requestHeaders = ɵoverlayCoreHeaders(init?.headers ?? (input instanceof Request ? input.headers : void 0), coreHeaders);
2205
+ init = {
2206
+ ...init,
2207
+ headers: requestHeaders
2208
+ };
1967
2209
  const meta = () => runtimeRequestMeta(init);
1968
2210
  const watchdog = this.armRuntimeRequestWatchdog(meta());
1969
2211
  try {
@@ -2033,7 +2275,15 @@ var AgentRegistry = class {
2033
2275
  const headersGeneration = this.inspectorMetadataHeadersGeneration;
2034
2276
  const credentialsGeneration = this.inspectorMetadataCredentialsGeneration;
2035
2277
  const friends = this.core;
2036
- const headers = { ...friends.headers };
2278
+ let headers;
2279
+ try {
2280
+ const resolved = friends.resolveHeaders();
2281
+ headers = { ...isPromiseLike(resolved) ? await resolved : resolved };
2282
+ } catch {
2283
+ if (generation === this.inspectorMetadataGeneration) this.setInspectorMetadata(void 0);
2284
+ return;
2285
+ }
2286
+ if (generation !== this.inspectorMetadataGeneration) return;
2037
2287
  const credentials = friends.credentials;
2038
2288
  const abortController = new AbortController();
2039
2289
  this.inspectorMetadataAbortController = abortController;
@@ -2194,6 +2444,10 @@ var AgentRegistry = class {
2194
2444
  async markRuntimeUnreachable(error) {
2195
2445
  this.setRuntimeConnectionStatus(CopilotKitCoreRuntimeConnectionStatus.Error);
2196
2446
  await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Error);
2447
+ if (isHeaderResolutionError(error)) {
2448
+ _copilotkit_shared.logger.warn(`Could not resolve request headers for the identification request (${this._runtimeUrl}/info). Check the headers builder passed to CopilotKit.`);
2449
+ return;
2450
+ }
2197
2451
  const runtimeStatus = isRuntimeInfoRequestError(error) ? error.runtimeInfoStatus : void 0;
2198
2452
  _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
2453
  await this.core.emitError({
@@ -2454,9 +2708,10 @@ var AgentRegistry = class {
2454
2708
  }
2455
2709
  }
2456
2710
  async fetchRuntimeInfo(runtimeUrl, runtimeTransport, signal) {
2457
- const baseHeaders = this.core.headers;
2458
- const credentials = this.core.credentials;
2459
- const headers = { ...baseHeaders };
2711
+ const friends = this.core;
2712
+ const credentials = friends.credentials;
2713
+ const resolved = friends.resolveHeaders();
2714
+ const headers = { ...isPromiseLike(resolved) ? await abortable(resolved, signal) : resolved };
2460
2715
  if (runtimeTransport === "single") return {
2461
2716
  runtimeInfo: await this.fetchRuntimeInfoSingle(this.singleEndpointUrlFor(runtimeUrl), headers, credentials, signal),
2462
2717
  resolvedTransport: "single"
@@ -2744,18 +2999,19 @@ var SuggestionEngine = class {
2744
2999
  const seededState = JSON.parse(JSON.stringify(suggestionsConsumerAgent.state ?? {}));
2745
3000
  const useStateless = this.core.suggestions === true && this.core.runtimeTransport !== "single";
2746
3001
  let suggestionAgent;
3002
+ let statelessAgent;
2747
3003
  if (useStateless) {
2748
3004
  const suggestUrl = `${this.core.runtimeUrl}/agent/${encodeURIComponent(resolvedProviderAgentId)}/suggest`;
2749
3005
  const credentials = this.core.credentials;
2750
- suggestionAgent = new _ag_ui_client.HttpAgent({
3006
+ statelessAgent = new _ag_ui_client.HttpAgent({
2751
3007
  agentId: resolvedProviderAgentId,
2752
3008
  url: suggestUrl,
2753
- headers: { ...this.core.headers },
2754
3009
  ...credentials ? { fetch: (url, requestInit) => fetch(url, {
2755
3010
  ...requestInit,
2756
3011
  credentials
2757
3012
  }) } : {}
2758
3013
  });
3014
+ suggestionAgent = statelessAgent;
2759
3015
  } else {
2760
3016
  suggestionAgent = suggestionsProviderAgent.clone();
2761
3017
  if (suggestionAgent instanceof ProxiedCopilotRuntimeAgent) suggestionAgent.messageFilter = void 0;
@@ -2768,6 +3024,9 @@ var SuggestionEngine = class {
2768
3024
  suggestionAgent.abortRun();
2769
3025
  } };
2770
3026
  this._runningSuggestions[consumerAgentId] = [...this._runningSuggestions[consumerAgentId] ?? [], runHandle];
3027
+ if (statelessAgent) statelessAgent.headers = { ...await this.core.resolveHeaders() };
3028
+ else await this.core.prepareAgentHeadersForRun(suggestionAgent);
3029
+ if (aborted) return;
2771
3030
  suggestionAgent.addMessage({
2772
3031
  id: suggestionId,
2773
3032
  role: "user",
@@ -3514,7 +3773,8 @@ var RunHandler = class {
3514
3773
  if (typeof cursorAware.clearReconnectCursor === "function") cursorAware.clearReconnectCursor(incomingThreadId);
3515
3774
  }
3516
3775
  }
3517
- this._internal.applyHeadersToAgent(agent);
3776
+ const headersApplied = this._internal.prepareAgentHeadersForRun(agent);
3777
+ if (headersApplied) await headersApplied;
3518
3778
  await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
3519
3779
  copilotkit: this.core,
3520
3780
  agent
@@ -3578,7 +3838,16 @@ var RunHandler = class {
3578
3838
  */
3579
3839
  async runAgent({ agent, forwardedProps, resume, runId }, continuationHandoff) {
3580
3840
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
3581
- this._internal.applyHeadersToAgent(agent);
3841
+ try {
3842
+ const headersApplied = this._internal.prepareAgentHeadersForRun(agent);
3843
+ if (headersApplied) await headersApplied;
3844
+ } catch {
3845
+ continuationHandoff?.cancel();
3846
+ return {
3847
+ result: void 0,
3848
+ newMessages: []
3849
+ };
3850
+ }
3582
3851
  if (agent.detachActiveRun) try {
3583
3852
  await agent.detachActiveRun();
3584
3853
  } catch (error) {
@@ -4745,6 +5014,9 @@ var TrajectoryConnection = class {
4745
5014
  stop() {
4746
5015
  const session = this.session;
4747
5016
  if (!session) return;
5017
+ const collector = session.collector;
5018
+ session.collector = void 0;
5019
+ collector?.stop();
4748
5020
  if (session.ready && session.connection) this.flush(session, session.connection);
4749
5021
  this.end(session, {
4750
5022
  status: "error",
@@ -4844,18 +5116,19 @@ var TrajectoryConnection = class {
4844
5116
  } finally {
4845
5117
  if (socket) {
4846
5118
  socket.off(connection.socketRefs);
5119
+ socket.connect = () => void 0;
4847
5120
  socket.disconnect();
4848
5121
  }
4849
5122
  }
4850
5123
  }
4851
5124
  fail(session, connection, code, retryable = true) {
4852
5125
  if (!this.current(session, connection)) return;
4853
- session.collector?.stop();
4854
- session.collector = void 0;
4855
5126
  if (session.ready && session.started) session.promise = new Promise((resolve) => {
4856
5127
  session.resolve = resolve;
4857
5128
  });
4858
5129
  session.ready = false;
5130
+ session.collector?.stop();
5131
+ session.collector = void 0;
4859
5132
  this.discardQueue(session);
4860
5133
  session.linkedThreads.clear();
4861
5134
  for (const pending of connection.pending) pending.finish("PERSISTENCE_UNKNOWN");
@@ -4899,12 +5172,15 @@ var TrajectoryConnection = class {
4899
5172
  if (!this.current(session, connection)) return;
4900
5173
  }
4901
5174
  const rest = transport === "rest";
5175
+ const resolved = this.core.resolveHeaders();
5176
+ const coreHeaders = isPromiseLike(resolved) ? await abortable(resolved, connection.abort.signal) : resolved;
5177
+ if (!this.current(session, connection)) return;
4902
5178
  const response = await fetch(rest ? `${runtimeUrl}/trajectory/${encodeURIComponent(session.trajectoryId)}/connect` : this.core.ɵruntimeEndpointUrl ?? runtimeUrl, {
4903
5179
  method: "POST",
4904
5180
  redirect: "error",
4905
5181
  signal: connection.abort.signal,
4906
5182
  headers: {
4907
- ...this.core.headers,
5183
+ ...coreHeaders,
4908
5184
  "Content-Type": "application/json"
4909
5185
  },
4910
5186
  credentials: this.core.credentials,
@@ -5013,7 +5289,11 @@ var TrajectoryConnection = class {
5013
5289
  return connection.socket?.isConnected() === true && connection.channel?.state === "joined";
5014
5290
  }
5015
5291
  send(session, connection, event) {
5016
- if (!this.current(session, connection) || !session.ready) return;
5292
+ if (!this.current(session, connection)) return;
5293
+ if (!session.ready) {
5294
+ this.addDropped(session, 1, false);
5295
+ return;
5296
+ }
5017
5297
  if (!this.connected(connection)) {
5018
5298
  this.addDropped(session, 1);
5019
5299
  this.fail(session, connection, "CONNECTION_LOST");
@@ -6519,6 +6799,11 @@ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode)
6519
6799
  CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
6520
6800
  CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
6521
6801
  CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
6802
+ /**
6803
+ * The `headers` builder threw, rejected, or returned something other than
6804
+ * an object. The request was not sent. `error.cause` is the builder's error.
6805
+ */
6806
+ CopilotKitCoreErrorCode["HEADER_RESOLUTION_FAILED"] = "header_resolution_failed";
6522
6807
  return CopilotKitCoreErrorCode;
6523
6808
  }({});
6524
6809
  /**
@@ -6541,17 +6826,8 @@ let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitC
6541
6826
  CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
6542
6827
  return CopilotKitCoreRuntimeConnectionStatus;
6543
6828
  }({});
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
6829
  var CopilotKitCore = class {
6554
- _headers;
6830
+ headerSource;
6555
6831
  _credentials;
6556
6832
  _messageFilter;
6557
6833
  _properties;
@@ -6582,7 +6858,14 @@ var CopilotKitCore = class {
6582
6858
  */
6583
6859
  previousAgentIds = /* @__PURE__ */ new Set();
6584
6860
  constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug, learning }) {
6585
- this._headers = normalizeHeaders(headers);
6861
+ this.headerSource = new HeaderSourceResolver((error) => {
6862
+ this.emitError({
6863
+ error,
6864
+ code: CopilotKitCoreErrorCode.HEADER_RESOLUTION_FAILED,
6865
+ context: { source: "headers" }
6866
+ });
6867
+ });
6868
+ this.headerSource.setSource(headers);
6586
6869
  this._credentials = credentials;
6587
6870
  this._messageFilter = messageFilter;
6588
6871
  this._properties = properties;
@@ -6640,6 +6923,7 @@ var CopilotKitCore = class {
6640
6923
  * Internal method used by delegate classes to emit errors
6641
6924
  */
6642
6925
  async emitError({ error, code, context = {} }) {
6926
+ if (code !== CopilotKitCoreErrorCode.HEADER_RESOLUTION_FAILED && isHeaderResolutionError(error)) return;
6643
6927
  await this.notifySubscribers((subscriber) => subscriber.onError?.({
6644
6928
  copilotkit: this,
6645
6929
  error,
@@ -6699,8 +6983,24 @@ var CopilotKitCore = class {
6699
6983
  get runtimeVersion() {
6700
6984
  return this.agentRegistry.runtimeVersion;
6701
6985
  }
6986
+ /**
6987
+ * The last resolved headers. With a builder this is the value from the most
6988
+ * recent request, not necessarily current; call `resolveHeaders()` for that.
6989
+ */
6702
6990
  get headers() {
6703
- return this._headers;
6991
+ return this.headerSource.headers;
6992
+ }
6993
+ /**
6994
+ * Resolve the current headers. Synchronous for a record or a sync builder,
6995
+ * a promise for an async builder. Concurrent calls share one builder call.
6996
+ * The returned object is shared; copy it before modifying.
6997
+ */
6998
+ resolveHeaders() {
6999
+ return this.headerSource.resolve();
7000
+ }
7001
+ /** Changes only on `setHeaders` or a new source, never on a new token. */
7002
+ get ɵheadersGeneration() {
7003
+ return this.headerSource.generation;
6704
7004
  }
6705
7005
  get credentials() {
6706
7006
  return this._credentials;
@@ -6841,9 +7141,17 @@ var CopilotKitCore = class {
6841
7141
  * with, set it at the provider/core level instead of on the agent, or update
6842
7142
  * it on the agent directly. The clear-on-logout pattern above is for
6843
7143
  * core-level headers.
7144
+ *
7145
+ * Pass a function to have headers evaluated when each request is sent
7146
+ * (sync or async). Setting the same function again is a no-op. A new token
7147
+ * from the builder doesn't notify `onHeadersChanged`. On a user switch,
7148
+ * call `setHeaders` with a NEW function (or a record), or remount.
7149
+ *
7150
+ * Passing a record equal (by value) to the currently applied record is
7151
+ * also a no-op — safe to call on every render with a fresh object literal.
6844
7152
  */
6845
7153
  setHeaders(headers) {
6846
- this._headers = normalizeHeaders(headers);
7154
+ if (!this.headerSource.setSource(headers)) return;
6847
7155
  if (this._memoryStore) this.syncMemoryContext();
6848
7156
  this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
6849
7157
  this.agentRegistry.handleHeadersChanged();
@@ -6990,8 +7298,8 @@ var CopilotKitCore = class {
6990
7298
  return this.learningBridge.registerOpenThread(params);
6991
7299
  }
6992
7300
  /**
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
7301
+ * Re-apply the last resolved header snapshot to a single agent (delegated
7302
+ * to AgentRegistry). Core headers are merged on top of the agent's own
6995
7303
  * construction-time headers rather than replacing them, so headers
6996
7304
  * configured directly on an `HttpAgent` (e.g. an `Authorization` for a
6997
7305
  * self-hosted backend) survive header updates instead of being silently
@@ -7002,11 +7310,31 @@ var CopilotKitCore = class {
7002
7310
  * afterwards is `setHeaders` (which re-applies to every agent), not mutating
7003
7311
  * `agent.headers` directly — a direct mutation is overwritten on the next
7004
7312
  * re-apply.
7313
+ *
7314
+ * A `ProxiedCopilotRuntimeAgent` keeps only its own construction-time
7315
+ * headers here — core headers are added by `ɵruntimeFetch` when each
7316
+ * request is sent (see #1937), so `agent.headers` never carries a stale
7317
+ * copy of a core header the builder has since stopped returning.
7318
+ *
7319
+ * Never invokes the headers builder (unlike the run/connect path's
7320
+ * internal `prepareAgentHeadersForRun`): safe to call from a dev-only
7321
+ * registration helper or a React effect that re-runs on every render
7322
+ * without risking a synchronous throw or an unhandled async rejection from
7323
+ * a user-supplied builder.
7005
7324
  */
7006
7325
  applyHeadersToAgent(agent) {
7007
7326
  this.agentRegistry.applyHeadersToAgent(agent);
7008
7327
  }
7009
7328
  /**
7329
+ * Resolve headers fresh and apply them to `agent` right before a run or
7330
+ * connect actually sends (#1937). Friends-only (delegated to
7331
+ * AgentRegistry) — the run handler is the sole caller, since resolving can
7332
+ * invoke a user-supplied builder that throws or rejects.
7333
+ */
7334
+ prepareAgentHeadersForRun(agent) {
7335
+ return this.agentRegistry.prepareAgentHeadersForRun(agent);
7336
+ }
7337
+ /**
7010
7338
  * Context management (delegated to ContextStore).
7011
7339
  * Pass `agentIds` to restrict the entry to runs of specific agents;
7012
7340
  * omit it for context every agent should receive.
@@ -7066,16 +7394,20 @@ var CopilotKitCore = class {
7066
7394
  /**
7067
7395
  * Pushes the current runtime wiring into the memory store. When the runtime
7068
7396
  * 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.
7397
+ * available, the store receives a context (runtime URL, WebSocket URL);
7398
+ * otherwise its context is cleared. No-op when the store has not been
7399
+ * created yet.
7400
+ *
7401
+ * Headers are deliberately NOT part of this context: the store's `fetch` is
7402
+ * `ɵruntimeFetch` (see `ensureMemoryStore`), which already resolves and
7403
+ * overlays the current core headers at send time (#1937) — a header
7404
+ * snapshot copied here would go stale between context syncs.
7072
7405
  */
7073
7406
  syncMemoryContext() {
7074
7407
  if (!this._memoryStore) return;
7075
7408
  if (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected && this.intelligence?.wsUrl && this.runtimeUrl) this._memoryStore.setContext({
7076
7409
  runtimeUrl: this.runtimeUrl,
7077
- wsUrl: this.intelligence.wsUrl,
7078
- headers: { ...this.headers }
7410
+ wsUrl: this.intelligence.wsUrl
7079
7411
  });
7080
7412
  else this._memoryStore.setContext(null);
7081
7413
  }
@@ -8506,6 +8838,7 @@ exports.ContextStore = ContextStore;
8506
8838
  exports.CopilotKitCore = CopilotKitCore;
8507
8839
  exports.CopilotKitCoreErrorCode = CopilotKitCoreErrorCode;
8508
8840
  exports.CopilotKitCoreRuntimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus;
8841
+ exports.CopilotKitHeaderResolutionError = CopilotKitHeaderResolutionError;
8509
8842
  exports.INSPECTOR_THREAD_BRIDGE_PLUGIN_ID = INSPECTOR_THREAD_BRIDGE_PLUGIN_ID;
8510
8843
  exports.IntelligenceAgent = IntelligenceAgent;
8511
8844
  exports.MEMORY_ERROR_REGISTRY = MEMORY_ERROR_REGISTRY;
@@ -8579,4 +8912,5 @@ exports.ɵselectThreads = ɵselectThreads;
8579
8912
  exports.ɵselectThreadsError = ɵselectThreadsError;
8580
8913
  exports.ɵselectThreadsIsLoading = ɵselectThreadsIsLoading;
8581
8914
  exports.ɵthreadAdapterEvents = ɵthreadAdapterEvents;
8915
+ exports.ɵwithHeaderDefaults = ɵwithHeaderDefaults;
8582
8916
  //# sourceMappingURL=index.cjs.map