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