Classifier-backed approval policy for local TUI and ACP runtimes.
Question types that require a non-empty choices list.
Derived from _requires_choices rather than written out, so it cannot omit a
new choice-based QuestionType member. Note that requiring choices is not the
same as being rendered as a choice list: the TUI has its own exhaustive
dispatch in _QuestionWidget.compose.
Runtime membership view of QuestionType.
Derived via get_args so the membership checks in ask_user and auto_mode
cannot drift from the alias when a new question type is added. That drift would
be silent: an unrecognized type makes _ask_user_question_count return None,
which drops the user's answers as same-turn authorization without any error.
Per-run classifier_model value meaning "review with the main agent model".
An absent (or None) classifier_model only says the run carries no
preference, so the classifier keeps whatever the server resolved at startup
(--auto-classifier-model, DEEPAGENTS_CODE_AUTO_CLASSIFIER_MODEL,
[models].auto_classifier). /auto model clear needs the stronger statement
that reviews go back to the main agent model, which this sentinel carries.
It cannot collide with a real spec: create_model resolves provider:model
(or a bare model name) and has no provider or model named __dcode_.... A
control character such as a leading NUL would also be collision-proof, but this
value has to survive the trip to a remote deployment intact — the context is
serialized to JSON and may be persisted, and Postgres text/jsonb rejects NUL
outright. A stripped sentinel would silently read as "no preference" and leave a
startup classifier authorizing actions after the UI reported the clear, so the
sentinel stays plain ASCII.
ToolMessage.additional_kwargs flag set on a synthetic auto-mode denial.
Set on both dispositions that synthesize a result instead of executing the
tool: policy_deny and the classifier_unavailable fallback.
The flag lets the TUI skip its uncorrelated-result warning for these. A
result reaches that warning when no widget mounted for the call, and a widget
mounts only when the streamed args parse (see ToolCallBuffer.parse_args).
A no-argument call streams no args, so it never mounts, and its denial result
arrives uncorrelated. The denial is not the cause of the miss; it is the
routine case in which the miss is expected.
The flag is carried in additional_kwargs so the adapter does not
string-match the content. additional_kwargs is dropped by the server
message converters unless they forward it; _convert_tool_message in
client/remote_client.py does, which is what the TUI depends on.
Return whether an ask_user answer counts as "no answer".
The single definition of emptiness for an answer, shared by the TUI (which blocks submitting a required question) and by the Auto authorization path (which keeps unanswered questions out of the consent evidence). Both sides must agree: an answer the TUI accepts as empty must not read as consent evidence downstream.
A bare .strip() is wrong for multi_select, whose empty encoding is the
truthy string []. Every other type is empty when it is blank.
Decode a multi_select answer produced by encode_multi_select_answer.
Return the store key for a thread's live approval mode.
Asynchronously read a live approval mode from a LangGraph Store.
The graph server supplies an async batched Store whose synchronous methods
reject calls from the event-loop thread. Prefer aget() for that runtime,
while retaining a synchronous fallback for lightweight local test stores.
Return a validated mode, failing closed to manual.
Project authoritative channels into deterministic notice state.
Build trusted classifier metadata for a client-created user message.
Return whether an MCP tool has coherent read-only annotations.
Return whether a tool carries dcode's MCP wrapper marker.
Return MCP names that require Manual or Auto review.
Return a compact reason safe for persistence, logs, and UI rendering.
Build a safe agent/UI reason for a failed auto classifier call.
Provider exception text stays out of the reason (it can carry secrets or
noisy HTML). Only real local deadline expiry
(_ClassifierDeadlineExceededError) says the classifier did not respond
within the configured wait budget; a bare provider TimeoutError stays
type-only so we do not claim dcode's deadline fired when the model failed
first. A configured classifier model that cannot be built is named as such
so the user fixes the setting instead of waiting out a nonexistent outage.
Tool-approval policy selected for an interactive thread.
Classifier denial categories exposed to the agent and TUI.
One structured classifier decision for a proposed tool call.
Validated classifier response for one unresolved action batch.
Server-owned denial and availability counters for one thread.
Checkpoint-safe disposition for one gated call.
Private checkpoint record joining model output to after-model routing.
Server-owned provenance for one exclusively allocated scratch file.
Reducer update that creates or removes one exact artifact record.
Agent state carrying private Auto decisions and scratch provenance.
Trusted metadata attached by the Textual client to a user message.
Server-resolved approval mode and trace-safe diagnostics.
Apply deterministic policy, classifier review, and HITL fallback.
Reject dynamically gated MCP calls when no approval UI exists.