Skip to content

Commit 5158fc3

Browse files
Compose a tool command with the agent
1 parent d88bcb6 commit 5158fc3

File tree

9 files changed

+101
-39
lines changed

9 files changed

+101
-39
lines changed

prompts/examples/generate-dockerfile.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ tools:
44
- image: vonwig/function_write_files:latest
55
- image: vonwig/docker_scout_tag_recommendation:latest
66
- image: vonwig/docker-rag:latest
7+
host-dir: /Users/slim/vonwig/altaservice
78
---
89

910
# prompt system

prompts/sql/Chinook.db

-904 KB
Binary file not shown.

prompts/sql/prompt.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
11
---
2-
agent: sql
2+
tools:
3+
- name: curl
4+
- name: sql-agent
5+
description: Execute a SQL query against a sqlite database
6+
parameters:
7+
type: object
8+
properties:
9+
database:
10+
type: string
11+
description: the sqlite database file
12+
prompt:
13+
type: string
14+
description: a human description of the query we need to run
15+
type: "prompt"
16+
prompt: sql-agent.md
317
host-dir: /Users/slim/docker/labs-ai-tools-for-devs/prompts/sql # override host-dir while testing
418
---
519

620
# prompt user
721

8-
find all artists in the database ./Chinook.db
22+
1. use curl to download 'https://storage.googleapis.com/benchmarks-artifacts/chinook/Chinook.db' and write to ./Chinook.db
23+
2. use the sql-agent tool to run the following prompt.
924

25+
> find all artists
26+
27+
Do not try to generate sql. Pass this prompt directly to the agent.

prompts/sql/sql-agent.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
agent: sql
3+
---
4+
5+
# prompt user
6+
7+
{{prompt}} in the database {{database}}

src/docker/main.clj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
git
1111
[git.registry :as registry]
1212
graph
13-
graphs.sql
1413
jsonrpc
1514
[logging :refer [warn]]
1615
prompts
@@ -182,8 +181,8 @@
182181
(-> (with-options opts (rest args))
183182
(assoc :thread-id thread-id))))]
184183
(graph/stream
185-
(if (= (-> m :metadata :agent) "sql")
186-
(graphs.sql/graph state)
184+
(if (-> m :metadata :agent)
185+
((graph/require-graph (-> m :metadata :agent)) state)
187186
(graph/chat-with-tools state))
188187
m))))
189188
user-loop/state-reducer

src/graph.clj

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@
8484
(async/<!
8585
(->> (tools/make-tool-calls
8686
(or (-> state :opts :level) 0)
87-
(partial
88-
tools/function-handler
87+
(partial
88+
tools/function-handler
8989
;; defaults for tool handling are opts, current state functions, and a host-dir override
90-
(merge
91-
(:opts state)
92-
(select-keys state [:functions])
90+
(merge
91+
(:opts state)
92+
(select-keys state [:functions])
9393
;; note that host-dir, if it exists, is an override here
94-
(select-keys (:metadata state) [:host-dir :timeout])))
94+
(select-keys (:metadata state) [:host-dir :timeout])))
9595
calls)
9696
(async/reduce conj []))))})))
9797

@@ -104,6 +104,11 @@
104104
[_]
105105
(async/go {}))
106106

107+
(defn require-graph [s]
108+
(let [graphs-ns-symbol (symbol (format "graphs.%s" s))]
109+
(require graphs-ns-symbol)
110+
(ns-resolve graphs-ns-symbol 'graph)))
111+
107112
(declare stream chat-with-tools)
108113

109114
(defn apply-functions [coll]
@@ -117,22 +122,33 @@
117122
[{:keys [init-state construct-graph next-state]}]
118123
(fn [state]
119124
(async/go
120-
(let [sub-graph-state
121-
(async/<!
122-
(stream
123-
((or construct-graph chat-with-tools) state)
125+
(try
126+
(let [new-conversation-state
124127
(->
125-
((or
126-
;; the sub-graph might have a function or a vector of state overlays to apply
127-
(and
128-
init-state
129-
(if (coll? init-state)
130-
(apply-functions init-state)
131-
init-state))
132-
;; default is to assume there's a tool call with a function that contains a prompt
133-
(comp state/construct-initial-state-from-prompts state/add-prompt-ref)) state)
134-
(update-in [:opts :level] (fnil inc 0)))))]
135-
((or next-state state/add-last-message-as-tool-call) state sub-graph-state)))))
128+
((or
129+
;; the sub-graph might have a function or a vector of state overlays to apply
130+
(and
131+
init-state
132+
(if (coll? init-state)
133+
(apply-functions init-state)
134+
init-state))
135+
;; default is to assume there's a tool call with a function that contains a prompt
136+
(comp state/construct-initial-state-from-prompts state/add-prompt-ref)) state)
137+
(update-in [:opts :level] (fnil inc 0)))
138+
139+
sub-graph-state
140+
(async/<!
141+
(stream
142+
((or construct-graph
143+
(if-let [agent (-> new-conversation-state :metadata :agent)]
144+
(require-graph agent)
145+
chat-with-tools)) state)
146+
(-> new-conversation-state
147+
(update-in [:metadata] dissoc :agent))))]
148+
((or next-state state/add-last-message-as-tool-call) state sub-graph-state))
149+
(catch Throwable t
150+
(jsonrpc/notify :error {:content (str t)})
151+
{:error (format "unable to enter sub-graph: %s" t)})))))
136152

137153
; =====================================================
138154
; edge functions takes state and returns next node
@@ -163,6 +179,9 @@
163179
(defn state-reducer
164180
"reduce the state with the change from running a node"
165181
[state change]
182+
(jsonrpc/notify :message {:debug (format "---\n%s\n---\n%s\n---\n"
183+
(with-out-str (pprint/pprint (state/summarize state)))
184+
(with-out-str (pprint/pprint change)))})
166185
(-> state
167186
(merge (dissoc change :messages :tools))
168187
(update :messages concat (:messages change))
@@ -176,7 +195,6 @@
176195
[state m
177196
node "start"]
178197
(jsonrpc/notify :message {:debug (format "\n-> entering %s\n\n" node)})
179-
#_(jsonrpc/notify :message {:debug (with-out-str (pprint/pprint (state/summarize (dissoc state :opts))))})
180198
;; TODO handling bad graphs with missing nodes
181199
(let [enter-node (get-in graph [:nodes node])
182200
new-state (state-reducer state (async/<! (enter-node state)))]
@@ -224,13 +242,12 @@
224242
(defn chat-with-tools [_]
225243
(construct-graph
226244
[[["start" start]
227-
["tools-query" tools-query]
228245
["completion" completion]
229246
[:edge tool-or-end]]
230247
[["sub-graph" (sub-graph-node {})]
231-
["tools-query"]]
248+
["completion"]]
232249
[["tool" (tool-node {})]
233-
["tools-query"]]
250+
["completion"]]
234251
[["end" end]]]))
235252

236253
(defn generate-one-tool-call [_]

src/graphs/sql.clj

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(ns graphs.sql
22
(:require
3+
[cheshire.core :as json]
34
[clojure.core.async :as async]
45
[clojure.string :as string]
56
[graph]
@@ -64,12 +65,22 @@
6465
:content (failed-tool-call-message (-> tc :function :name))
6566
:tool_call_id id}))))})))
6667

68+
(defn summary [{:keys [messages]}]
69+
(async/go
70+
(let [[{:keys [id] :as tc}] (:tool_calls (last messages))
71+
content (-> tc :function :arguments (json/parse-string) (get "final_answer"))]
72+
{:messages [{:role "tool"
73+
:content (or content (str tc))
74+
:tool_call_id id}
75+
{:role "assistant"
76+
:content (or content (str tc))}]})))
77+
6778
(defn should-continue
6879
"end, correct-query, or query-gen"
6980
[{:keys [messages]}]
7081
(let [last-message (last messages)]
7182
(cond
72-
(contains? last-message :tool_calls) "end"
83+
(contains? last-message :tool_calls) "summary"
7384
;; prevent inifinite loops of errors
7485
(string/starts-with? (:content last-message) "Error:") "query-gen"
7586
;; how many times should we try to correct because correct-query will always end up back here
@@ -100,5 +111,6 @@
100111
:construct-graph graph/generate-one-tool-call
101112
:next-state state/append-new-messages})]
102113
["query-gen"]]
103-
[["end" graph/end]]]))
114+
[["summary" summary]
115+
["end" graph/end]]]))
104116

src/prompts.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,6 @@
172172
#'jsonrpc/notify
173173
(fn [_] (partial (if (:jsonrpc {}) jsonrpc/-notify jsonrpc/-println) {})))
174174
(get-prompts {:prompts (fs/file "./prompts/examples/curl.md")})
175-
(get-prompts {:prompts (fs/file "./prompts/examples/generate-dockerfile.md")}))
175+
(get-prompts {:prompts (fs/file "./prompts/examples/generate-dockerfile.md")})
176+
(get-prompts {:prompts (fs/file "./README.md")}))
176177

src/state.clj

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
(-> m :function :name))
2626

2727
(defn summarize [state]
28-
(-> (select-keys state [:messages :metadata])
28+
(-> (select-keys state [:messages :metadata :opts])
29+
(update :opts #(select-keys % [:level :prompts :parameters]))
2930
(update :messages (each
3031
;summarize-content
3132
;summarize-tool-calls
@@ -48,6 +49,11 @@
4849
(-> % :name))))
4950
first)))
5051

52+
(defn prompt-file [state s]
53+
(if (string/starts-with? s "github:")
54+
(git/prompt-file s)
55+
(fs/file (-> state :opts :prompts fs/parent) s)))
56+
5157
(def prompt-tool? (comp prompt? get-function-definition))
5258

5359
(defn add-tool-call-id [m id] (assoc m :role "tool" :tool_call_id id))
@@ -76,10 +82,13 @@
7682
(let [definition (state/get-function-definition state)
7783
arg-context (let [raw-args (-> state :messages last :tool_calls first :function :arguments)]
7884
(tools/arg-context raw-args))]
79-
; this is the only place where parameters can be passed into the next prompts (extractors only)
85+
; this is the only place where parameters can be passed into the next prompts (extractors only)
8086
(-> state
8187
(dissoc :messages)
82-
(update-in [:opts :prompts] (constantly (git/prompt-file (-> definition :function :ref))))
88+
(update-in [:opts :prompts] (constantly (when-let [s (or
89+
(-> definition :function :prompt)
90+
(-> definition :function :ref))]
91+
(prompt-file state s))))
8392
(update-in [:opts :parameters] (constantly arg-context)))))
8493

8594
; ========================================
@@ -127,9 +136,7 @@
127136
(defn messages-from-prompt [s]
128137
(fn [_ state]
129138
(-> state
130-
(update-in [:opts :prompts] (constantly (if (string/starts-with? s "github:")
131-
(git/prompt-file s)
132-
(fs/file (-> state :opts :prompts fs/parent) s))))
139+
(update-in [:opts :prompts] (constantly (prompt-file state s)))
133140
(construct-initial-state-from-prompts))))
134141

135142
(defn metadata-merge [k]

0 commit comments

Comments
 (0)