@decidio/sdk 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/dist/adapters/_gate.js +3 -0
- package/dist/cli.js +84 -24
- package/dist/index.js +11 -4
- package/dist/resume.js +4 -0
- package/openapi.yaml +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,9 +4,10 @@ One line to put a human-or-policy approval gate in front of any AI-agent action
|
|
|
4
4
|
|
|
5
5
|
## Quickstart — seven steps to your first sealed receipt
|
|
6
6
|
|
|
7
|
-
Under 30 minutes, no help needed. You'll need Node 20+, a terminal, and a Decidio workspace
|
|
7
|
+
Under 30 minutes, no help needed. You'll need Node 20.6+, a terminal, and a Decidio workspace
|
|
8
8
|
(request one at [decidioai.com](https://decidioai.com/#early-access) — the hosted sandbox is
|
|
9
|
-
synthetic data, safe to experiment in).
|
|
9
|
+
synthetic data, safe to experiment in). Shell commands below are Bash; on PowerShell, `export
|
|
10
|
+
NAME=value` becomes `$env:NAME="value"`.
|
|
10
11
|
|
|
11
12
|
**1. Install**
|
|
12
13
|
|
|
@@ -28,6 +29,16 @@ is sent), registers the agent, mints its **floor-limited API token** (it can req
|
|
|
28
29
|
and nothing else — your workspace session never touches the agent's disk), and writes `.env`.
|
|
29
30
|
Every later command reads `.env` from this directory automatically.
|
|
30
31
|
|
|
32
|
+
What `.env` contains after a successful init: `DECIDIO_API_URL`, `DECIDIO_AGENT_ID`,
|
|
33
|
+
`DECIDIO_AGENT_DID` + `DECIDIO_AGENT_KEY` (the local keypair — the key is what earns
|
|
34
|
+
`application_confirmed` evidence later), `DECIDIO_API_TOKEN` (the floor-limited agent token),
|
|
35
|
+
`DECIDIO_WORKSPACE_ID`, and `DECIDIO_WEBHOOK_SECRET` (operator deployments only). Pick any
|
|
36
|
+
agent name — if it's already taken in your workspace, `init` stops cleanly and suggests a
|
|
37
|
+
fresh one. Headless terminal (no prompts possible)? Export `DECIDIO_SESSION_TOKEN` first:
|
|
38
|
+
request a sign-in link, then exchange its `?login=` value at `POST /demo/login-consume` — the
|
|
39
|
+
response's `token` is your session token (the CLI prints these exact instructions when it
|
|
40
|
+
can't prompt).
|
|
41
|
+
|
|
31
42
|
**3. Protect one function** — save this as `quickstart.mjs`:
|
|
32
43
|
|
|
33
44
|
```js
|
|
@@ -76,7 +87,7 @@ becomes the record's execution evidence.
|
|
|
76
87
|
|
|
77
88
|
```bash
|
|
78
89
|
npx @decidio/sdk receipt <decisionId>
|
|
79
|
-
npx @decidio/verify decidio-receipt-<decisionId>.json
|
|
90
|
+
npx --yes @decidio/verify decidio-receipt-<decisionId>.json
|
|
80
91
|
```
|
|
81
92
|
|
|
82
93
|
The receipt is a W3C Verifiable Credential: the signature and content binding verify with no
|
|
@@ -87,12 +98,15 @@ record verify panel). One receipt proves itself; chain order across receipts is
|
|
|
87
98
|
you pass several files at once.
|
|
88
99
|
|
|
89
100
|
What the credential contains, honestly: the sealed **authority decision** — who decided, what
|
|
90
|
-
was authorized, when, under which policy. It seals at decision time and is immutable
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
was authorized, when, under which policy. It seals at decision time and is immutable — which is
|
|
102
|
+
why the credential's own `confirmation.status` field reads `"pending"` forever. Execution
|
|
103
|
+
evidence that arrives *after* the seal (your function's captured result) lives on the
|
|
104
|
+
**record**, not inside the credential bytes: the `receipt` command prints the record's current
|
|
105
|
+
tier next to the file, and with the signing key `init` wrote you'll see `application_confirmed`
|
|
106
|
+
— the wrapper's report was cryptographically bound to your agent. (No signing key configured?
|
|
107
|
+
The server caps the evidence at the weaker `agent_asserted`, and the SDK warns at confirm
|
|
108
|
+
time.) Immutable seal + accruing evidence is the design, not an omission — corrections and
|
|
109
|
+
later facts supersede, they never rewrite.
|
|
96
110
|
|
|
97
111
|
**7. Prove a replay is rejected:**
|
|
98
112
|
|
package/dist/adapters/_gate.js
CHANGED
|
@@ -32,6 +32,9 @@ export async function gateConfirm(config, decisionId, result) {
|
|
|
32
32
|
// Sign the confirm too (bound to {action:"confirm", scope:decisionId}) so the adapter path
|
|
33
33
|
// earns application_confirmed; without a key the server caps it at agent_asserted.
|
|
34
34
|
const requesterIdentity = signConfirm(decisionId, config);
|
|
35
|
+
// Same no-silent-downgrade rule as the inline wrap (guard equivalent-path catch).
|
|
36
|
+
if (!requesterIdentity)
|
|
37
|
+
console.warn(`[decidio] execution evidence for ${decisionId} recorded as agent_asserted — no signing key configured, so the report can't be proven to come from this agent. Set DECIDIO_AGENT_KEY/DID to earn application_confirmed.`);
|
|
35
38
|
const res = await f(config.apiUrl.replace(/\/$/, "") + "/agent/confirm", {
|
|
36
39
|
method: "POST",
|
|
37
40
|
headers: { "content-type": "application/json", ...(config.apiToken ? { authorization: `Bearer ${config.apiToken}` } : {}) },
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,16 @@ import { readFileSync, writeFileSync, existsSync, appendFileSync } from "node:fs
|
|
|
22
22
|
import { randomBytes } from "node:crypto";
|
|
23
23
|
import { createServer } from "node:http";
|
|
24
24
|
import { createInterface } from "node:readline";
|
|
25
|
+
import { createRequire } from "node:module";
|
|
25
26
|
import { generateKeypair } from "./signing.js";
|
|
27
|
+
const VERSION = (() => {
|
|
28
|
+
try {
|
|
29
|
+
return createRequire(import.meta.url)("../package.json").version;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
26
35
|
// ---- environment: load the CWD .env FIRST (Codex finding: init writes .env, but the next
|
|
27
36
|
// command ignored it and pointed at localhost). Process env always wins — .env only fills gaps.
|
|
28
37
|
function readEnvFile() {
|
|
@@ -47,12 +56,15 @@ for (const [k, v] of Object.entries(readEnvFile())) {
|
|
|
47
56
|
process.env[k] = v;
|
|
48
57
|
}
|
|
49
58
|
const API = (process.env.DECIDIO_API_URL ?? "http://localhost:4000").replace(/\/$/, "");
|
|
50
|
-
|
|
59
|
+
// Token is read AT CALL TIME, not captured at import: init mints a fresh agent token mid-run and
|
|
60
|
+
// its closing doctor must probe with THAT, not the pre-init env (round-3 Codex catch — the stale
|
|
61
|
+
// capture made init's own doctor print "token: REJECTED" seconds after a successful mint).
|
|
62
|
+
const TOKEN = () => process.env.DECIDIO_API_TOKEN;
|
|
51
63
|
const ENV_PATH = ".env";
|
|
52
64
|
const log = (...a) => console.log(...a);
|
|
53
65
|
/** Fetch wrapper that turns transport failures into guidance instead of a stack trace. */
|
|
54
66
|
async function api(path, init = {}, bearer) {
|
|
55
|
-
const auth = bearer ?? TOKEN;
|
|
67
|
+
const auth = bearer ?? TOKEN();
|
|
56
68
|
let res;
|
|
57
69
|
try {
|
|
58
70
|
res = await fetch(API + path, { ...init, headers: { "content-type": "application/json", ...(auth ? { authorization: `Bearer ${auth}` } : {}), ...(init.headers ?? {}) } });
|
|
@@ -180,18 +192,24 @@ async function cmdInit(agentId) {
|
|
|
180
192
|
}
|
|
181
193
|
let did, privateKey;
|
|
182
194
|
if (r.status === 409) {
|
|
183
|
-
// Already registered to a
|
|
184
|
-
//
|
|
195
|
+
// Already registered to a server-held did. WITHOUT the original private key on this machine
|
|
196
|
+
// this is a HARD STOP, not a degraded continue (round-3 Codex catch: init used to write a
|
|
197
|
+
// keyless .env and print happy-path next steps — every request then routed unproven and
|
|
198
|
+
// execution evidence silently capped at agent_asserted).
|
|
185
199
|
did = r.body?.did;
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
if (existingKey) {
|
|
201
|
+
log(`• "${agentId}" is already registered in this workspace (did ${did}) — reusing it with the DECIDIO_AGENT_KEY already in .env.`);
|
|
202
|
+
if (sourceSystem)
|
|
203
|
+
log(` Note: sourceSystem can't change on an existing agent — the registered lane stands. To use the "${sourceSystem}" lane, register a NEW name.`);
|
|
204
|
+
}
|
|
191
205
|
else {
|
|
192
|
-
|
|
193
|
-
log(
|
|
194
|
-
log(`
|
|
206
|
+
const suggestion = `${agentId}-${randomBytes(2).toString("hex")}`;
|
|
207
|
+
log(`✘ "${agentId}" is already registered in this workspace, and its private key is not on this machine`);
|
|
208
|
+
log(` (keys never leave the machine that generated them — likely a previous run, or another directory).`);
|
|
209
|
+
log(` Nothing was written. Two ways forward:`);
|
|
210
|
+
log(` 1. Fresh agent (most common): npx @decidio/sdk init ${suggestion}`);
|
|
211
|
+
log(` 2. Reuse "${agentId}": restore its original DECIDIO_AGENT_KEY into .env here, then re-run init.`);
|
|
212
|
+
return 1;
|
|
195
213
|
}
|
|
196
214
|
}
|
|
197
215
|
else if (r.status >= 200 && r.status < 300) {
|
|
@@ -209,7 +227,7 @@ async function cmdInit(agentId) {
|
|
|
209
227
|
// without the tester-lab fence (plain local dev) the mint endpoint refuses; that's fine —
|
|
210
228
|
// local dev auths with its existing env and we say so instead of failing the init.
|
|
211
229
|
let agentToken, workspaceId;
|
|
212
|
-
const mintBearer = session ?? TOKEN;
|
|
230
|
+
const mintBearer = session ?? TOKEN();
|
|
213
231
|
if (mintBearer) {
|
|
214
232
|
const mint = await api("/api/workspace/agent-token", { method: "POST", body: JSON.stringify({ agentId, label: "sdk-cli" }) }, mintBearer);
|
|
215
233
|
if (mint.status >= 200 && mint.status < 300 && mint.body?.token) {
|
|
@@ -239,27 +257,38 @@ async function cmdInit(agentId) {
|
|
|
239
257
|
if (workspaceId)
|
|
240
258
|
envOut.DECIDIO_WORKSPACE_ID = workspaceId;
|
|
241
259
|
upsertEnv(envOut);
|
|
242
|
-
|
|
260
|
+
// The closing doctor (and anything else this process does) must see what init just wrote —
|
|
261
|
+
// OVERWRITE process.env with the fresh values (round-3 Codex catch: doctor probed with the
|
|
262
|
+
// stale pre-init token and reported the mint it just watched as REJECTED).
|
|
263
|
+
for (const [k, v] of Object.entries(envOut))
|
|
264
|
+
process.env[k] = v;
|
|
265
|
+
log(`✔ wrote ${ENV_PATH} — every decidio command reads it from this directory (your script loads it with node --env-file=.env)`);
|
|
243
266
|
ensureGitignore();
|
|
244
267
|
if (privateKey)
|
|
245
268
|
log(` (the agent's private signing key is in there — for production, move it to your secret manager)`);
|
|
246
269
|
log("");
|
|
247
270
|
log("Next: protect one function and watch it route. Two steps:");
|
|
248
271
|
log("");
|
|
249
|
-
log(" 1. Save this as quickstart.mjs:");
|
|
272
|
+
log(" 1. Save this as quickstart.mjs (the same snippet as the README's step 3):");
|
|
250
273
|
log("");
|
|
251
274
|
log(` import { guard } from "@decidio/sdk";`);
|
|
252
|
-
log(
|
|
253
|
-
log(` const
|
|
254
|
-
log(
|
|
255
|
-
log(`
|
|
256
|
-
log(`
|
|
275
|
+
log("");
|
|
276
|
+
log(` const payInvoiceRaw = async (invoice) => ({ paid: true, id: invoice.id }); // your real action`);
|
|
277
|
+
log("");
|
|
278
|
+
log(` const payInvoice = guard.protect(`);
|
|
279
|
+
log(` payInvoiceRaw,`);
|
|
280
|
+
log(` (invoice) => ({ action: "payInvoice", amount: invoice.amount, scope: "Invoice" }),`);
|
|
281
|
+
log(` { mode: "blocking" }, // blocking = watch it happen live; durable is the production mode`);
|
|
282
|
+
log(` );`);
|
|
283
|
+
log("");
|
|
284
|
+
log(` const result = await payInvoice({ id: "INV-2026-001", amount: 86_000 });`);
|
|
285
|
+
log(` console.log("executed after approval:", result);`);
|
|
257
286
|
log("");
|
|
258
287
|
log(" 2. Run it, approve it, watch it complete:");
|
|
259
288
|
log("");
|
|
260
|
-
log(` node --env-file=.env quickstart.mjs # routes to a human
|
|
289
|
+
log(` node --env-file=.env quickstart.mjs # routes to a human, prints the decision id, waits`);
|
|
261
290
|
log(` npx @decidio/sdk approvals # (second terminal) see it pending`);
|
|
262
|
-
log(` npx @decidio/sdk approvals approve <id> # approve -> your function runs ->
|
|
291
|
+
log(` npx @decidio/sdk approvals approve <id> # approve -> your function runs -> evidence recorded`);
|
|
263
292
|
log("");
|
|
264
293
|
return cmdDoctor();
|
|
265
294
|
}
|
|
@@ -287,8 +316,19 @@ async function cmdDoctor() {
|
|
|
287
316
|
const rec = await api("/api/records");
|
|
288
317
|
if (rec.status >= 200 && rec.status < 300)
|
|
289
318
|
log("✔ token scope: session/admin (init, approvals and receipt work from this env)");
|
|
290
|
-
else if (rec.status === 401)
|
|
291
|
-
|
|
319
|
+
else if (rec.status === 401) {
|
|
320
|
+
// A 401 off the agent floor could also mean an INVALID token (Codex catch: don't
|
|
321
|
+
// false-green expiry). Disambiguate with a floor probe: a valid agent token gets 404 for an
|
|
322
|
+
// unknown decision (authorized, not found); an invalid one gets 401 again. A rejection here
|
|
323
|
+
// flips the overall verdict — "all green" after a red line was round 3's other doctor bug.
|
|
324
|
+
const probe = await api("/agent/status/doctor-scope-probe");
|
|
325
|
+
if (probe.status === 404)
|
|
326
|
+
log("✔ token scope: agent floor — correct for the runtime SDK (approvals/receipt will ask you to sign in)");
|
|
327
|
+
else if (probe.status === 401)
|
|
328
|
+
line(false, "token: REJECTED on the agent floor too — it's invalid or expired. Re-run `npx @decidio/sdk init` to mint a fresh one.");
|
|
329
|
+
else
|
|
330
|
+
log(`⚠ token scope: agent-floor probe returned ${probe.status} — inconclusive`);
|
|
331
|
+
}
|
|
292
332
|
else
|
|
293
333
|
log(`⚠ token scope: unexpected ${rec.status} from /api/records`);
|
|
294
334
|
log(ok ? "\ndoctor: all green." : "\ndoctor: fix the ✘ items above, then re-run `npx @decidio/sdk doctor`.");
|
|
@@ -297,6 +337,9 @@ async function cmdDoctor() {
|
|
|
297
337
|
async function cmdApprovals(sub, id, reason) {
|
|
298
338
|
// Approvals are a HUMAN act on the workspace — session scope, never the agent token. If the
|
|
299
339
|
// env's token is agent-floor (401 on /api/*), sign in interactively; memory-only as always.
|
|
340
|
+
const jsonMode = sub === "--json";
|
|
341
|
+
if (jsonMode)
|
|
342
|
+
sub = undefined;
|
|
300
343
|
let bearer;
|
|
301
344
|
const probe = await api("/api/decisions/cards");
|
|
302
345
|
if (probe.status === 401 || probe.status === 403) {
|
|
@@ -343,6 +386,11 @@ async function cmdApprovals(sub, id, reason) {
|
|
|
343
386
|
}
|
|
344
387
|
const cards = r.body?.cards ?? [];
|
|
345
388
|
const pending = cards.filter((c) => c.isAgentRequest && c.status !== "sealed");
|
|
389
|
+
if (jsonMode) {
|
|
390
|
+
// Stable machine output (round-3 ask): agents scripting the queue parse this, not prose.
|
|
391
|
+
log(JSON.stringify(pending.map((c) => ({ decisionId: c.id, action: c.agentRequest?.action ?? null, amount: c.agentRequest?.amount ?? null, title: c.title ?? null })), null, 2));
|
|
392
|
+
return 0;
|
|
393
|
+
}
|
|
346
394
|
if (!pending.length) {
|
|
347
395
|
log("No pending agent approvals. Trigger one from your protected function, then re-run this.");
|
|
348
396
|
return 0;
|
|
@@ -386,6 +434,13 @@ async function cmdReceipt(id) {
|
|
|
386
434
|
const name = `decidio-receipt-${id.replace(/[^A-Za-z0-9_-]/g, "")}.json`;
|
|
387
435
|
writeFileSync(name, JSON.stringify(r.body.credential, null, 2) + "\n");
|
|
388
436
|
log(`✔ wrote ${name}`);
|
|
437
|
+
// The credential seals at DECISION time (immutable), so execution evidence that arrived later
|
|
438
|
+
// lives on the record — surface the CURRENT tier here so the reader doesn't need a second
|
|
439
|
+
// lookup to see it (Codex catch).
|
|
440
|
+
const detail = await api(`/api/records/${encodeURIComponent(id)}`, {}, bearer);
|
|
441
|
+
const conf = detail.body?.record?.confirmation;
|
|
442
|
+
if (conf?.status)
|
|
443
|
+
log(` Sealed credential: the authority decision (its confirmation field reads "pending" forever — immutable). Current record evidence tier: ${conf.status}${conf.confirmed ? " (confirmed)" : ""}.`);
|
|
389
444
|
log(` Verify it offline — no Decidio account or network needed:`);
|
|
390
445
|
log(` npx @decidio/verify ${name}`);
|
|
391
446
|
log(` To also prove WHO issued it, pin your workspace's issuer DID (shown in your app's record verify panel):`);
|
|
@@ -428,11 +483,16 @@ const USAGE = `decidio — the Decidio SDK command line
|
|
|
428
483
|
npx @decidio/sdk approvals reject <id> [reason]
|
|
429
484
|
npx @decidio/sdk receipt <id> download a sealed decision's Authority Receipt (.json)
|
|
430
485
|
npx @decidio/sdk dev [--target URL] [--port N] local relay for the resume webhook
|
|
486
|
+
npx @decidio/sdk --version print the CLI version
|
|
431
487
|
|
|
432
488
|
Docs: the README that shipped with this package (quickstart, durable resume, adapters).`;
|
|
433
489
|
async function main(argv) {
|
|
434
490
|
const [cmd, a, b, ...rest] = argv.slice(2);
|
|
435
491
|
const wantsHelp = (s) => s === "help" || s === "--help" || s === "-h";
|
|
492
|
+
if (cmd === "--version" || cmd === "-v" || cmd === "version") {
|
|
493
|
+
log(VERSION);
|
|
494
|
+
return 0;
|
|
495
|
+
}
|
|
436
496
|
if (!cmd || wantsHelp(cmd)) {
|
|
437
497
|
log(USAGE);
|
|
438
498
|
return 0;
|
package/dist/index.js
CHANGED
|
@@ -122,13 +122,16 @@ export function withApproval(fn, describe, config) {
|
|
|
122
122
|
throw new DecidioBlockedError(auth.reason ?? "blocked by policy", auth.decisionId);
|
|
123
123
|
// 2. routed → either SUSPEND for async resume (durable) or BLOCK-poll (interactive)
|
|
124
124
|
if (auth.decision === "route") {
|
|
125
|
-
//
|
|
126
|
-
//
|
|
125
|
+
// ALWAYS hand back the decision id — an agent that suspends and says only "waiting" leaves
|
|
126
|
+
// the operator hunting through a queue, and an agent that says NOTHING (the pre-0.1.2 bug:
|
|
127
|
+
// the print was gated on appUrl, which init never writes) leaves them staring at a silent
|
|
128
|
+
// terminal. The Codex acceptance run failed exactly this claim; the id line is unconditional
|
|
129
|
+
// now, with the deep link when appUrl is configured and the CLI command when not.
|
|
127
130
|
const approvalUrl = decisionUrl(config.appUrl, auth.decisionId);
|
|
128
131
|
if (config.onPending)
|
|
129
132
|
config.onPending({ decisionId: auth.decisionId, receiptId: auth.receiptId, url: approvalUrl });
|
|
130
|
-
else
|
|
131
|
-
console.log(`[decidio] ${ctx.action} is awaiting approval — approve it at ${approvalUrl}`);
|
|
133
|
+
else
|
|
134
|
+
console.log(`[decidio] ${ctx.action} is awaiting approval (decision ${auth.decisionId}) — approve it ${approvalUrl ? `at ${approvalUrl}` : `in your Decidio queue, or: npx @decidio/sdk approvals approve ${auth.decisionId}`}`);
|
|
132
135
|
// Durable transport: park the args agent-side, register the raw fn so a (cold)
|
|
133
136
|
// resume can replay it, and SUSPEND. The process may exit now; the controller's
|
|
134
137
|
// webhook handler or poll worker re-executes THIS fn when a human approves.
|
|
@@ -187,6 +190,10 @@ export function withApproval(fn, describe, config) {
|
|
|
187
190
|
source: "wrapper", // the SDK captured the genuine response, not an agent self-report
|
|
188
191
|
...(confirmIdentity ? { requesterIdentity: confirmIdentity } : {}),
|
|
189
192
|
});
|
|
193
|
+
// An UNSIGNED confirm is server-capped at the weaker agent_asserted tier. Say so at the
|
|
194
|
+
// moment it happens — a silent evidence downgrade was round 3's acceptance FAIL.
|
|
195
|
+
if (!confirmIdentity)
|
|
196
|
+
console.warn(`[decidio] execution evidence for ${auth.decisionId} recorded as agent_asserted — no signing key configured, so the report can't be proven to come from this agent. Set DECIDIO_AGENT_KEY/DID (npx @decidio/sdk init writes them) to earn application_confirmed.`);
|
|
190
197
|
}
|
|
191
198
|
catch (e) {
|
|
192
199
|
// surface but don't throw — the action already happened
|
package/dist/resume.js
CHANGED
|
@@ -110,6 +110,10 @@ async function confirm(cfg, decisionId, capturedResponse) {
|
|
|
110
110
|
// Sign the confirm so the DURABLE/resume path can earn application_confirmed too (bound to
|
|
111
111
|
// {action:"confirm", scope:decisionId}); without a key the server caps it at agent_asserted.
|
|
112
112
|
const requesterIdentity = signConfirm(decisionId, cfg);
|
|
113
|
+
// Same no-silent-downgrade rule as the inline wrap (guard equivalent-path catch): the durable
|
|
114
|
+
// path is what production agents run, so it must disclose an agent_asserted cap too.
|
|
115
|
+
if (!requesterIdentity)
|
|
116
|
+
console.warn(`[decidio] execution evidence for ${decisionId} recorded as agent_asserted — no signing key configured, so the report can't be proven to come from this agent. Set DECIDIO_AGENT_KEY/DID to earn application_confirmed.`);
|
|
113
117
|
await f(cfg.apiUrl.replace(/\/$/, "") + "/agent/confirm", {
|
|
114
118
|
method: "POST",
|
|
115
119
|
headers: { "content-type": "application/json", ...(cfg.apiToken ? { authorization: `Bearer ${cfg.apiToken}` } : {}) },
|
package/openapi.yaml
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
openapi: 3.1.0
|
|
6
6
|
info:
|
|
7
7
|
title: Decidio Agent Gate
|
|
8
|
-
version: 0.1.
|
|
8
|
+
version: 0.1.3
|
|
9
9
|
description: >
|
|
10
10
|
Authorize an AI-agent action (proceed | route | block), confirm the captured outcome, and
|
|
11
11
|
receive the signed resume webhook when a routed action is decided. Every outcome seals a
|
|
@@ -154,7 +154,10 @@ paths:
|
|
|
154
154
|
"404": { description: unknown decision }
|
|
155
155
|
/agent/confirm:
|
|
156
156
|
post:
|
|
157
|
-
summary:
|
|
157
|
+
summary: >
|
|
158
|
+
Report the captured execution outcome — recorded as the RECORD's evidence tier
|
|
159
|
+
(application_confirmed). The credential sealed at decision time is immutable; evidence
|
|
160
|
+
accrues on the record, never inside the sealed bytes.
|
|
158
161
|
requestBody:
|
|
159
162
|
required: true
|
|
160
163
|
content:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decidio/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "One-line approval gate for AI-agent actions. Wrap a risky tool call with guard.protect(); Decidio's policy engine decides proceed | route | block, a human approves routed actions, and every outcome is sealed as a verifiable Authority Receipt.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|