Skip to content

ACP: Name new chats "Untitled Chat N" and rename to the ACP session title on start (wire session_info_update) #404

Description

@gnoviawan

Will you contribute an implementation?

Yes — I plan to open a pull request.

Problem or Opportunity

When a new ACP agent chat is created, the chat shows a placeholder name like Agent 5f3a9c1b — the literal string Agent plus a slice of the random agent/session id. This comes from the deriveTitle() fallback:

// src/renderer/lib/acp-history-persistence.ts:49-55
export function deriveTitle(messages: ChatMessage[], agentId: string): string {
  const firstUser = messages.find((m) => m.role === 'user')
  if (firstUser) {
    const text = firstUser.blocks
      .map((b) => (b.type === 'text' ? (b.text ?? '') : ''))
      .join(' ')
      .trim()
    if (text.length > 0) return text.length > 40 ? `${text.slice(0, 40)}…` : text
  }
  return `Agent ${agentId.slice(0, 8)}` // ← random-looking placeholder
}

A freshly created session has title: null and no messages yet (src/renderer/stores/acp-store.ts:103, :798), so the Chats history list renders Agent <random>. This is noisy and meaningless to the user — it looks like a bug, and multiple new chats are hard to tell apart.

Separately, ACP already defines a first-class mechanism for agent-generated session titles, but Termul currently throws those titles away. The session_info_update notification (agent → client) is dropped in the Rust client:

// src-tauri/src/acp/client.rs:296-303
// SessionInfoUpdate and any future (non_exhaustive) variants have no
// dedicated P0 event; ignore them — but log so a silently-dropped
// update can be diagnosed instead of vanishing.
ref other => {
    log::debug!("[acp] agent {agent_id} sent an unhandled session/update variant: {other:?}");
}

So even when an ACP agent auto-generates a nice session title after the first prompt (e.g. "Implement user authentication"), the renderer never sees it and the chat keeps its placeholder / first-message-slice name.

Proposed Solution

Two coordinated changes:

1. Friendly placeholder for not-yet-started chats

Replace the Agent <random> fallback with an incrementing Untitled Chat N label (e.g. Untitled Chat 1, Untitled Chat 2, …). The number comes from a monotonic counter so concurrent new chats stay distinguishable.

2. Rename on chat start using the ACP session title

Wire the ACP session_info_update notification end-to-end so a started chat is renamed to the agent-provided session name, with a graceful fallback chain:

agent-pushed title (session_info_update)first user message (existing deriveTitle behavior)Untitled Chat N

Per the ACP spec, SessionInfo.title is "Human-readable title for the session. May be auto-generated from the first prompt," and agents send session_info_update "after the first meaningful exchange to auto-generate a title" — exactly the "rename when the chat starts" behavior requested here.

Implementation outline:

  • Rust (src-tauri/src/acp/)
    • Add EVENT_SESSION_INFO_UPDATE (acp:session_info_update) in events.rs and a SessionInfoUpdateEvent { agent_id, session_id, title } struct.
    • In client.rs::emit_session_update, handle SessionUpdate::SessionInfoUpdate and emit the new event instead of letting it fall into the debug-log catch-all.
  • Renderer API (src/renderer/lib/acp-api.ts)
    • Add sessionInfoUpdate: 'acp:session_info_update' to ACP_EVENTS (~line 312) and export a SessionInfoUpdateEvent type.
  • Store (src/renderer/stores/acp-store.ts)
    • Add _onSessionInfoUpdate reducer that sets session.title from the agent title and re-persists the session index entry; subscribe it in initAcpEventListeners.
    • Introduce the Untitled Chat N counter and use it as the placeholder.
  • Persistence (src/renderer/lib/acp-history-persistence.ts)
    • Update deriveTitle() fallback to Untitled Chat N.

Alternatives Considered

  • Keep deriving from the first user message only — already the current behavior once a message exists, but it does nothing for the pre-prompt placeholder and ignores the richer agent-generated titles ACP already provides.
  • session/setTitle (client → agent), spec PR #1199 — enables user-initiated rename pushed back to the agent. It's not in Termul's vendored SDK yet (only session_info_update is stabilized — see src-tauri/vendor/agent-client-protocol/CHANGELOG.md:102), so it's out of scope here but a natural follow-up for manual rename.

Success Criteria

Additional Context

ACP references

Code references

  • src/renderer/lib/acp-history-persistence.ts:49-55deriveTitle() placeholder
  • src-tauri/src/acp/client.rs:296-303 — dropped SessionInfoUpdate
  • src/renderer/stores/acp-store.ts:103, :476, :798 — session title lifecycle
  • src/renderer/lib/acp-api.ts:312ACP_EVENTS
  • src-tauri/src/acp/events.rs:20-47acp:* event constants
  • src/renderer/components/chat/AgentBadge.tsx:33, src/renderer/components/workspace/WorkspaceTabBar.tsx:649 — label surfaces

Related: Complements #363 (item #2 calls out the dropped SessionInfoUpdate); this issue is the "implement it properly" counterpart.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions