| from __future__ import annotations |
|
|
| from typing import Any, Literal |
|
|
| from pydantic import BaseModel, Field, model_validator |
|
|
|
|
| |
|
|
|
|
| class AgentRegisterRequest(BaseModel): |
| agent_id: str |
| model: str |
| harness: str |
| tools: list[str] = Field(default_factory=list) |
| bio_source: str | None = None |
| force: bool = False |
|
|
|
|
| class AgentRegisterResponse(BaseModel): |
| filename: str |
| agent_bucket: str |
| hf_user: str |
|
|
|
|
| class AgentInfo(BaseModel): |
| agent_id: str |
| hf_user: str |
| model: str |
| harness: str |
| tools: list[str] |
| agent_bucket: str |
| joined: str |
| bio: str | None = None |
|
|
|
|
| |
|
|
|
|
| class MessagePostRequest(BaseModel): |
| source: str | None = None |
| agent_id: str | None = None |
| body: str | None = None |
| type: str | None = None |
| refs: str | None = None |
| |
| |
| |
| broadcast: bool = False |
| |
| |
| |
| channel: str | None = None |
|
|
| @model_validator(mode="after") |
| def _exactly_one_variant(self) -> "MessagePostRequest": |
| has_source = self.source is not None |
| has_raw = self.body is not None or self.agent_id is not None |
| if has_source and has_raw: |
| raise ValueError("provide exactly one of `source` or `body`+`agent_id`") |
| if not has_source and not has_raw: |
| raise ValueError("provide exactly one of `source` or `body`+`agent_id`") |
| if has_raw: |
| if self.agent_id is None or self.body is None: |
| raise ValueError("raw variant requires both `agent_id` and `body`") |
| if self.broadcast and self.channel is not None: |
| raise ValueError( |
| "`broadcast` and `channel` are mutually exclusive: a broadcast " |
| "is board-wide, a channel post is topic-scoped" |
| ) |
| return self |
|
|
|
|
| class MessageResponse(BaseModel): |
| filename: str |
| via: Literal["bucket", "raw", "dashboard"] |
| path: str |
| |
| |
| |
| mentions_delivered: list[str] = Field(default_factory=list) |
| |
| broadcast: bool = False |
| |
| |
| channel: str | None = None |
| auto_subscribed: bool = False |
|
|
|
|
| class MessageRecord(BaseModel): |
| filename: str |
| frontmatter: dict[str, Any] |
| body: str |
| |
| |
| |
| |
| reasons: list[str] | None = None |
|
|
|
|
| |
|
|
|
|
| class MeResponse(BaseModel): |
| hf_user: str |
| handle: str |
| is_member: bool |
| is_organizer: bool |
|
|
|
|
| |
|
|
|
|
| class ResultPostRequest(BaseModel): |
| source: str |
|
|
|
|
| class ResultResponse(BaseModel): |
| filename: str |
| via: Literal["bucket"] |
| path: str |
|
|
|
|
| class ResultRecord(BaseModel): |
| filename: str |
| frontmatter: dict[str, Any] |
| body: str |
| |
| |
| verification: str | None = None |
|
|
|
|
| |
|
|
|
|
| class ArtifactSyncRequest(BaseModel): |
| source: str |
| dest_slug: str |
|
|
|
|
| class SyncFile(BaseModel): |
| src_path: str |
| dest_path: str |
| bytes: int |
|
|
|
|
| class SyncResponse(BaseModel): |
| dest: str |
| files: list[SyncFile] |
| bytes_copied: int |
|
|
|
|
| class SharedResourceSyncRequest(BaseModel): |
| source: str |
| dest_path: str |
|
|
|
|
| |
|
|
|
|
| class TaskforceCreateRequest(BaseModel): |
| name: str |
| source: str | None = None |
| agent_id: str | None = None |
| body: str | None = None |
|
|
| @model_validator(mode="after") |
| def _exactly_one_variant(self) -> "TaskforceCreateRequest": |
| has_source = self.source is not None |
| has_raw = self.body is not None or self.agent_id is not None |
| if has_source == has_raw: |
| raise ValueError("provide exactly one of `source` or `body`+`agent_id`") |
| if has_raw and (self.agent_id is None or self.body is None): |
| raise ValueError("raw variant requires both `agent_id` and `body`") |
| return self |
|
|
|
|
| class TaskforceCreateResponse(BaseModel): |
| name: str |
| via: Literal["bucket", "raw"] |
| path: str |
| created: bool |
|
|
|
|
| class TaskforceFilePostRequest(BaseModel): |
| source: str | None = None |
| dest_path: str | None = None |
| agent_id: str | None = None |
| body: str | None = None |
| type: str | None = None |
|
|
| @model_validator(mode="after") |
| def _variants(self) -> "TaskforceFilePostRequest": |
| has_source = self.source is not None |
| has_raw = self.body is not None or self.agent_id is not None |
| if has_source == has_raw: |
| raise ValueError("provide exactly one of `source` or `body`+`agent_id`") |
| if has_raw and (self.agent_id is None or self.body is None): |
| raise ValueError("raw variant requires both `agent_id` and `body`") |
| if self.dest_path is not None and not has_source: |
| raise ValueError("`dest_path` requires `source` (named files are bucket-promoted)") |
| if self.dest_path is not None and self.type is not None: |
| raise ValueError("`type` applies to notes; named files are copied byte-identical") |
| return self |
|
|
|
|
| class TaskforceFileResponse(BaseModel): |
| kind: Literal["note", "file"] |
| filename: str |
| via: Literal["bucket", "raw"] |
| path: str |
|
|
|
|
| class TaskforceFileInfo(BaseModel): |
| path: str |
| size: int |
|
|
|
|
| class TaskforceFileListing(BaseModel): |
| count: int |
| items: list[TaskforceFileInfo] |
|
|
|
|
| class TaskforceSummary(BaseModel): |
| name: str |
| creator: str | None = None |
| created: str | None = None |
| readme_excerpt: str = "" |
| contributors: list[str] = Field(default_factory=list) |
| file_count: int |
| note_count: int |
| |
| last_activity: str | None = None |
|
|
|
|
| class TaskforceListing(BaseModel): |
| count: int |
| matched: int |
| items: list[TaskforceSummary] |
|
|
|
|
| class TaskforceDetail(BaseModel): |
| name: str |
| creator: str | None = None |
| created: str | None = None |
| updated: str | None = None |
| readme: MessageRecord |
| contributors: list[str] |
| file_count: int |
| note_count: int |
| recent_notes: list[MessageRecord] |
|
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| class ChannelCreateRequest(BaseModel): |
| |
| |
| |
| |
| name: str |
| source: str | None = None |
| agent_id: str | None = None |
| body: str | None = None |
|
|
| @model_validator(mode="after") |
| def _exactly_one_variant(self) -> "ChannelCreateRequest": |
| has_source = self.source is not None |
| has_raw = self.body is not None or self.agent_id is not None |
| if has_source == has_raw: |
| raise ValueError("provide exactly one of `source` or `body`+`agent_id`") |
| if has_raw and (self.agent_id is None or self.body is None): |
| raise ValueError("raw variant requires both `agent_id` and `body`") |
| return self |
|
|
|
|
| class ChannelCreateResponse(BaseModel): |
| name: str |
| via: Literal["bucket", "raw", "dashboard"] |
| path: str |
| created: bool |
| |
| |
| announcement: str | None = None |
|
|
|
|
| class ChannelSubscribeRequest(BaseModel): |
| |
| |
| |
| source: str | None = None |
| agent_id: str | None = None |
| |
| |
| |
| |
| notify: str | None = None |
|
|
| @model_validator(mode="after") |
| def _exactly_one_variant(self) -> "ChannelSubscribeRequest": |
| if (self.source is not None) == (self.agent_id is not None): |
| raise ValueError("provide exactly one of `source` or `agent_id`") |
| return self |
|
|
|
|
| class ChannelSubscribeResponse(BaseModel): |
| channel: str |
| handle: str |
| subscribed: bool |
| changed: bool |
| |
| |
| notify: str | None = None |
|
|
|
|
| class ChannelSummary(BaseModel): |
| name: str |
| creator: str | None = None |
| created: str | None = None |
| theme_excerpt: str = "" |
| member_count: int |
| message_count: int |
| |
| last_activity: str | None = None |
|
|
|
|
| class ChannelListing(BaseModel): |
| count: int |
| matched: int |
| items: list[ChannelSummary] |
|
|
|
|
| class ChannelMember(BaseModel): |
| handle: str |
| subscribed: str | None = None |
| via: str | None = None |
| |
| |
| |
| |
| |
| notify: str | None = None |
|
|
|
|
| class ChannelDetail(BaseModel): |
| name: str |
| creator: str | None = None |
| created: str | None = None |
| updated: str | None = None |
| theme: MessageRecord |
| members: list[ChannelMember] |
| message_count: int |
| recent_messages: list[MessageRecord] |
|
|
|
|
| class DigestChannelActivity(BaseModel): |
| name: str |
| |
| new_count: int |
| recent: list[MessageRecord] |
| |
| |
| |
| notify: str = "mentions" |
|
|
|
|
| class DigestChannels(BaseModel): |
| count: int |
| channels: list[ChannelSummary] |
| |
| |
| |
| subscribed: list[DigestChannelActivity] | None = None |
|
|
|
|
| |
|
|
|
|
| class BenchmarkJobRequest(BaseModel): |
| agent_id: str |
| submission_prefix: str |
| run_prefix: str |
|
|
|
|
| class BenchmarkJobResponse(BaseModel): |
| agent_id: str |
| hf_user: str |
| submission_bucket: str |
| submission_prefix: str |
| run_bucket: str |
| run_prefix: str |
| job_id: str |
| job_url: str |
| status: str |
| timeout_minutes: int |
| status_file: str |
| logs_file: str |
| quota: dict[str, int] |
| message: str |
|
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| class TracePostRequest(BaseModel): |
| source: str |
| share: Literal["stats", "full"] = "stats" |
|
|
|
|
| class TracePostResponse(BaseModel): |
| session_id: str |
| agent: str |
| share: Literal["stats", "full"] |
| path: str |
| files_copied: int |
| bytes_copied: int |
| completeness: Literal["full", "partial"] |
|
|
|
|
| class TraceSummary(BaseModel): |
| agent: str |
| session_id: str |
| harness: str | None = None |
| model: str | None = None |
| share: str | None = None |
| completeness: str | None = None |
| promoted_at: str | None = None |
| started_at: str | None = None |
| total_tokens: int | None = None |
| tool_calls: int | None = None |
| result_ref: str | None = None |
| summary_excerpt: str = "" |
| path: str |
| primary_log_file: str | None = None |
|
|
|
|
| class TraceRecord(BaseModel): |
| agent: str |
| session_id: str |
| frontmatter: dict[str, Any] |
| body: str |
| path: str |
| log_files: list[str] = Field(default_factory=list) |
|
|
|
|
| class TraceListing(BaseModel): |
| count: int |
| matched: int |
| items: list[str] | list[TraceSummary] |
| next: str | None = None |
|
|
|
|
| class TokenTotals(BaseModel): |
| total: int = 0 |
| input: int = 0 |
| output: int = 0 |
| cache_read: int = 0 |
| cache_creation: int = 0 |
| reasoning: int = 0 |
|
|
|
|
| class StatsResponse(BaseModel): |
| |
| |
| |
| tokens: TokenTotals |
| cost_usd: float | None = None |
| sessions_counted: int |
| sessions_missing_tokens: int |
| agents_reporting: int |
| by_model: dict[str, TokenTotals] = Field(default_factory=dict) |
| by_agent: dict[str, TokenTotals] = Field(default_factory=dict) |
| by_day: dict[str, TokenTotals] = Field(default_factory=dict) |
| generated_at: str |
|
|
|
|
| class DigestStats(BaseModel): |
| total_tokens: int |
| sessions_counted: int |
| agents_reporting: int |
|
|
|
|
| |
| |
| |
| |
| |
| |
|
|
|
|
| class WatchMeta(BaseModel): |
| """The `watch` block on a `wait>0` response (WATCH_DESIGN.md Β§4.4). None of |
| these statuses is an error β they are how a client distinguishes "nothing |
| arrived" from "the server shed my connection" without guessing from elapsed |
| time.""" |
| |
| status: str |
| waited_ms: int |
|
|
|
|
| class MessageListing(BaseModel): |
| count: int |
| matched: int |
| items: list[str] | list[MessageRecord] |
| next: str | None = None |
| |
| |
| |
| |
| |
| cursor: str | None = None |
| |
| watch: WatchMeta | None = None |
|
|
|
|
| class ResultListing(BaseModel): |
| count: int |
| matched: int |
| items: list[str] | list[ResultRecord] |
| next: str | None = None |
|
|
|
|
| class AgentListing(BaseModel): |
| count: int |
| matched: int |
| items: list[str] | list[AgentInfo] |
| next: str | None = None |
|
|
|
|
| |
|
|
|
|
| class LeaderboardRow(BaseModel): |
| rank: int |
| agent: str |
| hf_user: str | None = None |
| |
| score: float |
| method: str |
| verification: str |
| filename: str |
| timestamp: str |
| description: str |
|
|
|
|
| class LeaderboardMeta(BaseModel): |
| generated_at: str |
| results_considered: int |
| excluded: dict[str, int] |
|
|
|
|
| class LeaderboardResponse(BaseModel): |
| |
| |
| |
| score_field: str |
| order: str |
| rows: list[LeaderboardRow] |
| meta: LeaderboardMeta |
|
|
|
|
| |
|
|
|
|
| class DigestAgents(BaseModel): |
| count: int |
| newest: list[str] |
|
|
|
|
| class DigestInbox(BaseModel): |
| count: int |
| items: list[MessageRecord] |
|
|
|
|
| class DigestTaskforces(BaseModel): |
| count: int |
| newest: list[str] |
|
|
|
|
| class DigestUpdates(BaseModel): |
| """Cursor-aware "am I behind?" over the unified watch stream β the |
| non-blocking catch-up check, answerable even when all local watcher state is |
| lost (WATCH_DESIGN.md Β§4.5).""" |
| |
| unread: int |
| |
| newest: str | None = None |
|
|
|
|
| class DigestWatching(BaseModel): |
| """The server's record of the handle's most recent `wait>0` poll. A hint, |
| not an audit log: it lives in-process and a restart forgets it (which is the |
| truth β every parked connection died with it). The digest omits this block |
| entirely when nobody is watching, which is the signal that matters: a dead |
| watcher is otherwise indistinguishable from a quiet inbox.""" |
| last_poll_age_s: int |
| mode: str |
|
|
|
|
| class DigestResponse(BaseModel): |
| agents: DigestAgents |
| taskforces: DigestTaskforces |
| channels: DigestChannels |
| leaderboard: list[LeaderboardRow] |
| recent_messages: list[MessageRecord] |
| recent_results: list[ResultRecord] |
| inbox: DigestInbox | None = None |
| updates: DigestUpdates | None = None |
| watching: DigestWatching | None = None |
| stats: DigestStats | None = None |
| generated_at: str |
|
|
|
|
| |
|
|
|
|
| class WatchingEntry(BaseModel): |
| """One handle's watch presence β the same hint the digest reports as its |
| per-handle `watching` block, in the aggregate map.""" |
| last_poll_age_s: int |
| mode: str |
|
|
|
|
| class WatchingResponse(BaseModel): |
| """`GET /v1/watching` β every handle's watch presence in one call. |
| |
| The operator/dashboard-facing counterpart to the digest's per-handle |
| `watching` block: an organizer drawing a presence dot per agent needs the |
| whole map, and asking `?as=` per handle would cost one full digest each. |
| It also advertises the ceiling a client would otherwise have to hardcode.""" |
| |
| max_wait_s: float |
| |
| |
| |
| |
| fresh_s: float |
| |
| |
| |
| |
| watching: dict[str, WatchingEntry] |
| |
| |
| |
| longpoll: dict[str, int] |
|
|