One module per API area (base, files, activity, skills, conversations, notifications, forms, search, plans, projects, services, misc, diff, cron, agents) on a shared base.Schema; __init__.py re-exports every model so handlers keep writing schemas.<Name>. OpenAPI output is byte-identical. PlanSummary lives in conversations.py to keep the module graph a DAG. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
124 lines
4.4 KiB
Python
124 lines
4.4 KiB
Python
"""The agents catalog (``backend/agents.py``) and the native Claude Code hooks."""
|
||
from __future__ import annotations
|
||
|
||
from typing import Optional
|
||
|
||
from .base import Schema
|
||
from .cron import CronJob
|
||
|
||
__all__ = [
|
||
"AgentSummary",
|
||
"AgentsTotals",
|
||
"AgentsResponse",
|
||
"AgentRun",
|
||
"AgentDay",
|
||
"AgentDetail",
|
||
"ClaudeHookEntry",
|
||
"ClaudeHooksResponse",
|
||
]
|
||
|
||
|
||
# ── agents catalog ───────────────────────────────────────────────────────────
|
||
# Sits after the cron models because an agent's detail carries the cron job
|
||
# scheduled on its definition file.
|
||
class AgentSummary(Schema):
|
||
"""One agent card: the definition on disk + what its runs actually cost.
|
||
|
||
The skills catalog can only *estimate* spend (context size × invocations);
|
||
an agent run is a whole conversation, so `cost`/`tokens` here are measured.
|
||
"""
|
||
name: str # the invocation name (frontmatter `name:`)
|
||
title: str
|
||
description: str
|
||
# None for a built-in agent type (`Explore`, `general-purpose`, …): nothing
|
||
# of it lives in this repo, so there is no file to link into the editor.
|
||
path: Optional[str] = None
|
||
dir: Optional[str] = None
|
||
source: str # "repo" | <project dir-name> | "builtin"
|
||
sourceKind: str # "repo" | "project" | "builtin"
|
||
tools: list[str] # frontmatter `tools:`; empty ⇒ inherits all
|
||
bytes: int
|
||
updatedAt: Optional[str] = None
|
||
# Run config declared in the frontmatter, verbatim (see agents.RUN_KEYS).
|
||
harness: Optional[str] = None
|
||
model: Optional[str] = None
|
||
effort: Optional[str] = None
|
||
thinking: Optional[str] = None
|
||
runs: int # total recorded runs, both origins
|
||
taskRuns: int # …spawned as a subagent (Task tool)
|
||
sessionRuns: int # …spawned as a session (cron / Run now)
|
||
lastRun: Optional[str] = None
|
||
conversations: int # distinct conversations it ran in
|
||
cost: float # real spend across every run
|
||
tokens: int
|
||
avgCost: float
|
||
contextTokens: Optional[int] = None # cost of loading the definition once
|
||
contextCost: Optional[float] = None
|
||
|
||
|
||
class AgentsTotals(Schema):
|
||
agents: int
|
||
used: int
|
||
runs: int
|
||
cost: float
|
||
tokens: int
|
||
|
||
|
||
class AgentsResponse(Schema):
|
||
agents: list[AgentSummary]
|
||
totals: AgentsTotals
|
||
|
||
|
||
class AgentRun(Schema):
|
||
"""One recorded run of an agent."""
|
||
agent: str
|
||
origin: str # "task" | "cron" | "manual"
|
||
account: Optional[str] = None # the Claude account the run billed
|
||
at: Optional[str] = None
|
||
cost: float
|
||
tokens: int
|
||
model: Optional[str] = None
|
||
title: Optional[str] = None
|
||
# The conversation to open: for a subagent run this is its *parent* (where
|
||
# the Task card is); `subConversationId` is the child transcript itself.
|
||
conversationId: Optional[str] = None
|
||
subConversationId: Optional[str] = None
|
||
|
||
|
||
class AgentDay(Schema):
|
||
"""One day of the detail page's run sparkline."""
|
||
date: str
|
||
runs: int
|
||
cost: float
|
||
|
||
|
||
class AgentDetail(Schema):
|
||
agent: AgentSummary
|
||
content: str # the definition file verbatim ("" if none)
|
||
runs: list[AgentRun] # most recent first
|
||
daily: list[AgentDay]
|
||
cron: Optional[CronJob] = None # the job scheduled on this definition
|
||
# False when cron would reject this definition as a prompt file (nested or
|
||
# project-local) — the UI explains instead of offering a button that 400s.
|
||
canSchedule: bool
|
||
|
||
|
||
# ── native Claude Code hooks ─────────────────────────────────────────────────
|
||
class ClaudeHookEntry(Schema):
|
||
"""One native Claude Code hook from the workspace's .claude/settings.json,
|
||
flattened to a single command."""
|
||
# PreToolUse / UserPromptSubmit / Stop / …
|
||
event: str
|
||
# The tool/name matcher, when the event supports one.
|
||
matcher: Optional[str] = None
|
||
type: str = "command"
|
||
command: str
|
||
|
||
|
||
class ClaudeHooksResponse(Schema):
|
||
"""The repo's native hooks — read-only: editing .claude/settings.json from
|
||
the container would be host-level code execution."""
|
||
path: str
|
||
exists: bool
|
||
entries: list[ClaudeHookEntry]
|