@trigger.dev/sdk 4.8.0-webhooks.20261015065339 → 4.8.0-webhooks.20261020092920
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/commonjs/v3/ai.d.ts +67 -1
- package/dist/commonjs/v3/ai.js +102 -29
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/query.d.ts +434 -1
- package/dist/commonjs/v3/query.js +115 -0
- package/dist/commonjs/v3/query.js.map +1 -1
- package/dist/commonjs/v3/webhooks.d.ts +8 -2
- package/dist/commonjs/v3/webhooks.js +2 -1
- package/dist/commonjs/v3/webhooks.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/ai.d.ts +67 -1
- package/dist/esm/v3/ai.js +101 -28
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/query.d.ts +434 -1
- package/dist/esm/v3/query.js +115 -0
- package/dist/esm/v3/query.js.map +1 -1
- package/dist/esm/v3/webhooks.d.ts +8 -2
- package/dist/esm/v3/webhooks.js +2 -1
- package/dist/esm/v3/webhooks.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/backend.mdx +6 -0
- package/docs/ai-chat/patterns/redacting-telemetry.mdx +117 -0
- package/docs/ai-chat/pending-messages.mdx +1 -1
- package/docs/ai-chat/reference.mdx +7 -4
- package/docs/ai-chat/transcript-storage.mdx +1 -1
- package/docs/apikeys.mdx +6 -4
- package/docs/cli-runs-commands.mdx +2 -2
- package/docs/cli-tasks-commands.mdx +95 -0
- package/docs/config/config-file.mdx +58 -0
- package/docs/config/extensions/prismaExtension.mdx +4 -4
- package/docs/deploy-environment-variables.mdx +4 -0
- package/docs/deployment/atomic-deployment.mdx +3 -3
- package/docs/deployment/overview.mdx +1 -1
- package/docs/deployment/preview-branches.mdx +1 -1
- package/docs/github-actions.mdx +3 -3
- package/docs/limits.mdx +6 -0
- package/docs/manual-setup.mdx +1 -1
- package/docs/mcp-tools.mdx +23 -3
- package/docs/observability/dashboards.mdx +62 -0
- package/docs/runs/max-duration.mdx +4 -0
- package/docs/self-hosting/env/supervisor.mdx +1 -0
- package/docs/webhooks/channels.mdx +6 -2
- package/docs/webhooks/connect.mdx +4 -0
- package/docs/webhooks/deliveries.mdx +4 -0
- package/docs/webhooks/filters.mdx +35 -2
- package/docs/webhooks/human-in-the-loop.mdx +6 -0
- package/docs/webhooks/linear.mdx +7 -3
- package/docs/webhooks/overview.mdx +4 -0
- package/docs/webhooks/session-routing.mdx +7 -1
- package/docs/webhooks/slack.mdx +12 -4
- package/docs/webhooks/sources.mdx +4 -0
- package/docs/webhooks/waiters.mdx +26 -2
- package/package.json +3 -2
package/dist/esm/v3/ai.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ type ChatTurnContext<TClientData = unknown> = {
|
|
|
34
34
|
turn: number;
|
|
35
35
|
continuation: boolean;
|
|
36
36
|
clientData?: TClientData;
|
|
37
|
+
recordUserMessage?: boolean;
|
|
37
38
|
};
|
|
38
39
|
export { __readChatSnapshotProductionPathForTests, __setReadChatSnapshotImplForTests, __setWriteChatSnapshotImplForTests, __writeChatSnapshotProductionPathForTests, } from "./chatSnapshotIo.js";
|
|
39
40
|
export { defaultStorage, memoryTranscriptStorage, reduceTranscriptChanges, snapshotTranscriptStorage, type LoadContextEvent, type MemoryTranscriptStorage, type TranscriptChange, type TranscriptChangeReason, type TranscriptChangeset, type TranscriptCursors, type TranscriptLoadOptions, type TranscriptLoadResult, type TranscriptScope, type TranscriptState, type TranscriptStorage, type TranscriptStorageContext, } from "./transcriptStorage.js";
|
|
@@ -1862,21 +1863,25 @@ export type ChannelControl = {
|
|
|
1862
1863
|
/**
|
|
1863
1864
|
* What a connector's `progress()` hook observes while a turn streams: each tool call as its input is
|
|
1864
1865
|
* complete, and each result or error as it lands. Text deltas are not reported (use `delivery: "stream"`).
|
|
1866
|
+
* `title` is the tool's display title (`tool({ title })`), when it declares one.
|
|
1865
1867
|
*/
|
|
1866
1868
|
export type ChannelProgressEvent = {
|
|
1867
1869
|
type: "tool-call";
|
|
1868
1870
|
toolCallId: string;
|
|
1869
1871
|
toolName: string;
|
|
1872
|
+
title?: string;
|
|
1870
1873
|
input: unknown;
|
|
1871
1874
|
} | {
|
|
1872
1875
|
type: "tool-result";
|
|
1873
1876
|
toolCallId: string;
|
|
1874
1877
|
toolName: string;
|
|
1878
|
+
title?: string;
|
|
1875
1879
|
output: unknown;
|
|
1876
1880
|
} | {
|
|
1877
1881
|
type: "tool-error";
|
|
1878
1882
|
toolCallId: string;
|
|
1879
1883
|
toolName: string;
|
|
1884
|
+
title?: string;
|
|
1880
1885
|
errorText: string;
|
|
1881
1886
|
};
|
|
1882
1887
|
/**
|
|
@@ -1900,7 +1905,7 @@ export type ChannelReplyStreamEnd = {
|
|
|
1900
1905
|
stopped: boolean;
|
|
1901
1906
|
/** The turn paused on a human decision; the controls follow as their own message. */
|
|
1902
1907
|
pending: boolean;
|
|
1903
|
-
/** The
|
|
1908
|
+
/** The connector's error line (`errorMessage`) when the turn ended on a model or stream error. */
|
|
1904
1909
|
errorText?: string;
|
|
1905
1910
|
};
|
|
1906
1911
|
/**
|
|
@@ -2026,6 +2031,12 @@ export interface ChannelConnector<TEvent = unknown, THandle = unknown> {
|
|
|
2026
2031
|
cancelInteraction?: (cancelled: ChannelCancelledToolCall[], ctx: ChannelTurnCtx<TEvent, THandle>) => Promise<void> | void;
|
|
2027
2032
|
react?: (reaction: ChannelReaction, ctx: ChannelReactCtx<TEvent>) => Promise<void>;
|
|
2028
2033
|
reactions?: ChannelReactions<TEvent>;
|
|
2034
|
+
/**
|
|
2035
|
+
* What the channel shows when a turn fails, in place of the error text: a fixed line, or a
|
|
2036
|
+
* function of the failure that returns one. Defaults to {@link CHANNEL_TURN_ERROR_MESSAGE}. The
|
|
2037
|
+
* error itself is logged on the run, and `outbound()` still receives it as `reply.error`.
|
|
2038
|
+
*/
|
|
2039
|
+
errorMessage?: ChannelErrorMessage<TEvent>;
|
|
2029
2040
|
/**
|
|
2030
2041
|
* Observe tool calls and results as the turn streams, to post progress into the surface (a Linear
|
|
2031
2042
|
* `action` activity, a Slack status). Called in order, awaited one at a time, independent of
|
|
@@ -2045,6 +2056,34 @@ export interface ChannelConnector<TEvent = unknown, THandle = unknown> {
|
|
|
2045
2056
|
readonly [channelEventPhantom]?: TEvent;
|
|
2046
2057
|
}
|
|
2047
2058
|
export type AnyChannelConnector = ChannelConnector<any, any>;
|
|
2059
|
+
/** The line a channel shows when a turn fails, unless the connector sets its own `errorMessage`. */
|
|
2060
|
+
export declare const CHANNEL_TURN_ERROR_MESSAGE = "Something went wrong answering this. Try again.";
|
|
2061
|
+
/** What an `errorMessage` function receives when a channel turn fails. */
|
|
2062
|
+
export type ChannelErrorContext<TEvent = unknown> = {
|
|
2063
|
+
/** The failure: the model or stream error, or what the turn threw. */
|
|
2064
|
+
error: Error;
|
|
2065
|
+
/** The text the turn streamed before it failed; empty when it failed before answering. */
|
|
2066
|
+
partialText: string;
|
|
2067
|
+
/** The event that started the turn; undefined on a turn the channel did not start (an action turn, a browser message). */
|
|
2068
|
+
event: TEvent | undefined;
|
|
2069
|
+
/** The run the turn failed in, for a support reference. */
|
|
2070
|
+
runId: string | undefined;
|
|
2071
|
+
/** The session's chat id. */
|
|
2072
|
+
chatId: string;
|
|
2073
|
+
/** {@link CHANNEL_TURN_ERROR_MESSAGE}, to extend rather than replace. */
|
|
2074
|
+
defaultMessage: string;
|
|
2075
|
+
};
|
|
2076
|
+
/**
|
|
2077
|
+
* A channel's error line: a fixed string, or a function of the failure. A function that returns
|
|
2078
|
+
* nothing, or throws, falls back to {@link CHANNEL_TURN_ERROR_MESSAGE}.
|
|
2079
|
+
*
|
|
2080
|
+
* @example
|
|
2081
|
+
* ```ts
|
|
2082
|
+
* errorMessage: ({ error, runId }) =>
|
|
2083
|
+
* error.name === "RateLimitError" ? "I'm a bit busy, try again in a minute." : `That failed (ref ${runId}).`,
|
|
2084
|
+
* ```
|
|
2085
|
+
*/
|
|
2086
|
+
export type ChannelErrorMessage<TEvent = unknown> = string | ((ctx: ChannelErrorContext<TEvent>) => string | null | undefined | Promise<string | null | undefined>);
|
|
2048
2087
|
/**
|
|
2049
2088
|
* A generic chat-frontend channel over any verified source. Unlike `slack()`, you supply the egress
|
|
2050
2089
|
* `send` yourself (post/edit the reply back to your surface), so the whole round-trip is under your
|
|
@@ -2088,6 +2127,8 @@ export declare function chatChannelCustom<TEndpoint extends AnyWebhookEndpoint,
|
|
|
2088
2127
|
filter?: ValidateWebhookFilter<InferWebhookEndpointEvent<TEndpoint>, TFilter>;
|
|
2089
2128
|
startOn?: ValidateWebhookFilter<InferWebhookEndpointEvent<TEndpoint>, TStartOn>;
|
|
2090
2129
|
delivery?: "final" | "stream";
|
|
2130
|
+
/** What the channel shows when a turn fails: a line, or a function of the failure. Defaults to {@link CHANNEL_TURN_ERROR_MESSAGE}. */
|
|
2131
|
+
errorMessage?: ChannelErrorMessage<NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>>;
|
|
2091
2132
|
}): ChannelConnector<NarrowWebhookEvent<InferWebhookEndpointEvent<TEndpoint>, TFilter>, THandle>;
|
|
2092
2133
|
export declare function resolveReactionChoice(choice: ChannelReactionChoice | undefined, event: unknown): Promise<string | undefined>;
|
|
2093
2134
|
/**
|
|
@@ -2184,6 +2225,31 @@ export type ChatAgentOptions<TIdentifier extends string, TClientDataSchema exten
|
|
|
2184
2225
|
* Ignored for sessions with no pin, and for sessions using `lockToVersion`.
|
|
2185
2226
|
*/
|
|
2186
2227
|
versionSkew?: ChatVersionSkewPolicy;
|
|
2228
|
+
/**
|
|
2229
|
+
* Controls which chat content the chat runtime records on its spans in the run trace.
|
|
2230
|
+
*
|
|
2231
|
+
* - `recordUserMessage` (default `true`) records the last user message as `chat.user_message`
|
|
2232
|
+
* and as the turn span's preview text, and messages sent mid-turn as `pending.messages`.
|
|
2233
|
+
* - `recordClientData` (default `true`) records the raw `clientData` sent by the frontend as
|
|
2234
|
+
* `chat.client_data`.
|
|
2235
|
+
*
|
|
2236
|
+
* Set either to `false` to keep that content out of telemetry. Content recorded by the AI SDK's
|
|
2237
|
+
* own spans is controlled separately, through `experimental_telemetry` on the model call.
|
|
2238
|
+
*
|
|
2239
|
+
* @example
|
|
2240
|
+
* ```ts
|
|
2241
|
+
* chat.agent({
|
|
2242
|
+
* id: "my-chat",
|
|
2243
|
+
* telemetry: { recordUserMessage: false, recordClientData: false },
|
|
2244
|
+
* run: async ({ messages, signal, streamText }) =>
|
|
2245
|
+
* streamText({ model, messages, abortSignal: signal }),
|
|
2246
|
+
* });
|
|
2247
|
+
* ```
|
|
2248
|
+
*/
|
|
2249
|
+
telemetry?: {
|
|
2250
|
+
recordUserMessage?: boolean;
|
|
2251
|
+
recordClientData?: boolean;
|
|
2252
|
+
};
|
|
2187
2253
|
/**
|
|
2188
2254
|
* Schema for validating `clientData` from the frontend.
|
|
2189
2255
|
* Accepts Zod, ArkType, Valibot, or any supported schema library.
|
package/dist/esm/v3/ai.js
CHANGED
|
@@ -2934,7 +2934,6 @@ async function drainSteeringQueue(config, messages, steps, queueOverride) {
|
|
|
2934
2934
|
// Span attributes describe the offered batch; the chunk and callback below
|
|
2935
2935
|
// describe what was actually claimed and injected.
|
|
2936
2936
|
const messageTexts = uiMessages.map(textOfUIMessage);
|
|
2937
|
-
const _previewText = messageTexts.length === 1 ? messageTexts[0].slice(0, 80) : `${queue.length} messages`;
|
|
2938
2937
|
return tracer.startActiveSpan("pending message injected", async () => {
|
|
2939
2938
|
/**
|
|
2940
2939
|
* Claim before transforming, and inject only what was claimed.
|
|
@@ -3073,7 +3072,7 @@ async function drainSteeringQueue(config, messages, steps, queueOverride) {
|
|
|
3073
3072
|
[SemanticInternalAttributes.STYLE_ICON]: "tabler-message-forward",
|
|
3074
3073
|
"pending.message_count": uiMessages.length,
|
|
3075
3074
|
"pending.step_number": stepNumber,
|
|
3076
|
-
"pending.messages": messageTexts,
|
|
3075
|
+
...(ctx?.recordUserMessage === false ? {} : { "pending.messages": messageTexts }),
|
|
3077
3076
|
...(ctx?.chatId ? { "pending.chat_id": ctx.chatId } : {}),
|
|
3078
3077
|
...(ctx?.turn != null ? { "pending.turn": ctx.turn } : {}),
|
|
3079
3078
|
...accessoryAttributes({
|
|
@@ -3819,13 +3818,39 @@ async function pipeChat(source, options, capture) {
|
|
|
3819
3818
|
await waitUntilComplete();
|
|
3820
3819
|
}
|
|
3821
3820
|
}
|
|
3821
|
+
/** The AI SDK's default `toUIMessageStream` `onError`: the error's message, as the client sees it. */
|
|
3822
|
+
function uiStreamErrorText(error) {
|
|
3823
|
+
if (error == null)
|
|
3824
|
+
return "unknown error";
|
|
3825
|
+
if (typeof error === "string")
|
|
3826
|
+
return error;
|
|
3827
|
+
if (error instanceof Error)
|
|
3828
|
+
return error.message;
|
|
3829
|
+
return JSON.stringify(error);
|
|
3830
|
+
}
|
|
3831
|
+
/** The line a channel shows when a turn fails, unless the connector sets its own `errorMessage`. */
|
|
3832
|
+
export const CHANNEL_TURN_ERROR_MESSAGE = "Something went wrong answering this. Try again.";
|
|
3833
|
+
async function channelTurnErrorMessage(connector, ctx) {
|
|
3834
|
+
const option = connector?.errorMessage;
|
|
3835
|
+
if (typeof option !== "function")
|
|
3836
|
+
return option || CHANNEL_TURN_ERROR_MESSAGE;
|
|
3837
|
+
try {
|
|
3838
|
+
const line = await option({ ...ctx, defaultMessage: CHANNEL_TURN_ERROR_MESSAGE });
|
|
3839
|
+
if (line)
|
|
3840
|
+
return line;
|
|
3841
|
+
}
|
|
3842
|
+
catch (error) {
|
|
3843
|
+
logger.warn("chat.agent: channel errorMessage threw; posting the default line", { error });
|
|
3844
|
+
}
|
|
3845
|
+
return CHANNEL_TURN_ERROR_MESSAGE;
|
|
3846
|
+
}
|
|
3822
3847
|
/**
|
|
3823
3848
|
* A generic chat-frontend channel over any verified source. Unlike `slack()`, you supply the egress
|
|
3824
3849
|
* `send` yourself (post/edit the reply back to your surface), so the whole round-trip is under your
|
|
3825
3850
|
* control. Use for providers without a preset, or to test the channel round-trip end to end.
|
|
3826
3851
|
*/
|
|
3827
3852
|
export function chatChannelCustom(options) {
|
|
3828
|
-
const { id, endpoint, key, inbound, bind, seed, outbound, ack, send, renderInteraction, onInteraction, finalizeInteraction, react, reactions, progress, surface, onControl, stream, endInterruptedStream, download, received, toAction, lifecycle, cancelInteraction, filter, startOn, delivery, } = options;
|
|
3853
|
+
const { id, endpoint, key, inbound, bind, seed, outbound, ack, send, renderInteraction, onInteraction, finalizeInteraction, react, reactions, progress, surface, onControl, stream, endInterruptedStream, download, received, toAction, lifecycle, cancelInteraction, filter, startOn, delivery, errorMessage, } = options;
|
|
3829
3854
|
if (!endpoint?.id) {
|
|
3830
3855
|
throw new Error(`chat.channels.custom("${id}"): an endpoint is required. Declare one with webhooks.endpoint.define() and pass it as { endpoint }.`);
|
|
3831
3856
|
}
|
|
@@ -3859,6 +3884,7 @@ export function chatChannelCustom(options) {
|
|
|
3859
3884
|
lifecycle,
|
|
3860
3885
|
cancelInteraction,
|
|
3861
3886
|
delivery: delivery ?? "final",
|
|
3887
|
+
errorMessage,
|
|
3862
3888
|
};
|
|
3863
3889
|
}
|
|
3864
3890
|
const chatChannels = {
|
|
@@ -4356,6 +4382,7 @@ function makeChannelProgressObserver(connector, wireEvent, handle) {
|
|
|
4356
4382
|
const progress = connector.progress;
|
|
4357
4383
|
const turnCtx = channelTurnCtx(wireEvent, handle);
|
|
4358
4384
|
const toolNames = new Map();
|
|
4385
|
+
const toolTitles = new Map();
|
|
4359
4386
|
let chain = Promise.resolve();
|
|
4360
4387
|
let stopped = false;
|
|
4361
4388
|
const emit = (event) => {
|
|
@@ -4378,6 +4405,10 @@ function makeChannelProgressObserver(connector, wireEvent, handle) {
|
|
|
4378
4405
|
const c = chunk;
|
|
4379
4406
|
if (!c?.type || !c.toolCallId)
|
|
4380
4407
|
return;
|
|
4408
|
+
if (c.title)
|
|
4409
|
+
toolTitles.set(c.toolCallId, c.title);
|
|
4410
|
+
const title = toolTitles.get(c.toolCallId);
|
|
4411
|
+
const titled = title ? { title } : {};
|
|
4381
4412
|
if (c.type === "tool-input-start" && c.toolName) {
|
|
4382
4413
|
toolNames.set(c.toolCallId, c.toolName);
|
|
4383
4414
|
return;
|
|
@@ -4385,7 +4416,7 @@ function makeChannelProgressObserver(connector, wireEvent, handle) {
|
|
|
4385
4416
|
if (c.type === "tool-input-available") {
|
|
4386
4417
|
const toolName = c.toolName ?? toolNames.get(c.toolCallId) ?? "tool";
|
|
4387
4418
|
toolNames.set(c.toolCallId, toolName);
|
|
4388
|
-
emit({ type: "tool-call", toolCallId: c.toolCallId, toolName, input: c.input });
|
|
4419
|
+
emit({ type: "tool-call", toolCallId: c.toolCallId, toolName, ...titled, input: c.input });
|
|
4389
4420
|
return;
|
|
4390
4421
|
}
|
|
4391
4422
|
if (c.type === "tool-output-available" && !c.preliminary) {
|
|
@@ -4393,6 +4424,7 @@ function makeChannelProgressObserver(connector, wireEvent, handle) {
|
|
|
4393
4424
|
type: "tool-result",
|
|
4394
4425
|
toolCallId: c.toolCallId,
|
|
4395
4426
|
toolName: toolNames.get(c.toolCallId) ?? "tool",
|
|
4427
|
+
...titled,
|
|
4396
4428
|
output: c.output,
|
|
4397
4429
|
});
|
|
4398
4430
|
return;
|
|
@@ -4402,6 +4434,7 @@ function makeChannelProgressObserver(connector, wireEvent, handle) {
|
|
|
4402
4434
|
type: "tool-error",
|
|
4403
4435
|
toolCallId: c.toolCallId,
|
|
4404
4436
|
toolName: toolNames.get(c.toolCallId) ?? "tool",
|
|
4437
|
+
...titled,
|
|
4405
4438
|
errorText: c.errorText ?? "tool failed",
|
|
4406
4439
|
});
|
|
4407
4440
|
}
|
|
@@ -4493,6 +4526,7 @@ function stopPendingToolCalls(message, toolCallIds, errorText) {
|
|
|
4493
4526
|
*/
|
|
4494
4527
|
function makeChannelReplyStreamObserver(stream) {
|
|
4495
4528
|
const toolNames = new Map();
|
|
4529
|
+
const toolTitles = new Map();
|
|
4496
4530
|
let stopped = false;
|
|
4497
4531
|
const safe = (fn) => {
|
|
4498
4532
|
try {
|
|
@@ -4515,22 +4549,32 @@ function makeChannelReplyStreamObserver(stream) {
|
|
|
4515
4549
|
if (!stream.progress || !c?.type || !c.toolCallId)
|
|
4516
4550
|
return;
|
|
4517
4551
|
const toolCallId = c.toolCallId;
|
|
4552
|
+
if (c.title)
|
|
4553
|
+
toolTitles.set(toolCallId, c.title);
|
|
4554
|
+
const title = toolTitles.get(toolCallId);
|
|
4555
|
+
const titled = title ? { title } : {};
|
|
4518
4556
|
if (c.type === "tool-input-start" && c.toolName) {
|
|
4519
4557
|
toolNames.set(toolCallId, c.toolName);
|
|
4520
4558
|
}
|
|
4521
4559
|
else if (c.type === "tool-input-available") {
|
|
4522
4560
|
const toolName = c.toolName ?? toolNames.get(toolCallId) ?? "tool";
|
|
4523
4561
|
toolNames.set(toolCallId, toolName);
|
|
4524
|
-
safe(() => stream.progress({ type: "tool-call", toolCallId, toolName, input: c.input }));
|
|
4562
|
+
safe(() => stream.progress({ type: "tool-call", toolCallId, toolName, ...titled, input: c.input }));
|
|
4525
4563
|
}
|
|
4526
4564
|
else if (c.type === "tool-output-available" && !c.preliminary) {
|
|
4527
4565
|
const toolName = toolNames.get(toolCallId) ?? "tool";
|
|
4528
|
-
safe(() => stream.progress({
|
|
4566
|
+
safe(() => stream.progress({
|
|
4567
|
+
type: "tool-result",
|
|
4568
|
+
toolCallId,
|
|
4569
|
+
toolName,
|
|
4570
|
+
...titled,
|
|
4571
|
+
output: c.output,
|
|
4572
|
+
}));
|
|
4529
4573
|
}
|
|
4530
4574
|
else if (c.type === "tool-output-error") {
|
|
4531
4575
|
const toolName = toolNames.get(toolCallId) ?? "tool";
|
|
4532
4576
|
const errorText = c.errorText ?? "tool failed";
|
|
4533
|
-
safe(() => stream.progress({ type: "tool-error", toolCallId, toolName, errorText }));
|
|
4577
|
+
safe(() => stream.progress({ type: "tool-error", toolCallId, toolName, ...titled, errorText }));
|
|
4534
4578
|
}
|
|
4535
4579
|
},
|
|
4536
4580
|
stop() {
|
|
@@ -4812,7 +4856,9 @@ function chatCustomAgent(options) {
|
|
|
4812
4856
|
return task;
|
|
4813
4857
|
}
|
|
4814
4858
|
function chatAgent(options) {
|
|
4815
|
-
const { run: userRun, clientDataSchema, onBoot, onRecoveryBoot, onPreload, onChatStart, onValidateMessages, hydrateMessages, storage, actionSchema, events, channels, onAction, onTurnStart, onBeforeTurnComplete, onCompacted, compaction, pendingMessages: pendingMessagesConfig, prepareMessages, tools: toolsOption, onTurnComplete, maxTurns = 100, turnTimeout = "1h", idleTimeoutInSeconds = 30, chatAccessTokenTTL = "1h", preloadIdleTimeoutInSeconds, preloadTimeout, uiMessageStreamOptions, onChatSuspend, onChatResume, exitAfterPreloadIdle = false, oomMachine, registry: promptRegistry, system: agentSystem, cacheControl: agentCacheControl, systemProviderOptions: agentSystemProviderOptions, versionSkew, ...restOptions } = options;
|
|
4859
|
+
const { run: userRun, clientDataSchema, onBoot, onRecoveryBoot, onPreload, onChatStart, onValidateMessages, hydrateMessages, storage, actionSchema, events, channels, onAction, onTurnStart, onBeforeTurnComplete, onCompacted, compaction, pendingMessages: pendingMessagesConfig, prepareMessages, tools: toolsOption, onTurnComplete, maxTurns = 100, turnTimeout = "1h", idleTimeoutInSeconds = 30, chatAccessTokenTTL = "1h", preloadIdleTimeoutInSeconds, preloadTimeout, uiMessageStreamOptions, onChatSuspend, onChatResume, exitAfterPreloadIdle = false, oomMachine, registry: promptRegistry, system: agentSystem, cacheControl: agentCacheControl, systemProviderOptions: agentSystemProviderOptions, versionSkew, telemetry: telemetryOptions, ...restOptions } = options;
|
|
4860
|
+
const recordUserMessage = telemetryOptions?.recordUserMessage ?? true;
|
|
4861
|
+
const recordClientData = telemetryOptions?.recordClientData ?? true;
|
|
4816
4862
|
if (hydrateMessages) {
|
|
4817
4863
|
if (storage) {
|
|
4818
4864
|
throw new Error(`chat.agent: "${options.id}" sets both \`hydrateMessages\` and \`storage\`. ` +
|
|
@@ -6094,6 +6140,8 @@ function chatAgent(options) {
|
|
|
6094
6140
|
let channelFinalSendFailed = false;
|
|
6095
6141
|
/** The stream-level error (an `error` chunk) this turn ended on, if any; posted to the channel in place of an empty reply. */
|
|
6096
6142
|
let channelStreamErrorText;
|
|
6143
|
+
/** The original error behind that chunk, captured from `toUIMessageStream`'s `onError` when auto-piping. */
|
|
6144
|
+
let channelStreamError;
|
|
6097
6145
|
/** The text this turn streamed, so the channel reply is this turn's answer and not the whole message. */
|
|
6098
6146
|
let channelTurnText;
|
|
6099
6147
|
try {
|
|
@@ -6501,7 +6549,7 @@ function chatAgent(options) {
|
|
|
6501
6549
|
: "tabler-message-chatbot",
|
|
6502
6550
|
[SemanticInternalAttributes.ENTITY_TYPE]: isAction ? "chat-action" : "chat-turn",
|
|
6503
6551
|
};
|
|
6504
|
-
if (lastUserMessage) {
|
|
6552
|
+
if (lastUserMessage && recordUserMessage) {
|
|
6505
6553
|
turnAttributes["chat.user_message"] = lastUserMessage;
|
|
6506
6554
|
// Show a truncated preview of the user message as an accessory
|
|
6507
6555
|
const preview = lastUserMessage.length > 80
|
|
@@ -6512,7 +6560,7 @@ function chatAgent(options) {
|
|
|
6512
6560
|
style: "codepath",
|
|
6513
6561
|
}));
|
|
6514
6562
|
}
|
|
6515
|
-
if (wireMetadata !== undefined) {
|
|
6563
|
+
if (wireMetadata !== undefined && recordClientData) {
|
|
6516
6564
|
turnAttributes["chat.client_data"] =
|
|
6517
6565
|
typeof wireMetadata === "string" ? wireMetadata : JSON.stringify(wireMetadata);
|
|
6518
6566
|
}
|
|
@@ -6537,6 +6585,7 @@ function chatAgent(options) {
|
|
|
6537
6585
|
turn,
|
|
6538
6586
|
continuation,
|
|
6539
6587
|
clientData,
|
|
6588
|
+
recordUserMessage,
|
|
6540
6589
|
});
|
|
6541
6590
|
// Resolve the per-turn `tools` set now that turn context
|
|
6542
6591
|
// (incl. parsed clientData) exists, so every toModelMessages
|
|
@@ -7437,6 +7486,12 @@ function chatAgent(options) {
|
|
|
7437
7486
|
// messageId. Without this, the frontend and backend generate IDs
|
|
7438
7487
|
// independently and they won't match for ID-based dedup.
|
|
7439
7488
|
generateMessageId: resolvedOptions.generateMessageId ?? generateMessageId,
|
|
7489
|
+
onError: (error) => {
|
|
7490
|
+
channelStreamError ??= error;
|
|
7491
|
+
return resolvedOptions.onError
|
|
7492
|
+
? resolvedOptions.onError(error)
|
|
7493
|
+
: uiStreamErrorText(error);
|
|
7494
|
+
},
|
|
7440
7495
|
onFinish: ({ responseMessage, finishReason, }) => {
|
|
7441
7496
|
capturedResponseMessage = responseMessage;
|
|
7442
7497
|
capturedPartialResponse = responseMessage;
|
|
@@ -7961,6 +8016,21 @@ function chatAgent(options) {
|
|
|
7961
8016
|
const renderControls = !!((wireChannelEvent || boundTurn) &&
|
|
7962
8017
|
pendingToolCalls.length > 0 &&
|
|
7963
8018
|
channelConn?.renderInteraction);
|
|
8019
|
+
let channelErrorLine;
|
|
8020
|
+
if (channelStreamErrorText && (wireChannelEvent || boundTurn)) {
|
|
8021
|
+
logger.warn("chat.agent: channel turn ended on a model or stream error", {
|
|
8022
|
+
errorText: channelStreamErrorText,
|
|
8023
|
+
});
|
|
8024
|
+
channelErrorLine = await channelTurnErrorMessage(channelConn, {
|
|
8025
|
+
error: channelStreamError instanceof Error
|
|
8026
|
+
? channelStreamError
|
|
8027
|
+
: new Error(channelStreamErrorText),
|
|
8028
|
+
partialText: channelTurnText?.trim() ?? "",
|
|
8029
|
+
event: channelWireEvent?.event,
|
|
8030
|
+
runId: ctx.run.id,
|
|
8031
|
+
chatId: currentWirePayload.chatId,
|
|
8032
|
+
});
|
|
8033
|
+
}
|
|
7964
8034
|
let channelReplyDelivered = false;
|
|
7965
8035
|
if (channelReplyStream) {
|
|
7966
8036
|
const replyStream = channelReplyStream;
|
|
@@ -7969,7 +8039,9 @@ function chatAgent(options) {
|
|
|
7969
8039
|
const ended = await replyStream.end({
|
|
7970
8040
|
stopped: turnCompleteEvent.stopped,
|
|
7971
8041
|
pending: renderControls,
|
|
7972
|
-
...(channelStreamErrorText
|
|
8042
|
+
...(channelStreamErrorText
|
|
8043
|
+
? { errorText: channelErrorLine ?? CHANNEL_TURN_ERROR_MESSAGE }
|
|
8044
|
+
: {}),
|
|
7973
8045
|
});
|
|
7974
8046
|
channelReplyDelivered = ended.delivered;
|
|
7975
8047
|
}
|
|
@@ -7999,13 +8071,16 @@ function chatAgent(options) {
|
|
|
7999
8071
|
? channelTurnText
|
|
8000
8072
|
: channelReplyText(turnCompleteEvent.responseMessage);
|
|
8001
8073
|
// A model or stream error surfaces as an `error` chunk and an empty reply, not as a
|
|
8002
|
-
// thrown turn. The mapper gets it on this one call, with the error
|
|
8003
|
-
// for an empty reply, so the placeholder never sits there as if the agent
|
|
8004
|
-
// still working.
|
|
8074
|
+
// thrown turn. The mapper gets it on this one call, with the connector's error line
|
|
8075
|
+
// standing in for an empty reply, so the placeholder never sits there as if the agent
|
|
8076
|
+
// were still working. The error text itself stays on the run, not in the channel.
|
|
8005
8077
|
const finalReply = {
|
|
8006
8078
|
// Prefer what this turn streamed; a resumed message carries earlier turns' text too.
|
|
8007
|
-
|
|
8008
|
-
|
|
8079
|
+
// A failed turn always ends on the connector's error line, after any partial text.
|
|
8080
|
+
text: channelErrorLine
|
|
8081
|
+
? replyText.trim().length > 0
|
|
8082
|
+
? `${replyText.trimEnd()}\n\n${channelErrorLine}`
|
|
8083
|
+
: channelErrorLine
|
|
8009
8084
|
: replyText,
|
|
8010
8085
|
message: turnCompleteEvent.responseMessage,
|
|
8011
8086
|
final: true,
|
|
@@ -8374,18 +8449,16 @@ function chatAgent(options) {
|
|
|
8374
8449
|
logger.warn("chat.agent: channel error reaction failed", { error: reactionError });
|
|
8375
8450
|
}
|
|
8376
8451
|
}
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
catch { }
|
|
8388
|
-
}
|
|
8452
|
+
// The channel gets the connector's error line, never the error itself: the run keeps that.
|
|
8453
|
+
const channelErrorText = channelReplyStream || ((channelWireEvent || boundTurn) && channelConn?.send)
|
|
8454
|
+
? await channelTurnErrorMessage(channelConn, {
|
|
8455
|
+
error: turnError instanceof Error ? turnError : new Error(String(turnError)),
|
|
8456
|
+
partialText: channelTurnText?.trim() ?? "",
|
|
8457
|
+
event: channelWireEvent?.event,
|
|
8458
|
+
runId: ctx.run.id,
|
|
8459
|
+
chatId: currentWirePayload.chatId,
|
|
8460
|
+
})
|
|
8461
|
+
: CHANNEL_TURN_ERROR_MESSAGE;
|
|
8389
8462
|
let errorStreamDelivered = false;
|
|
8390
8463
|
if (channelReplyStream) {
|
|
8391
8464
|
const replyStream = channelReplyStream;
|