@copilotkit/core 1.72.1-canary.sp-longthread-perf → 1.73.2-canary.1790068297
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 +438 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +141 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +438 -58
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +448 -62
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -380,16 +380,24 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
380
380
|
requestJoinCredentials$(mode, input, replayCursor) {
|
|
381
381
|
return (0, rxjs.defer)(async () => {
|
|
382
382
|
try {
|
|
383
|
-
const
|
|
383
|
+
const requestFetch = this.config.fetch ?? globalFetch;
|
|
384
|
+
const body = {
|
|
385
|
+
...input,
|
|
386
|
+
...mode === "connect" ? { lastSeenEventId: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor } : {}
|
|
387
|
+
};
|
|
388
|
+
const single = this.config.transport === "single";
|
|
389
|
+
const response = await requestFetch(single ? this.config.runtimeUrl : this.buildRuntimeUrl(mode), {
|
|
384
390
|
method: "POST",
|
|
391
|
+
redirect: "error",
|
|
385
392
|
headers: {
|
|
386
393
|
"Content-Type": "application/json",
|
|
387
394
|
...this.headers
|
|
388
395
|
},
|
|
389
|
-
body: JSON.stringify({
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
396
|
+
body: JSON.stringify(single ? {
|
|
397
|
+
method: `agent/${mode}`,
|
|
398
|
+
params: { agentId: this.config.agentId },
|
|
399
|
+
body
|
|
400
|
+
} : body),
|
|
393
401
|
...this.credentials ? { credentials: this.credentials } : {}
|
|
394
402
|
});
|
|
395
403
|
if (response.status === 204 && mode === "connect") return null;
|
|
@@ -623,6 +631,90 @@ function isRuntimeInfoRequestError(error) {
|
|
|
623
631
|
return typeof error === "object" && error !== null && typeof error.runtimeInfoStatus === "number";
|
|
624
632
|
}
|
|
625
633
|
|
|
634
|
+
//#endregion
|
|
635
|
+
//#region src/core/message-filter.ts
|
|
636
|
+
function toolCallIdsOf(message) {
|
|
637
|
+
const calls = message.toolCalls;
|
|
638
|
+
if (!Array.isArray(calls)) return [];
|
|
639
|
+
return calls.map((call) => call.id).filter((id) => Boolean(id));
|
|
640
|
+
}
|
|
641
|
+
function resultCallIdOf(message) {
|
|
642
|
+
if (message.role !== "tool") return void 0;
|
|
643
|
+
return message.toolCallId;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Repair the tool-call pairs a filter broke.
|
|
647
|
+
*
|
|
648
|
+
* Every provider rejects a half pair. A tool result whose call is gone reads as
|
|
649
|
+
* a reply to nothing, and an assistant tool call whose result is gone leaves
|
|
650
|
+
* the turn unanswered — the failure reporters hit on #1482 when a trimmed
|
|
651
|
+
* history landed mid-HITL and Anthropic answered "a tool result is expected".
|
|
652
|
+
* A filter written as `messages.slice(-1)` cannot know this, so the repair runs
|
|
653
|
+
* for every filter rather than being something each caller opts into.
|
|
654
|
+
*
|
|
655
|
+
* Both repairs restore, never discard, and both are anchored on the untrimmed
|
|
656
|
+
* thread:
|
|
657
|
+
*
|
|
658
|
+
* - A kept tool result whose assistant call was trimmed away gets that call put
|
|
659
|
+
* back in front of it. Dropping the result instead would be protocol-safe and
|
|
660
|
+
* semantically wrong: on a human-in-the-loop turn the result IS the new
|
|
661
|
+
* information, and a backend that already holds the call would be asked to
|
|
662
|
+
* resume with nothing.
|
|
663
|
+
* - A kept assistant call whose result was trimmed gets that result restored,
|
|
664
|
+
* placed directly after the call.
|
|
665
|
+
*
|
|
666
|
+
* Restoring a call pulls in every result for that call, not only the one the
|
|
667
|
+
* filter kept. Providers reject an assistant turn with a parallel tool call
|
|
668
|
+
* left unanswered, so a half-answered set is as invalid as a missing one.
|
|
669
|
+
*
|
|
670
|
+
* A call with no result anywhere in `full` is left alone. That is an open call
|
|
671
|
+
* (a pending frontend tool, an unanswered interrupt), not a broken pair. A
|
|
672
|
+
* result whose call is nowhere in `full` is left alone too: it was already
|
|
673
|
+
* unpaired before the filter ran, so it is not this function's to fix.
|
|
674
|
+
*
|
|
675
|
+
* The filter's own ordering is preserved. Restorations are the only insertions,
|
|
676
|
+
* and messages the filter synthesized (absent from `full`) pass through
|
|
677
|
+
* untouched.
|
|
678
|
+
*/
|
|
679
|
+
function ɵrepairToolCallPairs(kept, full) {
|
|
680
|
+
const callIdToIssuer = /* @__PURE__ */ new Map();
|
|
681
|
+
const callIdToResult = /* @__PURE__ */ new Map();
|
|
682
|
+
for (const message of full) {
|
|
683
|
+
for (const callId of toolCallIdsOf(message)) callIdToIssuer.set(callId, message);
|
|
684
|
+
const resultCallId = resultCallIdOf(message);
|
|
685
|
+
if (resultCallId !== void 0) callIdToResult.set(resultCallId, message);
|
|
686
|
+
}
|
|
687
|
+
const repaired = [];
|
|
688
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
689
|
+
const emit = (message) => {
|
|
690
|
+
if (emitted.has(message.id)) return;
|
|
691
|
+
emitted.add(message.id);
|
|
692
|
+
repaired.push(message);
|
|
693
|
+
};
|
|
694
|
+
/** Emit an assistant turn together with every result it is owed. */
|
|
695
|
+
const emitWithResults = (message) => {
|
|
696
|
+
emit(message);
|
|
697
|
+
for (const callId of toolCallIdsOf(message)) {
|
|
698
|
+
const result = callIdToResult.get(callId);
|
|
699
|
+
if (result) emit(result);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
for (const message of kept) {
|
|
703
|
+
const resultCallId = resultCallIdOf(message);
|
|
704
|
+
if (resultCallId === void 0) {
|
|
705
|
+
emitWithResults(message);
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
const issuer = callIdToIssuer.get(resultCallId);
|
|
709
|
+
if (issuer) {
|
|
710
|
+
emitWithResults(issuer);
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
emit(message);
|
|
714
|
+
}
|
|
715
|
+
return repaired;
|
|
716
|
+
}
|
|
717
|
+
|
|
626
718
|
//#endregion
|
|
627
719
|
//#region src/agent.ts
|
|
628
720
|
function hasHeaders(agent) {
|
|
@@ -661,6 +753,18 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
661
753
|
_capabilities;
|
|
662
754
|
delegate;
|
|
663
755
|
runtimeInfoPromise;
|
|
756
|
+
_messageFilter;
|
|
757
|
+
/**
|
|
758
|
+
* The HTTP `run` this agent started and has not yet seen finish, as the
|
|
759
|
+
* exact `{ threadId, runId }` it POSTed. `abortRun` narrows `/stop` to this
|
|
760
|
+
* run only while `threadId` still matches: `threadId` is a public field the
|
|
761
|
+
* host may reassign under a live run, and a runId from another thread must
|
|
762
|
+
* not be sent as if it were this thread's. Released when the run stream
|
|
763
|
+
* finalizes, cleared on `connect` (a reconnected thread may run under a
|
|
764
|
+
* runId this client never saw) and never copied by `clone`. Without a
|
|
765
|
+
* provable active run the stop stays thread-wide.
|
|
766
|
+
*/
|
|
767
|
+
activeRun;
|
|
664
768
|
constructor(config) {
|
|
665
769
|
const normalizedRuntimeUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/$/, "") : void 0;
|
|
666
770
|
const transport = config.transport ?? "auto";
|
|
@@ -679,10 +783,47 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
679
783
|
this.runtimeMode = config.runtimeMode ?? _copilotkit_shared.RUNTIME_MODE_SSE;
|
|
680
784
|
this.intelligence = config.intelligence;
|
|
681
785
|
this._capabilities = config.capabilities;
|
|
786
|
+
this._messageFilter = config.messageFilter;
|
|
682
787
|
if (config.debug) this.debug = config.debug;
|
|
683
788
|
if (this.transport === "single") this.singleEndpointUrl = this.runtimeEndpointUrl;
|
|
684
789
|
}
|
|
685
790
|
/**
|
|
791
|
+
* Adopt the runtime mode a fresh `/info` just reported.
|
|
792
|
+
*
|
|
793
|
+
* A live proxy outlives the runtime configuration that minted it: a
|
|
794
|
+
* redeploy, an env-var change or a rollback can flip `intelligence` → `sse`
|
|
795
|
+
* under a page that is already open. The registry preserves the proxy across
|
|
796
|
+
* that re-sync on purpose — it is backing an open conversation — so the new
|
|
797
|
+
* mode is pushed onto the instance here instead of replacing it.
|
|
798
|
+
*
|
|
799
|
+
* Without this the mode was decided once, at construction, and `run()` kept
|
|
800
|
+
* taking the delegate path against a runtime serving plain SSE, where
|
|
801
|
+
* `response.json()` on a `text/event-stream` body throws for the rest of the
|
|
802
|
+
* page's life. See #7130.
|
|
803
|
+
*
|
|
804
|
+
* A delegate built for the old mode is torn down: it speaks a protocol the
|
|
805
|
+
* runtime no longer serves, and it may be holding a websocket open. The
|
|
806
|
+
* memoized `/info` promise goes with it — it answered for the old
|
|
807
|
+
* configuration, so a later `ensureRuntimeConfiguration()` must re-ask
|
|
808
|
+
* rather than treat that answer as current.
|
|
809
|
+
*
|
|
810
|
+
* Only `wsUrl` is compared on the Intelligence metadata, because that is the
|
|
811
|
+
* one field the delegate bakes in at construction.
|
|
812
|
+
*/
|
|
813
|
+
adoptRuntimeMode(runtimeMode, intelligence) {
|
|
814
|
+
const unchanged = this.runtimeMode === runtimeMode && this.intelligence?.wsUrl === intelligence?.wsUrl;
|
|
815
|
+
this.runtimeMode = runtimeMode;
|
|
816
|
+
this.intelligence = intelligence;
|
|
817
|
+
if (unchanged) return;
|
|
818
|
+
this.runtimeInfoPromise = void 0;
|
|
819
|
+
const staleDelegate = this.delegate;
|
|
820
|
+
this.delegate = void 0;
|
|
821
|
+
if (staleDelegate) {
|
|
822
|
+
staleDelegate.abortRun();
|
|
823
|
+
this.detachActiveRun();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
686
827
|
* The agent id used for outbound runtime requests — `runtimeAgentId` when
|
|
687
828
|
* set (manually-registered proxy), otherwise `agentId` (registry id
|
|
688
829
|
* matches runtime id). Subscriber bookkeeping keeps using `agentId`
|
|
@@ -700,6 +841,67 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
700
841
|
get capabilities() {
|
|
701
842
|
return this._capabilities;
|
|
702
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* The filter applied to the outbound message list on every run.
|
|
846
|
+
*
|
|
847
|
+
* Registry-owned. `AgentRegistry` writes it whenever the core-level filter
|
|
848
|
+
* changes, so an agent discovered before the app configured one still picks
|
|
849
|
+
* it up — and so a value written here by hand is replaced on the registry's
|
|
850
|
+
* next sweep. Configure it through `CopilotKitCore` instead.
|
|
851
|
+
*/
|
|
852
|
+
get messageFilter() {
|
|
853
|
+
return this._messageFilter;
|
|
854
|
+
}
|
|
855
|
+
set messageFilter(filter) {
|
|
856
|
+
this._messageFilter = filter;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Narrow the outbound payload with the configured message filter.
|
|
860
|
+
*
|
|
861
|
+
* **Called from the HTTP paths only, and that placement is the Intelligence
|
|
862
|
+
* exemption.** An earlier revision applied the filter in
|
|
863
|
+
* `prepareRunAgentInput`, which runs before the runtime mode is resolved:
|
|
864
|
+
* with the default `"auto"` transport, or on a proxy still `"pending"` its
|
|
865
|
+
* first `/info`, `run()` prepared the input, *then* resolved the mode, then
|
|
866
|
+
* handed that already-filtered input to `#runViaDelegate` — so a managed
|
|
867
|
+
* runtime received a truncated thread despite the exemption. Filtering here
|
|
868
|
+
* makes that unreachable by construction: `#runViaHttp` and
|
|
869
|
+
* `#connectViaHttp` are only entered once the mode is known not to be
|
|
870
|
+
* Intelligence. Do not move this back up the call chain.
|
|
871
|
+
*
|
|
872
|
+
* The managed runtime is the store of record for the thread — the threads
|
|
873
|
+
* drawer and the Slack transcript read from it — so a client-side truncation
|
|
874
|
+
* there has a blast radius nobody asked for. Every reporter on #1482 is
|
|
875
|
+
* self-hosted.
|
|
876
|
+
*
|
|
877
|
+
* `prepareRunAgentInput` has already deep-cloned the thread and stripped
|
|
878
|
+
* `activity` messages by the time the input reaches here, so the filter
|
|
879
|
+
* cannot reach the messages the UI renders no matter what it does with the
|
|
880
|
+
* array it is handed. The filter gets a *second* deep clone on top of that,
|
|
881
|
+
* because `input.messages` is also the repair baseline and the untrimmed
|
|
882
|
+
* fallback: sharing the message objects let a filter that mutates a kept
|
|
883
|
+
* message's `toolCallId` corrupt the baseline, and an orphaned tool result
|
|
884
|
+
* then went out on the wire — a payload the provider rejects, which is
|
|
885
|
+
* exactly the failure this whole mechanism exists to prevent.
|
|
886
|
+
*/
|
|
887
|
+
#applyMessageFilter(input) {
|
|
888
|
+
const filter = this._messageFilter;
|
|
889
|
+
if (!filter) return input;
|
|
890
|
+
try {
|
|
891
|
+
const kept = filter((0, _ag_ui_client.structuredClone_)(input.messages), { agentId: this.agentId ?? "" });
|
|
892
|
+
if (!Array.isArray(kept)) {
|
|
893
|
+
console.warn("ProxiedCopilotRuntimeAgent: messageFilter returned a non-array value; sending the full message history instead.");
|
|
894
|
+
return input;
|
|
895
|
+
}
|
|
896
|
+
return {
|
|
897
|
+
...input,
|
|
898
|
+
messages: ɵrepairToolCallPairs(kept, input.messages)
|
|
899
|
+
};
|
|
900
|
+
} catch (error) {
|
|
901
|
+
console.warn("ProxiedCopilotRuntimeAgent: messageFilter failed; sending the full message history instead.", error);
|
|
902
|
+
return input;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
703
905
|
requestInit(input) {
|
|
704
906
|
return {
|
|
705
907
|
...super.requestInit(input),
|
|
@@ -723,6 +925,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
723
925
|
if (!this.agentId || !this.threadId) return;
|
|
724
926
|
if (typeof fetch === "undefined") return;
|
|
725
927
|
const routedId = this.routedAgentId();
|
|
928
|
+
const runId = this.activeRun?.threadId === this.threadId ? this.activeRun.runId : void 0;
|
|
726
929
|
if (this.transport === "single") {
|
|
727
930
|
if (!this.singleEndpointUrl) return;
|
|
728
931
|
const headers = new Headers({
|
|
@@ -737,7 +940,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
737
940
|
params: {
|
|
738
941
|
agentId: routedId,
|
|
739
942
|
threadId: this.threadId
|
|
740
|
-
}
|
|
943
|
+
},
|
|
944
|
+
...runId === void 0 ? {} : { body: { runId } }
|
|
741
945
|
}),
|
|
742
946
|
...this.credentials ? { credentials: this.credentials } : {}
|
|
743
947
|
}).catch((error) => {
|
|
@@ -756,6 +960,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
756
960
|
"Content-Type": "application/json",
|
|
757
961
|
...this.headers
|
|
758
962
|
},
|
|
963
|
+
...runId === void 0 ? {} : { body: JSON.stringify({ runId }) },
|
|
759
964
|
...this.credentials ? { credentials: this.credentials } : {}
|
|
760
965
|
}).catch((error) => {
|
|
761
966
|
console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
|
|
@@ -811,7 +1016,9 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
811
1016
|
#connectViaDelegate(input) {
|
|
812
1017
|
return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.connect(input))));
|
|
813
1018
|
}
|
|
814
|
-
#connectViaHttp(
|
|
1019
|
+
#connectViaHttp(unfiltered) {
|
|
1020
|
+
const input = this.#applyMessageFilter(unfiltered);
|
|
1021
|
+
this.activeRun = void 0;
|
|
815
1022
|
const routedId = this.routedAgentId();
|
|
816
1023
|
if (this.transport === "single") {
|
|
817
1024
|
if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
|
|
@@ -825,13 +1032,24 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
825
1032
|
#runViaDelegate(input) {
|
|
826
1033
|
return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.run(input))));
|
|
827
1034
|
}
|
|
828
|
-
#runViaHttp(
|
|
1035
|
+
#runViaHttp(unfiltered) {
|
|
1036
|
+
const input = this.#applyMessageFilter(unfiltered);
|
|
1037
|
+
const activeRun = {
|
|
1038
|
+
threadId: input.threadId,
|
|
1039
|
+
runId: input.runId
|
|
1040
|
+
};
|
|
1041
|
+
const trackActiveRun = (source) => {
|
|
1042
|
+
this.activeRun = activeRun;
|
|
1043
|
+
return source.pipe((0, rxjs_operators.finalize)(() => {
|
|
1044
|
+
if (this.activeRun === activeRun) this.activeRun = void 0;
|
|
1045
|
+
}));
|
|
1046
|
+
};
|
|
829
1047
|
if (this.transport === "single") {
|
|
830
1048
|
if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
|
|
831
1049
|
const requestInit = this.createSingleRouteRequestInit(input, "agent/run", { agentId: this.routedAgentId() });
|
|
832
|
-
return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(() => this.fetch(this.singleEndpointUrl, requestInit))));
|
|
1050
|
+
return trackActiveRun(withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(() => this.fetch(this.singleEndpointUrl, requestInit)))));
|
|
833
1051
|
}
|
|
834
|
-
return withAbortErrorHandling(super.run(input));
|
|
1052
|
+
return trackActiveRun(withAbortErrorHandling(super.run(input)));
|
|
835
1053
|
}
|
|
836
1054
|
clone() {
|
|
837
1055
|
const cloned = new ProxiedCopilotRuntimeAgent({
|
|
@@ -846,7 +1064,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
846
1064
|
intelligence: this.intelligence,
|
|
847
1065
|
capabilities: this._capabilities,
|
|
848
1066
|
debug: this.debug,
|
|
849
|
-
fetch: this.fetch
|
|
1067
|
+
fetch: this.fetch,
|
|
1068
|
+
messageFilter: this._messageFilter
|
|
850
1069
|
});
|
|
851
1070
|
cloned.threadId = this.threadId;
|
|
852
1071
|
cloned.setState(this.state);
|
|
@@ -974,9 +1193,11 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
|
|
|
974
1193
|
createIntelligenceDelegate() {
|
|
975
1194
|
const routedId = this.routedAgentId();
|
|
976
1195
|
if (!this.runtimeUrl || !routedId || !this.intelligence?.wsUrl) throw new Error("Intelligence mode requires runtimeUrl, agentId, and intelligence websocket metadata");
|
|
1196
|
+
const single = this.transport === "single";
|
|
977
1197
|
return new IntelligenceAgent({
|
|
978
1198
|
url: this.intelligence.wsUrl,
|
|
979
|
-
runtimeUrl: this.runtimeUrl,
|
|
1199
|
+
runtimeUrl: single ? this.runtimeEndpointUrl ?? this.runtimeUrl : this.runtimeUrl,
|
|
1200
|
+
transport: single ? "single" : "rest",
|
|
980
1201
|
agentId: routedId,
|
|
981
1202
|
headers: { ...this.headers },
|
|
982
1203
|
credentials: this.credentials,
|
|
@@ -1239,6 +1460,7 @@ var AgentRegistry = class {
|
|
|
1239
1460
|
this.localAgents = this.assignAgentIds(agents);
|
|
1240
1461
|
this.applyHeadersToAgents(this.localAgents);
|
|
1241
1462
|
this.applyCredentialsToAgents(this.localAgents);
|
|
1463
|
+
this.applyMessageFilterToAgents(this.localAgents);
|
|
1242
1464
|
this.applyRuntimeFetchToAgents(this.localAgents);
|
|
1243
1465
|
this._agents = this.localAgents;
|
|
1244
1466
|
}
|
|
@@ -1330,6 +1552,7 @@ var AgentRegistry = class {
|
|
|
1330
1552
|
};
|
|
1331
1553
|
this.applyHeadersToAgents(this._agents);
|
|
1332
1554
|
this.applyCredentialsToAgents(this._agents);
|
|
1555
|
+
this.applyMessageFilterToAgents(this._agents);
|
|
1333
1556
|
this.applyRuntimeFetchToAgents(this._agents);
|
|
1334
1557
|
this.notifyAgentsChanged();
|
|
1335
1558
|
}
|
|
@@ -1382,7 +1605,8 @@ var AgentRegistry = class {
|
|
|
1382
1605
|
credentials: friends.credentials,
|
|
1383
1606
|
runtimeMode: this._runtimeUrl ? this._runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected ? this._runtimeMode : "pending" : _copilotkit_shared.RUNTIME_MODE_SSE,
|
|
1384
1607
|
intelligence: this._intelligence,
|
|
1385
|
-
debug: debug ? (0, _copilotkit_shared.resolveDebugConfig)(debug) : void 0
|
|
1608
|
+
debug: debug ? (0, _copilotkit_shared.resolveDebugConfig)(debug) : void 0,
|
|
1609
|
+
messageFilter: friends.messageFilter
|
|
1386
1610
|
});
|
|
1387
1611
|
this.applyHeadersToAgent(agent);
|
|
1388
1612
|
this.applyRuntimeFetchToAgent(agent);
|
|
@@ -1451,6 +1675,45 @@ var AgentRegistry = class {
|
|
|
1451
1675
|
this.applyCredentialsToAgent(agent);
|
|
1452
1676
|
});
|
|
1453
1677
|
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Carry the mode a fresh `/info` reported onto a proxy this re-sync kept.
|
|
1680
|
+
*
|
|
1681
|
+
* `canReuseRuntimeAgent` deliberately ignores the mode: a preserved proxy is
|
|
1682
|
+
* backing an open conversation, and replacing the instance to change one
|
|
1683
|
+
* field would drop it. The mode is therefore pushed onto the survivor here,
|
|
1684
|
+
* the same way headers and credentials are. Without it the mode was fixed at
|
|
1685
|
+
* construction, so a runtime that flipped `intelligence` → `sse` under an
|
|
1686
|
+
* open page left every later run on the delegate path. See #7130.
|
|
1687
|
+
*/
|
|
1688
|
+
applyRuntimeModeToAgent(agent, runtimeInfo) {
|
|
1689
|
+
if (agent instanceof ProxiedCopilotRuntimeAgent) agent.adoptRuntimeMode(runtimeInfo.mode ?? _copilotkit_shared.RUNTIME_MODE_SSE, runtimeInfo.intelligence);
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Apply the core's message filter to an agent.
|
|
1693
|
+
*
|
|
1694
|
+
* The test is the class, not which bucket the agent is registered in: every
|
|
1695
|
+
* `ProxiedCopilotRuntimeAgent` gets the core filter, whether it came from
|
|
1696
|
+
* `/info` or from `registerProxiedAgent` (which files its proxy under
|
|
1697
|
+
* `localAgents`). Agents of any other class are left untouched — an
|
|
1698
|
+
* `AbstractAgent` the app built has no such hook, and its owner already has
|
|
1699
|
+
* the AG-UI middleware seam.
|
|
1700
|
+
*
|
|
1701
|
+
* This is the sole writer of `agent.messageFilter` in normal operation. The
|
|
1702
|
+
* public setter exists for the registry and for tests; a value written
|
|
1703
|
+
* directly onto an agent is replaced the next time the registry sweeps, the
|
|
1704
|
+
* same way per-agent credentials are.
|
|
1705
|
+
*/
|
|
1706
|
+
applyMessageFilterToAgent(agent) {
|
|
1707
|
+
if (agent instanceof ProxiedCopilotRuntimeAgent) agent.messageFilter = this.core.messageFilter;
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Apply the core's message filter to all agents
|
|
1711
|
+
*/
|
|
1712
|
+
applyMessageFilterToAgents(agents) {
|
|
1713
|
+
Object.values(agents).forEach((agent) => {
|
|
1714
|
+
this.applyMessageFilterToAgent(agent);
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1454
1717
|
createRuntimeFetch() {
|
|
1455
1718
|
if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
|
|
1456
1719
|
const meta = () => runtimeRequestMeta(init);
|
|
@@ -1838,7 +2101,9 @@ var AgentRegistry = class {
|
|
|
1838
2101
|
if (existing instanceof ProxiedCopilotRuntimeAgent && this.canReuseRuntimeAgent(existing, runtimeUrl, this._runtimeTransport)) {
|
|
1839
2102
|
this.applyHeadersToAgent(existing);
|
|
1840
2103
|
this.applyCredentialsToAgent(existing);
|
|
2104
|
+
this.applyMessageFilterToAgent(existing);
|
|
1841
2105
|
this.applyRuntimeFetchToAgent(existing);
|
|
2106
|
+
this.applyRuntimeModeToAgent(existing, runtimeInfoResponse);
|
|
1842
2107
|
return [id, existing];
|
|
1843
2108
|
}
|
|
1844
2109
|
const agent = new ProxiedCopilotRuntimeAgent({
|
|
@@ -1850,7 +2115,8 @@ var AgentRegistry = class {
|
|
|
1850
2115
|
runtimeMode: runtimeInfoResponse.mode ?? _copilotkit_shared.RUNTIME_MODE_SSE,
|
|
1851
2116
|
intelligence: runtimeInfoResponse.intelligence,
|
|
1852
2117
|
capabilities,
|
|
1853
|
-
debug: rawDebug ? (0, _copilotkit_shared.resolveDebugConfig)(rawDebug) : void 0
|
|
2118
|
+
debug: rawDebug ? (0, _copilotkit_shared.resolveDebugConfig)(rawDebug) : void 0,
|
|
2119
|
+
messageFilter: this.core.messageFilter
|
|
1854
2120
|
});
|
|
1855
2121
|
this.applyHeadersToAgent(agent);
|
|
1856
2122
|
this.applyRuntimeFetchToAgent(agent);
|
|
@@ -2242,7 +2508,10 @@ var SuggestionEngine = class {
|
|
|
2242
2508
|
credentials
|
|
2243
2509
|
}) } : {}
|
|
2244
2510
|
});
|
|
2245
|
-
} else
|
|
2511
|
+
} else {
|
|
2512
|
+
suggestionAgent = suggestionsProviderAgent.clone();
|
|
2513
|
+
if (suggestionAgent instanceof ProxiedCopilotRuntimeAgent) suggestionAgent.messageFilter = void 0;
|
|
2514
|
+
}
|
|
2246
2515
|
suggestionAgent.threadId = suggestionId;
|
|
2247
2516
|
suggestionAgent.setMessages(seededMessages);
|
|
2248
2517
|
suggestionAgent.setState(seededState);
|
|
@@ -2604,6 +2873,19 @@ var WebMCPRegistry = class {
|
|
|
2604
2873
|
//#endregion
|
|
2605
2874
|
//#region src/core/run-handler.ts
|
|
2606
2875
|
/**
|
|
2876
|
+
* Live approvals cancelled by stopping their own run, keyed by the handler's
|
|
2877
|
+
* signal. The value reports whether that stop is still current: no reconnect
|
|
2878
|
+
* has started and the thread is unchanged, so nothing will restore the call.
|
|
2879
|
+
*
|
|
2880
|
+
* Kept here rather than in `AbortSignal.reason`: React Native's global
|
|
2881
|
+
* `AbortController` is the `abort-controller@3` polyfill, whose `abort()`
|
|
2882
|
+
* takes no reason and whose signals never expose one.
|
|
2883
|
+
*/
|
|
2884
|
+
const liveHITLStops = /* @__PURE__ */ new WeakMap();
|
|
2885
|
+
function discardAbortedResult(signal, discardOnAbort, errorMessage) {
|
|
2886
|
+
return !!(discardOnAbort && signal?.aborted && !(liveHITLStops.get(signal)?.() && errorMessage));
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2607
2889
|
* Absolute safety cap on the depth of recursive follow-up runs triggered by
|
|
2608
2890
|
* `processAgentResult`. Without this, any scenario that keeps
|
|
2609
2891
|
* `needsFollowUp = true` (e.g. the LLM repeatedly calling the same tool, a
|
|
@@ -2716,6 +2998,10 @@ var RunHandler = class {
|
|
|
2716
2998
|
_lastConnectedThreadIdsByAgent = /* @__PURE__ */ new Map();
|
|
2717
2999
|
_anonymousAgentIds = /* @__PURE__ */ new WeakMap();
|
|
2718
3000
|
_nextAnonymousAgentId = 0;
|
|
3001
|
+
/** Prevent reconnects from starting an interaction already executing locally. */
|
|
3002
|
+
_executingToolCalls = /* @__PURE__ */ new WeakMap();
|
|
3003
|
+
_connectionGenerations = /* @__PURE__ */ new WeakMap();
|
|
3004
|
+
_interactionAbortControllers = /* @__PURE__ */ new WeakMap();
|
|
2719
3005
|
constructor(core) {
|
|
2720
3006
|
this.core = core;
|
|
2721
3007
|
}
|
|
@@ -2724,8 +3010,14 @@ var RunHandler = class {
|
|
|
2724
3010
|
* that in-flight tool handlers should stop and `processAgentResult` should
|
|
2725
3011
|
* not start a follow-up run.
|
|
2726
3012
|
*/
|
|
2727
|
-
abortCurrentRun() {
|
|
3013
|
+
abortCurrentRun(agent) {
|
|
2728
3014
|
this._runAbortController?.abort();
|
|
3015
|
+
const replay = this._interactionAbortControllers.get(agent);
|
|
3016
|
+
if (replay) {
|
|
3017
|
+
for (const controller of replay.controllers) controller.abort();
|
|
3018
|
+
this._interactionAbortControllers.delete(agent);
|
|
3019
|
+
this._executingToolCalls.delete(agent);
|
|
3020
|
+
}
|
|
2729
3021
|
}
|
|
2730
3022
|
/**
|
|
2731
3023
|
* Typed access to CopilotKitCore's internal ("friend") methods.
|
|
@@ -2881,7 +3173,14 @@ var RunHandler = class {
|
|
|
2881
3173
|
* Connect an agent (establish initial connection)
|
|
2882
3174
|
*/
|
|
2883
3175
|
async connectAgent({ agent }) {
|
|
3176
|
+
this._connectionGenerations.set(agent, {});
|
|
2884
3177
|
const incomingThreadId = agent.threadId ?? null;
|
|
3178
|
+
const previousReplay = this._interactionAbortControllers.get(agent);
|
|
3179
|
+
if (previousReplay && previousReplay.threadId !== incomingThreadId) {
|
|
3180
|
+
for (const controller of previousReplay.controllers) controller.abort();
|
|
3181
|
+
this._interactionAbortControllers.delete(agent);
|
|
3182
|
+
this._executingToolCalls.delete(agent);
|
|
3183
|
+
}
|
|
2885
3184
|
try {
|
|
2886
3185
|
const restoreKey = this.getConnectRestoreKey(agent);
|
|
2887
3186
|
const isFreshRestore = incomingThreadId !== (this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
|
|
@@ -2906,11 +3205,33 @@ var RunHandler = class {
|
|
|
2906
3205
|
tools: this.buildFrontendTools(agent.agentId),
|
|
2907
3206
|
context: this._internal.getContextForAgent(agent.agentId)
|
|
2908
3207
|
}, this.createAgentErrorSubscriber(agent));
|
|
2909
|
-
return
|
|
3208
|
+
if ((agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
|
|
3209
|
+
const controller = new AbortController();
|
|
3210
|
+
const replay = this._interactionAbortControllers.get(agent) ?? {
|
|
3211
|
+
threadId: incomingThreadId,
|
|
3212
|
+
controllers: /* @__PURE__ */ new Set()
|
|
3213
|
+
};
|
|
3214
|
+
replay.controllers.add(controller);
|
|
3215
|
+
this._interactionAbortControllers.set(agent, replay);
|
|
3216
|
+
this.processAgentResult({
|
|
2910
3217
|
runAgentResult,
|
|
2911
3218
|
agent,
|
|
2912
|
-
|
|
3219
|
+
toolExecutionMode: "human-in-the-loop",
|
|
3220
|
+
signal: controller.signal
|
|
3221
|
+
}).catch(async (error) => {
|
|
3222
|
+
await this._internal.emitError({
|
|
3223
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
3224
|
+
code: CopilotKitCoreErrorCode.AGENT_CONNECT_FAILED,
|
|
3225
|
+
context: {
|
|
3226
|
+
agentId: agent.agentId,
|
|
3227
|
+
threadId: incomingThreadId
|
|
3228
|
+
}
|
|
3229
|
+
});
|
|
3230
|
+
}).finally(() => {
|
|
3231
|
+
replay.controllers.delete(controller);
|
|
3232
|
+
if (replay.controllers.size === 0 && this._interactionAbortControllers.get(agent) === replay) this._interactionAbortControllers.delete(agent);
|
|
2913
3233
|
});
|
|
3234
|
+
return runAgentResult;
|
|
2914
3235
|
} catch (error) {
|
|
2915
3236
|
const connectError = error instanceof Error ? error : new Error(String(error));
|
|
2916
3237
|
if (!isAbortError$1(connectError)) {
|
|
@@ -3012,45 +3333,83 @@ var RunHandler = class {
|
|
|
3012
3333
|
/**
|
|
3013
3334
|
* Process agent result and execute tools
|
|
3014
3335
|
*/
|
|
3015
|
-
async processAgentResult({ runAgentResult, agent, runId,
|
|
3336
|
+
async processAgentResult({ runAgentResult, agent, runId, toolExecutionMode = "all", signal = this._runAbortController?.signal }) {
|
|
3016
3337
|
const { newMessages } = runAgentResult;
|
|
3017
3338
|
const agentId = agent.agentId;
|
|
3018
3339
|
let needsFollowUp = false;
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3340
|
+
const threadId = agent.threadId;
|
|
3341
|
+
const executing = this._executingToolCalls.get(agent) ?? /* @__PURE__ */ new Set();
|
|
3342
|
+
this._executingToolCalls.set(agent, executing);
|
|
3343
|
+
if (toolExecutionMode === "human-in-the-loop" && agent.messages.some((message) => message.role === "assistant" && message.toolCalls?.some((call) => executing.has(JSON.stringify([threadId, call.id])) && !agent.messages.some((result) => result.role === "tool" && result.toolCallId === call.id && !this.isFrontendPlaceholderResult(result))))) return runAgentResult;
|
|
3344
|
+
const messagesToProcess = toolExecutionMode === "human-in-the-loop" ? [...agent.messages] : newMessages;
|
|
3345
|
+
for (const message of messagesToProcess) if (message.role === "assistant") for (const toolCall of message.toolCalls || []) {
|
|
3346
|
+
const tool = this.getTool({
|
|
3347
|
+
toolName: toolCall.function.name,
|
|
3348
|
+
agentId: agent.agentId
|
|
3349
|
+
});
|
|
3350
|
+
let wildcardTool;
|
|
3351
|
+
const getWildcardTool = () => {
|
|
3352
|
+
if (tool || wildcardTool) return wildcardTool;
|
|
3353
|
+
wildcardTool = this.getTool({
|
|
3354
|
+
toolName: WILDCARD_TOOL_NAME,
|
|
3023
3355
|
agentId: agent.agentId
|
|
3024
3356
|
});
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3357
|
+
return wildcardTool;
|
|
3358
|
+
};
|
|
3359
|
+
const executableTool = tool ?? getWildcardTool();
|
|
3360
|
+
if (toolExecutionMode === "human-in-the-loop" && (executableTool?.type !== "human-in-the-loop" || !executableTool.handler)) continue;
|
|
3361
|
+
const executionKey = JSON.stringify([threadId, toolCall.id]);
|
|
3362
|
+
if (signal?.aborted || agent.threadId !== threadId || executing.has(executionKey)) continue;
|
|
3363
|
+
const existingResultIndex = newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
|
|
3364
|
+
let existingResult = agent.messages.find((m) => m.role === "tool" && m.toolCallId === toolCall.id) ?? newMessages[existingResultIndex];
|
|
3365
|
+
if (existingResult && executableTool?.handler && this.isFrontendPlaceholderResult(existingResult)) {
|
|
3366
|
+
if (existingResultIndex !== -1) newMessages.splice(existingResultIndex, 1);
|
|
3367
|
+
existingResult = void 0;
|
|
3368
|
+
const agentMsgIdx = agent.messages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
|
|
3369
|
+
if (agentMsgIdx !== -1) agent.messages.splice(agentMsgIdx, 1);
|
|
3370
|
+
}
|
|
3371
|
+
if (!existingResult) {
|
|
3372
|
+
executing.add(executionKey);
|
|
3373
|
+
const interactionController = toolExecutionMode === "all" && executableTool?.type === "human-in-the-loop" ? new AbortController() : void 0;
|
|
3374
|
+
const interactions = this._interactionAbortControllers.get(agent) ?? {
|
|
3375
|
+
threadId: threadId ?? null,
|
|
3376
|
+
controllers: /* @__PURE__ */ new Set()
|
|
3377
|
+
};
|
|
3378
|
+
const abortInteraction = () => {
|
|
3379
|
+
if (!interactionController) return;
|
|
3380
|
+
const connectionGeneration = this._connectionGenerations.get(agent);
|
|
3381
|
+
liveHITLStops.set(interactionController.signal, () => this._connectionGenerations.get(agent) === connectionGeneration && agent.threadId === threadId);
|
|
3382
|
+
interactionController.abort();
|
|
3033
3383
|
};
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
existingResultIndex = -1;
|
|
3040
|
-
const agentMsgIdx = agent.messages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
|
|
3041
|
-
if (agentMsgIdx !== -1) agent.messages.splice(agentMsgIdx, 1);
|
|
3384
|
+
if (interactionController) {
|
|
3385
|
+
interactions.controllers.add(interactionController);
|
|
3386
|
+
this._interactionAbortControllers.set(agent, interactions);
|
|
3387
|
+
signal?.addEventListener("abort", abortInteraction, { once: true });
|
|
3388
|
+
if (signal?.aborted) abortInteraction();
|
|
3042
3389
|
}
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3390
|
+
const executionSignal = interactionController?.signal ?? signal;
|
|
3391
|
+
const discardOnAbort = toolExecutionMode === "human-in-the-loop" || !!interactionController;
|
|
3392
|
+
try {
|
|
3393
|
+
if (tool) {
|
|
3394
|
+
if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
|
|
3395
|
+
} else {
|
|
3396
|
+
const fallbackTool = getWildcardTool();
|
|
3397
|
+
if (fallbackTool) {
|
|
3398
|
+
if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
} finally {
|
|
3402
|
+
executing.delete(executionKey);
|
|
3403
|
+
if (interactionController) {
|
|
3404
|
+
signal?.removeEventListener("abort", abortInteraction);
|
|
3405
|
+
interactions.controllers.delete(interactionController);
|
|
3406
|
+
if (interactions.controllers.size === 0 && this._interactionAbortControllers.get(agent) === interactions) this._interactionAbortControllers.delete(agent);
|
|
3049
3407
|
}
|
|
3050
3408
|
}
|
|
3409
|
+
if (interactionController?.signal.aborted) return runAgentResult;
|
|
3051
3410
|
}
|
|
3052
3411
|
}
|
|
3053
|
-
if (needsFollowUp && !
|
|
3412
|
+
if (needsFollowUp && agent.threadId === threadId && !signal?.aborted) if (this._runDepth >= MAX_FOLLOW_UP_DEPTH) _copilotkit_shared.logger.warn(`[CopilotKit] Follow-up depth limit (${MAX_FOLLOW_UP_DEPTH}) reached for agent "${agentId}". Stopping recursive follow-up runs to prevent an infinite loop. This usually indicates a tool that keeps requesting a follow-up (e.g. the LLM repeatedly calling the same tool). Consider setting "followUp: false" on the offending tool.`);
|
|
3054
3413
|
else {
|
|
3055
3414
|
await this._internal.waitForPendingFrameworkUpdates();
|
|
3056
3415
|
const continuationHandoff = this._internal.stateManager.markNextRunAsContinuation(agent, runId);
|
|
@@ -3070,7 +3429,7 @@ var RunHandler = class {
|
|
|
3070
3429
|
* Handles arg parsing, subscriber notifications, handler invocation, result stringification,
|
|
3071
3430
|
* and error handling.
|
|
3072
3431
|
*/
|
|
3073
|
-
async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId }) {
|
|
3432
|
+
async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId, signal = this._runAbortController?.signal, discardOnAbort = false }) {
|
|
3074
3433
|
let toolCallResult = "";
|
|
3075
3434
|
let errorMessage;
|
|
3076
3435
|
let isArgumentError = false;
|
|
@@ -3105,7 +3464,7 @@ var RunHandler = class {
|
|
|
3105
3464
|
const result = await tool.handler(parsedArgs, {
|
|
3106
3465
|
toolCall,
|
|
3107
3466
|
agent,
|
|
3108
|
-
signal
|
|
3467
|
+
signal
|
|
3109
3468
|
});
|
|
3110
3469
|
if (result === void 0 || result === null) toolCallResult = "";
|
|
3111
3470
|
else if (typeof result === "string") toolCallResult = result;
|
|
@@ -3113,7 +3472,7 @@ var RunHandler = class {
|
|
|
3113
3472
|
} catch (error) {
|
|
3114
3473
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3115
3474
|
errorMessage = handlerError.message;
|
|
3116
|
-
await this._internal.emitError({
|
|
3475
|
+
if (!discardAbortedResult(signal, discardOnAbort, errorMessage)) await this._internal.emitError({
|
|
3117
3476
|
error: handlerError,
|
|
3118
3477
|
code: CopilotKitCoreErrorCode.TOOL_HANDLER_FAILED,
|
|
3119
3478
|
context: {
|
|
@@ -3144,7 +3503,8 @@ var RunHandler = class {
|
|
|
3144
3503
|
/**
|
|
3145
3504
|
* Execute a specific tool
|
|
3146
3505
|
*/
|
|
3147
|
-
async executeSpecificTool(tool, toolCall, message, agent, agentId) {
|
|
3506
|
+
async executeSpecificTool(tool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
|
|
3507
|
+
const threadId = agent.threadId;
|
|
3148
3508
|
if (tool?.agentId && tool.agentId !== agent.agentId) return false;
|
|
3149
3509
|
let handlerResult = {
|
|
3150
3510
|
result: "",
|
|
@@ -3158,11 +3518,13 @@ var RunHandler = class {
|
|
|
3158
3518
|
agentId,
|
|
3159
3519
|
handlerArgs: toolCall.function.arguments,
|
|
3160
3520
|
toolType: "specific",
|
|
3161
|
-
messageId: message.id
|
|
3521
|
+
messageId: message.id,
|
|
3522
|
+
signal,
|
|
3523
|
+
discardOnAbort
|
|
3162
3524
|
});
|
|
3163
3525
|
{
|
|
3164
3526
|
const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
|
|
3165
|
-
if (messageIndex === -1) return false;
|
|
3527
|
+
if (discardAbortedResult(signal, discardOnAbort, handlerResult.error) || agent.threadId !== threadId || messageIndex === -1 || agent.messages.some((m) => m.role === "tool" && m.toolCallId === toolCall.id && !this.isFrontendPlaceholderResult(m))) return false;
|
|
3166
3528
|
let insertAt = messageIndex + 1;
|
|
3167
3529
|
while (insertAt < agent.messages.length && agent.messages[insertAt]?.role === "tool") insertAt++;
|
|
3168
3530
|
const toolMessage = {
|
|
@@ -3182,7 +3544,8 @@ var RunHandler = class {
|
|
|
3182
3544
|
* specific tools, so this method keeps its own arg-wrapping logic rather than
|
|
3183
3545
|
* delegating to `executeToolHandler`.
|
|
3184
3546
|
*/
|
|
3185
|
-
async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId) {
|
|
3547
|
+
async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
|
|
3548
|
+
const threadId = agent.threadId;
|
|
3186
3549
|
if (wildcardTool?.agentId && wildcardTool.agentId !== agent.agentId) return false;
|
|
3187
3550
|
let toolCallResult = "";
|
|
3188
3551
|
let errorMessage;
|
|
@@ -3220,7 +3583,8 @@ var RunHandler = class {
|
|
|
3220
3583
|
if (!errorMessage) try {
|
|
3221
3584
|
const result = await wildcardTool.handler(wildcardArgs, {
|
|
3222
3585
|
toolCall,
|
|
3223
|
-
agent
|
|
3586
|
+
agent,
|
|
3587
|
+
signal
|
|
3224
3588
|
});
|
|
3225
3589
|
if (result === void 0 || result === null) toolCallResult = "";
|
|
3226
3590
|
else if (typeof result === "string") toolCallResult = result;
|
|
@@ -3228,7 +3592,7 @@ var RunHandler = class {
|
|
|
3228
3592
|
} catch (error) {
|
|
3229
3593
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3230
3594
|
errorMessage = handlerError.message;
|
|
3231
|
-
await this._internal.emitError({
|
|
3595
|
+
if (!discardAbortedResult(signal, discardOnAbort, errorMessage)) await this._internal.emitError({
|
|
3232
3596
|
error: handlerError,
|
|
3233
3597
|
code: CopilotKitCoreErrorCode.TOOL_HANDLER_FAILED,
|
|
3234
3598
|
context: {
|
|
@@ -3253,7 +3617,7 @@ var RunHandler = class {
|
|
|
3253
3617
|
}
|
|
3254
3618
|
{
|
|
3255
3619
|
const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
|
|
3256
|
-
if (messageIndex === -1) return false;
|
|
3620
|
+
if (discardAbortedResult(signal, discardOnAbort, errorMessage) || agent.threadId !== threadId || messageIndex === -1 || agent.messages.some((m) => m.role === "tool" && m.toolCallId === toolCall.id && !this.isFrontendPlaceholderResult(m))) return false;
|
|
3257
3621
|
let insertAt = messageIndex + 1;
|
|
3258
3622
|
while (insertAt < agent.messages.length && agent.messages[insertAt]?.role === "tool") insertAt++;
|
|
3259
3623
|
const toolMessage = {
|
|
@@ -5038,6 +5402,7 @@ function normalizeHeaders(headers) {
|
|
|
5038
5402
|
var CopilotKitCore = class {
|
|
5039
5403
|
_headers;
|
|
5040
5404
|
_credentials;
|
|
5405
|
+
_messageFilter;
|
|
5041
5406
|
_properties;
|
|
5042
5407
|
_defaultThrottleMs;
|
|
5043
5408
|
_debug;
|
|
@@ -5062,9 +5427,10 @@ var CopilotKitCore = class {
|
|
|
5062
5427
|
* store that was registered prior to that initial notification.
|
|
5063
5428
|
*/
|
|
5064
5429
|
previousAgentIds = /* @__PURE__ */ new Set();
|
|
5065
|
-
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
|
|
5430
|
+
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
|
|
5066
5431
|
this._headers = normalizeHeaders(headers);
|
|
5067
5432
|
this._credentials = credentials;
|
|
5433
|
+
this._messageFilter = messageFilter;
|
|
5068
5434
|
this._properties = properties;
|
|
5069
5435
|
this._debug = debug;
|
|
5070
5436
|
this.agentRegistry = new AgentRegistry(this);
|
|
@@ -5184,6 +5550,9 @@ var CopilotKitCore = class {
|
|
|
5184
5550
|
get credentials() {
|
|
5185
5551
|
return this._credentials;
|
|
5186
5552
|
}
|
|
5553
|
+
get messageFilter() {
|
|
5554
|
+
return this._messageFilter;
|
|
5555
|
+
}
|
|
5187
5556
|
get properties() {
|
|
5188
5557
|
return this._properties;
|
|
5189
5558
|
}
|
|
@@ -5329,6 +5698,17 @@ var CopilotKitCore = class {
|
|
|
5329
5698
|
this.agentRegistry.applyCredentialsToAgents(this.agentRegistry.agents);
|
|
5330
5699
|
this.agentRegistry.handleCredentialsChanged();
|
|
5331
5700
|
}
|
|
5701
|
+
/**
|
|
5702
|
+
* Replace the message filter applied to every runtime agent.
|
|
5703
|
+
*
|
|
5704
|
+
* Applies to agents already discovered as well as ones discovered later, so
|
|
5705
|
+
* a filter set before `/info` lands is not lost. Pass `undefined` to go back
|
|
5706
|
+
* to sending the full thread.
|
|
5707
|
+
*/
|
|
5708
|
+
setMessageFilter(messageFilter) {
|
|
5709
|
+
this._messageFilter = messageFilter;
|
|
5710
|
+
this.agentRegistry.applyMessageFilterToAgents(this.agentRegistry.agents);
|
|
5711
|
+
}
|
|
5332
5712
|
setProperties(properties) {
|
|
5333
5713
|
this._properties = properties;
|
|
5334
5714
|
this.notifySubscribers((subscriber) => subscriber.onPropertiesChanged?.({
|
|
@@ -5677,7 +6057,7 @@ var CopilotKitCore = class {
|
|
|
5677
6057
|
return this.runHandler.connectAgent(params);
|
|
5678
6058
|
}
|
|
5679
6059
|
stopAgent(params) {
|
|
5680
|
-
this.runHandler.abortCurrentRun();
|
|
6060
|
+
this.runHandler.abortCurrentRun(params.agent);
|
|
5681
6061
|
params.agent.abortRun();
|
|
5682
6062
|
}
|
|
5683
6063
|
async runAgent(params) {
|