artifactr.agent¶
artifactr's integration with pydantic-ai.
Give an agent the ArtifactWorkspace capability and deps_type=Session[...], then run
it in threads with a Runner::
agent = Agent(
"anthropic:claude-sonnet-5-5",
deps_type=Session[None],
capabilities=[ArtifactWorkspace(types=[Doc, Plan])],
)
runner = Runner(agent, app=None)
await runner.send(workspace, thread_id, "Draft a launch plan")
The capability¶
See The agent.
ArtifactWorkspace
dataclass
¶
ArtifactWorkspace(
types: Sequence[type[Artifact]],
*,
ask: bool = False,
max_render_chars: int = 4000,
max_summary_chars: int = 200,
)
Bases: AbstractCapability[Session[Any]]
Make an agent a participant in a workspace.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
types
|
Sequence[type[Artifact]]
|
The artifact types the agent may create. |
required |
ask
|
bool
|
Include the |
False
|
max_render_chars
|
int
|
How much of each followed artifact's rendering to include in the instructions. |
4000
|
max_summary_chars
|
int
|
How much of each tool call's arguments and result to record. |
200
|
get_instructions
¶
get_instructions() -> Any
Return the instructions, rendered fresh for every model request.
wrap_run
async
¶
wrap_run(
ctx: Context, *, handler: WrapRunHandler
) -> AgentRunResult[Any]
Record the run, brief the agent, and watch the workspace while it runs.
before_tool_execute
async
¶
before_tool_execute(
ctx: Context,
*,
call: ToolCallPart,
tool_def: ToolDefinition,
args: ValidatedToolArgs,
) -> ValidatedToolArgs
Record the tool call.
wrap_tool_execute
async
¶
wrap_tool_execute(
ctx: Context,
*,
call: ToolCallPart,
tool_def: ToolDefinition,
args: ValidatedToolArgs,
handler: WrapToolExecuteHandler,
) -> Any
Record a tool's own ModelRetry or ToolFailed, which skip the error hook.
after_tool_execute
async
¶
after_tool_execute(
ctx: Context,
*,
call: ToolCallPart,
tool_def: ToolDefinition,
args: ValidatedToolArgs,
result: Any,
) -> Any
Record the tool's result.
on_tool_execute_error
async
¶
on_tool_execute_error(
ctx: Context,
*,
call: ToolCallPart,
tool_def: ToolDefinition,
args: ValidatedToolArgs,
error: Exception,
) -> Any
Turn rejections into retries the model can act on; record every failure.
Session
dataclass
¶
Session(
workspace: Workspace,
thread_id: ThreadId,
run_id: RunId,
app: AppDepsT,
trigger: Trigger = "api",
watch_after: int | None = None,
)
The pydantic-ai deps of one agent run.
Tools receive it as ctx.deps. Its workspace handle acts as the thread's agent, so
everything a tool commits is attributed to the agent and this run.
Create it with start rather than directly.
watch_after
class-attribute
instance-attribute
¶
watch_after: int | None = None
Watch the log for others' changes after this seq; None means from the run's start.
start
classmethod
¶
start(
workspace: Workspace,
thread_id: ThreadId,
*,
app: AppDepsT,
run_id: RunId | None = None,
agent_name: str = "assistant",
trigger: Trigger = "api",
watch_after: int | None = None,
) -> Session[AppDepsT]
Return a session for a new (or resuming) run of the thread's agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
workspace
|
Workspace
|
A handle on the workspace; the session derives the agent's handle. |
required |
thread_id
|
ThreadId
|
The thread the agent runs in. |
required |
app
|
AppDepsT
|
The application's own dependencies, available to tools as |
required |
run_id
|
RunId | None
|
The run's id; a new one is generated when omitted. |
None
|
agent_name
|
str
|
How the agent is named in change notes and messages. |
'assistant'
|
trigger
|
Trigger
|
What started the run. |
'api'
|
watch_after
|
int | None
|
The |
None
|
Trigger
module-attribute
¶
Trigger = Literal['message', 'resume', 'api']
What started a run: a posted message, answers to a pause, or a direct call.
load_history
async
¶
load_history(
workspace: Workspace, thread_id: ThreadId
) -> list[ModelMessage]
Return a thread's model history, to pass as message_history.
last_seen
async
¶
Return the seq up to which the thread's agent has been told what happened.
Running agents in threads¶
See Running the agent.
Runner
¶
Runner(
agent: Agent[Session[AppDepsT], Any],
*,
app: AppDepsT,
live: FanoutChannel | None = None,
agent_name: str = "assistant",
claim_ttl: timedelta = timedelta(seconds=30),
)
Runs an agent in workspace threads.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agent
|
Agent[Session[AppDepsT], Any]
|
The agent, whose |
required |
app
|
AppDepsT
|
The application's dependencies, passed to every run as |
required |
live
|
FanoutChannel | None
|
Where runs' live frames go. Defaults to an in-process fan-out. |
None
|
agent_name
|
str
|
How the agent is named in the workspace. |
'assistant'
|
claim_ttl
|
timedelta
|
How long a thread claim lasts without renewal, should this process die. |
timedelta(seconds=30)
|
execute
async
¶
Carry out any command the way every surface should.
Messages and answers go through send and answer, so they start, steer
and resume runs; stop_run stops a run of this workspace; everything else is
committed as-is.
Raises:
| Type | Description |
|---|---|
Rejection
|
If the command is rejected, or the run to stop is not in this workspace or not running in this process. |
send
async
¶
send(
workspace: Workspace,
thread_id: ThreadId,
content: str,
*,
message_id: MessageId | None = None,
) -> Sent
Post a message as the workspace handle's actor, and act on it.
answer
async
¶
answer(
workspace: Workspace, command: AnswerDeferred
) -> Sent
Answer one of a paused run's requests, resuming the run once all are answered.
resume
async
¶
Resume a paused run whose requests are all answered; otherwise do nothing.
stop
async
¶
Cancel a run of this process. Returns whether there was one to stop.
watch
¶
watch(run_id: RunId) -> AsyncIterator[LiveFrame]
Yield a run's live frames from now until it ends.
RunHandle
dataclass
¶
RunHandle(
run_id: RunId,
thread_id: ThreadId,
task: Task[AgentRunResult[Any]],
)
A run started by a Runner.
wait
async
¶
wait() -> AgentRunResult[Any]
Wait for the run to finish (or pause) and return its result.
Sent
dataclass
¶
Live output¶
See Live output.
ArtifactDraft
dataclass
¶
ArtifactDraft(
*,
kind: str,
snapshot: dict[str, Any],
artifact_id: ArtifactId | None = None,
)
Bases: CustomEvent
A snapshot of an artifact that a tool is still generating.
Emit it from an application tool with await ctx.emit(ArtifactDraft(...)); it reaches
live channels as a draft frame and is never stored.
forward_live
¶
forward_live(channel: LiveChannel) -> EventStreamHandler
Return a pydantic-ai event_stream_handler that sends live frames to channel.
The run id comes from the run's Session.
to_live
¶
to_live(event: AgentStreamEvent) -> list[LiveEvent]
Translate one pydantic-ai stream event into live events (often none).
LiveChannel
¶
FanoutChannel
¶
An in-process channel that fans each run's frames out to its watchers.
It keeps the frames of runs in progress, so a watcher that attaches mid-run first receives what the run has produced so far. Watchers that fall behind lose their oldest frames rather than slowing the run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
buffer
|
int
|
How many frames each run keeps, and each watcher may fall behind. |
1024
|
remember_closed
|
int
|
How many ended runs to remember, so late watchers end at once. |
10000
|
send
async
¶
send(frame: LiveFrame) -> None
Keep a frame for the run, and deliver it to the run's current watchers.
watch
async
¶
watch(run_id: RunId) -> AsyncIterator[LiveFrame]
Yield the run's frames so far, then new ones until close is called for it.
Watching a run that has already ended stops at once.
NullChannel
¶
Tool helpers¶
The generic tools, and helpers for writing your own.
artifact_tools
¶
artifact_tools(
types: Sequence[type[Artifact]], *, ask: bool = False
) -> FunctionToolset[Session[Any]]
Build the generic toolset for the given artifact types.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
types
|
Sequence[type[Artifact]]
|
The artifact types the agent may create; their JSON Schemas are described to the model once, so tool definitions never change between requests. |
required |
ask
|
bool
|
Whether to include |
False
|
describe_outcome
¶
Tell a model what its change did.
submit
async
¶
submit(
workspace: Workspace,
change: EditArtifact | ArchiveArtifact | CreateArtifact,
*,
propose: bool = False,
rationale: str | None = None,
) -> Applied | Proposed
Commit a change, or propose it for review when propose is set.
artifact_text
¶
Render an artifact for a model: a header line, then its render_for_agent text.