Repository navigation
feat(platform): headless chat - react hook - #315
Conversation
🚀 Package Preview Available!Install this PR's preview build with npm: npm i @base44-preview/sdk@0.8.54-pr.315.e54dc54Prefer not to change any import paths? Install using npm alias so your code still imports npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.54-pr.315.e54dc54"Or add it to your {
"dependencies": {
"@base44/sdk": "npm:@base44-preview/sdk@0.8.54-pr.315.e54dc54"
}
}
Preview published to npm registry — try new features instantly! |
51bc094 to
17c2d1a
Compare
🚀 Package Preview Available! (
|
A new subpath, @base44/platform/react, with one hook: useBase44Chat. It runs the AI chat for one app in the partner's own UI, on top of the platform client, and renders nothing. React 18 or 19 is an optional peer, so the client and server entries stay framework-free. - backend: four calls the partner implements (createApp, openLiveSession, sendMessage, submitToolCallInput). openLiveSession returns Base44's socket-session body unchanged, and is called again on every renewal. No credential reaches the browser. - items: the conversation, oldest first. Each step is one tool call, and a waiting step on the last assistant message carries its question, bound to the actions that answer it (choice, secrets, approval; every kind can be declined). A kind this release doesn't know is declined once per tool call. A sent prompt shows at once as a pending item until Base44's own message arrives. - status: error > waiting > building > submitted > ready. A failed build is error with code build_failed; submitted runs from the call until Base44 reports work, a reply or a queue change. - connection: connecting, connected, or disconnected once live updates stop for good, with error saying why. - send needs an app and create makes one; while appId is null the chat follows the app create made. - Rejoins keep messages older than the snapshot's window; a status older than the newest seen is ignored, since Base44 resends an earlier turn's. - Actions never throw: a failure lands in error, and a question whose answer failed opens again. The JSDoc follows the SDK docs guidelines, with @example blocks for the reference pages. Tests cover the item mapping, the hook under jsdom with a recorded platform client, the public types, and the published /react entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3dc0d96 to
1f80c84
Compare
ozsay
left a comment
There was a problem hiding this comment.
The public contract
Fields the socket already sends that the hook drops. All are in builder.events.generated.ts; adding them is additive. Inspired by comparing the contract with AG-UI.
Ids and links
StatusObject.turn_id: the turn the status belongs to (AG-UI's run id). Could beBase44Chat.turnIdandChatItem.turnId.additional_message_params.client_creation_id: lets a pending prompt be matched by id, not text (see the pending-prompt finding).Message.checkpoint_id: the app before or after a turn. Enables "restore to here" UIs.- Questions: expose
toolCallIdandmessageIdas data next to the bound methods, so items can be logged or stored.
Steps
display.summary(bash, exec, screenshot, shell),display.entity_nameandrecord_count,arguments.summaryfor entity updates and deletes: far better labels than tool name plus files.resultson media tools (ImageResultwithimage_urlandstatus) and theimage.resolvedevent: show generated images.task.progressed(current,total,percentage, keyed bytool_call_id): a progress bar on a running step.auto_approvedandmutation_appliedon every call: an "auto-approved" badge and "no changes made".display.writes_entities: tells a partner to refresh the preview.
Questions
QuestionAnswer.custom_textandQuestion.type: the choice answer can only send picked labels, so a free-text question cannot be answered.user_inputon question calls: what was answered stays visible after the question closes; today the question disappears.- Approval
guardanddetails(entity_name,change_type,changed_ops,function_name,method,inspection_failed): the approval exposes only the tool name and a reason. Question.coverswithUpdatePlanArguments,PrdArgumentsand theplan_mode/plan_approvedmessage flags: everything a plan-mode UI needs.
Chat-level state and events
snapshot.queueandqueue.updated(items,is_paused): the queue, and why a pending prompt waits (the builder pauses it while a question is open). The description defers the queue to another PR.preview.reload_requested,preview.navigation_requestedandfiles.changed: partners embedding a preview need these, and today only the raw client gives them.
Not candidates: system role (never sent), text deltas (messages are replaced whole).
From the review on #315: - An answer's submission ends once its call stops waiting, and any newer status ends a submission, so status no longer sticks at submitted when Base44 stayed processing while the question waited. - A send, answer or create that fails after the chat switched apps no longer touches the new app's error or status. - A pending prompt settles only on an exact text match, so another client's prompt to the same app never settles ours. - create while the chat follows a set appId drops its pending prompt, so it can't reappear when the new app is picked later. Choice answers now carry free text (answer(picked, texts?)), and send a single pick as selected_label and several as selected_labels, the way Base44's builder does; Base44 reads a design or palette pick only from selected_label. ChoiceEntry gains Base44's question type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…maries From the review on #315, the three fields partners need most: - ApprovalQuestion gains guard and details (summary, entityName, changeType, changedOps, functionName, method, inspectionFailed), so the user sees what they approve instead of a tool name alone. - ChatStep gains answered: what the user answered on a choice, next to each question, so the chat's history keeps it after the question closes. - ChatStep gains summary, Base44's description of the step, and label uses it, then the entity and record count, then the tool and its files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the review on #315, the fields that only pass on data Base44 already sends: - Every question carries toolCallId and messageId as data, beside the actions already bound to them, so a partner can log or store it. - ChatItem.checkpointId: the checkpoint Base44 ties to the message. - Base44Chat.turnId: the user message whose turn the current status belongs to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
a09735c to
c77c79d
Compare
|
@ozsay thanks, the AG-UI comparison was useful. On the fields the hook drops, I took the ones without which a partner's chat breaks or misleads, and left the rest until a partner asks: adding a field later is free, and taking one out after release breaks partners. Added
Left for later
Could you take another look? 🤖 Generated with Claude Code |
…ws it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main added the webhooks module to @base44/platform/server (#319). The package.json conflict keeps main's engines field beside this branch's single devDependencies block; the lockfile is main's plus the React dev dependencies, resolved from registry.npmjs.org. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @amitbardos, re-reviewed at 5ffd6d3. All five comments are fixed, and each fix has a test:
The new fields (free-text answers, One low-severity edge in the exact-match fix. The removed fallback was also the only way out for a pending prompt whose text never arrives. Base44 keeps the text as sent for a plain send, but the public queue API can edit ( On Nits (no change needed):
🤖 Generated with Claude Code |
* Tiny Sunny: run the chat on @base44/platform/react's useBase44Chat The chat's own Base44 layer (useLiveChat.ts: the socket, merging and sorting messages, the status, the question formats) is replaced by the hook, and ToolQuestion takes the hook's bound question instead of a raw tool call. - Chat draws items, steps and questions from the hook, shows a sent prompt at once (faded while pending), and keeps Send disabled unless the status is ready or error. - Chat no longer remounts per app, so the first prompt survives create. - openLiveSession passes Base44's socket-session body through, and sendMessage and submitToolCallInput return after 3 seconds: Base44 holds both open for the whole turn, and Next.js runs one server action at a time. - @base44/platform comes from base44/javascript-sdk#315's preview package until that PR is released. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: the released @base44/platform 0.3.0, with free-text answers, approval details and answers - @base44/platform is the released ^0.3.0 instead of #315's preview package. - A text_input question gets a text field, and the answer sends it. - An approval shows what the action would do: the entity, the change, the access, the function, as far as Base44's check says. - A step that was answered keeps its questions and answers under its line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: @base44/platform 0.4.0; "the AI", not "the builder" 0.4.0 renames the client's builder module to chat; Tiny Sunny only uses useBase44Chat, whose API is unchanged, so this is the version bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: one waitForRefusal for the held-open chat requests; log late failures sendMessage and submitToolCallInput share the 3-second cutoff instead of repeating it. A failure that lands after the cutoff has no caller left, so it is logged on the server rather than dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: an approval shows its action and reason only; current netlify.toml comment describe() repeated the summary the hook already puts in reason, so the approval line drops the details. The secrets-scan comment no longer names versions that both sides have moved past. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: one component per question kind ToolQuestion picks Choice, Secrets or Approval by kind, so each keeps only its own state. They share one Actions row for Submit/Allow and Decline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: the AI's messages render as Markdown The AI answers in Markdown, so its text showed raw ** and backticks. It now goes through react-markdown, the version Sunny already installs, with a few chat styles for lists, code and links. Links open in a new tab. The user's own prompts stay plain text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: the hook is useChat @base44/platform drops the Base44 prefix from its React entry (base44/javascript-sdk#345), so Chat.tsx uses useChat, UseChatResult and ChatBackend. The new names ship in 0.5.0; the dependency moves to ^0.5.0 once it is published. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tiny Sunny: @base44/platform ^0.5.0 0.5.0 is published with the new React names, so the dependency and the lockfile move to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Start here:
src/react/chat.types.tsis the whole public surface, anduseBase44Chat.tsthe hook. Usage lives in their JSDoc@exampleblocks, which the Mintlify pipeline turns into the reference's Example tabs.What
A new subpath,
@base44/platform/react, with one hook:useBase44Chat. It runs the AI chat for one app in the partner's own UI, on top of the platform client, and renders nothing. The contract is the one in the design doc "Partner chat: design".backend: four calls the partner implements (createApp,openLiveSession,sendMessage,submitToolCallInput), in any language behind them.openLiveSessionreturns Base44's socket-session body unchanged, and the client calls it again on every renewal. No credential reaches the browser.items: the conversation, oldest first:role,text,createdAt,pendingandsteps, one per tool call (tool,files,label,status). A sent prompt shows at once withpending: trueuntil Base44's own message arrives, matched by exact text.question(choice,secrets,approval), bound to its own tool call. A choice answers with picked labels and optional free text (custom_text), sent the way the builder sends them. Every kind can be declined; a kind this release doesn't know is declined once per tool call.status:error>waiting>building>submitted>ready. A failed build iserrorwith codebuild_failed.submittedruns from the call until Base44 reports a newer status, a reply or a queue change, or an answered call stops waiting.connection:connectinguntil the first snapshot, thenconnected, anddisconnectedonce live updates stop for good, witherrorsaying why. A reconnecting state needs a client callback and comes in its own PR.send(prompt)needs an app;create(prompt)makes one, and whileappIdisnullthe chat follows the app it made. A setappIdalways wins.error; a question whose answer failed opens again.Not in this PR: showing or editing Base44's prompt queue, a reconnecting state, and loading messages older than the last 50. The design doc's Next section lists them.
Packaging
exports["./react"]plustypesVersionsfor node10 resolution.reactis an optional peer; the client and server entries never import it. The tarball test asserts it is never a dependency.Tests
tests/unit/react/chat-items.test.ts: the message-to-items mapping, without React.tests/unit/react/useBase44Chat.test.ts: the hook under jsdom with a recorded platform client: status precedence, pending prompts, stale statuses, renewal, switching apps, answers and automatic declines.tests/types/react.types.ts: compiles against the subpath.tests/package.test.mjs: the published/reactentry resolves at runtime and under NodeNext, Bundler and Node resolution.🤖 Generated with Claude Code