@@ -4,7 +4,7 @@ import type { WorkflowAgentCallRecord } from "./workflow-types.js";
44
55function call (
66 partial : Partial < WorkflowAgentCallRecord > &
7- Pick < WorkflowAgentCallRecord , "callIndex" | "cacheKey" | "responseText" > ,
7+ Pick < WorkflowAgentCallRecord , "callIndex" | "cacheKey" > ,
88) : WorkflowAgentCallRecord {
99 return {
1010 runId : "wfr_prior" ,
@@ -15,6 +15,7 @@ function call(
1515 isolation : "shared" ,
1616 createdAt : "t" ,
1717 updatedAt : "t" ,
18+ returnValueJson : JSON . stringify ( `result-${ partial . callIndex } ` ) ,
1819 ...partial ,
1920 } ;
2021}
@@ -32,50 +33,75 @@ function identity(prompt = "prompt") {
3233
3334{
3435 const replay = createWorkflowReplay ( [
35- call ( { callIndex : 0 , cacheKey : "k0" , responseText : "a" } ) ,
36- call ( { callIndex : 1 , cacheKey : "k1" , responseText : "b" } ) ,
36+ call ( { callIndex : 0 , cacheKey : "k0" , returnValueJson : JSON . stringify ( "a" ) } ) ,
37+ call ( { callIndex : 1 , cacheKey : "k1" , returnValueJson : JSON . stringify ( "b" ) } ) ,
3738 ] ) ;
3839 assert . equal ( replay . decide ( 0 , "k0" , identity ( ) ) . hit ?. value , "a" ) ;
3940 assert . equal ( replay . decide ( 1 , "k1" , identity ( ) ) . hit ?. value , "b" ) ;
40- assert . equal ( replay . decide ( 2 , "k0 " , identity ( ) ) . miss ?. reason , "compatible_result_consumed " ) ;
41+ assert . equal ( replay . decide ( 2 , "k2 " , identity ( ) ) . miss ?. reason , "no_compatible_call " ) ;
4142}
4243
4344{
44- // fan-out reorder: callIndex mismatch, consume-once by key
4545 const replay = createWorkflowReplay ( [
46- call ( { callIndex : 0 , cacheKey : "ka" , responseText : "A" } ) ,
47- call ( { callIndex : 1 , cacheKey : "kb" , responseText : "B" } ) ,
46+ call ( { callIndex : 0 , cacheKey : "ka" , returnValueJson : JSON . stringify ( "A" ) } ) ,
47+ call ( { callIndex : 1 , cacheKey : "kb" , returnValueJson : JSON . stringify ( "B" ) } ) ,
4848 ] ) ;
49- // new run asks index0 for kb first
50- const reorderedB = replay . decide ( 0 , "kb" , identity ( ) ) . hit ;
51- assert . equal ( reorderedB ?. value , "B" ) ;
52- assert . equal ( reorderedB ?. replayMatch , "compatible_key" ) ;
53- assert . equal ( replay . decide ( 1 , "ka" , identity ( ) ) . hit ?. value , "A" ) ;
54- assert . equal (
55- replay . decide ( 2 , "ka" , identity ( ) ) . miss ?. reason ,
56- "compatible_result_consumed" ,
57- ) ;
49+ const changed = replay . decide ( 0 , "kb" , identity ( ) ) . miss ;
50+ assert . equal ( changed ?. reason , "identity_changed" ) ;
51+ assert . equal ( replay . decide ( 1 , "kb" , identity ( ) ) . miss ?. reason , "prefix_diverged" ) ;
5852}
5953
6054{
6155 const replay = createWorkflowReplay ( [
6256 call ( {
6357 callIndex : 0 ,
6458 cacheKey : "ks" ,
65- responseText : '{"ok":true}' ,
59+ responseText : "bounded preview" ,
6660 structuredJson : '{"ok":true}' ,
61+ returnValueJson : '{"ok":true,"text":"exact"}' ,
6762 } ) ,
6863 ] ) ;
69- assert . deepEqual ( replay . decide ( 0 , "ks" , identity ( ) ) . hit ?. value , { ok : true } ) ;
64+ assert . deepEqual ( replay . decide ( 0 , "ks" , identity ( ) ) . hit ?. value , {
65+ ok : true ,
66+ text : "exact" ,
67+ } ) ;
7068}
7169
7270{
7371 const replay = createWorkflowReplay ( [
74- call ( { callIndex : 0 , cacheKey : "old" , prompt : "old prompt" , responseText : "a" } ) ,
72+ call ( { callIndex : 0 , cacheKey : "old" , prompt : "old prompt" } ) ,
73+ call ( { callIndex : 1 , cacheKey : "later" } ) ,
7574 ] ) ;
7675 const miss = replay . decide ( 0 , "new" , identity ( "new prompt" ) ) . miss ;
7776 assert . equal ( miss ?. reason , "identity_changed" ) ;
7877 assert . deepEqual ( miss ?. changedFields , [ "prompt" ] ) ;
78+ assert . equal ( replay . decide ( 1 , "later" , identity ( ) ) . miss ?. reason , "prefix_diverged" ) ;
79+ }
80+
81+ {
82+ const replay = createWorkflowReplay ( [
83+ call ( { callIndex : 0 , cacheKey : "worktree" , isolation : "worktree" } ) ,
84+ call ( { callIndex : 1 , cacheKey : "later" } ) ,
85+ ] ) ;
86+ assert . equal (
87+ replay . decide ( 0 , "worktree" , { ...identity ( ) , isolation : "worktree" } ) . miss ?. reason ,
88+ "worktree_not_restored" ,
89+ ) ;
90+ assert . equal ( replay . decide ( 1 , "later" , identity ( ) ) . miss ?. reason , "prefix_diverged" ) ;
91+ }
92+
93+ {
94+ const replay = createWorkflowReplay ( [
95+ call ( { callIndex : 0 , cacheKey : "legacy" , returnValueJson : undefined } ) ,
96+ ] ) ;
97+ assert . equal ( replay . decide ( 0 , "legacy" , identity ( ) ) . miss ?. reason , "result_not_persisted" ) ;
98+ }
99+
100+ {
101+ const replay = createWorkflowReplay ( [
102+ call ( { callIndex : 0 , cacheKey : "corrupt" , returnValueJson : "{" } ) ,
103+ ] ) ;
104+ assert . equal ( replay . decide ( 0 , "corrupt" , identity ( ) ) . miss ?. reason , "stored_result_invalid" ) ;
79105}
80106
81107console . log ( "workflow-replay.test.ts: ok" ) ;
0 commit comments