The context API
Edit on GitHubEvery call between Orrery and an extension is in one list: harness/protocol/context-api.json. An extension asks the host for a service (a model, the session, a timer), or the host asks it to answer (a tool call, an interceptor, a context builder). Each call has one name in every runtime, so a page that teaches model.complete teaches it in Rust and in TypeScript alike.
This page lists the calls and where each one is documented. The pages on this set are:
- Models and sessions: a model call, which model it uses, the session, who said what.
- Input, timers and questions: sending input to the run, timers, subscriptions, asking the person, notices, keys.
- Interceptors: the five points where an extension may refuse or change a call.
- Context, compaction and memory: what the model is sent, how it is compacted, what it remembers.
- Which tools the model sees: hiding tools, choosing how they are offered.
- Show things: placements: placing a surface in the thread, a pane, the band or the footer, and the fallback a client draws.
Names
A call is area.verb in the list and area/verb on the wire. The SDKs use the same words in their own case:
| Area | TypeScript (ctx, from @getorrery/ext) | Rust (host() from orrery_ext_sdk) |
|---|---|---|
model.complete | ctx.model.complete(params, { onEvent }) | complete(None, ModelCallParams) |
model.list | ctx.model.list() | models() |
session.info | ctx.session.info() | session_info() |
session.read | ctx.session.read(opts) | session_read(params) |
session.append | ctx.session.append(text, { shown }) | session_append(params) |
run.send | ctx.run.send(input, { target, shown, to }) | send(params) |
run.status | ctx.run.status() | run_status() |
timer.set / cancel | ctx.timer.set(ms, tag, { hold }) / ctx.timer.cancel(id) | timer(params) / timer_cancel(id) |
tools.hide / show | ctx.tools.hide(globs) / ctx.tools.show(globs) | tools_hide(names) / tools_show(names) |
ui.notify / ui.status | ctx.ui.notify(text, level) / ctx.ui.status(key, text) | ui_notify(params) / ui_status(params) |
ui.show / ui.hide | ctx.ui.show({ id, placement, surface | component | structure, data?, fallback?, title? }) / ctx.ui.hide({ id }) | ui_show(params) (component(…), structure(…) build them) / ui_hide(params) |
ui.data | ctx.ui.data(id).set(obj) / .patch(ops) | host().ui_data(id).set(value) / .patch(ops) |
ui/event (from the host) | ctx.ui.onEvent(id?, handler) | on_ui_event(handler) |
person.ask | ctx.person.ask(question, choices or { kind }) | ask(question, AskKind) |
config.get | ctx.config.get(key) | orrery_ext_sdk::config_get(key) |
agents.* | ctx.agents.spawn, join, children, inspect, message, stop | ctx.agents_handle() |
The Rust column is the method on the host handle, orrery_ext_sdk::host(); its traits are in orrery_ext_api::facades. A name the list has and a binding lacks fails the binding's test, so an SDK cannot quietly fall behind.
Where a call runs
Every call the host makes to an extension says where it runs: the session, the branch, the turn, and the agent (main or a spawned agent's id). In TypeScript that is ctx.at; it is null when an older host sent none.
An extension built against an older SDK keeps working on a newer host: a host call it does not answer gets the host's default, not a crash.
Errors
- A call the host refuses throws
BrokerDeniedin TypeScript, naming the rule. Catch it when the tool can do something better; otherwise let it through. - A refusal of a bound names the key that raises it, in config (see Config keys).
- Nothing an extension sends can widen what it was granted. Each new capability is an aspect the user sees at install:
run.send,session.read,session.write,model,intercept,mem.read,mem.write.