fix(assistant): unify tool rendering and stack detail fields
Use generic MCP result rendering and place labels above values on macOS and iOS. Update existing presentation expectations. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
3b104e3046
commit
f117777ef8
5 files changed
+8
-14
No files matched your search
@@ -38,7 +38,7 @@ public struct AssistantToolDetails: View {
|
||||
@ViewBuilder private func item(_ value: AgentToolDetail.Item) -> some View {
|
||||
switch value {
|
||||
case .field(let field):
|
||||
HStack(alignment: .firstTextBaseline, spacing: 8) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(field.label).font(.caption.weight(.medium)).foregroundStyle(.secondary)
|
||||
if !field.value.isEmpty {
|
||||
if let navigation = field.navigation, let navigate {
|
||||
@@ -54,6 +54,8 @@ public struct AssistantToolDetails: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
case .message(let text, let tint): Text(text).foregroundStyle(color(tint))
|
||||
case .text(let block):
|
||||
if let title = block.title { Text(title).font(.caption.weight(.medium)).foregroundStyle(.secondary) }
|
||||
|
||||
@@ -24,9 +24,7 @@ nonisolated public enum TermindToolPresentationProfiles {
|
||||
|
||||
public static func profile(for descriptor: AgentToolDescriptor) -> AgentToolPresentationProfile {
|
||||
if descriptor.target == .mcp {
|
||||
var profile = AgentToolPresentationProfile()
|
||||
profile.preservesUnprojectedJSON = true
|
||||
return profile
|
||||
return .init()
|
||||
}
|
||||
// Privacy is independent of presenter availability; it is not semantic recovery.
|
||||
if descriptor.target == .local,
|
||||
|
||||
@@ -1545,14 +1545,13 @@ private enum NativeTranscriptFactory {
|
||||
) -> NSView {
|
||||
switch item {
|
||||
case .field(let field):
|
||||
let row = NativeStack.horizontal(spacing: Metrics.Space.s)
|
||||
let row = NativeStack.vertical(spacing: Metrics.Space.xs)
|
||||
let key = NativeLabel(
|
||||
field.label,
|
||||
font: .systemFont(ofSize: NSFont.smallSystemFontSize, weight: .medium),
|
||||
color: .secondaryLabelColor
|
||||
)
|
||||
if field.value.isEmpty { return key }
|
||||
key.widthAnchor.constraint(greaterThanOrEqualToConstant: 76).isActive = true
|
||||
row.addArrangedSubview(key)
|
||||
let font: NSFont =
|
||||
field.isMonospaced
|
||||
|
||||
@@ -82,7 +82,7 @@ struct AgentToolPresentationProfileTests {
|
||||
#expect(detail.layout.singleLineHeader)
|
||||
let fallback = try #require(TermindToolPresentationProfiles.renderer.detail(for: card))
|
||||
#expect(fallback.items != detail.items)
|
||||
#expect(AgentToolDetailPreview(fallback).fullText.contains("\"value\""))
|
||||
#expect(fallback.items == [.field(.init(label: "Value", value: "42"))])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -280,7 +280,7 @@ struct AgentToolPresentationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
func builtInFallbackUsesFieldsWhileMCPKeepsJSON() throws {
|
||||
func builtInAndMCPFallbackUseTheSameFields() throws {
|
||||
let payload = AgentJSONValue.object([
|
||||
"internal_flag": .bool(true), "count": .number(2),
|
||||
]).encodedString
|
||||
@@ -306,12 +306,7 @@ struct AgentToolPresentationTests {
|
||||
let mcpDetail = try #require(
|
||||
TermindToolPresentationProfiles.renderer.detail(
|
||||
for: mcp, presenter: AppDependencies.toolPresenter(for: mcp.descriptor)))
|
||||
guard case .text(let block) = try #require(mcpDetail.items.first) else {
|
||||
Issue.record("Expected MCP JSON text")
|
||||
return
|
||||
}
|
||||
#expect(block.text.contains("{"))
|
||||
#expect(block.text.contains("\"internal_flag\""))
|
||||
#expect(mcpDetail.items == builtInDetail.items)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user