veryfront 0.1.198 → 0.1.200

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.
Files changed (46) hide show
  1. package/esm/deno.js +1 -1
  2. package/esm/src/agent/ag-ui-browser-encoder.d.ts.map +1 -1
  3. package/esm/src/agent/ag-ui-browser-encoder.js +97 -34
  4. package/esm/src/agent/react/use-voice-input.js +3 -4
  5. package/esm/src/agent/runtime/chat-stream-handler.d.ts +1 -0
  6. package/esm/src/agent/runtime/chat-stream-handler.d.ts.map +1 -1
  7. package/esm/src/agent/runtime/chat-stream-handler.js +149 -9
  8. package/esm/src/agent/runtime/index.d.ts.map +1 -1
  9. package/esm/src/agent/runtime/index.js +0 -2
  10. package/esm/src/chat/index.d.ts +0 -1
  11. package/esm/src/chat/index.js +0 -1
  12. package/esm/src/markdown/index.d.ts +0 -1
  13. package/esm/src/markdown/index.js +0 -1
  14. package/esm/src/mdx/index.d.ts +0 -1
  15. package/esm/src/mdx/index.js +0 -1
  16. package/esm/src/platform/compat/runtime.js +10 -11
  17. package/esm/src/provider/runtime-loader.d.ts.map +1 -1
  18. package/esm/src/provider/runtime-loader.js +23 -12
  19. package/esm/src/react/components/Head.d.ts +0 -1
  20. package/esm/src/react/components/Head.js +0 -1
  21. package/esm/src/react/components/chat/chat/components/code-block.js +1 -2
  22. package/esm/src/react/components/chat/chat/components/inline-citation.js +2 -3
  23. package/esm/src/react/components/chat/chat/components/message-actions.js +1 -2
  24. package/esm/src/react/components/chat/chat/components/reasoning.js +1 -2
  25. package/esm/src/react/components/chat/chat/hooks/use-threads.js +1 -2
  26. package/esm/src/react/components/chat/markdown.js +2 -2
  27. package/esm/src/react/context/index.d.ts +0 -1
  28. package/esm/src/react/context/index.js +0 -1
  29. package/esm/src/react/fonts/index.d.ts +0 -1
  30. package/esm/src/react/fonts/index.js +0 -1
  31. package/esm/src/react/router/index.d.ts +0 -1
  32. package/esm/src/react/router/index.js +0 -1
  33. package/esm/src/security/client/html-sanitizer.js +1 -2
  34. package/esm/src/server/handlers/dev/framework-candidates.generated.d.ts.map +1 -1
  35. package/esm/src/server/handlers/dev/framework-candidates.generated.js +5 -3
  36. package/esm/src/utils/version-constant.d.ts +1 -1
  37. package/esm/src/utils/version-constant.js +1 -1
  38. package/package.json +1 -1
  39. package/src/deno.js +1 -1
  40. package/src/src/agent/ag-ui-browser-encoder.ts +101 -31
  41. package/src/src/agent/runtime/chat-stream-handler.ts +172 -9
  42. package/src/src/agent/runtime/index.ts +0 -3
  43. package/src/src/provider/runtime-loader.ts +28 -8
  44. package/src/src/react/components/chat/markdown.tsx +2 -2
  45. package/src/src/server/handlers/dev/framework-candidates.generated.ts +5 -3
  46. package/src/src/utils/version-constant.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-loader.d.ts","sourceRoot":"","sources":["../../../src/src/provider/runtime-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AA0oDD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAkDd;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,MAAM,GACd,YAAY,CA4Dd;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAkDd;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CA0ClB;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CAgDlB"}
1
+ {"version":3,"file":"runtime-loader.d.ts","sourceRoot":"","sources":["../../../src/src/provider/runtime-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AA8pDD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAkDd;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,MAAM,GACd,YAAY,CA4Dd;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,CAkDd;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CA0ClB;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,gBAAgB,CAgDlB"}
@@ -258,6 +258,20 @@ function toSnakeCaseRecord(record) {
258
258
  value,
259
259
  ]));
260
260
  }
261
+ function pushAnthropicUserContent(messages, content) {
262
+ if (content.length === 0) {
263
+ return;
264
+ }
265
+ const lastMessage = messages.at(-1);
266
+ if (lastMessage?.role === "user") {
267
+ lastMessage.content.push(...content);
268
+ return;
269
+ }
270
+ messages.push({
271
+ role: "user",
272
+ content,
273
+ });
274
+ }
261
275
  function toAnthropicMessages(prompt) {
262
276
  const systemParts = [];
263
277
  const messages = [];
@@ -269,10 +283,10 @@ function toAnthropicMessages(prompt) {
269
283
  }
270
284
  break;
271
285
  case "user":
272
- messages.push({
273
- role: "user",
274
- content: [{ type: "text", text: readTextParts(message.content) }],
275
- });
286
+ pushAnthropicUserContent(messages, [{
287
+ type: "text",
288
+ text: readTextParts(message.content),
289
+ }]);
276
290
  break;
277
291
  case "assistant":
278
292
  messages.push({
@@ -286,14 +300,11 @@ function toAnthropicMessages(prompt) {
286
300
  });
287
301
  break;
288
302
  case "tool":
289
- messages.push({
290
- role: "user",
291
- content: message.content.map((part) => ({
292
- type: "tool_result",
293
- tool_use_id: part.toolCallId,
294
- content: stringifyJsonValue(part.output.value),
295
- })),
296
- });
303
+ pushAnthropicUserContent(messages, message.content.map((part) => ({
304
+ type: "tool_result",
305
+ tool_use_id: part.toolCallId,
306
+ content: stringifyJsonValue(part.output.value),
307
+ })));
297
308
  break;
298
309
  }
299
310
  }
@@ -7,6 +7,5 @@
7
7
  * import { Head } from "veryfront/head";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { Head } from "../runtime/core.js";
12
11
  //# sourceMappingURL=Head.d.ts.map
@@ -7,5 +7,4 @@
7
7
  * import { Head } from "veryfront/head";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { Head } from "../runtime/core.js";
@@ -1,4 +1,3 @@
1
- import * as dntShim from "../../../../../../_dnt.shims.js";
2
1
  import * as React from "react";
3
2
  import { cn } from "../../theme.js";
4
3
  import { CheckIcon, CopyIcon } from "../../icons/index.js";
@@ -18,7 +17,7 @@ export const RichCodeBlock = React.forwardRef(function RichCodeBlock({ language,
18
17
  document.body.removeChild(textarea);
19
18
  }
20
19
  setCopied(true);
21
- dntShim.setTimeout(() => setCopied(false), 2000);
20
+ globalThis.setTimeout(() => setCopied(false), 2000);
22
21
  }, [code]);
23
22
  if (inline) {
24
23
  return (React.createElement("code", { className: cn("bg-[var(--accent)] px-1.5 py-0.5 rounded text-sm font-mono", className) }, code));
@@ -1,4 +1,3 @@
1
- import * as dntShim from "../../../../../../_dnt.shims.js";
2
1
  import * as React from "react";
3
2
  import { cn } from "../../theme.js";
4
3
  export function InlineCitation({ index, source, className, onClick, }) {
@@ -8,7 +7,7 @@ export function InlineCitation({ index, source, className, onClick, }) {
8
7
  const [cardStyle, setCardStyle] = React.useState({});
9
8
  const show = React.useCallback(() => {
10
9
  clearTimeout(timerRef.current);
11
- timerRef.current = dntShim.setTimeout(() => {
10
+ timerRef.current = globalThis.setTimeout(() => {
12
11
  // Position the card using fixed positioning to prevent overflow clipping
13
12
  const el = buttonRef.current;
14
13
  if (el) {
@@ -25,7 +24,7 @@ export function InlineCitation({ index, source, className, onClick, }) {
25
24
  }, []);
26
25
  const hide = React.useCallback(() => {
27
26
  clearTimeout(timerRef.current);
28
- timerRef.current = dntShim.setTimeout(() => setShowCard(false), 100);
27
+ timerRef.current = globalThis.setTimeout(() => setShowCard(false), 100);
29
28
  }, []);
30
29
  React.useEffect(() => () => clearTimeout(timerRef.current), []);
31
30
  return (React.createElement(React.Fragment, null,
@@ -1,4 +1,3 @@
1
- import * as dntShim from "../../../../../../_dnt.shims.js";
2
1
  import * as React from "react";
3
2
  import { cn } from "../../theme.js";
4
3
  import { CheckIcon, CopyIcon } from "../../icons/index.js";
@@ -7,7 +6,7 @@ export const MessageActions = React.forwardRef(function MessageActions({ content
7
6
  const [copied, setCopied] = React.useState(false);
8
7
  const setCopiedWithTimeout = React.useCallback(() => {
9
8
  setCopied(true);
10
- dntShim.setTimeout(() => setCopied(false), 2000);
9
+ globalThis.setTimeout(() => setCopied(false), 2000);
11
10
  }, []);
12
11
  const fallbackCopy = React.useCallback(() => {
13
12
  const textarea = document.createElement("textarea");
@@ -1,4 +1,3 @@
1
- import * as dntShim from "../../../../../../_dnt.shims.js";
2
1
  import * as React from "react";
3
2
  import { cn } from "../../theme.js";
4
3
  import { Markdown } from "../../markdown.js";
@@ -10,7 +9,7 @@ export const ReasoningCard = React.forwardRef(function ReasoningCard({ text, isS
10
9
  React.useEffect(() => {
11
10
  if (isStreaming || !isOpen || userToggledRef.current)
12
11
  return;
13
- const timer = dntShim.setTimeout(() => setIsOpen(false), 1000);
12
+ const timer = globalThis.setTimeout(() => setIsOpen(false), 1000);
14
13
  return () => clearTimeout(timer);
15
14
  }, [isStreaming, isOpen]);
16
15
  const label = isStreaming ? React.createElement(Shimmer, null, "Thinking...") : React.createElement("span", null, "Thought process");
@@ -1,4 +1,3 @@
1
- import * as dntShim from "../../../../../../_dnt.shims.js";
2
1
  import * as React from "react";
3
2
  import { isBrowserEnvironment } from "../../../../../platform/compat/runtime.js";
4
3
  function generateId() {
@@ -85,7 +84,7 @@ export function useThreads(options) {
85
84
  React.useEffect(() => () => clearTimeout(saveTimerRef.current), []);
86
85
  const persistThreads = React.useCallback((updated) => {
87
86
  clearTimeout(saveTimerRef.current);
88
- saveTimerRef.current = dntShim.setTimeout(() => {
87
+ saveTimerRef.current = globalThis.setTimeout(() => {
89
88
  saveIndex(storageKey, { ids: updated.map((t) => t.id) });
90
89
  for (const thread of updated) {
91
90
  saveThread(storageKey, thread);
@@ -3,12 +3,12 @@ import { cn } from "./theme.js";
3
3
  import { isBrowserEnvironment } from "../../../platform/compat/runtime.js";
4
4
  import { validateTrustedHtml } from "../../../security/client/html-sanitizer.js";
5
5
  import { RichCodeBlock } from "./chat/components/code-block.js";
6
- const ESM_REACT_MARKDOWN = "https://esm.sh/react-markdown@9.0.3?external=react&target=es2022&pin=v135";
6
+ const ESM_REACT_MARKDOWN = "https://esm.sh/react-markdown@9.0.3?target=es2022&pin=v135&deps=react@19.2.4";
7
7
  const ESM_REMARK_GFM = "https://esm.sh/remark-gfm@4.0.1?target=es2022&pin=v135";
8
8
  const ESM_REHYPE_HIGHLIGHT = "https://esm.sh/rehype-highlight@7.0.2?target=es2022&pin=v135";
9
9
  const ESM_MERMAID = "https://esm.sh/mermaid@11.4.1?pin=v135";
10
10
  async function importFromUrl(url) {
11
- return await import(url);
11
+ return await import(/* @vite-ignore */ url);
12
12
  }
13
13
  // deno-lint-ignore no-explicit-any
14
14
  let ReactMarkdown = null;
@@ -7,7 +7,6 @@
7
7
  * import { PageContextProvider, usePageContext } from "veryfront/context";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { PageContextProvider, usePageContext } from "../runtime/core.js";
12
11
  export type { MdxHeading, PageContextProviderProps, PageContextValue } from "../runtime/core.js";
13
12
  //# sourceMappingURL=index.d.ts.map
@@ -7,5 +7,4 @@
7
7
  * import { PageContextProvider, usePageContext } from "veryfront/context";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { PageContextProvider, usePageContext } from "../runtime/core.js";
@@ -15,7 +15,6 @@
15
15
  * />
16
16
  * ```
17
17
  */
18
- import "../../../_dnt.polyfills.js";
19
18
  import React from "react";
20
19
  export interface Font {
21
20
  name: string;
@@ -15,7 +15,6 @@
15
15
  * />
16
16
  * ```
17
17
  */
18
- import "../../../_dnt.polyfills.js";
19
18
  import React from "react";
20
19
  import { Head } from "../components/Head.js";
21
20
  function sortMixedArray(arr) {
@@ -7,7 +7,6 @@
7
7
  * import { Link, RouterProvider, useRouter } from "veryfront/router";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { Link, Router, RouterProvider, useRouter } from "../runtime/core.js";
12
11
  export type { LinkProps, RouterProviderProps, RouterValue } from "../runtime/core.js";
13
12
  //# sourceMappingURL=index.d.ts.map
@@ -7,5 +7,4 @@
7
7
  * import { Link, RouterProvider, useRouter } from "veryfront/router";
8
8
  * ```
9
9
  */
10
- import "../../../_dnt.polyfills.js";
11
10
  export { Link, Router, RouterProvider, useRouter } from "../runtime/core.js";
@@ -6,7 +6,6 @@
6
6
  * - Error messages and debug info are untrusted and must be escaped
7
7
  * - validateTrustedHtml() provides defense-in-depth for server HTML
8
8
  */
9
- import * as dntShim from "../../../_dnt.shims.js";
10
9
  import { escapeHtml } from "../../html/html-escape.js";
11
10
  import { SECURITY_VIOLATION } from "../../errors/error-registry.js";
12
11
  export { escapeHtml };
@@ -21,7 +20,7 @@ const SUSPICIOUS_PATTERNS = [
21
20
  { pattern: /data:\s*text\/html/gi, name: "data: HTML URL" },
22
21
  ];
23
22
  function isDevMode() {
24
- const g = dntShim.dntGlobalThis;
23
+ const g = globalThis;
25
24
  return g.__VERYFRONT_DEV__ === true || g.Deno?.env?.get?.("VERYFRONT_ENV") === "development";
26
25
  }
27
26
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"framework-candidates.generated.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/framework-candidates.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAixKjD,CAAC"}
1
+ {"version":3,"file":"framework-candidates.generated.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/dev/framework-candidates.generated.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAmxKjD,CAAC"}
@@ -528,6 +528,7 @@ export const FRAMEWORK_CANDIDATES = [
528
528
  "@internal",
529
529
  "@media(prefers-color-scheme:dark){[data-vf-chat]:not([data-vf-theme]){${dark}}}",
530
530
  "@module",
531
+ "@vite-ignore",
531
532
  "A",
532
533
  "ACTION_BUTTON",
533
534
  "AI",
@@ -2601,6 +2602,7 @@ export const FRAMEWORK_CANDIDATES = [
2601
2602
  "deno-lint-ignore",
2602
2603
  "dependency)",
2603
2604
  "deprecated,",
2605
+ "deps=react@19.2.4",
2604
2606
  "desc",
2605
2607
  "descendant",
2606
2608
  "describe(",
@@ -3142,7 +3144,7 @@ export const FRAMEWORK_CANDIDATES = [
3142
3144
  "html><html><head><style",
3143
3145
  "https://ai-sdk.dev/elements)",
3144
3146
  "https://esm.sh/mermaid@11.4.1?pin=v135",
3145
- "https://esm.sh/react-markdown@9.0.3?external=react",
3147
+ "https://esm.sh/react-markdown@9.0.3?target=es2022",
3146
3148
  "https://esm.sh/rehype-highlight@7.0.2?target=es2022",
3147
3149
  "https://esm.sh/remark-gfm@4.0.1?target=es2022",
3148
3150
  "https://example.com/",
@@ -3189,7 +3191,7 @@ export const FRAMEWORK_CANDIDATES = [
3189
3191
  "if",
3190
3192
  "ignores",
3191
3193
  "import",
3192
- "import(url)",
3194
+ "import(/*",
3193
3195
  "importFromUrl<DefaultModule<unknown>>(ESM_REACT_MARKDOWN),",
3194
3196
  "importFromUrl<DefaultModule<unknown>>(ESM_REHYPE_HIGHLIGHT),",
3195
3197
  "importFromUrl<DefaultModule<unknown>>(ESM_REMARK_GFM),",
@@ -4882,7 +4884,6 @@ export const FRAMEWORK_CANDIDATES = [
4882
4884
  "take",
4883
4885
  "target",
4884
4886
  "target=",
4885
- "target=es2022",
4886
4887
  "tbody>",
4887
4888
  "tc1",
4888
4889
  "td",
@@ -5205,6 +5206,7 @@ export const FRAMEWORK_CANDIDATES = [
5205
5206
  "upward",
5206
5207
  "url",
5207
5208
  "url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600",
5209
+ "url)",
5208
5210
  "url:",
5209
5211
  "url;",
5210
5212
  "url?:",
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.198";
1
+ export declare const VERSION = "0.1.200";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.198";
3
+ export const VERSION = "0.1.200";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.198",
3
+ "version": "0.1.200",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.198",
3
+ "version": "0.1.200",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -234,6 +234,28 @@ function createTextEvent(
234
234
  };
235
235
  }
236
236
 
237
+ function closeOpenTextEvent(state: AgUiBrowserEncoderState): AgUiBrowserEncodedEvent[] {
238
+ if (!state.textOpen) {
239
+ return [];
240
+ }
241
+
242
+ state.textOpen = false;
243
+ return [createTextEvent(getMessageId(state, { type: "text-end" }), "TextMessageEnd")];
244
+ }
245
+
246
+ function closeOpenReasoningEvent(state: AgUiBrowserEncoderState): AgUiBrowserEncodedEvent[] {
247
+ if (state.reasoningMessageId === null) {
248
+ return [];
249
+ }
250
+
251
+ const messageId = state.reasoningMessageId;
252
+ state.reasoningMessageId = null;
253
+ return [{
254
+ event: "ReasoningMessageEnd",
255
+ payload: { messageId },
256
+ }];
257
+ }
258
+
237
259
  export function mapRuntimeStreamEventToAgUiBrowserEvents(
238
260
  state: AgUiBrowserEncoderState,
239
261
  event: AgUiRuntimeStreamEvent,
@@ -254,33 +276,38 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
254
276
  return [];
255
277
 
256
278
  case "text-start": {
279
+ const events = closeOpenReasoningEvent(state);
257
280
  if (state.textOpen) return [];
258
281
  const messageId = getMessageId(state, event);
259
282
  state.textOpen = true;
260
283
  state.sawVisibleOutput = true;
261
- return [createTextEvent(messageId, "TextMessageStart")];
284
+ events.push(createTextEvent(messageId, "TextMessageStart"));
285
+ return events;
262
286
  }
263
287
 
264
288
  case "text-delta": {
289
+ const events = closeOpenReasoningEvent(state);
265
290
  const messageId = getMessageId(state, event);
266
291
  state.sawVisibleOutput = true;
267
292
  if (!state.textOpen) {
268
293
  state.textOpen = true;
269
- return [
294
+ events.push(
270
295
  createTextEvent(messageId, "TextMessageStart"),
271
296
  createTextEvent(
272
297
  messageId,
273
298
  "TextMessageContent",
274
299
  typeof event.delta === "string" ? event.delta : "",
275
300
  ),
276
- ];
301
+ );
302
+ return events;
277
303
  }
278
304
 
279
- return [createTextEvent(
305
+ events.push(createTextEvent(
280
306
  messageId,
281
307
  "TextMessageContent",
282
308
  typeof event.delta === "string" ? event.delta : "",
283
- )];
309
+ ));
310
+ return events;
284
311
  }
285
312
 
286
313
  case "text-end": {
@@ -289,13 +316,23 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
289
316
  return [createTextEvent(getMessageId(state, event), "TextMessageEnd")];
290
317
  }
291
318
 
292
- case "reasoning-start":
319
+ case "reasoning-start": {
320
+ const events = closeOpenTextEvent(state);
321
+ events.push(...closeOpenReasoningEvent(state));
293
322
  state.sawVisibleOutput = true;
294
- return [createReasoningEvent(state, event, "ReasoningMessageStart")];
323
+ events.push(createReasoningEvent(state, event, "ReasoningMessageStart"));
324
+ return events;
325
+ }
295
326
 
296
- case "reasoning-delta":
327
+ case "reasoning-delta": {
328
+ const events = closeOpenTextEvent(state);
297
329
  state.sawVisibleOutput = true;
298
- return [createReasoningEvent(state, event, "ReasoningMessageContent")];
330
+ if (state.reasoningMessageId === null) {
331
+ events.push(createReasoningEvent(state, event, "ReasoningMessageStart"));
332
+ }
333
+ events.push(createReasoningEvent(state, event, "ReasoningMessageContent"));
334
+ return events;
335
+ }
299
336
 
300
337
  case "reasoning-end": {
301
338
  const reasoningEvent = createReasoningEvent(state, event, "ReasoningMessageEnd");
@@ -303,15 +340,21 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
303
340
  return [reasoningEvent];
304
341
  }
305
342
 
306
- case "tool-input-start":
343
+ case "tool-input-start": {
344
+ const events = [
345
+ ...closeOpenTextEvent(state),
346
+ ...closeOpenReasoningEvent(state),
347
+ ];
307
348
  state.sawVisibleOutput = true;
308
- return [{
349
+ events.push({
309
350
  event: "ToolCallStart",
310
351
  payload: {
311
352
  toolCallId: event.toolCallId,
312
353
  toolCallName: event.toolName,
313
354
  },
314
- }];
355
+ });
356
+ return events;
357
+ }
315
358
 
316
359
  case "tool-input-delta":
317
360
  state.sawVisibleOutput = true;
@@ -328,12 +371,20 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
328
371
 
329
372
  case "tool-input-available": {
330
373
  state.sawVisibleOutput = true;
331
- return completeToolInput(state, event);
374
+ return [
375
+ ...closeOpenTextEvent(state),
376
+ ...closeOpenReasoningEvent(state),
377
+ ...completeToolInput(state, event),
378
+ ];
332
379
  }
333
380
 
334
381
  case "tool-input-error": {
335
382
  state.sawVisibleOutput = true;
336
- const events = completeToolInput(state, event);
383
+ const events = [
384
+ ...closeOpenTextEvent(state),
385
+ ...closeOpenReasoningEvent(state),
386
+ ...completeToolInput(state, event),
387
+ ];
337
388
  events.push({
338
389
  event: "ToolCallResult",
339
390
  payload: {
@@ -349,25 +400,45 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
349
400
 
350
401
  case "tool-output-available":
351
402
  state.sawVisibleOutput = true;
352
- return [createToolResultEvent(event.toolCallId, event.output)];
403
+ return [
404
+ ...closeOpenTextEvent(state),
405
+ ...closeOpenReasoningEvent(state),
406
+ createToolResultEvent(event.toolCallId, event.output),
407
+ ];
353
408
 
354
409
  case "tool-output-error":
355
410
  state.sawVisibleOutput = true;
356
- return [createToolResultEvent(event.toolCallId, { error: event.errorText }, true)];
411
+ return [
412
+ ...closeOpenTextEvent(state),
413
+ ...closeOpenReasoningEvent(state),
414
+ createToolResultEvent(event.toolCallId, { error: event.errorText }, true),
415
+ ];
357
416
 
358
417
  case "tool-output-denied":
359
418
  state.sawVisibleOutput = true;
360
- return [createToolResultEvent(event.toolCallId, { error: "Tool output denied" }, true)];
419
+ return [
420
+ ...closeOpenTextEvent(state),
421
+ ...closeOpenReasoningEvent(state),
422
+ createToolResultEvent(event.toolCallId, { error: "Tool output denied" }, true),
423
+ ];
361
424
 
362
425
  case "step-start":
363
426
  case "start-step":
364
427
  state.sawVisibleOutput = true;
365
- return [createStepEvent(state, "StepStarted")];
428
+ return [
429
+ ...closeOpenTextEvent(state),
430
+ ...closeOpenReasoningEvent(state),
431
+ createStepEvent(state, "StepStarted"),
432
+ ];
366
433
 
367
434
  case "step-end":
368
435
  case "finish-step":
369
436
  state.sawVisibleOutput = true;
370
- return [createStepEvent(state, "StepFinished")];
437
+ return [
438
+ ...closeOpenTextEvent(state),
439
+ ...closeOpenReasoningEvent(state),
440
+ createStepEvent(state, "StepFinished"),
441
+ ];
371
442
 
372
443
  case "data":
373
444
  applyDataMetadata(state, event);
@@ -375,12 +446,16 @@ export function mapRuntimeStreamEventToAgUiBrowserEvents(
375
446
 
376
447
  case "error":
377
448
  state.sawTerminalError = true;
378
- return [{
379
- event: "RunError",
380
- payload: {
381
- message: typeof event.error === "string" ? event.error : "Agent run failed",
449
+ return [
450
+ ...closeOpenTextEvent(state),
451
+ ...closeOpenReasoningEvent(state),
452
+ {
453
+ event: "RunError",
454
+ payload: {
455
+ message: typeof event.error === "string" ? event.error : "Agent run failed",
456
+ },
382
457
  },
383
- }];
458
+ ];
384
459
 
385
460
  default:
386
461
  return [];
@@ -409,13 +484,8 @@ export function finalizeAgUiBrowserEvents(
409
484
  }
410
485
 
411
486
  const events: AgUiBrowserEncodedEvent[] = [];
412
- if (state.textOpen) {
413
- state.textOpen = false;
414
- events.push({
415
- event: "TextMessageEnd",
416
- payload: { messageId: getMessageId(state, { type: "text-end" }) },
417
- });
418
- }
487
+ events.push(...closeOpenTextEvent(state));
488
+ events.push(...closeOpenReasoningEvent(state));
419
489
 
420
490
  events.push({
421
491
  event: "RunFinished",