blockether.vis.extension
Tool declarations, host APIs and extension lifecycle contracts.
For authoring workflows and examples, use the extension tutorial and extension API guide.
Operations every injected or outside vis host must implement.
Read the active session working copy, or the outside process directory.
Read this extension's project in the session working copy, or the outside process directory.
List the files that Git sees in the working copy, or None without Git.
Validate a declaration and fill defaults from the contract schema.
Read one setting from the current callback snapshot, as the type of default.
Write one JSON value into the extension's durable state.
Send one SDK request frame as JSON. Return the reply envelope as JSON.
Run one shell operation. Return the contract's result shape.
Run one shell op inside the workspace jail.
Ask the human, and block until the answer settles or is cancelled.
Open, patch, read or close a live view.
On open, listener(event) gets each human event of a panel view.
state accepts timeout_ms (0..86400000) and after_seq (nonnegative).
A positive timeout blocks until the sequence differs or the view closes.
An unchanged timeout returns is_open=True, timed_out=True, without view.
Ordinary state reads and changed waits return the current view with seq.
Replace the running symbol's headline, summary, content and sections.
Resolve the environment variables the extension declared.
Run one active session tool by the name python_execution calls.
Read one whole session as the sandbox read_session does. Return JSON.
List sessions as the sandbox list_sessions does. Return JSON.
Store one artifact of the running block. Return its descriptor as JSON.
List the session's artifact descriptors as JSON, pending ones included.
Return the descriptor of one artifact as JSON.
Create, find and read Vis sessions from an extension, as vis.sessions.
Each method returns blockether.vis.engine.Session handles that use the host. The
host records this extension as the origin of each session that it creates. An
extension can change only its bound session, its child sessions and its own sessions.
Create an independent session and return its Session.
Without root, the session starts in the root of the bound session. The other
options are the options of ExecutionLayer.create_session. Only an extension
callback can create a session.
Return the Model records that the model pickers show, in picker order.
The filters are those of ExecutionLayer.models. A thread of your extension
can also call it.
Return the session records of the first page, or the matches of search.
Create an independent session, run one turn in it and return the result.
The arguments are those of blockether.vis.engine.Agent.run. provider and
model pin the model of the new session. Without response_model, the result
is the turn record; check its status. Only an extension callback can call it.
Plain Activity text, never a model message or a question.
Heading for a section of this invocation's current content.
Inherited methods and attributes
Inherited from ActivityText.text.
Markdown content for this invocation.
Inherited methods and attributes
Inherited from ActivityText.text.
Code with an optional language hint.
Inherited methods and attributes
Inherited from ActivityText.text.
A diff, not engine-observed file-change evidence.
Inherited methods and attributes
Inherited from ActivityCode.language.
Inherited from ActivityText.text.
A rectangular table. Input lists are snapshotted as tuples.
paths is optional and, when given, holds one workspace path per row so
clients can open that row's file. Use an empty string for a row without one.
Reference an existing attachment, never an external media URL.
Display an existing image attachment.
Inherited methods and attributes
Inherited from ActivityFile.attachment_id.
Inherited from ActivityFile.label.
Display an existing video attachment.
Inherited methods and attributes
Inherited from ActivityFile.attachment_id.
Inherited from ActivityFile.label.
Display an existing audio attachment.
Inherited methods and attributes
Inherited from ActivityFile.attachment_id.
Inherited from ActivityFile.label.
Progress with paired value/total, or an indeterminate indicator when omitted.
One output line of an ActivityTerminal. Vis shows "stderr" lines as errors.
A command and its output, shown like a terminal.
command holds one or more stages. Start each later stage with its operator, for
example ("cd app", "&& npm test", "| tail -8"). Vis highlights the operators.
lines holds the output in order; a plain string is a stdout line. Keep the end
of long output and count the dropped lines in omitted_lines. Remove ANSI escape
codes first. exit is the exit code of a finished command.
A visible headline and one-line summary.
Only the content waits behind disclosure.
summary_format="markdown" opts into inline Markdown with HTTP(S) links. Unmarked or "inline" summaries are literal text. The 512-byte, one-line limit includes Markdown source. Images, HTML and block layout are not shown.
One atomic symbol presentation, optionally linked to a persistent handle.
Use the same non-secret handle_id for later receipts of one operation in this
extension and Python form. Vis shows one current outcome, and it keeps distinct
details, errors and every invocation in history. Omit it for independent calls. A
handle is not a label, tool argument or return value.
Set verdict when the call finished but reports on checks: "failed" for
failing tests or lint findings, "passed" when every check passed. Vis pins a
failed verdict in the settled turn's digest until a later run of the same tool
passes.
outcome is one short result line. Vis shows it after an arrow on the closed
row, for example the last line of command output. aside is short muted context
at the right edge of the row, for example a directory or "exit 1".
Return fresh portable data, without engine-owned lifecycle fields.
Inherited methods and attributes
Inherited from ActivitySection.headline.
Inherited from ActivitySection.summary.
Inherited from ActivitySection.content.
Inherited from ActivitySection.summary_format.
Human-facing symbol presentation. The engine owns identity, timing and outcome.
Declare Activity on every exported callable, including each object method. Write understandable English for people, not Python identifiers or object reprs. Labels and headlines use sentence case ("Read file", "Run tests") and keep proper names and acronyms. Summaries explain the target, useful counts or outcome. Use render or publish_activity for selected content. Return values stay independent.
show_start=False makes a fast operation end-only: no running row or start callback. Use it for quick reads, patches and local lookups. Keep show_start=True for work people wait for, such as tests, network requests or transfers. Internal start/end tracking still preserves ordering, timing, errors and cancellation. Published content is kept but stays hidden until an end-only invocation settles.
The final presentation must stand alone: name the target and outcome, including empty results or failures reported as return values. A normally returned failed workflow is still a failed workflow. "Completed" alone is not enough. Label partial lists and excerpts, and keep useful counts, errors and changes.
render is an optional synchronous callback. It receives phase, args, kwargs, result and error as keyword arguments. It returns an ActivityPresentation, or None to keep the current presentation. It runs on success and failure, and on start only when show_start=True. Use publish_activity for intermediate stages of long-running tools. Rendering failures never change returns or errors.
Arguments:
- presenter: Presentation category. Leave
"generic"for ordinary tools. - label: Optional nonblank, single-line label of at most 96 characters.
- render: Synchronous callback accepting
phase,args,kwargs,resultanderrorkeyword arguments. Return anActivityPresentationor None. - show_start: Whether readers see a running row before the call settles.
Raises:
- TypeError:
show_startis not boolean orrenderis not synchronous/callable. - ValueError: The presenter is unknown or the label is invalid.
Replace headline, summary, content and sections without authoring lifecycle.
Headline and summary stay visible when collapsed. Content uses typed text, Markdown, table, code, diff, attachment and progress blocks. Sections group multiple results with one blank line between them. To clear content, publish the same headline/summary with empty content. None from render keeps the last snapshot. Returns False outside an invocation or when publication is rejected.
Declare a boolean, choice or text setting shared by the app and TUI.
scopes allows any non-empty combination of global, project, group and session.
Omitting it uses the contract's global-only default. A project extension exists
only in its project, so there global means the whole project. The setting shows
in its extension's own settings section. value() reads the current callback's
response snapshot. Its type follows default: bool for a boolean setting, str
for a choice setting and for a text setting. Outside Vis, it returns the declared default.
A string setting holds one line of text. is_secret=True makes it write-only:
Settings show only whether a value is saved. A secret needs the default "" and
only the global scope. Its value stays on this machine and out of trajectories.
Read a secret while Vis calls its own extension, for example in a tool. Elsewhere,
value() can return the default.
parent names another setting of the same section. Settings shows this setting
under that setting. Settings can nest at any depth.
on_change(old, new, scope) runs once after a person changes the setting in the
app or TUI and its effective value changes. scope is global, project, group
or session. Vis keeps the saved value if the hook raises, and shows the error.
Group tools and host capabilities in one immutable declaration.
Arguments:
- name: Human-readable, nonblank extension name.
- description: Nonblank description of what the extension does.
- alias: Python namespace for exported symbols. Required with
symbols. - symbols:
Symboldeclarations for functions or object namespaces. - version: Optional extension version string.
- kind: Optional extension kind understood by the host.
- activation: Optional host activation callback.
- prompt: Instructions as text or a host callback.
- slash_commands:
SlashCommanddeclarations. - keybindings:
Keybindingdeclarations: TUI keys after C-x. - op_hooks:
OpHookdeclarations for host lifecycle operations. - ctx: Optional host context callback.
- providers:
Providerdeclarations. - network_filters:
NetworkFilterdeclarations. - settings: Host-owned
Settingdeclarations with explicit allowed scopes. - env: Environment variable names resolved at host registration.
- grants:
Grantdeclarations: toolchain paths for this extension'sjailed_shellchildren.
Collection inputs are copied into tuples. Constructing an Extension is pure: it does
not run callbacks or register anything. In an application, pass it to
blockether.vis.engine.Agent or its register_extension method. In an installed
extension entrypoint, call this module's register_extension once instead. The
application callback bridge rejects host-only fields before connecting.
Raises:
- ValueError: A required name, alias, callback or environment name is invalid.
- TypeError: A field has the wrong type or a collection contains something other than its corresponding SDK declaration.
Register one typed declaration and resolve its declared environment in this context.
Construction is pure, and registration is the only host boundary. A failure before completion leaves the context unregistered. No constructor registers itself.
Declare a dataclass's public list or tuple field as its sandbox sequence.
Apply this outside @dataclass. The returned class is unchanged except for
metadata: original methods are neither called nor transported. Each subclass must
opt in separately. Values are checked when an extension returns them. The backing
field must hold a built-in list or tuple, not a lazy iterable.
Sandbox records iterate over the received field and support length, truth testing, integer indices and slices. String keys still read named fields. Only the received items are exposed, and iteration never fetches another page.
Describe a public method on an object exported through Symbol.
Arguments:
- fn: Method to annotate. Omit it to use
@method(...). - tag: What the method does, as Activity reports it.
"observation"reads,"mutation"changes local state and"verification"checks work (tests, lint, CI status)."external"reaches people or systems beyond the session (messages, publications, remote hosts). - is_hidden: Hide the method from discovery without removing the callable.
- activity: This method's human-facing presentation. Declare it on each exported method, not on the containing object namespace.
Returns:
The original method, or a decorator returning it. Calling your method directly still uses normal Python behavior. This decorator adds metadata.
Raises:
- ValueError: The tag is unsupported or the decorated value is not callable.
- TypeError: The Activity declaration has the wrong type.
from blockether.vis.extension import Activity, Symbol, method
class Greeter:
@method(activity=Activity(label="Greet person", show_start=False))
def hello(self, name: str) -> str:
"Return a greeting for the named person."
return f"Hello, {name}!"
greeter = Greeter()
tool = Symbol(greeter, name="greeter")
assert greeter.hello("Ada") == "Hello, Ada!"
assert tool.contract["members"][0]["name"] == "greeter.hello"
Expose a function or an object's public methods as typed tools.
Arguments:
- fn: Function, or an object whose public methods form a namespace.
- name: Override the function name. Required for objects, and must then be a public Python identifier.
- tag: Default operation classification, one of the
methodtags. - is_hidden: Hide the symbol from discovery without removing the callable.
- activity: Human-facing presentation for a function. Declare one on every
exported callable. For an object, leave this unset and put an Activity
on every exported
methodinstead.
Construction validates the declaration and derives its contract without
calling the function or starting Vis. Function docstrings and type annotations
become tool documentation, not runtime argument validation. Export narrow
objects: public methods and nested namespace objects are traversed, not just
methods bearing the decorator.
Raises:
- ValueError: A callable lacks a docstring, or the name, operation tag, Activity placement or namespace is invalid, including cycles and repeated object references.
- TypeError: A declaration field has an unsupported type.
Fresh portable tool description, including literal defaults but no host access.
Namespace members carry their full public names. Strings in Annotated describe meaning. Unresolved annotations remain explicit and are never evaluated. This is documentation, not runtime argument or result validation.
An inert Python type description. References bound recursive records.
A dataclass field. Default values and factories are never exported or run.
A callable parameter. default_source is inert source, or None when unavailable.
Inherited methods and attributes
Inherited from FieldSpec.name.
Inherited from FieldSpec.type.
Inherited from FieldSpec.required.
Inherited from FieldSpec.has_default.
Inherited from FieldSpec.default_is_none.
Typed view of one public callable's authoritative Symbol contract.
A public namespace and its callable descendants, with full dotted names.
Generated reference text, not captured CLI output or an operation result.
Read-only snapshot of public Symbols. Construction and lookup do no IO.
Pass the same symbols to Catalog and Extension. Rebuild after changing declarations. This is an adapter, not a registry, dispatcher or runtime type validator.
Inspect declared tools without invoking them. Unknown or hidden names raise ValueError.
Render the same metadata as doc(). No configuration, authentication or operation runs.
Raises TypeError for a non-string name, and ValueError for unknown or hidden names.
A user-facing slash command, not a model-facing tool.
A TUI key binding: C-x, a group key and this key run a command, a verb or a function.
Arguments:
- key: One printable ASCII character from
!to~. - command: A slash command line that starts with
/. The TUI runs it as if the person typed it and pressed Enter. Give it withlabel. - action: A built-in TUI verb id in kebab case, such as
new-session. The verb moves tokey. - label: The key menu and palette label. Required with
commandandrun. - group: The C-x group of the key. A built-in group name, such as
Session, places the key there, in any case. A command or run binding without a group usesExtensions(C-x e). Any other name makes a group of its own under C-x e, opened by the first free letter of the name. An action binding without a group stays in the group of its verb. - run: A function that the gateway calls when the person presses the key.
It adds no turn to the transcript. It receives a dict with
key,group,channel,session_id,workspace_rootandproject_root. It returns None, a text,vis.ok(...)orvis.err(...), and the TUI shows the title. Callvis.notify(...)in it to tell every client of the session.
Give exactly one of command, action and run.
Raises:
- ValueError: A field breaks these rules.
An operation observer or a fail-closed gate. Never mix both kinds in one hook.
Request/response policy at the host's network-filter boundary.
Filesystem access that this extension's own jailed child processes need.
A toolchain often lives outside the workspace: a JDK, a package cache or a
launcher. Declare each path once. The host checks every grant at registration.
It adds the grant only to the jailed_shell children of this extension. The
model's shell never receives it, and the jail deny rules still win.
Arguments:
- path: Absolute path, or a path that starts with
~. - mode:
"read"to read and run files, or"read_write"for a cache that the tool also writes. - reason: Short text that tells people why the extension needs the path.
Raises:
- ValueError: The path or reason is blank, or the mode is unknown.
Endpoint defaults, not credentials. Opaque API payload keys remain unchanged.
extra carries additional router settings as JSON, never overriding named fields. Use enrich_models_fn for typed model metadata beyond default model names.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
A usable credential. Tokens and headers are excluded from repr.
Return None instead when no credential is available.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
Connection verdict, separate from usage limits. extra is display-only JSON metadata.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
Model metadata returned by enrichment. extra keeps additional router fields.
is_tool_call and is_image_input are old names of is_tool_calls_supported and is_vision_supported. They still work. A new name wins over its old name.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
The contract's calendar, rolling or lifetime window for one limit.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
One usage row in contract form.
Finite measurements keep their original precision.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
A limits failure, not an exception carrying a credential.
Inherited methods and attributes
Return fresh host data. Declared optional fields are omitted, not null.
Usage snapshot. The host fills omitted provider_id and fetched_at_ms values.
Return fresh host data. Declared optional fields are omitted, not null.
Pure provider declaration. register_extension adapts its callbacks to the host.
Credential reads are passive, and only auth_fn may start a login. Callbacks are synchronous and may run without a session. Refresh accepts zero arguments or one rejected token (None if unknown), chosen without retrying callback errors. Enrichment and selection inputs remain JSON mappings owned by the router or config, not a second SDK schema for those domains. Callback outputs use typed records.
Refuse the call a before op hook is deciding.
The model reads reason as the tool failure. hint tells it what to do next;
without one, the failure advises asking the user before a retry.
Return repaired source from a before hook, without writing or running it.
Only patch accepts this decision. Vis repairs python_execution blocks itself with parinferish. The host validates the request and reports the notes with the result. A patch still checks the complete original file before it writes the repaired text once.
Return the active session workspace as a path, including its current draft.
This is the primary working copy, not a language-specific project marker. Outside Vis, it is the process directory. A hosted call without a bound session fails instead of silently using the gateway process directory.
Return this extension's project root in the active session workspace.
The project root is the nearest directory above the extension entry that
holds a .vis directory, mapped into the session working copy. For an
extension in the workspace's own .vis/extensions, it is workspace_root().
Outside Vis, it is the process directory. A hosted call without a bound
session fails, like workspace_root().
Return the files under workspace_root() that Git sees.
The list holds tracked files and untracked files that Git does not ignore. The host lists the working copy once and gives the same list to each extension that asks within a short time. Use it instead of a child process for each extension. The result is None when the workspace is not in a Git working tree. Outside Vis, it lists the process directory.
Return the Python environment that the session's project selects.
The value comes from python.environment in the merged configuration.
shared means that project Python runs like vis-agent python --shared,
with Vis shared packages and without the project's .venv. project, the
default, means that the project's own environment applies. Outside Vis, the
value is project.
Replace path with text in one atomic step, readable only by its owner.
A failure keeps the previous file. A symbolic link writes the file it names. Missing parent directories are created owner-only.
Store an artifact as a durable attachment of the running block, or open an app.
source is a path, bytes, a Matplotlib figure or a Pillow image. The engine
stores the artifact with the python_execution block that called this tool,
exactly like the sandbox attach verb. A second attachment under the same
filename is the next version of that artifact. audience is both, user
or model; a PDF or HTML document is for the user only.
Returns the descriptor dict: id, filename, version, media_type, kind, size and audience. Every read function takes it as its target.
An app declaration from vis.ui.app(...) opens an app and answers its
LiveAttachment handle. The app row from list_attachments() answers a handle
for that app again. An app takes only on_event(event), which then runs for
each human change, submit, activate or shortcut, as with vis.live.
List the artifact descriptors of this session, oldest first.
The list includes the artifacts that the running block attached. With name,
it lists the versions of that one artifact.
Return the descriptor of one artifact, without its bytes.
target is a filename, an id or a descriptor. A filename means the latest
version, unless you give version. A negative version counts back.
Return the bytes of one artifact. target works as in get_attachment.
Show a stored image to the model for the next request only.
target works as in get_attachment. Returns the id, filename, media_type
and size of the queued image.
Read one whole session, exactly as the sandbox read_session does.
Without target, it reads the session that runs the extension. target takes a
bare id, an unambiguous prefix or the copied vis_session_id#<uuid> marker. The
introspection toggle does not apply, because an extension is trusted code.
Returns the same string-keyed dict: session, current_turn, failures, diagnosis, session_forks, turn_retries, usage and transcript.
List sessions newest first, exactly as the sandbox list_sessions does.
With search, it runs the session search of the TUI and the Companion app. The
rows come in rank order: title, request, reply, then thinking, newest first in
each rank. Keep that order. The introspection toggle does not apply.
Returns string-keyed rows: id, channel, title, goal, turn_count, created_at and modified_at. A match adds rank, the is_in_* flags and optional snippets.
The live view this handle drives is no longer open.
Raised by the next push after the human stopped watching — Escape in the
terminal, Stop in the app — so an unattended loop ends by itself. A loop
that would rather finish its own work reads view.is_interrupted instead
and decides.
note is the comment the person left with the stop, when they left one: the
reason it is being stopped, in their words.
One human action on a live view: change, submit, activate, select or shortcut.
value is the new value of a changed input; a secret input gives only
is_set. values holds every input that a submit button collected.
A Send in an app gives submission_id, the id of its receipt, and comments:
the thread messages that it posted, each with node_id, thread_id,
message_id, body and the anchor of a diff line.
A pressed app shortcut gives action, the id that the shortcut sends, and
key, the key that the person pressed. A shortcut that names a node gives an
activate event of that node instead.
A selection in a selectable table gives item_ids, the selected row ids.
A paragraph, heading or code block, replaced in place.
One node of a live view, addressed by its id.
One node of a live view, addressed by its id.
A titled card. A selectable card counts activations like a button.
One input component of a live view, read and set by id.
A secret input never shows its value: value is None for it, and its value
arrives only in the submit event, as a vis-secret: handle.
One node of a live view, addressed by its id.
One node of a live view, addressed by its id.
One node of a live view, addressed by its id.
One node of a live view, addressed by its id.
One node of a live view, addressed by its id.
Append complete lines, optionally styled by severity. Redact before writing.
Each argument is one stored line, not a raw byte fragment. A tone applies only to this call, and omitted tones are plain. Controls are displayed literally.
A node holding items the extension addresses by id: it can drop them.
Make rows the whole table, in their order, in one step.
Each row is a vis.ui.table_row(row_id, cells, tone=, parent=). Rows not
given are dropped. A selected row that comes back stays selected, and a
selected row that is gone loses its selection. An empty list empties the table.
A node holding items the extension addresses by id: it can drop them.
A unified diff that people review line by line, with threads on lines.
One conversation between people and the owner of the app.
A 3D world that surfaces draw. A tick sends only what changed.
Change the background, the field of view, wrapping or the tick length.
Add an object, or change the given keys of one: mesh, x, y, z, rx, ry,
rz, scale, color, is_emissive. A new object needs mesh.
A live view the human WATCHES, driven by the extension that opened it.
vis.live(...) mounts one and answers this handle. Nodes are addressed by id, as
view['jobs'] or view.node('jobs'), and each answers the typed handle its own
type declares. The view-level shortcuts (view.status(...), view.log(...),
view.row(...)) resolve to the one node of that type. When the view holds several
such nodes, they raise and name the candidate ids. So an ambiguous call fails where
it was written, and does not quietly patch the wrong table.
Pushes are BATCHED. Ops buffer and cross on the next push after flush_ms, or when
a coalesced push fills. They always cross before the view is read or closed. with
view.batch(): groups one logical picture explicitly, including structural add and
drop operations. Repeated writes to the same row or node collapse into the last one.
So a per-row progress counter costs one wire row per tick, not one per write.
Closing is the point: close() answers either the structured verdict or the compact
model_result that the extension chose. Used as a context manager, the view closes
itself. It closes as completed on the way out, and as failed with the error when
the body raised. A run that died midway still owes the model what happened.
Send one complete picture for a related group of node changes.
Node handles still coalesce exactly as usual, but neither the leading edge nor structural add/drop operations cross the host seam until the outermost batch ends. Reads and close remain explicit flush points.
Block until the view changes, ends, or seconds elapse.
One host wait replaces periodic state reads. An unchanged timeout returns no view payload. Returns True on change or close, False on timeout. Nonpositive durations do not flush or call the host.
True once the human stopped watching.
Asks the engine at most once per flush window. So a compute loop can poll it on every iteration and still cost one host call per tick.
True when a PERSON ended it, rather than the run itself or a deadline.
A view is always stoppable. Nothing is asked of the human, so stopping it leaves nothing unanswered. This is how the run finds out that a human stopped it.
The comment the human left with their stop, or None.
The stop always lands. The note says WHY in their own words, and the same words reach the model in the verdict.
Return the human actions that arrived since the last call.
Without timeout this never waits. With timeout seconds it waits up
to that long for the first new event. Each event also goes to every
callback that on_event registered, in arrival order.
Call callback(event) for each event that events or sleep reads.
A panel view opened with vis.live(..., on_event=...) gets its
events from the host instead. Each one runs as an extension callback with
the view session bound, also when no extension code waits on the view.
Returns the callback, so you can use this method as a decorator.
Add a whole node to a running view — a scan that discovers a seventh device should not have to have declared it.
End the view and answer the result the model reads.
model_result is an optional compact string returned instead of the
full structured verdict. The finished picture and close metadata remain
in the durable artifact and on human-facing close events.
selection_snapshots are finished pictures keyed by a selectable table and
its selected rows. They are sealed only into the artifact record, so a
reopened run can still switch rows without keeping its extension alive.
Closing twice is a no-op that answers the first result. A finally that closes
what an interrupt already closed must not overwrite the reason that the human
chose.
An app: a live view that is attached to the session and keeps its state.
vis.attach(vis.ui.app(title, *nodes)) opens one and answers this handle. The app
stays in the session after the call returns, also across gateway restarts. People
use it in the TUI and in the Companion app with the same vis.ui components. They
save drafts, and each Send gives a receipt in submissions(). The owner answers
with reply(...) and moves a receipt with set_status(...).
id is the app identity. vis.attach(row) with the app row from
list_attachments() answers a new handle for the same app, also after a restart.
Answer people in a thread of node node_id, as the owner of the app.
thread_id names an existing thread. On a diff without it, anchor
({"path", "side", "line"}) starts a thread on that line. submission_id
names the Send that you answer, and its receipt moves to answered. The
host sets the author. Answers thread_id, message_id and the new seq.
One thread as a dict: id, anchor, messages, draft, is_resolved.
A thread node is its own thread. On a diff, thread_id names the thread.
Replace the shortcuts of this app with vis.ui.shortcut(...) values.
An empty list removes every shortcut. Answers the new seq.
Tell the model the current state of this app, in plain text.
The model reads the newest note with the next user message, also when no
event reached the agent. A blank text removes the note. Answers the new
seq.
Serve the events of this app with callback(event) and block.
It returns when the app closes, when callback returns False, after
timeout seconds or on KeyboardInterrupt. Answers the number of events
that it served. Callbacks of on_event still get each event too.
Close the app and keep it only in the archived list of its session.
The record stays readable. A second archive changes nothing.
Inherited methods and attributes
Inherited from LiveView.view_id.
Inherited from LiveView.batch.
Inherited from LiveView.state.
Inherited from LiveView.sleep.
Inherited from LiveView.is_interrupted.
Inherited from LiveView.reason.
Inherited from LiveView.is_from_human.
Inherited from LiveView.note.
Inherited from LiveView.result.
Inherited from LiveView.values.
Inherited from LiveView.events.
Inherited from LiveView.on_event.
Inherited from LiveView.node.
Inherited from LiveView.status.
Inherited from LiveView.progress.
Inherited from LiveView.stat.
Inherited from LiveView.step.
Inherited from LiveView.write.
Inherited from LiveView.row.
Inherited from LiveView.group.
Inherited from LiveView.link.
Inherited from LiveView.add.
Inherited from LiveView.drop.
Inherited from LiveView.close.
Open a live view and answer the handle that drives it.
View options: description, source, session_id, channel_ids, plus flush_ms
for the batching window. EVERY key is a snake_case string, exactly as
vis.ask documents. There is no cancellable flag: a human can always stop
watching, and the verdict says they did (is_from_human) and why (note).
placement is inline (the default), attachment (an app, which answers a
LiveAttachment) or panel (the side panel of one session). Only extension code opens a panel view, and it needs a key:
the extension and the key own one view, so opening the same key again
replaces it. Such a view stays open after the call returns. It
closes on close() or when the extension unloads. on_event(event) then
runs for each human change, submit or activate, with the view session bound.
The view is mounted at once and nothing blocks — use it as a context manager so it closes itself:
with vis.live('Deploy', [vis.ui.steps('plan', steps=[...])]) as view:
view['plan'].set('build', tone='running')
Closing answers the verdict: is_completed, reason, the finished picture
as data, and whatever summary the extension chose to end with.