roboto.ai.agent.record#

Module Contents#

class roboto.ai.agent.record.AgentRecord(/, **data)#

Bases: pydantic.BaseModel

A pre-filled StartAgentThreadRequest plus declared variables.

An AgentRecord captures most of what an AgentThread needs to start - system prompt, model profile, seeded messages, declared goals - and leaves a small set of named holes that callers must fill at invoke time. The canonical example is a triage agent whose goal carries a fixed label_vocabulary but a {{dataset.id}} placeholder, so the same agent can be re-run against many datasets without re-declaring the vocabulary.

The record’s main invariant - enforced by _validate_variables_match_placeholders() - is that the set of {{...}} placeholders found anywhere in request_template equals exactly {v.name for v in variables}. A mismatch fails at save time so stale invoke forms can’t paper over typos.

Parameters:

data (Any)

agent_id: str#

Canonical handle. Generated server-side (agt_<short>); stable across renames.

created: datetime.datetime#

Wall-clock time the record was first persisted.

created_by: str#

User id of the agent’s original author.

description: str | None = None#

Free-form description rendered on the agents list and detail pages.

modified: datetime.datetime#

Wall-clock time of the most recent successful update.

modified_by: str#

User id who applied the most recent update; equals created_by on records that have not been edited since creation.

name: str#

Human-readable display name. Mutable. Unique per (org_id, name) - enforced at the persistence layer, not on the record.

org_id: str#

Organization that owns the agent. All CRUD and invoke calls must come from a member of this org.

request_template: roboto.ai.agent_thread.record.StartAgentThreadRequest#

The body that will be cloned and resolved into a real StartAgentThreadRequest at invoke time. Any string leaf may contain {{name}} placeholders; non-string fields cannot be templated in v1 (the substitution engine never visits them).

variables: list[TemplateVariable] = None#

Declared variables. The set of names here must equal the set of placeholder names parsed from request_template.

class roboto.ai.agent.record.CreateAgentRequest(/, **data)#

Bases: pydantic.BaseModel

Wire payload for POST /v1/ai/agents.

The server fills AgentRecord.agent_id, org_id, created_by, created, modified, and modified_by from the caller’s identity; everything else comes from this request.

Parameters:

data (Any)

description: str | None = None#
name: str#
request_template: roboto.ai.agent_thread.record.StartAgentThreadRequest#
variables: list[TemplateVariable] = None#
class roboto.ai.agent.record.LaunchAgentRequest(/, **data)#

Bases: pydantic.BaseModel

Wire payload for POST /v1/ai/agents/<agent_id>/launch.

The route resolves the named agent, substitutes values into its body, and starts a new AgentThread whose visibility comes from visibility and whose created_from_agent_id points back at the source agent.

Parameters:

data (Any)

values: dict[str, str] = None#

Variable name to caller-supplied value. Keys must match declared TemplateVariable names; values are coerced to str before being spliced into placeholders.

visibility: roboto.ai.agent_thread.record.ThreadVisibility#

Visibility of the resulting AgentThread. Invoke-time wins: this value overrides whatever the agent’s request_template.visibility field carries. Agents cannot pin visibility — authors who need to convey recommended visibility do so in the agent’s description. Defaults to ORG because agents exist to share workflows across teammates; PRIVATE is an explicit opt-out per invocation.

class roboto.ai.agent.record.TemplateVariable(/, **data)#

Bases: pydantic.BaseModel

A named slot in an AgentRecord that must be filled before the agent can be invoked.

Variables are declared up-front rather than inferred from the body so that the invoke UI can render typed inputs (dataset pickers, etc.) and so that a typo in the body ({{dataste.id}}) surfaces as a save-time validation error rather than a silent extra prompt at invoke time. The declared set and the set of placeholders parsed from the body must match exactly - see AgentRecord._validate_variables_match_placeholders().

Parameters:

data (Any)

collection_content_type: roboto.domain.collections.record.CollectionResourceType | None = None#

constrains the invoke-page collection picker to collections holding this resource type (e.g. event collections for a create-events goal). None leaves the picker unconstrained. Must be None for every other variable type — see _validate_resolvable().

Type:

Only meaningful when type is TemplateVariableType.COLLECTION_ID

default: str | None = None#

Default value substituted when the caller omits the variable. Coerced to str; types are a UI concern.

description: str | None = None#

Human-readable explanation rendered next to the input on the invoke page.

name: str#

Lookup key for substitution. Must match _VARIABLE_NAME_RE; see that pattern for the dotted-name namespace convention. Two variables sharing a prefix (dataset.id + dataset.name) without an upstream expander produce two unlinked inputs at invoke time — that’s a UI-authoring footgun, not an SDK contract.

required: bool = True#

If True the resolver raises UnresolvedAgentVariablesError when no value is supplied and no default is set.

type: TemplateVariableType#

UI hint for the invoke page. See TemplateVariableType.

class roboto.ai.agent.record.TemplateVariableType#

Bases: roboto.compat.StrEnum

How a variable is interpreted by the invoke-page UI and the invoke-time existence validator.

The substitution engine itself is type-agnostic: every value gets spliced in as a string. The type drives two separate consumers: the UI picks a richer input control (dataset picker, device picker), and the service-side invoke handler runs an existence check on typed values so a bad id fails at the invoke boundary instead of inside the agent’s first tool call. See roboto_service.routes.ai_router._VALUE_VALIDATORS.

COLLECTION_ID = 'collection_id'#

A Roboto collection identifier. UI renders a collection picker; invoke-time validator asserts the collection exists in the caller’s org.

DATASET_ID = 'dataset_id'#

A Roboto dataset identifier. UI renders a dataset picker; invoke-time validator asserts the dataset exists in the caller’s org.

DEVICE_ID = 'device_id'#

A Roboto device identifier. UI renders a device picker; invoke-time validator asserts the device is registered in the caller’s org.

STRING = 'string'#

Free-form text. The default; renders as a plain text input. No existence check (no entity to check against).

class roboto.ai.agent.record.UpdateAgentRequest(/, **data)#

Bases: pydantic.BaseModel

Wire payload for PUT /v1/ai/agents/<agent_id>.

Uses the NotSetType sentinel to distinguish “field omitted” from “field explicitly set to None” so partial updates don’t accidentally null out unrelated fields.

Parameters:

data (Any)

description: str | None | roboto.sentinels.NotSetType#
model_config#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

name: str | roboto.sentinels.NotSetType#
request_template: roboto.ai.agent_thread.record.StartAgentThreadRequest | roboto.sentinels.NotSetType#
variables: list[TemplateVariable] | roboto.sentinels.NotSetType#
roboto.ai.agent.record.extract_placeholders(body)#

Return every {{name}} placeholder referenced anywhere in body.

Walks the JSON form of the request rather than the Pydantic model so the traversal is type-agnostic - placeholders inside label_vocabulary values, message text, system prompt, etc. all get picked up without needing per-field logic. Only string values are scanned; dict keys are intentionally ignored so key-collision footguns never arise.

Parameters:

body (roboto.ai.agent_thread.record.StartAgentThreadRequest)

Return type:

set[str]