Skip to content

Commit 12ab426

Browse files
Add stdin content
1 parent 92a0c99 commit 12ab426

File tree

12 files changed

+156
-78
lines changed

12 files changed

+156
-78
lines changed

docs/content/tools/docs/gordon.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ volumes:
2323
external: false
2424
```
2525
26+
{{< callout type="info" >}}
27+
28+
`mcp/docker` uses the local docker engine to run containers.
29+
30+
{{< /callout >}}
31+
2632
## debugging
2733

2834
We suggest using `docker ai --debug` if you are trying to debug some of your tools while using the `docker ai` cli.

prompts/lorax/speculative.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,6 @@ tools:
149149

150150
Make a cloned repo available to the sandbox. The host repo is '/Users/slim/vonwig/altaservice' and it should be named atlas
151151

152-
# prompt
152+
# prompt test lorax
153153

154154
Clone the sandbox named atlas. We will get back the id of the new sandbox and we should remember that.

src/docker.clj

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@
88
[clojure.string :as string]
99
[creds]
1010
jsonrpc
11-
[jsonrpc.logger :as logger]
1211
logging
1312
schema)
1413
(:import
15-
[java.net URLEncoder UnixDomainSocketAddress]
14+
[java.net UnixDomainSocketAddress]
1615
[java.nio ByteBuffer]
1716
[java.nio.channels SocketChannel]
1817
[java.util Arrays Base64]))
@@ -36,7 +35,10 @@
3635
(curl/post
3736
(format "http://localhost/images/create?fromImage=%s" image)
3837
(merge
39-
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
38+
{:raw-args ["--unix-socket" (let [f (fs/file "/var/run/docker.raw.sock")]
39+
(if (.exists f)
40+
"/var/run/docker.raw.sock"
41+
"/var/run/docker.sock"))]
4042
:throw false}
4143
(when (or creds identity-token)
4244
{:headers {"X-Registry-Auth"
@@ -440,7 +442,7 @@
440442
"run container with stdin read from a file"
441443
[m]
442444
(let [x (docker/function-call-with-stdin
443-
(assoc m :content (slurp (-> m :stdin :file))))]
445+
(assoc m :content (or (-> m :stdin :content) (slurp (-> m :stdin :file)))))]
444446
(async/<!! (async/thread
445447
(Thread/sleep 10)
446448
(docker/finish-call x)))))
@@ -451,7 +453,7 @@
451453
[m]
452454
;; (schema/validate :schema/container-definition)
453455
(cond
454-
(-> m :stdin :file)
456+
(-> m :stdin)
455457
(run-with-stdin-content m)
456458
(true? (:background m))
457459
(run-background-function m)

src/git.clj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@
101101
(partition-by (comp :ref-hash :ref))
102102
(map first)))
103103

104-
(defn refresh-cache
104+
(defn refresh-cache
105105
" pure side-effect - clone or pull the cache"
106106
[coll]
107107
(doseq [m coll]
108-
(if (fs/exists? (-> m :ref :dir))
109-
(pull (:ref m))
110-
(clone (:ref m)))
111-
(when (not (= 0 (:exit-code m)))
112-
(jsonrpc/notify :error {:content (str m)}))))
108+
(let [c (if (fs/exists? (-> m :ref :dir))
109+
(pull (:ref m))
110+
(clone (:ref m)))]
111+
(when (not (= 0 (:exit-code c)))
112+
(jsonrpc/notify :error {:content (str c)})))))
113113

114114
(defn cached-prompt-file [{{:keys [dir path]} :ref :as m}]
115115
(if path

src/jsonrpc/db.clj

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99

1010
(def db* (atom {}))
1111

12-
(defn get-prompt-data [{:keys [register] :as opts}]
12+
(defn get-prompt-data
13+
"register is a coll of prompt file ref maps"
14+
[{:keys [register] :as opts}]
1315
(->> register
14-
(map (fn [{:keys [cached-path]}]
16+
(map (fn [{:keys [cached-path ref-string]}]
1517
(let [m (prompts/get-prompts (assoc opts :prompts cached-path))]
16-
[(or (-> m :metadata :name) ref) m])))
18+
[(or (-> m :metadata :name) ref-string) m])))
1719
(into {})))
1820

1921
(defn extract-resources [m]
@@ -56,13 +58,16 @@
5658
refs - coll of [type ref] type is static or dynamic"
5759
[refs]
5860
(if (seq refs)
61+
;; turn static/dynamic refs into maps of type, ref-string, and parsed ref with cache dir
5962
(let [git-map-coll (->> refs
6063
(map (fn [[t ref]] {:type t :ref-string ref :ref (git/parse-github-ref ref)}))
6164
(map (fn [m] (assoc-in m [:ref :ref-hash] (git/hashch (:ref m)))))
6265
(map (fn [m] (assoc-in m [:ref :dir] (git/cache-dir (:ref m))))))]
66+
;; refresh cache (side effect)
6367
(-> git-map-coll
6468
git/collect-unique-cache-dirs
6569
git/refresh-cache)
70+
;; updated git map with cached-path
6671
(let [typed-colls
6772
(->> git-map-coll
6873
(map git/cached-prompt-file)

src/jsonrpc/server.clj

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,10 @@
9696
:total 0
9797
:hasMore false}})
9898

99-
(defn entry->prompt-listing [k v message]
100-
(let [{:keys [description arguments]} (:metadata v)]
99+
(defn entry->prompt-listing [_ v message]
100+
(let [{:keys [arguments]} (:metadata v)]
101101
(merge
102-
{:name (if (:title message)
103-
(str k ":" (:title message))
104-
k)
105-
:description (or (:description message) description "missing description")}
102+
(select-keys message [:name :description])
106103
(when arguments
107104
{:arguments arguments}))))
108105

@@ -118,8 +115,15 @@
118115

119116
(defmethod lsp.server/receive-request "prompts/get" [_ {:keys [db*]} {:keys [name arguments]}]
120117
(logger/info "prompts/get " name)
121-
(let [{:keys [prompt-function metadata]} (-> @db* :mcp.prompts/registry (get name))]
122-
{:description (or (:description metadata) name)
118+
(let [{:keys [prompt-function description] :as m}
119+
(get
120+
(->> @db*
121+
:mcp.prompts/registry
122+
vals
123+
(mapcat :mcp/prompt-registry)
124+
(into {}))
125+
name)]
126+
{:description description
123127
:messages (prompt-function (or arguments {}))}))
124128

125129
(defmethod lsp.server/receive-request "resources/list" [_ {:keys [db*]} _]

src/markdown.clj

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
(defn section? [node]
7676
(and (list? node) (= "section" (first node))))
7777

78+
(defn fenced-code-block? [node]
79+
(and (list? node) (= "fenced_code_block" (first node))))
80+
7881
(defn description-section? [content node]
7982
(when-let [atx-header-node (first (filter #(= "atx_heading" (first %)) node))]
8083
(= "description" (string/trim (from-range (-> atx-header-node (nth 3) (nth 1)) content)))))
@@ -117,14 +120,25 @@
117120

118121
(def heading-1-loc->top-level-section-node (comp zip/node zip/up zip/up))
119122

120-
(defn extract-prompts-with-descriptions [content ast]
123+
(defn extract-prompts-with-descriptions [content metadata ast]
121124
(->>
122125
(iterate zip/next (zip/seq-zip ast))
123126
(take-while (complement zip/end?))
124127
(filter heading-1-section?)
125128
(map heading-1-loc->top-level-section-node)
126129
(filter (partial prompt-section? content))
127-
(map (partial h1-prompt-content content))))
130+
(map (partial h1-prompt-content content))
131+
(map (fn [m] (-> m
132+
(assoc :name (cond
133+
(and (:title m) (:name metadata)) (str (:name metadata) ":" (:title m))
134+
(:title m) (:title m)
135+
(:name metadata) (:name metadata)
136+
;; TODO fix this
137+
:else "missing name")
138+
:description (or
139+
(:description m)
140+
(:description metadata)
141+
"missing description")))))))
128142

129143
(defn extract-prompts [content ast]
130144
(->>
@@ -174,6 +188,28 @@
174188
(println ex)
175189
nil)))
176190

191+
(defn extract-first-yaml-code-block [content ast]
192+
(try
193+
(when-let [loc (when-let [first-section
194+
(->>
195+
(iterate zip/right (zip/down (zip/seq-zip ast)))
196+
(some (fn [loc] (when (section? (zip/node loc)) loc))))]
197+
(when-let [first-code-block
198+
(->>
199+
(iterate zip/right (zip/down first-section))
200+
(some (fn [loc] (when (fenced-code-block? (zip/node loc)) loc))))]
201+
first-code-block))]
202+
(->
203+
(from-range (-> loc zip/node (nth 5) (nth 1)) content)
204+
(clj-yaml/parse-string)))
205+
(catch Throwable ex
206+
(println ex)
207+
nil)))
208+
209+
(comment
210+
(let [content (slurp "prompts/examples/github_issues.md")]
211+
(extract-first-yaml-code-block content (parse-markdown content))))
212+
177213
(defn parse-markdown
178214
"use the custom sexp representation"
179215
[content]
@@ -189,15 +225,17 @@
189225
"parse out the h1 prompt sections and the metadata"
190226
[content]
191227
(let [content (str content "\n# END\n\n")
192-
ast (parse-markdown content)]
228+
ast (parse-markdown content)
229+
metadata (or
230+
(extract-metadata content ast)
231+
(extract-first-comment content ast)
232+
(extract-first-yaml-code-block content ast)
233+
{})]
193234
{:messages
194235
(->> ast
195-
(extract-prompts-with-descriptions content)
236+
(extract-prompts-with-descriptions content metadata)
196237
(into []))
197-
:metadata (or
198-
(extract-metadata content ast)
199-
(extract-first-comment content ast)
200-
{})}))
238+
:metadata metadata}))
201239

202240
;; ---------- future ---------
203241

src/prompts.clj

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,6 @@
175175
prompt-content
176176
(markdown-parser/parse-prompts prompt-content)
177177

178-
;; directory based prompts
179-
(fs/directory? prompts)
180-
{:messages
181-
(->> (fs/list-dir prompts)
182-
(filter (name-matches prompt-file-pattern))
183-
(sort-by fs/file-name)
184-
(map (fn [f] {:role (let [[_ role] (re-find prompt-file-pattern (fs/file-name f))] role)
185-
:content (slurp (fs/file f))}))
186-
(into []))
187-
:metadata (:metadata (markdown-parser/parse-prompts (slurp (metadata-file prompts))))}
188-
189178
;; file based prompts
190179
:else
191180
(markdown-parser/parse-prompts (slurp prompts)))
@@ -201,11 +190,20 @@
201190
(moustache-render prompts (merge (facts m user platform host-dir) arguments) message)))]
202191
((schema/validate :schema/prompts-file)
203192
(-> prompt-data
204-
((fn [m] (assoc m :prompt-function (fn [arguments]
205-
(->> (:messages m)
206-
(map (comp ->message (partial renderer arguments)))
207-
(into []))))))
208-
(update :messages #(map (partial renderer {}) %))
193+
(assoc :mcp/prompt-registry
194+
(->> (:messages prompt-data)
195+
(map (fn [{:keys [name] :as v}]
196+
[name (assoc
197+
(select-keys v [:description])
198+
:prompt-function
199+
(fn [arguments]
200+
[((comp ->message (partial renderer arguments))
201+
(select-keys v [:role :content]))]))]))
202+
(into {})))
203+
(update :messages (fn [messages]
204+
(->> messages
205+
(map (partial renderer {}))
206+
(map #(dissoc % :name :description :title)))))
209207
(update :metadata dissoc :functions :tools :extractors)
210208
(assoc :functions (->> (or (:tools metadata) (:functions metadata)) (mapcat function-definition)))))))
211209

src/tools.clj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@
8181
(-> definition :container :workdir)
8282
(:workdir defaults))]
8383
{:workdir (first (interpolate arg-context wd))}))
84-
(-> definition :stdin :file) (update-in [:stdin :file] (fn [s] (first (interpolate arg-context s)))))]
84+
85+
(-> definition :stdin :file) (update-in [:stdin :file] (fn [s] (first (interpolate arg-context s))))
86+
87+
(-> definition :stdin :content) (update-in [:stdin :content] (fn [s] (first (interpolate arg-context s)))))]
8588
(jsonrpc/notify
8689
:message
8790
{:debug (format "function call %s"
@@ -109,7 +112,8 @@
109112

110113
(fail (format "bad container definition %s" definition)))
111114
(catch Throwable t
112-
(fail (format "system failure %s" t)))))
115+
(fail (format "system failure %s" t))
116+
(fail (with-out-str (.printStackTrace t))))))
113117
(fail "no function found")))
114118

115119
(defn call-function

test/jsonrpc/db_t.clj

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,47 @@
77
[lsp4clj.server :as server]))
88

99
(def correct-refs
10-
[[:dynamic
11-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/hello_world.md"]
12-
[:dynamic
13-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/mcp-sqlite.md"]
14-
[:dynamic
15-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/curl.md"]
16-
[:dynamic
17-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/ffmpeg.md"]
18-
[:dynamic
19-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/explain_dockerfile.md"]
20-
[:dynamic
21-
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/qrencode.md"]])
10+
[ [:dynamic
11+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/hello_world.md"]
12+
[:dynamic
13+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/curl.md"]
14+
[:dynamic
15+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/qrencode.md"]
16+
[:dynamic
17+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/mcp-sqlite.md"]
18+
[:dynamic
19+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/explain_dockerfile.md"]
20+
[:dynamic
21+
"github:docker/labs-ai-tools-for-devs?ref=main&path=prompts/examples/ffmpeg.md"]
22+
[:dynamic
23+
"github:docker/labs-ai-tools-for-devs?path=prompts/examples/mcp-memory.md"]
24+
[:dynamic
25+
"github:docker/labs-ai-tools-for-devs?path=prompts/lorax/speculative.md"]])
2226

2327
(t/deftest registry-ref-tests
2428
(t/testing "parse-registry"
2529
(t/is (= correct-refs
2630
(db/registry-refs "test/registry.yaml")))))
2731

28-
(let []
29-
(db/add-refs
32+
(comment
33+
(do
34+
(db/add-refs
3035
(concat
31-
(->> []
32-
(map (fn [ref] [:static ref])))
33-
;; register dynamic prompts
34-
(when (fs/exists? (fs/file "test/registry.yaml"))
35-
(db/registry-refs "test/registry.yaml"))))
36-
(server/receive-request "prompts/list" {:db* db*} {}))
36+
(->> []
37+
(map (fn [ref] [:static ref])))
38+
;; register dynamic prompts
39+
(when (fs/exists? (fs/file "test/registry.yaml"))
40+
(db/registry-refs "test/registry.yaml"))))
41+
(->> @db/db*
42+
:mcp.prompts/registry
43+
vals
44+
(mapcat :mcp/prompt-registry))
45+
(get-in (deref db/db*) [:mcp.prompts/registry "curl"])
46+
(server/receive-request "prompts/list" {:db* db/db*} {})
47+
(server/receive-request
48+
"prompts/get"
49+
{:db* db/db*}
50+
{:name "curl:fetch gists" :arguments {:user "slimslender"}})))
3751

3852
(comment
3953
(db/add-refs

0 commit comments

Comments
 (0)