@axonity-ai/mcp 0.1.0 → 0.2.2

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 CHANGED
@@ -1,9 +1,10 @@
1
1
  # @axonity-ai/mcp — Axonity Flow MCP connector
2
2
 
3
3
  A local [Model Context Protocol](https://modelcontextprotocol.io) server that lets
4
- an external agent (e.g. **Claude Code** on your laptop) read, draft, and update
5
- **workflows, agents, tools, skills, policies and reference docs** in your Axonity
6
- tenant — the same verbs the internal Builder team has, minus direct publish.
4
+ an external agent (e.g. **Claude Code** on your laptop) read, draft, update, and
5
+ recoverably delete **workflows, agents, tools, skills, policies, reference docs,
6
+ personas, output schemas, prompt snippets and flows** in your Axonity tenant —
7
+ the same verbs the internal Builder team has, minus direct publish.
7
8
 
8
9
  It runs on your machine and talks to Axonity **only over the public REST API**,
9
10
  authenticated with a per-tenant **service token**. The backend re-enforces
@@ -13,7 +14,11 @@ tenant + scope on every call, so the connector is not a trust boundary.
13
14
 
14
15
  1. **Mint a service token** in Axonity → **Settings → API tokens**. Copy it once
15
16
  (it starts with `axs_`); you won't see it again. Use a **read-only** token if
16
- you only want the agent to read.
17
+ you only want the agent to read — it is genuinely enforced, any write from it
18
+ is refused with a 403. Every token expires (you choose 7, 15, 30, 60 or 90
19
+ days at mint time; there is no "never"), and there is no way for the agent to
20
+ check remaining lifetime in advance — an expired token fails exactly like a
21
+ revoked one, so mint a fresh one when that happens.
17
22
  2. **Add the connector to Claude Code:**
18
23
 
19
24
  ```bash
@@ -26,43 +31,156 @@ tenant + scope on every call, so the connector is not a trust boundary.
26
31
  `AXONITY_API_URL` is optional (defaults to the Axonity SaaS URL); set it if you
27
32
  self-host.
28
33
 
34
+ Do **not** pass extra CLI arguments to `axonity-mcp`; startup only reads
35
+ environment variables. If arguments are supplied, the process exits with a
36
+ clear usage-style error.
37
+
29
38
  3. Ask Claude Code things like *"list my Axonity workflows"*, *"create a workflow
30
39
  called Onboarding"*, or *"add a step to workflow X"*.
31
40
 
32
41
  ## Tools
33
42
 
34
- | Tool | What it does |
35
- |------|--------------|
36
- | `axonity_conventions` | The authoring rules (drafts vs live, optimistic locking, per-entity fields). Read this first. |
37
- Each entity — **workflow, agent, tool, skill, policy, reference_doc** — gets the
38
- same five verbs:
43
+ 200+ tools total. `axonity_conventions` (read this first) covers the authoring
44
+ rules — drafts vs live, optimistic locking, per-entity fields, delete/restore,
45
+ and how to tell a retryable error from one that will never succeed.
46
+
47
+ ### The generic entity family
48
+
49
+ Ten entities — **workflow, agent, tool, skill, policy, reference_doc, persona,
50
+ output_schema, prompt_snippet, flow** — share one shape, though not every
51
+ entity gets every verb (see the per-entity notes below for the exceptions):
39
52
 
40
53
  | Tool (per `<entity>`) | What it does |
41
54
  |------|--------------|
42
- | `list_<entity>s` | List the tenant's entities. |
55
+ | `list_<plural>` | List the tenant's entities. |
43
56
  | `read_<entity>` | Read one by id (incl. its version — read before you update). |
44
57
  | `create_<entity>` | Create a new **draft**. |
45
- | `update_<entity>` | Update a draft (carries `expectedVersion`; 409 on a stale write). |
58
+ | `update_<entity>` | Update a draft (`expectedVersion` in the body; 409 on a stale write). |
59
+ | `delete_<entity>` | Soft-delete. **Recoverable** — see `restore_<entity>`. |
60
+ | `restore_<entity>` | Undo a delete. No version check. |
61
+ | `list_deleted_<plural>` | Restore candidates. |
62
+ | `discard_<entity>_draft` | Reset the draft to the last published state. |
46
63
  | `request_publish_<entity>` | Ask for a draft to be published — creates a pending approval; never publishes. |
47
64
 
48
- Plus `apply_workflow_mutations` for structural workflow edits (add steps, connect
49
- edges) via mutation commands.
65
+ Exceptions: `persona` has no `create_persona` (create only via
66
+ `create_agent_persona`).
67
+
68
+ Plus:
69
+ - `apply_workflow_mutations` for structural workflow edits (add steps, connect
70
+ edges) via mutation commands, sequenced and version-threaded for you.
71
+ - `replace_workflow_document` for one-shot full-document replacement in a single
72
+ atomic PUT.
50
73
 
51
- Also:
74
+ ### Version history, rollback, and version-level delete
52
75
 
53
- - **Personas** (agent-scoped, 1:1 with an agent): `read_agent_persona`,
54
- `create_agent_persona`, `update_persona`.
76
+ For the ten versioned entities (including `flow`):
77
+
78
+ | Tool | What it does |
79
+ |------|--------------|
80
+ | `list_<entity>_versions` | List version history (checkpoints + named majors). |
81
+ | `read_<entity>_version` | Read one, by **integer checkpoint number**. |
82
+ | `restore_<entity>_version` | Roll the draft back to an old version (`expectedVersion` in body). |
83
+ | `delete_<entity>_version` | Remove one history entry. Draft and published version are protected. |
84
+ | `list_deleted_<entity>_versions` | Restore candidates for the row above. |
85
+ | `restore_deleted_<entity>_version` | Undo the delete above. No version check. |
86
+ | `read_<entity>_published` | The live snapshot, as opposed to the draft. |
87
+
88
+ `{version}` (an int) and `{versionId}` (a UUID) are two different identifiers
89
+ across these routes — the tool parameter names say which.
90
+
91
+ ### Also
92
+
93
+ - **Personas**: `read_agent_persona`, `create_agent_persona` — agent-scoped,
94
+ since a persona can only be created through its agent. Everything else about
95
+ a persona (list, read, update, delete/restore, versions) is the generic
96
+ entity family above.
55
97
  - **Connectors** (a tool of type `connector`): `create_connector`,
56
98
  `update_connector` — `authConfig` must be placeholders only; a human fills real
57
- secrets in Axonity.
58
- - **Attach memory to a target**: `attach_skill_to_agent`,
59
- `attach_skill_to_workflow`, `attach_policy_to_agent`, `attach_reference_to_agent`.
99
+ secrets in Axonity. (`create_tool`/`update_tool` carry the same guard, so a
100
+ connector authored either way is covered.)
101
+ - **Attach / detach memory**: `attach_skill_to_agent`,
102
+ `attach_skill_to_workflow`, `attach_policy_to_agent`,
103
+ `attach_reference_to_agent`, and a `detach_*_from_*` for each. Detaching
104
+ removes the link only — the skill or policy itself is untouched.
105
+ - **Catalog & cloning**: `list_system_tools` (read-only catalog — enabling one
106
+ for an agent is `update_agent` with the id added to `systemToolIds`),
107
+ `clone_flow`, `clone_prompt_snippet`.
108
+ - `list_deleted_prompt_snippets` calls `/api/v1/prompt-snippets/deleted`; the
109
+ backend returns it as `{ items: [... ] }`, and the tool forwards that response
110
+ unchanged.
111
+
112
+ ### Validate and run before you publish
60
113
 
61
- ## Publishing
62
-
63
- The connector **never publishes directly**. `request_publish_*` creates a
64
- **pending approval** in Axonity; an admin approves it there, and only then does
65
- the draft go live. Rejecting it changes nothing.
114
+ | Tool | What it does |
115
+ |------|--------------|
116
+ | `validate_workflow` | Structural + schema check of a workflow document. Stateless and read-only-token safe; does not verify referenced agents/tools exist. |
117
+ | `analyze_workflow_reachable_outputs` | What a given step can read from upstream — bind inputs to real fields instead of guessing. Stateless and read-only-token safe. |
118
+ | `validate_tool_code` | Syntax and banned-pattern check for Python tool code. Stateless and read-only-token safe. |
119
+ | `format_tool_code` | Format tool code with Black. Stateless and read-only-token safe. |
120
+ | `execute_tool` | Actually RUN tool code (not just validate it) and see the real output. |
121
+ | `execute_stored_connector` | Test-run an already-saved connector. The backend decrypts its real secret server-side — the agent supplies only input parameters and never sees the secret. |
122
+
123
+ ### Triggers — what makes a workflow run
124
+
125
+ `list_/create_/delete_` for **webhook triggers** (plus
126
+ `rotate_webhook_trigger`), **cron schedules**, and **conditional triggers**
127
+ (plus `update_conditional_trigger`). Trigger deletes are **hard** deletes with
128
+ no restore, and a webhook token is shown **once** at create or rotate.
129
+
130
+ ### Runs — evaluating what you built
131
+
132
+ `list_runs`, `list_workflow_runs`, `read_run`, `read_run_trace`,
133
+ `read_run_cost`, `read_runs_summary`, `archive_run` / `unarchive_run`,
134
+ `bulk_archive_runs` / `bulk_delete_runs`. There is no findings endpoint —
135
+ evaluation means reading a run's validator verdicts and its trace.
136
+
137
+ ### Approvals
138
+
139
+ `list_publish_approvals({ status?, limit?, offset? })` and
140
+ `get_publish_approval({ approvalId })` — how you find out whether a
141
+ `request_publish_*` was approved or rejected. Approving and rejecting are
142
+ human-only actions in Axonity.
143
+
144
+ ## What this is for — and what it is not
145
+
146
+ **Authoring.** An agent composing an entity from intent: drafting a workflow,
147
+ writing a tool, wiring memory onto an agent, and checking its own work. That is
148
+ what these tools are built for.
149
+
150
+ **Not bulk migration.** Do not use the connector to move many entities verbatim
151
+ from one place to another. Axonity's config export/import moves bytes with no
152
+ model in the path and fails closed on secrets; content routed through an agent
153
+ can be subtly altered in transit, which is precisely the risk a fidelity
154
+ migration cannot take.
155
+
156
+ ## Guardrails
157
+
158
+ These are enforced by the backend, not merely by convention:
159
+
160
+ - **The connector never publishes.** `request_publish_*` creates a **pending
161
+ approval**; a human approves it in Axonity, and only then does the draft go
162
+ live. A direct publish from a service token is refused with a 403, so there is
163
+ no tool for it and no way around it.
164
+ - **A read-only token is genuinely read-only for mutations.** Any write from a token
165
+ without the `write` scope is refused with a 403.
166
+ - **The four stateless analysis tools are the exception:** `validate_workflow`,
167
+ `analyze_workflow_reachable_outputs`, `validate_tool_code`, and `format_tool_code`
168
+ can be called by read-only and write tokens because they never mutate state.
169
+ - **The token is tenant-bound.** An agent cannot reach another tenant.
170
+ - **Secrets never pass through the agent.** A connector's `authConfig` accepts
171
+ placeholders only; a write carrying something that looks like a real
172
+ credential is rejected before it leaves the connector. Tenant secrets
173
+ (`/api/v1/secrets`) aren't wrapped at all — the backend refuses any service
174
+ token there outright.
175
+ - **Errors carry a machine-readable `code`, not just prose.** A 409 can mean a
176
+ stale write (retry) or a live reference conflict (don't — see
177
+ `axonity_conventions`); the connector tells them apart by `code`, never by
178
+ matching the message text.
179
+
180
+ **One known exception, not enforced:** a framework-provided `flow` is meant to
181
+ be read-only to a tenant, but the backend does not actually block
182
+ `update_flow`/`delete_flow` against one. Prefer `clone_flow` over editing a
183
+ framework flow in place.
66
184
 
67
185
  ## Development
68
186
 
package/dist/client.d.ts CHANGED
@@ -8,6 +8,8 @@
8
8
  */
9
9
  import type { AxonityConfig } from "./config.js";
10
10
  export type Json = Record<string, unknown>;
11
+ /** Query-string values a route may take. `undefined` entries are omitted. */
12
+ export type Query = Record<string, string | number | boolean | undefined>;
11
13
  export declare class AxonityClient {
12
14
  private readonly config;
13
15
  constructor(config: AxonityConfig);
@@ -16,9 +18,16 @@ export declare class AxonityClient {
16
18
  * Issue a request and return the parsed JSON body. Non-2xx responses are
17
19
  * thrown as typed errors; a 204/empty body resolves to `undefined`.
18
20
  */
19
- request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
20
- get<T = unknown>(path: string): Promise<T>;
21
+ request<T = unknown>(method: string, path: string, body?: unknown, query?: Query): Promise<T>;
22
+ get<T = unknown>(path: string, query?: Query): Promise<T>;
21
23
  post<T = unknown>(path: string, body?: unknown): Promise<T>;
22
24
  put<T = unknown>(path: string, body?: unknown): Promise<T>;
23
25
  patch<T = unknown>(path: string, body?: unknown): Promise<T>;
26
+ /**
27
+ * DELETE. The optimistic lock travels as a QUERY parameter on these routes,
28
+ * not in the body — and its spelling differs by entity family
29
+ * (`expectedVersion` vs `expected_version`), so the caller passes it in.
30
+ * A 204 with no body resolves to `undefined`.
31
+ */
32
+ del<T = unknown>(path: string, query?: Query): Promise<T>;
24
33
  }
package/dist/client.js CHANGED
@@ -12,17 +12,26 @@ export class AxonityClient {
12
12
  constructor(config) {
13
13
  this.config = config;
14
14
  }
15
- url(path) {
16
- return `${this.config.apiUrl}${path.startsWith("/") ? path : `/${path}`}`;
15
+ url(path, query) {
16
+ const base = `${this.config.apiUrl}${path.startsWith("/") ? path : `/${path}`}`;
17
+ if (!query)
18
+ return base;
19
+ const params = new URLSearchParams();
20
+ for (const [key, value] of Object.entries(query)) {
21
+ if (value !== undefined)
22
+ params.set(key, String(value));
23
+ }
24
+ const qs = params.toString();
25
+ return qs ? `${base}?${qs}` : base;
17
26
  }
18
27
  /**
19
28
  * Issue a request and return the parsed JSON body. Non-2xx responses are
20
29
  * thrown as typed errors; a 204/empty body resolves to `undefined`.
21
30
  */
22
- async request(method, path, body) {
31
+ async request(method, path, body, query) {
23
32
  let resp;
24
33
  try {
25
- resp = await fetch(this.url(path), {
34
+ resp = await fetch(this.url(path, query), {
26
35
  method,
27
36
  headers: {
28
37
  Authorization: `Bearer ${this.config.token}`,
@@ -39,15 +48,15 @@ export class AxonityClient {
39
48
  const text = await resp.text();
40
49
  const parsed = text ? safeJson(text) : undefined;
41
50
  if (!resp.ok) {
42
- const detail = parsed && typeof parsed === "object" && "detail" in parsed
43
- ? parsed.detail
44
- : parsed;
45
- throw errorForStatus(resp.status, detail);
51
+ // Pass the FULL body — errorForStatus reads `code`/`retryable`/`message`
52
+ // off the structured error envelope when present, and falls back
53
+ // gracefully for a bare `detail` string/array from older routes.
54
+ throw errorForStatus(resp.status, parsed);
46
55
  }
47
56
  return parsed;
48
57
  }
49
- get(path) {
50
- return this.request("GET", path);
58
+ get(path, query) {
59
+ return this.request("GET", path, undefined, query);
51
60
  }
52
61
  post(path, body) {
53
62
  return this.request("POST", path, body);
@@ -58,6 +67,15 @@ export class AxonityClient {
58
67
  patch(path, body) {
59
68
  return this.request("PATCH", path, body);
60
69
  }
70
+ /**
71
+ * DELETE. The optimistic lock travels as a QUERY parameter on these routes,
72
+ * not in the body — and its spelling differs by entity family
73
+ * (`expectedVersion` vs `expected_version`), so the caller passes it in.
74
+ * A 204 with no body resolves to `undefined`.
75
+ */
76
+ del(path, query) {
77
+ return this.request("DELETE", path, undefined, query);
78
+ }
61
79
  }
62
80
  function safeJson(text) {
63
81
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI9D,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE9C,GAAG,CAAC,IAAY;QACtB,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IAC5E,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CACX,MAAc,EACd,IAAY,EACZ,IAAc;QAEd,IAAI,IAAc,CAAC;QACnB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACjC,MAAM;gBACN,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;oBAC5C,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtE;gBACD,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;aAC5D,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,6EAA6E;YAC7E,MAAM,IAAI,eAAe,CACvB,sCAAsC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI;gBAC1D,yCAAyC,EAC3C,CAAC,EACD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,MAAM,GACV,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,QAAQ,IAAI,MAAM;gBACxD,CAAC,CAAE,MAA8B,CAAC,MAAM;gBACxC,CAAC,CAAC,MAAM,CAAC;YACb,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;IAED,GAAG,CAAc,IAAY;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAc,IAAY,EAAE,IAAc;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,IAAc;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAc,IAAY,EAAE,IAAc;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAO9D,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE9C,GAAG,CAAC,IAAY,EAAE,KAAa;QACrC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QAChF,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,KAAK,KAAK,SAAS;gBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CACX,MAAc,EACd,IAAY,EACZ,IAAc,EACd,KAAa;QAEb,IAAI,IAAc,CAAC;QACnB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;gBACxC,MAAM;gBACN,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;oBAC5C,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACtE;gBACD,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;aAC5D,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,6EAA6E;YAC7E,MAAM,IAAI,eAAe,CACvB,sCAAsC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI;gBAC1D,yCAAyC,EAC3C,CAAC,EACD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,yEAAyE;YACzE,iEAAiE;YACjE,iEAAiE;YACjE,MAAM,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,MAAW,CAAC;IACrB,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,KAAa;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,CAAc,IAAY,EAAE,IAAc;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,IAAc;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAc,IAAY,EAAE,IAAc;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAc,IAAY,EAAE,KAAa;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAI,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/errors.d.ts CHANGED
@@ -5,31 +5,74 @@
5
5
  * clean, actionable message to the agent — never a raw stack trace or an
6
6
  * opaque status code.
7
7
  */
8
+ /**
9
+ * Mirrors the backend's `ErrorCode` enum (`src/error_codes.py`) — the stable,
10
+ * machine-readable vocabulary every structured error response carries as
11
+ * `code`. An external agent has no access to the backend repository, so this
12
+ * is the one field worth branching on; `message` is human-readable prose that
13
+ * can be reworded without notice.
14
+ */
15
+ export type ErrorCode = "internal_error" | "bad_request" | "unauthorized" | "forbidden" | "not_found" | "gone" | "payload_too_large" | "service_unavailable" | "upstream_error" | "validation_error" | "config_secret_leak" | "config_import_error" | "conflict" | "version_conflict" | "reference_conflict" | "idempotency_conflict" | "already_terminal" | "concurrency_error" | "admin_session_required" | "rate_limited" | "trigger_concurrency_exceeded" | "config_deploy_disabled" | "git_provider_error";
16
+ /** Codes where re-issuing the SAME request can succeed later. Mirrors `RETRYABLE_CODES`. */
17
+ export declare const RETRYABLE_CODES: ReadonlySet<ErrorCode>;
18
+ /**
19
+ * Render the server's `detail` as a compact, readable line.
20
+ *
21
+ * FastAPI returns a bare string for a raised error and a list of
22
+ * `{loc, msg, type}` objects for a 422 schema rejection. The list form is what
23
+ * names the offending field, so it is flattened to `body.fieldName: message`
24
+ * rather than dumped as JSON — the agent has to act on it, not read it.
25
+ */
26
+ export declare function describeDetail(detail: unknown): string | undefined;
8
27
  export declare class AxonityApiError extends Error {
9
28
  /** HTTP status that produced this error. */
10
29
  readonly status: number;
11
- /** Server-provided detail, when present. */
30
+ /** The server's response body, when present (may be the structured envelope). */
12
31
  readonly detail?: unknown | undefined;
32
+ /** The envelope's `code`, when the server sent one — branch on this, not on `message`. */
33
+ readonly code?: string | undefined;
34
+ /** Whether re-issuing the same request could succeed. `undefined` = unknown. */
35
+ readonly retryable?: boolean | undefined;
13
36
  constructor(message: string,
14
37
  /** HTTP status that produced this error. */
15
38
  status: number,
16
- /** Server-provided detail, when present. */
17
- detail?: unknown | undefined);
39
+ /** The server's response body, when present (may be the structured envelope). */
40
+ detail?: unknown | undefined,
41
+ /** The envelope's `code`, when the server sent one — branch on this, not on `message`. */
42
+ code?: string | undefined,
43
+ /** Whether re-issuing the same request could succeed. `undefined` = unknown. */
44
+ retryable?: boolean | undefined);
18
45
  }
19
46
  /** 409 — the entity was modified since the agent read it. Re-read and retry. */
20
47
  export declare class VersionConflictError extends AxonityApiError {
21
- constructor(detail?: unknown);
48
+ constructor(body?: unknown);
49
+ }
50
+ /**
51
+ * 409 — the entity is referenced by something published or live. Both this and
52
+ * `VersionConflictError` are HTTP 409; the `code` is what tells them apart, and
53
+ * it matters: retrying THIS one can never succeed on its own.
54
+ */
55
+ export declare class ReferenceConflictError extends AxonityApiError {
56
+ constructor(body?: unknown);
57
+ }
58
+ /** 404 — no such entity in this tenant (or it was deleted). */
59
+ export declare class NotFoundError extends AxonityApiError {
60
+ constructor(body?: unknown);
22
61
  }
23
- /** 401 — the service token is missing, unknown, or revoked. */
62
+ /** 401 — the service token is missing, unknown, expired, or revoked. */
24
63
  export declare class AuthError extends AxonityApiError {
25
- constructor(detail?: unknown);
64
+ constructor(body?: unknown);
26
65
  }
27
66
  /** 403 — the token lacks the scope for this action (e.g. read-only on a write). */
28
67
  export declare class ForbiddenError extends AxonityApiError {
29
- constructor(detail?: unknown);
68
+ constructor(body?: unknown);
30
69
  }
31
70
  /**
32
- * Map an HTTP response to the right error type. `detail` is the parsed body
33
- * (FastAPI returns `{ detail: … }`), passed through for context.
71
+ * Map an HTTP response to the right error type. `body` is the parsed response
72
+ * body — ideally the structured `{error, code, retryable, message, detail?}`
73
+ * envelope, but may be a bare FastAPI `detail` string/array for routes that
74
+ * predate it. When a recognised `code` is present it takes priority over the
75
+ * HTTP status, because the status alone cannot distinguish e.g. a retryable
76
+ * version conflict from a non-retryable reference conflict — both are 409.
34
77
  */
35
- export declare function errorForStatus(status: number, detail?: unknown): AxonityApiError;
78
+ export declare function errorForStatus(status: number, body?: unknown): AxonityApiError;
package/dist/errors.js CHANGED
@@ -5,58 +5,202 @@
5
5
  * clean, actionable message to the agent — never a raw stack trace or an
6
6
  * opaque status code.
7
7
  */
8
+ /** Codes where re-issuing the SAME request can succeed later. Mirrors `RETRYABLE_CODES`. */
9
+ export const RETRYABLE_CODES = new Set([
10
+ "version_conflict",
11
+ "rate_limited",
12
+ "trigger_concurrency_exceeded",
13
+ ]);
14
+ /** Recognise the structured `{error, code, retryable, message, detail?}` shape. */
15
+ function asEnvelope(body) {
16
+ if (typeof body !== "object" || body === null || Array.isArray(body))
17
+ return undefined;
18
+ const b = body;
19
+ return {
20
+ message: typeof b.message === "string" ? b.message : undefined,
21
+ code: typeof b.code === "string" ? b.code : undefined,
22
+ retryable: typeof b.retryable === "boolean" ? b.retryable : undefined,
23
+ detail: "detail" in b ? b.detail : undefined,
24
+ affectedEntities: "affectedEntities" in b ? b.affectedEntities : undefined,
25
+ };
26
+ }
27
+ /**
28
+ * Render the server's `detail` as a compact, readable line.
29
+ *
30
+ * FastAPI returns a bare string for a raised error and a list of
31
+ * `{loc, msg, type}` objects for a 422 schema rejection. The list form is what
32
+ * names the offending field, so it is flattened to `body.fieldName: message`
33
+ * rather than dumped as JSON — the agent has to act on it, not read it.
34
+ */
35
+ export function describeDetail(detail) {
36
+ if (detail === undefined || detail === null)
37
+ return undefined;
38
+ if (typeof detail === "string")
39
+ return detail.trim() || undefined;
40
+ if (Array.isArray(detail)) {
41
+ const lines = detail
42
+ .map((item) => {
43
+ if (typeof item === "string")
44
+ return item;
45
+ if (typeof item !== "object" || item === null)
46
+ return String(item);
47
+ const { loc, msg, message } = item;
48
+ const where = Array.isArray(loc) ? loc.join(".") : undefined;
49
+ const what = typeof msg === "string" ? msg : typeof message === "string" ? message : undefined;
50
+ if (where && what)
51
+ return `${where}: ${what}`;
52
+ return what ?? where ?? JSON.stringify(item);
53
+ })
54
+ .filter(Boolean);
55
+ return lines.length ? lines.join("; ") : undefined;
56
+ }
57
+ if (typeof detail === "object") {
58
+ const { detail: nested, message } = detail;
59
+ if (typeof nested === "string")
60
+ return nested;
61
+ if (typeof message === "string")
62
+ return message;
63
+ return JSON.stringify(detail);
64
+ }
65
+ return String(detail);
66
+ }
67
+ /**
68
+ * Render a response body for a human, whether it's the new structured
69
+ * envelope, a bare FastAPI `detail` array/string, or something else entirely.
70
+ * Falls back to `describeDetail` when the body doesn't look like the envelope,
71
+ * so older/simpler error bodies still render exactly as before.
72
+ */
73
+ function describeBody(body) {
74
+ const env = asEnvelope(body);
75
+ if (!env)
76
+ return describeDetail(body);
77
+ const parts = [];
78
+ if (env.message)
79
+ parts.push(env.message);
80
+ const detailText = describeDetail(env.detail);
81
+ if (detailText && detailText !== env.message)
82
+ parts.push(detailText);
83
+ if (Array.isArray(env.affectedEntities) && env.affectedEntities.length > 0) {
84
+ parts.push(`Affects: ${env.affectedEntities.map(String).join(", ")}`);
85
+ }
86
+ return parts.length ? parts.join(" ") : describeDetail(body);
87
+ }
88
+ /** Append the server's rendered body to a base message, when there is one. */
89
+ function withDetail(base, body) {
90
+ const described = describeBody(body);
91
+ return described ? `${base} ${described}` : base;
92
+ }
8
93
  export class AxonityApiError extends Error {
9
94
  status;
10
95
  detail;
96
+ code;
97
+ retryable;
11
98
  constructor(message,
12
99
  /** HTTP status that produced this error. */
13
100
  status,
14
- /** Server-provided detail, when present. */
15
- detail) {
101
+ /** The server's response body, when present (may be the structured envelope). */
102
+ detail,
103
+ /** The envelope's `code`, when the server sent one — branch on this, not on `message`. */
104
+ code,
105
+ /** Whether re-issuing the same request could succeed. `undefined` = unknown. */
106
+ retryable) {
16
107
  super(message);
17
108
  this.status = status;
18
109
  this.detail = detail;
110
+ this.code = code;
111
+ this.retryable = retryable;
19
112
  this.name = "AxonityApiError";
20
113
  }
21
114
  }
22
115
  /** 409 — the entity was modified since the agent read it. Re-read and retry. */
23
116
  export class VersionConflictError extends AxonityApiError {
24
- constructor(detail) {
25
- super("Version conflict: the entity changed since you read it. Read it again to " +
26
- "get the current version, then re-apply your change.", 409, detail);
117
+ constructor(body) {
118
+ const env = asEnvelope(body);
119
+ super(withDetail("Version conflict: the entity changed since you read it. Read it again to " +
120
+ "get the current version, then re-apply your change.", body), 409, body, env?.code ?? "version_conflict", env?.retryable ?? true);
27
121
  this.name = "VersionConflictError";
28
122
  }
29
123
  }
30
- /** 401 — the service token is missing, unknown, or revoked. */
124
+ /**
125
+ * 409 — the entity is referenced by something published or live. Both this and
126
+ * `VersionConflictError` are HTTP 409; the `code` is what tells them apart, and
127
+ * it matters: retrying THIS one can never succeed on its own.
128
+ */
129
+ export class ReferenceConflictError extends AxonityApiError {
130
+ constructor(body) {
131
+ const env = asEnvelope(body);
132
+ super(withDetail("Reference conflict: this entity is referenced by something published or " +
133
+ "live. This is NOT a stale-read problem — re-reading and retrying will " +
134
+ "never succeed. Detach the reference, or unpublish the referencing " +
135
+ "entity, then try again.", body), 409, body, env?.code ?? "reference_conflict", env?.retryable ?? false);
136
+ this.name = "ReferenceConflictError";
137
+ }
138
+ }
139
+ /** 404 — no such entity in this tenant (or it was deleted). */
140
+ export class NotFoundError extends AxonityApiError {
141
+ constructor(body) {
142
+ const env = asEnvelope(body);
143
+ super(withDetail("Not found (404): no such entity in this tenant. Check the id, or list " +
144
+ "the collection to find it. A deleted entity also reads as not found — " +
145
+ "list_deleted_* first if you suspect that.", body), 404, body, env?.code ?? "not_found", env?.retryable ?? false);
146
+ this.name = "NotFoundError";
147
+ }
148
+ }
149
+ /** 401 — the service token is missing, unknown, expired, or revoked. */
31
150
  export class AuthError extends AxonityApiError {
32
- constructor(detail) {
33
- super("Authentication failed (401): the service token is missing, invalid, or revoked. " +
34
- "Check AXONITY_TOKEN, or mint a new token in Axonity → Settings → API tokens.", 401, detail);
151
+ constructor(body) {
152
+ const env = asEnvelope(body);
153
+ super(withDetail("Authentication failed (401): the service token is missing, invalid, expired, " +
154
+ "or revoked. The backend deliberately returns the same message for all four " +
155
+ "causes, so do not guess which one it is and do not retry — tell your human " +
156
+ "the token is dead and a new one must be minted in Axonity → Settings → API tokens.", body), 401, body, env?.code ?? "unauthorized", env?.retryable ?? false);
35
157
  this.name = "AuthError";
36
158
  }
37
159
  }
38
160
  /** 403 — the token lacks the scope for this action (e.g. read-only on a write). */
39
161
  export class ForbiddenError extends AxonityApiError {
40
- constructor(detail) {
41
- super("Forbidden (403): this service token is not allowed to perform that action. " +
42
- "A read-only token cannot create, update, or request-publish.", 403, detail);
162
+ constructor(body) {
163
+ const env = asEnvelope(body);
164
+ super(withDetail("Forbidden (403): this service token is not allowed to perform that action. " +
165
+ "A read-only token cannot create, update, delete, or request-publish, and no " +
166
+ "token may publish directly — use request_publish_* and let a human approve.", body), 403, body, env?.code ?? "forbidden", env?.retryable ?? false);
43
167
  this.name = "ForbiddenError";
44
168
  }
45
169
  }
46
170
  /**
47
- * Map an HTTP response to the right error type. `detail` is the parsed body
48
- * (FastAPI returns `{ detail: … }`), passed through for context.
171
+ * Map an HTTP response to the right error type. `body` is the parsed response
172
+ * body — ideally the structured `{error, code, retryable, message, detail?}`
173
+ * envelope, but may be a bare FastAPI `detail` string/array for routes that
174
+ * predate it. When a recognised `code` is present it takes priority over the
175
+ * HTTP status, because the status alone cannot distinguish e.g. a retryable
176
+ * version conflict from a non-retryable reference conflict — both are 409.
49
177
  */
50
- export function errorForStatus(status, detail) {
178
+ export function errorForStatus(status, body) {
179
+ const env = asEnvelope(body);
180
+ switch (env?.code) {
181
+ case "version_conflict":
182
+ return new VersionConflictError(body);
183
+ case "reference_conflict":
184
+ return new ReferenceConflictError(body);
185
+ case "not_found":
186
+ return new NotFoundError(body);
187
+ case "unauthorized":
188
+ return new AuthError(body);
189
+ case "forbidden":
190
+ case "admin_session_required":
191
+ return new ForbiddenError(body);
192
+ }
51
193
  switch (status) {
52
194
  case 401:
53
- return new AuthError(detail);
195
+ return new AuthError(body);
54
196
  case 403:
55
- return new ForbiddenError(detail);
197
+ return new ForbiddenError(body);
198
+ case 404:
199
+ return new NotFoundError(body);
56
200
  case 409:
57
- return new VersionConflictError(detail);
201
+ return new VersionConflictError(body);
58
202
  default:
59
- return new AxonityApiError(`Axonity API request failed (${status}).`, status, detail);
203
+ return new AxonityApiError(withDetail(`Axonity API request failed (${status}).`, body), status, body, env?.code, env?.retryable);
60
204
  }
61
205
  }
62
206
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAI7B;IAEA;IALX,YACE,OAAe;IACf,4CAA4C;IACnC,MAAc;IACvB,4CAA4C;IACnC,MAAgB;QAEzB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,WAAM,GAAN,MAAM,CAAQ;QAEd,WAAM,GAAN,MAAM,CAAU;QAGzB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,gFAAgF;AAChF,MAAM,OAAO,oBAAqB,SAAQ,eAAe;IACvD,YAAY,MAAgB;QAC1B,KAAK,CACH,2EAA2E;YACzE,qDAAqD,EACvD,GAAG,EACH,MAAM,CACP,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,+DAA+D;AAC/D,MAAM,OAAO,SAAU,SAAQ,eAAe;IAC5C,YAAY,MAAgB;QAC1B,KAAK,CACH,kFAAkF;YAChF,8EAA8E,EAChF,GAAG,EACH,MAAM,CACP,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,OAAO,cAAe,SAAQ,eAAe;IACjD,YAAY,MAAgB;QAC1B,KAAK,CACH,6EAA6E;YAC3E,8DAA8D,EAChE,GAAG,EACH,MAAM,CACP,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,MAAgB;IAC7D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,KAAK,GAAG;YACN,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,KAAK,GAAG;YACN,OAAO,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC1C;YACE,OAAO,IAAI,eAAe,CACxB,+BAA+B,MAAM,IAAI,EACzC,MAAM,EACN,MAAM,CACP,CAAC;IACN,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}