@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
55import { clearLargeValueCacheForTests } from '@/lib/execution/payloads/cache'
66import { isLargeArrayManifest } from '@/lib/execution/payloads/large-array-manifest-metadata'
77import { buildTraceSpans } from '@/lib/logs/execution/trace-spans/trace-spans'
8+ import { calculateStreamingCost } from '@/lib/tokenization'
89import { BlockType } from '@/executor/constants'
910import type { DAGNode } from '@/executor/dag/builder'
1011import { BlockExecutor } from '@/executor/execution/block-executor'
@@ -954,6 +955,51 @@ describe('BlockExecutor streaming pump', () => {
954955 expect ( state . getBlockOutput ( block . id ) ?. content ) . toBe ( 'offline answer' )
955956 } )
956957
958+ it ( 'estimates missing streaming usage from resolved input before sanitizing logs' , async ( ) => {
959+ const secret = `sk-${ 'resolved-secret-' . repeat ( 20 ) } `
960+ const params = { prompt : '{{OPENAI_API_KEY}}' , model : 'gpt-4o' }
961+ const handler : BlockHandler = {
962+ canHandle : ( ) => true ,
963+ execute : async ( _ctx , _block , resolvedInputs ) => ( {
964+ stream : new ReadableStream ( {
965+ start ( controller ) {
966+ controller . enqueue ( new TextEncoder ( ) . encode ( 'streamed answer' ) )
967+ controller . close ( )
968+ } ,
969+ } ) ,
970+ execution : {
971+ success : true ,
972+ output : { content : '' , model : 'gpt-4o' } ,
973+ logs : [ ] ,
974+ metadata : {
975+ startTime : new Date ( ) . toISOString ( ) ,
976+ endTime : new Date ( ) . toISOString ( ) ,
977+ duration : 1 ,
978+ } ,
979+ } ,
980+ } ) ,
981+ }
982+ const { executor, block, state } = createExecutor ( handler , params )
983+ const ctx = createContext ( state )
984+ ctx . environmentVariables = { OPENAI_API_KEY : secret }
985+
986+ await executor . execute ( ctx , createNode ( block ) , block )
987+
988+ const expected = calculateStreamingCost (
989+ 'gpt-4o' ,
990+ JSON . stringify ( { prompt : secret , model : 'gpt-4o' } ) ,
991+ 'streamed answer'
992+ )
993+ expect ( state . getBlockOutput ( block . id ) ?. tokens ) . toEqual ( expected . tokens )
994+ expect ( state . getBlockOutput ( block . id ) ?. cost ) . toEqual ( expected . cost )
995+ expect ( ctx . blockLogs [ 0 ] . input ) . toEqual ( {
996+ prompt : '{{OPENAI_API_KEY}}' ,
997+ model : 'gpt-4o' ,
998+ } )
999+ expect ( ctx . blockLogs [ 0 ] . output ?. tokens ) . toEqual ( expected . tokens )
1000+ expect ( JSON . stringify ( ctx . blockLogs [ 0 ] ) ) . not . toContain ( secret )
1001+ } )
1002+
9571003 it ( 'throws on mid-stream provider error (no truncated success)' , async ( ) => {
9581004 const handler = createAgentEventsStreamingHandler ( {
9591005 failAfterText : 'partial' ,
0 commit comments