Skip to content

Commit fb09eeb

Browse files
committed
show invite authorization errors clearly
1 parent 6618ba2 commit fb09eeb

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

apps/kitchen/src/app/agents/page.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ import type { AgentProtocol, AgentStatus, RegisteredAgent } from "@/types";
1717
type ProtocolFilter = "all" | AgentProtocol;
1818
type StatusFilter = "all" | AgentStatus;
1919

20+
function inviteErrorMessage(error: unknown) {
21+
const message = error instanceof Error ? error.message : "Invite creation failed.";
22+
if (message.includes("Registry write authorization required")) {
23+
return "Operator key required. Paste the operator key, then click Copy Invite again.";
24+
}
25+
return message;
26+
}
27+
2028
function formatAgentOnboardingPrompt(command: string) {
2129
return [
2230
"Run this Agent Kitchen onboarding command exactly as written.",
@@ -124,8 +132,13 @@ export default function AgentRegistryPage() {
124132
}
125133
onCreateInvite={(input) => {
126134
setInviteStatus(null);
135+
setInviteCommand(null);
127136
inviteMutation.mutate(input, {
128137
onSuccess: async (result) => {
138+
if (!result.command) {
139+
setInviteStatus("Invite response did not include a command. Try again.");
140+
return;
141+
}
129142
const prompt = formatAgentOnboardingPrompt(result.command);
130143
setInviteCommand(prompt);
131144
if (await copyTextToClipboard(prompt)) {
@@ -135,7 +148,8 @@ export default function AgentRegistryPage() {
135148
}
136149
},
137150
onError: (error) => {
138-
setInviteStatus(error instanceof Error ? error.message : "Invite creation failed.");
151+
setInviteCommand(null);
152+
setInviteStatus(inviteErrorMessage(error));
139153
},
140154
});
141155
}}
@@ -150,9 +164,11 @@ export default function AgentRegistryPage() {
150164
)}
151165

152166
{(inviteCommand || inviteStatus) && (
153-
<div className="border border-sky-500/30 bg-sky-500/10 p-3">
167+
<div className={`border p-3 ${inviteCommand ? "border-sky-500/30 bg-sky-500/10" : "border-rose-500/30 bg-rose-500/10"}`}>
154168
<div className="flex flex-wrap items-center justify-between gap-2">
155-
<p className="text-xs font-semibold uppercase tracking-wide text-sky-300">Generic onboarding invite</p>
169+
<p className={`text-xs font-semibold uppercase tracking-wide ${inviteCommand ? "text-sky-300" : "text-rose-300"}`}>
170+
{inviteCommand ? "Generic onboarding invite" : "Invite not created"}
171+
</p>
156172
{inviteCommand && (
157173
<Button
158174
type="button"
@@ -170,7 +186,7 @@ export default function AgentRegistryPage() {
170186
</Button>
171187
)}
172188
</div>
173-
{inviteStatus && <p className="mt-1 text-xs text-sky-100">{inviteStatus}</p>}
189+
{inviteStatus && <p className={`mt-1 text-xs ${inviteCommand ? "text-sky-100" : "text-rose-100"}`}>{inviteStatus}</p>}
174190
{inviteCommand && <pre className="mt-2 whitespace-pre-wrap break-words text-sm text-sky-50">{inviteCommand}</pre>}
175191
</div>
176192
)}

apps/kitchen/src/components/agents/__tests__/agent-registry-page.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,21 @@ describe("AgentRegistryPage", () => {
185185
expect(execCommand).toHaveBeenCalledWith("copy");
186186
});
187187

188+
it("shows a clear operator-key error when public invite creation is unauthorized", async () => {
189+
render(<AgentRegistryPage />);
190+
191+
fireEvent.click(screen.getByText("Copy Invite"));
192+
193+
const [, options] = mutateInvite.mock.calls[0];
194+
options.onError(new Error("/api/onboarding/invite: Registry write authorization required"));
195+
196+
await waitFor(() => {
197+
expect(screen.getByText("Invite not created")).toBeInTheDocument();
198+
});
199+
expect(screen.getByText("Operator key required. Paste the operator key, then click Copy Invite again.")).toBeInTheDocument();
200+
expect(screen.queryByText("Generic onboarding invite")).not.toBeInTheDocument();
201+
});
202+
188203
it("supports A2A card registration mode", () => {
189204
render(<AgentRegistryPage />);
190205

0 commit comments

Comments
 (0)