feat: update session notices and skill reloads

This commit is contained in:
Dax Raad 2026-07-01 14:37:27 -04:00
commit fb884bb91e
29 changed files with 304 additions and 75 deletions

View file

@ -163,6 +163,9 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
case "agent.updated":
void result.location.agent.refresh(event.location)
break
case "skill.updated":
void result.location.skill.refresh(event.location)
break
case "session.next.agent.switched":
if (store.session.info[event.data.sessionID])
setStore("session", "info", event.data.sessionID, "agent", event.data.agent)
@ -248,6 +251,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
type: "synthetic",
sessionID: event.data.sessionID,
text: event.data.text,
description: event.data.description,
time: { created: event.data.timestamp },
})
})

View file

@ -1250,13 +1250,14 @@ function SessionSwitchMessageV2(props: { message: SessionMessage }) {
function SessionNoticeMessageV2(props: { message: SessionMessage }) {
const { theme } = useTheme()
const text = () => {
if (props.message.type === "system" || props.message.type === "synthetic") return props.message.text
if (props.message.type === "system") return "Instructions updated"
if (props.message.type === "synthetic") return props.message.description ?? ""
return ""
}
return (
<box paddingLeft={3}>
<text fg={theme.textMuted}>{text()}</text>
</box>
<InlineToolRow icon="◈" color={theme.textMuted} pending="Notice" complete={true}>
{text()}
</InlineToolRow>
)
}

View file

@ -119,7 +119,9 @@ export function createSessionRows(sessionID: Accessor<string>) {
data.on("session.next.prompt.admitted", message),
data.on("session.next.prompted", message),
data.on("session.next.context.updated", message),
data.on("session.next.synthetic", message),
data.on("session.next.synthetic", (event) => {
if (event.data.sessionID === sessionID() && event.data.description?.trim()) appendMessage(event.data.messageID)
}),
data.on("session.next.shell.started", message),
data.on("session.next.agent.switched", message),
data.on("session.next.model.switched", message),
@ -160,6 +162,7 @@ export function createSessionRows(sessionID: Accessor<string>) {
export function reduceSessionRows(messages: SessionMessage[]) {
return messages.reduce<SessionRow[]>((rows, message) => {
if (message.type !== "assistant") {
if (message.type === "synthetic" && !message.description?.trim()) return rows
completePrevious(rows)
rows.push({ type: "message", messageID: message.id })
return rows

View file

@ -122,6 +122,66 @@ test("completes exploration groups when another row follows", () => {
])
})
test("hides synthetic messages without descriptions", () => {
const messages: SessionMessage[] = [
assistant("assistant-1", [{ type: "tool", id: "read-1", name: "read", state: pending(), time: { created: 1 } }]),
{
type: "synthetic",
id: "synthetic-1",
sessionID: "session-1",
text: "internal context",
time: { created: 2 },
},
assistant("assistant-2", [{ type: "tool", id: "grep-1", name: "grep", state: pending(), time: { created: 3 } }]),
]
expect(reduceSessionRows(messages)).toEqual([
{
type: "group",
kind: "exploration",
pending: [],
completed: false,
refs: [
{ messageID: "assistant-1", partID: "read-1" },
{ messageID: "assistant-2", partID: "grep-1" },
],
},
])
})
test("renders synthetic messages with descriptions", () => {
const messages: SessionMessage[] = [
assistant("assistant-1", [{ type: "tool", id: "read-1", name: "read", state: pending(), time: { created: 1 } }]),
{
type: "synthetic",
id: "synthetic-1",
sessionID: "session-1",
text: "internal context",
description: "Explicit notice",
time: { created: 2 },
},
assistant("assistant-2", [{ type: "tool", id: "grep-1", name: "grep", state: pending(), time: { created: 3 } }]),
]
expect(reduceSessionRows(messages)).toEqual([
{
type: "group",
kind: "exploration",
pending: [],
completed: true,
refs: [{ messageID: "assistant-1", partID: "read-1" }],
},
{ type: "message", messageID: "synthetic-1" },
{
type: "group",
kind: "exploration",
pending: [],
completed: false,
refs: [{ messageID: "assistant-2", partID: "grep-1" }],
},
])
})
function assistant(id: string, content: SessionMessageAssistant["content"]): SessionMessageAssistant {
return {
type: "assistant",