@agent-native/core 0.92.4 → 0.92.6
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +19 -0
- package/corpus/core/docs/content/template-assets.mdx +139 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +96 -6
- package/corpus/core/src/cli/design-connect.ts +43 -16
- package/corpus/core/src/cli/skills.ts +52 -16
- package/corpus/core/src/client/AssistantChat.tsx +127 -15
- package/corpus/core/src/client/chat/tool-call-display.tsx +9 -3
- package/corpus/core/src/client/org/TeamPage.tsx +274 -177
- package/corpus/core/src/client/settings/DemoModeSection.tsx +6 -6
- package/corpus/core/src/client/settings/SettingsPanel.tsx +1 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +49 -1
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
- package/corpus/core/src/demo/config.ts +3 -3
- package/corpus/core/src/demo/redact.ts +720 -0
- package/corpus/core/src/extensions/url-safety.ts +13 -1
- package/corpus/core/src/localization/default-messages.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +7 -0
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +7 -0
- package/corpus/templates/analytics/AGENTS.md +6 -3
- package/corpus/templates/analytics/changelog/2026-07-09-uptime-monitors-use-scheduled-workers-in-production-serverless.md +6 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +5 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +14 -2
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +35 -0
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +19 -0
- package/corpus/templates/assets/AGENTS.md +13 -0
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +73 -0
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +63 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +22 -8
- package/corpus/templates/assets/actions/duplicate-library.ts +49 -1
- package/corpus/templates/assets/actions/generate-image-batch.ts +14 -1
- package/corpus/templates/assets/actions/generate-image.ts +195 -26
- package/corpus/templates/assets/actions/import-asset-from-url.ts +323 -0
- package/corpus/templates/assets/actions/list-generation-presets.ts +1 -1
- package/corpus/templates/assets/actions/rerun-generation-run.ts +37 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +19 -1
- package/corpus/templates/assets/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/assets/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/assets/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/assets/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/assets/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/assets/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/assets/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/assets/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/assets/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +41 -0
- package/corpus/templates/assets/app/i18n-data.ts +93 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +66 -11
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +959 -24
- package/corpus/templates/assets/changelog/2026-07-07-preset-skeleton-controls-fit-correctly-on-narrower-edit-page.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-09-import-reference-images-from-url.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-09-preset-reference-board.md +6 -0
- package/corpus/templates/assets/server/handlers/assets.ts +7 -27
- package/corpus/templates/assets/server/lib/generation.ts +83 -2
- package/corpus/templates/assets/server/lib/preset-chat-context.ts +17 -4
- package/corpus/templates/assets/server/lib/preset-references.ts +182 -0
- package/corpus/templates/assets/server/lib/upload-validation.ts +38 -0
- package/corpus/templates/assets/shared/api.ts +20 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +6 -0
- package/corpus/templates/calendar/actions/create-event.ts +8 -2
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +22 -7
- package/corpus/templates/calendar/changelog/2026-07-09-calendar-events-with-guests-now-automatically-get-a-google-m.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-09-new-events-now-mark-the-creator-rsvp-as-yes.md +6 -0
- package/corpus/templates/calendar/server/handlers/events.ts +9 -2
- package/corpus/templates/calendar/server/lib/event-video-conferencing.ts +58 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +1 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-reminder-popovers-can-now-be-dismissed-with-a-top-le.md +6 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +3 -1
- package/corpus/templates/clips/desktop/src/styles.css +13 -9
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +5 -2
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +27 -15
- package/corpus/templates/design/actions/connect-localhost.ts +40 -11
- package/corpus/templates/design/actions/open-visual-edit.ts +7 -1
- package/dist/agent/production-agent.d.ts +34 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +58 -5
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/design-connect.d.ts +5 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +37 -16
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +52 -16
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +3 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +96 -15
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +5 -1
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +32 -13
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -3
- package/dist/client/settings/DemoModeSection.js +4 -4
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +38 -2
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/demo/actions/toggle-demo-mode.js +2 -2
- package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
- package/dist/demo/config.js +3 -3
- package/dist/demo/config.js.map +1 -1
- package/dist/demo/redact.d.ts +1 -1
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +0 -0
- package/dist/demo/redact.js.map +1 -1
- package/dist/extensions/url-safety.d.ts +5 -0
- package/dist/extensions/url-safety.d.ts.map +1 -1
- package/dist/extensions/url-safety.js +10 -0
- package/dist/extensions/url-safety.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +7 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +7 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/templates/default/app/i18n/ar-SA.ts +7 -0
- package/dist/templates/default/app/i18n/de-DE.ts +7 -0
- package/dist/templates/default/app/i18n/en-US.ts +7 -0
- package/dist/templates/default/app/i18n/es-ES.ts +7 -0
- package/dist/templates/default/app/i18n/fr-FR.ts +7 -0
- package/dist/templates/default/app/i18n/hi-IN.ts +7 -0
- package/dist/templates/default/app/i18n/ja-JP.ts +7 -0
- package/dist/templates/default/app/i18n/ko-KR.ts +7 -0
- package/dist/templates/default/app/i18n/pt-BR.ts +7 -0
- package/dist/templates/default/app/i18n/zh-CN.ts +7 -0
- package/dist/templates/default/app/i18n/zh-TW.ts +7 -0
- package/docs/content/template-assets.mdx +139 -0
- package/package.json +1 -1
- package/src/templates/default/app/i18n/ar-SA.ts +7 -0
- package/src/templates/default/app/i18n/de-DE.ts +7 -0
- package/src/templates/default/app/i18n/en-US.ts +7 -0
- package/src/templates/default/app/i18n/es-ES.ts +7 -0
- package/src/templates/default/app/i18n/fr-FR.ts +7 -0
- package/src/templates/default/app/i18n/hi-IN.ts +7 -0
- package/src/templates/default/app/i18n/ja-JP.ts +7 -0
- package/src/templates/default/app/i18n/ko-KR.ts +7 -0
- package/src/templates/default/app/i18n/pt-BR.ts +7 -0
- package/src/templates/default/app/i18n/zh-CN.ts +7 -0
- package/src/templates/default/app/i18n/zh-TW.ts +7 -0
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.92.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5f187db: Highlight run-code source snippets in chat and keep raw tool output popovers within the available viewport.
|
|
8
|
+
- 5f187db: Fix duplicate in-progress chat output during reconnect handoff so streaming text and tool calls render once while the live assistant message catches up. Also stop a reconnect tool spinner from rendering a second card beside its live pending tool card when their reader-local and server-scoped ids don't match, in every reconnect/handoff window.
|
|
9
|
+
- 5f187db: Focus the settings search field automatically when desktop users open settings.
|
|
10
|
+
- 5f187db: Improve organization settings so invites stay above the fold and members appear in a separate table card.
|
|
11
|
+
- 6a29ba0: `ssrfSafeFetch` hardening: a new `httpsOnly` option validates the URL scheme on the initial request and on every redirect hop, so HTTPS-only callers cannot be downgraded to plain HTTP by a redirect from the untrusted origin. Followed redirect responses now also have their bodies cancelled so each hop's connection is released immediately instead of being held until GC.
|
|
12
|
+
- 5f187db: Remove the divider between settings tabs and their tab content.
|
|
13
|
+
- 5f187db: Preserve dashboard, chart, and label names in demo mode while continuing to anonymize free-text/contact names, emails, and numbers.
|
|
14
|
+
- c32c174: add preset-driven-flow to asset template docs
|
|
15
|
+
|
|
16
|
+
## 0.92.5
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- eed1710: Fix `/visual-edit` live-edit 401s. The design server now mints the bridge token in `connect-localhost` and returns it from `open-visual-edit`, and `design connect` adopts it via a new `--bridge-token` flag (or `AGENT_NATIVE_BRIDGE_TOKEN`) instead of minting its own. The local bridge and the user's connection row now share the secret without the CLI needing its own auth to self-register — which was impossible under OAuth-based MCP and was the root cause of the 401s. The `visual-edit` skill is updated to call `open-visual-edit` first and start the bridge with the returned token.
|
|
21
|
+
|
|
3
22
|
## 0.92.4
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -102,6 +102,145 @@ Live demo: [assets.agent-native.com](https://assets.agent-native.com).
|
|
|
102
102
|
4. **Use the asset elsewhere.** Copy the export, embed the picker in another
|
|
103
103
|
app, or let another agent call Assets over A2A.
|
|
104
104
|
|
|
105
|
+
## The preset-driven workflow
|
|
106
|
+
|
|
107
|
+
Assets produces its best, most repeatable results when work is split into two
|
|
108
|
+
jobs that need very different skills:
|
|
109
|
+
|
|
110
|
+
1. **Designing the recipe** — slow, craft-heavy, done once per use case. A
|
|
111
|
+
designer works with the agent to build a **generation preset**: the rules,
|
|
112
|
+
references, locked-in model, and a prompt template that has been QA'd until
|
|
113
|
+
it reliably produces on-brand output.
|
|
114
|
+
2. **Running the recipe** — fast and repeatable. A marketer pastes a campaign
|
|
115
|
+
brief, tags the preset, and gets a finished, brand-safe asset without
|
|
116
|
+
touching model settings, aspect ratios, masks, or prompt wording.
|
|
117
|
+
|
|
118
|
+
A preset is the contract between these two people. The designer encodes taste
|
|
119
|
+
and technical judgment once; everyone else inherits it on every generation.
|
|
120
|
+
Think of presets as the design system for AI-generated assets: a raw prompt is
|
|
121
|
+
a throwaway that drifts every time it is retyped, while a preset is durable,
|
|
122
|
+
shared, and carries the decisions (model, aspect ratio, text and reference
|
|
123
|
+
rules, logo handling, fixed layout) that actually determine whether the output
|
|
124
|
+
is usable.
|
|
125
|
+
|
|
126
|
+
### Designers: build one preset per use case
|
|
127
|
+
|
|
128
|
+
Create a separate preset for each repeatable format rather than one generic
|
|
129
|
+
"social post" preset that tries to do everything. Specific presets give the
|
|
130
|
+
model clearer rules and produce better output. Good examples:
|
|
131
|
+
|
|
132
|
+
- LinkedIn ad
|
|
133
|
+
- Webinar announcement
|
|
134
|
+
- Event speaker card
|
|
135
|
+
- Podcast guest card
|
|
136
|
+
- Customer story quote card
|
|
137
|
+
- Blog hero
|
|
138
|
+
- Blog body diagram
|
|
139
|
+
|
|
140
|
+
The primary way to build one is **conversationally**: describe the use case to
|
|
141
|
+
the agent and let it create the preset and fill in sensible defaults — model,
|
|
142
|
+
aspect ratio and size, a first prompt template, and text/reference/logo
|
|
143
|
+
policies — then refine in the same conversation ("make it darker", "tighten the
|
|
144
|
+
text policy", "try a square variant"). Because that reasoning shows up directly
|
|
145
|
+
in the defaults the agent picks, run this design conversation on the strongest
|
|
146
|
+
available model.
|
|
147
|
+
|
|
148
|
+
Each preset locks down:
|
|
149
|
+
|
|
150
|
+
| Setting | What it controls |
|
|
151
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
152
|
+
| Prompt template | The QA'd creative recipe, with slots for the campaign brief |
|
|
153
|
+
| Model | The right image engine for this job (see below) |
|
|
154
|
+
| Aspect ratio + size | Output format for the target channel |
|
|
155
|
+
| Text policy | Whether and how literal copy is rendered vs suppressed |
|
|
156
|
+
| Reference policy | Which brand references anchor the look |
|
|
157
|
+
| Reference board | Named fixed or per-run visual references, such as a usual host, guest speaker, product, backdrop, or composition cue |
|
|
158
|
+
| Logo | Composites the library's canonical logo pixel-perfect after generation, so the model never redraws it |
|
|
159
|
+
| Skeleton / mask | A fixed brand plate the subject is composited or inpainted into, for locked layouts |
|
|
160
|
+
|
|
161
|
+
### Choosing the model per preset
|
|
162
|
+
|
|
163
|
+
Pick the model in the preset so downstream users never have to:
|
|
164
|
+
|
|
165
|
+
- **A general high-quality image model** for hero images, rich scenes, and
|
|
166
|
+
complex compositions, when you need broad aspect-ratio flexibility.
|
|
167
|
+
- **A fast image model** for high-volume social where turnaround matters more
|
|
168
|
+
than maximum polish.
|
|
169
|
+
- **gpt-image-2** for customer-facing, text-heavy, and identity-sensitive work.
|
|
170
|
+
It renders crisp literal copy inside the image, and it is the engine used for
|
|
171
|
+
**mask inpainting** into a fixed layout.
|
|
172
|
+
- **gpt-image-1** for transparent **cutout** subjects that are composited onto a
|
|
173
|
+
brand plate afterward.
|
|
174
|
+
|
|
175
|
+
When a use case has a **fixed brand frame** that must survive every generation
|
|
176
|
+
(a webinar template with a locked header and logo, an ad plate with a reserved
|
|
177
|
+
product area), build a preset skeleton: upload the background plate, choose
|
|
178
|
+
gpt-image-2, and optionally add a same-size mask. **Opaque areas are preserved,
|
|
179
|
+
transparent areas are editable**, so the logo, framing, and existing copy come
|
|
180
|
+
back untouched while only the art region changes. Note that gpt-image edits are
|
|
181
|
+
guided semantic rewrites, not pixel-only patches, so the prompt should still
|
|
182
|
+
describe the whole intended image and restate what must not change.
|
|
183
|
+
|
|
184
|
+
Use the **reference board** when a preset needs annotated visual inputs that
|
|
185
|
+
ride along with each run. Each board entry names one thing — a person, product,
|
|
186
|
+
style, background, or composition example — and can pin up to four images plus a
|
|
187
|
+
plain-language description. Fixed entries attach automatically. Variable
|
|
188
|
+
entries can be replaced per run with `presetReferenceFills`, and required
|
|
189
|
+
variable entries block generation until the agent supplies images from user
|
|
190
|
+
attachments or the library.
|
|
191
|
+
|
|
192
|
+
For example, a Webinar Announcement preset might use a skeleton plate and mask
|
|
193
|
+
for the locked event chrome, a fixed "Steve" subject entry for the usual host,
|
|
194
|
+
and a required variable "Guest speaker" entry for each event. Use a
|
|
195
|
+
`background` entry for setting context. Use a `composition` entry for layout
|
|
196
|
+
inspiration from a past poster; exact placement belongs in the skeleton plate,
|
|
197
|
+
not a reference image.
|
|
198
|
+
|
|
199
|
+
### QA the prompt until it is reliable
|
|
200
|
+
|
|
201
|
+
The model, references, and skeleton set the stage, but the prompt template is
|
|
202
|
+
what turns a brief into a consistently good asset. Have the agent generate
|
|
203
|
+
several candidates against realistic briefs and tighten the template until it
|
|
204
|
+
holds. Techniques worth baking in:
|
|
205
|
+
|
|
206
|
+
- **Structure the prompt in a fixed order**: scene, subject, key details,
|
|
207
|
+
constraints. Name the intended use so the model picks the right polish level.
|
|
208
|
+
- **For literal copy, be surgical**: put exact text in quotes or ALL CAPS,
|
|
209
|
+
specify font, size, color, and placement, and for tricky brand names spell
|
|
210
|
+
them out. Ask for the text exactly once with no extra characters.
|
|
211
|
+
- **For skeleton or inpainting presets, restate the invariants every run**:
|
|
212
|
+
"change only the center region, preserve the header, logo, and framing."
|
|
213
|
+
|
|
214
|
+
Before handing a preset to the wider team, run realistic QA generations
|
|
215
|
+
(including briefs you did not write) and confirm it: follows the use case,
|
|
216
|
+
respects the mask, preserves fixed text and logos, avoids inventing extra
|
|
217
|
+
headlines or badges, uses references correctly, places the subject in the right
|
|
218
|
+
region, handles short and long briefs, and still holds up after a refinement.
|
|
219
|
+
|
|
220
|
+
### Everyone else: paste the brief, tag the preset, generate
|
|
221
|
+
|
|
222
|
+
Once a preset exists, running it is three moves: paste the campaign brief, tag
|
|
223
|
+
the preset with `@`, and generate. The tagged preset injects its full aesthetic
|
|
224
|
+
brief into the agent, and the saved model, format, tier, logo, and skeleton all
|
|
225
|
+
apply automatically.
|
|
226
|
+
|
|
227
|
+
```text
|
|
228
|
+
Create a LinkedIn ad for our webinar on AI landing pages.
|
|
229
|
+
Audience: B2B marketing teams.
|
|
230
|
+
Message: launch campaign pages faster while staying on brand.
|
|
231
|
+
CTA: Register now.
|
|
232
|
+
|
|
233
|
+
@Webinar Announcement
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
No model picking, no aspect-ratio math, no mask files, no prompt engineering.
|
|
237
|
+
Rule of thumb: designers own the preset, everyone else owns the brief. If a
|
|
238
|
+
user finds themselves choosing models, masks, or layout rules during normal
|
|
239
|
+
use, the preset is not specific enough yet.
|
|
240
|
+
|
|
241
|
+
For deeper prompting guidance on the underlying models, see OpenAI's
|
|
242
|
+
[GPT Image prompting guide](https://developers.openai.com/cookbook/examples/multimodal/image-gen-models-prompting-guide).
|
|
243
|
+
|
|
105
244
|
## Useful prompts
|
|
106
245
|
|
|
107
246
|
- "Generate three blog hero options using the Acme product references."
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.92.
|
|
3
|
+
"version": "0.92.6",
|
|
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": {
|
|
@@ -4193,7 +4193,7 @@ export async function runAgentLoop(opts: {
|
|
|
4193
4193
|
// `_agentImages` result field (stripped from the JSON the model
|
|
4194
4194
|
// reads, even in demo mode). Demo mode drops the images themselves —
|
|
4195
4195
|
// text redaction can't scrub pixels, and a screenshot would leak the
|
|
4196
|
-
// real names/emails the redaction exists to hide. The images array
|
|
4196
|
+
// real contact names/emails/numbers the redaction exists to hide. The images array
|
|
4197
4197
|
// never touches the ledger — only the compact text notes appended
|
|
4198
4198
|
// below are persisted.
|
|
4199
4199
|
let imageNotes: string[] = [];
|
|
@@ -4664,7 +4664,40 @@ export function backgroundContinuationReasonForRun(
|
|
|
4664
4664
|
}
|
|
4665
4665
|
|
|
4666
4666
|
export async function runAgentLoopWithMainChatInternalContinuations(
|
|
4667
|
-
opts: Parameters<typeof runAgentLoop>[0]
|
|
4667
|
+
opts: Parameters<typeof runAgentLoop>[0] & {
|
|
4668
|
+
/**
|
|
4669
|
+
* Opt-in: also catch a thrown `isResumableEngineError` (gateway drop /
|
|
4670
|
+
* transport interruption surviving engine retries) and retry it in-process
|
|
4671
|
+
* — the same "continue from where you left off" treatment already applied
|
|
4672
|
+
* to in-loop `auto_continue` events below — instead of letting it
|
|
4673
|
+
* propagate out to the caller. Default false/omitted preserves the exact
|
|
4674
|
+
* prior behavior: such an error is NOT caught here and propagates to
|
|
4675
|
+
* `startRun`'s outer catch, which marks the run "errored" and (for a
|
|
4676
|
+
* background worker) hands off to `chainServerDrivenContinuation` for a
|
|
4677
|
+
* fresh invocation.
|
|
4678
|
+
*
|
|
4679
|
+
* Only safe to enable when the CALLER is a proven durable-background
|
|
4680
|
+
* worker (`isInBackgroundFunctionRuntime()`): such a worker has minutes of
|
|
4681
|
+
* remaining budget on this same invocation, so resuming in-process avoids
|
|
4682
|
+
* a self-dispatch entirely — critically, it avoids the bg-function
|
|
4683
|
+
* self-dispatch 404 (a background function cannot invoke its own public
|
|
4684
|
+
* URL from inside a live invocation) that this same recoverable-error
|
|
4685
|
+
* path would otherwise hit via `chainServerDrivenContinuation`. A
|
|
4686
|
+
* foreground turn (~40s budget) must NOT set this — it keeps depending on
|
|
4687
|
+
* the existing cross-invocation recovery (foreground self-chain or the
|
|
4688
|
+
* client's `auto_continue` re-POST), unchanged.
|
|
4689
|
+
*/
|
|
4690
|
+
resumeResumableErrorsInProcess?: boolean;
|
|
4691
|
+
/**
|
|
4692
|
+
* Override for the per-invocation continuation attempt cap. Defaults to
|
|
4693
|
+
* `MAIN_CHAT_INTERNAL_CONTINUATION_LIMIT` (6) when omitted — unchanged for
|
|
4694
|
+
* every existing caller. A proven background-function worker (15-min
|
|
4695
|
+
* budget) can pass a higher cap (e.g. `MAX_BACKGROUND_RUN_CONTINUATIONS`)
|
|
4696
|
+
* so a run that needs several resumable-error recoveries within one
|
|
4697
|
+
* 13-minute chunk isn't cut off at the foreground-sized limit.
|
|
4698
|
+
*/
|
|
4699
|
+
maxContinuations?: number;
|
|
4700
|
+
},
|
|
4668
4701
|
): Promise<Awaited<ReturnType<typeof runAgentLoop>>> {
|
|
4669
4702
|
const usage: Awaited<ReturnType<typeof runAgentLoop>> = {
|
|
4670
4703
|
inputTokens: 0,
|
|
@@ -4681,11 +4714,18 @@ export async function runAgentLoopWithMainChatInternalContinuations(
|
|
|
4681
4714
|
usage.model = next.model;
|
|
4682
4715
|
};
|
|
4683
4716
|
|
|
4717
|
+
const resumeResumableErrorsInProcess =
|
|
4718
|
+
opts.resumeResumableErrorsInProcess === true;
|
|
4719
|
+
const maxContinuations =
|
|
4720
|
+
typeof opts.maxContinuations === "number" && opts.maxContinuations > 0
|
|
4721
|
+
? opts.maxContinuations
|
|
4722
|
+
: MAIN_CHAT_INTERNAL_CONTINUATION_LIMIT;
|
|
4723
|
+
|
|
4684
4724
|
const localTurnEvents: AgentChatEvent[] = [];
|
|
4685
4725
|
let lastAttemptWasUnfinishedContinuation = false;
|
|
4686
4726
|
for (
|
|
4687
4727
|
let attempt = 0;
|
|
4688
|
-
!opts.signal.aborted && attempt <
|
|
4728
|
+
!opts.signal.aborted && attempt < maxContinuations;
|
|
4689
4729
|
attempt++
|
|
4690
4730
|
) {
|
|
4691
4731
|
lastAttemptWasUnfinishedContinuation = false;
|
|
@@ -4703,8 +4743,23 @@ export async function runAgentLoopWithMainChatInternalContinuations(
|
|
|
4703
4743
|
opts.send(event);
|
|
4704
4744
|
};
|
|
4705
4745
|
|
|
4706
|
-
|
|
4707
|
-
|
|
4746
|
+
try {
|
|
4747
|
+
const nextUsage = await runAgentLoop({ ...opts, send });
|
|
4748
|
+
addUsage(nextUsage);
|
|
4749
|
+
} catch (err) {
|
|
4750
|
+
// Preserve exact prior behavior unless explicitly opted in: an aborted
|
|
4751
|
+
// signal (real soft-timeout / user stop) or a non-resumable error is
|
|
4752
|
+
// always rethrown, and when `resumeResumableErrorsInProcess` is not
|
|
4753
|
+
// set, EVERY thrown error is rethrown exactly as before.
|
|
4754
|
+
if (
|
|
4755
|
+
!resumeResumableErrorsInProcess ||
|
|
4756
|
+
opts.signal.aborted ||
|
|
4757
|
+
!isResumableEngineError(err)
|
|
4758
|
+
) {
|
|
4759
|
+
throw err;
|
|
4760
|
+
}
|
|
4761
|
+
continuationReason = continuationReasonForResumableError(err);
|
|
4762
|
+
}
|
|
4708
4763
|
|
|
4709
4764
|
if (!continuationReason || opts.signal.aborted) {
|
|
4710
4765
|
return usage;
|
|
@@ -6525,10 +6580,25 @@ export function createProductionAgentHandler(
|
|
|
6525
6580
|
// chaining via the regular function — the Netlify
|
|
6526
6581
|
// `-background` function is only emitted into the deploy
|
|
6527
6582
|
// output when the durable flag is on.
|
|
6583
|
+
//
|
|
6584
|
+
// `&& !runsInBackgroundFunction`: a worker PROVEN to already
|
|
6585
|
+
// be executing inside the real `-background` function must
|
|
6586
|
+
// never dispatch back to that same function's own URL — a
|
|
6587
|
+
// background function invoking itself by URL from inside a
|
|
6588
|
+
// live invocation is a documented Netlify platform
|
|
6589
|
+
// limitation (404), unlike the initial foreground→background
|
|
6590
|
+
// dispatch or a worker that landed on the regular function
|
|
6591
|
+
// (a genuinely different function calling the background
|
|
6592
|
+
// one, which works). This only changes the dispatch TARGET
|
|
6593
|
+
// for that one proven-in-bg-function case — by this point
|
|
6594
|
+
// (with the in-process resumable-error resume above) it is
|
|
6595
|
+
// reached only when the chunk genuinely exhausted its
|
|
6596
|
+
// budget, so falling back to the regular `_process-run`
|
|
6597
|
+
// function (40s clamp) here is the correct, safe target.
|
|
6528
6598
|
chainViaDurableBackground:
|
|
6529
6599
|
isAgentChatDurableBackgroundEnabled({
|
|
6530
6600
|
appOptIn: options.durableBackgroundRuns === true,
|
|
6531
|
-
}),
|
|
6601
|
+
}) && !runsInBackgroundFunction,
|
|
6532
6602
|
});
|
|
6533
6603
|
}
|
|
6534
6604
|
} finally {
|
|
@@ -6946,6 +7016,26 @@ export function createProductionAgentHandler(
|
|
|
6946
7016
|
.slice(0, 200),
|
|
6947
7017
|
}
|
|
6948
7018
|
: {}),
|
|
7019
|
+
// A worker PROVEN to be running inside the real 15-min Netlify
|
|
7020
|
+
// `-background` function (`runsInBackgroundFunction`) has minutes of
|
|
7021
|
+
// budget left on THIS invocation. Let it catch a recoverable
|
|
7022
|
+
// transport/gateway error (isResumableEngineError) and resume the
|
|
7023
|
+
// agent loop in-process instead of unwinding out to `startRun`'s
|
|
7024
|
+
// outer catch, which would otherwise hand off to
|
|
7025
|
+
// `chainServerDrivenContinuation` — and for a worker already inside
|
|
7026
|
+
// the background function, that hand-off is a same-function
|
|
7027
|
+
// self-dispatch that 404s on Netlify (a background function cannot
|
|
7028
|
+
// invoke its own public URL from inside a live invocation). A
|
|
7029
|
+
// foreground turn or a worker that landed on the regular ~60s
|
|
7030
|
+
// function (runsInBackgroundFunction false) must NOT set this — it
|
|
7031
|
+
// keeps depending on the existing cross-invocation recovery
|
|
7032
|
+
// (foreground self-chain / client auto_continue re-POST), unchanged.
|
|
7033
|
+
...(runsInBackgroundFunction
|
|
7034
|
+
? {
|
|
7035
|
+
resumeResumableErrorsInProcess: true,
|
|
7036
|
+
maxContinuations: MAX_BACKGROUND_RUN_CONTINUATIONS,
|
|
7037
|
+
}
|
|
7038
|
+
: {}),
|
|
6949
7039
|
};
|
|
6950
7040
|
|
|
6951
7041
|
send({ type: "activity", label: "Contacting model" });
|
|
@@ -60,6 +60,10 @@ export interface DesignConnectArgs {
|
|
|
60
60
|
* are present) the CLI POSTs to `/_agent-native/actions/connect-localhost`
|
|
61
61
|
* with the real bridge token so the server can store it for grant minting. */
|
|
62
62
|
appUrl?: string;
|
|
63
|
+
/** Server-minted bridge token to adopt instead of minting one, so the bridge
|
|
64
|
+
* matches the token already stored on the user's connection row (no
|
|
65
|
+
* self-registration). Also read from AGENT_NATIVE_BRIDGE_TOKEN. */
|
|
66
|
+
bridgeToken?: string;
|
|
63
67
|
json: boolean;
|
|
64
68
|
once: boolean;
|
|
65
69
|
dryRun: boolean;
|
|
@@ -174,6 +178,11 @@ export function parseDesignConnectArgs(argv: string[]): DesignConnectArgs {
|
|
|
174
178
|
index += 1;
|
|
175
179
|
} else if (arg.startsWith("--app-url=")) {
|
|
176
180
|
parsed.appUrl = arg.slice("--app-url=".length);
|
|
181
|
+
} else if (arg === "--bridge-token") {
|
|
182
|
+
parsed.bridgeToken = stringFlagValue(args, index, arg);
|
|
183
|
+
index += 1;
|
|
184
|
+
} else if (arg.startsWith("--bridge-token=")) {
|
|
185
|
+
parsed.bridgeToken = arg.slice("--bridge-token=".length);
|
|
177
186
|
} else if (arg === "--json") {
|
|
178
187
|
parsed.json = true;
|
|
179
188
|
parsed.once = true;
|
|
@@ -1215,12 +1224,16 @@ async function walkBridgeFiles(rootPath: string): Promise<ListFilesResult> {
|
|
|
1215
1224
|
|
|
1216
1225
|
export async function startDesignConnectBridge(
|
|
1217
1226
|
manifest: DesignConnectManifest,
|
|
1227
|
+
seedToken?: string,
|
|
1218
1228
|
): Promise<DesignConnectBridge> {
|
|
1219
|
-
//
|
|
1220
|
-
//
|
|
1221
|
-
//
|
|
1222
|
-
//
|
|
1223
|
-
const bridgeToken =
|
|
1229
|
+
// Shared secret the browser sends (x-bridge-token) to unlock live-edit/read/
|
|
1230
|
+
// write. Bridge and the user's connection row must agree on it. Adopt a
|
|
1231
|
+
// server-minted seed when given (MCP flow); otherwise mint one and rely on
|
|
1232
|
+
// --app-url self-registration to push it up. Kept in-process, never served.
|
|
1233
|
+
const bridgeToken =
|
|
1234
|
+
seedToken ||
|
|
1235
|
+
process.env["AGENT_NATIVE_BRIDGE_TOKEN"] ||
|
|
1236
|
+
crypto.randomBytes(32).toString("hex");
|
|
1224
1237
|
let liveEditBridgeScript = "";
|
|
1225
1238
|
|
|
1226
1239
|
const server = http.createServer(
|
|
@@ -1795,6 +1808,12 @@ Options:
|
|
|
1795
1808
|
--route-manifest <path> Non-destructive route manifest output path
|
|
1796
1809
|
--app-url <url> Deployed design app URL for self-registration
|
|
1797
1810
|
(also reads AGENT_NATIVE_URL / DESIGN_APP_URL env)
|
|
1811
|
+
--bridge-token <token> Adopt a bridge token minted server-side by the
|
|
1812
|
+
authenticated connect-localhost / open-visual-edit
|
|
1813
|
+
action instead of minting one. Used by the remote-MCP
|
|
1814
|
+
/visual-edit flow so the bridge and the user's stored
|
|
1815
|
+
connection token match with no self-registration.
|
|
1816
|
+
(also reads AGENT_NATIVE_BRIDGE_TOKEN env)
|
|
1798
1817
|
--daemon Start the bridge detached, wait for /health, then exit
|
|
1799
1818
|
--json Print the manifest JSON and exit
|
|
1800
1819
|
--once Prepare/scaffold the manifest and exit
|
|
@@ -1931,25 +1950,33 @@ export async function runDesign(argv: string[]) {
|
|
|
1931
1950
|
return 0;
|
|
1932
1951
|
}
|
|
1933
1952
|
|
|
1934
|
-
const
|
|
1953
|
+
const seedToken =
|
|
1954
|
+
parsed.bridgeToken || process.env["AGENT_NATIVE_BRIDGE_TOKEN"] || undefined;
|
|
1955
|
+
const bridge = await startDesignConnectBridge(manifest, seedToken);
|
|
1935
1956
|
console.error("Design localhost bridge running");
|
|
1936
1957
|
console.error(`Bridge: ${manifest.bridgeUrl}`);
|
|
1937
1958
|
console.error(`Manifest: ${manifest.bridgeUrl}/manifest.json`);
|
|
1938
1959
|
console.error(`Routes: ${manifest.routeCount}`);
|
|
1939
1960
|
console.error(`Dev URL: ${manifest.devServerUrl}`);
|
|
1940
1961
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
const appUrl = resolveAppUrl(parsed.appUrl);
|
|
1945
|
-
if (appUrl) {
|
|
1946
|
-
void registerConnectionWithServer(appUrl, bridge, resolveAuthToken());
|
|
1947
|
-
} else {
|
|
1948
|
-
// No app URL means the token never reaches the DB — surface it instead of
|
|
1949
|
-
// silently skipping, since live-edit will then 401.
|
|
1962
|
+
if (seedToken) {
|
|
1963
|
+
// Server already stored this token on the row; bridge matches it, so no
|
|
1964
|
+
// self-registration needed. Zero-config path for the remote-MCP flow.
|
|
1950
1965
|
console.error(
|
|
1951
|
-
"[design connect]
|
|
1966
|
+
"[design connect] Using server-provided bridge token; skipping self-registration.",
|
|
1952
1967
|
);
|
|
1968
|
+
} else {
|
|
1969
|
+
// No seed: fall back to self-registration — POST the minted token to
|
|
1970
|
+
// connect-localhost. Needs an auth token in env or it 401s (the old gap).
|
|
1971
|
+
const appUrl = resolveAppUrl(parsed.appUrl);
|
|
1972
|
+
if (appUrl) {
|
|
1973
|
+
void registerConnectionWithServer(appUrl, bridge, resolveAuthToken());
|
|
1974
|
+
} else {
|
|
1975
|
+
// No token source at all — warn rather than 401 silently at edit time.
|
|
1976
|
+
console.error(
|
|
1977
|
+
"[design connect] No bridge token or app URL resolved (pass --bridge-token, or --app-url / AGENT_NATIVE_URL); skipping self-registration — live-edit will fail to authorize.",
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1953
1980
|
}
|
|
1954
1981
|
|
|
1955
1982
|
return await new Promise<number>((resolve) => {
|
|
@@ -486,34 +486,66 @@ iframe-backed screens on the infinite canvas.
|
|
|
486
486
|
|
|
487
487
|
## Required Local Bridge
|
|
488
488
|
|
|
489
|
-
|
|
489
|
+
The live-edit bridge is unlocked by a shared secret (the "bridge token") that
|
|
490
|
+
must match on two sides: the local bridge process, and the user's connection row
|
|
491
|
+
in Design (which the browser reads to authorize \`/live-edit-bridge\`,
|
|
492
|
+
\`/read-file\`, \`/write-file\`). Get them to match by letting the
|
|
493
|
+
**authenticated** \`open-visual-edit\` action mint the token, then starting the
|
|
494
|
+
bridge with it. This is the only ordering that works for the remote-MCP flow —
|
|
495
|
+
the bridge cannot push its own token to the server without a CLI auth token, so
|
|
496
|
+
the server mints instead and the bridge adopts.
|
|
497
|
+
|
|
498
|
+
From the target app repo, make sure its dev server is running, then:
|
|
499
|
+
|
|
500
|
+
**1. Discover routes without starting a durable bridge** (one-shot, exits):
|
|
490
501
|
|
|
491
502
|
\`\`\`bash
|
|
492
|
-
npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --
|
|
503
|
+
npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --json
|
|
493
504
|
\`\`\`
|
|
494
505
|
|
|
495
|
-
|
|
496
|
-
\`
|
|
497
|
-
|
|
506
|
+
This prints the manifest (routes + capabilities). Parse it to build
|
|
507
|
+
\`routeManifest\` for the next step. (Skip this if the user already gave explicit
|
|
508
|
+
paths/URLs to place.)
|
|
509
|
+
|
|
510
|
+
**2. Call \`open-visual-edit\`** (see Action Flow below) with NO \`bridgeToken\`.
|
|
511
|
+
The server mints one, stores it on the user's connection row, copies it into the
|
|
512
|
+
placed screens' metadata, and returns it to you as \`bridgeToken\`. Capture it.
|
|
498
513
|
|
|
499
|
-
|
|
514
|
+
**3. Start the persistent bridge adopting that token** (single line; prefer the
|
|
515
|
+
env var so the secret does not appear in \`ps\`):
|
|
516
|
+
|
|
517
|
+
\`\`\`bash
|
|
518
|
+
AGENT_NATIVE_BRIDGE_TOKEN="<bridgeToken from step 2>" npx @agent-native/core@latest design connect --url http://localhost:5173 --root . --daemon
|
|
519
|
+
\`\`\`
|
|
520
|
+
|
|
521
|
+
(Equivalently, pass \`--bridge-token <token>\`.) This starts a detached bridge on
|
|
522
|
+
\`http://127.0.0.1:7331\`, adopts the server-minted token — so bridge and row
|
|
523
|
+
agree and live-edit authorizes with no self-registration — and stays alive after
|
|
524
|
+
the command exits.
|
|
525
|
+
|
|
526
|
+
For a manual health/manifest check on the running bridge:
|
|
500
527
|
|
|
501
528
|
\`\`\`bash
|
|
502
529
|
curl http://127.0.0.1:7331/manifest.json
|
|
503
530
|
\`\`\`
|
|
504
531
|
|
|
505
|
-
|
|
506
|
-
\`--dry-run\`
|
|
507
|
-
|
|
532
|
+
Only use \`--json\` for the step-1 route probe. Never use \`--json\`, \`--once\`,
|
|
533
|
+
or \`--dry-run\` for the durable step-3 bridge: they print the manifest and exit,
|
|
534
|
+
so Design falls back to a non-editable live iframe.
|
|
508
535
|
|
|
509
536
|
## Action Flow
|
|
510
537
|
|
|
511
538
|
Prefer the single authenticated \`open-visual-edit\` action. It registers or
|
|
512
|
-
refreshes the localhost bridge,
|
|
513
|
-
URL-backed screens, stores the active
|
|
514
|
-
overview mode in one call. This avoids
|
|
515
|
-
synthetic CLI user and then handing the browser
|
|
516
|
-
shadowed by an existing session.
|
|
539
|
+
refreshes the localhost bridge connection, mints and stores the bridge token,
|
|
540
|
+
creates or reuses a Design project, places URL-backed screens, stores the active
|
|
541
|
+
visual-edit context, and navigates to overview mode in one call. This avoids
|
|
542
|
+
creating a private design under a synthetic CLI user and then handing the browser
|
|
543
|
+
a tokenized URL that may be shadowed by an existing session.
|
|
544
|
+
|
|
545
|
+
Call it BEFORE starting the durable bridge (step 3 above): it does not contact
|
|
546
|
+
the bridge, so the bridge need not be running yet, and you need its returned
|
|
547
|
+
\`bridgeToken\` to start the bridge with a matching secret. Omit \`bridgeToken\`
|
|
548
|
+
on the call so the server mints one.
|
|
517
549
|
|
|
518
550
|
\`\`\`bash
|
|
519
551
|
pnpm action open-visual-edit '{
|
|
@@ -526,8 +558,12 @@ pnpm action open-visual-edit '{
|
|
|
526
558
|
}'
|
|
527
559
|
\`\`\`
|
|
528
560
|
|
|
529
|
-
The action returns \`designId\`, \`connectionId\`, \`
|
|
530
|
-
\`openUrl\`. Keep
|
|
561
|
+
The action returns \`designId\`, \`connectionId\`, \`bridgeToken\`, \`screens\`,
|
|
562
|
+
\`urlPath\`, and \`openUrl\`. Keep \`designId\`/\`connectionId\` in the chat context
|
|
563
|
+
for follow-ups, and pass \`bridgeToken\` to \`design connect\` (step 3) to start
|
|
564
|
+
the bridge. On follow-up calls reusing an existing \`connectionId\`, the same
|
|
565
|
+
token is returned (it is minted once and reused), so the running bridge stays
|
|
566
|
+
valid.
|
|
531
567
|
|
|
532
568
|
For a numbered flow the user describes in chat, keep the labels and order:
|
|
533
569
|
|