-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutil.clj
More file actions
132 lines (115 loc) · 4.45 KB
/
util.clj
File metadata and controls
132 lines (115 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(ns github.copilot-sdk.util
"Utility functions for the Copilot SDK."
(:require [camel-snake-kebab.core :as csk]
[camel-snake-kebab.extras :as cske]))
;; -----------------------------------------------------------------------------
;; Key conversion utilities
;; Convert between wire format (camelCase) and Clojure idiom (kebab-case)
;; -----------------------------------------------------------------------------
(defn- keyword->camel
[k]
(if (keyword? k)
(csk/->camelCaseKeyword k)
k))
(defn- keyword->kebab
[k]
(if (keyword? k)
(csk/->kebab-case-keyword k)
k))
(defn ->wire-keys
"Convert map keys from kebab-case to camelCase for wire format.
Works recursively on nested maps. Non-keyword keys are preserved."
[m]
(cske/transform-keys keyword->camel m))
(defn ->clj-keys
"Convert map keys from camelCase to kebab-case for Clojure idiom.
Works recursively on nested maps. Non-keyword keys are preserved."
[m]
(cske/transform-keys keyword->kebab m))
(defn wire->clj
"Convert a wire-format map to Clojure idiom.
Alias for ->clj-keys."
[m]
(->clj-keys m))
(defn clj->wire
"Convert a Clojure idiom map to wire format.
Alias for ->wire-keys."
[m]
(->wire-keys m))
;; MCP server config keys use an :mcp- prefix in Clojure for clarity
;; (e.g., :mcp-command, :mcp-args, :mcp-tools) but the upstream wire
;; protocol expects bare names (command, args, tools, url, headers, type, timeout).
;; This mapping strips the mcp- prefix before applying camelCase conversion.
(def ^:private mcp-key-renames
{:mcp-command :command
:mcp-args :args
:mcp-tools :tools
:mcp-server-type :type
:mcp-timeout :timeout
:mcp-url :url
:mcp-headers :headers})
(defn mcp-server->wire
"Convert a single MCP server config from Clojure idiom to wire format.
Strips the :mcp- prefix from MCP-specific keys, then converts remaining
keys to camelCase. Keyword values for :type are converted to strings.
Example: {:mcp-command \"node\" :mcp-args [\"x\"] :mcp-server-type :http}
becomes {\"command\" \"node\" \"args\" [\"x\"] \"type\" \"http\"}."
[m]
(let [renamed (reduce-kv (fn [acc k v]
(assoc acc (get mcp-key-renames k k) v))
{}
m)
;; Convert keyword values for :type to strings (upstream expects string)
stringified (cond-> renamed
(keyword? (:type renamed))
(update :type name))]
(clj->wire stringified)))
(defn mcp-servers->wire
"Convert MCP servers map from Clojure idiom to wire format.
Each server value has :mcp-* prefixed keys stripped before camelCase conversion."
[servers]
(into {} (map (fn [[k v]] [k (mcp-server->wire v)])) servers))
;; -----------------------------------------------------------------------------
;; Attachment wire conversion
;; -----------------------------------------------------------------------------
(defn attachment->wire
"Convert an attachment from Clojure format to wire format.
Handles the special mapping for selection attachments where
:file-path -> filePath and :selection-range -> selection."
[att]
(case (:type att)
:selection
(cond-> {:type "selection"
:filePath (:file-path att)
:displayName (:display-name att)}
(:selection-range att) (assoc :selection (clj->wire (:selection-range att)))
(:text att) (assoc :text (:text att)))
:github-reference
{:type "github_reference"
:number (:number att)
:title (:title att)
:referenceType (name (:reference-type att))
:state (:state att)
:url (:url att)}
;; :file and :directory
(cond-> {:type (name (:type att))
:path (:path att)}
(:display-name att) (assoc :displayName (:display-name att)))))
(defn attachments->wire
"Convert a vector of attachments to wire format."
[attachments]
(mapv attachment->wire attachments))
;; -----------------------------------------------------------------------------
;; Event type normalization
;; -----------------------------------------------------------------------------
(defn event-type->keyword
"Normalize event :type values to namespaced keywords.
Example: \"assistant.message_delta\" -> :copilot/assistant.message_delta."
[event-type]
(cond
(keyword? event-type)
(if (namespace event-type)
event-type
(keyword "copilot" (name event-type)))
(string? event-type) (keyword "copilot" event-type)
:else event-type))