@mastra/client-js 1.21.0-alpha.1 → 1.21.0-alpha.10

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
@@ -499,6 +499,24 @@ var BaseResource = class {
499
499
  };
500
500
 
501
501
  // src/resources/agent.ts
502
+ var SIGNAL_RUNTIME_OPTIONS_TTL_MS = 5 * 60 * 1e3;
503
+ var signalRuntimeOptionsByRunId = /* @__PURE__ */ new Map();
504
+ var latestSignalRuntimeOptionsByThread = /* @__PURE__ */ new Map();
505
+ var createSignalRuntimeOptionsEntry = (store, key, streamOptions) => {
506
+ const timeout = setTimeout(() => store.delete(key), SIGNAL_RUNTIME_OPTIONS_TTL_MS);
507
+ timeout.unref?.();
508
+ return { streamOptions, timeout };
509
+ };
510
+ var setSignalRuntimeOptionsEntry = (store, key, streamOptions) => {
511
+ const existing = store.get(key);
512
+ if (existing) clearTimeout(existing.timeout);
513
+ store.set(key, createSignalRuntimeOptionsEntry(store, key, streamOptions));
514
+ };
515
+ var deleteSignalRuntimeOptionsEntry = (store, key) => {
516
+ const existing = store.get(key);
517
+ if (existing) clearTimeout(existing.timeout);
518
+ store.delete(key);
519
+ };
502
520
  var noopClientToolObserve = {
503
521
  async span(_name, fn) {
504
522
  return fn();
@@ -696,6 +714,52 @@ var Agent = class extends BaseResource {
696
714
  const queryString = searchParams.toString();
697
715
  return queryString ? `${delimiter}${queryString}` : "";
698
716
  }
717
+ getSignalRuntimeRunKey(runId) {
718
+ return `${this.options.baseUrl}|${this.apiPrefix}|${this.agentId}|${runId}`;
719
+ }
720
+ getSignalRuntimeThreadKey({
721
+ resourceId,
722
+ threadId
723
+ }) {
724
+ if (!threadId) return void 0;
725
+ return `${this.options.baseUrl}|${this.apiPrefix}|${this.agentId}|${resourceId ?? ""}|${threadId}`;
726
+ }
727
+ setSignalRuntimeOptions({
728
+ runId,
729
+ resourceId,
730
+ threadId,
731
+ streamOptions
732
+ }) {
733
+ const threadKey = this.getSignalRuntimeThreadKey({ resourceId, threadId });
734
+ if (runId) {
735
+ setSignalRuntimeOptionsEntry(signalRuntimeOptionsByRunId, this.getSignalRuntimeRunKey(runId), streamOptions);
736
+ if (threadKey) deleteSignalRuntimeOptionsEntry(latestSignalRuntimeOptionsByThread, threadKey);
737
+ return;
738
+ }
739
+ if (threadKey) {
740
+ setSignalRuntimeOptionsEntry(latestSignalRuntimeOptionsByThread, threadKey, streamOptions);
741
+ }
742
+ }
743
+ getSignalRuntimeOptions({
744
+ runId,
745
+ resourceId,
746
+ threadId
747
+ }) {
748
+ if (runId) {
749
+ const runOptions = signalRuntimeOptionsByRunId.get(this.getSignalRuntimeRunKey(runId));
750
+ if (runOptions) return runOptions.streamOptions;
751
+ }
752
+ const threadKey = this.getSignalRuntimeThreadKey({ resourceId, threadId });
753
+ return threadKey ? latestSignalRuntimeOptionsByThread.get(threadKey)?.streamOptions : void 0;
754
+ }
755
+ deleteSignalRuntimeOptions(runId) {
756
+ if (!runId) return;
757
+ deleteSignalRuntimeOptionsEntry(signalRuntimeOptionsByRunId, this.getSignalRuntimeRunKey(runId));
758
+ }
759
+ deleteLatestSignalRuntimeOptions({ resourceId, threadId }) {
760
+ const threadKey = this.getSignalRuntimeThreadKey({ resourceId, threadId });
761
+ if (threadKey) deleteSignalRuntimeOptionsEntry(latestSignalRuntimeOptionsByThread, threadKey);
762
+ }
699
763
  /**
700
764
  * Retrieves details about the agent
701
765
  * @param requestContext - Optional request context to pass as query parameter
@@ -741,32 +805,227 @@ var Agent = class extends BaseResource {
741
805
  /**
742
806
  * @experimental Agent signals are experimental and may change in a future release.
743
807
  */
744
- sendSignal(params) {
745
- return this.request(`/agents/${this.agentId}/signals`, {
746
- method: "POST",
747
- body: params
748
- });
808
+ async sendSignal(params) {
809
+ const streamOptions = params.ifIdle?.streamOptions;
810
+ if (streamOptions) {
811
+ this.setSignalRuntimeOptions({
812
+ resourceId: params.resourceId,
813
+ threadId: params.threadId,
814
+ streamOptions
815
+ });
816
+ }
817
+ const body = params.ifIdle?.streamOptions ? {
818
+ ...params,
819
+ ifIdle: {
820
+ ...params.ifIdle,
821
+ streamOptions: {
822
+ ...params.ifIdle.streamOptions,
823
+ requestContext: parseClientRequestContext(params.ifIdle.streamOptions.requestContext),
824
+ clientTools: processClientTools(params.ifIdle.streamOptions.clientTools)
825
+ }
826
+ }
827
+ } : params;
828
+ let response;
829
+ try {
830
+ response = await this.request(`/agents/${this.agentId}/signals`, {
831
+ method: "POST",
832
+ body
833
+ });
834
+ } catch (error) {
835
+ if (streamOptions) {
836
+ this.deleteLatestSignalRuntimeOptions({ resourceId: params.resourceId, threadId: params.threadId });
837
+ }
838
+ throw error;
839
+ }
840
+ if (streamOptions) {
841
+ this.setSignalRuntimeOptions({
842
+ runId: response.runId,
843
+ resourceId: params.resourceId,
844
+ threadId: params.threadId,
845
+ streamOptions
846
+ });
847
+ }
848
+ return response;
749
849
  }
750
850
  /**
751
851
  * @experimental Agent signals are experimental and may change in a future release.
752
852
  */
753
853
  async subscribeToThread(params) {
754
- const streamResponse = await this.request(`/agents/${this.agentId}/threads/subscribe`, {
854
+ const { resourceId, threadId } = params;
855
+ const requestSubscription = () => this.request(`/agents/${this.agentId}/threads/subscribe`, {
755
856
  method: "POST",
756
- body: params,
857
+ body: { resourceId, threadId },
757
858
  stream: true
758
859
  });
860
+ const streamResponse = await requestSubscription();
759
861
  if (!streamResponse.body) {
760
862
  throw new Error("No response body");
761
863
  }
762
- streamResponse.processDataStream = async ({
763
- onChunk
764
- }) => {
765
- await processMastraStream({
766
- stream: streamResponse.body,
767
- onChunk,
768
- signal: this.options.abortSignal
769
- });
864
+ const agent = this;
865
+ streamResponse.processDataStream = async ({ onChunk, reconnect }) => {
866
+ const pendingToolCallsByRunId = /* @__PURE__ */ new Map();
867
+ const handleSubscribedChunk = async (chunk) => {
868
+ if (chunk.type === "tool-call") {
869
+ const payload = chunk.payload;
870
+ const toolCallId = payload?.toolCallId;
871
+ const toolName = payload?.toolName;
872
+ const runId2 = chunk.runId;
873
+ if (!toolCallId || !toolName || !runId2) return;
874
+ const pendingToolCalls2 = pendingToolCallsByRunId.get(runId2) ?? [];
875
+ pendingToolCalls2.push({ toolCallId, toolName, args: payload.args, observability: payload.observability });
876
+ pendingToolCallsByRunId.set(runId2, pendingToolCalls2);
877
+ return;
878
+ }
879
+ if (chunk.type !== "finish") return;
880
+ const runId = chunk.runId;
881
+ const finishPayload = chunk;
882
+ if (!runId) return;
883
+ if (finishPayload.payload?.stepResult?.reason !== "tool-calls") {
884
+ agent.deleteSignalRuntimeOptions(runId);
885
+ return;
886
+ }
887
+ const pendingToolCalls = pendingToolCallsByRunId.get(runId);
888
+ pendingToolCallsByRunId.delete(runId);
889
+ if (!pendingToolCalls?.length) {
890
+ agent.deleteSignalRuntimeOptions(runId);
891
+ return;
892
+ }
893
+ const activeRuntimeOptions = agent.getSignalRuntimeOptions({ runId, resourceId, threadId });
894
+ const activeClientTools = activeRuntimeOptions?.clientTools;
895
+ if (!activeClientTools) {
896
+ agent.deleteSignalRuntimeOptions(runId);
897
+ return;
898
+ }
899
+ const activeRequestContext = activeRuntimeOptions.requestContext;
900
+ const processedClientTools = processClientTools(activeClientTools);
901
+ const processedRequestContext = parseClientRequestContext(activeRequestContext);
902
+ const toolResultMessages = [];
903
+ for (const toolCall of pendingToolCalls) {
904
+ const clientTool = activeClientTools[toolCall.toolName];
905
+ if (!clientTool || typeof clientTool.execute !== "function") continue;
906
+ let result;
907
+ let observability;
908
+ try {
909
+ const execution = await executeClientToolWithObservability({
910
+ clientTool,
911
+ args: toolCall.args,
912
+ toolName: toolCall.toolName,
913
+ parentContext: toolCall.observability,
914
+ executeContext: {
915
+ requestContext: activeRequestContext,
916
+ tracingContext: { currentSpan: void 0 },
917
+ agent: {
918
+ agentId: agent.agentId,
919
+ messages: finishPayload.payload?.messages?.nonUser ?? [],
920
+ toolCallId: toolCall.toolCallId,
921
+ suspend: async () => {
922
+ },
923
+ threadId,
924
+ resourceId
925
+ }
926
+ }
927
+ });
928
+ result = execution.result;
929
+ observability = execution.observability;
930
+ } catch (error) {
931
+ result = { error: String(error) };
932
+ }
933
+ const toolResultContent = {
934
+ type: "tool-result",
935
+ toolCallId: toolCall.toolCallId,
936
+ toolName: toolCall.toolName,
937
+ result
938
+ };
939
+ if (observability) {
940
+ toolResultContent.__mastraObservability = observability;
941
+ }
942
+ await onChunk({
943
+ type: "tool-result",
944
+ runId,
945
+ payload: toolResultContent
946
+ });
947
+ toolResultMessages.push({
948
+ role: "tool",
949
+ content: [toolResultContent]
950
+ });
951
+ }
952
+ if (toolResultMessages.length === 0) {
953
+ agent.deleteSignalRuntimeOptions(runId);
954
+ return;
955
+ }
956
+ try {
957
+ const continuation = await agent.streamUntilIdle(
958
+ [...finishPayload.payload?.messages?.nonUser ?? [], ...toolResultMessages],
959
+ {
960
+ ...activeRuntimeOptions,
961
+ runId: uuid.v4(),
962
+ requestContext: processedRequestContext,
963
+ memory: threadId ? { thread: threadId, resource: resourceId } : void 0,
964
+ clientTools: processedClientTools
965
+ }
966
+ );
967
+ try {
968
+ void continuation.body?.cancel?.();
969
+ } catch {
970
+ }
971
+ } catch (error) {
972
+ console.error("Error running client-tool continuation:", error);
973
+ } finally {
974
+ agent.deleteSignalRuntimeOptions(runId);
975
+ }
976
+ };
977
+ const reconnectOptions = reconnect === true ? { maxRetries: Infinity, delayMs: 1e3 } : reconnect ? { maxRetries: reconnect.maxRetries ?? Infinity, delayMs: reconnect.delayMs ?? 1e3 } : null;
978
+ let response = streamResponse;
979
+ let attempts = 0;
980
+ const onChunkErrorSentinel = /* @__PURE__ */ Symbol("onChunkErrorSentinel");
981
+ const guardedOnChunk = async (chunk) => {
982
+ try {
983
+ await onChunk(chunk);
984
+ await handleSubscribedChunk(chunk);
985
+ } catch (cause) {
986
+ throw { [onChunkErrorSentinel]: true, cause };
987
+ }
988
+ };
989
+ while (true) {
990
+ if (!response.body) {
991
+ throw new Error("No response body");
992
+ }
993
+ try {
994
+ await processMastraStream({
995
+ stream: response.body,
996
+ onChunk: guardedOnChunk,
997
+ signal: this.options.abortSignal
998
+ });
999
+ } catch (error) {
1000
+ if (typeof error === "object" && error !== null && error[onChunkErrorSentinel]) {
1001
+ throw error.cause;
1002
+ }
1003
+ if (!reconnectOptions || this.options.abortSignal?.aborted || attempts >= reconnectOptions.maxRetries) {
1004
+ throw error;
1005
+ }
1006
+ }
1007
+ if (!reconnectOptions || this.options.abortSignal?.aborted || attempts >= reconnectOptions.maxRetries) {
1008
+ return;
1009
+ }
1010
+ while (attempts < reconnectOptions.maxRetries) {
1011
+ attempts++;
1012
+ if (this.options.abortSignal?.aborted) {
1013
+ return;
1014
+ }
1015
+ await new Promise((resolve) => setTimeout(resolve, reconnectOptions.delayMs));
1016
+ if (this.options.abortSignal?.aborted) {
1017
+ return;
1018
+ }
1019
+ try {
1020
+ response = await requestSubscription();
1021
+ break;
1022
+ } catch (error) {
1023
+ if (this.options.abortSignal?.aborted || attempts >= reconnectOptions.maxRetries) {
1024
+ throw error;
1025
+ }
1026
+ }
1027
+ }
1028
+ }
770
1029
  };
771
1030
  return streamResponse;
772
1031
  }
@@ -1294,6 +1553,7 @@ var Agent = class extends BaseResource {
1294
1553
  update,
1295
1554
  onToolCall,
1296
1555
  onFinish,
1556
+ onStreamChunk,
1297
1557
  getCurrentDate = () => /* @__PURE__ */ new Date(),
1298
1558
  lastMessage
1299
1559
  }) {
@@ -1361,6 +1621,7 @@ var Agent = class extends BaseResource {
1361
1621
  // TODO: casting as any here because the stream types were all typed as any before in core.
1362
1622
  // but this is completely wrong and this fn is probably broken. Remove ":any" and you'll see a bunch of type errors
1363
1623
  onChunk: async (chunk) => {
1624
+ onStreamChunk?.(chunk);
1364
1625
  switch (chunk.type) {
1365
1626
  case "tripwire": {
1366
1627
  message.parts.push({
@@ -1462,6 +1723,7 @@ var Agent = class extends BaseResource {
1462
1723
  execUpdate();
1463
1724
  }
1464
1725
  }
1726
+ break;
1465
1727
  }
1466
1728
  case "tool-call-input-streaming-start": {
1467
1729
  if (message.toolInvocations == null) {
@@ -1578,6 +1840,7 @@ var Agent = class extends BaseResource {
1578
1840
  try {
1579
1841
  let toolCalls = [];
1580
1842
  let messages = [];
1843
+ let streamRunId = processedParams.runId;
1581
1844
  const [streamForController, streamForProcessing] = response.body.tee();
1582
1845
  const pipePromise = streamForController.pipeTo(
1583
1846
  new WritableStream({
@@ -1631,25 +1894,76 @@ var Agent = class extends BaseResource {
1631
1894
  const clientTool = processedParams.clientTools?.[toolCall2.toolName];
1632
1895
  if (clientTool && clientTool.execute) {
1633
1896
  shouldExecuteClientTool = true;
1634
- const { result, observability } = await executeClientToolWithObservability({
1635
- clientTool,
1636
- args: toolCall2?.args,
1637
- toolName: toolCall2.toolName,
1638
- parentContext: getClientToolObservabilityContext(toolCall2),
1639
- executeContext: {
1640
- requestContext: processedParams.requestContext,
1641
- tracingContext: { currentSpan: void 0 },
1642
- agent: {
1643
- agentId: this.agentId,
1644
- messages: response.messages,
1645
- toolCallId: toolCall2?.toolCallId,
1646
- suspend: async () => {
1647
- },
1648
- threadId,
1649
- resourceId
1897
+ const runId = streamRunId ?? toolCall2.toolCallId;
1898
+ let result;
1899
+ let observability;
1900
+ let synthetic;
1901
+ try {
1902
+ ({ result, observability } = await executeClientToolWithObservability({
1903
+ clientTool,
1904
+ args: toolCall2?.args,
1905
+ toolName: toolCall2.toolName,
1906
+ parentContext: getClientToolObservabilityContext(toolCall2),
1907
+ executeContext: {
1908
+ requestContext: processedParams.requestContext,
1909
+ tracingContext: { currentSpan: void 0 },
1910
+ agent: {
1911
+ agentId: this.agentId,
1912
+ messages: response.messages,
1913
+ toolCallId: toolCall2?.toolCallId,
1914
+ suspend: async () => {
1915
+ },
1916
+ threadId,
1917
+ resourceId
1918
+ }
1650
1919
  }
1651
- }
1652
- });
1920
+ }));
1921
+ synthetic = {
1922
+ type: "tool-result",
1923
+ runId,
1924
+ from: "AGENT",
1925
+ payload: {
1926
+ toolCallId: toolCall2.toolCallId,
1927
+ toolName: toolCall2.toolName,
1928
+ result,
1929
+ isError: false,
1930
+ providerExecuted: false
1931
+ }
1932
+ };
1933
+ } catch (error) {
1934
+ synthetic = {
1935
+ type: "tool-error",
1936
+ runId,
1937
+ from: "AGENT",
1938
+ payload: {
1939
+ toolCallId: toolCall2.toolCallId,
1940
+ toolName: toolCall2.toolName,
1941
+ error,
1942
+ args: toolCall2?.args,
1943
+ providerExecuted: false
1944
+ }
1945
+ };
1946
+ result = { error: error instanceof Error ? error.message : String(error) };
1947
+ }
1948
+ try {
1949
+ await pipePromise;
1950
+ } catch {
1951
+ }
1952
+ try {
1953
+ const errorForSerialization = synthetic.type === "tool-error" ? synthetic.payload.error : void 0;
1954
+ const serializedError = errorForSerialization instanceof Error ? {
1955
+ name: errorForSerialization.name,
1956
+ message: errorForSerialization.message,
1957
+ stack: errorForSerialization.stack
1958
+ } : errorForSerialization;
1959
+ const payloadForWire = synthetic.type === "tool-error" ? { ...synthetic, payload: { ...synthetic.payload, error: serializedError } } : synthetic;
1960
+ const sseLine = `data: ${JSON.stringify(payloadForWire)}
1961
+
1962
+ `;
1963
+ controller.enqueue(new TextEncoder().encode(sseLine));
1964
+ } catch (enqueueErr) {
1965
+ console.error("Failed to enqueue synthetic tool-result chunk:", enqueueErr);
1966
+ }
1653
1967
  const lastMessageRaw = messages[messages.length - 1];
1654
1968
  const lastMessage = lastMessageRaw != null ? JSON.parse(JSON.stringify(lastMessageRaw)) : void 0;
1655
1969
  const toolInvocationPart = lastMessage?.parts?.find(
@@ -1699,6 +2013,11 @@ var Agent = class extends BaseResource {
1699
2013
  controller.close();
1700
2014
  }
1701
2015
  },
2016
+ onStreamChunk: (chunk) => {
2017
+ if (!streamRunId && typeof chunk.runId === "string") {
2018
+ streamRunId = chunk.runId;
2019
+ }
2020
+ },
1702
2021
  lastMessage: void 0
1703
2022
  }).catch(async (error) => {
1704
2023
  console.error("Error processing stream response:", error);