Skip to content
Shiny.NET
Commercial SupportGuaranteed response times on Shiny bug fixes, straight from the maintainers. Plans from US$1,500 a year.See the plans

AI Conversation

NuGet package Shiny.AppDeviceBridge.AiConversation

The AI conversation bridge gives the page conversations with the app’s AI model. Replies stream as events, the AI can ask questions with choices, sessions are stored and resumable, and the assistant remembers things across them. A hands-free voice loop (wake word, push-to-talk, talking over a reply) is optional. The model, its key, its tools and its prompts stay in the app; the page never sees them.

Terminal window
dotnet add package Shiny.AppDeviceBridge.AiConversation
builder.UseAppDeviceBridge(
bridge => bridge.AddAiConversationBridge(
ai => ai
.SetChatClientProvider<MyChatClientProvider>() // or register an IChatClient
.AddSessionTitles(),
o => o.Voice = true // optional: the voice loop
),
webApp => { /* … */ }
);

The first argument configures Shiny.AiConversation itself: the model, stores, tools, memory and interceptors. Without a provider it uses the IChatClient registered in the container. The in-memory stores are the default; register the SQLite stores from Shiny.AiConversation.Stores.SqliteDocDb to keep sessions across launches.

Client C# TypeScript
IAiConversationBridge AddAiConversationBridgeClient() AiConversationBridge

Built on Shiny.AiConversation 3.0.

Topic Details
Sessions POST sessions starts one, GET sessions/latest carries on the most recent (204 when there are none), GET sessions lists and searches them, and DELETE sessions/{id} deletes one with its messages and memory. A session never ends: it is compacted as its context fills.
Sending POST sessions/{id}/messages takes text, or an answer to a question with choices, plus up to 4 images from file roots and per-turn instructions. It answers with the turnId straight away; with "wait": true it answers once the turn ends, with the reply. A new message supersedes a turn still running, and DELETE sessions/{id}/turn interrupts it.
Streaming ai.delta carries each piece of the reply, ai.message each stored or changed message, and ai.turn.ended how the turn ended (Completed, AwaitingUser, Interrupted, Superseded, Failed, with the error). Every event names its session.
Open sessions Events come from sessions the bridge has open: starting, reading or sending to one opens it. It keeps MaxOpenSessions (8) open and closes the least recently used idle one beyond that; using it again reopens it.
Questions When the model asks something, ai.questions and the session’s pendingQuestions carry it. Answer a question with choices with answer: { questionId, choiceIds } (one id unless allowMultiple), and one without choices with text. A question no longer pending answers 409 no_such_question.
History GET sessions/{id}/messages?before=&count= pages backwards. Each message has its display text, what was actually spokenText when it was interrupted, and its parts: text, tool calls and results, answers and images. An image part’s attachmentId fetches it from GET attachments?id=.
Memory GET memory, PUT memory and DELETE memory read, write and forget what the assistant remembers, globally, per profile or per session; ai.memory fires when the assistant changes it. Writes from the page are recorded as the user’s.
Voice With o.Voice = true, POST voice attaches the voice loop to a session, with an optional wakeWord, interruption mode, quiet words, follow-up timeout and culture. It needs a listener on ai.voice.state to attach (409 not_listening) and detaches once the last one is gone, so a page that went away can’t leave the microphone waiting for a wake word. voice/talk, voice/stop, voice/pause and voice/resume drive it, and ai.voice.transcript, ai.voice.speaking, ai.voice.interrupted and ai.voice.level report it. A loop the app attached itself answers 409 voice_busy.
Platforms Sessions and memory work on every platform. The voice loop uses Shiny.Speech’s on-device recognizer and synthesizer on iOS, Mac Catalyst, macOS, Android and Windows; Linux has none, so register a cloud or Whisper ISpeechToTextService and ITextToSpeechService there. Without AI conversations registered, the bridge answers 501; without the voice loop, its routes do.
Platform setup For voice: Android needs RECORD_AUDIO. Apple platforms need NSSpeechRecognitionUsageDescription and NSMicrophoneUsageDescription, plus the com.apple.security.device.audio-input entitlement for sandboxed apps.
import { AiConversationBridge } from "@shinyorg/appdevicebridge";
const ai = new AiConversationBridge();
const session = (await ai.getLatestSession()) ?? (await ai.startSession({}));
await ai.onDelta(e => e.sessionId === session.id && (reply.textContent += e.text));
await ai.onQuestions(e => showChoices(e.questions));
await ai.onTurnEnded(e => e.error && showError(e.error));
await ai.send(session.id, { text: "Plan a dinner for four" });
// Or wait for the whole reply.
const { reply } = await ai.send(session.id, { text: "Make it vegetarian", wait: true });
// Answering a question with choices.
await ai.send(session.id, { answer: { questionId: "size", choiceIds: ["large"] } });
GET/_bridge/ai#

What the app registered.

C#IAiConversationBridge.GetStatusAsyncTSAiConversationBridge.getStatus
Response
200 AiStatus
AiStatus · 3 fields
supportedbooleanWhether the app registered AI conversations.
voiceSupportedbooleanWhether the app registered the voice loop.
openSessionsnumberSessions the bridge holds open, and raises events for.
GET/_bridge/ai/sessions#

Stored sessions, most recently active first, filtered by text in their messages, a tag or a profile.

C#IAiConversationBridge.GetSessionsAsyncTSAiConversationBridge.getSessions
ParameterInType
textquerystring | nulloptional
tagquerystring | nulloptional
profilequerystring | nulloptional
skipquerynumberoptional
takequerynumberoptional
Response
200 AiSessionSummary[]
AiSessionSummary · 8 fields
idstring
titlestring | null
startedstring
lastActivitystring
messageCountnumber
profilestring | null
tagsstring[]
usageAiUsage
POST/_bridge/ai/sessions#

Starts a session.

C#IAiConversationBridge.StartSessionAsyncTSAiConversationBridge.startSession
Body
application/json · AiStartSessionRequest
AiStartSessionRequest · 5 fields
titlestring | null
profilestring | nullSelects the app's tools, memory and prompts for a kind of conversation.
tagsstring[] | null
metadataRecord&lt;string, string&gt; | null
excludeFromSearchbooleanKeep it out of conversation search and long-term memory.
Response
200 AiSession
AiSession · 9 fields
idstring
titlestring | null
startedstring
stateAiSessionState
pendingQuestionsAiQuestion[]
usageAiUsage
contextAiContext
profilestring | null
tagsstring[]
GET/_bridge/ai/sessions/latest#

The most recently active session — to carry on where the user left off — or null when there are none.

C#IAiConversationBridge.GetLatestSessionAsyncTSAiConversationBridge.getLatestSession
Response
200 AiSession · or 204 when there is none
AiSession · 9 fields
idstring
titlestring | null
startedstring
stateAiSessionState
pendingQuestionsAiQuestion[]
usageAiUsage
contextAiContext
profilestring | null
tagsstring[]
GET/_bridge/ai/sessions/{id}#

A session. Fails with 404 when there is none.

C#IAiConversationBridge.GetSessionAsyncTSAiConversationBridge.getSession
ParameterInType
idpathstringrequired
Response
200 AiSession
AiSession · 9 fields
idstring
titlestring | null
startedstring
stateAiSessionState
pendingQuestionsAiQuestion[]
usageAiUsage
contextAiContext
profilestring | null
tagsstring[]
Errors
404Not found
DELETE/_bridge/ai/sessions/{id}#

Deletes a session, its messages and its memory.

C#IAiConversationBridge.DeleteSessionAsyncTSAiConversationBridge.deleteSession
ParameterInType
idpathstringrequired
Response
204 No content
PUT/_bridge/ai/sessions/{id}/title#

Renames a session.

C#IAiConversationBridge.SetTitleAsyncTSAiConversationBridge.setTitle
ParameterInType
idpathstringrequired
Body
application/json · AiTitleRequest
AiTitleRequest · 1 field
titlestring
Response
200 AiSession
AiSession · 9 fields
idstring
titlestring | null
startedstring
stateAiSessionState
pendingQuestionsAiQuestion[]
usageAiUsage
contextAiContext
profilestring | null
tagsstring[]
POST/_bridge/ai/sessions/{id}/messages#

Sends a message, replacing any turn still running. The reply streams through onDelta and ends with onTurnEnded; with wait, this answers with it too.

C#IAiConversationBridge.SendAsyncTSAiConversationBridge.send
ParameterInType
idpathstringrequired
Body
application/json · AiSendRequest
AiSendRequest · 5 fields
textstring | nullAt most 32,000 characters.
answerAiAnswer | null
imagesAiImageRef[] | nullAt most 4, each a JPEG, PNG, WebP, HEIC or GIF of at most 10 MB.
instructionsstring[] | nullExtra direction for this turn only, not shown in the history.
waitbooleanAnswer once the turn ends, with its reply, rather than as soon as it starts.
Response
200 AiSendResult
AiSendResult · 5 fields
turnIdstring
outcomeAiTurnOutcome | nullNull when it is still running.
replyAiMessage | null
questionsAiQuestion[] | null
errorstring | null
GET/_bridge/ai/sessions/{id}/messages#

The stored history, newest page first: pass the oldest sequence of a page as before for the one before it.

C#IAiConversationBridge.GetMessagesAsyncTSAiConversationBridge.getMessages
ParameterInType
idpathstringrequired
beforequerynumber | nulloptional
countquerynumberoptional
Response
200 AiMessagePage
AiMessagePage · 2 fields
messagesAiMessage[]Oldest first.
hasMorebooleanOlder messages remain; ask again with the first one's sequence.
DELETE/_bridge/ai/sessions/{id}/turn#

Interrupts the running turn, keeping what was written. Fails with 409 no_turn when none is running.

C#IAiConversationBridge.InterruptAsyncTSAiConversationBridge.interrupt
ParameterInType
idpathstringrequired
Response
204 No content
Errors
409Conflict
POST/_bridge/ai/sessions/{id}/compact#

Folds older messages into the session's summary now, rather than when the context fills.

C#IAiConversationBridge.CompactAsyncTSAiConversationBridge.compact
ParameterInType
idpathstringrequired
Response
204 No content
GET/_bridge/ai/attachments#

An image attached to a message, by its part's attachmentId.

C#IAiConversationBridge.GetAttachmentAsyncTSAiConversationBridge.getAttachment
ParameterInType
idquerystringrequired
Response
200 Binary content — Blob in TypeScript, Stream / byte[] in C#
GET/_bridge/ai/memory#

What the assistant remembers, optionally in one scope.

C#IAiConversationBridge.GetMemoryAsyncTSAiConversationBridge.getMemory
ParameterInType
scopequeryAiMemoryScope | nulloptional
scopeKeyquerystring | nulloptional
Response
200 AiMemoryDocument[]
AiMemoryDocument · 9 fields
pathstring
scopeAiMemoryScope
scopeKeystring | nullThe session id or profile name; null for Global.
descriptionstring | null
contentstring
createdstring
updatedstring
updatedByAiMemoryAuthor
versionnumber
PUT/_bridge/ai/memory#

Writes a memory document, as the user.

C#IAiConversationBridge.SaveMemoryAsyncTSAiConversationBridge.saveMemory
Body
application/json · AiMemorySaveRequest
AiMemorySaveRequest · 5 fields
scopeAiMemoryScope
pathstring
contentstring
scopeKeystring | nullThe session id or profile name; null for Global.
descriptionstring | null
Response
200 AiMemoryDocument
AiMemoryDocument · 9 fields
pathstring
scopeAiMemoryScope
scopeKeystring | nullThe session id or profile name; null for Global.
descriptionstring | null
contentstring
createdstring
updatedstring
updatedByAiMemoryAuthor
versionnumber
DELETE/_bridge/ai/memory#

Forgets one memory document.

C#IAiConversationBridge.DeleteMemoryAsyncTSAiConversationBridge.deleteMemory
ParameterInType
scopequeryAiMemoryScoperequired
pathquerystringrequired
scopeKeyquerystring | nulloptional
Response
204 No content
GET/_bridge/ai/voice#

Whether the voice loop is there, and where it is.

C#IAiConversationBridge.GetVoiceAsyncTSAiConversationBridge.getVoice
Response
200 AiVoiceStatus
AiVoiceStatus · 3 fields
supportedbooleanWhether the app registered the voice loop.
stateAiVoiceState
sessionIdstring | nullThe session it is attached to.
POST/_bridge/ai/voice/access#

Requests microphone and speech recognition permission.

C#IAiConversationBridge.RequestVoiceAccessAsyncTSAiConversationBridge.requestVoiceAccess
Response
200 AiAccessResult
AiAccessResult · 1 field
accessAccessState
POST/_bridge/ai/voice#

Attaches the voice loop to a session. Listen to onVoiceState first: without a listener it fails with 409 not_listening, and it detaches once the last listener is gone, so a page that went away cannot leave the microphone listening for a wake word.

C#IAiConversationBridge.AttachVoiceAsyncTSAiConversationBridge.attachVoice
Body
application/json · AiVoiceRequest
AiVoiceRequest · 7 fields
sessionIdstring
wakeWordstring | nullListen for this before each conversation; without one, the loop starts on pushToTalk.
interruptionAiInterruptionMode | null
quietWordsstring[] | nullWhat stops a reply under QuietWords; at most 32.
followUpTimeoutSecondsnumber | nullHow long it listens for an answer to a question before needing the wake word again.
acknowledgementAiAcknowledgement | null
culturestring | nullRecognition and speech, such as en-US.
Response
200 AiVoiceStatus
AiVoiceStatus · 3 fields
supportedbooleanWhether the app registered the voice loop.
stateAiVoiceState
sessionIdstring | nullThe session it is attached to.
Errors
409Conflict
DELETE/_bridge/ai/voice#

Detaches the voice loop and releases the microphone.

C#IAiConversationBridge.DetachVoiceAsyncTSAiConversationBridge.detachVoice
Response
204 No content
POST/_bridge/ai/voice/talk#

Listens now, without the wake word, interrupting any reply.

C#IAiConversationBridge.PushToTalkAsyncTSAiConversationBridge.pushToTalk
Response
204 No content
POST/_bridge/ai/voice/stop#

Stops the reply being spoken, without listening.

C#IAiConversationBridge.StopSpeakingAsyncTSAiConversationBridge.stopSpeaking
Response
204 No content
POST/_bridge/ai/voice/pause#

C#IAiConversationBridge.PauseVoiceAsyncTSAiConversationBridge.pauseVoice
Response
204 No content
POST/_bridge/ai/voice/resume#

C#IAiConversationBridge.ResumeVoiceAsyncTSAiConversationBridge.resumeVoice
Response
204 No content
EVENTai.turn.started#

C#IAiConversationBridge.OnTurnStartedAsyncTSAiConversationBridge.onTurnStarted
Payload
AiTurnStarted
sessionIdstring
turnIdstring
userMessageAiMessage
EVENTai.delta#

C#IAiConversationBridge.OnDeltaAsyncTSAiConversationBridge.onDelta
Payload
AiTextDelta
sessionIdstring
turnIdstring
textstring
EVENTai.tool#

C#IAiConversationBridge.OnToolCallAsyncTSAiConversationBridge.onToolCall
Payload
AiToolCall
sessionIdstring
turnIdstring
callIdstring
namestring
completedboolean
isErrorboolean
silentbooleanA tool the app marked as not worth showing.
EVENTai.questions#

C#IAiConversationBridge.OnQuestionsAsyncTSAiConversationBridge.onQuestions
Payload
AiQuestionsAsked
sessionIdstring
turnIdstring
questionsAiQuestion[]
EVENTai.turn.ended#

C#IAiConversationBridge.OnTurnEndedAsyncTSAiConversationBridge.onTurnEnded
Payload
AiTurnEnded
sessionIdstring
turnIdstring
outcomeAiTurnOutcome
replyMessageIdstring | null
spokenTextstring | nullWhat was heard before an interruption.
errorstring | null
EVENTai.message#

A message was stored or changed.

C#IAiConversationBridge.OnMessageAsyncTSAiConversationBridge.onMessage
Payload
AiMessageChanged
sessionIdstring
messageAiMessage
updatedbooleanTrue when an existing message changed — finished streaming, interrupted, compacted.
EVENTai.title#

C#IAiConversationBridge.OnTitleAsyncTSAiConversationBridge.onTitle
Payload
AiTitleChanged
sessionIdstring
titlestring | null
EVENTai.compacted#

C#IAiConversationBridge.OnCompactedAsyncTSAiConversationBridge.onCompacted
Payload
AiCompacted
sessionIdstring
compactedCountnumber
wasHardTrimbooleanMessages were dropped without a summary, because summarizing failed or there was no room.
EVENTai.error#

C#IAiConversationBridge.OnErrorAsyncTSAiConversationBridge.onError
Payload
AiSessionError
sessionIdstring
messagestring
EVENTai.voice.transcript#

C#IAiConversationBridge.OnTranscriptAsyncTSAiConversationBridge.onTranscript
Payload
AiTranscript
textstring
finalbooleanFalse while the user is still speaking.
EVENTai.voice.speaking#

C#IAiConversationBridge.OnSpeakingAsyncTSAiConversationBridge.onSpeaking
Payload
AiSpeaking
textstring
EVENTai.voice.interrupted#

C#IAiConversationBridge.OnInterruptedAsyncTSAiConversationBridge.onInterrupted
Payload
AiSpeechInterrupted
reasonAiInterruptionReason
heardTextstring | null
spokenTextstring | null
EVENTai.voice.level#

The microphone and speech levels about 20 times a second.

C#IAiConversationBridge.OnVoiceLevelAsyncTSAiConversationBridge.onVoiceLevel
Payload
AiVoiceLevel
inputnumberThe microphone, 0–1.
outputnumberThe speech, 0–1.
EVENTai.voice.error#

C#IAiConversationBridge.OnVoiceErrorAsyncTSAiConversationBridge.onVoiceError
Payload
AiVoiceError
messagestring

JSON property names are camelCase and enums travel as their names. A ? marks a property the payload may omit;| null one that may be null.

AiStatusobject#
supportedbooleanWhether the app registered AI conversations.
voiceSupportedbooleanWhether the app registered the voice loop.
openSessionsnumberSessions the bridge holds open, and raises events for.
AiSessionSummaryobject#

A stored session, without loading it.

idstring
titlestring | null
startedstring
lastActivitystring
messageCountnumber
profilestring | null
tagsstring[]
usageAiUsage
AiUsageobject#

Everything billed in a session.

inputTokensnumber
outputTokensnumber
cachedInputTokensnumber
reasoningTokensnumber
totalTokensnumber
requestCountnumber
AiStartSessionRequestobject#

A new session. Every field is optional.

title?string | null
profile?string | nullSelects the app's tools, memory and prompts for a kind of conversation.
tags?string[] | null
metadata?Record&lt;string, string&gt; | null
excludeFromSearch?booleanKeep it out of conversation search and long-term memory.
AiSessionStateenum#
"Idle""Thinking""Responding""AwaitingUser""Compacting"
AiQuestionobject#

Something the AI asked, with the answers to pick from when it gave some.

idstring
textstring
choicesAiChoice[] | null
allowMultipleboolean
AiChoiceobject#
idstring
labelstring
AiContextobject#

How full the model's context window is.

currentTokensnumber
maxTokensnumber | null
percentUsednumber | null
pressureAiContextPressure | null
isEstimatebooleanTrue when counted locally rather than reported by the model.
AiContextPressureenum#
"Normal""Warning""Critical"
AiTitleRequestobject#
titlestring
AiSendRequestobject#

A message to the AI: text, or an answer to a question with choices. A question without choices is answered with text.

text?string | nullAt most 32,000 characters.
answer?AiAnswer | null
images?AiImageRef[] | nullAt most 4, each a JPEG, PNG, WebP, HEIC or GIF of at most 10 MB.
instructions?string[] | nullExtra direction for this turn only, not shown in the history.
wait?booleanAnswer once the turn ends, with its reply, rather than as soon as it starts.
AiAnswerobject#

An answer to one of pendingQuestions by its choices.

questionIdstring
choiceIdsstring[]
AiImageRefobject#

An image to send, from a file root — one the page wrote, a photo, a camera capture.

fileBridgeFile
description?string | nullWhat it shows, for models and history that cannot see it.
retention?AiImageRetention
BridgeFileobject#

A file the page can reach through the files bridge: a named root and a path inside it. Bridges that take or return a file use this, so nothing reaches the page that /_bridge/files would not also serve.

rootstring
pathstring
AiImageRetentionenum#

What happens to an image after the turn that sent it.

"DropAfterTurn""KeepInContext""DontStore"
AiSendResultobject#

A turn that started, or with wait, one that ended.

turnIdstring
outcomeAiTurnOutcome | nullNull when it is still running.
replyAiMessage | null
questionsAiQuestion[] | null
errorstring | null
AiTurnOutcomeenum#

How a turn ended.

"Completed""AwaitingUser""Interrupted""Superseded""Failed"
AiMessageobject#
idstring
sessionIdstring
sequencenumber
timestampstring
roleAiMessageRole
sourceAiMessageSource
statusAiMessageStatus
textstring | nullWhat to show.
spokenTextstring | nullWhat was actually heard, when it was spoken and interrupted.
partsAiMessagePart[]
compactedbooleanFolded into a summary; no longer sent to the model.
AiMessageRoleenum#
"User""Assistant""Tool""System""Summary"
AiMessageSourceenum#
"Typed""Voice""ChoiceAnswer""Camera""Interceptor""Compaction""MemoryFlush""Model"
AiMessageStatusenum#
"Complete""Streaming""Interrupted""Failed"
AiMessagePartobject#

One part of a message. Which fields are set depends on kind.

kindAiPartKind
displayedbooleanShown in the conversation.
spokenbooleanRead aloud by the voice loop.
textstring | nullThe text; a tool call's arguments as JSON; a tool's result; an answer's labels.
namestring | null
callIdstring | null
isErrorboolean
attachmentIdstring | nullAn image's id for getAttachment.
mediaTypestring | null
questionIdstring | null
choiceIdsstring[] | null
AiPartKindenum#
"Text""ToolCall""ToolResult""Answer""Image"
AiMessagePageobject#
messagesAiMessage[]Oldest first.
hasMorebooleanOlder messages remain; ask again with the first one's sequence.
AiMemoryScopeenum#

Whose memory a document is: one session's, one profile's, or every session's.

"Session""Profile""Global"
AiMemoryDocumentobject#

Something the assistant remembers, as a markdown document at a path.

pathstring
scopeAiMemoryScope
scopeKeystring | nullThe session id or profile name; null for Global.
descriptionstring | null
contentstring
createdstring
updatedstring
updatedByAiMemoryAuthor
versionnumber
AiMemoryAuthorenum#
"Assistant""User""App"
AiMemorySaveRequestobject#
scopeAiMemoryScope
pathstring
contentstring
scopeKey?string | nullThe session id or profile name; null for Global.
description?string | null
AiVoiceStatusobject#
supportedbooleanWhether the app registered the voice loop.
stateAiVoiceState
sessionIdstring | nullThe session it is attached to.
AiVoiceStateenum#
"Off""WaitingForWakeWord""Listening""FollowUp""Thinking""Speaking""Paused"
AccessStateenum#

Where a permission stands. Reported by every bridge that needs one; the names match Shiny's own.

"Unknown""NotSupported""NotSetup""Disabled""Restricted""Denied""Available"
AiVoiceRequestobject#

Attaches the voice loop to a session. Every field but the session is optional.

sessionIdstring
wakeWord?string | nullListen for this before each conversation; without one, the loop starts on pushToTalk.
interruption?AiInterruptionMode | null
quietWords?string[] | nullWhat stops a reply under QuietWords; at most 32.
followUpTimeoutSeconds?number | nullHow long it listens for an answer to a question before needing the wake word again.
acknowledgement?AiAcknowledgement | null
culture?string | nullRecognition and speech, such as en-US.
AiInterruptionModeenum#

How the user can talk over a reply.

"Off""QuietWords""Full"
AiAcknowledgementenum#

What the voice loop does to acknowledge it heard the user.

"None""AudioBlip""LessWordy""Full"
AiTurnStartedobject#
sessionIdstring
turnIdstring
userMessageAiMessage
AiTextDeltaobject#

The next piece of the reply as the model writes it.

sessionIdstring
turnIdstring
textstring
AiToolCallobject#

The model called one of the app's tools, or one finished.

sessionIdstring
turnIdstring
callIdstring
namestring
completedboolean
isErrorboolean
silentbooleanA tool the app marked as not worth showing.
AiQuestionsAskedobject#
sessionIdstring
turnIdstring
questionsAiQuestion[]
AiTurnEndedobject#
sessionIdstring
turnIdstring
outcomeAiTurnOutcome
replyMessageIdstring | null
spokenTextstring | nullWhat was heard before an interruption.
errorstring | null
AiMessageChangedobject#
sessionIdstring
messageAiMessage
updatedbooleanTrue when an existing message changed — finished streaming, interrupted, compacted.
AiTitleChangedobject#
sessionIdstring
titlestring | null
AiCompactedobject#
sessionIdstring
compactedCountnumber
wasHardTrimbooleanMessages were dropped without a summary, because summarizing failed or there was no room.
AiMemoryChangeenum#
"Created""Updated""Deleted""Renamed"
AiSessionErrorobject#
sessionIdstring
messagestring
AiTranscriptobject#
textstring
finalbooleanFalse while the user is still speaking.
AiSpeakingobject#

The sentence the voice loop is speaking now.

textstring
AiInterruptionReasonenum#
"QuietWord""Answer""NewSpeech""PushToTalk""Stop"
AiVoiceLevelobject#
inputnumberThe microphone, 0–1.
outputnumberThe speech, 0–1.
AiVoiceErrorobject#
messagestring

These routes sit under AppDeviceBridgePolicies.Bridges like every other bridge: callers on this device by default. The page spends the app’s model, and every tool the app registers runs when the model decides to call it, on a prompt the page wrote. Register only the tools the web app may use, and treat a page that can reach this bridge as able to call them. See Security.