@agent-native/dispatch 0.2.12 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/start-workspace-app-creation.js +1 -1
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/components/app-keys-popover.js +3 -3
- package/dist/components/app-keys-popover.js.map +1 -1
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +5 -1
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts +6 -0
- package/dist/components/workspace-app-card.d.ts.map +1 -0
- package/dist/components/workspace-app-card.js +12 -0
- package/dist/components/workspace-app-card.js.map +1 -0
- package/dist/lib/workspace-apps.d.ts +15 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -0
- package/dist/lib/workspace-apps.js +9 -0
- package/dist/lib/workspace-apps.js.map +1 -0
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +1 -5
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +3 -20
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/overview.d.ts.map +1 -1
- package/dist/routes/pages/overview.js +2 -20
- package/dist/routes/pages/overview.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +5 -1
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.d.ts.map +1 -1
- package/dist/server/plugins/agent-chat.js +1 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/integrations.d.ts.map +1 -1
- package/dist/server/plugins/integrations.js +2 -0
- package/dist/server/plugins/integrations.js.map +1 -1
- package/package.json +2 -2
- package/src/actions/start-workspace-app-creation.ts +1 -1
- package/src/components/app-keys-popover.tsx +3 -3
- package/src/components/create-app-popover.tsx +5 -1
- package/src/components/workspace-app-card.tsx +85 -0
- package/src/lib/workspace-apps.ts +21 -0
- package/src/routes/pages/apps.$appId.tsx +4 -17
- package/src/routes/pages/apps.tsx +6 -89
- package/src/routes/pages/overview.tsx +5 -84
- package/src/server/lib/app-creation-store.ts +5 -1
- package/src/server/plugins/agent-chat.ts +1 -0
- package/src/server/plugins/integrations.ts +2 -0
|
@@ -9,23 +9,10 @@ import {
|
|
|
9
9
|
import { DispatchShell } from "@/components/dispatch-shell";
|
|
10
10
|
import { Badge } from "@/components/ui/badge";
|
|
11
11
|
import { Button } from "@/components/ui/button";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
description?: string;
|
|
17
|
-
path: string;
|
|
18
|
-
url?: string | null;
|
|
19
|
-
status?: "ready" | "pending";
|
|
20
|
-
statusLabel?: string;
|
|
21
|
-
builderUrl?: string | null;
|
|
22
|
-
branchName?: string | null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function workspaceAppHref(app: WorkspaceAppSummary): string | null {
|
|
26
|
-
if (app.status === "pending") return app.builderUrl || null;
|
|
27
|
-
return app.path || app.url || null;
|
|
28
|
-
}
|
|
12
|
+
import {
|
|
13
|
+
workspaceAppHref,
|
|
14
|
+
type WorkspaceAppSummary,
|
|
15
|
+
} from "@/lib/workspace-apps";
|
|
29
16
|
|
|
30
17
|
export function meta() {
|
|
31
18
|
return [{ title: "Workspace app - Dispatch" }];
|
|
@@ -1,37 +1,10 @@
|
|
|
1
1
|
import { useActionQuery } from "@agent-native/core/client";
|
|
2
|
-
import {
|
|
3
|
-
IconArrowUpRight,
|
|
4
|
-
IconApps,
|
|
5
|
-
IconClockHour4,
|
|
6
|
-
IconPlus,
|
|
7
|
-
} from "@tabler/icons-react";
|
|
8
|
-
import { AppKeysPopover } from "@/components/app-keys-popover";
|
|
2
|
+
import { IconApps, IconPlus } from "@tabler/icons-react";
|
|
9
3
|
import { CreateAppPopover } from "@/components/create-app-popover";
|
|
10
4
|
import { DispatchShell } from "@/components/dispatch-shell";
|
|
11
|
-
import {
|
|
5
|
+
import { WorkspaceAppCard } from "@/components/workspace-app-card";
|
|
12
6
|
import { Button } from "@/components/ui/button";
|
|
13
|
-
|
|
14
|
-
interface WorkspaceAppSummary {
|
|
15
|
-
id: string;
|
|
16
|
-
name: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
path: string;
|
|
19
|
-
url?: string | null;
|
|
20
|
-
isDispatch: boolean;
|
|
21
|
-
status?: "ready" | "pending";
|
|
22
|
-
statusLabel?: string;
|
|
23
|
-
builderUrl?: string | null;
|
|
24
|
-
branchName?: string | null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function workspaceAppHref(app: WorkspaceAppSummary): string | null {
|
|
28
|
-
if (app.status === "pending") return app.builderUrl || null;
|
|
29
|
-
return app.path || app.url || null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function isPendingBuilderHref(app: WorkspaceAppSummary): boolean {
|
|
33
|
-
return app.status === "pending" && !!app.builderUrl;
|
|
34
|
-
}
|
|
7
|
+
import type { WorkspaceAppSummary } from "@/lib/workspace-apps";
|
|
35
8
|
|
|
36
9
|
export function meta() {
|
|
37
10
|
return [{ title: "Apps — Dispatch" }];
|
|
@@ -94,65 +67,9 @@ export default function AppsRoute() {
|
|
|
94
67
|
</div>
|
|
95
68
|
|
|
96
69
|
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
|
|
97
|
-
{typedApps.map((app) =>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// those in a new tab. Ready workspace apps stay in-window
|
|
101
|
-
// so the cards work inside the Builder webview, where new
|
|
102
|
-
// tabs would escape to the host browser.
|
|
103
|
-
const openInNewTab = isPendingBuilderHref(app);
|
|
104
|
-
return (
|
|
105
|
-
<a
|
|
106
|
-
key={app.id}
|
|
107
|
-
href={href ?? undefined}
|
|
108
|
-
target={openInNewTab ? "_blank" : undefined}
|
|
109
|
-
rel={openInNewTab ? "noreferrer" : undefined}
|
|
110
|
-
aria-disabled={!href}
|
|
111
|
-
className="group rounded-lg border bg-card p-4 transition hover:border-foreground/30 aria-disabled:pointer-events-none aria-disabled:opacity-60"
|
|
112
|
-
>
|
|
113
|
-
<div className="flex items-start justify-between gap-3">
|
|
114
|
-
<div className="min-w-0">
|
|
115
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
116
|
-
<h3 className="truncate text-sm font-semibold text-foreground">
|
|
117
|
-
{app.name}
|
|
118
|
-
</h3>
|
|
119
|
-
{app.status === "pending" ? (
|
|
120
|
-
<Badge
|
|
121
|
-
variant="outline"
|
|
122
|
-
className="shrink-0 gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300"
|
|
123
|
-
>
|
|
124
|
-
<IconClockHour4 size={12} />
|
|
125
|
-
Building
|
|
126
|
-
</Badge>
|
|
127
|
-
) : null}
|
|
128
|
-
</div>
|
|
129
|
-
<p className="mt-1 truncate font-mono text-xs text-muted-foreground">
|
|
130
|
-
{app.path}
|
|
131
|
-
</p>
|
|
132
|
-
{app.status === "pending" && app.branchName ? (
|
|
133
|
-
<p className="mt-1 truncate text-xs text-muted-foreground">
|
|
134
|
-
Branch: {app.branchName}
|
|
135
|
-
</p>
|
|
136
|
-
) : null}
|
|
137
|
-
{app.description ? (
|
|
138
|
-
<p className="mt-2 line-clamp-2 text-xs leading-relaxed text-muted-foreground">
|
|
139
|
-
{app.description}
|
|
140
|
-
</p>
|
|
141
|
-
) : null}
|
|
142
|
-
</div>
|
|
143
|
-
<div className="flex shrink-0 items-center gap-1">
|
|
144
|
-
{app.status === "ready" ? (
|
|
145
|
-
<AppKeysPopover appId={app.id} appName={app.name} />
|
|
146
|
-
) : null}
|
|
147
|
-
<IconArrowUpRight
|
|
148
|
-
size={16}
|
|
149
|
-
className="text-muted-foreground transition group-hover:text-foreground"
|
|
150
|
-
/>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
</a>
|
|
154
|
-
);
|
|
155
|
-
})}
|
|
70
|
+
{typedApps.map((app) => (
|
|
71
|
+
<WorkspaceAppCard key={app.id} app={app} />
|
|
72
|
+
))}
|
|
156
73
|
|
|
157
74
|
<CreateAppPopover />
|
|
158
75
|
</div>
|
|
@@ -21,11 +21,10 @@ import {
|
|
|
21
21
|
IconShieldCheck,
|
|
22
22
|
type IconProps,
|
|
23
23
|
} from "@tabler/icons-react";
|
|
24
|
-
import { AppKeysPopover } from "@/components/app-keys-popover";
|
|
25
24
|
import { CreateAppPopover } from "@/components/create-app-popover";
|
|
26
25
|
import { DispatchShell } from "@/components/dispatch-shell";
|
|
26
|
+
import { WorkspaceAppCard } from "@/components/workspace-app-card";
|
|
27
27
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
28
|
-
import { Badge } from "@/components/ui/badge";
|
|
29
28
|
import { Button } from "@/components/ui/button";
|
|
30
29
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
31
30
|
import {
|
|
@@ -34,6 +33,7 @@ import {
|
|
|
34
33
|
TooltipTrigger,
|
|
35
34
|
} from "@/components/ui/tooltip";
|
|
36
35
|
import { submitOverviewPrompt } from "@/lib/overview-chat";
|
|
36
|
+
import type { WorkspaceAppSummary } from "@/lib/workspace-apps";
|
|
37
37
|
|
|
38
38
|
interface IntegrationStatus {
|
|
39
39
|
platform: string;
|
|
@@ -67,28 +67,6 @@ const ZERO_TASK_QUEUE_STATS: TaskQueueStats = {
|
|
|
67
67
|
recent_failures: [],
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
-
interface WorkspaceAppSummary {
|
|
71
|
-
id: string;
|
|
72
|
-
name: string;
|
|
73
|
-
description?: string;
|
|
74
|
-
path: string;
|
|
75
|
-
url?: string | null;
|
|
76
|
-
isDispatch: boolean;
|
|
77
|
-
status?: "ready" | "pending";
|
|
78
|
-
statusLabel?: string;
|
|
79
|
-
builderUrl?: string | null;
|
|
80
|
-
branchName?: string | null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function workspaceAppHref(app: WorkspaceAppSummary): string | null {
|
|
84
|
-
if (app.status === "pending") return app.builderUrl || null;
|
|
85
|
-
return app.path || app.url || null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function isPendingBuilderHref(app: WorkspaceAppSummary): boolean {
|
|
89
|
-
return app.status === "pending" && !!app.builderUrl;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
70
|
const HOME_CHAT_SUGGESTIONS = [
|
|
93
71
|
"Create a lightweight customer onboarding app",
|
|
94
72
|
"Ask Slides to draft a board update from our latest metrics",
|
|
@@ -186,66 +164,9 @@ function WorkspaceAppsSection({
|
|
|
186
164
|
? Array.from({ length: 6 }).map((_, index) => (
|
|
187
165
|
<AppCardSkeleton key={index} />
|
|
188
166
|
))
|
|
189
|
-
: visibleApps.map((app) =>
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// editor URL); open those in a new tab. Ready workspace apps
|
|
193
|
-
// navigate the current window so this works inside the
|
|
194
|
-
// Builder webview, where new tabs would try to open in the
|
|
195
|
-
// host browser and break the embedded session.
|
|
196
|
-
const openInNewTab = isPendingBuilderHref(app);
|
|
197
|
-
return (
|
|
198
|
-
<a
|
|
199
|
-
key={app.id}
|
|
200
|
-
href={href ?? undefined}
|
|
201
|
-
target={openInNewTab ? "_blank" : undefined}
|
|
202
|
-
rel={openInNewTab ? "noreferrer" : undefined}
|
|
203
|
-
aria-disabled={!href}
|
|
204
|
-
className="group min-h-32 rounded-lg border bg-card p-4 transition hover:border-foreground/30 aria-disabled:pointer-events-none aria-disabled:opacity-60"
|
|
205
|
-
>
|
|
206
|
-
<div className="flex h-full items-start justify-between gap-3">
|
|
207
|
-
<div className="min-w-0">
|
|
208
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
209
|
-
<h3 className="truncate text-sm font-semibold text-foreground">
|
|
210
|
-
{app.name}
|
|
211
|
-
</h3>
|
|
212
|
-
{app.status === "pending" ? (
|
|
213
|
-
<Badge
|
|
214
|
-
variant="outline"
|
|
215
|
-
className="shrink-0 gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300"
|
|
216
|
-
>
|
|
217
|
-
<IconClockHour4 size={12} />
|
|
218
|
-
Building
|
|
219
|
-
</Badge>
|
|
220
|
-
) : null}
|
|
221
|
-
</div>
|
|
222
|
-
<p className="mt-1 truncate font-mono text-xs text-muted-foreground">
|
|
223
|
-
{app.path}
|
|
224
|
-
</p>
|
|
225
|
-
{app.status === "pending" && app.branchName ? (
|
|
226
|
-
<p className="mt-1 truncate text-xs text-muted-foreground">
|
|
227
|
-
Branch: {app.branchName}
|
|
228
|
-
</p>
|
|
229
|
-
) : null}
|
|
230
|
-
{app.description ? (
|
|
231
|
-
<p className="mt-2 line-clamp-2 text-xs leading-relaxed text-muted-foreground">
|
|
232
|
-
{app.description}
|
|
233
|
-
</p>
|
|
234
|
-
) : null}
|
|
235
|
-
</div>
|
|
236
|
-
<div className="flex shrink-0 items-center gap-1">
|
|
237
|
-
{app.status === "ready" ? (
|
|
238
|
-
<AppKeysPopover appId={app.id} appName={app.name} />
|
|
239
|
-
) : null}
|
|
240
|
-
<IconArrowUpRight
|
|
241
|
-
size={16}
|
|
242
|
-
className="text-muted-foreground transition group-hover:text-foreground"
|
|
243
|
-
/>
|
|
244
|
-
</div>
|
|
245
|
-
</div>
|
|
246
|
-
</a>
|
|
247
|
-
);
|
|
248
|
-
})}
|
|
167
|
+
: visibleApps.map((app) => (
|
|
168
|
+
<WorkspaceAppCard key={app.id} app={app} className="min-h-32" />
|
|
169
|
+
))}
|
|
249
170
|
|
|
250
171
|
{!showSkeletons ? <CreateAppPopover /> : null}
|
|
251
172
|
</div>
|
|
@@ -864,6 +864,10 @@ function buildWorkspaceAppPrompt(input: {
|
|
|
864
864
|
`Dispatch workspace resources selected for this app:\n${resourceList}`,
|
|
865
865
|
"",
|
|
866
866
|
`Use the workspace app layout: create it under apps/${appId}, mount it at /${appId}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
|
|
867
|
+
`Important routing rule: from outside the app, link to /${appId}; inside apps/${appId}, React Router routes are app-local. Use <Link to="/review"> and navigate("/review"), not "/${appId}/review"; APP_BASE_PATH supplies the mounted prefix, and hardcoding it causes doubled URLs like /${appId}/${appId}/review.`,
|
|
868
|
+
"Existing first-party apps are neighbors, not implementation details for this app. If the user prompt mentions Mail, Calendar, Analytics, Dispatch, or other templates, treat them as existing hosted/connected apps that this app can link to or call through A2A/default connected agents. For example, Mail, Calendar, and Analytics already exist at https://mail.agent-native.com, https://calendar.agent-native.com, and https://analytics.agent-native.com.",
|
|
869
|
+
`Do not clone first-party templates, create wrapper apps, or scaffold child apps/routes for Mail, Calendar, Analytics, etc. inside apps/${appId} just so this app can access them. If the request is a cross-app dashboard or overview, build only the new dashboard/overview app and delegate to the existing apps for domain work.`,
|
|
870
|
+
"Only create another first-party app copy when the user explicitly asks for a customized fork/copy of that app; otherwise keep using the hosted/shared app so improvements to the base template keep flowing to users.",
|
|
867
871
|
selectedKeys.length
|
|
868
872
|
? `Dispatch will create pending vault requests for the selected keys for appId "${appId}" after this app creation request is accepted. Do not grant or sync vault keys directly from the app-creation branch.`
|
|
869
873
|
: "Do not grant or request any Dispatch vault keys unless the user asks later.",
|
|
@@ -873,7 +877,7 @@ function buildWorkspaceAppPrompt(input: {
|
|
|
873
877
|
"",
|
|
874
878
|
"Agent-native rules (these are the framework's contract — not optional):",
|
|
875
879
|
`- Persist ALL data in SQL via Drizzle. Add tables to apps/${appId}/server/db/schema.ts and migrations to apps/${appId}/server/plugins/db.ts. NEVER use localStorage, sessionStorage, IndexedDB, or in-memory state for anything the user expects to persist — agent and UI must read the same source of truth.`,
|
|
876
|
-
`- Define every create/read/update/delete as an action in apps/${appId}/actions/ using defineAction. The agent calls these as tools and the frontend calls them
|
|
880
|
+
`- Define every create/read/update/delete as an action in apps/${appId}/actions/ using defineAction. The agent calls these as tools and the frontend calls them via useActionQuery / useActionMutation. If you must raw-fetch framework action endpoints, use agentNativePath("/_agent-native/actions/<name>") so mounted apps call the right URL. Don't add /api/* routes for CRUD.`,
|
|
877
881
|
"- Build the UI from shadcn/ui components in app/components/ui/ (Button, Input, Dialog, Popover, Card, etc.) and Tailwind utilities. Don't author bespoke CSS classes in global.css unless you genuinely need a primitive that shadcn doesn't ship.",
|
|
878
882
|
"- Use Tabler Icons (@tabler/icons-react) for every icon. Never use emojis as icons.",
|
|
879
883
|
`- Expose what the user is looking at via application_state (navigation.view, selection, etc.) so the agent has live context. Mirror the patterns in templates/mail or templates/slides.`,
|
|
@@ -29,6 +29,7 @@ Use the standard workspace primitives:
|
|
|
29
29
|
- Use custom agent profiles in agents/*.md for local spawned work and remote-agents/*.json for remote A2A apps.
|
|
30
30
|
- When answering whether workspace apps expose agent cards or A2A endpoints, call list-workspace-apps with includeAgentCards=true. If you have not requested that probe, absence of agent-card fields means unchecked, not unavailable.
|
|
31
31
|
- When creating a new workspace app, create a separate app under apps/<app-id> with apps/<app-id>/package.json, mount it at /<app-id>, use relative /<app-id> links, never hardcode localhost or dev ports, use shadcn/ui with @tabler/icons-react rather than lucide-react, and ensure the React Router client entry preserves APP_BASE_PATH/VITE_APP_BASE_PATH via appBasePath(). There is no separate workspace app registry to edit.
|
|
32
|
+
- Treat first-party apps such as Mail, Calendar, Analytics, and Dispatch as existing hosted/connected neighbors available through links and A2A/default connected agents. Do not create wrapper apps, child apps, nested routes, or cloned template copies just to give a new app access to them; build only the genuinely new workflow and delegate cross-app work to those existing apps.
|
|
32
33
|
|
|
33
34
|
When a user asks for something like a digest, reminder, routing rule, or saved behavior:
|
|
34
35
|
- First decide whether it should be a resource, a recurring job, a destination, or a delegated task.
|
|
@@ -13,6 +13,7 @@ Default posture:
|
|
|
13
13
|
- Heavily delegate domain work to specialized agents through A2A (call-agent) when another app owns the job. Apps you can delegate to include slides (decks/presentations), analytics (data/dashboards), content (docs/articles), videos (Remotion compositions), forms (form builder), clips (screen recordings), design (visual designs), and images (brand image libraries and generated raster imagery).
|
|
14
14
|
- Use list-connected-agents to see what agents are available before assuming a request must be handled locally.
|
|
15
15
|
- When asked whether workspace apps expose agent cards or A2A endpoints, call list-workspace-apps with includeAgentCards=true. Without that probe, missing agent-card fields mean unchecked, not unavailable.
|
|
16
|
+
- Treat first-party apps such as Mail, Calendar, Analytics, and Dispatch as existing hosted/connected neighbors available through links and A2A/default connected agents. Do not create wrapper apps, child apps, nested routes, or cloned template copies just to give a new app access to them; build only the genuinely new workflow and delegate cross-app work to those existing apps.
|
|
16
17
|
- Keep durable memory and operating instructions in resources rather than ephemeral chat.
|
|
17
18
|
- Reply in the originating thread unless the user explicitly asks you to send to a saved destination.
|
|
18
19
|
|
|
@@ -21,6 +22,7 @@ When a user asks for something:
|
|
|
21
22
|
- After call-agent returns an answer, RELAY IT DIRECTLY to the user with at most a one-line preface — do not rephrase, summarize, or add commentary. The downstream agent already crafted the answer; your job is delivery, not editing. This minimizes round-trips and keeps the user-visible reply fast.
|
|
22
23
|
- Exception: if the downstream agent reports a missing model/provider credential, do not name exact env vars, Vault keys, tokens, or secrets. Say the target app needs an LLM connection and recommend connecting Builder/managed LLM for that app; keep bring-your-own provider keys as a secondary option only if the user asks.
|
|
23
24
|
- If the user asks to create, build, make, scaffold, or generate an "agent" from Dispatch chat or by tagging @agent-native in Slack, email, or Telegram, first classify the ask. If it is a simple Dispatch-native behavior like a reminder, digest, monitor, routing rule, saved instruction, or recurring workflow, create or update the recurring job/resource/destination in Dispatch. If it is a robust unique product or teammate that needs its own UI, data model, actions, integrations, or domain workflow, treat it as a new workspace app and call start-workspace-app-creation.
|
|
25
|
+
- If a new-app prompt asks for access to Mail, Calendar, Analytics, or similar first-party app data/agents, keep using the existing hosted/connected app and A2A path. Do not ask Builder to scaffold those apps as children of the new app unless the user explicitly asks for a customized fork/copy.
|
|
24
26
|
- If the user explicitly asks for a new app or workspace app, call start-workspace-app-creation with their prompt. Do not satisfy a new-app request by adding a route, page, component, or file inside apps/starter or another existing app unless the user explicitly asks to modify that existing app. If the request is too vague to classify, ask one concise follow-up. If the action returns mode "builder", reply with the Builder branch URL; Builder is responsible for creating the separate workspace app under apps/<app-id>, mounting it at /<app-id>, ensuring apps/<app-id>/package.json exists so Dispatch discovers it, using relative /<app-id> links instead of hardcoded localhost/dev ports, and preserving APP_BASE_PATH/VITE_APP_BASE_PATH via appBasePath() in the React Router client entry. There is no separate workspace app registry to edit. If it returns mode "local-agent", tell the user it is ready for the local code agent and include the returned app path/prompt summary. If it returns mode "coming-soon" or "builder-unavailable", explain the missing Builder setup and ask them to connect/configure Builder.
|
|
25
27
|
- For digests, reminders, or saved behavior, prefer recurring jobs, resources, or destinations over chat replies.
|
|
26
28
|
- Keep responses concise and operational — messaging platforms have character limits.
|