better-mastra 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/messages.d.ts +10 -0
- package/dist/client/messages.d.ts.map +1 -1
- package/dist/client/messages.js +30 -0
- package/dist/client/messages.js.map +1 -1
- package/dist/client/resume.d.ts +27 -0
- package/dist/client/resume.d.ts.map +1 -0
- package/dist/client/resume.js +46 -0
- package/dist/client/resume.js.map +1 -0
- package/dist/client/session.d.ts +5 -0
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +36 -1
- package/dist/client/session.js.map +1 -1
- package/dist/client/turn.d.ts +4 -0
- package/dist/client/turn.d.ts.map +1 -1
- package/dist/client/turn.js +16 -0
- package/dist/client/turn.js.map +1 -1
- package/dist/dictation/react/index.d.ts +4 -2
- package/dist/dictation/react/index.d.ts.map +1 -1
- package/dist/dictation/react/index.js +9 -1
- package/dist/dictation/react/index.js.map +1 -1
- package/dist/dictation/session.d.ts +5 -1
- package/dist/dictation/session.d.ts.map +1 -1
- package/dist/dictation/session.js +25 -5
- package/dist/dictation/session.js.map +1 -1
- package/dist/dictation/vue/index.d.ts +4 -2
- package/dist/dictation/vue/index.d.ts.map +1 -1
- package/dist/dictation/vue/index.js +9 -1
- package/dist/dictation/vue/index.js.map +1 -1
- package/dist/evals/checks.d.ts +2 -1
- package/dist/evals/checks.d.ts.map +1 -1
- package/dist/evals/checks.js +1 -1
- package/dist/evals/checks.js.map +1 -1
- package/dist/evals/cli.js +21 -2
- package/dist/evals/cli.js.map +1 -1
- package/dist/evals/judge.d.ts +16 -2
- package/dist/evals/judge.d.ts.map +1 -1
- package/dist/evals/judge.js +13 -4
- package/dist/evals/judge.js.map +1 -1
- package/dist/evals/mastra.d.ts.map +1 -1
- package/dist/evals/mastra.js +17 -2
- package/dist/evals/mastra.js.map +1 -1
- package/dist/evals/run.d.ts +6 -3
- package/dist/evals/run.d.ts.map +1 -1
- package/dist/evals/run.js +6 -8
- package/dist/evals/run.js.map +1 -1
- package/dist/hono/chatRoute.d.ts +7 -2
- package/dist/hono/chatRoute.d.ts.map +1 -1
- package/dist/hono/chatRoute.js +10 -6
- package/dist/hono/chatRoute.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/turn/agent.d.ts.map +1 -1
- package/dist/turn/agent.js +4 -1
- package/dist/turn/agent.js.map +1 -1
- package/dist/turn/index.d.ts +3 -3
- package/dist/turn/index.d.ts.map +1 -1
- package/dist/turn/index.js +1 -1
- package/dist/turn/index.js.map +1 -1
- package/dist/turn/runChatTurn.d.ts +10 -5
- package/dist/turn/runChatTurn.d.ts.map +1 -1
- package/dist/turn/runChatTurn.js +38 -2
- package/dist/turn/runChatTurn.js.map +1 -1
- package/dist/turn/stream.d.ts +8 -0
- package/dist/turn/stream.d.ts.map +1 -1
- package/dist/turn/stream.js +11 -0
- package/dist/turn/stream.js.map +1 -1
- package/dist/turn/threads.d.ts +17 -2
- package/dist/turn/threads.d.ts.map +1 -1
- package/dist/turn/threads.js +18 -5
- package/dist/turn/threads.js.map +1 -1
- package/dist/turn/types.d.ts +23 -4
- package/dist/turn/types.d.ts.map +1 -1
- package/dist/turn/types.js.map +1 -1
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.js +1 -0
- package/dist/vue/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +1 -0
- package/src/client/messages.ts +41 -0
- package/src/client/resume.ts +82 -0
- package/src/client/session.ts +53 -1
- package/src/client/turn.ts +19 -0
- package/src/dictation/react/index.ts +16 -3
- package/src/dictation/session.ts +38 -5
- package/src/dictation/vue/index.ts +16 -3
- package/src/evals/checks.ts +3 -3
- package/src/evals/cli.ts +24 -2
- package/src/evals/judge.ts +38 -6
- package/src/evals/mastra.ts +23 -4
- package/src/evals/run.ts +8 -8
- package/src/hono/chatRoute.ts +18 -9
- package/src/react/index.ts +2 -0
- package/src/turn/agent.ts +6 -2
- package/src/turn/index.ts +3 -0
- package/src/turn/runChatTurn.ts +61 -5
- package/src/turn/stream.ts +15 -0
- package/src/turn/threads.ts +47 -6
- package/src/turn/types.ts +25 -4
- package/src/vue/index.ts +2 -0
package/dist/client/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA"}
|
package/dist/client/index.js
CHANGED
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA","sourcesContent":["export * from './actions.js'\nexport * from './cards.js'\nexport * from './chat.js'\nexport * from './errors.js'\nexport * from './fetch.js'\nexport * from './messages.js'\nexport * from './pending.js'\nexport * from './ratings.js'\nexport * from './reveal.js'\nexport * from './screen-context.js'\nexport * from './session.js'\nexport * from './turn.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,qBAAqB,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA","sourcesContent":["export * from './actions.js'\nexport * from './cards.js'\nexport * from './chat.js'\nexport * from './errors.js'\nexport * from './fetch.js'\nexport * from './messages.js'\nexport * from './pending.js'\nexport * from './ratings.js'\nexport * from './resume.js'\nexport * from './reveal.js'\nexport * from './screen-context.js'\nexport * from './session.js'\nexport * from './turn.js'\n"]}
|
|
@@ -31,6 +31,8 @@ export interface RequestMessageOptions {
|
|
|
31
31
|
/** The transient data part a server streams after an answer: up to three replies the user can tap to send. */
|
|
32
32
|
export declare const REPLY_SUGGESTIONS_PART = "data-reply-suggestions";
|
|
33
33
|
export declare const REPLY_SUGGESTIONS_MAX = 3;
|
|
34
|
+
/** The transient data part a turn streams right after its start: the user's message, for a client that reattaches before the thread stores it. */
|
|
35
|
+
export declare const USER_MESSAGE_PART = "data-user-message";
|
|
34
36
|
/** The longest reply offered, in characters; a longer one is dropped. */
|
|
35
37
|
export declare const REPLY_SUGGESTION_MAX_LENGTH = 80;
|
|
36
38
|
/**
|
|
@@ -113,6 +115,14 @@ export declare function countShownParts(message: UIMessage | undefined, isUserFa
|
|
|
113
115
|
* too long or repeated ones, at most three; undefined when the data is not a
|
|
114
116
|
* reply list.
|
|
115
117
|
*/
|
|
118
|
+
/** The user message a `data-user-message` part carries, or undefined for any other data. */
|
|
119
|
+
export declare function readUserMessage(data: unknown): UIMessage | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* Why the server stopped the answer early, such as `tool_call_budget`
|
|
122
|
+
* (`TOOL_CALL_BUDGET_STOP_REASON`): the `reason` of its tripwire part.
|
|
123
|
+
* Undefined for an answer that ended on its own.
|
|
124
|
+
*/
|
|
125
|
+
export declare function readStopReason(message: UIMessage | undefined): string | undefined;
|
|
116
126
|
export declare function readReplySuggestions(data: unknown): readonly string[] | undefined;
|
|
117
127
|
/** The replies worth offering from a model's list, in its order. */
|
|
118
128
|
export declare function toReplySuggestions(suggestions: readonly (string | undefined)[]): readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/client/messages.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/client/messages.ts"],"names":[],"mappings":"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"}
|
package/dist/client/messages.js
CHANGED
|
@@ -11,6 +11,10 @@ const OBSERVATIONAL_MEMORY_PART_PREFIX = 'data-om-';
|
|
|
11
11
|
/** The transient data part a server streams after an answer: up to three replies the user can tap to send. */
|
|
12
12
|
export const REPLY_SUGGESTIONS_PART = 'data-reply-suggestions';
|
|
13
13
|
export const REPLY_SUGGESTIONS_MAX = 3;
|
|
14
|
+
/** The transient data part a turn streams right after its start: the user's message, for a client that reattaches before the thread stores it. */
|
|
15
|
+
export const USER_MESSAGE_PART = 'data-user-message';
|
|
16
|
+
/** The tripwire part a run that a processor stopped ends with; its `reason` says why. */
|
|
17
|
+
const TRIPWIRE_PART = 'data-tripwire';
|
|
14
18
|
/** The longest reply offered, in characters; a longer one is dropped. */
|
|
15
19
|
export const REPLY_SUGGESTION_MAX_LENGTH = 80;
|
|
16
20
|
/**
|
|
@@ -212,6 +216,32 @@ export function countShownParts(message, isUserFacing = isUserFacingPart) {
|
|
|
212
216
|
* too long or repeated ones, at most three; undefined when the data is not a
|
|
213
217
|
* reply list.
|
|
214
218
|
*/
|
|
219
|
+
/** The user message a `data-user-message` part carries, or undefined for any other data. */
|
|
220
|
+
export function readUserMessage(data) {
|
|
221
|
+
const message = data?.message;
|
|
222
|
+
return typeof message?.id === 'string' &&
|
|
223
|
+
message.role === 'user' &&
|
|
224
|
+
Array.isArray(message.parts)
|
|
225
|
+
? message
|
|
226
|
+
: undefined;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Why the server stopped the answer early, such as `tool_call_budget`
|
|
230
|
+
* (`TOOL_CALL_BUDGET_STOP_REASON`): the `reason` of its tripwire part.
|
|
231
|
+
* Undefined for an answer that ended on its own.
|
|
232
|
+
*/
|
|
233
|
+
export function readStopReason(message) {
|
|
234
|
+
if (message?.role !== 'assistant')
|
|
235
|
+
return undefined;
|
|
236
|
+
for (const part of message.parts) {
|
|
237
|
+
const reason = part.type === TRIPWIRE_PART
|
|
238
|
+
? part.data?.reason
|
|
239
|
+
: undefined;
|
|
240
|
+
if (typeof reason === 'string')
|
|
241
|
+
return reason;
|
|
242
|
+
}
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
215
245
|
export function readReplySuggestions(data) {
|
|
216
246
|
const suggestions = data?.suggestions;
|
|
217
247
|
if (!Array.isArray(suggestions)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/client/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Message helpers every client shares: which messages one request sends,\n * which parts reach the user, the stored thread merged with the live one,\n * tool calls a request left without a result, and the reply suggestions an\n * answer offers.\n */\n\nimport {\n\tgetToolName,\n\tisReasoningUIPart,\n\tisTextUIPart,\n\tisToolUIPart,\n\ttype UIMessage\n} from 'ai'\n\nimport { readSuspendedRun } from './pending.js'\n\n// TYPES\n\ntype MessagePart = UIMessage['parts'][number]\n\n/** A tool call in a message, from a typed tool or a dynamic one. */\nexport type ToolPart = Extract<MessagePart, { readonly toolCallId: string }>\n\n/** One block a message draws, in the order of its parts. */\nexport type MessageBlock =\n\t| {\n\t\t\treadonly kind: 'text'\n\t\t\treadonly key: string\n\t\t\treadonly text: string\n\t\t\t/** The AI SDK is still writing this text. */\n\t\t\treadonly streaming: boolean\n\t }\n\t/** Neighbouring tool parts: the cards of one step sit in one place between the texts. */\n\t| {\n\t\t\treadonly kind: 'tools'\n\t\t\treadonly key: string\n\t\t\treadonly parts: readonly ToolPart[]\n\t }\n\nexport interface RequestMessageOptions {\n\t/** Whether a tool part holds a result the client produced: a client action's result, or an error it posted. */\n\treadonly isClientResult?: (part: ToolPart) => boolean\n}\n\n// CONSTANTS\n\nconst OBSERVATIONAL_MEMORY_PART_PREFIX = 'data-om-'\n\n/** The transient data part a server streams after an answer: up to three replies the user can tap to send. */\nexport const REPLY_SUGGESTIONS_PART = 'data-reply-suggestions'\n\nexport const REPLY_SUGGESTIONS_MAX = 3\n\n/** The longest reply offered, in characters; a longer one is dropped. */\nexport const REPLY_SUGGESTION_MAX_LENGTH = 80\n\n/**\n * What the model reads for a server tool call a request left without a\n * result: Mastra drops a server result when a client action shares its step.\n */\nexport const STRANDED_TOOL_ERROR =\n\t'This tool call was interrupted because it ran in the same step as a client action. Call the tool again on its own to get the result.'\n\n// FUNCTIONS\n\n/** Whether a message part may reach the user: observational memory's `data-om-*` bookkeeping parts may not. */\nexport function isUserFacingPart(part: { readonly type: string }): boolean {\n\treturn !part.type.startsWith(OBSERVATIONAL_MEMORY_PART_PREFIX)\n}\n\n/** The message with only its user-facing parts. */\nexport function toUserFacingMessage<M extends UIMessage>(message: M): M {\n\treturn { ...message, parts: message.parts.filter(isUserFacingPart) }\n}\n\n/**\n * The blocks one message draws: its non-blank texts and its runs of tool\n * parts. Every other part, and every part observational memory adds, draws\n * nothing here; a client draws the data parts it knows itself.\n */\nexport function toMessageBlocks(message: UIMessage): MessageBlock[] {\n\tconst blocks: MessageBlock[] = []\n\n\tfor (const [index, part] of message.parts.entries()) {\n\t\tconst key = `${message.id}:${index}`\n\t\tconst previous = blocks.at(-1)\n\n\t\tif (!isUserFacingPart(part)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isTextUIPart(part) && part.text.trim() !== '') {\n\t\t\tblocks.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tkey,\n\t\t\t\ttext: part.text,\n\t\t\t\tstreaming: part.state === 'streaming'\n\t\t\t})\n\t\t} else if (isToolUIPart(part)) {\n\t\t\tif (previous?.kind === 'tools') {\n\t\t\t\tblocks[blocks.length - 1] = {\n\t\t\t\t\t...previous,\n\t\t\t\t\tparts: [...previous.parts, part]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tblocks.push({ kind: 'tools', key, parts: [part] })\n\t\t\t}\n\t\t}\n\t}\n\n\treturn blocks\n}\n\n/**\n * The messages one request sends. Observational memory supplies the thread's\n * history, so a new user turn sends only the user's new message. When the\n * trailing assistant message carries results the client produced (client\n * action results, approval answers), the messages of the current user turn,\n * ending with that message. To resume a suspended run, the trailing assistant\n * message alone: Mastra resumes the run from its snapshot.\n */\nexport function selectRequestMessages(\n\tmessages: readonly UIMessage[],\n\toptions: RequestMessageOptions = {}\n): UIMessage[] {\n\tconst lastMessage = messages.at(-1)\n\n\tif (lastMessage === undefined) {\n\t\treturn []\n\t}\n\n\tswitch (lastMessage.role) {\n\t\tcase 'user':\n\t\t\treturn [lastMessage]\n\t\tcase 'assistant':\n\t\t\tif (\n\t\t\t\tlastMessage.parts.some((part) => readSuspendedRun(part) !== undefined)\n\t\t\t) {\n\t\t\t\treturn [lastMessage]\n\t\t\t}\n\n\t\t\treturn carriesClientResults(lastMessage, options)\n\t\t\t\t? currentUserTurn(messages)\n\t\t\t\t: lastUserMessage(messages)\n\t\tcase 'system':\n\t\t\treturn lastUserMessage(messages)\n\t}\n}\n\n/** From the last user message to the end; the trailing message alone when there is no user message. */\nexport function currentUserTurn(messages: readonly UIMessage[]): UIMessage[] {\n\tconst lastUserIndex = lastIndexOfUser(messages)\n\n\tif (lastUserIndex !== -1) {\n\t\treturn messages.slice(lastUserIndex)\n\t}\n\n\tconst trailing = messages.at(-1)\n\n\treturn trailing === undefined ? [] : [trailing]\n}\n\n/** Which parts an answer resumes after: Mastra stores the continuation as a message of its own. */\nexport type ResumePointOptions = {\n\t/** Default `isToolResultPart`: after any tool's result. */\n\treadonly isResumePoint?: (part: MessagePart) => boolean\n}\n\n/** A tool call with its output or error, the default resume point. */\nexport function isToolResultPart(part: MessagePart): boolean {\n\treturn (\n\t\tisToolUIPart(part) &&\n\t\t(part.state === 'output-available' || part.state === 'output-error')\n\t)\n}\n\n/**\n * Joins an assistant message into the assistant message before it when that\n * one ends at a resume point. Mastra stores the text a run wrote after\n * resuming from a client tool's result as a new message, while the client\n * streamed it into the message that holds the call; joining keeps that\n * message and its id.\n */\nexport function joinResumedAnswers<M extends UIMessage>(\n\tmessages: readonly M[],\n\toptions: ResumePointOptions = {}\n): M[] {\n\tconst isResumePoint = options.isResumePoint ?? isToolResultPart\n\n\treturn messages.reduce<M[]>((joined, message) => {\n\t\tconst previous = joined.at(-1)\n\t\tconst lastPart = previous?.parts.at(-1)\n\t\tconst resumesPrevious =\n\t\t\tmessage.role === 'assistant' &&\n\t\t\tprevious?.role === 'assistant' &&\n\t\t\tlastPart !== undefined &&\n\t\t\tisResumePoint(lastPart)\n\n\t\tif (previous !== undefined && resumesPrevious) {\n\t\t\tjoined[joined.length - 1] = {\n\t\t\t\t...previous,\n\t\t\t\tparts: [...previous.parts, ...message.parts]\n\t\t\t}\n\t\t} else {\n\t\t\tjoined.push(message)\n\t\t}\n\n\t\treturn joined\n\t}, [])\n}\n\n/**\n * The stored messages, oldest first, then the live ones. A message in both\n * shows once, as the live copy, which is the one still changing. An answer\n * resumed after a client action's result shows as one answer (see\n * `joinResumedAnswers`).\n */\nexport function mergeThreadMessages<M extends UIMessage>(\n\tstored: readonly M[],\n\tlive: readonly M[],\n\toptions: ResumePointOptions = {}\n): M[] {\n\tconst liveIds = new Set(live.map((message) => message.id))\n\n\treturn joinResumedAnswers(\n\t\t[...stored.filter((message) => !liveIds.has(message.id)), ...live],\n\t\toptions\n\t)\n}\n\n/**\n * Server tool calls a request left at `input-available`: Mastra drops a\n * server result when a client action shares its step. The session answers\n * them with `STRANDED_TOOL_ERROR`, so the follow-up goes on instead of\n * hanging.\n */\nexport function findStrandedToolCalls(\n\tmessage: UIMessage | undefined,\n\tisClientAction: (toolName: string) => boolean\n): { readonly toolCallId: string; readonly toolName: string }[] {\n\tif (message?.role !== 'assistant') {\n\t\treturn []\n\t}\n\n\tconst suspended = new Set(\n\t\tmessage.parts.flatMap((part) => readSuspendedRun(part)?.toolCallId ?? [])\n\t)\n\n\treturn message.parts.flatMap((part) => {\n\t\tif (\n\t\t\t!isToolUIPart(part) ||\n\t\t\tpart.state !== 'input-available' ||\n\t\t\tpart.providerExecuted === true ||\n\t\t\tsuspended.has(part.toolCallId)\n\t\t) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst toolName = getToolName(part)\n\n\t\treturn isClientAction(toolName)\n\t\t\t? []\n\t\t\t: [{ toolCallId: part.toolCallId, toolName }]\n\t})\n}\n\n/**\n * Whether the newest answer's latest step puts something on screen: answer\n * text, a running tool card, or shown reasoning. A step with only finished\n * tools or hidden reasoning is the model working out of sight, and a\n * \"Thinking…\" indicator has to cover that gap.\n */\nexport function isShowingProgress(\n\tmessages: readonly UIMessage[],\n\toptions: { readonly reasoningVisible?: boolean } = {}\n): boolean {\n\tconst newest = messages.at(-1)\n\n\tif (newest?.role !== 'assistant') {\n\t\treturn false\n\t}\n\n\tfor (let index = newest.parts.length - 1; index >= 0; index -= 1) {\n\t\tconst part = newest.parts[index]\n\n\t\tif (part === undefined || part.type === 'step-start') {\n\t\t\treturn false\n\t\t}\n\n\t\tif (isTextUIPart(part) && part.text.length > 0) {\n\t\t\treturn true\n\t\t}\n\n\t\tif (isToolUIPart(part)) {\n\t\t\treturn (\n\t\t\t\tpart.state === 'input-streaming' || part.state === 'input-available'\n\t\t\t)\n\t\t}\n\n\t\tif (\n\t\t\toptions.reasoningVisible &&\n\t\t\tisReasoningUIPart(part) &&\n\t\t\tpart.state === 'streaming'\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * How many parts of an answer are on screen: answer text that is not blank,\n * and every tool part. Reasoning is not shown, and observational memory's\n * parts never are.\n */\nexport function countShownParts(\n\tmessage: UIMessage | undefined,\n\tisUserFacing: (part: MessagePart) => boolean = isUserFacingPart\n): number {\n\tif (message?.role !== 'assistant') {\n\t\treturn 0\n\t}\n\n\treturn message.parts.filter(\n\t\t(part) =>\n\t\t\tisUserFacing(part) &&\n\t\t\t((isTextUIPart(part) && part.text.trim() !== '') || isToolUIPart(part))\n\t).length\n}\n\n/**\n * The replies a reply-suggestions data part carries, trimmed, without empty,\n * too long or repeated ones, at most three; undefined when the data is not a\n * reply list.\n */\nexport function readReplySuggestions(\n\tdata: unknown\n): readonly string[] | undefined {\n\tconst suggestions = (data as { suggestions?: unknown } | null)?.suggestions\n\n\tif (!Array.isArray(suggestions)) {\n\t\treturn undefined\n\t}\n\n\treturn toReplySuggestions(\n\t\tsuggestions.map((suggestion) =>\n\t\t\ttypeof suggestion === 'string' ? suggestion : undefined\n\t\t)\n\t)\n}\n\n/** The replies worth offering from a model's list, in its order. */\nexport function toReplySuggestions(\n\tsuggestions: readonly (string | undefined)[]\n): readonly string[] {\n\tconst replies: string[] = []\n\n\tfor (const suggestion of suggestions) {\n\t\tconst reply = suggestion?.trim() ?? ''\n\t\tconst isOffered =\n\t\t\treply.length > 0 &&\n\t\t\treply.length <= REPLY_SUGGESTION_MAX_LENGTH &&\n\t\t\t!replies.some((offered) => offered.toLowerCase() === reply.toLowerCase())\n\n\t\tif (isOffered) {\n\t\t\treplies.push(reply)\n\t\t}\n\t}\n\n\treturn replies.slice(0, REPLY_SUGGESTIONS_MAX)\n}\n\nfunction carriesClientResults(\n\tmessage: UIMessage,\n\toptions: RequestMessageOptions\n): boolean {\n\treturn message.parts.some(\n\t\t(part) =>\n\t\t\tisToolUIPart(part) &&\n\t\t\t(part.state === 'approval-responded' ||\n\t\t\t\t((part.state === 'output-available' || part.state === 'output-error') &&\n\t\t\t\t\toptions.isClientResult?.(part) === true))\n\t)\n}\n\nfunction lastUserMessage(messages: readonly UIMessage[]): UIMessage[] {\n\tconst message = messages[lastIndexOfUser(messages)]\n\n\treturn message === undefined ? [] : [message]\n}\n\n/** `findLastIndex`, which the ES2022 build target lacks. */\nfunction lastIndexOfUser(messages: readonly UIMessage[]): number {\n\tfor (let index = messages.length - 1; index >= 0; index -= 1) {\n\t\tif (messages[index]?.role === 'user') {\n\t\t\treturn index\n\t\t}\n\t}\n\n\treturn -1\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/client/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Message helpers every client shares: which messages one request sends,\n * which parts reach the user, the stored thread merged with the live one,\n * tool calls a request left without a result, and the reply suggestions an\n * answer offers.\n */\n\nimport {\n\tgetToolName,\n\tisReasoningUIPart,\n\tisTextUIPart,\n\tisToolUIPart,\n\ttype UIMessage\n} from 'ai'\n\nimport { readSuspendedRun } from './pending.js'\n\n// TYPES\n\ntype MessagePart = UIMessage['parts'][number]\n\n/** A tool call in a message, from a typed tool or a dynamic one. */\nexport type ToolPart = Extract<MessagePart, { readonly toolCallId: string }>\n\n/** One block a message draws, in the order of its parts. */\nexport type MessageBlock =\n\t| {\n\t\t\treadonly kind: 'text'\n\t\t\treadonly key: string\n\t\t\treadonly text: string\n\t\t\t/** The AI SDK is still writing this text. */\n\t\t\treadonly streaming: boolean\n\t }\n\t/** Neighbouring tool parts: the cards of one step sit in one place between the texts. */\n\t| {\n\t\t\treadonly kind: 'tools'\n\t\t\treadonly key: string\n\t\t\treadonly parts: readonly ToolPart[]\n\t }\n\nexport interface RequestMessageOptions {\n\t/** Whether a tool part holds a result the client produced: a client action's result, or an error it posted. */\n\treadonly isClientResult?: (part: ToolPart) => boolean\n}\n\n// CONSTANTS\n\nconst OBSERVATIONAL_MEMORY_PART_PREFIX = 'data-om-'\n\n/** The transient data part a server streams after an answer: up to three replies the user can tap to send. */\nexport const REPLY_SUGGESTIONS_PART = 'data-reply-suggestions'\n\nexport const REPLY_SUGGESTIONS_MAX = 3\n\n/** The transient data part a turn streams right after its start: the user's message, for a client that reattaches before the thread stores it. */\nexport const USER_MESSAGE_PART = 'data-user-message'\n\n/** The tripwire part a run that a processor stopped ends with; its `reason` says why. */\nconst TRIPWIRE_PART = 'data-tripwire'\n\n/** The longest reply offered, in characters; a longer one is dropped. */\nexport const REPLY_SUGGESTION_MAX_LENGTH = 80\n\n/**\n * What the model reads for a server tool call a request left without a\n * result: Mastra drops a server result when a client action shares its step.\n */\nexport const STRANDED_TOOL_ERROR =\n\t'This tool call was interrupted because it ran in the same step as a client action. Call the tool again on its own to get the result.'\n\n// FUNCTIONS\n\n/** Whether a message part may reach the user: observational memory's `data-om-*` bookkeeping parts may not. */\nexport function isUserFacingPart(part: { readonly type: string }): boolean {\n\treturn !part.type.startsWith(OBSERVATIONAL_MEMORY_PART_PREFIX)\n}\n\n/** The message with only its user-facing parts. */\nexport function toUserFacingMessage<M extends UIMessage>(message: M): M {\n\treturn { ...message, parts: message.parts.filter(isUserFacingPart) }\n}\n\n/**\n * The blocks one message draws: its non-blank texts and its runs of tool\n * parts. Every other part, and every part observational memory adds, draws\n * nothing here; a client draws the data parts it knows itself.\n */\nexport function toMessageBlocks(message: UIMessage): MessageBlock[] {\n\tconst blocks: MessageBlock[] = []\n\n\tfor (const [index, part] of message.parts.entries()) {\n\t\tconst key = `${message.id}:${index}`\n\t\tconst previous = blocks.at(-1)\n\n\t\tif (!isUserFacingPart(part)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif (isTextUIPart(part) && part.text.trim() !== '') {\n\t\t\tblocks.push({\n\t\t\t\tkind: 'text',\n\t\t\t\tkey,\n\t\t\t\ttext: part.text,\n\t\t\t\tstreaming: part.state === 'streaming'\n\t\t\t})\n\t\t} else if (isToolUIPart(part)) {\n\t\t\tif (previous?.kind === 'tools') {\n\t\t\t\tblocks[blocks.length - 1] = {\n\t\t\t\t\t...previous,\n\t\t\t\t\tparts: [...previous.parts, part]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tblocks.push({ kind: 'tools', key, parts: [part] })\n\t\t\t}\n\t\t}\n\t}\n\n\treturn blocks\n}\n\n/**\n * The messages one request sends. Observational memory supplies the thread's\n * history, so a new user turn sends only the user's new message. When the\n * trailing assistant message carries results the client produced (client\n * action results, approval answers), the messages of the current user turn,\n * ending with that message. To resume a suspended run, the trailing assistant\n * message alone: Mastra resumes the run from its snapshot.\n */\nexport function selectRequestMessages(\n\tmessages: readonly UIMessage[],\n\toptions: RequestMessageOptions = {}\n): UIMessage[] {\n\tconst lastMessage = messages.at(-1)\n\n\tif (lastMessage === undefined) {\n\t\treturn []\n\t}\n\n\tswitch (lastMessage.role) {\n\t\tcase 'user':\n\t\t\treturn [lastMessage]\n\t\tcase 'assistant':\n\t\t\tif (\n\t\t\t\tlastMessage.parts.some((part) => readSuspendedRun(part) !== undefined)\n\t\t\t) {\n\t\t\t\treturn [lastMessage]\n\t\t\t}\n\n\t\t\treturn carriesClientResults(lastMessage, options)\n\t\t\t\t? currentUserTurn(messages)\n\t\t\t\t: lastUserMessage(messages)\n\t\tcase 'system':\n\t\t\treturn lastUserMessage(messages)\n\t}\n}\n\n/** From the last user message to the end; the trailing message alone when there is no user message. */\nexport function currentUserTurn(messages: readonly UIMessage[]): UIMessage[] {\n\tconst lastUserIndex = lastIndexOfUser(messages)\n\n\tif (lastUserIndex !== -1) {\n\t\treturn messages.slice(lastUserIndex)\n\t}\n\n\tconst trailing = messages.at(-1)\n\n\treturn trailing === undefined ? [] : [trailing]\n}\n\n/** Which parts an answer resumes after: Mastra stores the continuation as a message of its own. */\nexport type ResumePointOptions = {\n\t/** Default `isToolResultPart`: after any tool's result. */\n\treadonly isResumePoint?: (part: MessagePart) => boolean\n}\n\n/** A tool call with its output or error, the default resume point. */\nexport function isToolResultPart(part: MessagePart): boolean {\n\treturn (\n\t\tisToolUIPart(part) &&\n\t\t(part.state === 'output-available' || part.state === 'output-error')\n\t)\n}\n\n/**\n * Joins an assistant message into the assistant message before it when that\n * one ends at a resume point. Mastra stores the text a run wrote after\n * resuming from a client tool's result as a new message, while the client\n * streamed it into the message that holds the call; joining keeps that\n * message and its id.\n */\nexport function joinResumedAnswers<M extends UIMessage>(\n\tmessages: readonly M[],\n\toptions: ResumePointOptions = {}\n): M[] {\n\tconst isResumePoint = options.isResumePoint ?? isToolResultPart\n\n\treturn messages.reduce<M[]>((joined, message) => {\n\t\tconst previous = joined.at(-1)\n\t\tconst lastPart = previous?.parts.at(-1)\n\t\tconst resumesPrevious =\n\t\t\tmessage.role === 'assistant' &&\n\t\t\tprevious?.role === 'assistant' &&\n\t\t\tlastPart !== undefined &&\n\t\t\tisResumePoint(lastPart)\n\n\t\tif (previous !== undefined && resumesPrevious) {\n\t\t\tjoined[joined.length - 1] = {\n\t\t\t\t...previous,\n\t\t\t\tparts: [...previous.parts, ...message.parts]\n\t\t\t}\n\t\t} else {\n\t\t\tjoined.push(message)\n\t\t}\n\n\t\treturn joined\n\t}, [])\n}\n\n/**\n * The stored messages, oldest first, then the live ones. A message in both\n * shows once, as the live copy, which is the one still changing. An answer\n * resumed after a client action's result shows as one answer (see\n * `joinResumedAnswers`).\n */\nexport function mergeThreadMessages<M extends UIMessage>(\n\tstored: readonly M[],\n\tlive: readonly M[],\n\toptions: ResumePointOptions = {}\n): M[] {\n\tconst liveIds = new Set(live.map((message) => message.id))\n\n\treturn joinResumedAnswers(\n\t\t[...stored.filter((message) => !liveIds.has(message.id)), ...live],\n\t\toptions\n\t)\n}\n\n/**\n * Server tool calls a request left at `input-available`: Mastra drops a\n * server result when a client action shares its step. The session answers\n * them with `STRANDED_TOOL_ERROR`, so the follow-up goes on instead of\n * hanging.\n */\nexport function findStrandedToolCalls(\n\tmessage: UIMessage | undefined,\n\tisClientAction: (toolName: string) => boolean\n): { readonly toolCallId: string; readonly toolName: string }[] {\n\tif (message?.role !== 'assistant') {\n\t\treturn []\n\t}\n\n\tconst suspended = new Set(\n\t\tmessage.parts.flatMap((part) => readSuspendedRun(part)?.toolCallId ?? [])\n\t)\n\n\treturn message.parts.flatMap((part) => {\n\t\tif (\n\t\t\t!isToolUIPart(part) ||\n\t\t\tpart.state !== 'input-available' ||\n\t\t\tpart.providerExecuted === true ||\n\t\t\tsuspended.has(part.toolCallId)\n\t\t) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst toolName = getToolName(part)\n\n\t\treturn isClientAction(toolName)\n\t\t\t? []\n\t\t\t: [{ toolCallId: part.toolCallId, toolName }]\n\t})\n}\n\n/**\n * Whether the newest answer's latest step puts something on screen: answer\n * text, a running tool card, or shown reasoning. A step with only finished\n * tools or hidden reasoning is the model working out of sight, and a\n * \"Thinking…\" indicator has to cover that gap.\n */\nexport function isShowingProgress(\n\tmessages: readonly UIMessage[],\n\toptions: { readonly reasoningVisible?: boolean } = {}\n): boolean {\n\tconst newest = messages.at(-1)\n\n\tif (newest?.role !== 'assistant') {\n\t\treturn false\n\t}\n\n\tfor (let index = newest.parts.length - 1; index >= 0; index -= 1) {\n\t\tconst part = newest.parts[index]\n\n\t\tif (part === undefined || part.type === 'step-start') {\n\t\t\treturn false\n\t\t}\n\n\t\tif (isTextUIPart(part) && part.text.length > 0) {\n\t\t\treturn true\n\t\t}\n\n\t\tif (isToolUIPart(part)) {\n\t\t\treturn (\n\t\t\t\tpart.state === 'input-streaming' || part.state === 'input-available'\n\t\t\t)\n\t\t}\n\n\t\tif (\n\t\t\toptions.reasoningVisible &&\n\t\t\tisReasoningUIPart(part) &&\n\t\t\tpart.state === 'streaming'\n\t\t) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n/**\n * How many parts of an answer are on screen: answer text that is not blank,\n * and every tool part. Reasoning is not shown, and observational memory's\n * parts never are.\n */\nexport function countShownParts(\n\tmessage: UIMessage | undefined,\n\tisUserFacing: (part: MessagePart) => boolean = isUserFacingPart\n): number {\n\tif (message?.role !== 'assistant') {\n\t\treturn 0\n\t}\n\n\treturn message.parts.filter(\n\t\t(part) =>\n\t\t\tisUserFacing(part) &&\n\t\t\t((isTextUIPart(part) && part.text.trim() !== '') || isToolUIPart(part))\n\t).length\n}\n\n/**\n * The replies a reply-suggestions data part carries, trimmed, without empty,\n * too long or repeated ones, at most three; undefined when the data is not a\n * reply list.\n */\n/** The user message a `data-user-message` part carries, or undefined for any other data. */\nexport function readUserMessage(data: unknown): UIMessage | undefined {\n\tconst message = (data as { message?: unknown } | null)?.message as\n\t\t| Partial<UIMessage>\n\t\t| undefined\n\n\treturn typeof message?.id === 'string' &&\n\t\tmessage.role === 'user' &&\n\t\tArray.isArray(message.parts)\n\t\t? (message as UIMessage)\n\t\t: undefined\n}\n\n/**\n * Why the server stopped the answer early, such as `tool_call_budget`\n * (`TOOL_CALL_BUDGET_STOP_REASON`): the `reason` of its tripwire part.\n * Undefined for an answer that ended on its own.\n */\nexport function readStopReason(\n\tmessage: UIMessage | undefined\n): string | undefined {\n\tif (message?.role !== 'assistant') return undefined\n\n\tfor (const part of message.parts) {\n\t\tconst reason =\n\t\t\tpart.type === TRIPWIRE_PART\n\t\t\t\t? (part as { data?: { reason?: unknown } }).data?.reason\n\t\t\t\t: undefined\n\n\t\tif (typeof reason === 'string') return reason\n\t}\n\n\treturn undefined\n}\n\nexport function readReplySuggestions(\n\tdata: unknown\n): readonly string[] | undefined {\n\tconst suggestions = (data as { suggestions?: unknown } | null)?.suggestions\n\n\tif (!Array.isArray(suggestions)) {\n\t\treturn undefined\n\t}\n\n\treturn toReplySuggestions(\n\t\tsuggestions.map((suggestion) =>\n\t\t\ttypeof suggestion === 'string' ? suggestion : undefined\n\t\t)\n\t)\n}\n\n/** The replies worth offering from a model's list, in its order. */\nexport function toReplySuggestions(\n\tsuggestions: readonly (string | undefined)[]\n): readonly string[] {\n\tconst replies: string[] = []\n\n\tfor (const suggestion of suggestions) {\n\t\tconst reply = suggestion?.trim() ?? ''\n\t\tconst isOffered =\n\t\t\treply.length > 0 &&\n\t\t\treply.length <= REPLY_SUGGESTION_MAX_LENGTH &&\n\t\t\t!replies.some((offered) => offered.toLowerCase() === reply.toLowerCase())\n\n\t\tif (isOffered) {\n\t\t\treplies.push(reply)\n\t\t}\n\t}\n\n\treturn replies.slice(0, REPLY_SUGGESTIONS_MAX)\n}\n\nfunction carriesClientResults(\n\tmessage: UIMessage,\n\toptions: RequestMessageOptions\n): boolean {\n\treturn message.parts.some(\n\t\t(part) =>\n\t\t\tisToolUIPart(part) &&\n\t\t\t(part.state === 'approval-responded' ||\n\t\t\t\t((part.state === 'output-available' || part.state === 'output-error') &&\n\t\t\t\t\toptions.isClientResult?.(part) === true))\n\t)\n}\n\nfunction lastUserMessage(messages: readonly UIMessage[]): UIMessage[] {\n\tconst message = messages[lastIndexOfUser(messages)]\n\n\treturn message === undefined ? [] : [message]\n}\n\n/** `findLastIndex`, which the ES2022 build target lacks. */\nfunction lastIndexOfUser(messages: readonly UIMessage[]): number {\n\tfor (let index = messages.length - 1; index >= 0; index -= 1) {\n\t\tif (messages[index]?.role === 'user') {\n\t\t\treturn index\n\t\t}\n\t}\n\n\treturn -1\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The moments an app may have missed part of a running answer, as resume
|
|
3
|
+
* signals for `createChatSession({ resumeOn })`. The React Native ones take
|
|
4
|
+
* `AppState` and NetInfo as arguments, so the client imports neither.
|
|
5
|
+
*/
|
|
6
|
+
import type { ResumeSignal } from './session.js';
|
|
7
|
+
/** The subset of React Native's `AppState` the signal listens to. */
|
|
8
|
+
export interface AppStateLike {
|
|
9
|
+
addEventListener(type: 'change', listener: (state: string) => void): {
|
|
10
|
+
remove(): void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** The subset of `@react-native-community/netinfo` the signal listens to. */
|
|
14
|
+
export interface NetInfoLike {
|
|
15
|
+
addEventListener(listener: (state: {
|
|
16
|
+
readonly isConnected: boolean | null;
|
|
17
|
+
}) => void): () => void;
|
|
18
|
+
}
|
|
19
|
+
/** The browser tab came back into view. */
|
|
20
|
+
export declare const resumeOnVisible: ResumeSignal;
|
|
21
|
+
/** The browser is online again. */
|
|
22
|
+
export declare const resumeOnOnline: ResumeSignal;
|
|
23
|
+
/** The app came back to the foreground. */
|
|
24
|
+
export declare function resumeOnAppActive(appState: AppStateLike): ResumeSignal;
|
|
25
|
+
/** The device has a connection again after losing it; NetInfo's first report is not a regain. */
|
|
26
|
+
export declare function resumeOnNetworkRegain(netInfo: NetInfoLike): ResumeSignal;
|
|
27
|
+
//# sourceMappingURL=resume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/client/resume.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC5B,gBAAgB,CACf,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B;QAAE,MAAM,IAAI,IAAI,CAAA;KAAE,CAAA;CACrB;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC3B,gBAAgB,CACf,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GACjE,MAAM,IAAI,CAAA;CACb;AAeD,2CAA2C;AAC3C,eAAO,MAAM,eAAe,EAAE,YAS7B,CAAA;AAED,mCAAmC;AACnC,eAAO,MAAM,cAAc,EAAE,YAM5B,CAAA;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,YAAY,CAQtE;AAED,iGAAiG;AACjG,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,CAYxE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The moments an app may have missed part of a running answer, as resume
|
|
3
|
+
* signals for `createChatSession({ resumeOn })`. The React Native ones take
|
|
4
|
+
* `AppState` and NetInfo as arguments, so the client imports neither.
|
|
5
|
+
*/
|
|
6
|
+
const browser = () => globalThis;
|
|
7
|
+
/** The browser tab came back into view. */
|
|
8
|
+
export const resumeOnVisible = (resume) => {
|
|
9
|
+
const { document } = browser();
|
|
10
|
+
const listener = () => {
|
|
11
|
+
if (document.visibilityState === 'visible')
|
|
12
|
+
resume();
|
|
13
|
+
};
|
|
14
|
+
document.addEventListener('visibilitychange', listener);
|
|
15
|
+
return () => document.removeEventListener('visibilitychange', listener);
|
|
16
|
+
};
|
|
17
|
+
/** The browser is online again. */
|
|
18
|
+
export const resumeOnOnline = (resume) => {
|
|
19
|
+
const window = browser();
|
|
20
|
+
window.addEventListener('online', resume);
|
|
21
|
+
return () => window.removeEventListener('online', resume);
|
|
22
|
+
};
|
|
23
|
+
/** The app came back to the foreground. */
|
|
24
|
+
export function resumeOnAppActive(appState) {
|
|
25
|
+
return (resume) => {
|
|
26
|
+
const subscription = appState.addEventListener('change', (state) => {
|
|
27
|
+
if (state === 'active')
|
|
28
|
+
resume();
|
|
29
|
+
});
|
|
30
|
+
return () => subscription.remove();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** The device has a connection again after losing it; NetInfo's first report is not a regain. */
|
|
34
|
+
export function resumeOnNetworkRegain(netInfo) {
|
|
35
|
+
return (resume) => {
|
|
36
|
+
let wasConnected;
|
|
37
|
+
return netInfo.addEventListener(({ isConnected }) => {
|
|
38
|
+
if (isConnected === null)
|
|
39
|
+
return;
|
|
40
|
+
if (isConnected && wasConnected === false)
|
|
41
|
+
resume();
|
|
42
|
+
wasConnected = isConnected;
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/client/resume.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA8BH,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,UAAsC,CAAA;AAE5D,2CAA2C;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAiB,CAAC,MAAM,EAAE,EAAE;IACvD,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAA;IAC9B,MAAM,QAAQ,GAAG,GAAG,EAAE;QACrB,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;YAAE,MAAM,EAAE,CAAA;IACrD,CAAC,CAAA;IAED,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAA;IAEvD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAA;AACxE,CAAC,CAAA;AAED,mCAAmC;AACnC,MAAM,CAAC,MAAM,cAAc,GAAiB,CAAC,MAAM,EAAE,EAAE;IACtD,MAAM,MAAM,GAAG,OAAO,EAAE,CAAA;IAExB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAEzC,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AAC1D,CAAC,CAAA;AAED,2CAA2C;AAC3C,MAAM,UAAU,iBAAiB,CAAC,QAAsB;IACvD,OAAO,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,YAAY,GAAG,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAClE,IAAI,KAAK,KAAK,QAAQ;gBAAE,MAAM,EAAE,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAA;IACnC,CAAC,CAAA;AACF,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,qBAAqB,CAAC,OAAoB;IACzD,OAAO,CAAC,MAAM,EAAE,EAAE;QACjB,IAAI,YAAiC,CAAA;QAErC,OAAO,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE;YACnD,IAAI,WAAW,KAAK,IAAI;gBAAE,OAAM;YAEhC,IAAI,WAAW,IAAI,YAAY,KAAK,KAAK;gBAAE,MAAM,EAAE,CAAA;YAEnD,YAAY,GAAG,WAAW,CAAA;QAC3B,CAAC,CAAC,CAAA;IACH,CAAC,CAAA;AACF,CAAC","sourcesContent":["/**\n * The moments an app may have missed part of a running answer, as resume\n * signals for `createChatSession({ resumeOn })`. The React Native ones take\n * `AppState` and NetInfo as arguments, so the client imports neither.\n */\n\nimport type { ResumeSignal } from './session.js'\n\n/** The subset of React Native's `AppState` the signal listens to. */\nexport interface AppStateLike {\n\taddEventListener(\n\t\ttype: 'change',\n\t\tlistener: (state: string) => void\n\t): { remove(): void }\n}\n\n/** The subset of `@react-native-community/netinfo` the signal listens to. */\nexport interface NetInfoLike {\n\taddEventListener(\n\t\tlistener: (state: { readonly isConnected: boolean | null }) => void\n\t): () => void\n}\n\n/** The browser globals the web signals listen on; the client builds without the DOM types. */\ninterface BrowserEvents {\n\treadonly document: {\n\t\treadonly visibilityState: string\n\t\taddEventListener(type: string, listener: () => void): void\n\t\tremoveEventListener(type: string, listener: () => void): void\n\t}\n\taddEventListener(type: string, listener: () => void): void\n\tremoveEventListener(type: string, listener: () => void): void\n}\n\nconst browser = () => globalThis as unknown as BrowserEvents\n\n/** The browser tab came back into view. */\nexport const resumeOnVisible: ResumeSignal = (resume) => {\n\tconst { document } = browser()\n\tconst listener = () => {\n\t\tif (document.visibilityState === 'visible') resume()\n\t}\n\n\tdocument.addEventListener('visibilitychange', listener)\n\n\treturn () => document.removeEventListener('visibilitychange', listener)\n}\n\n/** The browser is online again. */\nexport const resumeOnOnline: ResumeSignal = (resume) => {\n\tconst window = browser()\n\n\twindow.addEventListener('online', resume)\n\n\treturn () => window.removeEventListener('online', resume)\n}\n\n/** The app came back to the foreground. */\nexport function resumeOnAppActive(appState: AppStateLike): ResumeSignal {\n\treturn (resume) => {\n\t\tconst subscription = appState.addEventListener('change', (state) => {\n\t\t\tif (state === 'active') resume()\n\t\t})\n\n\t\treturn () => subscription.remove()\n\t}\n}\n\n/** The device has a connection again after losing it; NetInfo's first report is not a regain. */\nexport function resumeOnNetworkRegain(netInfo: NetInfoLike): ResumeSignal {\n\treturn (resume) => {\n\t\tlet wasConnected: boolean | undefined\n\n\t\treturn netInfo.addEventListener(({ isConnected }) => {\n\t\t\tif (isConnected === null) return\n\n\t\t\tif (isConnected && wasConnected === false) resume()\n\n\t\t\twasConnected = isConnected\n\t\t})\n\t}\n}\n"]}
|
package/dist/client/session.d.ts
CHANGED
|
@@ -113,6 +113,11 @@ export interface ChatSession<TResumeData = unknown> {
|
|
|
113
113
|
}) => boolean;
|
|
114
114
|
readonly stop: () => void;
|
|
115
115
|
readonly tryAgain: () => void;
|
|
116
|
+
/**
|
|
117
|
+
* Writes the newest answer again from the user's message, when no user
|
|
118
|
+
* turn runs or waits; the server replaces the stored answer.
|
|
119
|
+
*/
|
|
120
|
+
readonly regenerate: () => void;
|
|
116
121
|
/** Answers an approval the user turn waits for; any other approval is left alone. */
|
|
117
122
|
readonly answerApproval: (answer: ApprovalAnswer) => void;
|
|
118
123
|
/** Resumes a suspended run the user turn waits for, once. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/client/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACN,KAAK,QAAQ,EAEb,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,MAAM,IAAI,CAAA;AAEX,OAAO,EACN,KAAK,YAAY,EAEjB,KAAK,aAAa,EAGlB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EACN,KAAK,iBAAiB,EAItB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/client/session.ts"],"names":[],"mappings":"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"}
|
package/dist/client/session.js
CHANGED
|
@@ -23,7 +23,7 @@ import { DefaultChatTransport, getToolName, isToolUIPart, lastAssistantMessageIs
|
|
|
23
23
|
import { runClientAction, toClientToolDefs } from './actions.js';
|
|
24
24
|
import { ObservableChat } from './chat.js';
|
|
25
25
|
import { classifyChatError, isConnectionLost, readErrorResponse } from './errors.js';
|
|
26
|
-
import { countShownParts, findStrandedToolCalls, isUserFacingPart, REPLY_SUGGESTIONS_PART, readReplySuggestions, STRANDED_TOOL_ERROR, selectRequestMessages } from './messages.js';
|
|
26
|
+
import { countShownParts, findStrandedToolCalls, isUserFacingPart, REPLY_SUGGESTIONS_PART, readReplySuggestions, readUserMessage, STRANDED_TOOL_ERROR, selectRequestMessages, USER_MESSAGE_PART } from './messages.js';
|
|
27
27
|
import { readWaitingChanges } from './pending.js';
|
|
28
28
|
import { initialChatTurnState, reduceChatTurn } from './turn.js';
|
|
29
29
|
// CONSTANTS
|
|
@@ -68,6 +68,8 @@ export function createChatSession(options) {
|
|
|
68
68
|
let offersReplies = true;
|
|
69
69
|
/** The resume the request in flight sends, read by the transport. */
|
|
70
70
|
let pendingResume;
|
|
71
|
+
/** The messages on screen when the request started; the answer it streams is not among them. */
|
|
72
|
+
let shownBeforeRequest = new Set();
|
|
71
73
|
let requestError;
|
|
72
74
|
let requestEnd;
|
|
73
75
|
const clientActions = () => {
|
|
@@ -109,6 +111,10 @@ export function createChatSession(options) {
|
|
|
109
111
|
},
|
|
110
112
|
onData: (part) => {
|
|
111
113
|
options.onData?.(part);
|
|
114
|
+
if (part.type === USER_MESSAGE_PART) {
|
|
115
|
+
showQuestion(readUserMessage(part.data));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
112
118
|
if (part.type !== REPLY_SUGGESTIONS_PART || !offersReplies) {
|
|
113
119
|
return;
|
|
114
120
|
}
|
|
@@ -205,6 +211,23 @@ export function createChatSession(options) {
|
|
|
205
211
|
}
|
|
206
212
|
effect;
|
|
207
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* A reattached answer's question, when the page on screen was read before
|
|
216
|
+
* the thread stored it: it goes before the answer the stream started.
|
|
217
|
+
*/
|
|
218
|
+
function showQuestion(message) {
|
|
219
|
+
if (message === undefined ||
|
|
220
|
+
chat.messages.some((shown) => shown.id === message.id)) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const messages = [...chat.messages];
|
|
224
|
+
const last = messages.at(-1);
|
|
225
|
+
const answerIndex = last?.role === 'assistant' && !shownBeforeRequest.has(last.id)
|
|
226
|
+
? messages.length - 1
|
|
227
|
+
: messages.length;
|
|
228
|
+
messages.splice(answerIndex, 0, message);
|
|
229
|
+
chat.messages = messages;
|
|
230
|
+
}
|
|
208
231
|
function restoreDraft(text) {
|
|
209
232
|
publish({
|
|
210
233
|
...snapshot,
|
|
@@ -289,6 +312,7 @@ export function createChatSession(options) {
|
|
|
289
312
|
void request().then(() => finishRequest(kind), (error) => finishRequest(kind, toError(error)));
|
|
290
313
|
}
|
|
291
314
|
function resetRequest() {
|
|
315
|
+
shownBeforeRequest = new Set(chat.messages.map((message) => message.id));
|
|
292
316
|
takeReplySuggestions();
|
|
293
317
|
offersReplies = true;
|
|
294
318
|
pendingResume = undefined;
|
|
@@ -488,6 +512,17 @@ export function createChatSession(options) {
|
|
|
488
512
|
dispatch({ kind: 'try-again-pressed' });
|
|
489
513
|
startsOver = false;
|
|
490
514
|
},
|
|
515
|
+
regenerate: () => {
|
|
516
|
+
const { messages } = chat;
|
|
517
|
+
const hasAnswer = messages.at(-1)?.role === 'assistant' &&
|
|
518
|
+
messages.some((message) => message.role === 'user');
|
|
519
|
+
if (!hasAnswer) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
startsOver = true;
|
|
523
|
+
dispatch({ kind: 'regenerate-pressed' });
|
|
524
|
+
startsOver = false;
|
|
525
|
+
},
|
|
491
526
|
answerApproval: ({ approvalId, approved, reason }) => {
|
|
492
527
|
const turn = snapshot.turn;
|
|
493
528
|
const waits = turn.kind === 'waiting' &&
|