|
|
@@ -5,7 +5,66 @@ import {
|
|
|
formatPart,
|
|
|
formatTranscript,
|
|
|
} from "../../../src/cli/cmd/tui/util/transcript"
|
|
|
-import type { AssistantMessage, Part, UserMessage } from "@opencode-ai/sdk/v2"
|
|
|
+import type { AssistantMessage, Part, Provider, UserMessage } from "@opencode-ai/sdk/v2"
|
|
|
+
|
|
|
+const providers: Provider[] = [
|
|
|
+ {
|
|
|
+ id: "anthropic",
|
|
|
+ name: "Anthropic",
|
|
|
+ source: "api",
|
|
|
+ env: [],
|
|
|
+ options: {},
|
|
|
+ models: {
|
|
|
+ "claude-sonnet-4-20250514": {
|
|
|
+ id: "claude-sonnet-4-20250514",
|
|
|
+ providerID: "anthropic",
|
|
|
+ api: {
|
|
|
+ id: "claude-sonnet-4-20250514",
|
|
|
+ url: "https://example.com/claude-sonnet-4-20250514",
|
|
|
+ npm: "@ai-sdk/anthropic",
|
|
|
+ },
|
|
|
+ name: "Claude Sonnet 4",
|
|
|
+ capabilities: {
|
|
|
+ temperature: true,
|
|
|
+ reasoning: true,
|
|
|
+ attachment: true,
|
|
|
+ toolcall: true,
|
|
|
+ input: {
|
|
|
+ text: true,
|
|
|
+ audio: false,
|
|
|
+ image: true,
|
|
|
+ video: false,
|
|
|
+ pdf: true,
|
|
|
+ },
|
|
|
+ output: {
|
|
|
+ text: true,
|
|
|
+ audio: false,
|
|
|
+ image: false,
|
|
|
+ video: false,
|
|
|
+ pdf: false,
|
|
|
+ },
|
|
|
+ interleaved: false,
|
|
|
+ },
|
|
|
+ cost: {
|
|
|
+ input: 0,
|
|
|
+ output: 0,
|
|
|
+ cache: {
|
|
|
+ read: 0,
|
|
|
+ write: 0,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ limit: {
|
|
|
+ context: 200_000,
|
|
|
+ output: 8_192,
|
|
|
+ },
|
|
|
+ status: "active",
|
|
|
+ options: {},
|
|
|
+ headers: {},
|
|
|
+ release_date: "2025-05-14",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+]
|
|
|
|
|
|
describe("transcript", () => {
|
|
|
describe("formatAssistantHeader", () => {
|
|
|
@@ -29,6 +88,11 @@ describe("transcript", () => {
|
|
|
expect(result).toBe("## Assistant (Build · claude-sonnet-4-20250514 · 5.4s)\n\n")
|
|
|
})
|
|
|
|
|
|
+ test("uses model display name when available", () => {
|
|
|
+ const result = formatAssistantHeader(baseMsg, true, providers)
|
|
|
+ expect(result).toBe("## Assistant (Build · Claude Sonnet 4 · 5.4s)\n\n")
|
|
|
+ })
|
|
|
+
|
|
|
test("excludes metadata when disabled", () => {
|
|
|
const result = formatAssistantHeader(baseMsg, false)
|
|
|
expect(result).toBe("## Assistant\n\n")
|
|
|
@@ -196,7 +260,7 @@ describe("transcript", () => {
|
|
|
})
|
|
|
|
|
|
describe("formatMessage", () => {
|
|
|
- const options = { thinking: true, toolDetails: true, assistantMetadata: true }
|
|
|
+ const options = { thinking: true, toolDetails: true, assistantMetadata: true, providers }
|
|
|
|
|
|
test("formats user message", () => {
|
|
|
const msg: UserMessage = {
|
|
|
@@ -230,7 +294,7 @@ describe("transcript", () => {
|
|
|
}
|
|
|
const parts: Part[] = [{ id: "p1", sessionID: "ses_123", messageID: "msg_123", type: "text", text: "Hi there" }]
|
|
|
const result = formatMessage(msg, parts, options)
|
|
|
- expect(result).toContain("## Assistant (Build · claude-sonnet-4-20250514 · 5.4s)")
|
|
|
+ expect(result).toContain("## Assistant (Build · Claude Sonnet 4 · 5.4s)")
|
|
|
expect(result).toContain("Hi there")
|
|
|
})
|
|
|
})
|
|
|
@@ -272,7 +336,12 @@ describe("transcript", () => {
|
|
|
parts: [{ id: "p2", sessionID: "ses_abc123", messageID: "msg_2", type: "text" as const, text: "Hi!" }],
|
|
|
},
|
|
|
]
|
|
|
- const options = { thinking: false, toolDetails: false, assistantMetadata: true }
|
|
|
+ const options = {
|
|
|
+ thinking: false,
|
|
|
+ toolDetails: false,
|
|
|
+ assistantMetadata: true,
|
|
|
+ providers,
|
|
|
+ }
|
|
|
|
|
|
const result = formatTranscript(session, messages, options)
|
|
|
|
|
|
@@ -280,11 +349,46 @@ describe("transcript", () => {
|
|
|
expect(result).toContain("**Session ID:** ses_abc123")
|
|
|
expect(result).toContain("## User")
|
|
|
expect(result).toContain("Hello")
|
|
|
- expect(result).toContain("## Assistant (Build · claude-sonnet-4-20250514 · 0.5s)")
|
|
|
+ expect(result).toContain("## Assistant (Build · Claude Sonnet 4 · 0.5s)")
|
|
|
expect(result).toContain("Hi!")
|
|
|
expect(result).toContain("---")
|
|
|
})
|
|
|
|
|
|
+ test("falls back to raw model id when provider data is missing", () => {
|
|
|
+ const session = {
|
|
|
+ id: "ses_abc123",
|
|
|
+ title: "Test Session",
|
|
|
+ time: { created: 1000000000000, updated: 1000000001000 },
|
|
|
+ }
|
|
|
+ const messages = [
|
|
|
+ {
|
|
|
+ info: {
|
|
|
+ id: "msg_1",
|
|
|
+ sessionID: "ses_abc123",
|
|
|
+ role: "assistant" as const,
|
|
|
+ agent: "build",
|
|
|
+ modelID: "claude-sonnet-4-20250514",
|
|
|
+ providerID: "anthropic",
|
|
|
+ mode: "",
|
|
|
+ parentID: "msg_0",
|
|
|
+ path: { cwd: "/test", root: "/test" },
|
|
|
+ cost: 0.001,
|
|
|
+ tokens: { input: 100, output: 50, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
|
+ time: { created: 1000000000100, completed: 1000000000600 },
|
|
|
+ },
|
|
|
+ parts: [{ id: "p1", sessionID: "ses_abc123", messageID: "msg_1", type: "text" as const, text: "Response" }],
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ const result = formatTranscript(session, messages, {
|
|
|
+ thinking: false,
|
|
|
+ toolDetails: false,
|
|
|
+ assistantMetadata: true,
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(result).toContain("## Assistant (Build · claude-sonnet-4-20250514 · 0.5s)")
|
|
|
+ })
|
|
|
+
|
|
|
test("formats transcript without assistant metadata", () => {
|
|
|
const session = {
|
|
|
id: "ses_abc123",
|