@mastra/client-js 1.56.0 → 1.57.0-alpha.1
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/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/docs/SKILL.md +5 -3
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-connections-a2a.md +1 -1
- package/dist/docs/references/docs-harness-agent-controller.md +7 -7
- package/dist/docs/references/docs-harness-schedules.md +5 -5
- package/dist/docs/references/docs-server-mastra-client.md +1 -1
- package/dist/docs/references/docs-signals-notifications.md +233 -0
- package/dist/docs/references/docs-signals-sending-signals.md +166 -0
- package/dist/docs/references/docs-signals-thread-streams.md +94 -0
- package/dist/docs/references/docs-studio-editor.md +39 -23
- package/dist/docs/references/reference-client-js-agent-controller.md +2 -2
- package/dist/docs/references/reference-client-js-agents.md +18 -2
- package/dist/docs/references/reference-client-js-datasets.md +1 -1
- package/dist/docs/references/reference-client-js-observability.md +26 -1
- package/dist/docs/references/reference-observability-tracing-advanced-queries.md +92 -11
- package/dist/index.cjs +148 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -22
- package/dist/index.js.map +1 -1
- package/dist/resources/agent.d.ts +10 -3
- package/dist/resources/agent.d.ts.map +1 -1
- package/dist/resources/observability-route-types.d.ts +2 -0
- package/dist/resources/observability-route-types.d.ts.map +1 -1
- package/dist/resources/observability.d.ts +7 -1
- package/dist/resources/observability.d.ts.map +1 -1
- package/dist/route-types.generated.d.ts +437 -359
- package/dist/route-types.generated.d.ts.map +1 -1
- package/dist/utils/process-mastra-stream.d.ts.map +1 -1
- package/dist/utils/sse-event-splitter.d.ts +3 -0
- package/dist/utils/sse-event-splitter.d.ts.map +1 -0
- package/package.json +8 -8
- package/dist/docs/references/docs-harness-signals.md +0 -546
|
@@ -10,8 +10,9 @@ Advanced trace queries select completed traces with a structured time range and
|
|
|
10
10
|
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------ |
|
|
11
11
|
| Query traces | List matching traces, paginate through them, and poll for new ones. | `queryTraces()` | `POST /api/observability/traces/query` |
|
|
12
12
|
| Aggregate traces | Count matching traces and compute measures, such as error rate, latency percentiles, tokens, and cost, optionally grouped by dimensions and time buckets. | `aggregateTraces()` | `POST /api/observability/traces/aggregate` |
|
|
13
|
+
| Aggregate spans | Compute the same measures over individual spans, such as every agent run including nested ones, grouped by span dimensions. | `aggregateSpans()` | `POST /api/observability/spans/aggregate` |
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
The trace APIs accept the same [trace selection](#select-traces). The filters, operators, and limits on this page apply to each. Use the aggregate API to find the group that needs attention, such as an agent with a high error rate, then send the same predicate plus the group's dimensions to the query API to list the traces behind it. Each query result represents a trace. Use its `traceId` to [retrieve the full trace](https://mastra.ai/reference/client-js/observability).
|
|
15
16
|
|
|
16
17
|
The endpoints use the same authentication as other observability routes and require the `observability:read` permission. Every request requires a time range.
|
|
17
18
|
|
|
@@ -25,6 +26,7 @@ The configured observability store must support each API. Call `getObservability
|
|
|
25
26
|
| -------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
26
27
|
| `traceQuery` | `trace-query` | `queryTraces()` |
|
|
27
28
|
| `traceAggregate` | `trace-aggregate` | `aggregateTraces()` |
|
|
29
|
+
| `spanAggregate` | `span-aggregate` | `aggregateSpans()` |
|
|
28
30
|
| `traceQueryRootDuration` | `trace-query-root-duration` | Trace-scope `durationMs` predicates |
|
|
29
31
|
| `traceQueryTimeToFirstChunk` | `trace-query-time-to-first-chunk` | `timeToFirstChunkMs` predicates and results |
|
|
30
32
|
| `traceQueryTimeToFirstChunkSort` | `trace-query-time-to-first-chunk-sort` | `orderBy` on `timeToFirstChunkMs` |
|
|
@@ -34,7 +36,7 @@ The configured observability store must support each API. Call `getObservability
|
|
|
34
36
|
| `traceQueryDiscovery` | `trace-query-discovery` | [Field and value discovery](#discover-fields-and-values) |
|
|
35
37
|
| `traceQueryTenantScope` | `trace-query-tenant-scope` | [Trusted tenant scope](#trusted-tenant-scope) |
|
|
36
38
|
|
|
37
|
-
A missing `traceAggregate` value means the server doesn't support aggregation. Servers without the aggregate route return `404`, and stores without the feature return `501 TRACE_AGGREGATE_UNSUPPORTED`. Against a store without a sub-feature, a request that uses a gated field returns `501` before storage runs. Root span `name`, `spanType`, and `entityId` are the exception and return `422` with a `field_not_allowed` issue.
|
|
39
|
+
A missing `traceAggregate` value means the server doesn't support aggregation. Servers without the aggregate route return `404`, and stores without the feature return `501 TRACE_AGGREGATE_UNSUPPORTED`. A missing `spanAggregate` value means the same for span aggregation, and stores without the feature return `501 SPAN_AGGREGATE_UNSUPPORTED`. Against a store without a sub-feature, a request that uses a gated field returns `501` before storage runs. Root span `name`, `spanType`, and `entityId` are the exception and return `422` with a `field_not_allowed` issue.
|
|
38
40
|
|
|
39
41
|
## Select traces
|
|
40
42
|
|
|
@@ -212,7 +214,7 @@ const selectedModel = {
|
|
|
212
214
|
{
|
|
213
215
|
op: 'eq',
|
|
214
216
|
left: { path: 'model' },
|
|
215
|
-
right: { literal: 'claude-sonnet-
|
|
217
|
+
right: { literal: 'claude-sonnet-5-5' },
|
|
216
218
|
},
|
|
217
219
|
{ op: 'eq', left: { path: 'provider' }, right: { literal: 'anthropic' } },
|
|
218
220
|
],
|
|
@@ -700,14 +702,14 @@ Token and cost measures read the model usage metrics recorded for each trace, so
|
|
|
700
702
|
|
|
701
703
|
A trace that recorded at least one usage metric is usage-bearing. `tokens.<kind>.sum` adds the tokens of a group's usage-bearing traces, and `tokens.<kind>.avg` divides that sum by the number of usage-bearing traces, not by `count`. Both are `null` when the group has no usage-bearing traces.
|
|
702
704
|
|
|
703
|
-
Cost comes from estimated cost recorded on total input and total output token metrics. `cost.sum` adds the cost of traces with at least one priced metric, and `cost.avg` divides by the number of those traces. A
|
|
705
|
+
Cost comes from estimated cost recorded on total input and total output token metrics. `cost.sum` adds the cost of traces with at least one priced metric, and `cost.avg` divides by the number of those traces. A partly priced call, where Mastra could price some token types but not others, adds the cost of the priced token types. A metric with any other pricing failure adds no cost.
|
|
704
706
|
|
|
705
707
|
When you request any `cost.*` measure, every row also includes a `cost` object:
|
|
706
708
|
|
|
707
|
-
| Field | Description
|
|
708
|
-
| ---------- |
|
|
709
|
-
| `coverage` | Fraction of usage-bearing traces whose usage was fully priced, from 0 to 1. `null` when the group has no usage-bearing traces. |
|
|
710
|
-
| `unit` | Cost unit of the priced metrics, such as `USD`. `'mixed'` when they use more than one unit, and `null` when none are priced.
|
|
709
|
+
| Field | Description |
|
|
710
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
711
|
+
| `coverage` | Fraction of usage-bearing traces whose usage was fully priced, from 0 to 1. A trace with a partly priced call isn't fully priced, so it lowers coverage even though its known cost is in `cost.sum`. `null` when the group has no usage-bearing traces. |
|
|
712
|
+
| `unit` | Cost unit of the priced metrics, such as `USD`. `'mixed'` when they use more than one unit, and `null` when none are priced. |
|
|
711
713
|
|
|
712
714
|
`cost.sum` and `cost.avg` are `null` when the group has no priced traces or `unit` is `'mixed'`. A coverage below 1 means the cost understates the group's spend. The `cost` object isn't a measure, so `having` and `orderBy` can't reference it.
|
|
713
715
|
|
|
@@ -803,11 +805,90 @@ PostgreSQL and ClickHouse stop aggregations after the same `traceQueryTimeoutMs`
|
|
|
803
805
|
| `501` | The installed Core or configured observability store doesn't support aggregation or a requested field. Returns `TRACE_AGGREGATE_UNSUPPORTED`. |
|
|
804
806
|
| `504` | A PostgreSQL or ClickHouse aggregation exceeded its execution timeout. Returns `TRACE_QUERY_EXECUTION_TIMEOUT` without partial results. |
|
|
805
807
|
|
|
808
|
+
## Aggregate spans
|
|
809
|
+
|
|
810
|
+
Use `aggregateSpans()` or `POST /api/observability/spans/aggregate` to compute measures over individual spans instead of traces. Trace aggregation only sees each trace's root span, so an agent run nested inside a workflow isn't counted. Span aggregation counts every span that matches, at any depth.
|
|
811
|
+
|
|
812
|
+
The request has the same shape as [`aggregateTraces()`](#aggregate-request-fields), with the same measures, `having`, `orderBy`, `interval`, limits, and errors. The differences are in which records are selected and which dimensions are available.
|
|
813
|
+
|
|
814
|
+
### Aggregate spans with the client SDK
|
|
815
|
+
|
|
816
|
+
This request counts agent runs by status per day, including nested runs:
|
|
817
|
+
|
|
818
|
+
```typescript
|
|
819
|
+
const { capabilities } = await mastraClient.getObservabilityCapabilities()
|
|
820
|
+
|
|
821
|
+
if (capabilities.spanAggregate) {
|
|
822
|
+
const { rows } = await mastraClient.aggregateSpans({
|
|
823
|
+
timeRange: {
|
|
824
|
+
from: '2026-08-01T00:00:00.000Z',
|
|
825
|
+
to: '2026-08-08T00:00:00.000Z',
|
|
826
|
+
},
|
|
827
|
+
where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'agent_run' } },
|
|
828
|
+
groupBy: ['status'],
|
|
829
|
+
interval: '1d',
|
|
830
|
+
measures: ['count', 'duration.p95'],
|
|
831
|
+
})
|
|
832
|
+
}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Send the same body to `POST /api/observability/spans/aggregate` to use HTTP directly.
|
|
836
|
+
|
|
837
|
+
### Span selection
|
|
838
|
+
|
|
839
|
+
Aggregation selects the spans that [`querySpans()`](https://mastra.ai/reference/client-js/observability) would return for the same `timeRange` and `where`:
|
|
840
|
+
|
|
841
|
+
- `timeRange` bounds each span's `startedAt`, and can span up to 365 days.
|
|
842
|
+
- `where` accepts the `querySpans()` fields and operators, such as `spanType`, `name`, `status`, `durationMs`, entity and parent/root entity fields, and context identifiers.
|
|
843
|
+
- Only completed spans count. When a span was exported more than once, only its latest copy counts.
|
|
844
|
+
|
|
845
|
+
`count` equals the number of spans `querySpans()` pages through for the same request. Buckets use each span's `startedAt`. `duration.*` measures read the span's own duration, and `errorCount` and `errorRate` read whether the span itself recorded an error.
|
|
846
|
+
|
|
847
|
+
On ClickHouse, a request whose `where` limits `spanType` to agent, workflow, processor, or scorer runs, RAG ingestion, or tool calls reads the smaller branch table instead of every span. That path can differ from `querySpans()`:
|
|
848
|
+
|
|
849
|
+
- Spans written before an upgrade from `@mastra/clickhouse` 1.4, 1.5, or 1.6 aren't in the branch table, so older windows can count fewer spans.
|
|
850
|
+
- After ClickHouse merges the copies of a span exported more than once, the branch table keeps the copy written last, not the one that ended last. Counts don't change, but the `status` and duration of a retried span can.
|
|
851
|
+
|
|
852
|
+
### Span dimensions
|
|
853
|
+
|
|
854
|
+
| Dimension | Notes |
|
|
855
|
+
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
856
|
+
| `name`, `spanType`, `status` | The span's own name, type, and status. `status` is `error` when the span recorded an error and `success` otherwise. |
|
|
857
|
+
| `entityType`, `entityId`, `entityName` | The entity that produced the span. |
|
|
858
|
+
| `parentEntityType`, `parentEntityName`, `rootEntityType`, `rootEntityName` | The calling entity and the trace's root entity, such as the agent that made a model call. |
|
|
859
|
+
| `environment`, `serviceName`, `executionSource` | Deployment attributes recorded on the span. |
|
|
860
|
+
| `threadId`, `resourceId`, `userId`, `sessionId`, `organizationId`, `experimentId` | Context identifiers recorded on the span. |
|
|
861
|
+
|
|
862
|
+
`countDistinct.<field>` accepts these dimensions and `traceId`, so `countDistinct.traceId` counts the traces the selected spans belong to. Span aggregation can't group by `metadata.<key>`, identity fields such as `traceId`, `spanId`, or `runId`, or by model and provider.
|
|
863
|
+
|
|
864
|
+
### Span tokens and cost
|
|
865
|
+
|
|
866
|
+
Token and cost measures use the usage metrics recorded by each span, matched by `traceId` and `spanId`. The [trace token rules](#token-and-cost-measures) apply per span: metrics from `timeRange.from` on count, retried exports count once, and averages divide by usage-bearing spans.
|
|
867
|
+
|
|
868
|
+
Usage isn't added up to parent spans. Model calls record usage on `model_generation` spans, so an `agent_run` span has no tokens of its own unless a model call under it wasn't exported. When a `model_generation` span isn't exported, its usage is recorded on the nearest exported ancestor instead. For token totals per agent, select `model_generation` spans and group by the calling agent:
|
|
869
|
+
|
|
870
|
+
```typescript
|
|
871
|
+
const tokensByAgent = await mastraClient.aggregateSpans({
|
|
872
|
+
timeRange: {
|
|
873
|
+
from: '2026-08-01T00:00:00.000Z',
|
|
874
|
+
to: '2026-08-08T00:00:00.000Z',
|
|
875
|
+
},
|
|
876
|
+
where: { op: 'eq', left: { path: 'spanType' }, right: { literal: 'model_generation' } },
|
|
877
|
+
groupBy: ['parentEntityName'],
|
|
878
|
+
measures: ['tokens.total.sum', 'cost.sum'],
|
|
879
|
+
orderBy: { field: 'cost.sum', direction: 'desc' },
|
|
880
|
+
})
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
### List the spans behind a group
|
|
884
|
+
|
|
885
|
+
Aggregation never returns span records. To inspect a group, send the same `timeRange` and `where` to `querySpans()`, and add the group's dimension values as `eq` conditions. For example, add `{ op: 'eq', left: { path: 'status' }, right: { literal: 'error' } }` to list the failed agent runs from the first example.
|
|
886
|
+
|
|
806
887
|
## Trusted tenant scope
|
|
807
888
|
|
|
808
|
-
Hosts that serve more than one tenant supply a trusted scope outside the query document. The server reads the reserved `organizationId` request-context key, which only server-side authentication can set, and passes `{ organizationId }` to the planner. The scope is carried on the trusted plan and ANDed into every scan: current roots, related spans, the usage metrics read by token and cost measures, and both discovery routes. A related record from another tenant that shares a `traceId` never qualifies a trace.
|
|
889
|
+
Hosts that serve more than one tenant supply a trusted scope outside the query document. The server reads the reserved `organizationId` request-context key, which only server-side authentication can set, and passes `{ organizationId }` to the planner. The scope is carried on the trusted plan and ANDed into every scan: current roots, related spans, the usage metrics read by token and cost measures, span aggregation, and both discovery routes. A related record from another tenant that shares a `traceId` never qualifies a trace.
|
|
809
890
|
|
|
810
|
-
Hosts that call storage directly can pass a fuller scope to `planTraceQuery()`, `planTraceAggregate()`, `planTraceQueryObservedFields()`, and `planTraceQueryValues()`:
|
|
891
|
+
Hosts that call storage directly can pass a fuller scope to `planTraceQuery()`, `planTraceAggregate()`, `planSpanAggregate()`, `planTraceQueryObservedFields()`, and `planTraceQueryValues()`:
|
|
811
892
|
|
|
812
893
|
```typescript
|
|
813
894
|
const plan = planTraceQuery(parseTraceQueryRequest(request), {
|
|
@@ -938,7 +1019,7 @@ Both routes require `observability:read` and use the configured observability st
|
|
|
938
1019
|
|
|
939
1020
|
## Limitations
|
|
940
1021
|
|
|
941
|
-
|
|
1022
|
+
The query and aggregate APIs consider completed traces and spans only, not running ones. Trace queries can't return custom projections, embedded evidence, or summaries, and numbered trace pages include a total count. Trace aggregation can't group by span fields other than the root span's `name`, `spanType`, and `entityId`, or by `traceId` or `attributes.*`. Aggregation can't compute numeric measures over metadata, paginate groups, or zero-fill empty buckets. Span aggregation can't group by `model` or `provider`, and it attributes tokens only to the span that recorded them. The CLI's `mastra api trace aggregate` covers trace aggregation, and `mastra api span query` and `mastra api span aggregate` cover span queries and span aggregation.
|
|
942
1023
|
|
|
943
1024
|
## Related
|
|
944
1025
|
|
package/dist/index.cjs
CHANGED
|
@@ -1080,11 +1080,51 @@ function processClientTools(clientTools) {
|
|
|
1080
1080
|
}));
|
|
1081
1081
|
}
|
|
1082
1082
|
//#endregion
|
|
1083
|
+
//#region src/utils/sse-event-splitter.ts
|
|
1084
|
+
/** Split SSE events without rescanning or copying an unfinished event on each read. */
|
|
1085
|
+
function createSseEventSplitter() {
|
|
1086
|
+
let parts = [];
|
|
1087
|
+
let pendingNewline = false;
|
|
1088
|
+
return (text, isFinal = false) => {
|
|
1089
|
+
const events = [];
|
|
1090
|
+
let start = 0;
|
|
1091
|
+
if (text) {
|
|
1092
|
+
if (pendingNewline) {
|
|
1093
|
+
if (text.startsWith("\n")) {
|
|
1094
|
+
events.push(parts.join(""));
|
|
1095
|
+
parts = [];
|
|
1096
|
+
start = 1;
|
|
1097
|
+
} else parts.push("\n");
|
|
1098
|
+
pendingNewline = false;
|
|
1099
|
+
}
|
|
1100
|
+
let separator;
|
|
1101
|
+
while ((separator = text.indexOf("\n\n", start)) !== -1) {
|
|
1102
|
+
parts.push(text.slice(start, separator));
|
|
1103
|
+
events.push(parts.join(""));
|
|
1104
|
+
parts = [];
|
|
1105
|
+
start = separator + 2;
|
|
1106
|
+
}
|
|
1107
|
+
if (start < text.length) {
|
|
1108
|
+
pendingNewline = text.endsWith("\n");
|
|
1109
|
+
const end = pendingNewline ? text.length - 1 : text.length;
|
|
1110
|
+
if (start < end) parts.push(text.slice(start, end));
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (isFinal) {
|
|
1114
|
+
if (pendingNewline) parts.push("\n");
|
|
1115
|
+
events.push(parts.join(""));
|
|
1116
|
+
parts = [];
|
|
1117
|
+
pendingNewline = false;
|
|
1118
|
+
}
|
|
1119
|
+
return events;
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
//#endregion
|
|
1083
1123
|
//#region src/utils/process-mastra-stream.ts
|
|
1084
1124
|
async function sharedProcessMastraStream({ stream, onChunk, signal }) {
|
|
1085
1125
|
const reader = stream.getReader();
|
|
1086
1126
|
const decoder = new TextDecoder();
|
|
1087
|
-
|
|
1127
|
+
const splitEvents = createSseEventSplitter();
|
|
1088
1128
|
const abort = () => void reader.cancel();
|
|
1089
1129
|
if (signal?.aborted) abort();
|
|
1090
1130
|
else signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -1092,9 +1132,7 @@ async function sharedProcessMastraStream({ stream, onChunk, signal }) {
|
|
|
1092
1132
|
while (true) {
|
|
1093
1133
|
const { done, value } = await reader.read();
|
|
1094
1134
|
if (done) break;
|
|
1095
|
-
|
|
1096
|
-
const lines = buffer.split("\n\n");
|
|
1097
|
-
buffer = lines.pop() || "";
|
|
1135
|
+
const lines = splitEvents(decoder.decode(value, { stream: true }));
|
|
1098
1136
|
for (const line of lines) if (line.startsWith("data: ")) {
|
|
1099
1137
|
const data = line.slice(6);
|
|
1100
1138
|
if (data === "[DONE]") return;
|
|
@@ -1894,10 +1932,18 @@ var Agent = class extends BaseResource {
|
|
|
1894
1932
|
};
|
|
1895
1933
|
return streamResponse;
|
|
1896
1934
|
}
|
|
1897
|
-
|
|
1935
|
+
/** Stops execution of a run, including runs without a memory thread. */
|
|
1936
|
+
async abortRun(runId, options) {
|
|
1937
|
+
return this.request(`/agents/${this.agentId}/runs/${encodeURIComponent(runId)}/abort`, {
|
|
1938
|
+
method: "POST",
|
|
1939
|
+
signal: options?.signal
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
async abortThread(params, options) {
|
|
1898
1943
|
const { resourceId, threadId, clearPendingSignals, expectedRunId } = params;
|
|
1899
1944
|
return this.request(`/agents/${this.agentId}/threads/abort`, {
|
|
1900
1945
|
method: "POST",
|
|
1946
|
+
signal: options?.signal,
|
|
1901
1947
|
body: {
|
|
1902
1948
|
resourceId,
|
|
1903
1949
|
threadId,
|
|
@@ -2631,10 +2677,11 @@ var Agent = class extends BaseResource {
|
|
|
2631
2677
|
}
|
|
2632
2678
|
/**
|
|
2633
2679
|
* Creates the consumer-facing stream for the streaming methods. Cancelling the
|
|
2634
|
-
* returned stream
|
|
2635
|
-
*
|
|
2680
|
+
* returned stream or the client-wide signal detaches the HTTP observer and
|
|
2681
|
+
* stops any client-tool continuations. Per-call execution cancellation is
|
|
2682
|
+
* handled separately by processStreamResponse.
|
|
2636
2683
|
*/
|
|
2637
|
-
createCancellableStream(
|
|
2684
|
+
createCancellableStream() {
|
|
2638
2685
|
const abortController = new AbortController();
|
|
2639
2686
|
let readableController;
|
|
2640
2687
|
return {
|
|
@@ -2647,10 +2694,63 @@ var Agent = class extends BaseResource {
|
|
|
2647
2694
|
}
|
|
2648
2695
|
}),
|
|
2649
2696
|
controller: readableController,
|
|
2650
|
-
signal: mergeAbortSignals(abortController.signal,
|
|
2697
|
+
signal: mergeAbortSignals(abortController.signal, this.options.abortSignal)
|
|
2651
2698
|
};
|
|
2652
2699
|
}
|
|
2653
2700
|
async processStreamResponse(processedParams, controller, route = "stream", signal) {
|
|
2701
|
+
const suppliedRunId = processedParams.runId;
|
|
2702
|
+
processedParams = {
|
|
2703
|
+
...processedParams,
|
|
2704
|
+
runId: processedParams.runId ?? (0, _lukeed_uuid.v4)()
|
|
2705
|
+
};
|
|
2706
|
+
const callerSignal = processedParams.abortSignal;
|
|
2707
|
+
callerSignal?.throwIfAborted();
|
|
2708
|
+
const transportAbort = new AbortController();
|
|
2709
|
+
const cancellationAbort = new AbortController();
|
|
2710
|
+
const detachSignal = signal;
|
|
2711
|
+
signal = mergeAbortSignals(detachSignal, transportAbort.signal);
|
|
2712
|
+
let cancellationTimer;
|
|
2713
|
+
const stopCancellation = () => cancellationAbort.abort();
|
|
2714
|
+
const cancelExecution = () => {
|
|
2715
|
+
cancellationTimer = setTimeout(() => cancellationAbort.abort(/* @__PURE__ */ new Error("Agent run cancellation was not acknowledged")), 1e4);
|
|
2716
|
+
(async () => {
|
|
2717
|
+
try {
|
|
2718
|
+
while (true) {
|
|
2719
|
+
cancellationAbort.signal.throwIfAborted();
|
|
2720
|
+
if ((await this.abortRun(processedParams.runId, { signal: cancellationAbort.signal })).aborted) return;
|
|
2721
|
+
await new Promise((resolve, reject) => {
|
|
2722
|
+
const onAbort = () => {
|
|
2723
|
+
clearTimeout(timer);
|
|
2724
|
+
reject(cancellationAbort.signal.reason);
|
|
2725
|
+
};
|
|
2726
|
+
const timer = setTimeout(() => {
|
|
2727
|
+
cancellationAbort.signal.removeEventListener("abort", onAbort);
|
|
2728
|
+
resolve();
|
|
2729
|
+
}, 100);
|
|
2730
|
+
cancellationAbort.signal.addEventListener("abort", onAbort, { once: true });
|
|
2731
|
+
if (cancellationAbort.signal.aborted) onAbort();
|
|
2732
|
+
});
|
|
2733
|
+
}
|
|
2734
|
+
} catch (error) {
|
|
2735
|
+
if (!cancellationAbort.signal.aborted && !(error instanceof Error && "status" in error && (error.status === 404 || error.status === 501))) try {
|
|
2736
|
+
controller.error(error);
|
|
2737
|
+
} catch {}
|
|
2738
|
+
} finally {
|
|
2739
|
+
clearTimeout(cancellationTimer);
|
|
2740
|
+
transportAbort.abort(callerSignal?.reason);
|
|
2741
|
+
}
|
|
2742
|
+
})();
|
|
2743
|
+
};
|
|
2744
|
+
const cleanupCancellation = () => {
|
|
2745
|
+
callerSignal?.removeEventListener("abort", cancelExecution);
|
|
2746
|
+
detachSignal?.removeEventListener("abort", stopCancellation);
|
|
2747
|
+
clearTimeout(cancellationTimer);
|
|
2748
|
+
stopCancellation();
|
|
2749
|
+
};
|
|
2750
|
+
detachSignal?.addEventListener("abort", stopCancellation, { once: true });
|
|
2751
|
+
if (detachSignal?.aborted) stopCancellation();
|
|
2752
|
+
callerSignal?.addEventListener("abort", cancelExecution, { once: true });
|
|
2753
|
+
if (callerSignal?.aborted) cancelExecution();
|
|
2654
2754
|
const { memory } = processedParams ?? {};
|
|
2655
2755
|
const { resource, thread } = memory ?? {};
|
|
2656
2756
|
const threadId = processedParams.threadId ?? (typeof thread === "string" ? thread : thread?.id);
|
|
@@ -2667,9 +2767,15 @@ var Agent = class extends BaseResource {
|
|
|
2667
2767
|
body: requestBody,
|
|
2668
2768
|
stream: true,
|
|
2669
2769
|
signal
|
|
2770
|
+
}).catch((error) => {
|
|
2771
|
+
cleanupCancellation();
|
|
2772
|
+
throw error;
|
|
2670
2773
|
});
|
|
2671
|
-
if (!response.body)
|
|
2672
|
-
|
|
2774
|
+
if (!response.body) {
|
|
2775
|
+
cleanupCancellation();
|
|
2776
|
+
throw new Error("No response body");
|
|
2777
|
+
}
|
|
2778
|
+
const isAborted = () => Boolean(signal?.aborted || callerSignal?.aborted);
|
|
2673
2779
|
const isAbortError = (error) => isAborted() || error?.name === "AbortError";
|
|
2674
2780
|
const safeClose = () => {
|
|
2675
2781
|
try {
|
|
@@ -2682,18 +2788,16 @@ var Agent = class extends BaseResource {
|
|
|
2682
2788
|
};
|
|
2683
2789
|
try {
|
|
2684
2790
|
let messages = [];
|
|
2685
|
-
let streamRunId =
|
|
2791
|
+
let streamRunId = suppliedRunId;
|
|
2686
2792
|
let finishedHistory;
|
|
2687
2793
|
let suspended = false;
|
|
2688
2794
|
const resumedToolCallIds = /* @__PURE__ */ new Set();
|
|
2689
2795
|
const releaseOpenStream = streamRunId ? this.trackOpenStream(streamRunId) : () => {};
|
|
2690
2796
|
const [streamForController, streamForProcessing] = response.body.tee();
|
|
2691
2797
|
const decoder = new TextDecoder();
|
|
2692
|
-
|
|
2798
|
+
const splitEvents = createSseEventSplitter();
|
|
2693
2799
|
const enqueueReadableText = (text, isFinal = false) => {
|
|
2694
|
-
|
|
2695
|
-
const lines = pendingText.split("\n\n");
|
|
2696
|
-
pendingText = isFinal ? "" : lines.pop() ?? "";
|
|
2800
|
+
const lines = splitEvents(text, isFinal);
|
|
2697
2801
|
for (const line of lines) {
|
|
2698
2802
|
if (!line.startsWith("data: ") || !line.includes("\"type\":\"finish\"")) continue;
|
|
2699
2803
|
try {
|
|
@@ -2799,6 +2903,7 @@ var Agent = class extends BaseResource {
|
|
|
2799
2903
|
payload: {
|
|
2800
2904
|
toolCallId: toolCall.toolCallId,
|
|
2801
2905
|
toolName: toolCall.toolName,
|
|
2906
|
+
args: toolCall.args,
|
|
2802
2907
|
result,
|
|
2803
2908
|
isError: false,
|
|
2804
2909
|
providerExecuted: false
|
|
@@ -2899,10 +3004,12 @@ var Agent = class extends BaseResource {
|
|
|
2899
3004
|
} catch {}
|
|
2900
3005
|
safeClose();
|
|
2901
3006
|
}).finally(() => {
|
|
3007
|
+
cleanupCancellation();
|
|
2902
3008
|
signal?.removeEventListener("abort", onAbort);
|
|
2903
3009
|
releaseOpenStream();
|
|
2904
3010
|
});
|
|
2905
3011
|
} catch (error) {
|
|
3012
|
+
cleanupCancellation();
|
|
2906
3013
|
if (!isAbortError(error)) console.error("Error processing stream response:", error);
|
|
2907
3014
|
}
|
|
2908
3015
|
return response;
|
|
@@ -3000,7 +3107,7 @@ var Agent = class extends BaseResource {
|
|
|
3000
3107
|
clientTools: processClientTools(params.clientToolsResolver?.() ?? params.clientTools),
|
|
3001
3108
|
structuredOutput
|
|
3002
3109
|
};
|
|
3003
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3110
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3004
3111
|
const response = await this.processStreamResponse(processedParams, readableController, "stream", signal);
|
|
3005
3112
|
const streamResponse = new Response(readable, {
|
|
3006
3113
|
status: response.status,
|
|
@@ -3031,7 +3138,7 @@ var Agent = class extends BaseResource {
|
|
|
3031
3138
|
clientTools: processClientTools(params.clientToolsResolver?.() ?? params.clientTools),
|
|
3032
3139
|
structuredOutput
|
|
3033
3140
|
};
|
|
3034
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3141
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3035
3142
|
const response = await this.processStreamResponse(processedParams, readableController, "stream-until-idle", signal);
|
|
3036
3143
|
const streamResponse = new Response(readable, {
|
|
3037
3144
|
status: response.status,
|
|
@@ -3075,7 +3182,7 @@ var Agent = class extends BaseResource {
|
|
|
3075
3182
|
requestContext: parseClientRequestContext(requestContext),
|
|
3076
3183
|
clientTools: processClientTools(executableClientTools)
|
|
3077
3184
|
};
|
|
3078
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3185
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3079
3186
|
const response = await this.processStreamResponse(processedParams, readableController, "approve-tool-call", signal).catch((error) => {
|
|
3080
3187
|
releaseHold({ force: true });
|
|
3081
3188
|
throw error;
|
|
@@ -3112,7 +3219,7 @@ var Agent = class extends BaseResource {
|
|
|
3112
3219
|
requestContext: parseClientRequestContext(requestContext),
|
|
3113
3220
|
clientTools: processClientTools(executableClientTools)
|
|
3114
3221
|
};
|
|
3115
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3222
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3116
3223
|
const response = await this.processStreamResponse(processedParams, readableController, "decline-tool-call", signal).catch((error) => {
|
|
3117
3224
|
releaseHold({ force: true });
|
|
3118
3225
|
throw error;
|
|
@@ -3188,7 +3295,7 @@ var Agent = class extends BaseResource {
|
|
|
3188
3295
|
schema: (0, _mastra_schema_compat_schema.standardSchemaToJSONSchema)((0, _mastra_schema_compat_schema.toStandardSchema)(options.structuredOutput.schema))
|
|
3189
3296
|
} : void 0
|
|
3190
3297
|
};
|
|
3191
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3298
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3192
3299
|
const response = await this.processStreamResponse(processedParams, readableController, "resume-stream", signal).catch((error) => {
|
|
3193
3300
|
releaseHold({ force: true });
|
|
3194
3301
|
throw error;
|
|
@@ -3257,7 +3364,7 @@ var Agent = class extends BaseResource {
|
|
|
3257
3364
|
schema: (0, _mastra_schema_compat_schema.standardSchemaToJSONSchema)((0, _mastra_schema_compat_schema.toStandardSchema)(options.structuredOutput.schema))
|
|
3258
3365
|
} : void 0
|
|
3259
3366
|
};
|
|
3260
|
-
const { readable, controller: readableController, signal } = this.createCancellableStream(
|
|
3367
|
+
const { readable, controller: readableController, signal } = this.createCancellableStream();
|
|
3261
3368
|
const response = await this.processStreamResponse(processedParams, readableController, "resume-stream-until-idle", signal).catch((error) => {
|
|
3262
3369
|
releaseHold({ force: true });
|
|
3263
3370
|
throw error;
|
|
@@ -5290,6 +5397,17 @@ var Observability = class extends BaseResource {
|
|
|
5290
5397
|
body: params
|
|
5291
5398
|
});
|
|
5292
5399
|
}
|
|
5400
|
+
/**
|
|
5401
|
+
* Groups and measures individual completed spans selected by a time range and optional span-query predicate.
|
|
5402
|
+
* Token and cost measures count usage recorded on each span itself. Check `capabilities.spanAggregate` from
|
|
5403
|
+
* `getObservabilityCapabilities()` first; servers without it return 404 or 501.
|
|
5404
|
+
*/
|
|
5405
|
+
aggregateSpans(params) {
|
|
5406
|
+
return this.request("/observability/spans/aggregate", {
|
|
5407
|
+
method: "POST",
|
|
5408
|
+
body: params
|
|
5409
|
+
});
|
|
5410
|
+
}
|
|
5293
5411
|
/** Returns canonical and observed fields available to the advanced trace-query grammar. */
|
|
5294
5412
|
getTraceQueryFields(params, options) {
|
|
5295
5413
|
return this.request("/observability/traces/query/fields", {
|
|
@@ -8154,6 +8272,14 @@ var MastraClient = class extends BaseResource {
|
|
|
8154
8272
|
aggregateTraces(params) {
|
|
8155
8273
|
return this.observability.aggregateTraces(params);
|
|
8156
8274
|
}
|
|
8275
|
+
/**
|
|
8276
|
+
* Groups and measures individual completed spans selected by a time range and optional span-query predicate.
|
|
8277
|
+
* Token and cost measures count usage recorded on each span itself. Check `capabilities.spanAggregate` from
|
|
8278
|
+
* `getObservabilityCapabilities()` first; servers without it return 404 or 501.
|
|
8279
|
+
*/
|
|
8280
|
+
aggregateSpans(params) {
|
|
8281
|
+
return this.observability.aggregateSpans(params);
|
|
8282
|
+
}
|
|
8157
8283
|
/** Returns canonical and observed fields available to the advanced trace-query grammar. */
|
|
8158
8284
|
getTraceQueryFields(params, options) {
|
|
8159
8285
|
return this.observability.getTraceQueryFields(params, options);
|