The branch-render guard landed earlier (78b133127d); what remained was
provenance: a projected continuation tip rendered as a brand-new
session. list_sessions_rich now stamps continuation_kind='compression'
on projected rows, StoredSessionRow carries it (contracts regenerated),
and the sidebar session row labels continuations with their lineage
root instead of a fresh-conversation affordance. The live tip stays
listable while naming its parent; sealed chain segments stay hidden.
Co-authored-by: wave-2 worker D <wave2d@hermes-triage>
271 lines
8.2 KiB
Python
271 lines
8.2 KiB
Python
"""Value shapes shared by several methods and events (declared once, imported everywhere)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Annotated, Literal
|
|
|
|
from pydantic import Field
|
|
|
|
from .base import JsonValue, Params, Payload, Result, WireEnum
|
|
|
|
|
|
class OpenModel(Result):
|
|
"""A result/payload row whose known fields are typed but which the producer may extend
|
|
(the closed set is owned elsewhere: hermes_state rows, provider inventories)."""
|
|
|
|
model_config = Result.model_config | {"extra": "allow"}
|
|
|
|
|
|
class Usage(OpenModel):
|
|
"""``tui_gateway/server.py::_get_usage`` + ``agent/context_breakdown.py::context_usage_fields``."""
|
|
|
|
model: str = ""
|
|
input: int = 0
|
|
output: int = 0
|
|
reasoning: int = 0
|
|
prompt: int = 0
|
|
completion: int = 0
|
|
total: int = 0
|
|
calls: int = 0
|
|
compressions: int | None = None
|
|
context_used: int | None = None
|
|
context_max: int | None = None
|
|
context_percent: int | None = None
|
|
context_source: str | None = None
|
|
context_estimated: bool | None = None
|
|
cache_hit_pct: int | None = None
|
|
cache_read: int | None = None
|
|
cache_write: int | None = None
|
|
avg_latency_s: float | None = None
|
|
avg_tps: float | None = None
|
|
active_subagents: int | None = None
|
|
dev_credits_spent_micros: int | None = None
|
|
cost_usd: float | None = None
|
|
cost_status: str | None = None
|
|
|
|
|
|
class ProjectRef(Result):
|
|
"""``tui_gateway/server.py::_project_info_for_cwd``."""
|
|
|
|
id: str
|
|
slug: str
|
|
name: str
|
|
primary_path: str | None = None
|
|
|
|
|
|
class McpServerStatus(OpenModel):
|
|
name: str = ""
|
|
status: str | None = None
|
|
tool_count: int | None = None
|
|
error: str | None = None
|
|
|
|
|
|
class SessionLiveInfo(OpenModel):
|
|
"""``tui_gateway/server.py::_session_info`` — the ``session.info`` event and the ``info`` field of
|
|
``session.create`` / ``session.resume`` / ``session.activate`` results."""
|
|
|
|
model: str = ""
|
|
provider: str = ""
|
|
reasoning_effort: str = ""
|
|
# The level the route's entry clamp actually sends for ``reasoning_effort`` ("" when unset/none;
|
|
# equal when verbatim). Lets clients label a clamped Hermes step ("ultra sends max on this route").
|
|
reasoning_effort_wire: str = ""
|
|
service_tier: str = ""
|
|
fast: bool = False
|
|
yolo: bool = False
|
|
approval_mode: str = "manual"
|
|
tools: dict[str, list[str]] = Field(default_factory=dict)
|
|
skills: dict[str, list[str]] = Field(default_factory=dict)
|
|
cwd: str = ""
|
|
branch: str | None = None
|
|
project: ProjectRef | None = None
|
|
terminal_backend: str = ""
|
|
personality: str = ""
|
|
running: bool = False
|
|
turn_started_at: float | None = None
|
|
title: str = ""
|
|
stored_session_id: str = ""
|
|
desktop_contract: int | str | None = None
|
|
version: str = ""
|
|
release_date: str = ""
|
|
update_behind: JsonValue | None = None
|
|
update_command: str = ""
|
|
usage: Usage | None = None
|
|
profile_name: str | None = None
|
|
mcp_servers: list[McpServerStatus] = Field(default_factory=list)
|
|
system_prompt: str | None = None
|
|
credential_warning: str | None = None
|
|
lazy: bool | None = None
|
|
|
|
|
|
class StoredSessionRow(OpenModel):
|
|
"""One ``sessions`` row as ``hermes_state`` lists it (``session.list`` / ``session.info`` rows /
|
|
``sessions.changed``)."""
|
|
|
|
id: str
|
|
title: str | None = None
|
|
preview: str | None = None
|
|
source: str | None = None
|
|
model: str | None = None
|
|
started_at: float | None = None
|
|
ended_at: float | None = None
|
|
last_active: float | None = None
|
|
message_count: int = 0
|
|
tool_call_count: int = 0
|
|
input_tokens: int = 0
|
|
output_tokens: int = 0
|
|
is_active: bool = False
|
|
cwd: str | None = None
|
|
git_branch: str | None = None
|
|
git_repo_root: str | None = None
|
|
parent_session_id: str | None = None
|
|
pinned: bool | None = None
|
|
unread: bool | None = None
|
|
archived: bool | None = None
|
|
actual_cost_usd: float | None = None
|
|
estimated_cost_usd: float | None = None
|
|
handoff_platform: str | None = None
|
|
handoff_state: str | None = None
|
|
lineage_root_id: str | None = Field(default=None, alias="_lineage_root_id")
|
|
lineage_ids: list[str] | None = Field(default=None, alias="_lineage_ids")
|
|
# #121148: provenance of a projected continuation tip — 'compression' when the row
|
|
# continues a sealed segment (automatic rotation), None for plain rows and branches.
|
|
continuation_kind: str | None = None
|
|
|
|
|
|
class ToolLabelKind(WireEnum):
|
|
"""Which surface one inner call of a bridged ``tool_call`` runs on."""
|
|
|
|
connector = "connector"
|
|
mcp = "mcp"
|
|
tool = "tool"
|
|
|
|
|
|
class ToolLabel(Payload):
|
|
"""``tools.tool_labels.ToolLabel`` — what one call executed through the tool_search bridge is,
|
|
in words. Clients render ``text`` (or ``app``/``action`` in their own columns) and never parse
|
|
the tool name themselves."""
|
|
|
|
kind: ToolLabelKind
|
|
app: str
|
|
action: str
|
|
emoji: str
|
|
text: str
|
|
name: str
|
|
preview: str = ""
|
|
|
|
|
|
class TranscriptMessage(OpenModel):
|
|
"""One transcript row as the gateway PROJECTS it for renderers (``session_history._project_history``):
|
|
``text``, display-only ``timestamp`` / ``display_kind`` / ``display_metadata``, the durable ``row_id``
|
|
rewind targets, and for tool rows raw ``content``, ``tool_call_id``, ``name``, ``context`` and ``args``.
|
|
Assistant detail sidecars (``reasoning``, …) ride as extra keys."""
|
|
|
|
role: str
|
|
text: str | None = None
|
|
content: JsonValue | None = None
|
|
tool_call_id: str | None = None
|
|
timestamp: float | None = None
|
|
row_id: int | None = None
|
|
display_kind: str | None = None
|
|
display_metadata: JsonValue | None = None
|
|
name: str | None = None
|
|
context: str | None = None
|
|
args: dict[str, JsonValue] | None = None
|
|
labels: list[ToolLabel] | None = None
|
|
reasoning: str | None = None
|
|
|
|
|
|
class SubagentStatus(WireEnum):
|
|
"""Lifecycle of one delegated child (``tools/delegate_tool_child_run.py``); ``failed`` /
|
|
``error`` / ``timeout`` / ``interrupted`` / ``completed`` are terminal."""
|
|
|
|
queued = "queued"
|
|
running = "running"
|
|
completed = "completed"
|
|
failed = "failed"
|
|
error = "error"
|
|
timeout = "timeout"
|
|
interrupted = "interrupted"
|
|
|
|
|
|
TERMINAL_SUBAGENT_STATUSES = frozenset({
|
|
SubagentStatus.completed, SubagentStatus.failed, SubagentStatus.error,
|
|
SubagentStatus.timeout, SubagentStatus.interrupted,
|
|
})
|
|
|
|
|
|
class PendingApproval(OpenModel):
|
|
"""One unresolved ``tools/approval.py`` gateway queue entry as ``server._approval_request_payload``
|
|
renders it (command redacted; ``choices`` precomputed). The key set is owned by the approval tool."""
|
|
|
|
request_id: str | None = None
|
|
command: str | None = None
|
|
description: str | None = None
|
|
pattern_key: str | None = None
|
|
pattern_keys: list[str] | None = None
|
|
allow_permanent: bool | None = None
|
|
allow_session: bool | None = None
|
|
smart_denied: bool | None = None
|
|
choices: list[str] | None = None
|
|
tool_name: str | None = None
|
|
|
|
|
|
class MessageReaction(OpenModel):
|
|
"""One persisted reaction row (``hermes_state_messages.set_message_reaction``); ``seen`` is
|
|
stamped once announced."""
|
|
|
|
emoji: str
|
|
author: str
|
|
at: float | None = None
|
|
seen: bool | None = None
|
|
|
|
|
|
class SessionParams(Params):
|
|
"""Any method addressed at one live session."""
|
|
|
|
session_id: str
|
|
profile: str | None = None
|
|
|
|
|
|
class ProfileParams(Params):
|
|
"""Any method the desktop may route to a named profile (``requestGatewayForProfile`` adds ``profile``)."""
|
|
|
|
profile: str | None = None
|
|
|
|
|
|
class SessionOwner(Params):
|
|
type: Literal["session"]
|
|
session_id: str = Field(min_length=1)
|
|
|
|
|
|
class AccountOwner(Params):
|
|
type: Literal["account"]
|
|
|
|
|
|
ConnectorOwner = Annotated[SessionOwner | AccountOwner, Field(discriminator="type")]
|
|
|
|
|
|
class OkResult(Result):
|
|
ok: bool = True
|
|
|
|
|
|
class StatusResult(OpenModel):
|
|
status: str
|
|
|
|
|
|
class EmptyResult(Result):
|
|
pass
|
|
|
|
|
|
class EmptyPayload(Payload):
|
|
pass
|
|
|
|
|
|
__all__ = [
|
|
"TERMINAL_SUBAGENT_STATUSES", "AccountOwner", "ConnectorOwner", "EmptyPayload", "EmptyResult", "McpServerStatus",
|
|
"MessageReaction", "OkResult", "OpenModel", "PendingApproval",
|
|
"ProfileParams", "ProjectRef", "SessionLiveInfo", "SessionOwner", "SessionParams", "StatusResult", "StoredSessionRow",
|
|
"SubagentStatus", "ToolLabel", "ToolLabelKind", "TranscriptMessage", "Usage",
|
|
]
|