Skip to content

Commit a107372

Browse files
committed
Fix ns cyclic deps
1 parent 4cf0e5b commit a107372

8 files changed

Lines changed: 139 additions & 121 deletions

File tree

src/eca/config.clj

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,23 @@
99
When `:config-file` from cli option is passed, it uses that instead of searching default locations."
1010
(:require
1111
[babashka.fs :as fs]
12-
[borkdude.dynaload :refer [dynaload]]
1312
[camel-snake-kebab.core :as csk]
1413
[cheshire.core :as json]
1514
[cheshire.factory :as json.factory]
1615
[clojure.core.memoize :as memoize]
1716
[clojure.java.io :as io]
1817
[clojure.string :as string]
1918
[clojure.walk :as walk]
19+
[eca.features.agents :as agents]
20+
[eca.interpolation :as interpolation]
2021
[eca.logger :as logger]
2122
[eca.messenger :as messenger]
22-
[eca.secrets :as secrets]
2323
[eca.shared :as shared :refer [multi-str]])
2424
(:import
2525
[java.io File]))
2626

2727
(set! *warn-on-reflection* true)
2828

29-
(def ^:private all-md-agents (dynaload 'eca.features.agents/all-md-agents))
30-
3129
(def ^:private logger-tag "[CONFIG]")
3230

3331
(def ^:dynamic *env-var-config-error* false)
@@ -174,51 +172,13 @@
174172
:autoCompactPercentage 75
175173
:env "prod"})
176174

177-
(defn replace-dynamic-strings
178-
"Given a string and a current working directory, look for patterns replacing its content:
179-
- `${env:SOME-ENV:default-value}`: Replace with a env falling back to a optional default value
180-
- `${file:/some/path}`: Replace with a file content checking from cwd if relative
181-
- `${classpath:path/to/file}`: Replace with a file content found checking classpath
182-
- `${netrc:api.provider.com}`: Replace with the content from Unix net RC [credential files](https://eca.dev/config/models/#credential-file-authentication)"
183-
[s cwd config]
184-
(some-> s
185-
(string/replace #"\$\{env:([^:}]+)(?::([^}]*))?\}"
186-
(fn [[_match env-var default-value]]
187-
(or (get-env env-var) default-value "")))
188-
(string/replace #"\$\{file:([^}]+)\}"
189-
(fn [[_match file-path]]
190-
(try
191-
(let [file-path (fs/expand-home file-path)]
192-
(slurp (str (if (fs/absolute? file-path)
193-
file-path
194-
(if cwd
195-
(fs/path cwd file-path)
196-
(fs/path file-path))))))
197-
(catch Exception _
198-
(logger/warn logger-tag "File not found when parsing string:" s)
199-
""))))
200-
(string/replace #"\$\{classpath:([^}]+)\}"
201-
(fn [[_match resource-path]]
202-
(try
203-
(slurp (io/resource resource-path))
204-
(catch Exception e
205-
(logger/warn logger-tag "Error reading classpath resource:" (.getMessage e))
206-
""))))
207-
(string/replace #"\$\{netrc:([^}]+)\}"
208-
(fn [[_match key-rc]]
209-
(try
210-
(or (secrets/get-credential key-rc (get config "netrcFile")) "")
211-
(catch Exception e
212-
(logger/warn logger-tag "Error reading netrc credential:" (.getMessage e))
213-
""))))))
214-
215175
(defn ^:private parse-dynamic-string-values
216176
"walk through config parsing dynamic string contents if value is a string."
217177
[config cwd]
218178
(walk/postwalk
219179
(fn [x]
220180
(if (string? x)
221-
(replace-dynamic-strings x cwd config)
181+
(interpolation/replace-dynamic-strings x cwd config)
222182
x))
223183
config))
224184

@@ -455,7 +415,8 @@
455415
;; Merge markdown-defined agents (lowest priority — JSON config agents win)
456416
(as-> config
457417
(let [md-agent-configs (when-not pure-config?
458-
(all-md-agents (:workspace-folders db)))]
418+
;; TODO how to avoid this dependency?
419+
(agents/all-md-agents (:workspace-folders db)))]
459420
(if (seq md-agent-configs)
460421
(update config :agent (fn [existing]
461422
(merge md-agent-configs existing)))

src/eca/features/agents.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[babashka.fs :as fs]
77
[clojure.java.io :as io]
88
[clojure.string :as string]
9-
[eca.config :as config]
9+
[eca.interpolation :as interpolation]
1010
[eca.logger :as logger]
1111
[eca.shared :as shared]))
1212

@@ -47,7 +47,7 @@
4747
(try
4848
(let [agent-name (string/lower-case (fs/strip-ext (fs/file-name md-file)))
4949
content (slurp (str md-file))
50-
content (config/replace-dynamic-strings content (fs/parent md-file) nil)
50+
content (interpolation/replace-dynamic-strings content (fs/parent md-file) nil)
5151
parsed (shared/parse-md content)
5252
agent-config (md->agent-config parsed)]
5353
(when (seq agent-config)

src/eca/features/skills.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
[babashka.fs :as fs]
44
[clojure.java.io :as io]
55
[eca.config :as config]
6+
[eca.interpolation :as interpolation]
67
[eca.shared :as shared]))
78

89
(set! *warn-on-reflection* true)
910

1011
(defn ^:private skill-file->skill [skill-file]
11-
(let [content (config/replace-dynamic-strings (slurp (str skill-file)) (fs/parent skill-file) nil)
12+
(let [content (interpolation/replace-dynamic-strings (slurp (str skill-file)) (fs/parent skill-file) nil)
1213
{:keys [name description body]} (shared/parse-md (or content ""))]
1314
(when (and name description)
1415
{:name name

src/eca/features/tools/agent.clj

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
(ns eca.features.tools.agent
22
"Tool for spawning subagents to perform focused tasks in isolated context."
33
(:require
4-
[borkdude.dynaload :refer [dynaload]]
54
[clojure.string :as str]
65
[eca.features.tools.util :as tools.util]
76
[eca.logger :as logger]
@@ -11,9 +10,6 @@
1110

1211
(def ^:private logger-tag "[AGENT-TOOL]")
1312

14-
(def ^:private chat-prompt (dynaload 'eca.features.chat/prompt))
15-
(def ^:private chat-prompt-stop (dynaload 'eca.features.chat/prompt-stop))
16-
1713
(defn ^:private all-agents
1814
[config]
1915
(->> (:agent config)
@@ -79,10 +75,11 @@
7975
(defn ^:private stop-subagent-chat!
8076
"Stop a running subagent chat."
8177
[db* messenger metrics subagent-chat-id agent-name]
82-
(try
83-
(chat-prompt-stop {:chat-id subagent-chat-id} db* messenger metrics)
84-
(catch Exception e
85-
(logger/warn logger-tag (format "Error stopping subagent '%s': %s" agent-name (.getMessage e))))))
78+
(let [prompt-stop (requiring-resolve 'eca.features.chat/prompt-stop)]
79+
(try
80+
(prompt-stop {:chat-id subagent-chat-id} db* messenger metrics)
81+
(catch Exception e
82+
(logger/warn logger-tag (format "Error stopping subagent '%s': %s" agent-name (.getMessage e)))))))
8683

8784
(defn ^:private spawn-agent
8885
"Handler for the spawn_agent tool.
@@ -128,7 +125,9 @@
128125
max-steps-limit (assoc :max-steps max-steps-limit)))
129126

130127
(try
131-
(let [task-prompt (if max-steps-limit
128+
;; Require chat ns here to avoid circular dependency
129+
(let [chat-prompt (requiring-resolve 'eca.features.chat/prompt)
130+
task-prompt (if max-steps-limit
132131
(format "%s\n\nIMPORTANT: You have a maximum of %d steps to complete this task. Be efficient and provide a clear summary of your findings before reaching the limit."
133132
task max-steps-limit)
134133
task)]

src/eca/interpolation.clj

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
(ns eca.interpolation
2+
"Expands dynamic placeholder patterns in strings:
3+
- `${env:SOME-ENV:default-value}`: environment variable with optional default
4+
- `${file:/some/path}`: file content (relative paths resolved from cwd)
5+
- `${classpath:path/to/file}`: classpath resource content
6+
- `${netrc:api.provider.com}`: credential from Unix netrc files"
7+
(:require
8+
[babashka.fs :as fs]
9+
[clojure.java.io :as io]
10+
[clojure.string :as string]
11+
[eca.logger :as logger]
12+
[eca.secrets :as secrets]))
13+
14+
(set! *warn-on-reflection* true)
15+
16+
(def ^:private logger-tag "[INTERPOLATION]")
17+
18+
(defn get-env [env] (System/getenv env))
19+
20+
(defn replace-dynamic-strings
21+
"Given a string and a current working directory, look for patterns replacing its content:
22+
- `${env:SOME-ENV:default-value}`: Replace with a env falling back to a optional default value
23+
- `${file:/some/path}`: Replace with a file content checking from cwd if relative
24+
- `${classpath:path/to/file}`: Replace with a file content found checking classpath
25+
- `${netrc:api.provider.com}`: Replace with the content from Unix net RC [credential files](https://eca.dev/config/models/#credential-file-authentication)"
26+
[s cwd config]
27+
(some-> s
28+
(string/replace #"\$\{env:([^:}]+)(?::([^}]*))?\}"
29+
(fn [[_match env-var default-value]]
30+
(or (get-env env-var) default-value "")))
31+
(string/replace #"\$\{file:([^}]+)\}"
32+
(fn [[_match file-path]]
33+
(try
34+
(let [file-path (fs/expand-home file-path)]
35+
(slurp (str (if (fs/absolute? file-path)
36+
file-path
37+
(if cwd
38+
(fs/path cwd file-path)
39+
(fs/path file-path))))))
40+
(catch Exception _
41+
(logger/warn logger-tag "File not found when parsing string:" s)
42+
""))))
43+
(string/replace #"\$\{classpath:([^}]+)\}"
44+
(fn [[_match resource-path]]
45+
(try
46+
(slurp (io/resource resource-path))
47+
(catch Exception e
48+
(logger/warn logger-tag "Error reading classpath resource:" (.getMessage e))
49+
""))))
50+
(string/replace #"\$\{netrc:([^}]+)\}"
51+
(fn [[_match key-rc]]
52+
(try
53+
(or (secrets/get-credential key-rc (get config "netrcFile")) "")
54+
(catch Exception e
55+
(logger/warn logger-tag "Error reading netrc credential:" (.getMessage e))
56+
""))))))

src/eca/main.clj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
[clojure.string :as string]
88
[eca.client-http :as client]
99
[eca.config :as config]
10-
[eca.features.agents] ;; TODO how to fix this cyclic dep
1110
[eca.logger :as logger]
1211
[eca.server :as server]))
1312

0 commit comments

Comments
 (0)