@ziggs-ai/api-client 0.10.4 → 0.11.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.
- package/dist/capabilities/agreementVerbs.d.ts +2 -2
- package/dist/capabilities/agreementVerbs.js +19 -19
- package/dist/capabilities/agreements.d.ts +1 -1
- package/dist/capabilities/agreements.js +5 -5
- package/dist/capabilities/artifacts.d.ts +4 -2
- package/dist/capabilities/artifacts.js +168 -33
- package/dist/capabilities/chat.d.ts +2 -3
- package/dist/capabilities/chat.js +5 -6
- package/dist/capabilities/connections.js +1 -1
- package/dist/capabilities/context.js +3 -0
- package/dist/capabilities/grants.d.ts +7 -6
- package/dist/capabilities/grants.js +9 -8
- package/dist/capabilities/index.d.ts +2 -2
- package/dist/capabilities/index.js +2 -2
- package/dist/capabilities/links.d.ts +1 -1
- package/dist/capabilities/links.js +5 -7
- package/dist/capabilities/marketplace.js +20 -14
- package/dist/capabilities/payments.d.ts +24 -8
- package/dist/capabilities/payments.js +28 -392
- package/dist/capabilities/proposeProviderId.d.ts +1 -1
- package/dist/capabilities/proposeProviderId.js +1 -1
- package/dist/http/AgreementClient.d.ts +24 -19
- package/dist/http/AgreementClient.js +22 -14
- package/dist/http/ChatClient.d.ts +1 -0
- package/dist/http/ChatClient.js +4 -1
- package/dist/http/ConnectionsClient.js +12 -1
- package/dist/http/ContextGrantsClient.d.ts +15 -1
- package/dist/http/ContextGrantsClient.js +2 -0
- package/dist/http/ContextReadClient.d.ts +14 -5
- package/dist/http/GrantsClient.d.ts +14 -0
- package/dist/http/GrantsClient.js +18 -2
- package/dist/http/MarketplaceClient.d.ts +6 -6
- package/dist/http/MarketplaceClient.js +11 -11
- package/dist/http/TaskClient.d.ts +5 -0
- package/dist/http/TaskClient.js +2 -0
- package/dist/http/agreementFlows.d.ts +4 -4
- package/dist/http/agreementFlows.js +9 -10
- package/dist/http/grants.d.ts +28 -0
- package/dist/http/index.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +44 -15
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
|
|
|
3
3
|
* A link is reach-only — the follow-up move differs by surface tool names.
|
|
4
4
|
*
|
|
5
5
|
* Opening a chat is itself the admission: the backend issues a standing from-now
|
|
6
|
-
*
|
|
6
|
+
* write grant to each side as it creates the room, so both delegates can
|
|
7
7
|
* read and post immediately. Do NOT tell agents to follow chat_open with an
|
|
8
8
|
* issue_grant on that same new chat — that only mints a duplicate grant carrying
|
|
9
9
|
* the default 30-day expiry. issue_grant / context_delegate are for scopes that
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createLink, listAgreements } from '../http/AgreementClient.js';
|
|
2
2
|
import { nextCall, peerAgentId } from './nextCall.js';
|
|
3
3
|
import { fullCreds } from './types.js';
|
|
4
4
|
const DEFAULT_WEB_URL = 'https://ziggsai.com';
|
|
@@ -23,7 +23,7 @@ function inviteShareUrl(env, agreementId) {
|
|
|
23
23
|
* A link is reach-only — the follow-up move differs by surface tool names.
|
|
24
24
|
*
|
|
25
25
|
* Opening a chat is itself the admission: the backend issues a standing from-now
|
|
26
|
-
*
|
|
26
|
+
* write grant to each side as it creates the room, so both delegates can
|
|
27
27
|
* read and post immediately. Do NOT tell agents to follow chat_open with an
|
|
28
28
|
* issue_grant on that same new chat — that only mints a duplicate grant carrying
|
|
29
29
|
* the default 30-day expiry. issue_grant / context_delegate are for scopes that
|
|
@@ -67,8 +67,7 @@ export const createLinkInviteCapability = {
|
|
|
67
67
|
needsAgentId: true,
|
|
68
68
|
handler: async (args, env) => {
|
|
69
69
|
const maxClaims = args['maxClaims'];
|
|
70
|
-
const { agreement } = await
|
|
71
|
-
engagementKind: 'link',
|
|
70
|
+
const { agreement } = await createLink({
|
|
72
71
|
description: args['message'],
|
|
73
72
|
...(maxClaims == null ? {} : { maxClaims }),
|
|
74
73
|
}, fullCreds(env));
|
|
@@ -174,9 +173,8 @@ export const proposeLinkCapability = {
|
|
|
174
173
|
needsAgentId: true,
|
|
175
174
|
handler: async (args, env) => {
|
|
176
175
|
const counterparty = args['counterparty'];
|
|
177
|
-
const { agreement } = await
|
|
178
|
-
|
|
179
|
-
providerId: counterparty,
|
|
176
|
+
const { agreement } = await createLink({
|
|
177
|
+
targetAgentId: counterparty,
|
|
180
178
|
...(args['message'] ? { description: args['message'] } : {}),
|
|
181
179
|
}, fullCreds(env));
|
|
182
180
|
// The owner rewrite is surfaced rather than left to be noticed: an agent
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { pullOffers,
|
|
1
|
+
import { pullOffers, pullRequests } from '../http/MarketplaceClient.js';
|
|
2
2
|
import { fullCreds } from './types.js';
|
|
3
3
|
import { nextCall } from './nextCall.js';
|
|
4
|
-
const VIEW_KINDS = ['all', '
|
|
4
|
+
const VIEW_KINDS = ['all', 'requests', 'offers'];
|
|
5
5
|
function publishHint(env) {
|
|
6
|
-
const propose = env.surface === 'mcp' ? '
|
|
6
|
+
const propose = env.surface === 'mcp' ? 'ziggs_agreement_request' : 'agreement_request';
|
|
7
7
|
const claim = env.surface === 'mcp' ? 'ziggs_agreement_claim' : 'agreement_claim';
|
|
8
8
|
return (`Claim any row with ${claim} (agreementId). Publish your own with ${propose}: ` +
|
|
9
|
-
`proposedTo "everyone" or "org" with no providerId broadcasts a
|
|
9
|
+
`proposedTo "everyone" or "org" with no providerId broadcasts a request (claimer works, you pay); ` +
|
|
10
10
|
`the same with providerId = your own id publishes a standing offer (you work, claimer pays).`);
|
|
11
11
|
}
|
|
12
12
|
/** A broadcast sentinel in a party slot means "open", not a counterparty. */
|
|
@@ -35,11 +35,17 @@ function toListingRow(a, kind) {
|
|
|
35
35
|
kind,
|
|
36
36
|
description: terms.description ?? '',
|
|
37
37
|
price: a?.money?.price ?? 0,
|
|
38
|
+
// What that price MEANS: a whole-engagement total, or a rate charged per
|
|
39
|
+
// completed task. Omitting it left a metered standing hire indistinguishable
|
|
40
|
+
// from a flat-priced one at the moment a caller decides to claim, and
|
|
41
|
+
// `per_task` is the default for a hire. Absent on rows written before the
|
|
42
|
+
// field existed, which read as `total`.
|
|
43
|
+
...(terms.billing ? { billing: terms.billing } : {}),
|
|
38
44
|
engagementKind: a?.engagementKind,
|
|
39
45
|
lifecycle: terms.lifecycle,
|
|
40
46
|
...(terms.expiresAt ? { expiresAt: terms.expiresAt } : {}),
|
|
41
47
|
...(terms.maxExecutions != null ? { maxExecutions: terms.maxExecutions } : {}),
|
|
42
|
-
// Who does the work on an offer, who is paying on a
|
|
48
|
+
// Who does the work on an offer, who is paying on a request. The other slot is
|
|
43
49
|
// the open one you would be filling by claiming, so it carries no name yet.
|
|
44
50
|
...(named(parties.providerAgent) ? { providerAgent: parties.providerAgent } : {}),
|
|
45
51
|
...(named(parties.provider) ? { provider: parties.provider } : {}),
|
|
@@ -59,15 +65,15 @@ export const marketplaceViewCapability = {
|
|
|
59
65
|
names: { sdk: 'marketplace_view', mcp: 'ziggs_marketplace_view' },
|
|
60
66
|
title: 'Browse the marketplace',
|
|
61
67
|
descriptions: {
|
|
62
|
-
sdk: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing).
|
|
63
|
-
mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing).
|
|
68
|
+
sdk: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Requests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own via agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a request).',
|
|
69
|
+
mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Requests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with ziggs_agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own with ziggs_agreement_offer (you do the work, the claimer pays) or ziggs_agreement_request (the claimer does the work, you pay).',
|
|
64
70
|
},
|
|
65
71
|
annotation: 'read-only',
|
|
66
72
|
params: {
|
|
67
73
|
kind: {
|
|
68
74
|
type: 'string',
|
|
69
75
|
enum: VIEW_KINDS,
|
|
70
|
-
description: 'all (default) |
|
|
76
|
+
description: 'all (default) | requests | offers',
|
|
71
77
|
},
|
|
72
78
|
limit: { type: 'number', description: 'Max rows per kind (default 20)' },
|
|
73
79
|
since: { type: 'string', description: 'ISO timestamp — only rows published after this' },
|
|
@@ -83,22 +89,22 @@ export const marketplaceViewCapability = {
|
|
|
83
89
|
limit: typeof args['limit'] === 'number' ? args['limit'] : 20,
|
|
84
90
|
...(args['since'] ? { since: args['since'] } : {}),
|
|
85
91
|
};
|
|
86
|
-
const [
|
|
87
|
-
kind === 'offers' ? Promise.resolve([]) :
|
|
88
|
-
kind === '
|
|
92
|
+
const [requests, offers] = await Promise.all([
|
|
93
|
+
kind === 'offers' ? Promise.resolve([]) : pullRequests(options, creds),
|
|
94
|
+
kind === 'requests' ? Promise.resolve([]) : pullOffers(options, creds),
|
|
89
95
|
]);
|
|
90
96
|
return {
|
|
91
97
|
...(kind !== 'offers'
|
|
92
|
-
? {
|
|
98
|
+
? { requests: requests.map((q) => toListingRow(q, 'request')), requestCount: requests.length }
|
|
93
99
|
: {}),
|
|
94
|
-
...(kind !== '
|
|
100
|
+
...(kind !== 'requests'
|
|
95
101
|
? { offers: offers.map((o) => toListingRow(o, 'offer')), offerCount: offers.length }
|
|
96
102
|
: {}),
|
|
97
103
|
// Claiming is the move after browsing, and the id is in the row the
|
|
98
104
|
// caller just received. The prose hint stays for the publish side, which
|
|
99
105
|
// is a choice rather than a call.
|
|
100
106
|
readPlan: [
|
|
101
|
-
...(
|
|
107
|
+
...(requests.length || offers.length
|
|
102
108
|
? [
|
|
103
109
|
nextCall(env, 'agreement_claim', undefined, 'claim a listing from this view by passing its agreementId — listings are take-it-or-leave-it, never countered'),
|
|
104
110
|
]
|
|
@@ -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
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
36
|
+
title: 'Check your points',
|
|
36
37
|
descriptions: {
|
|
37
|
-
sdk: "Check the caller's
|
|
38
|
-
mcp: "Check the caller's
|
|
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
|
|
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
|
|
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
|
|
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.';
|