@dani-builder/agent-contract
Zero-dependency TypeScript wire contracts for Daniworks Agent clients.
import type { ChatRequest, ChatResponse } from "@dani-builder/agent-contract";
import { parseSseEvent } from "@dani-builder/agent-contract";
The package is safe to import from browser clients: it has no Strapi or plugin peer dependency. It defines chat request/response, retrieval citation, and SSE event shapes; it does not implement a chat runtime.
Follow-up question extensions support two wire versions. The existing
FollowUpQuestionsExtension type remains version 1:
import type { FollowUpQuestionsExtension } from "@dani-builder/agent-contract";
const v1: FollowUpQuestionsExtension = {
type: "follow_up_questions",
version: 1,
payload: { questions: ["Tell me more"] },
};
Version 2 separates the displayed label from an optional submitted prompt. Import
FollowUpQuestionsV2Extension and SuggestedPrompt from the package root:
import type {
FollowUpQuestionsExtension,
FollowUpQuestionsV2Extension,
ResponseExtension,
SuggestedPrompt,
} from "@dani-builder/agent-contract";
const item: SuggestedPrompt = {
label: "Pricing",
prompt: "What does your service cost?",
};
const v2: FollowUpQuestionsV2Extension = {
type: "follow_up_questions",
version: 2,
payload: { items: [item, { label: "Tell me more" }] },
};
function submittedPrompts(extension: ResponseExtension): string[] {
if (extension.type !== "follow_up_questions") return [];
if (extension.version === 1) return extension.payload.questions;
return extension.payload.items.map((item) => item.prompt ?? item.label);
}
Discriminate on version after checking type: both versions belong to
ResponseExtension, so exhaustive consumers must account for version 2.
parseSseEvent accepts both standalone extension events and extensions in done
events. For version 2, labels must be nonblank strings; missing, empty, or
whitespace-only prompts are omitted so item.prompt ?? item.label falls back to
the label. Nonblank strings are preserved, including surrounding whitespace.
Non-string prompts and malformed items reject the extension; done events filter
invalid extensions. Empty item arrays are valid. Version 1 parsing is unchanged.
Persistent sessions and inquiry drafts
SessionResponse contains the issued sessionId, plaintext token, and
expiresAt. Send this token as Bearer auth for chat, restore, and cancel. Chat
adds optional requestId for compatibility with standalone runtimes; the installed
plugin content API requires it for admission and idempotent replay.
ConversationRestoreResponse contains completed history, activePersona, and
expiration. History messages can carry persona, previousPersona, and
requestId, so the UI can identify the speaker after restoration.
persona_routing v1 carries persona, searchQuery and string topic.
The plugin projects a structured planner topic to its title. Legacy intent and
explicitInquiryRequest properties are ignored rather than propagated.
Response extensions
See Agent output extensions for the
wire table and consumer-owned action/form migration. ResponseExtension contains
UI blocks, persona routing, generic blocks and both follow-up versions.
Removed inquiry_draft extensions are treated like unknown extension types: an
individual extension event is ignored, and done.extensions retains valid siblings.
InquiryDraftExtension and InquiryPrefill are no longer exported here; form
prefill belongs to @dani-builder/blocks/forms.