feat(tooling): preserve native tool titles#1133
Conversation
There was a problem hiding this comment.
Findings
- [Major] Native titles still do not render for OpenCode local unknown/lowercase tools —
parseToolCallnow preservesstate.titlewhile keeping tool names such asbash, but the web call sites pass that title throughdescriptionandgetToolPresentationignoresdescriptionon its unknown-tool path. For OpenCode localbash, the card still rendersbashinstead ofRun project tests, so the core feature in this PR is lost for that backend. Evidence:cli/src/opencode/utils/opencodeLocalToolParse.test.ts:33,web/src/components/ToolCard/ToolCard.tsx:322, related contextweb/src/components/ToolCard/knownTools.tsx:551.
Suggested fix:// web/src/components/ToolCard/knownTools.tsx type ToolOpts = { toolName: string input: unknown result: unknown childrenCount: number description: string | null nativeTitle?: string | null metadata: SessionMetadataSummary | null } // In the unknown-tool fallback: let title = opts.nativeTitle ?? opts.description ?? opts.toolName if (subtitle && subtitle === title) { if (filePath) title = t ? t('tool.semanticTitle.readFile') : 'Read file' else if (command) title = t ? t('tool.semanticTitle.runShell') : 'Run shell' else if (pattern) title = t ? t('tool.semanticTitle.search') : 'Search' else if (url) title = t ? t('tool.semanticTitle.openUrl') : 'Open URL' else if (query) title = t ? t('tool.semanticTitle.query') : 'Query' }
Questions
- None.
Summary
- Review mode: initial
- One rendering bug found; preserved OpenCode native titles can still be dropped at presentation time for lowercase/unknown tool names.
Testing
- Not run (automation)
HAPI Bot
| result: props.block.tool.result, | ||
| childrenCount: props.block.children.length, | ||
| description: props.block.tool.description, | ||
| description: props.block.tool.nativeTitle ?? props.block.tool.description, |
There was a problem hiding this comment.
[Major] Native titles are still ignored for lower-case/unknown OpenCode tools.
OpenCode local parsing now preserves state.title while keeping names like bash, but this call site tunnels the title through description. getToolPresentation only reads description for known tools such as Bash/shell_command; the unknown fallback uses opts.toolName, so OpenCode local bash still renders as bash instead of the native title.
Suggested fix:
// web/src/components/ToolCard/knownTools.tsx
type ToolOpts = {
toolName: string
input: unknown
result: unknown
childrenCount: number
description: string | null
nativeTitle?: string | null
metadata: SessionMetadataSummary | null
}
// In the unknown-tool fallback:
let title = opts.nativeTitle ?? opts.description ?? opts.toolName
if (subtitle && subtitle === title) {
if (filePath) title = t ? t('tool.semanticTitle.readFile') : 'Read file'
else if (command) title = t ? t('tool.semanticTitle.runShell') : 'Run shell'
else if (pattern) title = t ? t('tool.semanticTitle.search') : 'Search'
else if (url) title = t ? t('tool.semanticTitle.openUrl') : 'Open URL'
else if (query) title = t ? t('tool.semanticTitle.query') : 'Query'
}3dea4b6 to
ed3641b
Compare
There was a problem hiding this comment.
Findings
- [Major] OpenCode execute-hook late calls still drop native titles —
tool.execute.beforenow forwardsnativeTitle, but the same branch returns early whenbeforehas empty{}input. In that documented fallback, the only tool-call emitted is fromtool.execute.after, and that recovery payload still omitsnativeTitle, so native titles are lost for tools whose usable args arrive only onafter. Evidence:cli/src/opencode/opencodeLocalLauncher.ts:424.
Suggested fix:const nativeTitle = getString(tool.title ?? record.title); session.sendAgentMessage({ type: 'tool-call', name, callId, input: toolInput, ...(nativeTitle ? { nativeTitle } : {}) });
- [Minor] Single tool cards can keep a stale presentation when only
nativeTitlechanges — the memo readsprops.block.tool.nativeTitle, whileensureToolBlockcan updatenativeTitleon an existing block independently ofdescription; becausenativeTitleis not in the dependency list, a live metadata-only update can leave the visible title unchanged until another dependency changes. Evidence:web/src/components/ToolCard/ToolCard.tsx:322.
Suggested fix:], [ props.block.tool.name, props.block.tool.input, props.block.tool.result, props.block.children.length, props.block.tool.nativeTitle, props.block.tool.description, props.metadata, t ])
Questions
- None.
Summary
- Review mode: follow-up after new commits
- Two issues found in the updated title-preservation paths: one OpenCode local fallback still drops the title, and one web memo can stale on live metadata-only updates.
Testing
- Not run (automation; static review only)
HAPI Bot
| callId, | ||
| input: toolInput | ||
| input: toolInput, | ||
| ...(getString(tool.title ?? record.title) ? { nativeTitle: getString(tool.title ?? record.title) } : {}) |
There was a problem hiding this comment.
[Major] Native titles are still dropped on the execute-hook late recovery path.
This adds nativeTitle only to the tool.execute.before emission, but that branch returns early when before carries placeholder {} input. In that documented fallback, the only tool-call is emitted from tool.execute.after, and that recovery payload still omits the same title, so tools whose real args arrive only on after lose the native title.
Suggested fix:
const nativeTitle = getString(tool.title ?? record.title);
session.sendAgentMessage({
type: 'tool-call',
name,
callId,
input: toolInput,
...(nativeTitle ? { nativeTitle } : {})
});| result: props.block.tool.result, | ||
| childrenCount: props.block.children.length, | ||
| description: props.block.tool.description, | ||
| description: props.block.tool.nativeTitle ?? props.block.tool.description, |
There was a problem hiding this comment.
[Minor] Include nativeTitle in the presentation memo dependencies.
The memo now reads props.block.tool.nativeTitle, and ensureToolBlock can update nativeTitle on an existing block without changing description. If a live update only adds presentation metadata, this card can keep rendering the old title until another listed dependency changes.
Suggested fix:
], [
props.block.tool.name,
props.block.tool.input,
props.block.tool.result,
props.block.children.length,
props.block.tool.nativeTitle,
props.block.tool.description,
props.metadata,
t
])ed3641b to
528d454
Compare
There was a problem hiding this comment.
Findings
- No issues found.
Questions
- None.
Summary
- Review mode: follow-up after new commits
- Full current diff reviewed. Prior bot findings appear addressed: native titles are forwarded on the OpenCode late execute recovery path, and the ToolCard presentation memo now depends on
nativeTitle. - Residual risk: static review only; I did not execute PR code.
Testing
- Not run (security/static review only; PR reports
bun typecheck, targeted CLI/web tests, andbun run testpassing)
HAPI Bot
Summary
titleandkindthrough the generic agent conversion pathCloses #1130
Verification
bun typecheckbun run test— CLI 1381, hub 505, web 1298, shared 115 tests passed