Skip to content

Commit 2021b5f

Browse files
os-zhuangclaude
andauthored
feat(console): "Edit with AI" — open the build agent pre-scoped to an app's package (#2018)
ADR-0070 follow-up (UI half). Adds an "Edit with AI" action to each app in App Management that opens the build agent in a fresh conversation pre-scoped to that app's package: it navigates to `/ai/build?package=<packageId>&new=1`, and the AI chat page forwards the package as `context.packageId`. The cloud agent seeds it as the conversation's active package, so the AI's metadata reads scope to THIS app and edits bind to it from the first message (no reliance on the model calling set_active_package). Shown only for apps that have a package id. - AppManagementPage: a Sparkles "Edit with AI" button beside "Edit app". - AiChatPage: read `?package=` and forward it as `context.packageId` (threaded into ChatPane, the component that builds the chat request context). Pairs with the cloud seeding mechanism (objectstack-ai/cloud#590). Type-check clean (app-shell + console); app-shell 927 + console 4656 tests pass, 0 regressions. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 66316a3 commit 2021b5f

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

apps/console/src/pages/system/AppManagementPage.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
Star,
2626
ExternalLink,
2727
Search,
28+
Sparkles,
2829
} from 'lucide-react';
2930
import { toast } from 'sonner';
3031
import { useMetadata } from '@object-ui/app-shell';
@@ -241,6 +242,23 @@ export function AppManagementPage() {
241242
>
242243
<Pencil className="h-4 w-4" />
243244
</Button>
245+
{app._packageId ? (
246+
<Button
247+
variant="ghost"
248+
size="icon"
249+
title="Edit with AI"
250+
aria-label={`Edit ${app.label || app.name} with AI`}
251+
// ADR-0070 — open the build agent in a fresh conversation
252+
// pre-scoped to this app's package (passed as the chat
253+
// context.packageId the cloud seeds as the active package),
254+
// so the AI iterates within THIS app, not the whole env.
255+
onClick={() =>
256+
navigate(`/ai/build?package=${encodeURIComponent(app._packageId!)}&new=1`)
257+
}
258+
>
259+
<Sparkles className="h-4 w-4" />
260+
</Button>
261+
) : null}
244262
<Button
245263
variant="ghost"
246264
size="icon"

packages/app-shell/src/console/ai/AiChatPage.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,11 @@ export function AiChatPage({ apiBase: apiBaseProp, defaultAgent: defaultAgentPro
486486
// existing conversation, and the flag is stripped once the fresh id is
487487
// mirrored into the URL.
488488
const forceNewConversation = searchParams.get('new') !== null;
489+
// ADR-0070 "Edit with AI": the package the user opened to edit (from the app
490+
// list's per-app action). Forwarded to the build agent as `context.packageId`
491+
// so its metadata reads scope to that app and edits bind to it from the first
492+
// message (the agent seeds it as the conversation's active package).
493+
const editPackageId = searchParams.get('package')?.trim() || undefined;
489494
const navigate = useNavigate();
490495
const { setContext } = useNavigationContext();
491496

@@ -849,6 +854,7 @@ export function AiChatPage({ apiBase: apiBaseProp, defaultAgent: defaultAgentPro
849854
chatApi={chatApi}
850855
apiBase={apiBase}
851856
conversationId={conversationId}
857+
editPackageId={editPackageId}
852858
initialMessages={initialMessages}
853859
onSent={handleSent}
854860
onShare={() => setShareOpen(true)}
@@ -920,6 +926,9 @@ interface ChatPaneProps {
920926
chatApi: string | undefined;
921927
apiBase: string;
922928
conversationId: string | undefined;
929+
/** ADR-0070 "Edit with AI": the package the user opened to edit (from `?package=`),
930+
* forwarded to the build agent as `context.packageId` to scope it to that app. */
931+
editPackageId?: string;
923932
initialMessages: HydratedUIMessage[];
924933
onSent: (firstUserMessage?: string) => void;
925934
onShare: () => void;
@@ -935,6 +944,7 @@ function ChatPane({
935944
chatApi,
936945
apiBase,
937946
conversationId,
947+
editPackageId,
938948
initialMessages,
939949
onSent,
940950
onShare,
@@ -1040,6 +1050,9 @@ function ChatPane({
10401050
// Tell the agent the environment's publish posture so its narration
10411051
// matches reality (an auto-published build is live, not "to publish").
10421052
autoPublishAiBuilds: getRuntimeConfig().features.autoPublishAiBuilds,
1053+
// ADR-0070 "Edit with AI": scope the build agent to the app the user
1054+
// opened to edit. Cloud seeds it as the conversation's active package.
1055+
...(editPackageId ? { packageId: editPackageId } : {}),
10431056
},
10441057
},
10451058
initialMessages: hydrated,

0 commit comments

Comments
 (0)