@@ -17,6 +17,7 @@ import {
1717} from "../schema"
1818import { JsonObject , optionalArray , optionalNull , ProviderShared } from "./shared"
1919import * as Cache from "./utils/cache"
20+ import { Lifecycle } from "./utils/lifecycle"
2021import { ToolStream } from "./utils/tool-stream"
2122
2223const ADAPTER = "anthropic-messages"
@@ -190,6 +191,7 @@ type AnthropicEvent = Schema.Schema.Type<typeof AnthropicEvent>
190191interface ParserState {
191192 readonly tools : ToolStream . State < number >
192193 readonly usage ?: Usage
194+ readonly lifecycle : Lifecycle . State
193195}
194196
195197const invalid = ProviderShared . invalidRequest
@@ -500,37 +502,45 @@ const onContentBlockStart = (state: ParserState, event: AnthropicEvent): StepRes
500502 if ( ! block ) return [ state , NO_EVENTS ]
501503
502504 if ( ( block . type === "tool_use" || block . type === "server_tool_use" ) && event . index !== undefined ) {
505+ const events : LLMEvent [ ] = [ ]
506+ const lifecycle = Lifecycle . stepStart ( state . lifecycle , events )
503507 return [
504508 {
505509 ...state ,
510+ lifecycle,
506511 tools : ToolStream . start ( state . tools , event . index , {
507512 id : block . id ?? String ( event . index ) ,
508513 name : block . name ?? "" ,
509514 providerExecuted : block . type === "server_tool_use" ,
510515 } ) ,
511516 } ,
512- NO_EVENTS ,
517+ [ ... events , LLMEvent . toolInputStart ( { id : block . id ?? String ( event . index ) , name : block . name ?? "" } ) ] ,
513518 ]
514519 }
515520
516521 if ( block . type === "text" && block . text ) {
517- return [ state , [ LLMEvent . textDelta ( { id : `text-${ event . index ?? 0 } ` , text : block . text } ) ] ]
522+ const events : LLMEvent [ ] = [ ]
523+ return [
524+ { ...state , lifecycle : Lifecycle . textDelta ( state . lifecycle , events , `text-${ event . index ?? 0 } ` , block . text ) } ,
525+ events ,
526+ ]
518527 }
519528
520529 if ( block . type === "thinking" && block . thinking ) {
530+ const events : LLMEvent [ ] = [ ]
521531 return [
522- state ,
523- [
524- LLMEvent . reasoningDelta ( {
525- id : `reasoning-${ event . index ?? 0 } ` ,
526- text : block . thinking ,
527- } ) ,
528- ] ,
532+ {
533+ ...state ,
534+ lifecycle : Lifecycle . reasoningDelta ( state . lifecycle , events , `reasoning-${ event . index ?? 0 } ` , block . thinking ) ,
535+ } ,
536+ events ,
529537 ]
530538 }
531539
532540 const result = serverToolResultEvent ( block )
533- return [ state , result ? [ result ] : NO_EVENTS ]
541+ if ( ! result ) return [ state , NO_EVENTS ]
542+ const events : LLMEvent [ ] = [ ]
543+ return [ { ...state , lifecycle : Lifecycle . stepStart ( state . lifecycle , events ) } , [ ...events , result ] ]
534544}
535545
536546const onContentBlockDelta = Effect . fn ( "AnthropicMessages.onContentBlockDelta" ) ( function * (
@@ -540,25 +550,37 @@ const onContentBlockDelta = Effect.fn("AnthropicMessages.onContentBlockDelta")(f
540550 const delta = event . delta
541551
542552 if ( delta ?. type === "text_delta" && delta . text ) {
543- return [ state , [ LLMEvent . textDelta ( { id : `text-${ event . index ?? 0 } ` , text : delta . text } ) ] ] satisfies StepResult
553+ const events : LLMEvent [ ] = [ ]
554+ return [
555+ { ...state , lifecycle : Lifecycle . textDelta ( state . lifecycle , events , `text-${ event . index ?? 0 } ` , delta . text ) } ,
556+ events ,
557+ ] satisfies StepResult
544558 }
545559
546560 if ( delta ?. type === "thinking_delta" && delta . thinking ) {
561+ const events : LLMEvent [ ] = [ ]
547562 return [
548- state ,
549- [ LLMEvent . reasoningDelta ( { id : `reasoning-${ event . index ?? 0 } ` , text : delta . thinking } ) ] ,
563+ {
564+ ...state ,
565+ lifecycle : Lifecycle . reasoningDelta ( state . lifecycle , events , `reasoning-${ event . index ?? 0 } ` , delta . thinking ) ,
566+ } ,
567+ events ,
550568 ] satisfies StepResult
551569 }
552570
553571 if ( delta ?. type === "signature_delta" && delta . signature ) {
572+ const events : LLMEvent [ ] = [ ]
554573 return [
555- state ,
556- [
557- LLMEvent . reasoningEnd ( {
558- id : `reasoning-${ event . index ?? 0 } ` ,
559- providerMetadata : anthropicMetadata ( { signature : delta . signature } ) ,
560- } ) ,
561- ] ,
574+ {
575+ ...state ,
576+ lifecycle : Lifecycle . reasoningEnd (
577+ state . lifecycle ,
578+ events ,
579+ `reasoning-${ event . index ?? 0 } ` ,
580+ anthropicMetadata ( { signature : delta . signature } ) ,
581+ ) ,
582+ } ,
583+ events ,
562584 ] satisfies StepResult
563585 }
564586
@@ -572,7 +594,10 @@ const onContentBlockDelta = Effect.fn("AnthropicMessages.onContentBlockDelta")(f
572594 "Anthropic Messages tool argument delta is missing its tool call" ,
573595 )
574596 if ( ToolStream . isError ( result ) ) return yield * result
575- return [ { ...state , tools : result . tools } , result . event ? [ result . event ] : NO_EVENTS ] satisfies StepResult
597+ const events : LLMEvent [ ] = [ ]
598+ const lifecycle = result . events . length ? Lifecycle . stepStart ( state . lifecycle , events ) : state . lifecycle
599+ events . push ( ...result . events )
600+ return [ { ...state , lifecycle, tools : result . tools } , events ] satisfies StepResult
576601 }
577602
578603 return [ state , NO_EVENTS ] satisfies StepResult
@@ -584,23 +609,30 @@ const onContentBlockStop = Effect.fn("AnthropicMessages.onContentBlockStop")(fun
584609) {
585610 if ( event . index === undefined ) return [ state , NO_EVENTS ] satisfies StepResult
586611 const result = yield * ToolStream . finish ( ADAPTER , state . tools , event . index )
587- return [ { ...state , tools : result . tools } , result . event ? [ result . event ] : NO_EVENTS ] satisfies StepResult
612+ const events : LLMEvent [ ] = [ ]
613+ const resultEvents = result . events ?? [ ]
614+ const lifecycle = resultEvents . length
615+ ? Lifecycle . stepStart ( state . lifecycle , events )
616+ : Lifecycle . reasoningEnd (
617+ Lifecycle . textEnd ( state . lifecycle , events , `text-${ event . index } ` ) ,
618+ events ,
619+ `reasoning-${ event . index } ` ,
620+ )
621+ events . push ( ...resultEvents )
622+ return [ { ...state , lifecycle, tools : result . tools } , events ] satisfies StepResult
588623} )
589624
590625const onMessageDelta = ( state : ParserState , event : AnthropicEvent ) : StepResult => {
591626 const usage = mergeUsage ( state . usage , mapUsage ( event . usage ) )
592- return [
593- { ...state , usage } ,
594- [
595- LLMEvent . requestFinish ( {
596- reason : mapFinishReason ( event . delta ?. stop_reason ) ,
597- usage,
598- providerMetadata : event . delta ?. stop_sequence
599- ? anthropicMetadata ( { stopSequence : event . delta . stop_sequence } )
600- : undefined ,
601- } ) ,
602- ] ,
603- ]
627+ const events : LLMEvent [ ] = [ ]
628+ const lifecycle = Lifecycle . finish ( state . lifecycle , events , {
629+ reason : mapFinishReason ( event . delta ?. stop_reason ) ,
630+ usage,
631+ providerMetadata : event . delta ?. stop_sequence
632+ ? anthropicMetadata ( { stopSequence : event . delta . stop_sequence } )
633+ : undefined ,
634+ } )
635+ return [ { ...state , lifecycle, usage } , events ]
604636}
605637
606638const onError = ( state : ParserState , event : AnthropicEvent ) : StepResult => [
@@ -634,7 +666,7 @@ export const protocol = Protocol.make({
634666 } ,
635667 stream : {
636668 event : Protocol . jsonEvent ( AnthropicEvent ) ,
637- initial : ( ) => ( { tools : ToolStream . empty < number > ( ) } ) ,
669+ initial : ( ) => ( { tools : ToolStream . empty < number > ( ) , lifecycle : Lifecycle . initial ( ) } ) ,
638670 step,
639671 } ,
640672} )
0 commit comments