@decidio/sdk 0.1.12 → 0.2.1
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 +52 -15
- package/dist/adapters/_gate.d.ts +8 -2
- package/dist/adapters/_gate.js +16 -7
- package/dist/adapters/langgraph.d.ts +3 -1
- package/dist/adapters/langgraph.js +2 -2
- package/dist/adapters/openai.d.ts +7 -2
- package/dist/adapters/openai.js +11 -3
- package/dist/adapters/temporal.d.ts +6 -2
- package/dist/adapters/temporal.js +3 -1
- package/dist/canonical.d.ts +1 -1
- package/dist/canonical.js +8 -4
- package/dist/cli.js +68 -35
- package/dist/errors.d.ts +12 -5
- package/dist/errors.js +37 -5
- package/dist/evidence.d.ts +19 -0
- package/dist/evidence.js +7 -4
- package/dist/guard.d.ts +19 -2
- package/dist/guard.js +7 -5
- package/dist/index.d.ts +27 -2
- package/dist/index.js +32 -12
- package/dist/inngest.d.ts +4 -0
- package/dist/inngest.js +1 -1
- package/dist/resume.d.ts +331 -57
- package/dist/resume.js +678 -139
- package/dist/signing.js +19 -1
- package/openapi.yaml +89 -6
- package/package.json +15 -9
package/dist/signing.js
CHANGED
|
@@ -111,6 +111,18 @@ export function assertJsonSafe(value, path = "args") {
|
|
|
111
111
|
walk(value, path);
|
|
112
112
|
}
|
|
113
113
|
export function assertSafeTransport(url, hasCredential) {
|
|
114
|
+
if (!hasCredential) {
|
|
115
|
+
let probe = null;
|
|
116
|
+
try {
|
|
117
|
+
probe = new URL(url);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
probe = null;
|
|
121
|
+
}
|
|
122
|
+
if (probe && (probe.username || probe.password)) {
|
|
123
|
+
throw new Error(`[decidio] the gate URL carries credentials in the URL itself (${probe.protocol}//user:***@${probe.host}). Decidio authenticates with a bearer token, so this is either a mistake or a secret you did not mean to put on the wire — and it is sent on every request regardless of whether an api token is configured. Remove the user:password from the URL. Nothing was sent.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
114
126
|
if (!hasCredential)
|
|
115
127
|
return;
|
|
116
128
|
let u;
|
|
@@ -124,11 +136,17 @@ export function assertSafeTransport(url, hasCredential) {
|
|
|
124
136
|
}
|
|
125
137
|
return;
|
|
126
138
|
}
|
|
139
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
140
|
+
throw new Error(`[decidio] the gate URL uses the ${u.protocol.replace(":", "")} scheme, which is not a Decidio endpoint — use https (or http://localhost for local dev). Nothing was sent.`);
|
|
141
|
+
}
|
|
142
|
+
if (u.username || u.password) {
|
|
143
|
+
throw new Error(`[decidio] the gate URL carries credentials in the URL itself (${u.protocol}//user:***@${u.host}). Decidio authenticates with a bearer token; remove the user:password from the URL. Nothing was sent.`);
|
|
144
|
+
}
|
|
127
145
|
if (u.protocol !== "http:")
|
|
128
146
|
return;
|
|
129
147
|
const host = u.hostname.toLowerCase();
|
|
130
148
|
const local = host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1";
|
|
131
|
-
if (local
|
|
149
|
+
if (local)
|
|
132
150
|
return;
|
|
133
151
|
throw new Error(`[decidio] refusing to send credentials over plaintext http to ${u.origin} — use https, or localhost for local dev. Nothing was sent.`);
|
|
134
152
|
}
|
package/openapi.yaml
CHANGED
|
@@ -147,12 +147,76 @@ components:
|
|
|
147
147
|
properties:
|
|
148
148
|
protected: { type: string, description: "base64url JWS protected header (EdDSA, kid=did, typ=decidio-execution-report+jws)" }
|
|
149
149
|
signature: { type: string, description: base64url detached signature over protected.payload }
|
|
150
|
+
ResumeWebhookResponse:
|
|
151
|
+
type: object
|
|
152
|
+
description: >
|
|
153
|
+
What the agent's resume endpoint answers. Through 0.1.x this was `{ok, outcome:{status,
|
|
154
|
+
decisionId}}` — the operator learned the SDK had finished, not whether the execution was
|
|
155
|
+
recorded, which is the only part Decidio can act on. Every field below was already
|
|
156
|
+
computed and discarded at the last line of the handler.
|
|
157
|
+
required: [ok, outcome]
|
|
158
|
+
properties:
|
|
159
|
+
ok: { type: boolean }
|
|
160
|
+
outcome:
|
|
161
|
+
type: object
|
|
162
|
+
required: [status, decisionId]
|
|
163
|
+
properties:
|
|
164
|
+
status:
|
|
165
|
+
type: string
|
|
166
|
+
enum: [executed, indeterminate, rejected, blocked, no_handler, unknown]
|
|
167
|
+
description: >
|
|
168
|
+
the LOCAL run. `indeterminate` means the handler was invoked and its outcome is
|
|
169
|
+
unknown — it will NOT be retried automatically and needs reconcile().
|
|
170
|
+
decisionId: { type: string }
|
|
171
|
+
reportRecorded: { type: boolean, description: "Decidio accepted the execution report." }
|
|
172
|
+
executionConfirmed: { type: boolean, description: "the recorded tier attests a COMMITTED execution — a different question from reportRecorded." }
|
|
173
|
+
evidenceTier:
|
|
174
|
+
type: string
|
|
175
|
+
enum: [pending, execution_unconfirmed, agent_asserted, sensor_observed, application_confirmed, independently_reconciled]
|
|
176
|
+
executionReportVerified: { type: boolean }
|
|
177
|
+
executionReportReason: { type: string, description: "why the attestation did not verify — a field, so a caller can branch instead of parsing prose." }
|
|
178
|
+
confirmationRetryable: { type: boolean, description: "whether re-sending this report could succeed." }
|
|
179
|
+
reportJournalled: { type: boolean, description: "whether the reported value is durable, which decides whether reconfirm() can help." }
|
|
180
|
+
evidenceError: { type: string, description: "the evidence mapper rejected the return value, so an empty captured response was reported." }
|
|
181
|
+
diagnostic: { type: string }
|
|
182
|
+
ConfirmResponse:
|
|
183
|
+
type: object
|
|
184
|
+
description: >
|
|
185
|
+
What the gate actually recorded. The SDK treats an unrecognised `confirmation` as NOT
|
|
186
|
+
evidence (closed enum, fail-closed), so adding a tier here is a breaking change for older
|
|
187
|
+
clients by design — they refuse to interpret what they do not understand rather than
|
|
188
|
+
guess.
|
|
189
|
+
required: [ok]
|
|
190
|
+
properties:
|
|
191
|
+
ok:
|
|
192
|
+
type: boolean
|
|
193
|
+
description: false means nothing was recorded; the SDK does not treat the report as delivered.
|
|
194
|
+
confirmation:
|
|
195
|
+
type: string
|
|
196
|
+
enum: [pending, execution_unconfirmed, agent_asserted, sensor_observed, application_confirmed, independently_reconciled]
|
|
197
|
+
description: the tier the report EARNED. Absent on a 2xx means no tier was assigned — also not evidence.
|
|
198
|
+
recordId:
|
|
199
|
+
type: string
|
|
200
|
+
description: the record the evidence accrued to.
|
|
201
|
+
executionReport:
|
|
202
|
+
type: object
|
|
203
|
+
description: >
|
|
204
|
+
The server's verdict on the signed report, when one was sent. `verified: false` with a
|
|
205
|
+
reason is surfaced to the caller verbatim — an execution whose proof did not check out
|
|
206
|
+
must not read as confirmed.
|
|
207
|
+
properties:
|
|
208
|
+
verified: { type: boolean }
|
|
209
|
+
reason:
|
|
210
|
+
type: string
|
|
211
|
+
description: why verification failed (unknown did, expired proof, burnt nonce, payload mismatch).
|
|
150
212
|
ResumeWebhook:
|
|
151
213
|
type: object
|
|
152
214
|
description: >
|
|
153
215
|
OUTBOUND — Decidio → your resumeUrl when a routed decision is decided. The raw body is
|
|
154
216
|
HMAC-signed; verify `x-decidio-signature: sha256=<hex>` with your DECIDIO_WEBHOOK_SECRET
|
|
155
|
-
BEFORE acting (the SDK resume controllers fail closed).
|
|
217
|
+
BEFORE acting (the SDK resume controllers fail closed). A duplicate delivery cannot cause a
|
|
218
|
+
second execution: the SDK writes a durable invoking marker before calling the handler,
|
|
219
|
+
so once invocation may have begun it is never invoked again automatically.
|
|
156
220
|
OPERATOR DEPLOYMENTS ONLY: signing uses a shared secret configured on both the Decidio
|
|
157
221
|
server and the agent, and self-hosted production allow-lists resume hosts (default-deny).
|
|
158
222
|
Self-serve agents against the hosted sandbox use the SDK's poll worker (guard.worker())
|
|
@@ -201,16 +265,27 @@ paths:
|
|
|
201
265
|
/agent/confirm:
|
|
202
266
|
post:
|
|
203
267
|
summary: >
|
|
204
|
-
Report the captured execution outcome — recorded as the RECORD's evidence tier
|
|
205
|
-
|
|
206
|
-
|
|
268
|
+
Report the captured execution outcome — recorded as the RECORD's evidence tier. The tier
|
|
269
|
+
is EARNED, not requested: `application_confirmed` when the report carries a valid signed
|
|
270
|
+
executionReport from a registered agent, `agent_asserted` when it is an unsigned
|
|
271
|
+
self-report, `execution_unconfirmed` when the captured response carries no usable
|
|
272
|
+
evidence. The caller does not choose it and this endpoint does not always grant the top
|
|
273
|
+
one. The credential sealed at decision time is immutable; evidence accrues on the record,
|
|
274
|
+
never inside the sealed bytes.
|
|
207
275
|
requestBody:
|
|
208
276
|
required: true
|
|
209
277
|
content:
|
|
210
278
|
application/json:
|
|
211
279
|
schema: { $ref: "#/components/schemas/ConfirmRequest" }
|
|
212
280
|
responses:
|
|
213
|
-
"200":
|
|
281
|
+
"200":
|
|
282
|
+
description: >
|
|
283
|
+
The report was accepted. `ok` and the tier are what the SDK branches on — a 200 alone
|
|
284
|
+
does NOT mean the execution was confirmed, and a client that assumes it does will
|
|
285
|
+
record an assurance the server never granted.
|
|
286
|
+
content:
|
|
287
|
+
application/json:
|
|
288
|
+
schema: { $ref: "#/components/schemas/ConfirmResponse" }
|
|
214
289
|
"401": { description: missing/invalid agent token }
|
|
215
290
|
x-webhooks:
|
|
216
291
|
resume:
|
|
@@ -221,5 +296,13 @@ paths:
|
|
|
221
296
|
application/json:
|
|
222
297
|
schema: { $ref: "#/components/schemas/ResumeWebhook" }
|
|
223
298
|
responses:
|
|
224
|
-
"200":
|
|
299
|
+
"200":
|
|
300
|
+
description: >
|
|
301
|
+
Agent accepted; executed at most once — a duplicate delivery is refused by the
|
|
302
|
+
durable execution state, not re-run. The body reports what was RECORDED, not merely
|
|
303
|
+
that the SDK finished: a 200 whose `outcome.reportRecorded` is false means the
|
|
304
|
+
action ran and Decidio does NOT have its report.
|
|
305
|
+
content:
|
|
306
|
+
application/json:
|
|
307
|
+
schema: { $ref: "#/components/schemas/ResumeWebhookResponse" }
|
|
225
308
|
"401": { description: signature missing/invalid — the controller fails closed }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decidio/sdk",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"./openai": {
|
|
34
34
|
"types": "./dist/adapters/openai.d.ts",
|
|
35
35
|
"default": "./dist/adapters/openai.js"
|
|
36
|
-
}
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
37
38
|
},
|
|
38
39
|
"files": [
|
|
39
40
|
"dist",
|
|
@@ -54,24 +55,29 @@
|
|
|
54
55
|
"verifiable-credentials"
|
|
55
56
|
],
|
|
56
57
|
"homepage": "https://decidioai.com/developers/",
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/OmniTwin/Decidio.git",
|
|
61
|
+
"directory": "packages/decidio-guard"
|
|
62
|
+
},
|
|
57
63
|
"publishConfig": {
|
|
58
64
|
"access": "public"
|
|
59
65
|
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"@langchain/langgraph": ">=0.2 <2",
|
|
68
|
+
"@temporalio/workflow": ">=1.9 <2"
|
|
69
|
+
},
|
|
60
70
|
"peerDependenciesMeta": {
|
|
61
|
-
"inngest": {
|
|
62
|
-
"optional": true
|
|
63
|
-
},
|
|
64
71
|
"@langchain/langgraph": {
|
|
65
72
|
"optional": true
|
|
66
73
|
},
|
|
67
74
|
"@temporalio/workflow": {
|
|
68
75
|
"optional": true
|
|
69
|
-
},
|
|
70
|
-
"@openai/agents": {
|
|
71
|
-
"optional": true
|
|
72
76
|
}
|
|
73
77
|
},
|
|
74
78
|
"devDependencies": {
|
|
79
|
+
"@langchain/langgraph": "^1.4.13",
|
|
80
|
+
"@temporalio/workflow": "^1.23.0",
|
|
75
81
|
"@types/node": "^22.20.1",
|
|
76
82
|
"typescript": "^5.9.3"
|
|
77
83
|
},
|
|
@@ -81,7 +87,7 @@
|
|
|
81
87
|
"prepublishOnly": "npm run typecheck && npm run build"
|
|
82
88
|
},
|
|
83
89
|
"dependencies": {
|
|
84
|
-
"@decidio/verify": "0.1
|
|
90
|
+
"@decidio/verify": "0.2.1"
|
|
85
91
|
},
|
|
86
92
|
"author": "OmniTwin Technologies Inc.",
|
|
87
93
|
"bugs": {
|