useComposer
useComposer(selector) is available only inside a hosted composer-panel and throws elsewhere. Import it from @sota/core/hooks. Select only the field a component needs so unrelated draft changes do not force work.
| Field | Contract |
|---|---|
value | Plain-text view of the current draft. |
content | Structured text and app-reference nodes. |
references | Resolved slash, conversation, and lane-scoped app references. |
pendingToolResults | Deferred tool results belonging to this panel's exact app execution. |
applyEdit(edit) | One undoable editor transaction in replace, insert-at-cursor, or append mode. |
focus() | Moves focus to the composer editor. |
acquireLock() | Disables send, draft edits, existing-message edits, and queued auto-send while held; returns an idempotent release function. |
import { useEffect } from 'react';
import { useComposer } from '@sota/core/hooks';
export function PendingActionPanel() {
const pending = useComposer((composer) => composer.pendingToolResults);
const acquireLock = useComposer((composer) => composer.acquireLock);
const active = pending.find((item) => item.toolName === 'readCalendar');
useEffect(() => {
if (!active) return;
return acquireLock();
}, [acquireLock, active]);
if (!active) return null;
return <p>Complete the app action to continue.</p>;
}Locks are reference-counted: multiple panels or pending operations can hold them independently. Core auto-releases a lock when its surface unmounts, but app code should still return the release function from its effect. Preserve structured content; rebuilding from value flattens references.
import { useComposer } from '@sota/core/hooks';
export function InsertReportButton() {
const applyEdit = useComposer((composer) => composer.applyEdit);
return <button type="button" onClick={() => applyEdit({
mode: 'insert-at-cursor',
content: [
{ kind: 'text', text: 'Review ' },
{
kind: 'app-reference',
referenceType: 'report',
referenceId: 'report-42',
label: 'Q3 report',
fallbackText: 'Q3 report',
},
],
})}>Insert report</button>;
}pendingToolResults items contain operationId, toolCallId, canonical toolName, collision-resolved modelToolName, optional opaque data, and exact execution. Narrow app-owned data at runtime before rendering it. The pendingToolResults/acquireLock fields require platform contract 1.3.0 or newer.