Skip to main content
Glama
extentos

extentos

injectAssistantUtterance

Inject synthetic user utterances into live assistant sessions to trigger tool calls for E2E testing. Returns a watch cursor for assertions; works with OpenAi and Mock providers.

Instructions

Phase 4 — drive an assistant turn from outside the live session for agent-driven E2E tests of glasses.assistant.start { tool(...) { ... } }. As of iter5.2 (2026-05-27) the text: path works for BOTH the Mock provider and the real OpenAi Realtime provider — same MCP call, provider-appropriate routing: (a) OpenAi (default in production apps) — injected as a synthetic user turn via conversation.item.create + response.create on the live Realtime WebSocket. Drives REAL model behavior with full conversation context + tool routing decisions; costs real tokens (~$0.005/turn); takes 500-2000ms for the model to respond + dispatch tool. (b) Mock — word-overlap-matches against registered tool descriptions + dispatches synchronously. Sub-ms, deterministic, $0. The library filters inject frames to source: "assistant_inject" only, so browser-mic STT transcripts (already flowing via the PCM audio path) are NOT double-injected. Wake first if Dormant. This handler does NOT auto-wake — if the session is Dormant (silence-timeout, fresh session, post-end_conversation), the library's injectUserTurn silently no-ops because connectionRef is null + the inject is dropped. Drive the wake faithfully via injectTranscript({ text: "<your wake phrase>" }), wait for assistant.session_started in getEventLog, THEN inject. This mirrors what a real user does on real hardware: phrase, wait, command. (The iter5.3 autoWake convenience was shipped + reverted in 0.1.4 — it collapsed the explicit two-step into one call, hiding the wake step and racing with onWake greeting hooks.) audioWavBase64 path is DEFERRED to v1.1 (needs Rust core changes) — handler returns not_implemented if passed. Returns watchCursor — a seq cursor captured immediately before the inject; pass it straight into assertToolCalled({ sinceCursor }) so the assertion anchors BEFORE this inject and never misses the tool call it triggers (the model fires the tool 0.5-2s later, often after your assertToolCalled call has already started). USE in the agent E2E loop: createSimulatorSession → injectTranscript("") → (wait for session_started) → const r = injectAssistantUtterance({ text: "..." })assertToolCalled({ name: "...", sinceCursor: r.watchCursor }) → getEventLog(types:['assistant.*']) → cross-verify via adb logcat + screencap. DON'T USE for Phase 3 glasses.conversation.onWake { listen / speak } flows — that's still injectTranscript's domain.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
textNoUtterance text the agent wants the assistant to react to. Routed differently per provider, but always via the same `stt_transcript`/`source: "assistant_inject"` frame: (a) **OpenAi provider (iter5.2)** — injected as a synthetic user turn via `conversation.item.create` + `response.create` on the live Realtime WebSocket. The model decides which tool to call based on its full instructions + the user message. ~$0.005/turn, 500-2000ms latency. Use for real-provider verification without needing real audio or human-in-loop. (b) **Mock provider** — word-overlap-matches against each registered tool's description (case-insensitive, tokens ≥ 3 chars, first match wins). Sub-ms, $0. Write tool descriptions so the keywords your test utterance contains overlap, e.g. "Take a photo with the glasses camera" matches text "take a photo". **Mock tool args are an empty object (F-75):** the Mock matches the tool by DESCRIPTION but does not extract arguments from the utterance — it dispatches with `{}`, so a tool whose args type has REQUIRED fields throws MissingFieldException under Mock injection. Make Mock-testable tools' args optional (nullable / defaulted) or parse them from the utterance text in the tool body; validate required-typed-arg tools against the real OpenAi provider, which fills args from the model.
sessionIdYes
audioWavBase64NoDEFERRED to v1.1 — passing this field returns `not_implemented`. The intended path: base64-encoded WAV (mono i16 LE PCM; rate matched to the live audio path at implementation time); library decodes and feeds through audio_chunks Flow to the active real provider. Needs a Rust core extension that Sprint 1's machine-split deliberately avoids. For end-to-end real-provider validation in the meantime, run the OpenAi provider session with a real mic source (sim browser tab mic, or real glasses).
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full burden. It thoroughly discloses provider routing (OpenAi vs Mock), costs, latency, mock argument behavior (empty object), deferred audioWavBase64, wake requirement (no auto-wake), and return value (watchCursor). This is comprehensive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very long and detailed, which impacts conciseness. However, it is well-structured with bold headers, bullet points, and code-like steps. It front-loads the purpose and usage, but the length may hinder quick scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, the absence of output schema, and moderate schema coverage, the description is exceptionally complete. It covers purpose, usage, behavioral nuances, parameter details, return value, dependencies, and exclusions. The example usage pattern ties it all together.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, so baseline is 3. The description adds significant meaning: for `text`, it explains provider-specific routing and mock matching; for `audioWavBase64`, it clarifies deferred status and intended path; for `sessionId`, it implies use from `createSimulatorSession`. The description compensates well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'drive an assistant turn from outside the live session for agent-driven E2E tests'. It specifies the verb (inject) and resource (assistant utterance), and distinguishes it from sibling `injectTranscript` by mentioning Phase 4 vs Phase 3.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage instructions: 'USE in the agent E2E loop: createSimulatorSession → injectTranscript → ... → injectAssistantUtterance → assertToolCalled' and 'DON'T USE for Phase 3 glasses.conversation.onWake flows — that's still injectTranscript's domain'. It also explains the wake requirement and how to use with `assertToolCalled`.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/extentos/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server