@agent-native/core 0.84.34 → 0.84.36
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/README.md +15 -51
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +20 -0
- package/corpus/core/docs/content/actions.mdx +17 -24
- package/corpus/core/docs/content/agent-surfaces.mdx +59 -56
- package/corpus/core/docs/content/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/faq.mdx +4 -4
- package/corpus/core/docs/content/getting-started.mdx +246 -204
- package/corpus/core/docs/content/key-concepts.mdx +9 -9
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/ar-SA/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/ar-SA/getting-started.mdx +148 -214
- package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/ar-SA/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/de-DE/getting-started.mdx +145 -211
- package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/de-DE/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/es-ES/getting-started.mdx +148 -214
- package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/es-ES/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/fr-FR/getting-started.mdx +146 -212
- package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/fr-FR/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/hi-IN/getting-started.mdx +149 -215
- package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +8 -13
- package/corpus/core/docs/content/locales/hi-IN/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/ja-JP/getting-started.mdx +144 -210
- package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +8 -13
- package/corpus/core/docs/content/locales/ja-JP/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/ko-KR/getting-started.mdx +146 -212
- package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +8 -13
- package/corpus/core/docs/content/locales/ko-KR/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/pt-BR/getting-started.mdx +145 -211
- package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/pt-BR/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/zh-CN/getting-started.mdx +158 -209
- package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/zh-CN/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/faq.mdx +4 -4
- package/corpus/core/docs/content/locales/zh-TW/getting-started.mdx +158 -212
- package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -9
- package/corpus/core/docs/content/locales/zh-TW/template-chat.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/native-chat-ui.mdx +17 -32
- package/corpus/core/docs/content/pure-agent-apps.mdx +46 -26
- package/corpus/core/docs/content/template-chat.mdx +8 -8
- package/corpus/core/docs/content/using-your-agent.mdx +2 -2
- package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/response-text.ts +10 -1
- package/corpus/core/src/agent/production-agent.ts +23 -20
- package/corpus/core/src/agent/run-manager.ts +46 -1
- package/corpus/core/src/agent/thread-data-builder.ts +15 -2
- package/corpus/core/src/cli/skills.ts +7 -9
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +2 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +172 -18
- package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +57 -9
- package/corpus/core/src/client/blocks/library/wireframe.tsx +3 -18
- package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +28 -32
- package/corpus/core/src/client/code-agent-chat-adapter.ts +8 -1
- package/corpus/core/src/client/sse-event-processor.ts +21 -3
- package/corpus/core/src/code-agents/transcript-normalizer.ts +31 -0
- package/corpus/core/src/db/schema.ts +5 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +8 -2
- package/corpus/core/src/server/agent-teams.ts +24 -2
- package/corpus/core/src/styles/blocks.css +27 -6
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -4
- package/corpus/templates/analytics/changelog/2026-07-01-smoother-chat-streaming.md +6 -0
- package/corpus/templates/content/actions/list-trashed-content-databases.ts +1 -1
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -9
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -9
- package/dist/a2a/response-text.d.ts +1 -0
- package/dist/a2a/response-text.d.ts.map +1 -1
- package/dist/a2a/response-text.js +8 -2
- package/dist/a2a/response-text.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +31 -27
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +12 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +32 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +15 -2
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/skills.d.ts +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +7 -9
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts +13 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +123 -16
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +6 -6
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.js +52 -5
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.js +1 -11
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.js +27 -31
- package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +5 -1
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +21 -3
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +24 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/db/schema.d.ts +2 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +3 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +2 -3
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +17 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/blocks.css +27 -6
- package/docs/content/actions.mdx +17 -24
- package/docs/content/agent-surfaces.mdx +59 -56
- package/docs/content/cloneable-saas.mdx +3 -3
- package/docs/content/faq.mdx +4 -4
- package/docs/content/getting-started.mdx +246 -204
- package/docs/content/key-concepts.mdx +9 -9
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +3 -3
- package/docs/content/locales/ar-SA/faq.mdx +4 -4
- package/docs/content/locales/ar-SA/getting-started.mdx +148 -214
- package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/ar-SA/template-chat.mdx +2 -2
- package/docs/content/locales/ar-SA/using-your-agent.mdx +2 -2
- package/docs/content/locales/de-DE/cloneable-saas.mdx +3 -3
- package/docs/content/locales/de-DE/faq.mdx +4 -4
- package/docs/content/locales/de-DE/getting-started.mdx +145 -211
- package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/de-DE/template-chat.mdx +2 -2
- package/docs/content/locales/de-DE/using-your-agent.mdx +2 -2
- package/docs/content/locales/es-ES/cloneable-saas.mdx +3 -3
- package/docs/content/locales/es-ES/faq.mdx +4 -4
- package/docs/content/locales/es-ES/getting-started.mdx +148 -214
- package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/es-ES/template-chat.mdx +2 -2
- package/docs/content/locales/es-ES/using-your-agent.mdx +2 -2
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/fr-FR/faq.mdx +4 -4
- package/docs/content/locales/fr-FR/getting-started.mdx +146 -212
- package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/fr-FR/template-chat.mdx +2 -2
- package/docs/content/locales/fr-FR/using-your-agent.mdx +2 -2
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +3 -3
- package/docs/content/locales/hi-IN/faq.mdx +4 -4
- package/docs/content/locales/hi-IN/getting-started.mdx +149 -215
- package/docs/content/locales/hi-IN/pure-agent-apps.mdx +8 -13
- package/docs/content/locales/hi-IN/template-chat.mdx +2 -2
- package/docs/content/locales/hi-IN/using-your-agent.mdx +2 -2
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ja-JP/faq.mdx +4 -4
- package/docs/content/locales/ja-JP/getting-started.mdx +144 -210
- package/docs/content/locales/ja-JP/pure-agent-apps.mdx +8 -13
- package/docs/content/locales/ja-JP/template-chat.mdx +2 -2
- package/docs/content/locales/ja-JP/using-your-agent.mdx +2 -2
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +3 -3
- package/docs/content/locales/ko-KR/faq.mdx +4 -4
- package/docs/content/locales/ko-KR/getting-started.mdx +146 -212
- package/docs/content/locales/ko-KR/pure-agent-apps.mdx +8 -13
- package/docs/content/locales/ko-KR/template-chat.mdx +2 -2
- package/docs/content/locales/ko-KR/using-your-agent.mdx +2 -2
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +3 -3
- package/docs/content/locales/pt-BR/faq.mdx +4 -4
- package/docs/content/locales/pt-BR/getting-started.mdx +145 -211
- package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/pt-BR/template-chat.mdx +2 -2
- package/docs/content/locales/pt-BR/using-your-agent.mdx +2 -2
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +3 -3
- package/docs/content/locales/zh-CN/faq.mdx +4 -4
- package/docs/content/locales/zh-CN/getting-started.mdx +158 -209
- package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/zh-CN/template-chat.mdx +2 -2
- package/docs/content/locales/zh-CN/using-your-agent.mdx +2 -2
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +3 -3
- package/docs/content/locales/zh-TW/faq.mdx +4 -4
- package/docs/content/locales/zh-TW/getting-started.mdx +158 -212
- package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -9
- package/docs/content/locales/zh-TW/template-chat.mdx +2 -2
- package/docs/content/locales/zh-TW/using-your-agent.mdx +2 -2
- package/docs/content/native-chat-ui.mdx +17 -32
- package/docs/content/pure-agent-apps.mdx +46 -26
- package/docs/content/template-chat.mdx +8 -8
- package/docs/content/using-your-agent.mdx +2 -2
- package/docs/content/what-is-agent-native.mdx +6 -6
- package/package.json +1 -1
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
description: "
|
|
2
|
+
title: "Automation-First Apps"
|
|
3
|
+
description: "No-browser Agent-Native apps for scheduled jobs, queues, scripts, integration workers, and external agents."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Automation-First Apps
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
scheduled
|
|
11
|
-
|
|
12
|
-
belongs. It is still a real app: actions, sessions, app state, history,
|
|
13
|
-
settings, credentials, and share records all live in SQL.
|
|
8
|
+
Most Agent-Native products should start with chat and grow into inline results
|
|
9
|
+
and durable app pages. Use this pattern when the primary surface is not a
|
|
10
|
+
browser UI yet: scheduled reports, queues, integration workers, CLI loops, or
|
|
11
|
+
another app or agent calling this app over MCP/A2A.
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Automation-first does **not** mean stateless. The app-agent loop still uses the
|
|
14
|
+
same Agent-Native contract: actions, sessions, app state, history, settings,
|
|
15
|
+
credentials, and share records live in SQL.
|
|
16
|
+
|
|
17
|
+
<Diagram id="doc-block-automation-first" title="Automation-first still uses the app contract" summary={"Jobs, scripts, channels, and external agents reach one Agent-Native loop over SQL-backed actions and state."}>
|
|
16
18
|
|
|
17
19
|
```html
|
|
18
20
|
<div class="diagram-pure">
|
|
19
21
|
<div class="diagram-col">
|
|
20
|
-
<div class="diagram-pill">Terminal</div>
|
|
21
|
-
<div class="diagram-pill">Slack · email</div>
|
|
22
22
|
<div class="diagram-pill">Scheduled job</div>
|
|
23
|
+
<div class="diagram-pill">Queue worker</div>
|
|
24
|
+
<div class="diagram-pill">CLI script</div>
|
|
25
|
+
<div class="diagram-pill">Slack · email</div>
|
|
23
26
|
<div class="diagram-pill">Another agent (A2A)</div>
|
|
24
|
-
<div class="diagram-pill">Chat</div>
|
|
25
27
|
</div>
|
|
26
28
|
<div class="diagram-arrow diagram-muted" aria-hidden="true">→</div>
|
|
27
29
|
<div class="diagram-panel center" data-rough>
|
|
@@ -30,7 +32,9 @@ settings, credentials, and share records all live in SQL.
|
|
|
30
32
|
</div>
|
|
31
33
|
<div class="diagram-arrow diagram-muted" aria-hidden="true">→</div>
|
|
32
34
|
<div class="diagram-box" data-rough>
|
|
33
|
-
Result returns<br /><small class="diagram-muted"
|
|
35
|
+
Result returns<br /><small class="diagram-muted"
|
|
36
|
+
>to the channel that asked</small
|
|
37
|
+
>
|
|
34
38
|
</div>
|
|
35
39
|
</div>
|
|
36
40
|
```
|
|
@@ -62,20 +66,36 @@ settings, credentials, and share records all live in SQL.
|
|
|
62
66
|
</Diagram>
|
|
63
67
|
|
|
64
68
|
Reach for this shape when the work runs in the background, the output leaves the
|
|
65
|
-
app, the domain is one-shot, or you
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
app, the domain is one-shot, or you are building a callable workflow for another
|
|
70
|
+
system. If users need to inspect, compare, correct, or share persistent objects,
|
|
71
|
+
start with [Chat](/docs/template-chat) or add a small app page around the same
|
|
72
|
+
actions.
|
|
73
|
+
|
|
74
|
+
## Scaffold {#scaffold}
|
|
75
|
+
|
|
76
|
+
Use the no-browser scaffold when you know you do not want a browser UI yet:
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
```bash
|
|
79
|
+
npx @agent-native/core@latest create my-agent --headless
|
|
80
|
+
cd my-agent
|
|
81
|
+
pnpm install
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then add actions and instructions exactly as you would in a chat app:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pnpm agent "Run the daily response-insights report and post the summary."
|
|
88
|
+
```
|
|
71
89
|
|
|
72
|
-
|
|
90
|
+
The `--headless` flag only chooses the initial scaffold. It does not choose a
|
|
91
|
+
different architecture. You can later move the same `actions/`, instructions,
|
|
92
|
+
skills, and SQL state into a chat app or full application surface.
|
|
73
93
|
|
|
74
|
-
## What
|
|
94
|
+
## What to add next {#whats-next}
|
|
75
95
|
|
|
76
|
-
- [**
|
|
77
|
-
- [**
|
|
78
|
-
- [**
|
|
79
|
-
- [**Messaging the agent**](/docs/messaging) — how users talk to the agent across web, Slack, Telegram, email
|
|
96
|
+
- [**Getting Started**](/docs/getting-started) — the chat-first tutorial from action to inline result to durable page
|
|
97
|
+
- [**Agent Surfaces — Automation-first app**](/docs/agent-surfaces#headless) — the full decision guide and APIs
|
|
98
|
+
- [**Actions**](/docs/actions) — the operations your automation calls
|
|
99
|
+
- [**Messaging the agent**](/docs/messaging) — how users talk to the agent across web, Slack, Telegram, and email
|
|
80
100
|
- [**Recurring Jobs**](/docs/recurring-jobs) — scheduled prompts the agent runs on its own
|
|
81
|
-
- [**
|
|
101
|
+
- [**Dispatch**](/docs/template-dispatch) — the workspace control plane for shared secrets, scheduled jobs, and delegated work
|
|
@@ -5,9 +5,9 @@ description: "A minimal chat-first agent-native app: durable chat threads, actio
|
|
|
5
5
|
|
|
6
6
|
# Chat Template
|
|
7
7
|
|
|
8
|
-
Chat is the basic
|
|
8
|
+
Chat is the basic agentic app starting point. It gives you a clean ChatGPT-style shell with chat at the center, a threads list on the left, standard app navigation, auth, live sync, actions, and one example action. Start here when you want a real browser app you can build on before committing to a domain template.
|
|
9
9
|
|
|
10
|
-
If you want
|
|
10
|
+
If you want a finished domain product shape, start from [Calendar](/docs/template-calendar), [Mail](/docs/template-mail), [Content](/docs/template-content), [Forms](/docs/template-forms), [Analytics](/docs/template-analytics), or another domain template. If you truly do not need a browser UI yet, see [Automation-First Apps](/docs/pure-agent-apps).
|
|
11
11
|
|
|
12
12
|
<WireframeBlock id="doc-block-1qu69ww">
|
|
13
13
|
<Screen
|
|
@@ -104,7 +104,7 @@ That's the point. Chat is a thin, useful default shell for your own agent, not a
|
|
|
104
104
|
## When to pick it {#when-to-pick}
|
|
105
105
|
|
|
106
106
|
- **You want a basic app users can talk to immediately** and then extend with actions and UI.
|
|
107
|
-
- **You
|
|
107
|
+
- **You want the default Agent-Native on-ramp**: chat first, then actions, native results, and app pages.
|
|
108
108
|
- **You want to plug your own agent backend into a familiar chat UI** while keeping Agent-Native's actions, state, auth, and deployment shape.
|
|
109
109
|
- **You are prototyping a custom internal tool** that does not match a domain template.
|
|
110
110
|
|
|
@@ -117,13 +117,13 @@ pnpm install
|
|
|
117
117
|
pnpm dev
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
The no-browser scaffold is still available for automation-first work, but it is not the main Chat template path:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
npx @agent-native/core@latest create my-agent --headless
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
Use it for scheduled jobs, queues, CLI loops, or external-agent workflows where chat and app pages are not useful yet. The key invariant stays the same: actions are the shared surface for chat, UI, HTTP, MCP, A2A, and CLI.
|
|
127
127
|
|
|
128
128
|
## First code to inspect {#first-code}
|
|
129
129
|
|
|
@@ -196,8 +196,8 @@ The agent should add a Drizzle schema, actions, route, navigation, and instructi
|
|
|
196
196
|
|
|
197
197
|
## What's next
|
|
198
198
|
|
|
199
|
-
- [**Getting Started**](/docs) —
|
|
200
|
-
- [**Agent Surfaces**](/docs/agent-surfaces) —
|
|
199
|
+
- [**Getting Started**](/docs) — build the chat-first path from action to inline result to app page
|
|
200
|
+
- [**Agent Surfaces**](/docs/agent-surfaces) — chat, inline UI, app pages, embedded, automation, and external-agent patterns
|
|
201
201
|
- [**Actions**](/docs/actions) — the action system chat and UI both call
|
|
202
202
|
- [**Native Chat UI**](/docs/native-chat-ui) — chat surface primitives and runtime options
|
|
203
|
-
- [**
|
|
203
|
+
- [**Automation-First Apps**](/docs/pure-agent-apps) — no-browser workflows for jobs, queues, scripts, and external agents
|
|
@@ -99,7 +99,7 @@ The agent isn't a separate app you tab over to. It ships as a handful of React c
|
|
|
99
99
|
|
|
100
100
|
Not every app needs a full dashboard. When the agent _is_ the product, you can skip most of the custom UI: open the app, ask for what you want, and let the agent do the rest. The agent still has its management surface — history, workspace, settings — but the primary interaction is conversation rather than clicks.
|
|
101
101
|
|
|
102
|
-
→ [**
|
|
102
|
+
→ [**Automation-First Apps**](/docs/pure-agent-apps) — no-browser apps for jobs, queues, scripts, and external agents.
|
|
103
103
|
|
|
104
104
|
## You co-edit with it {#you-co-edit}
|
|
105
105
|
|
|
@@ -113,5 +113,5 @@ When you and the agent are working on the same document, you don't take turns. W
|
|
|
113
113
|
- [**Agent Mentions**](/docs/agent-mentions) — direct it with `@`-mentions
|
|
114
114
|
- [**Voice Input**](/docs/voice-input) — direct it by speaking
|
|
115
115
|
- [**Drop-in Agent**](/docs/drop-in-agent) — embed it in any React app
|
|
116
|
-
- [**
|
|
116
|
+
- [**Automation-First Apps**](/docs/pure-agent-apps) — use no-browser apps for jobs, queues, scripts, and external agents
|
|
117
117
|
- [**Real-Time Collaboration**](/docs/real-time-collaboration) — co-edit the same document together
|
|
@@ -5,13 +5,13 @@ description: "Why most AI apps feel half-built, what makes an app truly agent-na
|
|
|
5
5
|
|
|
6
6
|
# What Is Agent-Native?
|
|
7
7
|
|
|
8
|
-
Agent-native is a way of building software where the AI agent and the product surface around it are **equal partners**.
|
|
8
|
+
Agent-native is a way of building software where the AI agent and the product surface around it are **equal partners**. The usual path starts with chat, adds typed actions, renders structured results inline, and grows into durable app pages around the same SQL state. The important part is that agents and humans share the same actions, database, and state.
|
|
9
9
|
|
|
10
10
|
If you only remember one thing from this page, remember this: most AI apps today stop one step short of being useful, and that gap is the biggest mistake in the space right now.
|
|
11
11
|
|
|
12
12
|
## What it looks like as a user {#what-it-looks-like}
|
|
13
13
|
|
|
14
|
-
Picture a background worker, inbox, calendar, form builder, or analytics dashboard.
|
|
14
|
+
Picture a background worker, inbox, calendar, form builder, or analytics dashboard. Often the first screen is chat: you ask what you want, the agent guides setup, shows a table or chart, and opens the right app view. Sometimes chat is docked on the right side of a full application. Sometimes there is no custom screen yet because the workflow is a scheduled job, queue, script, or external-agent integration. Across those shapes, you can:
|
|
15
15
|
|
|
16
16
|
- **Start with the real operation.** One durable action can run from the CLI, HTTP, MCP, A2A, the app-agent loop, and later a UI.
|
|
17
17
|
- **Click anything you'd normally click when there is a UI.** All the buttons, lists, dashboards, keyboard shortcuts — they all call the same operations the agent can call.
|
|
@@ -116,7 +116,7 @@ Even when the agent does all the heavy lifting, humans still need to:
|
|
|
116
116
|
|
|
117
117
|
At minimum, "a UI for the agent" is an observability and management dashboard. At maximum, it's a full SaaS app with the agent embedded as a co-pilot. Both ends count as agent-native, and the surface can grow from one without a rewrite.
|
|
118
118
|
|
|
119
|
-
You don't have to choose
|
|
119
|
+
You don't have to choose every surface up front. The agent can start in rich chat, render native inline UI, live inside a full application, or run from automation and external-agent channels around the same action surface — see [Agent Surfaces](/docs/agent-surfaces) for the concrete shapes and APIs.
|
|
120
120
|
|
|
121
121
|
## Why every app benefits from an agent {#why-every-app-benefits-from-an-agent}
|
|
122
122
|
|
|
@@ -124,7 +124,7 @@ The flip side is just as important. Existing SaaS products keep hitting the same
|
|
|
124
124
|
|
|
125
125
|
Agent-native flips that. Because every action in the app is defined once and exposed as both a button and an agent tool, the agent can do everything the buttons can — and more — without a separate "AI world" to maintain. Natural language becomes a first-class input alongside clicks.
|
|
126
126
|
|
|
127
|
-
The argument isn't "agents replace UI." It's "**agents belong inside applications, with a UI on top, as equal partners**." Even an app
|
|
127
|
+
The argument isn't "agents replace UI." It's "**agents belong inside applications, with a UI on top, as equal partners**." Even an automation-first app still needs some surface for humans to supervise, configure, and steer it — usually chat, a job history, or a small status page. See [Agent Surfaces — Automation-first app](/docs/agent-surfaces#headless).
|
|
128
128
|
|
|
129
129
|
## Agent + UI parity {#agent-ui-parity}
|
|
130
130
|
|
|
@@ -394,8 +394,8 @@ One action, many surfaces: the agent calls it as a tool, the UI calls it as a ty
|
|
|
394
394
|
|
|
395
395
|
## What's next {#whats-next}
|
|
396
396
|
|
|
397
|
-
- [**Getting Started**](/docs/getting-started) — start with
|
|
398
|
-
- [**Agent Surfaces**](/docs/agent-surfaces) — choose
|
|
397
|
+
- [**Getting Started**](/docs/getting-started) — start with chat, add an action, render a native result, and grow into a page
|
|
398
|
+
- [**Agent Surfaces**](/docs/agent-surfaces) — choose chat, native inline UI, full app pages, embedded sidecar, automation, or external agent access
|
|
399
399
|
- [**Key Concepts**](/docs/key-concepts) — the architecture: SQL, actions, polling sync, context awareness, portability
|
|
400
400
|
- [**Templates**](/docs/cloneable-saas) — templates as complete products you own
|
|
401
401
|
- [**Workspace**](/docs/workspace) — the per-user customization layer (skills, memory, instructions, MCP) backed by SQL, not files
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.84.
|
|
3
|
+
"version": "0.84.36",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -4,6 +4,15 @@ export interface CollectFinalResponseTextOptions {
|
|
|
4
4
|
fallbackToPreToolText?: boolean;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
export function applyAgentTextEventToBuffer(
|
|
8
|
+
currentText: string,
|
|
9
|
+
event: AgentChatEvent,
|
|
10
|
+
): string {
|
|
11
|
+
if (event.type === "clear") return "";
|
|
12
|
+
if (event.type === "text") return currentText + event.text;
|
|
13
|
+
return currentText;
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
export function collectFinalResponseTextFromAgentEvents(
|
|
8
17
|
events: readonly AgentChatEvent[],
|
|
9
18
|
options: CollectFinalResponseTextOptions = {},
|
|
@@ -38,7 +47,7 @@ function collectTextEvents(
|
|
|
38
47
|
let text = "";
|
|
39
48
|
for (let i = startIdx; i < events.length; i++) {
|
|
40
49
|
const event = events[i];
|
|
41
|
-
|
|
50
|
+
text = applyAgentTextEventToBuffer(text, event);
|
|
42
51
|
}
|
|
43
52
|
return text;
|
|
44
53
|
}
|
|
@@ -2670,7 +2670,6 @@ export async function runAgentLoop(opts: {
|
|
|
2670
2670
|
}
|
|
2671
2671
|
}
|
|
2672
2672
|
|
|
2673
|
-
const bufferTextUntilFinalGuard = Boolean(opts.finalResponseGuard);
|
|
2674
2673
|
let finalGuardRetries = 0;
|
|
2675
2674
|
let iterations = 0;
|
|
2676
2675
|
|
|
@@ -2700,7 +2699,7 @@ export async function runAgentLoop(opts: {
|
|
|
2700
2699
|
}
|
|
2701
2700
|
|
|
2702
2701
|
let assistantContent: EngineContentPart[] | undefined;
|
|
2703
|
-
let
|
|
2702
|
+
let streamedAssistantText = "";
|
|
2704
2703
|
let terminalStopReason:
|
|
2705
2704
|
| Extract<EngineEvent, { type: "stop" }>["reason"]
|
|
2706
2705
|
| undefined;
|
|
@@ -2768,7 +2767,7 @@ export async function runAgentLoop(opts: {
|
|
|
2768
2767
|
|
|
2769
2768
|
for (let retry = 0; ; retry++) {
|
|
2770
2769
|
assistantContent = undefined;
|
|
2771
|
-
|
|
2770
|
+
streamedAssistantText = "";
|
|
2772
2771
|
terminalStopReason = undefined;
|
|
2773
2772
|
toolCallErrors.clear();
|
|
2774
2773
|
try {
|
|
@@ -2833,11 +2832,8 @@ export async function runAgentLoop(opts: {
|
|
|
2833
2832
|
}
|
|
2834
2833
|
}
|
|
2835
2834
|
if (event.type === "text-delta") {
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
} else {
|
|
2839
|
-
send({ type: "text", text: event.text });
|
|
2840
|
-
}
|
|
2835
|
+
streamedAssistantText += event.text;
|
|
2836
|
+
send({ type: "text", text: event.text });
|
|
2841
2837
|
} else if (event.type === "thinking-delta") {
|
|
2842
2838
|
thinkingBuffer += event.text;
|
|
2843
2839
|
// Forward thinking deltas as a distinct event type so the UI
|
|
@@ -3007,21 +3003,22 @@ export async function runAgentLoop(opts: {
|
|
|
3007
3003
|
}
|
|
3008
3004
|
}
|
|
3009
3005
|
|
|
3010
|
-
const
|
|
3011
|
-
if (
|
|
3012
|
-
const text =
|
|
3013
|
-
bufferedAssistantText || collectTextParts(assistantContentForHistory);
|
|
3006
|
+
const flushUnstreamedAssistantText = () => {
|
|
3007
|
+
if (streamedAssistantText) return;
|
|
3008
|
+
const text = collectTextParts(assistantContentForHistory);
|
|
3014
3009
|
if (text) send({ type: "text", text });
|
|
3015
3010
|
};
|
|
3016
3011
|
|
|
3017
3012
|
if (toolCallParts.length === 0) {
|
|
3018
3013
|
if (terminalStopReason === "max_tokens") {
|
|
3019
|
-
|
|
3014
|
+
flushUnstreamedAssistantText();
|
|
3020
3015
|
appendAgentLoopContinuation(messages, "max_tokens");
|
|
3021
3016
|
continue;
|
|
3022
3017
|
}
|
|
3023
|
-
|
|
3024
|
-
|
|
3018
|
+
let guard: Awaited<ReturnType<AgentLoopFinalResponseGuard>> | null = null;
|
|
3019
|
+
if (opts.finalResponseGuard) {
|
|
3020
|
+
try {
|
|
3021
|
+
guard = await opts.finalResponseGuard({
|
|
3025
3022
|
messages,
|
|
3026
3023
|
assistantContent: assistantContentForHistory,
|
|
3027
3024
|
text: collectTextParts(assistantContentForHistory),
|
|
@@ -3029,8 +3026,12 @@ export async function runAgentLoop(opts: {
|
|
|
3029
3026
|
toolResults: [...toolResultHistory],
|
|
3030
3027
|
retryCount: finalGuardRetries,
|
|
3031
3028
|
executionMode: opts.executionMode ?? "act",
|
|
3032
|
-
})
|
|
3033
|
-
|
|
3029
|
+
});
|
|
3030
|
+
} catch (err) {
|
|
3031
|
+
send({ type: "clear" });
|
|
3032
|
+
throw err;
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3034
3035
|
let guardEmittedFallback = false;
|
|
3035
3036
|
if (guard) {
|
|
3036
3037
|
const retryMessage =
|
|
@@ -3039,16 +3040,18 @@ export async function runAgentLoop(opts: {
|
|
|
3039
3040
|
typeof guard === "string" ? guard : guard.fallbackMessage;
|
|
3040
3041
|
if (finalGuardRetries < 1) {
|
|
3041
3042
|
finalGuardRetries += 1;
|
|
3043
|
+
send({ type: "clear" });
|
|
3042
3044
|
messages.push({
|
|
3043
3045
|
role: "user",
|
|
3044
3046
|
content: [{ type: "text", text: retryMessage }],
|
|
3045
3047
|
});
|
|
3046
3048
|
continue;
|
|
3047
3049
|
}
|
|
3050
|
+
send({ type: "clear" });
|
|
3048
3051
|
send({ type: "text", text: fallbackMessage ?? retryMessage });
|
|
3049
3052
|
guardEmittedFallback = true;
|
|
3050
3053
|
} else {
|
|
3051
|
-
|
|
3054
|
+
flushUnstreamedAssistantText();
|
|
3052
3055
|
}
|
|
3053
3056
|
// Some providers (notably OpenAI Responses for gpt-5+) can stream a
|
|
3054
3057
|
// successful turn that contains only reasoning content and zero output
|
|
@@ -3059,7 +3062,7 @@ export async function runAgentLoop(opts: {
|
|
|
3059
3062
|
if (
|
|
3060
3063
|
!guardEmittedFallback &&
|
|
3061
3064
|
collectTextParts(assistantContentForHistory).trim().length === 0 &&
|
|
3062
|
-
|
|
3065
|
+
streamedAssistantText.trim().length === 0
|
|
3063
3066
|
) {
|
|
3064
3067
|
send({
|
|
3065
3068
|
type: "text",
|
|
@@ -3076,7 +3079,7 @@ export async function runAgentLoop(opts: {
|
|
|
3076
3079
|
// permanently disabled for the rest of a long multi-step run.
|
|
3077
3080
|
finalGuardRetries = 0;
|
|
3078
3081
|
|
|
3079
|
-
|
|
3082
|
+
flushUnstreamedAssistantText();
|
|
3080
3083
|
|
|
3081
3084
|
let requestedActionStop: { message: string; errorCode?: string } | null =
|
|
3082
3085
|
null;
|
|
@@ -124,6 +124,30 @@ export const DEFAULT_ERRORED_RUN_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
|
124
124
|
*/
|
|
125
125
|
export const TERMINAL_RUN_RECONNECT_WINDOW_MS = 10 * 60 * 1000;
|
|
126
126
|
|
|
127
|
+
/** Fast poll cadence while a SQL-backed SSE subscription is actively receiving rows. */
|
|
128
|
+
export const SQL_SUBSCRIPTION_ACTIVE_POLL_MS = 125;
|
|
129
|
+
|
|
130
|
+
/** Baseline SQL-backed SSE poll cadence when the run is idle. */
|
|
131
|
+
export const SQL_SUBSCRIPTION_IDLE_POLL_MS = 500;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Keep briefly polling quickly after rows arrive so token streams stay smooth,
|
|
135
|
+
* then back off to the idle cadence if the producer goes quiet.
|
|
136
|
+
*/
|
|
137
|
+
export const SQL_SUBSCRIPTION_ACTIVE_GRACE_MS = 2_000;
|
|
138
|
+
|
|
139
|
+
/** Keep terminal/status probes at the historical cadence to bound DB work. */
|
|
140
|
+
export const SQL_SUBSCRIPTION_STATUS_POLL_MS = 500;
|
|
141
|
+
|
|
142
|
+
export function resolveSqlSubscriptionPollMs(
|
|
143
|
+
now: number,
|
|
144
|
+
activePollUntil: number,
|
|
145
|
+
): number {
|
|
146
|
+
return now < activePollUntil
|
|
147
|
+
? SQL_SUBSCRIPTION_ACTIVE_POLL_MS
|
|
148
|
+
: SQL_SUBSCRIPTION_IDLE_POLL_MS;
|
|
149
|
+
}
|
|
150
|
+
|
|
127
151
|
const PROVIDER_RATE_LIMITED_ERROR_CODE = "provider_rate_limited";
|
|
128
152
|
|
|
129
153
|
function isPreparingActionActivityEvent(event: AgentChatEvent): boolean {
|
|
@@ -960,6 +984,8 @@ function subscribeFromSQL(
|
|
|
960
984
|
return new ReadableStream({
|
|
961
985
|
async start(controller) {
|
|
962
986
|
let lastSeq = fromSeq;
|
|
987
|
+
let activePollUntil = 0;
|
|
988
|
+
let lastStatusCheckAt = 0;
|
|
963
989
|
const ping = () => {
|
|
964
990
|
try {
|
|
965
991
|
controller.enqueue(encoder.encode(`: ping ${Date.now()}\n\n`));
|
|
@@ -976,6 +1002,9 @@ function subscribeFromSQL(
|
|
|
976
1002
|
try {
|
|
977
1003
|
// Read new events from SQL
|
|
978
1004
|
const events = await getRunEventsSince(runId, lastSeq);
|
|
1005
|
+
if (events.length > 0) {
|
|
1006
|
+
activePollUntil = Date.now() + SQL_SUBSCRIPTION_ACTIVE_GRACE_MS;
|
|
1007
|
+
}
|
|
979
1008
|
for (const { seq, eventData } of events) {
|
|
980
1009
|
// Advance the cursor first, before any parse/enqueue branch can
|
|
981
1010
|
// `continue`/`return`. Otherwise a single corrupt (unparseable)
|
|
@@ -1009,6 +1038,18 @@ function subscribeFromSQL(
|
|
|
1009
1038
|
|
|
1010
1039
|
// Check if run completed (no terminal event but status changed)
|
|
1011
1040
|
if (events.length === 0) {
|
|
1041
|
+
const now = Date.now();
|
|
1042
|
+
if (now - lastStatusCheckAt < SQL_SUBSCRIPTION_STATUS_POLL_MS) {
|
|
1043
|
+
if (!cancelled) {
|
|
1044
|
+
const pollMs = resolveSqlSubscriptionPollMs(
|
|
1045
|
+
now,
|
|
1046
|
+
activePollUntil,
|
|
1047
|
+
);
|
|
1048
|
+
pollTimer = setTimeout(poll, pollMs);
|
|
1049
|
+
}
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
lastStatusCheckAt = now;
|
|
1012
1053
|
// Opportunistically reap a stale producer before trusting SQL's
|
|
1013
1054
|
// "running" status — otherwise a crashed server leaves us polling
|
|
1014
1055
|
// forever.
|
|
@@ -1099,7 +1140,11 @@ function subscribeFromSQL(
|
|
|
1099
1140
|
|
|
1100
1141
|
// Schedule next poll
|
|
1101
1142
|
if (!cancelled) {
|
|
1102
|
-
|
|
1143
|
+
const pollMs = resolveSqlSubscriptionPollMs(
|
|
1144
|
+
Date.now(),
|
|
1145
|
+
activePollUntil,
|
|
1146
|
+
);
|
|
1147
|
+
pollTimer = setTimeout(poll, pollMs);
|
|
1103
1148
|
}
|
|
1104
1149
|
} catch {
|
|
1105
1150
|
// SQL error — close stream
|
|
@@ -126,8 +126,7 @@ export function buildAssistantMessage(
|
|
|
126
126
|
|
|
127
127
|
for (const { event } of events) {
|
|
128
128
|
if (event.type === "clear") {
|
|
129
|
-
content
|
|
130
|
-
toolCallCounter = 0;
|
|
129
|
+
clearAssistantDraftContent(content);
|
|
131
130
|
continue;
|
|
132
131
|
}
|
|
133
132
|
|
|
@@ -252,6 +251,20 @@ export function buildAssistantMessage(
|
|
|
252
251
|
};
|
|
253
252
|
}
|
|
254
253
|
|
|
254
|
+
function clearAssistantDraftContent(content: ContentPart[]): void {
|
|
255
|
+
for (let index = content.length - 1; index >= 0; index--) {
|
|
256
|
+
const part = content[index];
|
|
257
|
+
if (!part) continue;
|
|
258
|
+
if (part.type === "text") {
|
|
259
|
+
content.splice(index, 1);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (part.type === "tool-call" && part.result === undefined) {
|
|
263
|
+
content.splice(index, 1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
255
268
|
function getStoredMessage(entry: any): any {
|
|
256
269
|
return entry?.message ?? entry;
|
|
257
270
|
}
|
|
@@ -762,15 +762,13 @@ background, text, border, ring, fill, stroke, gradient, placeholder, decoration,
|
|
|
762
762
|
or shadow color, rewrite it to renderer tokens or remove it. Layout-only classes
|
|
763
763
|
are still discouraged; inline flex/grid styles are safer and easier to review.
|
|
764
764
|
|
|
765
|
-
**Keep Rough.js sparse.**
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
rough targets from parent containers and let backgrounds plus spacing separate
|
|
773
|
-
the surfaces.
|
|
765
|
+
**Keep Rough.js sparse.** The renderer sketches the outer frame, standard
|
|
766
|
+
\`.wf-*\` primitives, controls, and inline border dividers by default. Do not add
|
|
767
|
+
\`data-rough\` to broad root wrappers, dialog shells, page panels, grid cells, or
|
|
768
|
+
nested containers unless that single container is the visual point. Use
|
|
769
|
+
\`data-rough\` only for a deliberate one-off shape. If a mockup starts looking
|
|
770
|
+
like stacked/overlapping sketch lines, remove rough targets from parent
|
|
771
|
+
containers and let backgrounds plus spacing separate the surfaces.
|
|
774
772
|
|
|
775
773
|
**Use literal CSS lengths for spacing.** The \`--wf-*\` tokens are for colors and
|
|
776
774
|
renderer-owned visual styling, not layout spacing. Do not use guessed spacing
|
|
@@ -2685,6 +2685,8 @@ export function MultiTabAssistantChat({
|
|
|
2685
2685
|
<RunStuckBanner
|
|
2686
2686
|
threadId={tabId}
|
|
2687
2687
|
apiUrl={apiUrl}
|
|
2688
|
+
autoRetry
|
|
2689
|
+
autoRetryOwnerId={browserTabId}
|
|
2688
2690
|
onRetry={() => {
|
|
2689
2691
|
const handle = chatRefs.current.get(tabId);
|
|
2690
2692
|
handle?.sendRecoveryMessage(
|