@@ -5,7 +5,66 @@ import {
55 formatPart ,
66 formatTranscript ,
77} from "../../../src/cli/cmd/tui/util/transcript"
8- import type { AssistantMessage , Part , UserMessage } from "@opencode-ai/sdk/v2"
8+ import type { AssistantMessage , Part , Provider , UserMessage } from "@opencode-ai/sdk/v2"
9+
10+ const providers : Provider [ ] = [
11+ {
12+ id : "anthropic" ,
13+ name : "Anthropic" ,
14+ source : "api" ,
15+ env : [ ] ,
16+ options : { } ,
17+ models : {
18+ "claude-sonnet-4-20250514" : {
19+ id : "claude-sonnet-4-20250514" ,
20+ providerID : "anthropic" ,
21+ api : {
22+ id : "claude-sonnet-4-20250514" ,
23+ url : "https://example.com/claude-sonnet-4-20250514" ,
24+ npm : "@ai-sdk/anthropic" ,
25+ } ,
26+ name : "Claude Sonnet 4" ,
27+ capabilities : {
28+ temperature : true ,
29+ reasoning : true ,
30+ attachment : true ,
31+ toolcall : true ,
32+ input : {
33+ text : true ,
34+ audio : false ,
35+ image : true ,
36+ video : false ,
37+ pdf : true ,
38+ } ,
39+ output : {
40+ text : true ,
41+ audio : false ,
42+ image : false ,
43+ video : false ,
44+ pdf : false ,
45+ } ,
46+ interleaved : false ,
47+ } ,
48+ cost : {
49+ input : 0 ,
50+ output : 0 ,
51+ cache : {
52+ read : 0 ,
53+ write : 0 ,
54+ } ,
55+ } ,
56+ limit : {
57+ context : 200_000 ,
58+ output : 8_192 ,
59+ } ,
60+ status : "active" ,
61+ options : { } ,
62+ headers : { } ,
63+ release_date : "2025-05-14" ,
64+ } ,
65+ } ,
66+ } ,
67+ ]
968
1069describe ( "transcript" , ( ) => {
1170 describe ( "formatAssistantHeader" , ( ) => {
@@ -29,6 +88,11 @@ describe("transcript", () => {
2988 expect ( result ) . toBe ( "## Assistant (Build · claude-sonnet-4-20250514 · 5.4s)\n\n" )
3089 } )
3190
91+ test ( "uses model display name when available" , ( ) => {
92+ const result = formatAssistantHeader ( baseMsg , true , providers )
93+ expect ( result ) . toBe ( "## Assistant (Build · Claude Sonnet 4 · 5.4s)\n\n" )
94+ } )
95+
3296 test ( "excludes metadata when disabled" , ( ) => {
3397 const result = formatAssistantHeader ( baseMsg , false )
3498 expect ( result ) . toBe ( "## Assistant\n\n" )
@@ -196,7 +260,7 @@ describe("transcript", () => {
196260 } )
197261
198262 describe ( "formatMessage" , ( ) => {
199- const options = { thinking : true , toolDetails : true , assistantMetadata : true }
263+ const options = { thinking : true , toolDetails : true , assistantMetadata : true , providers }
200264
201265 test ( "formats user message" , ( ) => {
202266 const msg : UserMessage = {
@@ -230,7 +294,7 @@ describe("transcript", () => {
230294 }
231295 const parts : Part [ ] = [ { id : "p1" , sessionID : "ses_123" , messageID : "msg_123" , type : "text" , text : "Hi there" } ]
232296 const result = formatMessage ( msg , parts , options )
233- expect ( result ) . toContain ( "## Assistant (Build · claude-sonnet-4-20250514 · 5.4s)" )
297+ expect ( result ) . toContain ( "## Assistant (Build · Claude Sonnet 4 · 5.4s)" )
234298 expect ( result ) . toContain ( "Hi there" )
235299 } )
236300 } )
@@ -272,19 +336,59 @@ describe("transcript", () => {
272336 parts : [ { id : "p2" , sessionID : "ses_abc123" , messageID : "msg_2" , type : "text" as const , text : "Hi!" } ] ,
273337 } ,
274338 ]
275- const options = { thinking : false , toolDetails : false , assistantMetadata : true }
339+ const options = {
340+ thinking : false ,
341+ toolDetails : false ,
342+ assistantMetadata : true ,
343+ providers,
344+ }
276345
277346 const result = formatTranscript ( session , messages , options )
278347
279348 expect ( result ) . toContain ( "# Test Session" )
280349 expect ( result ) . toContain ( "**Session ID:** ses_abc123" )
281350 expect ( result ) . toContain ( "## User" )
282351 expect ( result ) . toContain ( "Hello" )
283- expect ( result ) . toContain ( "## Assistant (Build · claude-sonnet-4-20250514 · 0.5s)" )
352+ expect ( result ) . toContain ( "## Assistant (Build · Claude Sonnet 4 · 0.5s)" )
284353 expect ( result ) . toContain ( "Hi!" )
285354 expect ( result ) . toContain ( "---" )
286355 } )
287356
357+ test ( "falls back to raw model id when provider data is missing" , ( ) => {
358+ const session = {
359+ id : "ses_abc123" ,
360+ title : "Test Session" ,
361+ time : { created : 1000000000000 , updated : 1000000001000 } ,
362+ }
363+ const messages = [
364+ {
365+ info : {
366+ id : "msg_1" ,
367+ sessionID : "ses_abc123" ,
368+ role : "assistant" as const ,
369+ agent : "build" ,
370+ modelID : "claude-sonnet-4-20250514" ,
371+ providerID : "anthropic" ,
372+ mode : "" ,
373+ parentID : "msg_0" ,
374+ path : { cwd : "/test" , root : "/test" } ,
375+ cost : 0.001 ,
376+ tokens : { input : 100 , output : 50 , reasoning : 0 , cache : { read : 0 , write : 0 } } ,
377+ time : { created : 1000000000100 , completed : 1000000000600 } ,
378+ } ,
379+ parts : [ { id : "p1" , sessionID : "ses_abc123" , messageID : "msg_1" , type : "text" as const , text : "Response" } ] ,
380+ } ,
381+ ]
382+
383+ const result = formatTranscript ( session , messages , {
384+ thinking : false ,
385+ toolDetails : false ,
386+ assistantMetadata : true ,
387+ } )
388+
389+ expect ( result ) . toContain ( "## Assistant (Build · claude-sonnet-4-20250514 · 0.5s)" )
390+ } )
391+
288392 test ( "formats transcript without assistant metadata" , ( ) => {
289393 const session = {
290394 id : "ses_abc123" ,
0 commit comments