@ziggs-ai/api-client 0.10.4 → 0.12.0

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 (51) hide show
  1. package/dist/capabilities/agreementVerbs.d.ts +9 -2
  2. package/dist/capabilities/agreementVerbs.js +61 -21
  3. package/dist/capabilities/agreements.d.ts +1 -1
  4. package/dist/capabilities/agreements.js +18 -6
  5. package/dist/capabilities/artifacts.d.ts +4 -2
  6. package/dist/capabilities/artifacts.js +168 -33
  7. package/dist/capabilities/chat.d.ts +2 -3
  8. package/dist/capabilities/chat.js +5 -6
  9. package/dist/capabilities/connections.js +1 -1
  10. package/dist/capabilities/context.js +3 -0
  11. package/dist/capabilities/grants.d.ts +7 -6
  12. package/dist/capabilities/grants.js +9 -8
  13. package/dist/capabilities/index.d.ts +4 -4
  14. package/dist/capabilities/index.js +4 -4
  15. package/dist/capabilities/links.d.ts +17 -6
  16. package/dist/capabilities/links.js +71 -86
  17. package/dist/capabilities/marketplace.js +23 -17
  18. package/dist/capabilities/nextCall.d.ts +36 -5
  19. package/dist/capabilities/nextCall.js +53 -7
  20. package/dist/capabilities/payments.d.ts +24 -8
  21. package/dist/capabilities/payments.js +28 -392
  22. package/dist/capabilities/proposeProviderId.d.ts +1 -1
  23. package/dist/capabilities/proposeProviderId.js +1 -1
  24. package/dist/http/AgreementClient.d.ts +63 -27
  25. package/dist/http/AgreementClient.js +51 -39
  26. package/dist/http/ChatClient.d.ts +1 -0
  27. package/dist/http/ChatClient.js +4 -1
  28. package/dist/http/ConnectionsClient.js +12 -1
  29. package/dist/http/ContextGrantsClient.d.ts +15 -1
  30. package/dist/http/ContextGrantsClient.js +2 -0
  31. package/dist/http/ContextReadClient.d.ts +14 -5
  32. package/dist/http/GrantsClient.d.ts +14 -0
  33. package/dist/http/GrantsClient.js +18 -2
  34. package/dist/http/InboxClient.js +4 -0
  35. package/dist/http/MarketplaceClient.d.ts +6 -8
  36. package/dist/http/MarketplaceClient.js +11 -30
  37. package/dist/http/TaskClient.d.ts +5 -0
  38. package/dist/http/TaskClient.js +4 -7
  39. package/dist/http/agreementFlows.d.ts +6 -7
  40. package/dist/http/agreementFlows.js +14 -20
  41. package/dist/http/grants.d.ts +28 -0
  42. package/dist/http/index.d.ts +2 -2
  43. package/dist/index.d.ts +3 -3
  44. package/dist/index.js +1 -1
  45. package/dist/instanceIdentity.d.ts +4 -0
  46. package/dist/instanceIdentity.js +44 -0
  47. package/dist/relay/provisionRelayWorkers.d.ts +2 -2
  48. package/dist/relay/provisionRelayWorkers.js +5 -5
  49. package/dist/types.d.ts +80 -31
  50. package/dist/types.js +18 -0
  51. package/package.json +1 -1
@@ -14,19 +14,65 @@ export function nextCall(env, capabilityKey, args, why) {
14
14
  };
15
15
  }
16
16
  /**
17
- * The other party in a two-party agreement, from the perspective of `selfId`.
17
+ * The other PRINCIPAL in a two-party agreement, from the perspective of
18
+ * `selfId`.
19
+ *
20
+ * This was `peerAgentId`, and it read the `actor` columns — the agents that
21
+ * carried the paperwork. Those became courier info when a link was re-keyed to
22
+ * the two people it belongs to, and on most links they are null, so the hint it
23
+ * fed either pre-filled a call with an agent that is no longer a door or
24
+ * silently vanished because the helper returned nothing.
25
+ *
26
+ * Named for the SLOT, not for what a link happens to put in it. On a link both
27
+ * principals are guaranteed to be people, because links are person-only and
28
+ * both sides are userIds by construction — but the same slots hold an org or an
29
+ * agent on other engagement kinds, so a caller who read "person" here and
30
+ * trusted it on a hire would be wrong. The person guarantee is a link-only
31
+ * property; ask the kind before relying on it.
18
32
  *
19
33
  * Returns null rather than guessing when the row does not identify one, because
20
34
  * a pre-filled call naming the wrong counterparty is worse than no pre-filled
21
35
  * call: the caller would run it, and it would do something they did not ask for.
22
36
  */
23
- export function peerAgentId(parties, selfId) {
37
+ export function peerPrincipalId(parties, selfId) {
24
38
  if (!parties || !selfId)
25
39
  return null;
26
- const { creatorAgent, providerAgent } = parties;
27
- if (creatorAgent && creatorAgent !== selfId)
28
- return creatorAgent;
29
- if (providerAgent && providerAgent !== selfId)
30
- return providerAgent;
40
+ const creator = parties.creator?.principal;
41
+ const provider = parties.provider?.principal;
42
+ if (creator && creator !== selfId)
43
+ return creator;
44
+ if (provider && provider !== selfId)
45
+ return provider;
31
46
  return null;
32
47
  }
48
+ /**
49
+ * The peer's principal, located by finding MY side rather than by knowing my
50
+ * own principal id.
51
+ *
52
+ * An agent knows its own agent id and not the id of the person it answers for,
53
+ * so it cannot ask {@link peerPrincipalId} which of two people it is. What it
54
+ * CAN recognise is its own courier stamp: if my agent id is in one side's
55
+ * `actor`, that side is mine and the other side's principal is the peer.
56
+ *
57
+ * Note the difference from the bug this replaced. Reading the peer's `actor` as
58
+ * the peer's address was wrong — those slots are courier info, null on most
59
+ * links, and never a door. Reading MY OWN `actor` to work out which side I am on
60
+ * is sound, because I am comparing against an id I hold.
61
+ *
62
+ * Returns null when neither side carries my stamp, which is the common case for
63
+ * a link two people formed from the web. No pre-filled call is the right answer
64
+ * there: naming the wrong counterparty would get run.
65
+ */
66
+ export function peerPrincipalForCourier(parties, myAgentId) {
67
+ if (!parties || !myAgentId)
68
+ return null;
69
+ const mineIsCreator = parties.creator?.actor === myAgentId;
70
+ const mineIsProvider = parties.provider?.actor === myAgentId;
71
+ // Both sides stamped with me is one estate on both ends, not a peer.
72
+ if (mineIsCreator === mineIsProvider)
73
+ return null;
74
+ const peer = mineIsCreator
75
+ ? parties.provider?.principal
76
+ : parties.creator?.principal;
77
+ return peer && peer !== myAgentId ? peer : null;
78
+ }
@@ -1,11 +1,27 @@
1
1
  import { type CapabilityDefinition } from './types.js';
2
+ /**
3
+ * Reading the balance is the whole rail on an agent surface.
4
+ *
5
+ * What left this surface is every verb that moved value on its own:
6
+ * `payment_transfer`, `payment_hold`, `payment_release`,
7
+ * `payment_wait_for_approval` and `payment_resolve_wallet`, plus the three
8
+ * grant mutations (issue / attenuate / revoke), which are now the wallet
9
+ * owner's to make in the web app rather than an agent's to make on their
10
+ * behalf. An agent holding a free-standing "move value from A to B" verb is
11
+ * what reads as transferring a financial asset between third parties, and it
12
+ * is the shape assistant-store connector policy rejects.
13
+ *
14
+ * What did NOT change: agreements still settle in points. The hold on
15
+ * activation, the transfer in `settleCompletedTask` and the settle on fulfill
16
+ * all stay exactly as they were, and priced agreements keep moving points
17
+ * between org wallets. That double-entry IS the meter — the chain and the
18
+ * middleman margins are the measurement we want — so removing the verbs costs
19
+ * no capability: nothing an agent could do through them was load-bearing for
20
+ * getting paid under an agreement.
21
+ *
22
+ * Balance stays readable, because "see your points" is the intended
23
+ * experience. Note that `ZIGGS_MCP_CORE_ONLY` gates this whole group off
24
+ * including balance, so it is not the lever for this on its own.
25
+ */
2
26
  export declare const paymentBalanceCapability: CapabilityDefinition;
3
- export declare const paymentResolveWalletCapability: CapabilityDefinition;
4
- export declare const paymentTransferCapability: CapabilityDefinition;
5
- export declare const paymentWaitForApprovalCapability: CapabilityDefinition;
6
- export declare const paymentHoldCapability: CapabilityDefinition;
7
- export declare const paymentReleaseCapability: CapabilityDefinition;
8
- export declare const paymentIssueGrantCapability: CapabilityDefinition;
9
- export declare const paymentAttenuateGrantCapability: CapabilityDefinition;
10
- export declare const paymentRevokeGrantCapability: CapabilityDefinition;
11
27
  export declare const PAYMENT_CAPABILITIES: CapabilityDefinition[];
@@ -6,36 +6,37 @@ function client(env) {
6
6
  throw new Error('operatorKey missing from tool context');
7
7
  return new PaymentsClient(operatorKey, agentId, env.baseUrl);
8
8
  }
9
- /** Lower the optional caveat args to the wire's caveat list (was written twice). */
10
- function buildCaveats(args) {
11
- const caveats = [];
12
- if (args['maxAmount'] != null)
13
- caveats.push({ type: 'max_amount', value: args['maxAmount'] });
14
- if (args['dailyBudget'] != null)
15
- caveats.push({ type: 'daily_budget', value: args['dailyBudget'] });
16
- if (args['allowedRecipients'] != null)
17
- caveats.push({ type: 'allowed_recipients', value: args['allowedRecipients'] });
18
- if (args['expiresInSeconds'] != null)
19
- caveats.push({ type: 'expires_at', value: Date.now() + args['expiresInSeconds'] * 1000 });
20
- return caveats;
21
- }
22
- const grantCaveatParams = {
23
- maxAmount: { type: 'number', description: 'Per-transfer ceiling in cents' },
24
- dailyBudget: { type: 'number', description: 'Rolling daily budget in cents' },
25
- allowedRecipients: {
26
- type: 'array',
27
- items: { type: 'string' },
28
- description: 'Wallet ids the holder may pay',
29
- },
30
- expiresInSeconds: { type: 'number', description: 'Grant lifetime from now' },
31
- };
9
+ /**
10
+ * Reading the balance is the whole rail on an agent surface.
11
+ *
12
+ * What left this surface is every verb that moved value on its own:
13
+ * `payment_transfer`, `payment_hold`, `payment_release`,
14
+ * `payment_wait_for_approval` and `payment_resolve_wallet`, plus the three
15
+ * grant mutations (issue / attenuate / revoke), which are now the wallet
16
+ * owner's to make in the web app rather than an agent's to make on their
17
+ * behalf. An agent holding a free-standing "move value from A to B" verb is
18
+ * what reads as transferring a financial asset between third parties, and it
19
+ * is the shape assistant-store connector policy rejects.
20
+ *
21
+ * What did NOT change: agreements still settle in points. The hold on
22
+ * activation, the transfer in `settleCompletedTask` and the settle on fulfill
23
+ * all stay exactly as they were, and priced agreements keep moving points
24
+ * between org wallets. That double-entry IS the meter — the chain and the
25
+ * middleman margins are the measurement we want — so removing the verbs costs
26
+ * no capability: nothing an agent could do through them was load-bearing for
27
+ * getting paid under an agreement.
28
+ *
29
+ * Balance stays readable, because "see your points" is the intended
30
+ * experience. Note that `ZIGGS_MCP_CORE_ONLY` gates this whole group off
31
+ * including balance, so it is not the lever for this on its own.
32
+ */
32
33
  export const paymentBalanceCapability = {
33
34
  key: 'payment_balance',
34
35
  names: { sdk: 'payment_balance', mcp: 'ziggs_payment_balance' },
35
- title: 'Check your balance',
36
+ title: 'Check your points',
36
37
  descriptions: {
37
- sdk: "Check the caller's current wallet balance and available balance (total minus active holds). Use before a transfer to confirm sufficient funds.",
38
- mcp: "Check the caller's current wallet balance and available balance (total minus active holds). Use before a transfer to confirm sufficient funds.",
38
+ sdk: "Check the caller's points balance and available balance (total minus points held against active agreements). Points move as a consequence of an agreement settling.",
39
+ mcp: "Check the caller's points balance and available balance (total minus points held against active agreements). Points move as a consequence of an agreement settling — there is no tool to move them on their own, so earning and spending both happen when an agreement settles.",
39
40
  },
40
41
  annotation: 'read-only',
41
42
  params: {},
@@ -44,375 +45,10 @@ export const paymentBalanceCapability = {
44
45
  return await client(env).balance();
45
46
  }
46
47
  catch (e) {
47
- rethrowWithContext(e, 'Failed to get balance');
48
- }
49
- },
50
- };
51
- export const paymentResolveWalletCapability = {
52
- key: 'payment_resolve_wallet',
53
- names: { sdk: 'payment_resolve_wallet', mcp: 'ziggs_payment_resolve_wallet' },
54
- title: 'Look up a wallet',
55
- descriptions: {
56
- sdk: 'Look up a walletId by userId or agentId. Use before a transfer when you only know the recipient by their platform ID.',
57
- mcp: 'Look up a walletId by userId or agentId. Use before a transfer when you only know the recipient by their platform ID.',
58
- },
59
- annotation: 'read-only',
60
- params: {
61
- userId: { type: 'string', description: 'User to resolve' },
62
- agentId: { type: 'string', description: 'Agent to resolve' },
63
- },
64
- handler: async (args, env) => {
65
- if (!args['userId'] && !args['agentId'])
66
- throw new Error('Provide userId or agentId to resolve a wallet');
67
- try {
68
- const wallet = await client(env).resolve({
69
- userId: args['userId'],
70
- agentId: args['agentId'],
71
- });
72
- return {
73
- walletId: wallet?.walletId || null,
74
- ownerId: wallet?.ownerId || null,
75
- currency: wallet?.currency || 'pez',
76
- status: wallet?.status || null,
77
- };
78
- }
79
- catch (e) {
80
- rethrowWithContext(e, 'Failed to resolve wallet');
81
- }
82
- },
83
- };
84
- export const paymentTransferCapability = {
85
- key: 'payment_transfer',
86
- names: { sdk: 'payment_transfer', mcp: 'ziggs_payment_transfer' },
87
- title: 'Transfer funds',
88
- descriptions: {
89
- sdk: 'Transfer funds to another wallet. Amounts are integer cents. Transfers above the wallet owner\'s policy pause with status "approval_required" — wait inline with payment_wait_for_approval when you expect a quick decision.',
90
- mcp: 'Transfer funds to another wallet. Amounts are integer cents. As a delegate you spend under a payment grant the wallet owner issued (paymentGrantId — find yours via ziggs_grant_list scopeKind=wallet). Transfers above the owner\'s policy pause with status "approval_required": the human approves on the wallet page (it also shows in ziggs_pending_decisions) — you can wait inline with ziggs_payment_wait_for_approval, and you must NEVER approve your own transfer.',
91
- },
92
- annotation: 'write',
93
- params: {
94
- toWalletId: {
95
- type: 'string',
96
- required: true,
97
- description: 'Destination wal_... id — or a userId/agentId to auto-resolve',
98
- },
99
- amount: { type: 'number', required: true, description: 'Amount in integer cents, > 0' },
100
- description: { type: 'string', description: 'Human-readable transfer memo' },
101
- idempotencyKey: {
102
- type: 'string',
103
- description: 'Client-supplied key to make retries safe (auto-generated when omitted)',
104
- },
105
- paymentGrantId: {
106
- type: 'string',
107
- description: 'Payment grant to spend under (required for agent-impersonated transfers)',
108
- },
109
- },
110
- handler: async (args, env) => {
111
- if (!args['toWalletId'])
112
- throw new Error('toWalletId is required');
113
- const amount = args['amount'];
114
- if (!amount || amount <= 0)
115
- throw new Error('amount must be positive');
116
- let result;
117
- try {
118
- result = await client(env).transfer({
119
- to: args['toWalletId'],
120
- amount: Math.round(amount),
121
- description: args['description'] || 'Agent-initiated transfer',
122
- idempotencyKey: args['idempotencyKey'],
123
- paymentGrantId: args['paymentGrantId'],
124
- });
125
- }
126
- catch (e) {
127
- rethrowWithContext(e, 'Transfer failed');
128
- }
129
- if (result.status === 'approval_required') {
130
- const base = {
131
- status: 'approval_required',
132
- approvalId: result.approvalId,
133
- expiresAt: result.expiresAt,
134
- reason: result.reason,
135
- amount,
136
- toWalletId: result.toWalletId,
137
- };
138
- // Same pause, surface-local guidance: the MCP delegate must surface the
139
- // pending approval to the human (pull-only MCP has no push); the SDK
140
- // runtime routes via structured next_actions.
141
- if (env.surface === 'mcp') {
142
- return {
143
- ...base,
144
- note: 'Transfer paused: the wallet owner must approve this amount on the wallet page (also listed by ziggs_pending_decisions). Tell the human now (pull-only MCP has no push). ' +
145
- 'Wait inline with ziggs_payment_wait_for_approval when you expect a quick decision (≤2 min).',
146
- };
147
- }
148
- return {
149
- ...base,
150
- message: 'Transfer paused: the wallet owner must approve this amount.',
151
- next_actions: [
152
- {
153
- tool: 'payment_wait_for_approval',
154
- when: 'You expect a quick decision (≤2 min) and can wait inline.',
155
- args: { approvalId: result.approvalId, timeoutMs: 120000 },
156
- },
157
- {
158
- tool: 'task_update_plan_step',
159
- when: 'You want to abandon the transfer and route around it.',
160
- },
161
- ],
162
- };
163
- }
164
- return {
165
- status: 'transferred',
166
- transactionId: result.transactionId,
167
- amount,
168
- toWalletId: result.toWalletId,
169
- };
170
- },
171
- };
172
- export const paymentWaitForApprovalCapability = {
173
- key: 'payment_wait_for_approval',
174
- names: { sdk: 'payment_wait_for_approval', mcp: 'ziggs_payment_wait_for_approval' },
175
- title: 'Wait on a payment approval',
176
- descriptions: {
177
- sdk: 'Poll a paused transfer (status "approval_required") until the human decides or the timeout passes. Returns executed | rejected | expired | timeout | gone.',
178
- mcp: 'Poll a paused transfer (status "approval_required") until the human decides or the timeout passes. Returns executed | rejected | expired | timeout | gone. Use for quick decisions (≤2 min); for longer waits, stop and check again next session.',
179
- },
180
- annotation: 'read-only',
181
- params: {
182
- approvalId: {
183
- type: 'string',
184
- required: true,
185
- description: 'Approval to wait on (from the paused transfer)',
186
- },
187
- timeoutMs: { type: 'number', description: 'Max wait, default 120000' },
188
- pollMs: { type: 'number', description: 'Poll interval, default 3000 (min 500)' },
189
- },
190
- handler: async (args, env) => {
191
- if (!args['approvalId'])
192
- throw new Error('approvalId is required');
193
- try {
194
- const result = await client(env).waitForApproval(args['approvalId'], {
195
- timeoutMs: args['timeoutMs'],
196
- pollMs: args['pollMs'],
197
- });
198
- const loose = result;
199
- return {
200
- status: result.status,
201
- approvalId: args['approvalId'],
202
- transactionId: loose['transactionId'] || null,
203
- approval: loose['approval'] || null,
204
- };
205
- }
206
- catch (e) {
207
- rethrowWithContext(e, 'wait_for_approval failed');
208
- }
209
- },
210
- };
211
- export const paymentHoldCapability = {
212
- key: 'payment_hold',
213
- names: { sdk: 'payment_hold', mcp: 'ziggs_payment_hold' },
214
- title: 'Hold funds in escrow',
215
- descriptions: {
216
- sdk: 'Pre-authorize (escrow) funds without moving them. Use to reserve payment at agreement formation; release with payment_release once work is complete or to refund if work is cancelled.',
217
- mcp: "Pre-authorize (escrow) funds without moving them. Use to reserve payment at agreement formation; release with ziggs_payment_release once work is complete, or refund if it's cancelled.",
218
- },
219
- annotation: 'write',
220
- params: {
221
- amount: { type: 'number', required: true, description: 'Amount in integer cents, > 0' },
222
- description: { type: 'string', description: 'Human-readable hold memo' },
223
- idempotencyKey: { type: 'string', description: 'Client-supplied retry-safety key' },
224
- paymentGrantId: {
225
- type: 'string',
226
- description: 'Payment grant authorizing this hold (required for agent actors; auto-picks an active wallet grant when omitted)',
227
- },
228
- },
229
- handler: async (args, env) => {
230
- const amount = args['amount'];
231
- if (!amount || amount <= 0)
232
- throw new Error('amount must be positive');
233
- try {
234
- const result = await client(env).hold({
235
- amount: Math.round(amount),
236
- description: args['description'] || 'Agent escrow hold',
237
- idempotencyKey: args['idempotencyKey'],
238
- paymentGrantId: args['paymentGrantId'],
239
- });
240
- return {
241
- status: 'held',
242
- transactionId: result.transaction?.transactionId || null,
243
- amount,
244
- };
245
- }
246
- catch (e) {
247
- rethrowWithContext(e, 'Hold failed');
248
- }
249
- },
250
- };
251
- export const paymentReleaseCapability = {
252
- key: 'payment_release',
253
- names: { sdk: 'payment_release', mcp: 'ziggs_payment_release' },
254
- title: 'Settle or refund a hold',
255
- descriptions: {
256
- sdk: "Settle or refund an escrow hold. Use action='complete' to transfer held funds to toWalletId (work done), or action='refund' to return funds to the sender (work cancelled).",
257
- mcp: "Settle or refund an escrow hold. action='complete' transfers held funds to toWalletId (work done); action='refund' returns funds to the sender (work cancelled).",
258
- },
259
- annotation: 'write',
260
- params: {
261
- holdId: {
262
- type: 'string',
263
- required: true,
264
- description: 'Hold to settle (transactionId from the hold)',
265
- },
266
- action: {
267
- type: 'string',
268
- required: true,
269
- enum: ['complete', 'refund'],
270
- description: 'complete = pay out, refund = return',
271
- },
272
- toWalletId: { type: 'string', description: 'Destination wallet — required when action=complete' },
273
- idempotencyKey: { type: 'string', description: 'Client-supplied retry-safety key' },
274
- },
275
- handler: async (args, env) => {
276
- if (!args['holdId'])
277
- throw new Error('holdId is required');
278
- const action = args['action'];
279
- if (action !== 'complete' && action !== 'refund')
280
- throw new Error("action must be 'complete' or 'refund'");
281
- if (action === 'complete' && !args['toWalletId'])
282
- throw new Error('toWalletId is required when action=complete');
283
- try {
284
- const result = await client(env).release({
285
- holdId: args['holdId'],
286
- action,
287
- toWalletId: args['toWalletId'],
288
- idempotencyKey: args['idempotencyKey'],
289
- });
290
- return {
291
- status: action === 'complete' ? 'settled' : 'refunded',
292
- transactionId: result.transaction?.transactionId || null,
293
- holdId: args['holdId'],
294
- action,
295
- };
296
- }
297
- catch (e) {
298
- rethrowWithContext(e, 'Release failed');
299
- }
300
- },
301
- };
302
- export const paymentIssueGrantCapability = {
303
- key: 'payment_issue_grant',
304
- names: { sdk: 'payment_issue_grant', mcp: 'ziggs_payment_issue_grant' },
305
- title: 'Issue a spend grant',
306
- descriptions: {
307
- sdk: "Issue a payment grant delegating bounded spend from the operator's wallet to an agent holder. Caveats bound what the holder can do (max_amount, daily_budget, allowed_recipients, expiry). The holder spends by passing the grantId as paymentGrantId on transfers.",
308
- mcp: "Issue a payment grant delegating bounded spend from the operator's wallet to an agent holder. Caveats bound what the holder can do (max_amount, daily_budget, allowed_recipients, expiry). The holder spends by passing the grantId as paymentGrantId on transfers.",
309
- },
310
- annotation: 'write',
311
- params: {
312
- holderId: { type: 'string', required: true, description: 'Agent that will hold the grant' },
313
- ...grantCaveatParams,
314
- },
315
- handler: async (args, env) => {
316
- if (!args['holderId'])
317
- throw new Error('holderId is required');
318
- try {
319
- const caveats = buildCaveats(args);
320
- const { grant } = await client(env).issueGrant({
321
- holderId: args['holderId'],
322
- caveats,
323
- });
324
- return {
325
- grantId: grant?.grantId || null,
326
- holderId: grant?.holderId || args['holderId'],
327
- caveats: grant?.caveats || caveats,
328
- expiresAt: grant?.expiresAt || null,
329
- };
330
- }
331
- catch (e) {
332
- rethrowWithContext(e, 'Failed to issue payment grant');
333
- }
334
- },
335
- };
336
- export const paymentAttenuateGrantCapability = {
337
- key: 'payment_attenuate_grant',
338
- names: { sdk: 'payment_attenuate_grant', mcp: 'ziggs_payment_attenuate_grant' },
339
- title: 'Pass on a tighter spend grant',
340
- descriptions: {
341
- sdk: 'Re-delegate a payment grant you hold to another agent with TIGHTER caveats (narrowing only — the child can never exceed the parent). Use to pass a bounded spend slice to a sub-agent.',
342
- mcp: 'Re-delegate a payment grant you hold to another agent with TIGHTER caveats (narrowing only — the child can never exceed the parent). Use to pass a bounded spend slice to a sub-agent.',
343
- },
344
- annotation: 'write',
345
- params: {
346
- grantId: { type: 'string', required: true, description: 'Parent grant to attenuate' },
347
- holderId: {
348
- type: 'string',
349
- required: true,
350
- description: 'Agent that will hold the narrowed grant',
351
- },
352
- ...grantCaveatParams,
353
- },
354
- handler: async (args, env) => {
355
- const grantId = args['grantId'];
356
- if (!grantId)
357
- throw new Error('grantId is required');
358
- if (!args['holderId'])
359
- throw new Error('holderId is required');
360
- try {
361
- const caveats = buildCaveats(args);
362
- const { grant } = await client(env).attenuateGrant({
363
- grantId,
364
- holderId: args['holderId'],
365
- caveats,
366
- });
367
- return {
368
- grantId: grant?.grantId || null,
369
- parentGrantId: grant?.parentGrantId || grantId,
370
- holderId: grant?.holderId || args['holderId'],
371
- caveats: grant?.caveats || caveats,
372
- expiresAt: grant?.expiresAt || null,
373
- };
374
- }
375
- catch (e) {
376
- rethrowWithContext(e, 'Failed to attenuate payment grant');
377
- }
378
- },
379
- };
380
- export const paymentRevokeGrantCapability = {
381
- key: 'payment_revoke_grant',
382
- names: { sdk: 'payment_revoke_grant', mcp: 'ziggs_payment_revoke_grant' },
383
- title: 'Revoke a spend grant',
384
- descriptions: {
385
- sdk: 'Revoke a payment grant (and its attenuated children). The holder can no longer spend under it.',
386
- mcp: 'Revoke a payment grant (and its attenuated children). The holder can no longer spend under it.',
387
- },
388
- annotation: 'destructive',
389
- params: {
390
- grantId: { type: 'string', required: true, description: 'Grant to revoke' },
391
- },
392
- handler: async (args, env) => {
393
- const grantId = args['grantId'];
394
- if (!grantId)
395
- throw new Error('grantId is required');
396
- try {
397
- const result = await client(env).revokeGrant(grantId);
398
- return { status: 'revoked', grantId, revoked: result?.revoked ?? null };
399
- }
400
- catch (e) {
401
- rethrowWithContext(e, 'Failed to revoke payment grant');
48
+ rethrowWithContext(e, 'Failed to read points balance');
402
49
  }
403
50
  },
404
51
  };
405
- // payment_list_grants stays retired; the wallet rail is part of the
406
- // unified grant_list capability (scopeKind: 'wallet'). Grant *mutations* stay
407
- // on the payment rail above.
408
52
  export const PAYMENT_CAPABILITIES = [
409
53
  paymentBalanceCapability,
410
- paymentTransferCapability,
411
- paymentWaitForApprovalCapability,
412
- paymentHoldCapability,
413
- paymentReleaseCapability,
414
- paymentResolveWalletCapability,
415
- paymentIssueGrantCapability,
416
- paymentAttenuateGrantCapability,
417
- paymentRevokeGrantCapability,
418
54
  ];
@@ -3,4 +3,4 @@
3
3
  * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
4
  * the rule from the validation error.
5
5
  */
6
- export declare const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = "REQUIRED on a direct proposal: name who does the work \u2014 your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a quest (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.";
6
+ export declare const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = "REQUIRED on a direct proposal: name who does the work \u2014 your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a request (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.";
@@ -3,4 +3,4 @@
3
3
  * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
4
  * the rule from the validation error.
5
5
  */
6
- export const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = 'REQUIRED on a direct proposal: name who does the work — your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a quest (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.';
6
+ export const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = 'REQUIRED on a direct proposal: name who does the work — your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a request (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.';