Skip to content

Commit 521c30a

Browse files
committed
Fixed invalid state transition bug.
This bug was caused by an incomplete merging of changes to master to allow the config to auto-allow or auto-deny tool calls. There was a state transition from :check-approval to :execution-approved on :auto-approve. However, since :auto-approve can now be either allow or deny, the next-state is not correct. Since the next state depends on a conditional, that has tobe in the code and can only influence the outcome of the state machine via events. So made the code decide to send different events depending on the config values. Updated the tests to accommodate.
1 parent 4ccbbc0 commit 521c30a

File tree

2 files changed

+40
-38
lines changed

2 files changed

+40
-38
lines changed

src/eca/features/chat.clj

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@
8484
Actions:
8585
- send-* notifications
8686
- promise init & delivery
87-
- logging/metrics"
87+
- logging/metrics
88+
89+
Note: all choices (i.e. conditionals) have to be made in code and result
90+
in different events sent to the state machine.
91+
For example, from the :check-approval state you can either get
92+
a :config-ask event, a :config-allow event, or a :config-deny event."
8893
{;; Note: transition-tool-call! treats no existing state as :initial state
8994
[:initial :tool-prepare]
9095
{:status :preparing
@@ -98,13 +103,17 @@
98103
{:status :check-approval
99104
:actions [:init-approval-promise :send-toolCallRun]}
100105

101-
[:check-approval :ask-approve]
106+
[:check-approval :config-ask]
102107
{:status :waiting-approval
103108
:actions [:send-progress]}
104109

105-
[:check-approval :auto-approve]
110+
[:check-approval :config-allow]
106111
{:status :execution-approved
107-
:actions [:deliver-default-approval]}
112+
:actions [:deliver-approval-true]}
113+
114+
[:check-approval :config-deny]
115+
{:status :rejected
116+
:actions [:deliver-approval-false]}
108117

109118
[:waiting-approval :user-approve]
110119
{:status :execution-approved
@@ -438,12 +447,12 @@
438447
:manual-approval ask?
439448
:details details
440449
:summary summary})
441-
(if ask?
442-
(transition-tool-call! db* chat-ctx id :ask-approve
443-
{:state :running
444-
:text "Waiting for tool call approval"})
445-
(transition-tool-call! db* chat-ctx id :auto-approve
446-
{:default-approval (= :allow approval)}))
450+
(case approval
451+
:ask (transition-tool-call! db* chat-ctx id :config-ask
452+
{:state :running
453+
:text "Waiting for tool call approval"})
454+
:allow (transition-tool-call! db* chat-ctx id :config-allow)
455+
:deny (transition-tool-call! db* chat-ctx id :config-deny))
447456
;; Execute each tool call concurrently
448457
(future
449458
(if @approved?* ;TODO: Should there be a timeout here? If so, what would be the state transitions?

test/eca/features/chat_tool_call_state_test.clj

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
"Expected state machine to contain [:preparing :tool-prepare] transition")
2929
(is (contains? state-machine [:preparing :tool-run])
3030
"Expected state machine to contain [:preparing :tool-run] transition")
31-
(is (contains? state-machine [:check-approval :manual-approve])
32-
"Expected state machine to contain [:check-approval :manual-approve] transition")
33-
(is (contains? state-machine [:check-approval :auto-approve])
34-
"Expected state machine to contain [:check-approval :auto-approve] transition")
31+
(is (contains? state-machine [:check-approval :config-ask])
32+
"Expected state machine to contain [:check-approval :config-ask] transition")
33+
(is (contains? state-machine [:check-approval :config-allow])
34+
"Expected state machine to contain [:check-approval :config-allow] transition")
35+
(is (contains? state-machine [:check-approval :config-deny])
36+
"Expected state machine to contain [:check-approval :config-deny] transition")
3537
(is (contains? state-machine [:waiting-approval :user-approve])
3638
"Expected state machine to contain [:waiting-approval :user-approve] transition")
3739
(is (contains? state-machine [:waiting-approval :user-reject])
@@ -286,7 +288,7 @@
286288
"Expected the exact promise passed in to be stored")))
287289

288290
;; Step 3: :check-approval -> :waiting-approval (manual approval needed)
289-
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :manual-approve manual-approve-event-data)]
291+
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-ask manual-approve-event-data)]
290292
(is (match? {:status :waiting-approval
291293
:actions [:send-progress]}
292294
result)
@@ -337,10 +339,9 @@
337339
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run run-event-data)
338340

339341
;; Step 3: :check-approval -> :execution-approved (auto approval)
340-
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
341-
{:default-approval true})]
342+
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)]
342343
(is (match? {:status :execution-approved
343-
:actions [:deliver-default-approval]}
344+
:actions [:deliver-approval-true]}
344345
result)
345346
"Expected transition to :execution-approved with deliver approval true action")
346347

@@ -363,7 +364,7 @@
363364
{:name "test" :origin "test" :arguments-text "{}"})
364365
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run
365366
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval true})
366-
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :manual-approve
367+
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-ask
367368
{:state :running :text "Waiting"})
368369

369370
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :user-reject)]
@@ -398,8 +399,7 @@
398399
{:name "list_files" :origin "filesystem" :arguments-text "{\"path\": \"/tmp\"}"})
399400
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run
400401
{:approved?* approved?* :name "list_files" :origin "filesystem" :arguments {:path "/tmp"} :manual-approval false})
401-
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
402-
{:default-approval true})
402+
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)
403403

404404
(let [tool-state (#'f.chat/get-tool-call-state @db* chat-id tool-call-id)]
405405
(is (= :execution-approved (:status tool-state))
@@ -491,8 +491,7 @@
491491
{:name "test" :origin "test" :arguments-text "{}"})
492492
(#'f.chat/transition-tool-call! db* chat-ctx "tool-completed" :tool-run
493493
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval false})
494-
(#'f.chat/transition-tool-call! db* chat-ctx "tool-completed" :auto-approve
495-
{:default-approval true})
494+
(#'f.chat/transition-tool-call! db* chat-ctx "tool-completed" :config-allow)
496495
(#'f.chat/transition-tool-call! db* chat-ctx "tool-completed" :execution-start
497496
{:name "test" :origin "test" :arguments {}})
498497
(#'f.chat/transition-tool-call! db* chat-ctx "tool-completed" :execution-end
@@ -512,7 +511,7 @@
512511
{:name "test" :origin "test" :arguments-text "{}"})
513512
(#'f.chat/transition-tool-call! db* chat-ctx "tool-rejected" :tool-run
514513
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval true})
515-
(#'f.chat/transition-tool-call! db* chat-ctx "tool-rejected" :manual-approve
514+
(#'f.chat/transition-tool-call! db* chat-ctx "tool-rejected" :config-ask
516515
{:state :running :text "Waiting"})
517516
(#'f.chat/transition-tool-call! db* chat-ctx "tool-rejected" :user-reject)
518517

@@ -548,7 +547,7 @@
548547
{:name "test" :origin "test" :arguments-text "{}"})
549548
(#'f.chat/transition-tool-call! db* chat-ctx "tool-2" :tool-run
550549
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval true})
551-
(#'f.chat/transition-tool-call! db* chat-ctx "tool-2" :manual-approve
550+
(#'f.chat/transition-tool-call! db* chat-ctx "tool-2" :config-ask
552551
{:state :running :text "Waiting"})
553552

554553
(let [result (#'f.chat/transition-tool-call! db* chat-ctx "tool-2" :stop-requested)]
@@ -567,8 +566,7 @@
567566
{:name "test" :origin "test" :arguments-text "{}"})
568567
(#'f.chat/transition-tool-call! db* chat-ctx "tool-3" :tool-run
569568
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval false})
570-
(#'f.chat/transition-tool-call! db* chat-ctx "tool-3" :auto-approve
571-
{:default-approval true})
569+
(#'f.chat/transition-tool-call! db* chat-ctx "tool-3" :config-allow)
572570

573571
(let [result (#'f.chat/transition-tool-call! db* chat-ctx "tool-3" :stop-requested)]
574572
(is (match? {:status :stopped
@@ -731,10 +729,9 @@
731729
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run
732730
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval false})
733731

734-
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
735-
{:default-approval true})]
732+
(let [result (#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)]
736733
(is (match? {:status :execution-approved
737-
:actions [:deliver-default-approval]}
734+
:actions [:deliver-approval-true]}
738735
result)
739736
"Expected transition to :execution-approved with deliver approval true action")
740737

@@ -758,8 +755,7 @@
758755
{:name "test" :origin "test" :arguments-text "{}"})
759756
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run
760757
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval false})
761-
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
762-
{:default-approval true})
758+
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)
763759
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :execution-start
764760
{:name "test" :origin "test" :arguments {}})
765761

@@ -806,8 +802,7 @@
806802
{:name "test" :origin "test" :arguments-text "{}"})
807803
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :tool-run
808804
{:approved?* approved?* :name "test" :origin "test" :arguments {} :manual-approval false})
809-
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
810-
{:default-approval true})
805+
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)
811806
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :execution-start
812807
{:name "test" :origin "test" :arguments {}})
813808

@@ -862,8 +857,7 @@
862857
(is (identical? approved?* (:approved?* state-after-run))
863858
"Expected same promise to be stored in state"))
864859

865-
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :auto-approve
866-
{:default-approval true})
860+
(#'f.chat/transition-tool-call! db* chat-ctx tool-call-id :config-allow)
867861

868862
(let [state-after-approve (#'f.chat/get-tool-call-state @db* chat-id tool-call-id)]
869863
(is (= :execution-approved (:status state-after-approve))
@@ -889,8 +883,7 @@
889883
{:name "test1" :origin "test" :arguments-text "{}"})
890884
(#'f.chat/transition-tool-call! db* chat-ctx-1 tool-call-id :tool-run
891885
{:approved?* approved-1* :name "test1" :origin "test" :arguments {} :manual-approval false})
892-
(#'f.chat/transition-tool-call! db* chat-ctx-1 tool-call-id :auto-approve
893-
{:default-approval true})
886+
(#'f.chat/transition-tool-call! db* chat-ctx-1 tool-call-id :config-allow)
894887

895888
;; Tool 2
896889
(#'f.chat/transition-tool-call! db* chat-ctx-2 tool-call-id :tool-prepare

0 commit comments

Comments
 (0)