codeer-cli 0.1.13__tar.gz → 0.1.15__tar.gz
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.
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/API_REFERENCE.md +34 -14
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/PKG-INFO +86 -6
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/README.md +85 -5
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/pyproject.toml +1 -1
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/cli.py +3 -1
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/eval_cmd.py +52 -5
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/history.py +46 -9
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/kb.py +400 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/eval_.py +18 -2
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/histories.py +93 -11
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/kb.py +0 -1
- codeer_cli-0.1.15/tests/test_eval_evaluators.py +230 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_eval_pairs.py +5 -2
- codeer_cli-0.1.15/tests/test_history_read.py +299 -0
- codeer_cli-0.1.15/tests/test_kb_export.py +185 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_kb_nodes.py +24 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/uv.lock +1 -1
- codeer_cli-0.1.13/tests/test_history_read.py +0 -132
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/.gitignore +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/__init__.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/_validate.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/agents.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/chats.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/client.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/__init__.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/_util.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/agent.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/check.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/model.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/commands/profile.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/constants.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/models.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/src/codeer_cli/parse.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_agent_handoff.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_agent_model_settings.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_chats_v2.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_client_transport.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_eval_labels.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_history_send.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_kb_ranges.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_models.py +0 -0
- {codeer_cli-0.1.13 → codeer_cli-0.1.15}/tests/test_util.py +0 -0
|
@@ -84,6 +84,20 @@ Base path: `/organizations/{org_id}/workspaces/{ws_id}/knowledge_bases`
|
|
|
84
84
|
| `POST .../files/status` | Batch-poll indexing status by node ID |
|
|
85
85
|
| `GET .../{kb_id}/nodes/{node_id}/content` | Read a file's extracted content |
|
|
86
86
|
|
|
87
|
+
The workspace API-key external routes used by `codeer-cli` include:
|
|
88
|
+
|
|
89
|
+
| Method & path | Purpose |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| `GET /external/knowledge-bases/nodes?parent_id={node_id}` | List KB roots or direct children |
|
|
92
|
+
| `GET /external/knowledge-bases/files/{node_id}/content` | Read one file's extracted snapshot content |
|
|
93
|
+
|
|
94
|
+
`codeer kb export --node-id <file-id> --file <path>` maps directly to the second
|
|
95
|
+
route. `codeer kb export --node-id <folder-id> --dir <path>` recursively follows
|
|
96
|
+
the first route and calls the second route for every file. Any returned text is
|
|
97
|
+
written as UTF-8 Markdown regardless of indexing status, with that status
|
|
98
|
+
preserved in the manifest. A `null` content response cannot be exported. The
|
|
99
|
+
command does not reconstruct the originally uploaded binary file.
|
|
100
|
+
|
|
87
101
|
Attach KB files to an agent by listing their node IDs in the agent's
|
|
88
102
|
`unified_tools[].knowledge_node_ids`.
|
|
89
103
|
|
|
@@ -187,8 +201,8 @@ version; it does not currently replace this draft-pinning path.
|
|
|
187
201
|
| `GET /eval/evaluators?wid=<ws>` | List evaluators |
|
|
188
202
|
| `PUT /eval/evaluators/{id}` | Update |
|
|
189
203
|
| `DELETE /eval/evaluators/{id}` | Delete |
|
|
190
|
-
| `POST /eval/case-evaluator-infos:batch` | Read assigned evaluators/rubrics for cases |
|
|
191
|
-
| `PUT /eval/cases/{case_id}/case-evaluator-infos` | Replace assigned evaluators/rubrics for one case |
|
|
204
|
+
| `POST /external/eval/case-evaluator-infos:batch` | Read assigned evaluators/rubrics for cases through the API-key facade |
|
|
205
|
+
| `PUT /external/eval/cases/{case_id}/case-evaluator-infos` | Replace assigned evaluators/rubrics for one case through the API-key facade |
|
|
192
206
|
| `POST /eval/trigger` | Run explicit assigned `case_evaluator_pairs` pinned to `agent_history_id` |
|
|
193
207
|
| `POST /eval/stop` | Cancel running case+evaluator combo |
|
|
194
208
|
| `POST /eval/rubric` | Set/override the rubric for one (case, evaluator); also creates assignment |
|
|
@@ -275,12 +289,12 @@ the public CLI.
|
|
|
275
289
|
| --- | --- |
|
|
276
290
|
| `POST /api/v2/chats` | Create a persisted history using an agent's current published version |
|
|
277
291
|
| `POST /api/v2/chats/{id}/messages` | Append a turn through structured SSE using the current published version |
|
|
278
|
-
| `GET /api/
|
|
279
|
-
| `GET /
|
|
280
|
-
| `GET /histories
|
|
281
|
-
| `GET /histories/{id}
|
|
282
|
-
| `
|
|
283
|
-
| `POST /histories/{hid}/conversations/{cid}/
|
|
292
|
+
| `GET /api/v1/external/histories/{id}/messages` | Export persisted diagnostic parts for workspace editors (`history-parts-v1`) |
|
|
293
|
+
| `GET /api/v2/chats/{id}/messages` | Read client-visible parts under the external client-owner contract |
|
|
294
|
+
| `GET /api/v1/external/histories?agent_id=X&feedback_filter=improve_feedback&external_user_id=…` | List conversations with filters |
|
|
295
|
+
| `GET /api/v1/external/histories/{id}` | Read one history's metadata |
|
|
296
|
+
| `GET /api/v1/external/histories/{id}/conversations` | Legacy compact conversation rows; not complete tool I/O |
|
|
297
|
+
| `POST /api/v1/external/histories/{hid}/conversations/{cid}/feedbacks` | Leave freeform improvement feedback |
|
|
284
298
|
|
|
285
299
|
The CLI exposes the first two operations as `codeer history create` and
|
|
286
300
|
`codeer history send`. Messages explicitly set `stream: true`, consume Chat V2
|
|
@@ -289,6 +303,11 @@ per-message SSE read timeout defaults to 240 seconds. A timeout,
|
|
|
289
303
|
`response.failed`, or disconnect before completion has an uncertain write
|
|
290
304
|
outcome, so read the history before retrying to avoid duplicate turns.
|
|
291
305
|
|
|
306
|
+
`codeer history conversations` uses the management export by default. Pass
|
|
307
|
+
`--client-visible --user <external-user-id>` only to select the external Chat
|
|
308
|
+
V2 read contract explicitly. The management export includes persisted tool
|
|
309
|
+
calls/results but excludes system prompts and provider raw traces.
|
|
310
|
+
|
|
292
311
|
`feedback_filter` accepts the `FeedbackFilterType` enum values:
|
|
293
312
|
`no_feedback`, `with_feedback`, `helpful_feedback`, `improve_feedback`.
|
|
294
313
|
|
|
@@ -491,12 +510,13 @@ you can and can't recover from each assistant turn:
|
|
|
491
510
|
| Tool **outputs** (raw JSON returned by the tool) | same — stored only as derived `primary_sources` for retrieval tools |
|
|
492
511
|
| Reasoning steps mid-turn | `meta.reasoning_steps` is currently always `null` |
|
|
493
512
|
|
|
494
|
-
|
|
495
|
-
`response.part.created` / `response.part.completed`, and
|
|
496
|
-
`GET /api/
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
history read remains useful for compact
|
|
513
|
+
Native parts improve this contract: structured SSE emits tool calls and returns
|
|
514
|
+
as `response.part.created` / `response.part.completed`, and the management
|
|
515
|
+
`GET /api/v1/external/histories/{id}/messages` export reads persisted
|
|
516
|
+
after-the-fact tool I/O for workspace editors. The client-owner
|
|
517
|
+
`GET /api/v2/chats/{id}/messages` route remains available for explicitly
|
|
518
|
+
client-visible reads. The legacy V1 history read remains useful for compact
|
|
519
|
+
turn-level compatibility only.
|
|
500
520
|
|
|
501
521
|
### 10. A KB has exactly ONE level of folders — no nesting
|
|
502
522
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: codeer-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: Command line tools for managing Codeer agents over the Codeer API.
|
|
5
5
|
Project-URL: Homepage, https://www.codeer.ai
|
|
6
6
|
Author: Codeer.AI
|
|
@@ -98,7 +98,8 @@ CODEER_AGENT_ID=<agent-id>
|
|
|
98
98
|
|
|
99
99
|
## Development install
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Codeer contributors should use an editable install from this checkout, not the
|
|
102
|
+
PyPI package, so the `codeer` command always executes the folder being edited:
|
|
102
103
|
|
|
103
104
|
```bash
|
|
104
105
|
cd /path/to/codeer-skills/codeer-cli
|
|
@@ -123,6 +124,34 @@ List the active cloud models without opening the Codeer web app:
|
|
|
123
124
|
codeer model list --type text
|
|
124
125
|
```
|
|
125
126
|
|
|
127
|
+
## Custom evaluator judge models
|
|
128
|
+
|
|
129
|
+
Custom evaluator create/update commands can select a judge LLM model by ID:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
codeer eval evaluator-create \
|
|
133
|
+
--name "Correctness" \
|
|
134
|
+
--system-prompt-template-file evaluator-prompt.txt \
|
|
135
|
+
--judge-model <model-id> \
|
|
136
|
+
--dry-run
|
|
137
|
+
|
|
138
|
+
codeer eval evaluator-update \
|
|
139
|
+
--evaluator <evaluator-id> \
|
|
140
|
+
--judge-model <model-id> \
|
|
141
|
+
--dry-run
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Omit the judge-model flags on update to leave the current setting unchanged.
|
|
145
|
+
Use `--clear-judge-model` to explicitly clear the override and return to the
|
|
146
|
+
system default:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
codeer eval evaluator-update \
|
|
150
|
+
--evaluator <evaluator-id> \
|
|
151
|
+
--clear-judge-model \
|
|
152
|
+
--dry-run
|
|
153
|
+
```
|
|
154
|
+
|
|
126
155
|
## Agent human handoff
|
|
127
156
|
|
|
128
157
|
`codeer agent apply` accepts the same `human_handoff` object as the Agent API.
|
|
@@ -197,10 +226,22 @@ Flags:
|
|
|
197
226
|
for raw eval results, full conversation turns, full rubric matrices, and
|
|
198
227
|
other data that can grow with cases, versions, or turns.
|
|
199
228
|
|
|
200
|
-
`history conversations`
|
|
201
|
-
automatically. Its stdout is
|
|
202
|
-
the
|
|
203
|
-
|
|
229
|
+
`history conversations` defaults to the workspace-editor management export and
|
|
230
|
+
follows all pages automatically. Its stdout is a bounded summary that never
|
|
231
|
+
prints tool arguments or results; the `--out` artifact preserves the complete
|
|
232
|
+
`history-parts-v1` payload, including persisted tool calls/results,
|
|
233
|
+
attachments, feedback, and metadata. System prompts and provider raw traces are
|
|
234
|
+
not part of that export contract, and a missing part does not prove that a tool
|
|
235
|
+
was not executed.
|
|
236
|
+
|
|
237
|
+
Use the external client-owner contract only when that distinction is the point
|
|
238
|
+
of the test:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
codeer history conversations <history-id> \
|
|
242
|
+
--client-visible --user <external-user-id> \
|
|
243
|
+
--out .codeer/current/client-history-<history-id>.json
|
|
244
|
+
```
|
|
204
245
|
|
|
205
246
|
Avoid piping large raw JSON directly into agent chat. Prefer `--out`, then ask
|
|
206
247
|
the coding agent to inspect targeted summaries, IDs, failing cases, or selected
|
|
@@ -228,6 +269,45 @@ paths containing `*` so the shell passes the wildcard to the CLI. Advanced
|
|
|
228
269
|
settings can still be passed through `--config-json`; explicit crawler flags
|
|
229
270
|
override matching JSON keys.
|
|
230
271
|
|
|
272
|
+
## Exporting KB snapshot content
|
|
273
|
+
|
|
274
|
+
Export one file directly from the content endpoint:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
codeer kb export \
|
|
278
|
+
--node-id <file-node-id> \
|
|
279
|
+
--file guide.md
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Or recursively export a folder or an entire KB root:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
codeer kb export \
|
|
286
|
+
--node-id <folder-or-kb-root-node-id> \
|
|
287
|
+
--dir kb-export \
|
|
288
|
+
--out kb-export-manifest.json
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`--file` and `--dir` are mutually exclusive. Single-file mode maps directly to
|
|
292
|
+
the external file-content endpoint and lets the caller choose the exact local
|
|
293
|
+
path. Folder mode recursively lists the node tree, calls that endpoint for each
|
|
294
|
+
file, and writes the extracted snapshot content as UTF-8 Markdown. Existing
|
|
295
|
+
`.md`/`.markdown` names are preserved; other folder-export names receive an
|
|
296
|
+
additional `.md` suffix (for example, `guide.pdf` becomes `guide.pdf.md`) so the
|
|
297
|
+
export is not mistaken for the original binary upload.
|
|
298
|
+
|
|
299
|
+
The command asks the content endpoint for every file regardless of indexing
|
|
300
|
+
status. If the endpoint returns text, it is exported even when the status is
|
|
301
|
+
not `READY`; the full manifest preserves that server status and marks the file
|
|
302
|
+
as `exported_while_not_ready`. If the endpoint returns `content: null`, the file
|
|
303
|
+
is skipped and the command exits non-zero. Existing target files block the
|
|
304
|
+
entire export before any content is written; pass `--overwrite` only when
|
|
305
|
+
replacing those local files is intended.
|
|
306
|
+
|
|
307
|
+
This is a snapshot-content export, not an original-file backup. The server API
|
|
308
|
+
returns processed text and does not return the original PDF, DOCX, or other
|
|
309
|
+
binary bytes through this endpoint.
|
|
310
|
+
|
|
231
311
|
## KB node rename and delete
|
|
232
312
|
|
|
233
313
|
Knowledge Base roots, folders, and files are all KnowledgeNodes. Use
|
|
@@ -80,7 +80,8 @@ CODEER_AGENT_ID=<agent-id>
|
|
|
80
80
|
|
|
81
81
|
## Development install
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
Codeer contributors should use an editable install from this checkout, not the
|
|
84
|
+
PyPI package, so the `codeer` command always executes the folder being edited:
|
|
84
85
|
|
|
85
86
|
```bash
|
|
86
87
|
cd /path/to/codeer-skills/codeer-cli
|
|
@@ -105,6 +106,34 @@ List the active cloud models without opening the Codeer web app:
|
|
|
105
106
|
codeer model list --type text
|
|
106
107
|
```
|
|
107
108
|
|
|
109
|
+
## Custom evaluator judge models
|
|
110
|
+
|
|
111
|
+
Custom evaluator create/update commands can select a judge LLM model by ID:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
codeer eval evaluator-create \
|
|
115
|
+
--name "Correctness" \
|
|
116
|
+
--system-prompt-template-file evaluator-prompt.txt \
|
|
117
|
+
--judge-model <model-id> \
|
|
118
|
+
--dry-run
|
|
119
|
+
|
|
120
|
+
codeer eval evaluator-update \
|
|
121
|
+
--evaluator <evaluator-id> \
|
|
122
|
+
--judge-model <model-id> \
|
|
123
|
+
--dry-run
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Omit the judge-model flags on update to leave the current setting unchanged.
|
|
127
|
+
Use `--clear-judge-model` to explicitly clear the override and return to the
|
|
128
|
+
system default:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
codeer eval evaluator-update \
|
|
132
|
+
--evaluator <evaluator-id> \
|
|
133
|
+
--clear-judge-model \
|
|
134
|
+
--dry-run
|
|
135
|
+
```
|
|
136
|
+
|
|
108
137
|
## Agent human handoff
|
|
109
138
|
|
|
110
139
|
`codeer agent apply` accepts the same `human_handoff` object as the Agent API.
|
|
@@ -179,10 +208,22 @@ Flags:
|
|
|
179
208
|
for raw eval results, full conversation turns, full rubric matrices, and
|
|
180
209
|
other data that can grow with cases, versions, or turns.
|
|
181
210
|
|
|
182
|
-
`history conversations`
|
|
183
|
-
automatically. Its stdout is
|
|
184
|
-
the
|
|
185
|
-
|
|
211
|
+
`history conversations` defaults to the workspace-editor management export and
|
|
212
|
+
follows all pages automatically. Its stdout is a bounded summary that never
|
|
213
|
+
prints tool arguments or results; the `--out` artifact preserves the complete
|
|
214
|
+
`history-parts-v1` payload, including persisted tool calls/results,
|
|
215
|
+
attachments, feedback, and metadata. System prompts and provider raw traces are
|
|
216
|
+
not part of that export contract, and a missing part does not prove that a tool
|
|
217
|
+
was not executed.
|
|
218
|
+
|
|
219
|
+
Use the external client-owner contract only when that distinction is the point
|
|
220
|
+
of the test:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
codeer history conversations <history-id> \
|
|
224
|
+
--client-visible --user <external-user-id> \
|
|
225
|
+
--out .codeer/current/client-history-<history-id>.json
|
|
226
|
+
```
|
|
186
227
|
|
|
187
228
|
Avoid piping large raw JSON directly into agent chat. Prefer `--out`, then ask
|
|
188
229
|
the coding agent to inspect targeted summaries, IDs, failing cases, or selected
|
|
@@ -210,6 +251,45 @@ paths containing `*` so the shell passes the wildcard to the CLI. Advanced
|
|
|
210
251
|
settings can still be passed through `--config-json`; explicit crawler flags
|
|
211
252
|
override matching JSON keys.
|
|
212
253
|
|
|
254
|
+
## Exporting KB snapshot content
|
|
255
|
+
|
|
256
|
+
Export one file directly from the content endpoint:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
codeer kb export \
|
|
260
|
+
--node-id <file-node-id> \
|
|
261
|
+
--file guide.md
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Or recursively export a folder or an entire KB root:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
codeer kb export \
|
|
268
|
+
--node-id <folder-or-kb-root-node-id> \
|
|
269
|
+
--dir kb-export \
|
|
270
|
+
--out kb-export-manifest.json
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`--file` and `--dir` are mutually exclusive. Single-file mode maps directly to
|
|
274
|
+
the external file-content endpoint and lets the caller choose the exact local
|
|
275
|
+
path. Folder mode recursively lists the node tree, calls that endpoint for each
|
|
276
|
+
file, and writes the extracted snapshot content as UTF-8 Markdown. Existing
|
|
277
|
+
`.md`/`.markdown` names are preserved; other folder-export names receive an
|
|
278
|
+
additional `.md` suffix (for example, `guide.pdf` becomes `guide.pdf.md`) so the
|
|
279
|
+
export is not mistaken for the original binary upload.
|
|
280
|
+
|
|
281
|
+
The command asks the content endpoint for every file regardless of indexing
|
|
282
|
+
status. If the endpoint returns text, it is exported even when the status is
|
|
283
|
+
not `READY`; the full manifest preserves that server status and marks the file
|
|
284
|
+
as `exported_while_not_ready`. If the endpoint returns `content: null`, the file
|
|
285
|
+
is skipped and the command exits non-zero. Existing target files block the
|
|
286
|
+
entire export before any content is written; pass `--overwrite` only when
|
|
287
|
+
replacing those local files is intended.
|
|
288
|
+
|
|
289
|
+
This is a snapshot-content export, not an original-file backup. The server API
|
|
290
|
+
returns processed text and does not return the original PDF, DOCX, or other
|
|
291
|
+
binary bytes through this endpoint.
|
|
292
|
+
|
|
213
293
|
## KB node rename and delete
|
|
214
294
|
|
|
215
295
|
Knowledge Base roots, folders, and files are all KnowledgeNodes. Use
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
codeer check
|
|
4
4
|
codeer agent list|get|apply|diff|versions
|
|
5
5
|
codeer model list
|
|
6
|
-
codeer kb list|files|upload|node-rename|node-delete|faq-list|faq-get|faq-create|faq-update|faq-delete
|
|
6
|
+
codeer kb list|files|export|upload|node-rename|node-delete|faq-list|faq-get|faq-create|faq-update|faq-delete
|
|
7
7
|
codeer eval list|label-list|label-create|label-update|label-delete|case-update|case-delete|evaluators|evaluator-create|evaluator-update|run|export|reconcile|cases-apply|rubrics|rubrics-apply
|
|
8
8
|
codeer history list|get|conversations|negative-feedback|create|send
|
|
9
9
|
"""
|
|
@@ -31,6 +31,8 @@ Safe workflow for coding agents:
|
|
|
31
31
|
codeer agent get <agent-id> --full
|
|
32
32
|
codeer kb list
|
|
33
33
|
codeer kb files --kb-id <kb-id>
|
|
34
|
+
codeer kb export --node-id <file-id> --file guide.md
|
|
35
|
+
codeer kb export --node-id <folder-id> --dir kb-export
|
|
34
36
|
codeer eval list --agent <agent-id>
|
|
35
37
|
codeer eval label-list
|
|
36
38
|
codeer eval case-update --case <case-id> --input "..." --dry-run
|
|
@@ -128,6 +128,12 @@ def register(subparsers):
|
|
|
128
128
|
g.add_argument("--system-prompt-template", help="Evaluator system prompt template text")
|
|
129
129
|
g.add_argument("--system-prompt-template-file", help="Path to evaluator system prompt template")
|
|
130
130
|
p.add_argument("--description", default=None)
|
|
131
|
+
p.add_argument(
|
|
132
|
+
"--judge-model",
|
|
133
|
+
default=None,
|
|
134
|
+
metavar="MODEL_ID",
|
|
135
|
+
help="Judge LLM model ID (default: system default)",
|
|
136
|
+
)
|
|
131
137
|
p.add_argument("--dry-run", action="store_true",
|
|
132
138
|
help="Validate inputs and print intended mutation without writing server state.")
|
|
133
139
|
p.set_defaults(func=run_evaluator_create)
|
|
@@ -140,6 +146,18 @@ def register(subparsers):
|
|
|
140
146
|
g.add_argument("--system-prompt-template", help="Evaluator system prompt template text")
|
|
141
147
|
g.add_argument("--system-prompt-template-file", help="Path to evaluator system prompt template")
|
|
142
148
|
p.add_argument("--description", default=None)
|
|
149
|
+
g = p.add_mutually_exclusive_group()
|
|
150
|
+
g.add_argument(
|
|
151
|
+
"--judge-model",
|
|
152
|
+
default=None,
|
|
153
|
+
metavar="MODEL_ID",
|
|
154
|
+
help="Set the judge LLM model ID",
|
|
155
|
+
)
|
|
156
|
+
g.add_argument(
|
|
157
|
+
"--clear-judge-model",
|
|
158
|
+
action="store_true",
|
|
159
|
+
help="Clear the evaluator override and use the system default judge model",
|
|
160
|
+
)
|
|
143
161
|
p.add_argument("--dry-run", action="store_true",
|
|
144
162
|
help="Validate inputs and print intended mutation without writing server state.")
|
|
145
163
|
p.set_defaults(func=run_evaluator_update)
|
|
@@ -249,6 +267,7 @@ def _evaluator_summary(evaluator: dict, *, full: bool = False) -> dict:
|
|
|
249
267
|
"id": evaluator.get("id"),
|
|
250
268
|
"name": evaluator.get("name"),
|
|
251
269
|
"description": evaluator.get("description"),
|
|
270
|
+
"judge_llm_model_id": evaluator.get("judge_llm_model_id"),
|
|
252
271
|
"system_prompt_template_chars": len(template),
|
|
253
272
|
"has_tool_steps_placeholder": "{tool_steps}" in template,
|
|
254
273
|
"has_output_placeholder": "{output}" in template,
|
|
@@ -534,6 +553,10 @@ def run_evaluator_create(args, client) -> int:
|
|
|
534
553
|
"workspace_id": workspace_id,
|
|
535
554
|
"name": args.name,
|
|
536
555
|
"description": args.description,
|
|
556
|
+
"judge_model": {
|
|
557
|
+
"action": "set" if args.judge_model is not None else "use_system_default",
|
|
558
|
+
"model_id": args.judge_model,
|
|
559
|
+
},
|
|
537
560
|
"system_prompt_template_chars": len(system_prompt_template or ""),
|
|
538
561
|
"would_write_server_state": True,
|
|
539
562
|
"next_step": "Review this summary, then rerun without --dry-run after approval.",
|
|
@@ -545,6 +568,7 @@ def run_evaluator_create(args, client) -> int:
|
|
|
545
568
|
name=args.name,
|
|
546
569
|
system_prompt_template=system_prompt_template,
|
|
547
570
|
description=args.description,
|
|
571
|
+
judge_llm_model_id=args.judge_model,
|
|
548
572
|
)
|
|
549
573
|
print_json(_evaluator_summary(evaluator, full=True))
|
|
550
574
|
return 0
|
|
@@ -560,13 +584,27 @@ def run_evaluator_update(args, client) -> int:
|
|
|
560
584
|
else:
|
|
561
585
|
system_prompt_template = args.system_prompt_template
|
|
562
586
|
|
|
563
|
-
if
|
|
587
|
+
if (
|
|
588
|
+
args.name is None
|
|
589
|
+
and args.description is None
|
|
590
|
+
and system_prompt_template is None
|
|
591
|
+
and args.judge_model is None
|
|
592
|
+
and not args.clear_judge_model
|
|
593
|
+
):
|
|
564
594
|
log(
|
|
565
595
|
"error: provide at least one of --name, --description, "
|
|
566
|
-
"--system-prompt-template, --system-prompt-template-file"
|
|
596
|
+
"--system-prompt-template, --system-prompt-template-file, "
|
|
597
|
+
"--judge-model, --clear-judge-model"
|
|
567
598
|
)
|
|
568
599
|
return 2
|
|
569
600
|
|
|
601
|
+
if args.clear_judge_model:
|
|
602
|
+
judge_model = {"action": "clear_to_system_default", "model_id": None}
|
|
603
|
+
elif args.judge_model is not None:
|
|
604
|
+
judge_model = {"action": "set", "model_id": args.judge_model}
|
|
605
|
+
else:
|
|
606
|
+
judge_model = {"action": "unchanged"}
|
|
607
|
+
|
|
570
608
|
if args.dry_run:
|
|
571
609
|
print_json({
|
|
572
610
|
"dry_run": True,
|
|
@@ -574,6 +612,7 @@ def run_evaluator_update(args, client) -> int:
|
|
|
574
612
|
"evaluator_id": args.evaluator,
|
|
575
613
|
"name": args.name,
|
|
576
614
|
"description": args.description,
|
|
615
|
+
"judge_model": judge_model,
|
|
577
616
|
"system_prompt_template_chars": (
|
|
578
617
|
len(system_prompt_template) if system_prompt_template is not None else None
|
|
579
618
|
),
|
|
@@ -582,12 +621,20 @@ def run_evaluator_update(args, client) -> int:
|
|
|
582
621
|
})
|
|
583
622
|
return 0
|
|
584
623
|
|
|
624
|
+
evaluator_kwargs: dict[str, Any] = {
|
|
625
|
+
"name": args.name,
|
|
626
|
+
"system_prompt_template": system_prompt_template,
|
|
627
|
+
"description": args.description,
|
|
628
|
+
}
|
|
629
|
+
if args.clear_judge_model:
|
|
630
|
+
evaluator_kwargs["judge_llm_model_id"] = None
|
|
631
|
+
elif args.judge_model is not None:
|
|
632
|
+
evaluator_kwargs["judge_llm_model_id"] = args.judge_model
|
|
633
|
+
|
|
585
634
|
evaluator = eval_mod.update_evaluator(
|
|
586
635
|
client,
|
|
587
636
|
evaluator_id=args.evaluator,
|
|
588
|
-
|
|
589
|
-
system_prompt_template=system_prompt_template,
|
|
590
|
-
description=args.description,
|
|
637
|
+
**evaluator_kwargs,
|
|
591
638
|
)
|
|
592
639
|
print_json(_evaluator_summary(evaluator, full=True))
|
|
593
640
|
return 0
|
|
@@ -48,13 +48,17 @@ def register(subparsers):
|
|
|
48
48
|
# codeer history conversations <id>
|
|
49
49
|
p = sub.add_parser(
|
|
50
50
|
"conversations",
|
|
51
|
-
help="Summarize
|
|
51
|
+
help="Summarize persisted History parts. Complete parts/tool payloads require --out.",
|
|
52
52
|
)
|
|
53
53
|
p.add_argument("history_id", type=int)
|
|
54
54
|
p.add_argument("--full", action="store_true",
|
|
55
55
|
help="Require --out and include longer stdout previews; the artifact is always complete.")
|
|
56
56
|
p.add_argument("--out", default=None,
|
|
57
|
-
help="Write every
|
|
57
|
+
help="Write every persisted part allowed by the selected export contract.")
|
|
58
|
+
p.add_argument("--client-visible", action="store_true",
|
|
59
|
+
help="Use the external client-owner Chat V2 contract instead of the management export.")
|
|
60
|
+
p.add_argument("--user", default=None,
|
|
61
|
+
help="external_user_id required with --client-visible.")
|
|
58
62
|
p.set_defaults(func=run_conversations)
|
|
59
63
|
|
|
60
64
|
# codeer history negative-feedback
|
|
@@ -158,10 +162,12 @@ def _history_summary(row: dict, *, full: bool = False) -> dict:
|
|
|
158
162
|
|
|
159
163
|
def _part_summary(part: dict, idx: int, *, full: bool = False) -> dict:
|
|
160
164
|
raw_content = part.get("content")
|
|
161
|
-
|
|
165
|
+
part_kind = part.get("part_kind")
|
|
166
|
+
is_tool_part = part_kind in {"tool-call", "tool-return"}
|
|
167
|
+
if is_tool_part:
|
|
168
|
+
content_value = None
|
|
169
|
+
elif isinstance(raw_content, dict):
|
|
162
170
|
content_value = raw_content.get("content")
|
|
163
|
-
if content_value is None and part.get("part_kind") == "tool-call":
|
|
164
|
-
content_value = raw_content.get("args")
|
|
165
171
|
else:
|
|
166
172
|
content_value = raw_content
|
|
167
173
|
if isinstance(content_value, str):
|
|
@@ -176,7 +182,7 @@ def _part_summary(part: dict, idx: int, *, full: bool = False) -> dict:
|
|
|
176
182
|
"conversation_id": part.get("conversation_id"),
|
|
177
183
|
"conversation_group_id": part.get("conversation_group_id"),
|
|
178
184
|
"sequence": part.get("sequence"),
|
|
179
|
-
"part_kind":
|
|
185
|
+
"part_kind": part_kind,
|
|
180
186
|
"source": part.get("source"),
|
|
181
187
|
"created_at": part.get("created_at"),
|
|
182
188
|
"content_preview": truncate(content, 600 if full else 240),
|
|
@@ -184,6 +190,12 @@ def _part_summary(part: dict, idx: int, *, full: bool = False) -> dict:
|
|
|
184
190
|
"attachment_count": len(part.get("attached_files") or []),
|
|
185
191
|
"feedback_count": len(part.get("feedbacks") or []),
|
|
186
192
|
}
|
|
193
|
+
if is_tool_part and isinstance(raw_content, dict):
|
|
194
|
+
row.update({
|
|
195
|
+
"tool_name": raw_content.get("tool_name"),
|
|
196
|
+
"tool_call_id": raw_content.get("tool_call_id"),
|
|
197
|
+
"outcome": raw_content.get("outcome"),
|
|
198
|
+
})
|
|
187
199
|
if full:
|
|
188
200
|
row["feedbacks"] = [
|
|
189
201
|
{
|
|
@@ -247,24 +259,49 @@ def run_get(args, client) -> int:
|
|
|
247
259
|
|
|
248
260
|
|
|
249
261
|
def run_conversations(args, client) -> int:
|
|
250
|
-
result = chats_mod.list_messages(client, args.history_id)
|
|
251
|
-
parts = result.get("messages") or []
|
|
252
262
|
if args.full and not args.out:
|
|
253
263
|
log("error: full conversation payloads are unbounded; pass --out <path>")
|
|
254
264
|
return 2
|
|
265
|
+
client_visible = bool(getattr(args, "client_visible", False))
|
|
266
|
+
external_user_id = getattr(args, "user", None)
|
|
267
|
+
if client_visible and not external_user_id:
|
|
268
|
+
log("error: --client-visible requires --user <external_user_id>")
|
|
269
|
+
return 2
|
|
270
|
+
if external_user_id and not client_visible:
|
|
271
|
+
log("error: --user is only valid with --client-visible")
|
|
272
|
+
return 2
|
|
273
|
+
|
|
274
|
+
if client_visible:
|
|
275
|
+
result = chats_mod.list_messages(
|
|
276
|
+
client,
|
|
277
|
+
args.history_id,
|
|
278
|
+
external_user_id=external_user_id,
|
|
279
|
+
)
|
|
280
|
+
export_mode = "client-visible"
|
|
281
|
+
else:
|
|
282
|
+
result = hist_mod.list_messages(client, args.history_id)
|
|
283
|
+
export_mode = "management"
|
|
284
|
+
parts = result.get("messages") or []
|
|
255
285
|
write_json(args.out, result)
|
|
256
286
|
group_ids = {
|
|
257
287
|
p.get("conversation_group_id")
|
|
258
288
|
for p in parts
|
|
259
289
|
if p.get("conversation_group_id")
|
|
260
290
|
}
|
|
291
|
+
stdout_limit = 50 if args.full else 20
|
|
292
|
+
shown_parts = parts[:stdout_limit]
|
|
261
293
|
print_json({
|
|
262
294
|
"history_id": args.history_id,
|
|
295
|
+
"export_mode": export_mode,
|
|
296
|
+
"export_contract": result.get("export_contract"),
|
|
297
|
+
"part_revision": result.get("part_revision"),
|
|
263
298
|
"turn_count": len(group_ids),
|
|
264
299
|
"part_count": len(parts),
|
|
300
|
+
"part_summaries_shown": len(shown_parts),
|
|
301
|
+
"part_summaries_truncated": len(parts) > len(shown_parts),
|
|
265
302
|
"wrote_full_detail": bool(args.out),
|
|
266
303
|
"stdout_is_summary": True,
|
|
267
|
-
"parts": [_part_summary(p, i, full=args.full) for i, p in enumerate(
|
|
304
|
+
"parts": [_part_summary(p, i, full=args.full) for i, p in enumerate(shown_parts)],
|
|
268
305
|
})
|
|
269
306
|
return 0
|
|
270
307
|
|