@nbardy/oompa 0.7.1 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -6
- package/agentnet/src/agentnet/agent.clj +45 -20
- package/agentnet/src/agentnet/cli.clj +852 -193
- package/agentnet/src/agentnet/cli.clj.bak +1384 -0
- package/agentnet/src/agentnet/core.clj +17 -2
- package/agentnet/src/agentnet/harness.clj +93 -37
- package/agentnet/src/agentnet/runs.clj +11 -6
- package/agentnet/src/agentnet/schema.clj +8 -1
- package/agentnet/src/agentnet/tasks.clj +6 -0
- package/agentnet/src/agentnet/worker.clj +867 -408
- package/bin/oompa.js +5 -1
- package/config/prompts/_task_header.md +9 -2
- package/config/prompts/magicgenie-executor.md +15 -0
- package/config/prompts/magicgenie-planner.md +26 -0
- package/config/prompts/magicgenie-reviewer.md +44 -0
- package/oompa.example.json +4 -4
- package/package.json +5 -3
- package/scripts/README.md +6 -0
- package/scripts/__pycache__/stream_bridge.cpython-314.pyc +0 -0
- package/scripts/copy-repo-code.sh +110 -0
- package/scripts/install-babashka.js +97 -0
- package/scripts/test-harness-resume.sh +229 -0
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
(defn now-ms []
|
|
9
9
|
(System/currentTimeMillis))
|
|
10
10
|
|
|
11
|
+
(defn- normalize-priority
|
|
12
|
+
"Coerce :priority to a sortable number.
|
|
13
|
+
Accepts: integer, \"P1\"/\"P2\" strings, numeric strings, nil.
|
|
14
|
+
Unknown/nil → 1000 (low priority)."
|
|
15
|
+
[p]
|
|
16
|
+
(cond
|
|
17
|
+
(number? p) p
|
|
18
|
+
(nil? p) 1000
|
|
19
|
+
(string? p)
|
|
20
|
+
(let [s (str/upper-case (str/trim p))]
|
|
21
|
+
(cond
|
|
22
|
+
(str/starts-with? s "P") (try (Integer/parseInt (subs s 1)) (catch Exception _ 1000))
|
|
23
|
+
:else (try (Integer/parseInt s) (catch Exception _ 1000))))
|
|
24
|
+
:else 1000))
|
|
25
|
+
|
|
11
26
|
(defn format-ago
|
|
12
27
|
"Return human-readable relative time string for epoch milliseconds."
|
|
13
28
|
[^long ts-ms]
|
|
@@ -50,7 +65,7 @@
|
|
|
50
65
|
|
|
51
66
|
(defn- queue-lines [tasks]
|
|
52
67
|
(->> tasks
|
|
53
|
-
(sort-by (juxt (comp
|
|
68
|
+
(sort-by (juxt (comp normalize-priority :priority) :id))
|
|
54
69
|
(map (fn [{:keys [id summary]}]
|
|
55
70
|
(format "`%s` • %s" id summary)))))
|
|
56
71
|
|
|
@@ -82,7 +97,7 @@
|
|
|
82
97
|
|
|
83
98
|
(defn- backlog-entries [tasks]
|
|
84
99
|
(->> tasks
|
|
85
|
-
(sort-by (juxt (comp
|
|
100
|
+
(sort-by (juxt (comp normalize-priority :priority) :id))
|
|
86
101
|
(map #(select-keys % [:id :summary]))
|
|
87
102
|
(remove #(nil? (:id %)))
|
|
88
103
|
(take 7)
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
(throw (ex-info (str "Binary not found on PATH: " name) {:binary name}))))))
|
|
35
35
|
|
|
36
36
|
;; =============================================================================
|
|
37
|
-
;;
|
|
37
|
+
;; NDJSON Output Parsing (harness-specific, lives here not in agent-cli)
|
|
38
38
|
;; =============================================================================
|
|
39
39
|
|
|
40
|
-
(defn- parse-
|
|
41
|
-
"Parse
|
|
42
|
-
Returns {:session-id string|nil, :text string|nil}."
|
|
40
|
+
(defn- parse-unified-jsonl-output
|
|
41
|
+
"Parse unified JSONL emitted by `agent-cli run`.
|
|
42
|
+
Returns {:session-id string|nil, :text string|nil, :warning string|nil}."
|
|
43
43
|
[s]
|
|
44
44
|
(let [raw (or s "")
|
|
45
45
|
events (->> (str/split-lines raw)
|
|
@@ -49,23 +49,47 @@
|
|
|
49
49
|
(catch Exception _
|
|
50
50
|
nil))))
|
|
51
51
|
doall)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(some-> (re-find #"(ses_[A-Za-z0-9]+)" raw) second))
|
|
52
|
+
event-types (->> events (keep :type) distinct (take 8) vec)
|
|
53
|
+
session-id (some->> events
|
|
54
|
+
(keep #(when (= "session.started" (:type %))
|
|
55
|
+
(:sessionId %)))
|
|
56
|
+
last)
|
|
58
57
|
text (->> events
|
|
59
|
-
(keep (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
(keep #(when (= "text.delta" (:type %)) (:text %)))
|
|
59
|
+
(remove str/blank?)
|
|
60
|
+
(str/join ""))
|
|
61
|
+
stderr-text (->> events
|
|
62
|
+
(keep #(when (= "stderr" (:type %)) (:text %)))
|
|
63
|
+
(remove str/blank?)
|
|
64
|
+
(str/join ""))
|
|
65
|
+
errors (->> events
|
|
66
|
+
(keep #(when (= "error" (:type %)) (:message %)))
|
|
67
|
+
(remove str/blank?)
|
|
68
|
+
vec)
|
|
69
|
+
warning (cond
|
|
70
|
+
(and (not (str/blank? raw)) (empty? events))
|
|
71
|
+
"agent-cli returned non-empty output, but no unified JSONL events were parsed."
|
|
72
|
+
|
|
73
|
+
(seq errors)
|
|
74
|
+
(str "agent-cli reported error events: " (str/join " | " (take 3 errors)))
|
|
75
|
+
|
|
76
|
+
(and (seq events) (str/blank? text))
|
|
77
|
+
(str "agent-cli returned unified events, but no text deltas were extracted"
|
|
78
|
+
" (types=" (if (seq event-types)
|
|
79
|
+
(str/join "," event-types)
|
|
80
|
+
"unknown")
|
|
81
|
+
").")
|
|
82
|
+
|
|
83
|
+
:else nil)]
|
|
67
84
|
{:session-id session-id
|
|
68
|
-
:text (
|
|
85
|
+
:text (cond
|
|
86
|
+
(not (str/blank? text)) text
|
|
87
|
+
(seq errors) (str/join "\n" errors)
|
|
88
|
+
(not (str/blank? stderr-text)) stderr-text
|
|
89
|
+
:else nil)
|
|
90
|
+
:warning warning
|
|
91
|
+
:raw-snippet (when-not (str/blank? raw)
|
|
92
|
+
(subs raw 0 (min 400 (count raw))))}))
|
|
69
93
|
|
|
70
94
|
;; =============================================================================
|
|
71
95
|
;; Env Helpers
|
|
@@ -90,11 +114,29 @@
|
|
|
90
114
|
;; :session - session ID strategy (:uuid, :extracted, :implicit)
|
|
91
115
|
;; :output - output format (:plain or :ndjson)
|
|
92
116
|
|
|
117
|
+
(def ^:private gemini-behavior
|
|
118
|
+
{:stdin :close :session :implicit :output :ndjson})
|
|
119
|
+
|
|
93
120
|
(def registry
|
|
94
|
-
|
|
95
|
-
:
|
|
96
|
-
|
|
97
|
-
|
|
121
|
+
(merge
|
|
122
|
+
{:codex {:stdin :close :session :uuid :output :plain}
|
|
123
|
+
:claude {:stdin :prompt :session :uuid :output :plain}
|
|
124
|
+
:opencode {:stdin :close :session :extracted :output :ndjson}
|
|
125
|
+
:gemini gemini-behavior}
|
|
126
|
+
{:gemini1 gemini-behavior
|
|
127
|
+
:gemini2 gemini-behavior
|
|
128
|
+
:gemini3 gemini-behavior}))
|
|
129
|
+
|
|
130
|
+
(defn- gemini-alias?
|
|
131
|
+
[harness-kw]
|
|
132
|
+
(and (keyword? harness-kw)
|
|
133
|
+
(re-matches #"^gemini\\d+$" (name harness-kw))))
|
|
134
|
+
|
|
135
|
+
(defn valid-harness?
|
|
136
|
+
"True for explicit registry entries and any `geminiNN` alias."
|
|
137
|
+
[harness-kw]
|
|
138
|
+
(or (contains? (set (keys registry)) harness-kw)
|
|
139
|
+
(gemini-alias? harness-kw)))
|
|
98
140
|
|
|
99
141
|
;; =============================================================================
|
|
100
142
|
;; Registry Access
|
|
@@ -104,6 +146,7 @@
|
|
|
104
146
|
"Look up harness config. Throws on unknown harness (no silent fallback)."
|
|
105
147
|
[harness-kw]
|
|
106
148
|
(or (get registry harness-kw)
|
|
149
|
+
(when (gemini-alias? harness-kw) gemini-behavior)
|
|
107
150
|
(throw (ex-info (str "Unknown harness: " harness-kw
|
|
108
151
|
". Known: " (str/join ", " (map name (keys registry))))
|
|
109
152
|
{:harness harness-kw}))))
|
|
@@ -131,11 +174,7 @@
|
|
|
131
174
|
|
|
132
175
|
(defn build-cmd
|
|
133
176
|
"Build CLI command vector via agent-cli JSON input.
|
|
134
|
-
|
|
135
|
-
and resolves the binary to an absolute path.
|
|
136
|
-
|
|
137
|
-
agent-cli owns all CLI flag syntax (session create/resume, model decomposition,
|
|
138
|
-
bypass flags, prompt delivery). This function just maps oompa opts to JSON."
|
|
177
|
+
Used for probe/debug flows. Execution should prefer `run-command!`."
|
|
139
178
|
[harness-kw opts]
|
|
140
179
|
(let [input (-> {:harness (name harness-kw)
|
|
141
180
|
:bypassPermissions true}
|
|
@@ -165,6 +204,26 @@
|
|
|
165
204
|
:prompt prompt
|
|
166
205
|
:close "")))
|
|
167
206
|
|
|
207
|
+
(defn run-command!
|
|
208
|
+
"Execute a harness through `agent-cli run`, which emits unified JSONL events."
|
|
209
|
+
[harness-kw opts]
|
|
210
|
+
(let [input (-> {:harness (name harness-kw)
|
|
211
|
+
:mode "conversation"
|
|
212
|
+
:prompt (:prompt opts)
|
|
213
|
+
:cwd (:cwd opts)
|
|
214
|
+
:yolo true}
|
|
215
|
+
(cond->
|
|
216
|
+
(:model opts) (assoc :model (:model opts))
|
|
217
|
+
(and (:session-id opts) (not (:resume? opts))) (assoc :sessionId (:session-id opts))
|
|
218
|
+
(and (:session-id opts) (:resume? opts)) (assoc :resumeSessionId (:session-id opts))
|
|
219
|
+
(:reasoning opts) (assoc :reasoningEffort (:reasoning opts))
|
|
220
|
+
(or (= harness-kw :gemini) (gemini-alias? harness-kw))
|
|
221
|
+
(assoc :debugRawEvents true))
|
|
222
|
+
(add-extra-args harness-kw opts)
|
|
223
|
+
json/generate-string)]
|
|
224
|
+
(process/sh ["agent-cli" "run" "--input" "-"]
|
|
225
|
+
{:in input :out :string :err :string})))
|
|
226
|
+
|
|
168
227
|
;; =============================================================================
|
|
169
228
|
;; Session Management
|
|
170
229
|
;; =============================================================================
|
|
@@ -184,17 +243,14 @@
|
|
|
184
243
|
;; =============================================================================
|
|
185
244
|
|
|
186
245
|
(defn parse-output
|
|
187
|
-
"Parse
|
|
188
|
-
For :plain, returns output as-is.
|
|
246
|
+
"Parse unified JSONL output from `agent-cli run`.
|
|
189
247
|
Returns {:output string, :session-id string}."
|
|
190
248
|
[harness-kw raw-output session-id]
|
|
191
|
-
(let [
|
|
192
|
-
(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
{:output raw-output
|
|
197
|
-
:session-id session-id})))
|
|
249
|
+
(let [parsed (parse-unified-jsonl-output raw-output)]
|
|
250
|
+
{:output (or (:text parsed) raw-output)
|
|
251
|
+
:session-id (or (:session-id parsed) session-id)
|
|
252
|
+
:warning (:warning parsed)
|
|
253
|
+
:raw-snippet (:raw-snippet parsed)}))
|
|
198
254
|
|
|
199
255
|
;; =============================================================================
|
|
200
256
|
;; Probe / Health Check — delegates to agent-cli check
|
|
@@ -66,8 +66,10 @@
|
|
|
66
66
|
:workers (mapv (fn [w]
|
|
67
67
|
{:id (:id w)
|
|
68
68
|
:harness (name (:harness w))
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
:model (:model w)
|
|
70
|
+
:reasoning (:reasoning w)
|
|
71
|
+
:runs (:runs w)
|
|
72
|
+
:max-cycles (:max-cycles w)
|
|
71
73
|
:iterations (:iterations w)
|
|
72
74
|
:can-plan (:can-plan w)
|
|
73
75
|
:prompts (:prompts w)})
|
|
@@ -103,7 +105,7 @@
|
|
|
103
105
|
"Write a review log for one cycle of a worker.
|
|
104
106
|
Contains: verdict, round number, full reviewer output, diff file list."
|
|
105
107
|
[swarm-id worker-id cycle round
|
|
106
|
-
{:keys [verdict output diff-files]}]
|
|
108
|
+
{:keys [verdict output diff-files duration-ms]}]
|
|
107
109
|
(ensure-run-dirs! swarm-id)
|
|
108
110
|
(let [filename (format "%s-c%d-r%d.json" worker-id cycle round)]
|
|
109
111
|
(write-json! (str (reviews-dir swarm-id) "/" filename)
|
|
@@ -113,6 +115,7 @@
|
|
|
113
115
|
:verdict (name verdict)
|
|
114
116
|
:timestamp (str (java.time.Instant/now))
|
|
115
117
|
:output output
|
|
118
|
+
:duration-ms (or duration-ms 0)
|
|
116
119
|
:diff-files (vec diff-files)})))
|
|
117
120
|
|
|
118
121
|
;; =============================================================================
|
|
@@ -125,13 +128,14 @@
|
|
|
125
128
|
session-id links to the Claude CLI conversation on disk for debugging.
|
|
126
129
|
Written at cycle end so dashboards can track progress in real-time."
|
|
127
130
|
[swarm-id worker-id cycle
|
|
128
|
-
{:keys [outcome duration-ms claimed-task-ids recycled-tasks
|
|
129
|
-
error-snippet review-rounds session-id]}]
|
|
131
|
+
{:keys [run outcome duration-ms claimed-task-ids recycled-tasks
|
|
132
|
+
error-snippet review-rounds session-id timing-ms]}]
|
|
130
133
|
(when swarm-id
|
|
131
134
|
(let [filename (format "%s-c%d.json" worker-id cycle)]
|
|
132
135
|
(write-json! (str (cycles-dir swarm-id) "/" filename)
|
|
133
136
|
{:worker-id worker-id
|
|
134
137
|
:cycle cycle
|
|
138
|
+
:run (or run 1)
|
|
135
139
|
:outcome (name outcome)
|
|
136
140
|
:timestamp (str (java.time.Instant/now))
|
|
137
141
|
:duration-ms duration-ms
|
|
@@ -139,7 +143,8 @@
|
|
|
139
143
|
:recycled-tasks (or recycled-tasks [])
|
|
140
144
|
:error-snippet error-snippet
|
|
141
145
|
:review-rounds (or review-rounds 0)
|
|
142
|
-
:session-id session-id
|
|
146
|
+
:session-id session-id
|
|
147
|
+
:timing-ms timing-ms}))))
|
|
143
148
|
|
|
144
149
|
;; =============================================================================
|
|
145
150
|
;; Read helpers (for cmd-status, dashboards)
|
|
@@ -48,7 +48,14 @@
|
|
|
48
48
|
(def merge-strategies #{:fast-forward :no-ff :squash :rebase})
|
|
49
49
|
(def conflict-resolutions #{:ours :theirs :manual :abort})
|
|
50
50
|
|
|
51
|
-
(defn
|
|
51
|
+
(defn- gemini-indexed-account?
|
|
52
|
+
[x]
|
|
53
|
+
(and (keyword? x)
|
|
54
|
+
(re-matches #"^gemini\d+$" (name x))))
|
|
55
|
+
|
|
56
|
+
(defn agent-type? [x]
|
|
57
|
+
(or (contains? agent-types x)
|
|
58
|
+
(gemini-indexed-account? x)))
|
|
52
59
|
(defn agent-role? [x] (contains? agent-roles x))
|
|
53
60
|
(defn task-status? [x] (contains? task-statuses x))
|
|
54
61
|
(defn worktree-status? [x] (contains? worktree-statuses x))
|
|
@@ -210,6 +210,12 @@
|
|
|
210
210
|
(unclaim-task! task))
|
|
211
211
|
(mapv :id to-recycle)))
|
|
212
212
|
|
|
213
|
+
(defn recycle-all-current!
|
|
214
|
+
"Move every task from current/ back to pending/.
|
|
215
|
+
Returns vector of recycled task IDs."
|
|
216
|
+
[]
|
|
217
|
+
(recycle-tasks! (current-task-ids)))
|
|
218
|
+
|
|
213
219
|
(defn all-complete?
|
|
214
220
|
"True if no pending or current tasks"
|
|
215
221
|
[]
|