@decentrys/agent 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/README.md +121 -28
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # @decentrys/agent
2
2
 
3
- AgentGuard: policy enforcement in front of an autonomous on-chain agent.
3
+ **AgentGuard: stops an autonomous agent doing something its operator never authorised.**
4
+
5
+ ## Why this exists separately from @decentrys/protect
6
+
7
+ Protect informs a human, who then decides. An agent has no judgement and will do
8
+ exactly what it is told, at machine speed, repeatedly. A person seeing
9
+ "unlimited approval requested" may reconsider; an agent will not.
10
+
11
+ So where Protect warns and never blocks, AgentGuard exists to be able to
12
+ **stop** an action — under a policy its operator set in advance.
4
13
 
5
14
  ## Install
6
15
 
@@ -8,55 +17,139 @@ AgentGuard: policy enforcement in front of an autonomous on-chain agent.
8
17
  npm install @decentrys/agent @decentrys/protect
9
18
  ```
10
19
 
11
- ## Why this is not @decentrys/protect
20
+ ## Getting an API key
12
21
 
13
- Protect informs a human, who then decides. An agent has no judgement and will
14
- do exactly what it is told, at machine speed, repeatedly. A person seeing
15
- "unlimited approval requested" may reconsider; an agent will not.
22
+ Sign in at [decentrys.com/developers](https://decentrys.com/developers) and create a key.
16
23
 
17
- So where Protect warns and never blocks, AgentGuard exists to be able to
18
- **stop** an action — under a policy its operator set in advance.
24
+ There are two kinds, and picking the wrong one is the mistake that matters:
25
+
26
+ | Prefix | Where it belongs | Why |
27
+ |---|---|---|
28
+ | `dk_pub_live_…` | **Publishable.** Ships inside a wallet, extension or mobile app. | Bounded to the origins you register and to read-only Protect endpoints. Anyone can extract it from your bundle; that's expected, and it's why it can't do anything dangerous. |
29
+ | `dk_live_…` | **Secret.** Server-side only. | Full scope access. If this ends up in a client bundle it is a leaked credential the moment it ships. |
30
+
31
+ **Secret key only.**
32
+
33
+ ## Quick start
19
34
 
20
35
  ```ts
36
+ import { AgentGuard, sealPolicy } from '@decentrys/agent';
37
+
38
+ // The operator sets this, ahead of time. The agent never sees a mutable copy.
21
39
  const policy = sealPolicy({
22
40
  maxValuePerActionUsd: 5_000,
23
- cumulative: [{ windowMs: 86_400_000, maxUsd: 25_000 }],
24
- allowedActions: ['swap'], // may swap, may not approve
41
+ cumulative: [{ windowMs: 86_400_000, maxUsd: 25_000 }], // $25k/day
42
+ rate: [{ windowMs: 60_000, maxActions: 10 }], // 10 actions/min
43
+ allowedActions: ['swap', 'transfer'], // may swap, may NOT approve
44
+ allowedChains: ['ethereum', 'base'],
45
+ blockedCounterparties: ['0xbad...'],
25
46
  allowUnlimitedApproval: false,
47
+ maxRiskLevel: 'CAUTION',
48
+ requireHumanApprovalAboveUsd: 10_000,
49
+ failMode: 'escalate',
26
50
  });
27
51
 
28
52
  const guard = new AgentGuard({ apiKey: 'dk_live_...', policy });
29
- const decision = await guard.assessAgentTransaction(action);
53
+ ```
54
+
55
+ ## In your agent's execution loop
56
+
57
+ ```ts
58
+ const decision = await guard.assessAgentTransaction({
59
+ chain: 'ethereum',
60
+ from: agentWallet,
61
+ to: routerAddress,
62
+ actionType: 'swap',
63
+ valueUsd: 2_500,
64
+ idempotencyKey: taskId,
65
+ });
66
+
67
+ switch (decision.verdict) {
68
+ case 'allow':
69
+ try { await signAndSend(); await guard.confirm(decision); }
70
+ catch { await guard.release(decision); } // hand budget back if it didn't happen
71
+ break;
30
72
 
31
- decision.verdict // 'allow' | 'require_human_approval' | 'deny'
32
- decision.evaluations // every rule considered, passes included
73
+ case 'require_human_approval':
74
+ await notifyOperator(guard.explain(decision));
75
+ break;
76
+
77
+ case 'deny':
78
+ await log(guard.explain(decision));
79
+ break;
80
+ }
33
81
  ```
34
82
 
83
+ Three verdicts, not two. Protect's `warn` has no recipient here — there's no
84
+ human watching — so it's refused at `sealPolicy` rather than silently
85
+ reinterpreted.
86
+
35
87
  ## The agent cannot widen its own limits
36
88
 
37
- A sealed policy is branded with a runtime symbol and deep-frozen, with your
38
- arrays cloned away. There is **no widening function in this package**
39
- `narrowPolicy` only ever tightens.
89
+ A sealed policy is branded with a runtime symbol, deep-frozen, and your arrays
90
+ are cloned away an operator holding a reference can't grow a live allowlist.
91
+ **There is no widening function in this package.** `narrowPolicy` only ever
92
+ tightens: min of caps, intersection of allowlists, union of blocklists.
93
+
94
+ ```ts
95
+ const restricted = guard.withPolicy(narrowPolicy(policy, { maxValuePerActionUsd: 500 }));
96
+ ```
97
+
98
+ ## Every allow is explainable afterwards
99
+
100
+ ```ts
101
+ decision.evaluations // EVERY rule considered, passes included
102
+ guard.explain(decision)
103
+ guard.auditLog()
104
+ ```
105
+
106
+ Evaluation never short-circuits, so a record can't say "exceeded its cap" while
107
+ omitting "and the counterparty was a confirmed drainer". `not_configured` is
108
+ distinguished from `not_applicable`, so you can see which axes your policy left
109
+ **unbounded** — the difference between "the rate ceiling was checked" and "there
110
+ is no rate ceiling".
111
+
112
+ Decisions carry a policy fingerprint and action digest, and `evaluatePolicy` is
113
+ pure and clock-injected, so a recorded decision replays to the same answer.
40
114
 
41
- ## `failMode` defaults to `escalate`
115
+ ## failMode defaults to `escalate`
42
116
 
43
117
  `open` signs unscreened during exactly the window an attacker would choose.
44
- `closed` halts the agent entirely, which for a liquidation agent is its own
45
- loss and pressures operators into choosing `open`. `escalate` spends a human's
46
- attention instead of the treasury. An outage removes one input but never
47
- suspends your limits.
118
+ `closed` halts the agent entirely for a liquidation agent that's its own loss,
119
+ and it pressures operators into choosing `open`. `escalate` spends a human's
120
+ attention instead of the treasury.
121
+
122
+ An outage removes one input but **never suspends your limits**: a local `deny`
123
+ still denies under `failMode: 'open'`.
124
+
125
+ ## Two behaviours worth knowing
126
+
127
+ **An unpriced action is denied** when any value rule exists. Pass `valueUsd: 0`
128
+ explicitly if an action genuinely moves nothing. For an autonomous signer, "we
129
+ couldn't price it" must not resolve to "so we signed it".
48
130
 
49
- ## Known limit, stated plainly
131
+ **An empty allowlist denies everything**, rather than reading as unconfigured.
50
132
 
51
- The bundled spend ledger is **in-process**. Two replicas each enforcing
52
- $10,000/day enforce $20,000, and a restart resets the window. Swap in shared
53
- storage via the two-method `AgentUsage` interface before running a fleet.
133
+ ## Known limit
134
+
135
+ The bundled `SpendLedger` is **in-process and in-memory**. Two replicas each
136
+ enforcing $10,000/day enforce $20,000, and a restart resets the window. Swap in
137
+ shared storage via the two-method `AgentUsage` interface before running a fleet —
138
+ `guard.reservesBudget` reports whether you got a real one.
139
+
140
+ ## The rest of the SDK
141
+
142
+ | Package | For |
143
+ |---|---|
144
+ | [`@decentrys/protect`](https://www.npmjs.com/package/@decentrys/protect) | Pre-sign risk assessment for wallets and dapps |
145
+ | [`@decentrys/ui-sdk`](https://www.npmjs.com/package/@decentrys/ui-sdk) | React components that render Protect results |
146
+ | [`@decentrys/sentinel-sdk`](https://www.npmjs.com/package/@decentrys/sentinel-sdk) | Monitoring deployed contracts and treasuries |
147
+ | [`@decentrys/risk-sdk`](https://www.npmjs.com/package/@decentrys/risk-sdk) | Screening for exchanges and custodians |
148
+ | [`@decentrys/dri-sdk`](https://www.npmjs.com/package/@decentrys/dri-sdk) | Fund tracing and recovery intelligence |
149
+ | [`@decentrys/agent`](https://www.npmjs.com/package/@decentrys/agent) | Policy enforcement for autonomous agents |
54
150
 
55
151
  ## Licence
56
152
 
57
153
  MIT © Decentrys Labs
58
154
 
59
- ## Links
60
-
61
- - [decentrys.com](https://decentrys.com) · [SDK overview](https://decentrys.com/sdk) · [Developer API](https://decentrys.com/developers)
62
- - Source: [github.com/teamdecentrys-byte/Decentrys](https://github.com/teamdecentrys-byte/Decentrys)
155
+ [decentrys.com](https://decentrys.com) · [SDK overview](https://decentrys.com/sdk) · [Developer API](https://decentrys.com/developers) · [Source](https://github.com/teamdecentrys-byte/Decentrys)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentrys/agent",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AgentGuard: policy enforcement in front of an autonomous on-chain agent. An agent cannot widen the limits its operator set.",
5
5
  "license": "MIT",
6
6
  "author": "Decentrys Labs",
@@ -49,7 +49,7 @@
49
49
  "README.md"
50
50
  ],
51
51
  "dependencies": {
52
- "@decentrys/protect": "0.1.0"
52
+ "@decentrys/protect": "0.1.1"
53
53
  },
54
54
  "devDependencies": {
55
55
  "typescript": "^5.7.2",