Skip to content

Commit 9e56f9f

Browse files
Fix h2 headers
1 parent 49308e2 commit 9e56f9f

File tree

13 files changed

+186
-40
lines changed

13 files changed

+186
-40
lines changed

dev/catalog.clj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
[medley.core :as medley]
77
prompts))
88

9-
(prompts/get-prompts {:prompts (fs/file "prompts/examples/mcp-memory.md")})
9+
(try
10+
(prompts/get-prompts {:prompts (fs/file "prompts/chrome.md")})
11+
(catch Throwable t
12+
(println t)))
1013

1114
(defn f->prompt [f]
1215
(prompts/get-prompts {:prompts f}))
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
* default is to run synchronously without stdin and in terminal model
3+
* image is mandatory
4+
* default is to try to pull image every time it runs
5+
* always binds docker-lsp volume (does not bind prompts volume - that's only for the server)
6+
* if server is running with a host-dir, that host-dir will bind with /volume
7+
* there will pretty much always be a mounted /thread volume but see below
8+
* volumes is also an optional parameter in the container definition
9+
* workingdir (parameter is called workdir) is either set in the definition or defaults to /project
10+
* /var/run/docker.sock is always mounted
11+
12+
# parameters
13+
14+
* volumes (list of strings) supports interpolation optional
15+
* command (list of strings) supports interpolation optional
16+
* workdir (string) supports interpolation optional
17+
* stdin (keys content, file) supports interpolation optional
18+
* entrypoint (string) does NOT suport interpolation optional
19+
* image (string) does not support interpolation mandatory
20+
21+
# interpolation
22+
23+
* has a filter called `|into` that will take a parameter list and _spread_ it into a string list
24+
* `volumes` `command` `workdir` `stdin.content` and `stdin.file` all support interpoloation
25+
* `image` and `entrypoint` do not support interpolation
26+

prompts/chrome.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ tools:
5252
- url
5353
container:
5454
image: zenika/alpine-chrome
55+
background: true
56+
ports:
57+
- "9222:9222"
5558
command:
5659
- "--no-sandbox"
5760
- "--remote-debugging-address=0.0.0.0"
@@ -68,33 +71,33 @@ You have `curl` and `websocat` available to you to control the browser and to an
6871

6972
If you don't see the browser running, use the chrome tool to start it. Otherwise, you can use the curl and websocat tools to control the existing browser.
7073

71-
**Verify the server is running**
74+
## Verify the server is running
7275

7376
Use curl to get the websocket url and make sure the server is running. If it isn't start it with the chrome tool. You can be easily overwhelmed when using curl to get html. Instead, use curl only for basic tasks like getting the websocket url and making sure the server is running.
7477

78+
When you get a websocket url back, change localhost to be host.docker.internal
79+
7580
Examples:
7681

7782
```sh
7883
# Get the websocket url
79-
curl -X PUT -sg http://localhost:9222/json/new
84+
curl -X PUT -H "HOST: localhost:9222" -sg http://host.docker.internal:9222/json/new
8085

8186
# Navigate to a page
8287

8388
$MESSAGE='Page.navigate {"url":"https://www.docker.com"}' # This format works with --jsonrpc where the first word is the method name and the rest is the arguments.
8489

85-
$MESSAGE | websocat -n1 --jsonrpc --jsonrpc-omit-jsonrpc ws://localhost:9222/devtools/page/<PAGE_ID>
90+
$MESSAGE | websocat -n1 --jsonrpc --jsonrpc-omit-jsonrpc ws://host.docker.internal:9222/devtools/page/<PAGE_ID>
8691

8792
{"id":2,"result":{"frameId":"A331E56CCB8615EB4FCB720425A82259","loaderId":"EF5AAD19F2F8BB27FAF55F94FFB27DF9"}}
8893
```
8994

9095
For more complex tasks, use websocat to send and receive messages to the browser. This can be used to execute javascript, navigate to a page, or screenshot the page.
9196

92-
**Cleanup**
97+
## Cleanup
9398

9499
It is important that when you are done with your page, you close it. This is important because the browser could continue to run even after you close the websocket connection.
95100

96101
The following is the question you are trying to answer:
97102

98-
# prompt user
99-
100-
What is the url for the docker logo?
103+
What is the url for the docker logo?

prompts/examples/explain_dockerfile.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ This tool can explain a pre-provided Dockerfile but it can also fetch the Docker
3636

3737
## content
3838

39-
Start by fetching the Dockerfile located at the path {{path}}.
39+
Start by fetching the Dockerfile located at the path {{path}} using the cat_file tool.
4040

4141
After fetching the Dockerfile contents, explain the Dockerfile line by line.
4242

src/docker.clj

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@
112112
;; Tty wraps the process in a pseudo terminal
113113
{:StdinOnce true
114114
:OpenStdin true}
115-
(defn create-container [{:keys [image entrypoint workdir command host-dir env thread-id opts mounts volumes] :or {opts {:Tty true}}}]
115+
(defn create-container [{:keys [image entrypoint workdir command host-dir env thread-id opts mounts volumes ports]
116+
:or {opts {:Tty true}}}]
116117
(let [payload (json/generate-string
117118
(merge
118119
{:Image image}
@@ -121,13 +122,17 @@
121122
(map (fn [[k v]] (format "%s=%s" (name k) v)))
122123
(into []))})
123124
{:HostConfig
124-
{:Binds
125-
(concat ["docker-lsp:/docker-lsp"
126-
"/var/run/docker.sock:/var/run/docker.sock"]
127-
(when host-dir [(format "%s:/project:rw" host-dir)])
128-
(when thread-id [(format "%s:/thread:rw" thread-id)])
129-
(or volumes mounts))}
125+
(merge
126+
{:Binds
127+
(concat ["docker-lsp:/docker-lsp"
128+
"/var/run/docker.sock:/var/run/docker.sock"]
129+
(when host-dir [(format "%s:/project:rw" host-dir)])
130+
(when thread-id [(format "%s:/thread:rw" thread-id)])
131+
(or volumes mounts))}
132+
(when ports
133+
{:PortBindings {"9222/tcp" [{:HostPort "9222"}]}}))
130134
:WorkingDir (or workdir "/project")}
135+
(when ports {:ExposedPorts {"9222/tcp" {}}})
131136
(when entrypoint {:Entrypoint entrypoint})
132137
(when command {:Cmd command})))
133138
ascii-payload (String. (.getBytes payload "ASCII"))]
@@ -234,8 +239,19 @@
234239
(def pull (comp (status? 200 "pull-image") pull-image))
235240
(def images (comp ->json list-images))
236241

242+
(defn- add-latest [image]
243+
(let [[_ tag] (re-find #".*(:.*)$" image)]
244+
(if tag
245+
image
246+
(str image ":latest"))))
247+
248+
(comment
249+
(add-latest "vonwig/go-linguist")
250+
(add-latest "blah/what:tag"))
251+
237252
(defn- -pull [m]
238253
(pull (merge m
254+
{:image (add-latest (:image m))}
239255
{:serveraddress "https://index.docker.io/v1/"}
240256
(when (and (:user m)
241257
(or (:jwt m) (:pat m)))
@@ -305,7 +321,8 @@
305321
(fn []
306322
(kill-container x)
307323
(delete x)))
308-
{:done :running}))
324+
{:done :running
325+
:pty-output (str "started up Ts" (:image m))}))
309326

310327
(defn run-function
311328
"run container function with no stdin, and no streaming output"

src/docker/main.clj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@
145145
(fn [m]
146146
(update-in m [:prompts] (fn [coll] (remove (fn [{:keys [type]}] (= type (second args))) coll))))))
147147
"run" (fn []
148+
(logger/setup (jsonrpc.server/->TimbreLogger))
149+
148150
(let [[in send]
149151
(let [[[w c] in] (user-loop/create-pipe)]
150152
[in (fn []

src/jsonrpc/db.clj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
(defn update-prompt
9595
"update the db with new markdown prompt content being dynamically registered"
9696
[opts s content]
97-
(logger/info (format "update prompt %s with content %s" s content))
9897
(let [m (prompts/get-prompts
9998
(assoc opts :prompt-content content))]
10099
(swap! db* (fn [db]

src/jsonrpc/server.clj

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,20 @@
286286
(apply log-wrapper-fn log-args)
287287
(recur))))
288288

289+
(defn decide-log-path []
290+
(let [prompts-dir (fs/file "/prompts")]
291+
(if (fs/exists? prompts-dir)
292+
(do
293+
(fs/create-dirs (fs/file prompts-dir "log"))
294+
(fs/file prompts-dir "log/docker-mcp-server.out"))
295+
(do
296+
(fs/create-dirs (fs/file "./log"))
297+
(fs/file "./log/docker-mcp-server.out")))))
298+
289299
(defrecord TimbreLogger []
290300
logger/ILogger
291301
(setup [this]
292-
(fs/create-dirs (fs/file "/prompts" "log"))
293-
(let [log-path (str (fs/file "/prompts/log/docker-mcp-server.out"))]
302+
(let [log-path (str (decide-log-path))]
294303
(timbre/merge-config! {:middleware [#(assoc % :hostname_ "")]
295304
:appenders {:println {:enabled? false}
296305
:spit (appenders/spit-appender {:fname log-path})}})

src/markdown.clj

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
[clj-yaml.core :as clj-yaml]
55
[clojure.core.async :as async]
66
[clojure.edn :as edn]
7-
[clojure.pprint :refer [pprint]]
87
[clojure.string :as string]
98
[clojure.zip :as zip]
109
[docker]
@@ -85,6 +84,11 @@
8584
(defn atx-heading-section? [node]
8685
(= "atx_heading" (first node)))
8786

87+
(defn atx-heading-1? [node]
88+
(and
89+
(= "atx_heading" (first node))
90+
(= "atx_h1_marker" (-> node (nth 2) first))))
91+
8892
(defn remove-section-content [content s node]
8993
(if (and (list? node) (= "atx_heading" (first node)))
9094
(string/replace s (from-range (nth node 1) content) "")
@@ -99,19 +103,40 @@
99103
(defn section-content [content node]
100104
(from-range (nth node 1) content))
101105

102-
(defn h1-prompt-content [content node]
106+
(defn h1-prompt-content
107+
" params
108+
node is a top-level h1 prompt node"
109+
[content node]
103110
(merge
104111
(-> node (nth 2) (nth 3) (nth 1) (from-range content) (parse-h1))
105-
(if (some section? node)
112+
(if (->> node
113+
(filter list?)
114+
(some (partial description-section? content)))
106115
;; prompt is broken up with real sections
107116
(merge
108-
{:content (->> node
109-
(filter list?)
110-
(filter (complement (partial description-section? content)))
111-
#_(filter (complement atx-heading-section?))
112-
(map (partial section-content content))
113-
(apply str)
114-
(string/trim))}
117+
{:content (let [top-level-content-nodes
118+
(->> node
119+
(filter list?)
120+
(filter (complement (partial description-section? content)))
121+
(filter (complement atx-heading-1?)))
122+
first-heading-node
123+
(->> top-level-content-nodes
124+
(filter section?)
125+
first
126+
(seq)
127+
(filter atx-heading-section?)
128+
first)
129+
prompt-content
130+
(->> top-level-content-nodes
131+
(map (partial section-content content))
132+
(apply str))]
133+
(string/trim
134+
(string/replace
135+
prompt-content
136+
(if first-heading-node
137+
(from-range (nth first-heading-node 1) content)
138+
"")
139+
"")))}
115140
(when-let [description (some->> node
116141
(filter section?)
117142
(filter (partial description-section? content))

src/schema.clj

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,20 +52,31 @@
5252
(s/def ::container-response (s/keys :req-un [::pty-output ::exit-code ::info ::done]
5353
:opt-un [::timeout ::kill-container]))
5454

55+
;; -- tool parameters --
56+
(s/def :tool/parameters any?)
57+
58+
;; -- container tools --
59+
(s/def :container/image string?)
60+
(s/def :container/command (s/coll-of string?))
61+
(s/def :container/stdin any?)
62+
(s/def :container/volumes (s/coll-of string?))
63+
(s/def :container/entrypoint string?)
64+
(s/def :container/workdir string?)
65+
(s/def :tool/container (s/keys :req-un [:container/image]
66+
:opt-un [:container/stdin :container/command :container/volumes :container/entrypoint :container/workdir]))
67+
5568
;; -- Spec definitions for Tools --
5669
(s/def ::github-ref (s/and string? #(string/starts-with? % "github:")))
5770
(s/def :prompt/ref ::github-ref)
5871
(s/def :prompt/prompt (s/or :github-ref ::github-ref :relative-path string?))
5972
(s/def :tool/name string?)
60-
(s/def :docker/type #{"prompt" "container"})
73+
(s/def :docker/type #{"prompt"})
6174
(s/def :tool/description string?)
6275
(s/def ::prompt-tool (s/keys :req-un [:tool/name :tool/description :docker/type]
6376
:opt-un [:tool/parameters :prompt/prompt :prompt/ref]))
6477
(s/def ::container-tool (s/keys :req-un [:tool/name :tool/description :tool/container]
6578
:opt-un [:tool/parameters]))
66-
(s/def ::placeholder-tool (s/keys :req-un [:tool/name :tool/description]
67-
:opt-un [:tool/parameters]))
68-
(s/def :tool/function (s/or :container ::container-tool :prompt ::prompt-tool :placeholder ::placeholder-tool))
79+
(s/def :tool/function (s/or :container ::container-tool :prompt ::prompt-tool))
6980
(s/def :tool/type #{"function"})
7081
(s/def ::tool (s/keys :req-un [:tool/type :tool/function]))
7182
(s/def ::tools (s/coll-of ::tool))

0 commit comments

Comments
 (0)