fix(contracts): SessionLiveInfo model/tools/skills stay optional — lazy and mirror paths emit session.info without them

The strict suite showed 41 emit sites sending {model} or {} alone; the TUI
banner coerces the missing maps instead of the contract lying about them.
This commit is contained in:
teknium1
2026-09-14 02:22:10 -07:00
committed by Teknium
parent cdf949877a
commit b67441309c
4 changed files with 19 additions and 25 deletions
@@ -515,15 +515,15 @@ export interface ConfigSetResult {
}
/** ``tui_gateway/server.py::_session_info`` — the ``session.info`` event and the ``info`` field of ``session.create`` / ``session.resume`` / ``session.activate`` results. */
export interface SessionLiveInfo {
model: string
model?: string
provider?: string
reasoning_effort?: string
service_tier?: string
fast?: boolean
yolo?: boolean
approval_mode?: string
tools: Record<string, string[]>
skills: Record<string, string[]>
tools?: Record<string, string[]>
skills?: Record<string, string[]>
cwd?: string
branch?: string | null
project?: ProjectRef | null
@@ -2615,15 +2615,15 @@ export interface SessionCwdSetParams {
}
/** The refreshed ``session.info`` view (full agent view, or the lazy shape). */
export interface SessionCwdSetResult {
model: string
model?: string
provider?: string
reasoning_effort?: string
service_tier?: string
fast?: boolean
yolo?: boolean
approval_mode?: string
tools: Record<string, string[]>
skills: Record<string, string[]>
tools?: Record<string, string[]>
skills?: Record<string, string[]>
cwd?: string
branch?: string | null
project?: ProjectRef | null
+2 -10
View File
@@ -24503,6 +24503,7 @@
"description": "The refreshed ``session.info`` view (full agent view, or the lazy shape).",
"properties": {
"model": {
"default": "",
"title": "Model",
"type": "string"
},
@@ -24728,11 +24729,6 @@
"title": "Lazy"
}
},
"required": [
"model",
"tools",
"skills"
],
"title": "SessionCwdSetResult",
"type": "object"
},
@@ -25357,6 +25353,7 @@
"description": "``tui_gateway/server.py::_session_info`` \u2014 the ``session.info`` event and the ``info`` field of\n``session.create`` / ``session.resume`` / ``session.activate`` results.",
"properties": {
"model": {
"default": "",
"title": "Model",
"type": "string"
},
@@ -25582,11 +25579,6 @@
"title": "Lazy"
}
},
"required": [
"model",
"tools",
"skills"
],
"title": "SessionLiveInfo",
"type": "object"
},
+3 -3
View File
@@ -62,15 +62,15 @@ 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
model: str = ""
provider: str = ""
reasoning_effort: str = ""
service_tier: str = ""
fast: bool = False
yolo: bool = False
approval_mode: str = "manual"
tools: dict[str, list[str]]
skills: dict[str, list[str]]
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
+8 -6
View File
@@ -250,8 +250,9 @@ export function SessionPanel({ info, maxWidth, sid, t }: SessionPanelProps) {
}
// ── Collapsible skills section ──
const skillEntries = Object.entries(info.skills).sort()
const skillsTotal = flat(info.skills).length
const skills = info.skills ?? {}
const skillEntries = Object.entries(skills).sort()
const skillsTotal = flat(skills).length
const skillsCatCount = skillEntries.length
const skillsBody = () => {
@@ -276,8 +277,9 @@ export function SessionPanel({ info, maxWidth, sid, t }: SessionPanelProps) {
}
// ── Collapsible tools section ──
const toolEntries = Object.entries(info.tools).sort()
const toolsTotal = flat(info.tools).length
const tools = info.tools ?? {}
const toolEntries = Object.entries(tools).sort()
const toolsTotal = flat(tools).length
// MCP headline counts *connected* servers, not configured-but-disabled ones,
// so it matches the classic CLI banner (`sum(s.connected)` in
@@ -354,7 +356,7 @@ export function SessionPanel({ info, maxWidth, sid, t }: SessionPanelProps) {
<Text />
<Text color={t.color.accent}>
{info.model.split('/').pop()}
{(info.model ?? '').split('/').pop()}
<Text color={t.color.muted}> · Nous Research</Text>
</Text>
@@ -386,7 +388,7 @@ export function SessionPanel({ info, maxWidth, sid, t }: SessionPanelProps) {
// here so they aren't lost.
<Box flexDirection="column" marginBottom={1}>
<Text color={t.color.accent} wrap="truncate-end">
{info.model.split('/').pop()}
{(info.model ?? '').split('/').pop()}
<Text color={t.color.muted}> · Nous Research</Text>
</Text>
<Text color={t.color.muted} wrap="truncate-end">