Skip to content

Commit 63111e7

Browse files
Dedup change events by content
1 parent eca3c98 commit 63111e7

File tree

3 files changed

+100
-42
lines changed

3 files changed

+100
-42
lines changed

src/jsonrpc/db.clj

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
[clojure.pprint :refer [pprint]]
88
git
99
[jsonrpc.logger :as logger]
10-
[medley.core :as medley]
1110
prompts
1211
prompts.core
1312
repl))
@@ -22,8 +21,8 @@
2221
register is a coll of prompt file ref maps"
2322
[{:keys [register] :as opts}]
2423
(->> register
25-
(map (fn [{:keys [cached-path ref-string config] :as registration-entry}]
26-
(logger/info registration-entry)
24+
(map (fn [{:keys [cached-path ref-string config]}]
25+
(logger/info (format "%-80s %s" ref-string cached-path))
2726
(try
2827
(let [m (prompts/get-prompts (-> opts
2928
(assoc :config config)
@@ -55,8 +54,6 @@
5554
(update :mcp.prompts/resources (fnil merge {}) (extract-resources m))))
5655

5756
(defn- add-dynamic-prompts [db m]
58-
(logger/info "dynamic keys" (keys (:mcp.prompts/registry db)))
59-
(logger/info "static keys" (keys (:mcp.prompts/static db)))
6057
(-> db
6158
(assoc :mcp.prompts/registry (merge m (:mcp.prompts/static db)))
6259
(update :mcp.prompts/resources (fnil merge {}) (extract-resources m))))
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
(ns jsonrpc.prompt-change-events
2+
(:require
3+
[babashka.fs :as fs]
4+
[clojure.core.async :as async]
5+
[clojure.string :as string]
6+
docker
7+
[jsonrpc.db :as db]
8+
[jsonrpc.logger :as logger]
9+
[jsonrpc.producer :as producer]
10+
[jsonrpc.state :as state]
11+
[prompts.core :refer [registry]]
12+
repl
13+
shutdown))
14+
15+
(defn debounce-by
16+
"Debounce in channel with ms miliseconds distincting by by-fn."
17+
[in by-fn]
18+
(let [out (async/chan)]
19+
(async/go-loop [state {}]
20+
(let [{:keys [f] :as new-val} (async/<! in)
21+
v (by-fn new-val)]
22+
(when (not (= (get state f) v))
23+
(async/>! out new-val))
24+
(recur (assoc state f v))))
25+
out))
26+
27+
(defn publish-change-event []
28+
(doseq [producer (vals @state/producers)]
29+
(try
30+
(producer/publish-tool-list-changed producer {})
31+
(producer/publish-prompt-list-changed producer {})
32+
(catch Throwable _))))
33+
34+
(defn registry-updated []
35+
(try
36+
(db/add-refs (db/registry-refs registry))
37+
(publish-change-event)
38+
(catch Throwable t
39+
(logger/error t "unable to parse registry.yaml"))))
40+
41+
(defn markdown-tool-updated [opts f]
42+
(try
43+
(db/update-prompt opts (string/replace f #"\.md" "") (slurp (fs/file (prompts.core/get-prompts-dir) f)))
44+
(publish-change-event)
45+
(catch Throwable t
46+
(logger/error t "unable to parse " f))))
47+
48+
(defn content [{:keys [f]}]
49+
(slurp (fs/file (prompts.core/get-prompts-dir) f)))
50+
51+
(defn init-dynamic-prompt-watcher [opts registry-updated markdown-tool-updated]
52+
(let [change-events-channel (async/chan)
53+
debounced (debounce-by change-events-channel content)]
54+
;; debounce the change event channel
55+
(async/go-loop
56+
[evt (async/<! debounced)]
57+
(case (:type evt)
58+
:registry (registry-updated)
59+
:markdown (markdown-tool-updated (:opts evt) (:f evt))
60+
:unknown)
61+
(recur (async/<! debounced)))
62+
;; watch filesystem
63+
(async/thread
64+
(let [{x :container}
65+
(docker/run-streaming-function-with-no-stdin
66+
{:image "vonwig/inotifywait:latest"
67+
:volumes ["docker-prompts:/prompts"]
68+
:command ["-e" "create" "-e" "modify" "-e" "delete" "-q" "-m" "/prompts"]}
69+
(fn [line]
70+
(let [[_dir _event f] (string/split line #"\s+")]
71+
(async/>!!
72+
change-events-channel
73+
(cond
74+
(= f "registry.yaml")
75+
{:opts opts :f f :type :registry}
76+
(string/ends-with? f ".md")
77+
{:opts opts :f f :type :markdown}
78+
:else
79+
{})))))]
80+
(shutdown/schedule-container-shutdown
81+
(fn []
82+
(logger/info "inotifywait shutting down")
83+
(docker/kill-container x)
84+
(docker/delete x)))))))
85+
86+
(comment
87+
(repl/setup-stdout-logger)
88+
(init-dynamic-prompt-watcher
89+
{}
90+
(fn [] (logger/info "registry updated"))
91+
(fn [& args] (logger/info "markdown updated " args))))
92+
93+

src/jsonrpc/server.clj

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
[jsonrpc.extras]
1616
[jsonrpc.logger :as logger]
1717
[jsonrpc.producer :as producer]
18+
jsonrpc.prompt-change-events
1819
[jsonrpc.socket-server :as socket-server]
1920
jsonrpc.state
2021
[lsp4clj.coercer :as coercer]
@@ -294,42 +295,6 @@
294295
(apply log-wrapper-fn log-args)
295296
(recur))))
296297

297-
(defn- init-dynamic-prompt-watcher [opts]
298-
(async/thread
299-
(let [{x :container}
300-
(docker/run-streaming-function-with-no-stdin
301-
{:image "vonwig/inotifywait:latest"
302-
:volumes ["docker-prompts:/prompts"]
303-
:command ["-e" "create" "-e" "modify" "-e" "delete" "-q" "-m" "/prompts"]}
304-
(fn [line]
305-
(logger/info "change event" line)
306-
(let [[_dir _event f] (string/split line #"\s+")]
307-
(when (= f "registry.yaml")
308-
(try
309-
(db/add-refs (db/registry-refs registry))
310-
(doseq [producer (vals @jsonrpc.state/producers)]
311-
(try
312-
(producer/publish-tool-list-changed producer {})
313-
(producer/publish-prompt-list-changed producer {})
314-
(catch Throwable _)))
315-
(catch Throwable t
316-
(logger/error t "unable to parse registry.yaml"))))
317-
(when (string/ends-with? f ".md")
318-
(try
319-
(db/update-prompt opts (string/replace f #"\.md" "") (slurp (str "/prompts/" f)))
320-
(doseq [producer (vals @jsonrpc.state/producers)]
321-
(try
322-
(producer/publish-tool-list-changed producer {})
323-
(producer/publish-prompt-list-changed producer {})
324-
(catch Throwable _)))
325-
(catch Throwable t
326-
(logger/error t "unable to parse " f)))))))]
327-
(shutdown/schedule-container-shutdown
328-
(fn []
329-
(logger/info "inotifywait shutting down")
330-
(docker/kill-container x)
331-
(docker/delete x))))))
332-
333298
(defn initialize-prompts [opts]
334299
;; initialize mcp cache
335300
(client/initialize-cache)
@@ -362,7 +327,10 @@
362327
;; initialize prompts
363328
(initialize-prompts opts)
364329
;; watch dynamic prompts in background
365-
(init-dynamic-prompt-watcher opts)
330+
(jsonrpc.prompt-change-events/init-dynamic-prompt-watcher
331+
opts
332+
jsonrpc.prompt-change-events/registry-updated
333+
jsonrpc.prompt-change-events/markdown-tool-updated)
366334
;; monitor our log channel (used by all chan servers)
367335
(monitor-server-logs log-ch)
368336
;; this won't do anything if nrepl is not present

0 commit comments

Comments
 (0)