codeer-cli 0.1.0__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.0/.gitignore +36 -0
- codeer_cli-0.1.0/API_REFERENCE.md +431 -0
- codeer_cli-0.1.0/PKG-INFO +108 -0
- codeer_cli-0.1.0/README.md +90 -0
- codeer_cli-0.1.0/pyproject.toml +33 -0
- codeer_cli-0.1.0/src/codeer_cli/__init__.py +54 -0
- codeer_cli-0.1.0/src/codeer_cli/_validate.py +131 -0
- codeer_cli-0.1.0/src/codeer_cli/agents.py +155 -0
- codeer_cli-0.1.0/src/codeer_cli/chats.py +87 -0
- codeer_cli-0.1.0/src/codeer_cli/cli.py +92 -0
- codeer_cli-0.1.0/src/codeer_cli/client.py +277 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/__init__.py +0 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/_util.py +12 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/agent.py +186 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/check.py +66 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/eval_cmd.py +919 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/history.py +200 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/kb.py +126 -0
- codeer_cli-0.1.0/src/codeer_cli/commands/profile.py +205 -0
- codeer_cli-0.1.0/src/codeer_cli/constants.py +66 -0
- codeer_cli-0.1.0/src/codeer_cli/eval_.py +423 -0
- codeer_cli-0.1.0/src/codeer_cli/histories.py +156 -0
- codeer_cli-0.1.0/src/codeer_cli/kb.py +226 -0
- codeer_cli-0.1.0/src/codeer_cli/parse.py +567 -0
- codeer_cli-0.1.0/uv.lock +91 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Python bytecode and caches
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Python build and packaging output
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Test, type-checker, and linter caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
|
|
19
|
+
# Virtual environments and local environment files
|
|
20
|
+
.venv/
|
|
21
|
+
venv/
|
|
22
|
+
env/
|
|
23
|
+
.env
|
|
24
|
+
.env.*
|
|
25
|
+
!.env.example
|
|
26
|
+
!.env.sample
|
|
27
|
+
session.env
|
|
28
|
+
|
|
29
|
+
# OS and editor local files
|
|
30
|
+
.DS_Store
|
|
31
|
+
Thumbs.db
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
|
|
35
|
+
# Local assistant/tool settings
|
|
36
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# Codeer API reference — CLI maintainers
|
|
2
|
+
|
|
3
|
+
> This file is the request-shape reference for maintaining `codeer-cli`.
|
|
4
|
+
|
|
5
|
+
The 9 stages below mirror the user-docs lifecycle (`agent-creation` →
|
|
6
|
+
`optimization-loop` → `publish`). Every path is under `/api/v1/`. All endpoints
|
|
7
|
+
authenticate via `x-api-key` from `CODEER_API_KEY`.
|
|
8
|
+
|
|
9
|
+
Envelope: successful responses look like
|
|
10
|
+
`{"error_code": 0, "message": "", "pagination": null, "data": <payload>}`.
|
|
11
|
+
The client unwraps `data` automatically; errors raise `CodeerError`.
|
|
12
|
+
|
|
13
|
+
**Environment config split:**
|
|
14
|
+
Auth means `CODEER_API_KEY`; it comes from the process environment only.
|
|
15
|
+
`CODEER_API_BASE` defaults to `https://api.codeer.ai` and is only needed for
|
|
16
|
+
local, beta, or preview. Do not store API keys in repo files or paste them into
|
|
17
|
+
agent chat.
|
|
18
|
+
|
|
19
|
+
Workspace and organization scope come from the workspace API-key virtual user's
|
|
20
|
+
profile (`default_workspace_id` and `default_organization_id`). The CLI does
|
|
21
|
+
not use `--workspace`, `--org`, `CODEER_WORKSPACE_ID`, or
|
|
22
|
+
`CODEER_ORGANIZATION_ID`. `CODEER_AGENT_ID` is still optional for commands that
|
|
23
|
+
need a default agent.
|
|
24
|
+
|
|
25
|
+
**Pagination conventions:**
|
|
26
|
+
- `/histories` uses **`limit` + `offset`** (NOT `page` / `page_size`).
|
|
27
|
+
Default in `histories.list()` is `limit=500`. Backend hard-cap may be
|
|
28
|
+
lower — check the response length.
|
|
29
|
+
- `/agents/{id}/histories`, `/eval/agents/{id}/cases`, `/eval/evaluators` all
|
|
30
|
+
return everything in one shot today (no pagination).
|
|
31
|
+
- `order_by` defaults to `"desc"` (most recent first) on endpoints that
|
|
32
|
+
support it.
|
|
33
|
+
|
|
34
|
+
## Stage 1 — Author agent
|
|
35
|
+
|
|
36
|
+
| Method & path | Purpose |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `POST /agents` | Create a new agent |
|
|
39
|
+
| `GET /agents?wid=<ws>` | List agents in a workspace |
|
|
40
|
+
| `GET /agents/all?wid=<ws>` or `?oid=<org>` | List across workspaces/org |
|
|
41
|
+
| `GET /agents/{id}` | Read current state |
|
|
42
|
+
| `PUT /agents/{id}` | Update — *auto-creates a new AgentHistory version* |
|
|
43
|
+
| `DELETE /agents/{id}` | Delete |
|
|
44
|
+
|
|
45
|
+
`unified_tools[]` fields: `type` ∈
|
|
46
|
+
{`knowledge_base`, `web_search`, `call_agent`, `image_generation`,
|
|
47
|
+
`request_form`, `payment`, `memory`, `http_request`}, plus type-specific fields
|
|
48
|
+
like `knowledge_node_ids`, `domain`, `agent_id`, `http_request` config.
|
|
49
|
+
|
|
50
|
+
Limits: 10 tools per agent, ≤5 `call_agent`, ≤1 `memory`.
|
|
51
|
+
|
|
52
|
+
## Stage 2 — Knowledge bases
|
|
53
|
+
|
|
54
|
+
Base path: `/organizations/{org_id}/workspaces/{ws_id}/knowledge_bases`
|
|
55
|
+
|
|
56
|
+
| Method & path | Purpose |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `GET .../nodes` | List KB/folder/file tree (supply `parent_id` to scope) |
|
|
59
|
+
| `POST .../nodes` | Create a KB (type=`knowledge_base`, no parent) or folder (parent_id set) |
|
|
60
|
+
| `PATCH .../nodes/{node_id}` | Rename a node |
|
|
61
|
+
| `DELETE .../nodes/{node_id}` | Delete a node and its descendants |
|
|
62
|
+
| `POST .../{kb_id}/files/upload` | Upload file (multipart) — kicks off async indexing |
|
|
63
|
+
| `POST .../files/status` | Batch-poll indexing status by node ID |
|
|
64
|
+
| `GET .../{kb_id}/nodes/{node_id}/content` | Read a file's extracted content |
|
|
65
|
+
|
|
66
|
+
Attach KB files to an agent by listing their node IDs in the agent's
|
|
67
|
+
`unified_tools[].knowledge_node_ids`.
|
|
68
|
+
|
|
69
|
+
## Stage 3 — Live Test on a specific version
|
|
70
|
+
|
|
71
|
+
| Method & path | Purpose |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `POST /chats` | Create a new chat session bound to an agent |
|
|
74
|
+
| `POST /chats/{chat_id}/messages` | Send a message; **SSE stream** of tool calls + reasoning + final text |
|
|
75
|
+
| `GET /chats/{chat_id}/messages` | Read historical messages for a chat |
|
|
76
|
+
| `POST /chats/{chat_id}/regenerate` | Re-run the last turn |
|
|
77
|
+
| `POST /chats/{chat_id}/messages/{msg_id}/feedbacks` | Thumbs up/down on a reply |
|
|
78
|
+
|
|
79
|
+
`POST /chats/.../messages` requires `agent_history_id` — this is the key hook
|
|
80
|
+
for the apply → test → publish workflow. Pass the draft `AgentHistory.id` from
|
|
81
|
+
`PUT /agents/{id}` to test an unpublished version.
|
|
82
|
+
|
|
83
|
+
## Stage 4 — Version management
|
|
84
|
+
|
|
85
|
+
| Method & path | Purpose |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `GET /agents/{id}/histories` | List every AgentHistory version, with `was_published` flags |
|
|
88
|
+
| `GET /agents/{id}/histories/{history_id}` | Read a specific version |
|
|
89
|
+
| `GET /agents/{id}/impact` | List downstream agents that `call_agent` this one |
|
|
90
|
+
|
|
91
|
+
## Stage 5 — Evaluation
|
|
92
|
+
|
|
93
|
+
| Method & path | Purpose |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `POST /eval/cases` | Create case (`input`, `expected_output?`, `rubric?`); rubric = user-docs "Standard" |
|
|
96
|
+
| `GET /eval/agents/{agent_id}/cases` | List cases for an agent |
|
|
97
|
+
| `GET /eval/cases/{case_id}` | Read one |
|
|
98
|
+
| `PUT /eval/cases/{case_id}` | Update |
|
|
99
|
+
| `DELETE /eval/cases/{case_id}` | Delete |
|
|
100
|
+
| `POST /eval/cases/upload-csv` | Bulk import |
|
|
101
|
+
| `POST /eval/cases/bulk` | Bulk delete |
|
|
102
|
+
| `POST /eval/evaluators` | Create evaluator (LLM-judge via `system_prompt_template`) |
|
|
103
|
+
| `GET /eval/evaluators?wid=<ws>` | List evaluators |
|
|
104
|
+
| `PUT /eval/evaluators/{id}` | Update |
|
|
105
|
+
| `DELETE /eval/evaluators/{id}` | Delete |
|
|
106
|
+
| `POST /eval/trigger` | Run a set of cases with evaluators, optionally pinned to `agent_history_id` |
|
|
107
|
+
| `POST /eval/stop` | Cancel running case+evaluator combo |
|
|
108
|
+
| `POST /eval/rubric` | Set/override the rubric for one (case, evaluator) — write-only |
|
|
109
|
+
| `POST /eval/rubrics/batch` | **Read** rubrics for a batch of (case, evaluator) pairs |
|
|
110
|
+
|
|
111
|
+
## Stage 6 — Diagnose + update
|
|
112
|
+
|
|
113
|
+
| Method & path | Purpose |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `POST /eval/results/batch` | Read per-case scores + `reason` + generated `output` + persisted tool trace for one `agent_history_id` |
|
|
116
|
+
| `PUT /agents/{id}` | Apply the fix — creates the next AgentHistory draft |
|
|
117
|
+
|
|
118
|
+
Iterate: trigger → results → PUT → trigger again, staying on drafts.
|
|
119
|
+
|
|
120
|
+
`POST /eval/results/batch` body shape:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"agent_history_id": "<uuid>",
|
|
125
|
+
"workspace_id": "<uuid>",
|
|
126
|
+
"case_ids": ["<uuid>", ...],
|
|
127
|
+
"evaluator_id": "<uuid>", // singular — NOT evaluator_ids
|
|
128
|
+
"include_output": true, // optional, default true
|
|
129
|
+
"include_reasoning_steps": true // include persisted tool args/results/timing
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Both `agent_history_id` and `workspace_id` are required at the body level
|
|
134
|
+
(passing `wid=...` as a query param doesn't count). Cases that haven't been
|
|
135
|
+
evaluated yet on that history come back with `score=null` rather than being
|
|
136
|
+
omitted, so use `null`-checks instead of length comparisons.
|
|
137
|
+
|
|
138
|
+
Pass `include_reasoning_steps=true` to include persisted tool/reasoning steps.
|
|
139
|
+
The rows then include `reasoning_steps[]` with `id`, `type`, `args`, `result`,
|
|
140
|
+
`start_at`, and `end_at` when available. The skill preserves these as
|
|
141
|
+
normalized `tool_calls`, `tool_calls_summary`, and `tool_total_duration_ms`;
|
|
142
|
+
`codeer eval export` also writes `tool_calls_json` and keeps untouched rows
|
|
143
|
+
in `eval_table_full.json`. Per-tool time is computed from `start_at/end_at`.
|
|
144
|
+
|
|
145
|
+
**`evaluator_id` is singular — one call returns results for one evaluator
|
|
146
|
+
only.** To see the full picture for a case, you must call this endpoint
|
|
147
|
+
once per evaluator. A case might score 1.0 on Style/Tone but 0.3 on
|
|
148
|
+
Content Compliance — checking only one evaluator hides the other failure.
|
|
149
|
+
Always iterate all evaluators in the workspace (or at least all evaluators
|
|
150
|
+
the agent's cases are judged by). `codeer eval run` and `codeer eval rubrics`
|
|
151
|
+
handle this automatically; if calling the API directly, loop over
|
|
152
|
+
`eval_mod.list_evaluators(workspace_id)` and call `get_results()` for each.
|
|
153
|
+
|
|
154
|
+
Regression workflow (apply prompt change → re-run all cases → spot side
|
|
155
|
+
effects): `codeer eval run --agent <agent_id>` runs the latest AgentHistory
|
|
156
|
+
by default. Review the full result set against the previous run summary.
|
|
157
|
+
|
|
158
|
+
## Stage 7 — Publish
|
|
159
|
+
|
|
160
|
+
| Method & path | Purpose |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| `POST /agents/{id}/publish-history` | Make a specific AgentHistory version the public one (also used for rollback) |
|
|
163
|
+
| `POST /agents/{id}/publish` | Change `publish_state` (`private` / `in_organization` / `public`) |
|
|
164
|
+
| `GET /agents/{id}/impact` | Always worth running first if other agents `call_agent` this one |
|
|
165
|
+
|
|
166
|
+
## Stage 8 — Post-release analysis
|
|
167
|
+
|
|
168
|
+
| Method & path | Purpose |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `GET /histories?agent_id=X&feedback_filter=improve_feedback&external_user_id=…` | List conversations with filters |
|
|
171
|
+
| `GET /histories/{id}` | Read one history's metadata |
|
|
172
|
+
| `GET /histories/{id}/conversations` | Full conversation turns incl. tool calls |
|
|
173
|
+
| `POST /histories/{hid}/conversations/{cid}/feedbacks` | Leave freeform improvement feedback |
|
|
174
|
+
| `POST /histories/{hid}/conversations/{cid}/score` | Numeric score |
|
|
175
|
+
|
|
176
|
+
`feedback_filter` accepts the `FeedbackFilterType` enum values:
|
|
177
|
+
`no_feedback`, `with_feedback`, `helpful_feedback`, `improve_feedback`.
|
|
178
|
+
|
|
179
|
+
No built-in filter for "histories where tool X was called" — walk the
|
|
180
|
+
conversations and inspect tool-call messages yourself.
|
|
181
|
+
|
|
182
|
+
## Stage 9 — Rollback
|
|
183
|
+
|
|
184
|
+
Reuse `POST /agents/{id}/publish-history` with an older `history_id`.
|
|
185
|
+
Non-destructive: older versions stay in `GET /agents/{id}/histories`.
|
|
186
|
+
|
|
187
|
+
## Other useful endpoints
|
|
188
|
+
|
|
189
|
+
| Method & path | Purpose |
|
|
190
|
+
| --- | --- |
|
|
191
|
+
| `GET /accounts/me` | Sanity-check session, read workspace_organization_map |
|
|
192
|
+
| `GET /organizations` | List orgs visible to the user |
|
|
193
|
+
| `GET /llm/models` | List available LLM model IDs to use as `llm_model` |
|
|
194
|
+
| `GET /retrieval/...` | Shared retrieval helpers (file upload for attachments, markdown conversion) |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Gotchas (read this before your first dogfood run)
|
|
199
|
+
|
|
200
|
+
These are traps we hit in practice; `codeer-cli/src/codeer_cli/_validate.py`
|
|
201
|
+
catches most of them client-side, but they're worth knowing when you're
|
|
202
|
+
writing payloads by hand.
|
|
203
|
+
|
|
204
|
+
### 1. `/agents` returns published only; `/agents/all` returns drafts too
|
|
205
|
+
|
|
206
|
+
`GET /agents?wid=<ws>` filters to **published** agents. While iterating on a
|
|
207
|
+
draft, use `GET /agents/all?wid=<ws>&oid=<org>` — **both** params are required,
|
|
208
|
+
or the server returns `400 Organization ID is required`. Map workspace → org via
|
|
209
|
+
`/accounts/me` → `profile.workspace_organization_map`.
|
|
210
|
+
|
|
211
|
+
### 2. Form field `type` has a fixed enum — backend doesn't enforce it
|
|
212
|
+
|
|
213
|
+
Valid values:
|
|
214
|
+
`shortText`, `longText`, `number`, `dropdown`, `radio`, `checkbox`, `date`.
|
|
215
|
+
|
|
216
|
+
There is **no** `"text" | "email" | "select"`. The backend validator accepts
|
|
217
|
+
anything (`extra="allow"`) so the agent saves, but the form builder renders
|
|
218
|
+
blank fields because none of the renderers match. Use:
|
|
219
|
+
|
|
220
|
+
- `"email"` → `shortText` + `placeholder`/`helpText` hint
|
|
221
|
+
- `"text"` → `shortText` (single-line) or `longText` (multi-line)
|
|
222
|
+
- `"select"` → `dropdown` with `options: [{value, label}]`
|
|
223
|
+
|
|
224
|
+
Every field also requires `id`, `type`, `name`, `label`, `question`, `required`
|
|
225
|
+
all present and non-empty. `name` is the submission key, `label` is the
|
|
226
|
+
analytics/column name, `question` is the user-facing prompt.
|
|
227
|
+
|
|
228
|
+
### 3. The `Standard` shown in Test Suite is a per-(case, evaluator) rubric
|
|
229
|
+
|
|
230
|
+
`POST /eval/cases` has a `rubric` field — this is NOT what the Test Suite's
|
|
231
|
+
`Standard` column reads. That column is populated by `POST /eval/rubric` keyed
|
|
232
|
+
on `(evaluation_case_id, evaluator_id)`. Set it explicitly for each
|
|
233
|
+
(case, evaluator) pair after creating the case, or use the eval helpers in
|
|
234
|
+
`codeer-cli/src/codeer_cli/eval_.py` which do both in one call.
|
|
235
|
+
|
|
236
|
+
To **read** rubrics back, use `POST /eval/rubrics/batch` with
|
|
237
|
+
`{case_ids: [...], evaluator_id}` — it returns the raw rubric strings out of
|
|
238
|
+
`CaseEvaluatorInfo`, no `agent_history_id` required since rubrics are
|
|
239
|
+
version-independent. Don't try to scrape rubrics out of past
|
|
240
|
+
`/eval/results/batch` `reason` text: the judge paraphrases them, and a case
|
|
241
|
+
with a rubric set but never evaluated is indistinguishable from one with no
|
|
242
|
+
rubric. Use the eval helpers in `codeer-cli/src/codeer_cli/eval_.py`.
|
|
243
|
+
|
|
244
|
+
Different evaluators should usually get differently-worded rubrics: a
|
|
245
|
+
Style/Tone evaluator should judge **how** the agent responded (language,
|
|
246
|
+
tone, format), while a Content Compliance evaluator should judge **what** it
|
|
247
|
+
said (scope, factuality, tool-use rules).
|
|
248
|
+
|
|
249
|
+
### 4. Agent version pinning works everywhere — use it
|
|
250
|
+
|
|
251
|
+
Both `POST /chats/{id}/messages` (`agent_history_id` required) and
|
|
252
|
+
`POST /eval/trigger` (`agent_history_id` optional, null = live state) accept
|
|
253
|
+
the draft history id. The apply-→-test-→-publish loop:
|
|
254
|
+
|
|
255
|
+
1. `PUT /agents/{id}` with your change → new `AgentHistory` with status=`draft`.
|
|
256
|
+
2. Find its id in the response (`latest_version_number` + `histories`).
|
|
257
|
+
3. Live-test and/or eval against that draft id.
|
|
258
|
+
4. Only `POST /agents/{id}/publish-history` when you're happy.
|
|
259
|
+
|
|
260
|
+
Never test a change on the currently-published version by mutating it — every
|
|
261
|
+
PUT already forks a new version for you.
|
|
262
|
+
|
|
263
|
+
### 5. API-key auth is required for every request
|
|
264
|
+
|
|
265
|
+
The `codeer` wrapper sends `CODEER_API_KEY` as `x-api-key`. If you curl by
|
|
266
|
+
hand, include that header and never print or paste the key into agent-visible
|
|
267
|
+
logs.
|
|
268
|
+
|
|
269
|
+
### 6. KB `POST /nodes` has no `type` field — and only ever creates folders
|
|
270
|
+
|
|
271
|
+
`CreateNodeSchema` is `{parent_id?, name, description?}`. There's no `type` /
|
|
272
|
+
`node_type` field; the server infers **KB root** when `parent_id` is null and
|
|
273
|
+
**folder** when it's set. This endpoint **cannot create files** — files only
|
|
274
|
+
come through `/files/upload`. Backend is lenient (`extra="allow"`), so a
|
|
275
|
+
`type: "knowledge_base"` or `type: "folder"` field gets silently dropped —
|
|
276
|
+
misleading but harmless.
|
|
277
|
+
|
|
278
|
+
Prefer `kb.create_kb()` / `kb.create_folder()` in new code over the generic
|
|
279
|
+
`create_node()`.
|
|
280
|
+
|
|
281
|
+
### 7. KB upload form is a single JSON-encoded field named `form`
|
|
282
|
+
|
|
283
|
+
Django Ninja serializes a `Schema`-typed form param as one form field whose
|
|
284
|
+
value is the JSON-stringified body — it is NOT flattened into top-level form
|
|
285
|
+
fields. So the multipart body looks like:
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
form: {"parent_id": "<folder-or-kb-root-id>"}
|
|
289
|
+
files: <file-1>
|
|
290
|
+
files: <file-2>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Sending `parent_id=...` as a top-level form field returns HTTP 422 with
|
|
294
|
+
`{"loc": ("body","form"), "msg": "Field required"}`. `kb.upload_file()` /
|
|
295
|
+
`kb.upload_files()` handle this; if you roll your own, replicate the shape.
|
|
296
|
+
|
|
297
|
+
### 8. KB upload needs an explicit `Content-Type` per file
|
|
298
|
+
|
|
299
|
+
`common/files.py :: validate_uploaded_file` rejects when `file.content_type`
|
|
300
|
+
is missing or unrecognized — and httpx's default for multipart uploads is
|
|
301
|
+
`application/octet-stream`, which is unrecognized. The response comes back
|
|
302
|
+
with `status: "FAILED"` and `node_id: null` with no `error_message`
|
|
303
|
+
populated, making this hard to debug.
|
|
304
|
+
|
|
305
|
+
Always pass `(name, file_handle, content_type)` as a 3-tuple. The helper uses
|
|
306
|
+
`mimetypes.guess_type` with overrides for `.md`/`.txt`/`.csv` (the stdlib
|
|
307
|
+
returns `None` for those on older systems). Accepted MIMEs: any `text/*`,
|
|
308
|
+
plus `application/pdf`, DOCX/DOC/PPTX, Google Docs/Slides, and HTML.
|
|
309
|
+
**Image files (JPEG, PNG, GIF, WEBP) are NOT accepted for KB uploads** —
|
|
310
|
+
the upload endpoint explicitly rejects them with "Image files are not
|
|
311
|
+
supported in knowledge base", even though `BASE_ALLOWED_CONTENT_TYPES`
|
|
312
|
+
includes image MIMEs (that set is shared with other upload paths like
|
|
313
|
+
eval-case attachments, where images are allowed).
|
|
314
|
+
|
|
315
|
+
### 9. KB upload response shape + enum casing
|
|
316
|
+
|
|
317
|
+
- Response envelope: `{"nodes": [{"node_id": "...", "status": "PENDING", "original_name": "...", ...}]}` — NOT `{files: [...]}` or a flat list.
|
|
318
|
+
- `node_type` in list responses is **uppercase** (`FOLDER`, `FILE`); the frontend / ingestion code often uses lowercase. Normalize with `.upper()` before comparing.
|
|
319
|
+
- Indexing status transitions: `PENDING` → `INDEXING` → `READY`, or `FAILED` / `ERROR`. Poll `/files/status` with `{"node_ids": [...]}` until terminal. Small text files usually hit `READY` within 1–2 polls.
|
|
320
|
+
|
|
321
|
+
### 12. Eval-case attachments come from `/retrieval/upload-file`; the id is `data.uuid`
|
|
322
|
+
|
|
323
|
+
To attach an image / PDF to an eval case (e.g. "owner uploaded a cat selfie
|
|
324
|
+
instead of a report"):
|
|
325
|
+
|
|
326
|
+
1. **Upload** via `POST /retrieval/upload-file` (multipart):
|
|
327
|
+
```
|
|
328
|
+
file: (filename, bytes, content_type)
|
|
329
|
+
data: {"workspace_id": "...", "scope": "persistent", "is_evaluation_context": true}
|
|
330
|
+
```
|
|
331
|
+
`data` must be a **JSON-encoded string** (same Django Ninja quirk as KB
|
|
332
|
+
upload — see Gotcha #7).
|
|
333
|
+
|
|
334
|
+
2. **Response**:
|
|
335
|
+
```json
|
|
336
|
+
{"data": {
|
|
337
|
+
"original_name": "cat.jpg", "content_type": "image/jpeg", "size": 43853,
|
|
338
|
+
"file_url": "https://codeer-media.s3.amazonaws.com/.../cat.jpg?...",
|
|
339
|
+
"uuid": "ab155432-5119-4070-bc12-65794ecef970",
|
|
340
|
+
"scope": "persistent"
|
|
341
|
+
}}
|
|
342
|
+
```
|
|
343
|
+
**The attachment id is `data.uuid`** — there is no `data.attachment_id`
|
|
344
|
+
or `data.id` field. Looking up either of those wastes a debugging round.
|
|
345
|
+
|
|
346
|
+
3. **Attach** to the case:
|
|
347
|
+
```python
|
|
348
|
+
eval_mod.update_case(c, case_id, attachment_ids=[uuid])
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
For bulk creation, `codeer eval cases-apply --attachments-dir <dir>` reads
|
|
352
|
+
each case's `attachment_files: ["x.jpg"]` array, uploads, and attaches in one
|
|
353
|
+
pass. Workspace scope is inferred from the API-key virtual user profile.
|
|
354
|
+
|
|
355
|
+
### 11. Tool args + outputs are NOT persisted in history reads
|
|
356
|
+
|
|
357
|
+
Conversations have only three roles (`OpenAIChatRole = system | user | assistant`)
|
|
358
|
+
— there is no `tool` role row. When you read a history, here's what you can
|
|
359
|
+
and can't recover from each assistant turn:
|
|
360
|
+
|
|
361
|
+
| Recoverable | Where |
|
|
362
|
+
| --- | --- |
|
|
363
|
+
| Tool name + call_id | regex over `content`: `<tool id=call_xxx>name</tool>` |
|
|
364
|
+
| Per-call token usage | `meta.token_usage.tool_calls[]` (positional match to tags) |
|
|
365
|
+
| Sequenced tool order within a turn | the order of `<tool …>` tags in `content` |
|
|
366
|
+
| Retrieved primary sources | top-level `primary_sources[]` on the assistant turn |
|
|
367
|
+
| Final answer text (no tool markers) | `strip_tool_markers(content)` |
|
|
368
|
+
|
|
369
|
+
| NOT recoverable | Why |
|
|
370
|
+
| --- | --- |
|
|
371
|
+
| Tool **arguments** (e.g. the regex passed to `list_kb_files`, the question/keywords passed to `retrieve_context_objs`) | flow over the WebSocket during execution, not stored on Conversation |
|
|
372
|
+
| Tool **outputs** (raw JSON returned by the tool) | same — stored only as derived `primary_sources` for retrieval tools |
|
|
373
|
+
| Reasoning steps mid-turn | `meta.reasoning_steps` is currently always `null` |
|
|
374
|
+
|
|
375
|
+
If you need full tool I/O, capture it at execution time via the chat SSE
|
|
376
|
+
stream (`POST /chats/{id}/messages`), not from history reads. For after-the-
|
|
377
|
+
fact analysis, the persisted shape is sufficient to surface tool-selection
|
|
378
|
+
patterns, token costs, and which sources the agent ended up citing.
|
|
379
|
+
|
|
380
|
+
### 10. A KB has exactly ONE level of folders — no nesting
|
|
381
|
+
|
|
382
|
+
The file-manager UI only renders a single layer of folders inside a KB:
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
KB root
|
|
386
|
+
├── file.md ← files at root are fine
|
|
387
|
+
├── file2.md
|
|
388
|
+
└── Folder/ ← one level of folders is the max
|
|
389
|
+
├── another.md ← files inside a folder are fine
|
|
390
|
+
└── one-more.md
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
The backend will happily accept a folder id as `parent_id` on `POST /nodes`
|
|
394
|
+
and create a grandchild folder, but the UI won't render it and retrieval
|
|
395
|
+
tooling treats KBs as flat. **Always pass the KB root id as `parent_id`
|
|
396
|
+
when creating folders**, not another folder's id.
|
|
397
|
+
|
|
398
|
+
If the user's source tree has deeper nesting, flatten it first with the
|
|
399
|
+
`kb-indexing` skill — it encodes the original path into the filename (e.g.
|
|
400
|
+
`products/a.md` using `/` U+FF0F as separator) so `list_kb_files` regex
|
|
401
|
+
can still recover structure. That skill's docs explain the full flow.
|
|
402
|
+
|
|
403
|
+
### 13. Eval results and rubrics are **per-evaluator** — always iterate all evaluators
|
|
404
|
+
|
|
405
|
+
Both `POST /eval/results/batch` and `POST /eval/rubrics/batch` take a
|
|
406
|
+
**singular** `evaluator_id`, not a list. Each call returns data for one
|
|
407
|
+
evaluator only. A common mistake is to check results for one evaluator
|
|
408
|
+
(e.g. Content Compliance), see a perfect score, and conclude the case is
|
|
409
|
+
passing — while the other evaluator (e.g. Style/Tone) scored it 0.3.
|
|
410
|
+
|
|
411
|
+
When pulling eval data manually, always:
|
|
412
|
+
1. List all evaluators: `eval_mod.list_evaluators(workspace_id)`.
|
|
413
|
+
2. Call `get_results()` or `get_rubrics_batch()` once **per evaluator**.
|
|
414
|
+
3. Join the results by `case_id` to get the full (case × evaluator) matrix.
|
|
415
|
+
|
|
416
|
+
The CLI commands (`codeer eval run`, `codeer eval rubrics`,
|
|
417
|
+
`codeer eval rubrics-apply`) and the `get_case_rubrics()` helper all handle
|
|
418
|
+
this iteration automatically. Prefer them for normal operations.
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Keeping this reference accurate
|
|
423
|
+
|
|
424
|
+
The canonical reference for Codeer's API and capabilities is the public
|
|
425
|
+
documentation at **https://docs.codeer.ai**. When uncertain about an API
|
|
426
|
+
shape, parameter name, or enum value, check docs.codeer.ai first — this
|
|
427
|
+
cheatsheet is a summary that can lag behind.
|
|
428
|
+
|
|
429
|
+
The enums and limits this skill validates against are mirrored in
|
|
430
|
+
`codeer-cli/src/codeer_cli/constants.py`. When a new tool type or field type is
|
|
431
|
+
added, update that file and add a Gotcha note here if behavior is surprising.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codeer-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command line tools for managing Codeer agents over the Codeer API.
|
|
5
|
+
Project-URL: Homepage, https://www.codeer.ai
|
|
6
|
+
Author: Codeer.AI
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: httpx>=0.27
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# codeer-cli
|
|
20
|
+
|
|
21
|
+
Standalone CLI for managing Codeer agents over the Codeer API.
|
|
22
|
+
|
|
23
|
+
## User install
|
|
24
|
+
|
|
25
|
+
After the package is published to PyPI, install the CLI as an isolated command
|
|
26
|
+
line tool:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv tool install codeer-cli
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Until the package is published, install directly from this repository:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv tool install 'git+https://github.com/<org>/codeer-skills.git#subdirectory=codeer-cli'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Replace `<org>` with the GitHub organization or user that hosts this repository.
|
|
39
|
+
|
|
40
|
+
Verify that the command is available:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
codeer --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Credentials
|
|
47
|
+
|
|
48
|
+
The CLI expects credentials to be configured outside any skill workspace. Add a
|
|
49
|
+
named profile, select it, then verify the setup:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
codeer profile add work
|
|
53
|
+
codeer profile use work
|
|
54
|
+
codeer check
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`codeer profile add` prompts for the API key without echoing it. The local
|
|
58
|
+
project stores only the selected profile name in `.codeer/profile`; API keys
|
|
59
|
+
remain in the user-level config file.
|
|
60
|
+
|
|
61
|
+
For a one-off shell session, you can also export an API key directly:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
export CODEER_API_KEY=<admin-workspace-api-key>
|
|
65
|
+
codeer check
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`CODEER_API_BASE` defaults to `https://api.codeer.ai`. Override it only for
|
|
69
|
+
local, beta, or preview environments:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
export CODEER_API_BASE=http://localhost:8000
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The CLI intentionally does not read repo-root credential files or caller CWD
|
|
76
|
+
`.env`, because those files are often visible to LLM workspace context. Do not
|
|
77
|
+
paste the API key into agent chat or commit it to the repository.
|
|
78
|
+
|
|
79
|
+
Workspace and organization scope are inferred from the workspace API-key
|
|
80
|
+
virtual user's profile. `--workspace`, `--org`, `CODEER_WORKSPACE_ID`, and
|
|
81
|
+
`CODEER_ORGANIZATION_ID` are not used by the CLI.
|
|
82
|
+
|
|
83
|
+
Agent scope is optional and can be set as a non-secret environment variable:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
CODEER_AGENT_ID=<agent-id>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Development install
|
|
90
|
+
|
|
91
|
+
Use an editable install while the CLI is changing quickly:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
cd /path/to/codeer-skills/codeer-cli
|
|
95
|
+
uv tool install --editable .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Reinstall only when dependencies, entry points, or package metadata change:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv tool install --reinstall --editable /path/to/codeer-skills/codeer-cli
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Validate setup before API work:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
codeer check
|
|
108
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# codeer-cli
|
|
2
|
+
|
|
3
|
+
Standalone CLI for managing Codeer agents over the Codeer API.
|
|
4
|
+
|
|
5
|
+
## User install
|
|
6
|
+
|
|
7
|
+
After the package is published to PyPI, install the CLI as an isolated command
|
|
8
|
+
line tool:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uv tool install codeer-cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Until the package is published, install directly from this repository:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv tool install 'git+https://github.com/<org>/codeer-skills.git#subdirectory=codeer-cli'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Replace `<org>` with the GitHub organization or user that hosts this repository.
|
|
21
|
+
|
|
22
|
+
Verify that the command is available:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
codeer --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Credentials
|
|
29
|
+
|
|
30
|
+
The CLI expects credentials to be configured outside any skill workspace. Add a
|
|
31
|
+
named profile, select it, then verify the setup:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
codeer profile add work
|
|
35
|
+
codeer profile use work
|
|
36
|
+
codeer check
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`codeer profile add` prompts for the API key without echoing it. The local
|
|
40
|
+
project stores only the selected profile name in `.codeer/profile`; API keys
|
|
41
|
+
remain in the user-level config file.
|
|
42
|
+
|
|
43
|
+
For a one-off shell session, you can also export an API key directly:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
export CODEER_API_KEY=<admin-workspace-api-key>
|
|
47
|
+
codeer check
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`CODEER_API_BASE` defaults to `https://api.codeer.ai`. Override it only for
|
|
51
|
+
local, beta, or preview environments:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export CODEER_API_BASE=http://localhost:8000
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The CLI intentionally does not read repo-root credential files or caller CWD
|
|
58
|
+
`.env`, because those files are often visible to LLM workspace context. Do not
|
|
59
|
+
paste the API key into agent chat or commit it to the repository.
|
|
60
|
+
|
|
61
|
+
Workspace and organization scope are inferred from the workspace API-key
|
|
62
|
+
virtual user's profile. `--workspace`, `--org`, `CODEER_WORKSPACE_ID`, and
|
|
63
|
+
`CODEER_ORGANIZATION_ID` are not used by the CLI.
|
|
64
|
+
|
|
65
|
+
Agent scope is optional and can be set as a non-secret environment variable:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
CODEER_AGENT_ID=<agent-id>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Development install
|
|
72
|
+
|
|
73
|
+
Use an editable install while the CLI is changing quickly:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd /path/to/codeer-skills/codeer-cli
|
|
77
|
+
uv tool install --editable .
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Reinstall only when dependencies, entry points, or package metadata change:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv tool install --reinstall --editable /path/to/codeer-skills/codeer-cli
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Validate setup before API work:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
codeer check
|
|
90
|
+
```
|