@ziggs-ai/api-client 0.9.12 → 0.10.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/dist/capabilities/agreementVerbs.d.ts +8 -0
- package/dist/capabilities/agreementVerbs.js +305 -0
- package/dist/capabilities/agreements.js +1 -0
- package/dist/capabilities/artifacts.js +21 -3
- package/dist/capabilities/chat.js +3 -2
- package/dist/capabilities/connections.js +2 -0
- package/dist/capabilities/context.js +4 -0
- package/dist/capabilities/discovery.js +3 -1
- package/dist/capabilities/grants.js +1 -0
- package/dist/capabilities/index.d.ts +3 -1
- package/dist/capabilities/index.js +3 -1
- package/dist/capabilities/links.d.ts +10 -0
- package/dist/capabilities/links.js +80 -7
- package/dist/capabilities/marketplace.js +14 -2
- package/dist/capabilities/nextCall.d.ts +44 -0
- package/dist/capabilities/nextCall.js +32 -0
- package/dist/capabilities/payments.js +9 -0
- package/dist/capabilities/types.d.ts +9 -0
- package/dist/http/ArtifactsClient.d.ts +8 -0
- package/dist/http/ArtifactsClient.js +18 -1
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CapabilityDefinition } from './types.js';
|
|
2
|
+
export declare const agreementCommissionCapability: CapabilityDefinition;
|
|
3
|
+
export declare const agreementBidCapability: CapabilityDefinition;
|
|
4
|
+
export declare const agreementBrokerCapability: CapabilityDefinition;
|
|
5
|
+
export declare const agreementQuestCapability: CapabilityDefinition;
|
|
6
|
+
export declare const agreementOfferCapability: CapabilityDefinition;
|
|
7
|
+
export declare const agreementHandoffCapability: CapabilityDefinition;
|
|
8
|
+
export declare const AGREEMENT_VERB_CAPABILITIES: CapabilityDefinition[];
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { getAgreement, proposeBroadcast, proposeDirectTo, } from '../http/AgreementClient.js';
|
|
2
|
+
import { publishOffer } from '../http/MarketplaceClient.js';
|
|
3
|
+
import { fullCreds } from './types.js';
|
|
4
|
+
import { nextCall } from './nextCall.js';
|
|
5
|
+
/**
|
|
6
|
+
* One verb per shape of agreement, instead of one verb and a dispatch table.
|
|
7
|
+
*
|
|
8
|
+
* `agreement_propose` computed which of nine shapes you meant from a
|
|
9
|
+
* combination of `proposedTo`, `providerId`, `parentAgreementId` and
|
|
10
|
+
* `engagementKind`, then spent 420 words of description teaching a caller to
|
|
11
|
+
* reconstruct that same table in its head so it could pick the params that
|
|
12
|
+
* produced the shape it already knew it wanted. Roughly a tenth of the whole
|
|
13
|
+
* tool surface was one tool, and most of that tenth explained `providerId`
|
|
14
|
+
* permutations.
|
|
15
|
+
*
|
|
16
|
+
* The direction of work is in the verb name now, so `providerId` survives on
|
|
17
|
+
* exactly one verb — `agreement_broker` — where naming a third-party provider
|
|
18
|
+
* is the entire point rather than a puzzle. Every shape the old dispatch could
|
|
19
|
+
* reach still has a verb: nothing was dropped to make the list shorter.
|
|
20
|
+
*
|
|
21
|
+
* The count goes up, from one tool to six. That is the trade on purpose: the
|
|
22
|
+
* cost was never the number of tools, it was the number of decisions per call.
|
|
23
|
+
*/
|
|
24
|
+
/** Terms every commercial agreement carries, whoever works and whoever pays. */
|
|
25
|
+
const TERMS_PARAMS = {
|
|
26
|
+
description: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
required: true,
|
|
29
|
+
description: 'What the work is, in the words the counterparty will read.',
|
|
30
|
+
},
|
|
31
|
+
price: {
|
|
32
|
+
type: 'number',
|
|
33
|
+
description: 'Amount in CENTS — 500 means $5.00, and ϟ5.00 in the UI. Optional; recording a price does not itself move money. Convert BOTH ways or you are off by 100x: a human who says "ϟ2" means 200, and quoting 500 back as "ϟ500" is the same mistake inverted.',
|
|
34
|
+
},
|
|
35
|
+
billing: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
enum: ['total', 'per_task'],
|
|
38
|
+
description: 'How price reads. total (default) is one price for the whole engagement, settled at fulfilment; per_task is a rate settled as each task completes (standing agreements only, and the default for a hire).',
|
|
39
|
+
},
|
|
40
|
+
engagementKind: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
enum: ['service', 'hire'],
|
|
43
|
+
description: 'service (default) is one deliverable; hire is an ongoing engagement you keep spawning tasks under.',
|
|
44
|
+
},
|
|
45
|
+
lifecycle: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'open (default) is standing: no expiry, unlimited tasks. Set this only when the engagement should end on its own.',
|
|
48
|
+
},
|
|
49
|
+
expiresAt: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'ISO timestamp after which this can no longer be acted on.',
|
|
52
|
+
},
|
|
53
|
+
maxExecutions: {
|
|
54
|
+
type: 'number',
|
|
55
|
+
description: 'End the engagement after this many tasks.',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
/** Pull the shared terms off a validated arg bag. */
|
|
59
|
+
function termsFrom(args) {
|
|
60
|
+
return {
|
|
61
|
+
description: args['description'],
|
|
62
|
+
...(args['price'] === undefined ? {} : { price: args['price'] }),
|
|
63
|
+
...(args['billing'] === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: { billing: args['billing'] }),
|
|
66
|
+
...(args['lifecycle'] === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { lifecycle: args['lifecycle'] }),
|
|
69
|
+
...(args['expiresAt'] === undefined
|
|
70
|
+
? {}
|
|
71
|
+
: { expiresAt: args['expiresAt'] }),
|
|
72
|
+
...(args['maxExecutions'] === undefined
|
|
73
|
+
? {}
|
|
74
|
+
: { maxExecutions: args['maxExecutions'] }),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function engagementKindFrom(args) {
|
|
78
|
+
return args['engagementKind'] ?? 'service';
|
|
79
|
+
}
|
|
80
|
+
/** The audience a broadcast reaches. */
|
|
81
|
+
const AUDIENCE_PARAM = {
|
|
82
|
+
type: 'string',
|
|
83
|
+
enum: ['everyone', 'org'],
|
|
84
|
+
required: true,
|
|
85
|
+
description: 'everyone is fully public; org is your active organisation only.',
|
|
86
|
+
};
|
|
87
|
+
const COUNTERPARTY_PARAM = {
|
|
88
|
+
type: 'string',
|
|
89
|
+
required: true,
|
|
90
|
+
description: 'Agent or user id of the counterparty.',
|
|
91
|
+
};
|
|
92
|
+
const CHAT_PARAM = {
|
|
93
|
+
type: 'string',
|
|
94
|
+
required: true,
|
|
95
|
+
description: 'The room this is proposed in — the counterparty reads it there.',
|
|
96
|
+
};
|
|
97
|
+
/** Marketplace follow-up: a published listing is claimed, never countered. */
|
|
98
|
+
function publishedNext(env) {
|
|
99
|
+
return [
|
|
100
|
+
nextCall(env, 'marketplace_view', undefined, 'see it listed alongside everything else on offer'),
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
/* ─────────────────────────── direct, to one counterparty ─────────────────── */
|
|
104
|
+
export const agreementCommissionCapability = {
|
|
105
|
+
key: 'agreement_commission',
|
|
106
|
+
names: { sdk: 'agreement_commission', mcp: 'ziggs_agreement_commission' },
|
|
107
|
+
title: 'Commission a counterparty',
|
|
108
|
+
descriptions: {
|
|
109
|
+
sdk: 'Ask a named counterparty to do work your side pays for. They provide, you pay. For work you would do for them instead, use agreement_bid; to reach whoever is available rather than someone named, use agreement_quest.',
|
|
110
|
+
mcp: 'Ask a named counterparty to do work your side pays for: they provide, you pay. Prefer claiming their listing first if they have one (ziggs_marketplace_view then ziggs_agreement_claim) — listings are take-it-or-leave-it and most published agents refuse direct proposals. Use this for bespoke terms, renegotiation, or a counterparty with no listing. For work you would do for them, use ziggs_agreement_bid; to reach whoever is available, use ziggs_agreement_quest.',
|
|
111
|
+
},
|
|
112
|
+
annotation: 'write',
|
|
113
|
+
params: {
|
|
114
|
+
counterparty: COUNTERPARTY_PARAM,
|
|
115
|
+
chatId: CHAT_PARAM,
|
|
116
|
+
...TERMS_PARAMS,
|
|
117
|
+
},
|
|
118
|
+
needsAgentId: true,
|
|
119
|
+
handler: async (args, env) => {
|
|
120
|
+
const counterparty = args['counterparty'];
|
|
121
|
+
const agreement = await proposeDirectTo({
|
|
122
|
+
...termsFrom(args),
|
|
123
|
+
proposedTo: counterparty,
|
|
124
|
+
chatId: args['chatId'],
|
|
125
|
+
// They provide. The payer is derived server-side as the other side.
|
|
126
|
+
providerId: counterparty,
|
|
127
|
+
engagementKind: engagementKindFrom(args),
|
|
128
|
+
}, fullCreds(env));
|
|
129
|
+
return { agreement };
|
|
130
|
+
},
|
|
131
|
+
sdkOptions: { isAgreementCreation: true },
|
|
132
|
+
};
|
|
133
|
+
export const agreementBidCapability = {
|
|
134
|
+
key: 'agreement_bid',
|
|
135
|
+
names: { sdk: 'agreement_bid', mcp: 'ziggs_agreement_bid' },
|
|
136
|
+
title: 'Offer to work for a counterparty',
|
|
137
|
+
descriptions: {
|
|
138
|
+
sdk: 'Offer to do work for a named counterparty, who pays. You provide. To publish the same offer to whoever wants it rather than one named party, use agreement_offer.',
|
|
139
|
+
mcp: 'Offer to do work for a named counterparty, who pays: you provide. This is the direct form of a listing — to publish the same offer to whoever wants it, use ziggs_agreement_offer instead. To ask someone else to do work you pay for, use ziggs_agreement_commission.',
|
|
140
|
+
},
|
|
141
|
+
annotation: 'write',
|
|
142
|
+
params: {
|
|
143
|
+
counterparty: COUNTERPARTY_PARAM,
|
|
144
|
+
chatId: CHAT_PARAM,
|
|
145
|
+
...TERMS_PARAMS,
|
|
146
|
+
},
|
|
147
|
+
needsAgentId: true,
|
|
148
|
+
handler: async (args, env) => {
|
|
149
|
+
const creds = fullCreds(env);
|
|
150
|
+
const agreement = await proposeDirectTo({
|
|
151
|
+
...termsFrom(args),
|
|
152
|
+
proposedTo: args['counterparty'],
|
|
153
|
+
chatId: args['chatId'],
|
|
154
|
+
// You provide, so the counterparty pays.
|
|
155
|
+
providerId: creds.agentId,
|
|
156
|
+
engagementKind: engagementKindFrom(args),
|
|
157
|
+
}, creds);
|
|
158
|
+
return { agreement };
|
|
159
|
+
},
|
|
160
|
+
sdkOptions: { isAgreementCreation: true },
|
|
161
|
+
};
|
|
162
|
+
export const agreementBrokerCapability = {
|
|
163
|
+
key: 'agreement_broker',
|
|
164
|
+
names: { sdk: 'agreement_broker', mcp: 'ziggs_agreement_broker' },
|
|
165
|
+
title: 'Broker work between two other parties',
|
|
166
|
+
descriptions: {
|
|
167
|
+
sdk: 'Introduce a provider to a customer: the provider does the work, the counterparty pays, and neither side is you. The provider must already have a matching active offer.',
|
|
168
|
+
mcp: 'Introduce a provider to a customer: the named provider does the work, the counterparty pays, and you are neither. The provider needs a matching active offer for this to stand. This is the one verb where naming a provider is the point — every other agreement verb infers it from the direction of work.',
|
|
169
|
+
},
|
|
170
|
+
annotation: 'write',
|
|
171
|
+
params: {
|
|
172
|
+
counterparty: {
|
|
173
|
+
...COUNTERPARTY_PARAM,
|
|
174
|
+
description: 'Who the work is done for, and who pays.',
|
|
175
|
+
},
|
|
176
|
+
provider: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
required: true,
|
|
179
|
+
description: 'Agent id of the party who does the work.',
|
|
180
|
+
},
|
|
181
|
+
chatId: CHAT_PARAM,
|
|
182
|
+
...TERMS_PARAMS,
|
|
183
|
+
},
|
|
184
|
+
needsAgentId: true,
|
|
185
|
+
handler: async (args, env) => {
|
|
186
|
+
const agreement = await proposeDirectTo({
|
|
187
|
+
...termsFrom(args),
|
|
188
|
+
proposedTo: args['counterparty'],
|
|
189
|
+
chatId: args['chatId'],
|
|
190
|
+
providerId: args['provider'],
|
|
191
|
+
engagementKind: engagementKindFrom(args),
|
|
192
|
+
}, fullCreds(env));
|
|
193
|
+
return { agreement };
|
|
194
|
+
},
|
|
195
|
+
sdkOptions: { isAgreementCreation: true },
|
|
196
|
+
};
|
|
197
|
+
/* ──────────────────────────────── broadcast ──────────────────────────────── */
|
|
198
|
+
export const agreementQuestCapability = {
|
|
199
|
+
key: 'agreement_quest',
|
|
200
|
+
names: { sdk: 'agreement_quest', mcp: 'ziggs_agreement_quest' },
|
|
201
|
+
title: 'Post a quest',
|
|
202
|
+
descriptions: {
|
|
203
|
+
sdk: 'Post work you want done and will pay for, for whoever claims it. Whoever claims does the work. To offer work you would do instead, use agreement_offer.',
|
|
204
|
+
mcp: 'Post work you want done and will pay for: whoever claims it does the work. Use this when nothing already listed fits, rather than proposing to named counterparties one at a time. To offer work you would do, use ziggs_agreement_offer. Claimable via ziggs_agreement_claim; visible in ziggs_marketplace_view.',
|
|
205
|
+
},
|
|
206
|
+
annotation: 'write',
|
|
207
|
+
params: { audience: AUDIENCE_PARAM, ...TERMS_PARAMS },
|
|
208
|
+
needsAgentId: true,
|
|
209
|
+
handler: async (args, env) => {
|
|
210
|
+
const agreement = await proposeBroadcast({
|
|
211
|
+
...termsFrom(args),
|
|
212
|
+
chatId: '',
|
|
213
|
+
audience: args['audience'],
|
|
214
|
+
engagementKind: engagementKindFrom(args),
|
|
215
|
+
}, fullCreds(env));
|
|
216
|
+
return { agreement, readPlan: publishedNext(env) };
|
|
217
|
+
},
|
|
218
|
+
sdkOptions: { isAgreementCreation: true },
|
|
219
|
+
};
|
|
220
|
+
export const agreementOfferCapability = {
|
|
221
|
+
key: 'agreement_offer',
|
|
222
|
+
names: { sdk: 'agreement_offer', mcp: 'ziggs_agreement_offer' },
|
|
223
|
+
title: 'Publish a standing offer',
|
|
224
|
+
descriptions: {
|
|
225
|
+
sdk: 'Publish work you will do, for whoever claims it and pays. You provide. This is your listing: it stands until revoked or exhausted. To offer one named counterparty instead, use agreement_bid.',
|
|
226
|
+
mcp: 'Publish work you will do, for whoever claims it and pays: you provide. This is your listing — it stands until revoked or exhausted, and claimers take it as posted rather than countering it. To offer one named counterparty instead, use ziggs_agreement_bid. To ask for work rather than supply it, use ziggs_agreement_quest.',
|
|
227
|
+
},
|
|
228
|
+
annotation: 'write',
|
|
229
|
+
params: { audience: AUDIENCE_PARAM, ...TERMS_PARAMS },
|
|
230
|
+
needsAgentId: true,
|
|
231
|
+
handler: async (args, env) => {
|
|
232
|
+
const terms = termsFrom(args);
|
|
233
|
+
const agreement = await publishOffer({
|
|
234
|
+
description: terms.description ?? '',
|
|
235
|
+
price: terms.price,
|
|
236
|
+
lifecycle: terms.lifecycle,
|
|
237
|
+
expiresAt: terms.expiresAt,
|
|
238
|
+
maxExecutions: terms.maxExecutions,
|
|
239
|
+
billing: terms.billing,
|
|
240
|
+
engagementKind: engagementKindFrom(args),
|
|
241
|
+
audience: args['audience'],
|
|
242
|
+
}, fullCreds(env));
|
|
243
|
+
return { agreement, readPlan: publishedNext(env) };
|
|
244
|
+
},
|
|
245
|
+
sdkOptions: { isAgreementCreation: true },
|
|
246
|
+
};
|
|
247
|
+
/* ──────────────────────────────── hand-off ───────────────────────────────── */
|
|
248
|
+
export const agreementHandoffCapability = {
|
|
249
|
+
key: 'agreement_handoff',
|
|
250
|
+
names: { sdk: 'agreement_handoff', mcp: 'ziggs_agreement_handoff' },
|
|
251
|
+
title: 'Hand off an agent you hired',
|
|
252
|
+
descriptions: {
|
|
253
|
+
sdk: 'Share an agent you have hired: the provider stays pinned, and whoever claims or approves becomes the customer the work is done for. Omit `to` to make it claimable by anyone. Handing off someone else\'s agent leaves that provider\'s approval pending — it must accept once before the hand-off can be claimed.',
|
|
254
|
+
mcp: 'Share an agent you have hired: the provider stays pinned, and whoever claims or approves is the CUSTOMER the work is done for, never the worker. Omit `to` to publish it claimable; name `to` and that party approves directly. On a priced hand-off the claimer is also the payer; omit price (or 0) and nobody is billed for their tasks. Handing off someone else\'s agent leaves that provider\'s approval pending — it must accept once before the hand-off can be claimed. The provider is read from the parent hire, so you do not pass it.',
|
|
255
|
+
},
|
|
256
|
+
annotation: 'write',
|
|
257
|
+
params: {
|
|
258
|
+
parentAgreementId: {
|
|
259
|
+
type: 'string',
|
|
260
|
+
required: true,
|
|
261
|
+
description: 'The ACTIVE hire you are handing off.',
|
|
262
|
+
},
|
|
263
|
+
to: {
|
|
264
|
+
type: 'string',
|
|
265
|
+
description: 'Who receives it. Omit to publish it claimable by anyone; name a party and they approve directly.',
|
|
266
|
+
},
|
|
267
|
+
...TERMS_PARAMS,
|
|
268
|
+
description: {
|
|
269
|
+
type: 'string',
|
|
270
|
+
description: 'What the recipient is getting. Defaults to the parent hire.',
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
needsAgentId: true,
|
|
274
|
+
handler: async (args, env) => {
|
|
275
|
+
const creds = fullCreds(env);
|
|
276
|
+
const parentAgreementId = args['parentAgreementId'];
|
|
277
|
+
// Read the provider off the parent instead of asking for it. The caller
|
|
278
|
+
// would have had to look it up to pass it, and a lookup whose answer is
|
|
279
|
+
// unique is not a decision worth handing to the caller.
|
|
280
|
+
const parent = await getAgreement(parentAgreementId, creds);
|
|
281
|
+
const providerId = parent?.parties?.providerAgent;
|
|
282
|
+
if (!providerId) {
|
|
283
|
+
throw new Error(`Cannot hand off ${parentAgreementId}: it names no provider, so there is no hire to share. Check the id with agreement_get.`);
|
|
284
|
+
}
|
|
285
|
+
const terms = {
|
|
286
|
+
...termsFrom(args),
|
|
287
|
+
description: args['description'] ?? parent.description ?? '',
|
|
288
|
+
parentAgreementId,
|
|
289
|
+
};
|
|
290
|
+
const to = args['to'];
|
|
291
|
+
const agreement = to
|
|
292
|
+
? await proposeDirectTo({ ...terms, proposedTo: to, chatId: '', providerId, engagementKind: 'hire' }, creds)
|
|
293
|
+
: await proposeBroadcast({ ...terms, chatId: '', audience: 'everyone', providerId, engagementKind: 'hire' }, creds);
|
|
294
|
+
return { agreement, ...(to ? {} : { readPlan: publishedNext(env) }) };
|
|
295
|
+
},
|
|
296
|
+
sdkOptions: { isAgreementCreation: true },
|
|
297
|
+
};
|
|
298
|
+
export const AGREEMENT_VERB_CAPABILITIES = [
|
|
299
|
+
agreementCommissionCapability,
|
|
300
|
+
agreementBidCapability,
|
|
301
|
+
agreementBrokerCapability,
|
|
302
|
+
agreementQuestCapability,
|
|
303
|
+
agreementOfferCapability,
|
|
304
|
+
agreementHandoffCapability,
|
|
305
|
+
];
|
|
@@ -9,6 +9,7 @@ import { fullCreds } from './types.js';
|
|
|
9
9
|
export const agreementClaimCapability = {
|
|
10
10
|
key: 'agreement_claim',
|
|
11
11
|
names: { sdk: 'agreement_claim', mcp: 'ziggs_agreement_claim' },
|
|
12
|
+
title: 'Claim a posted agreement',
|
|
12
13
|
descriptions: {
|
|
13
14
|
sdk: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim, activation is instant, no negotiation turns. Claims a quest (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced), or a link invite (bilateral trust forms immediately). You become the open party and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with agreement_respond instead, not claimed.',
|
|
14
15
|
mcp: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim, activation is instant, no negotiation turns. Claims a quest (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced), or a link invite (bilateral trust forms immediately). You become the open party and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with ziggs_marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with ziggs_agreement_respond instead, not claimed. You cannot claim your own broadcast.',
|
|
@@ -17,24 +17,35 @@ function reportingHint(env, contentType, taskId) {
|
|
|
17
17
|
}
|
|
18
18
|
return `Reporting finished work? Record it with contentType=result bound to the task (taskId), then close the task with ${close} — chat messages are conversation only.`;
|
|
19
19
|
}
|
|
20
|
+
/** ZIG-1320 — inline body cap + escape hatch, shared by SDK/MCP descriptions. */
|
|
21
|
+
const ARTIFACT_RECORD_INLINE_CAP = 'Inline text max 50000 characters. Over that: use ziggs_artifact_upload_url ' +
|
|
22
|
+
'(file rail), or record an index artifact plus part artifacts and list the ' +
|
|
23
|
+
'part ids in the index. The server does not auto-split.';
|
|
20
24
|
export const recordArtifactCapability = {
|
|
21
25
|
key: 'artifact_record',
|
|
22
26
|
names: { sdk: 'artifact_record', mcp: 'ziggs_artifact_record' },
|
|
27
|
+
title: 'Record an artifact',
|
|
23
28
|
descriptions: {
|
|
24
29
|
sdk: 'Write an artifact. Scope is optional: pass agreementId or chatId to record it there, ' +
|
|
25
30
|
'or pass no scope at all to record it as yours alone and attach it somewhere later. ' +
|
|
26
31
|
'Set visibility explicitly. For a finished deliverable, set contentType=result and pass ' +
|
|
27
|
-
'taskId to bind it to the task — heavy results belong in artifacts, not chat messages.'
|
|
32
|
+
'taskId to bind it to the task — heavy results belong in artifacts, not chat messages. ' +
|
|
33
|
+
ARTIFACT_RECORD_INLINE_CAP,
|
|
28
34
|
mcp: 'Write an artifact. Scope is optional — pass agreementId or chatId to record it into that ' +
|
|
29
35
|
'scope, pass taskId alone to bind a deliverable to its task, or pass no scope at all for a ' +
|
|
30
36
|
'free-standing artifact that is yours until you attach or share it. Never guess a scope: ' +
|
|
31
37
|
'recording with none always succeeds. Set visibility explicitly. ' +
|
|
32
38
|
'For a finished deliverable, set contentType=result and pass taskId to bind it to the task. ' +
|
|
33
|
-
'Finished work is the task result — set it with ziggs_task_set_result; never report finished work as a chat message (chat is conversation only).'
|
|
39
|
+
'Finished work is the task result — set it with ziggs_task_set_result; never report finished work as a chat message (chat is conversation only). ' +
|
|
40
|
+
ARTIFACT_RECORD_INLINE_CAP,
|
|
34
41
|
},
|
|
35
42
|
annotation: 'write',
|
|
36
43
|
params: {
|
|
37
|
-
text: {
|
|
44
|
+
text: {
|
|
45
|
+
type: 'string',
|
|
46
|
+
required: true,
|
|
47
|
+
description: 'Artifact body (max 50000 chars). Over limit: ziggs_artifact_upload_url or index+parts.',
|
|
48
|
+
},
|
|
38
49
|
visibility: {
|
|
39
50
|
type: 'string',
|
|
40
51
|
required: true,
|
|
@@ -111,6 +122,7 @@ export const recordArtifactCapability = {
|
|
|
111
122
|
export const listArtifactsCapability = {
|
|
112
123
|
key: 'artifact_list',
|
|
113
124
|
names: { sdk: 'artifact_list', mcp: 'ziggs_artifact_list' },
|
|
125
|
+
title: 'List artifacts you wrote',
|
|
114
126
|
descriptions: {
|
|
115
127
|
sdk: 'List artifacts you authored, in any scope or none — including free-standing ones no scope read can reach. Forward-delta with `after`.',
|
|
116
128
|
mcp: 'List artifacts YOU authored, across every scope and none. Use this to find something you ' +
|
|
@@ -148,6 +160,7 @@ export const listArtifactsCapability = {
|
|
|
148
160
|
export const shareArtifactCapability = {
|
|
149
161
|
key: 'artifact_share',
|
|
150
162
|
names: { sdk: 'artifact_share', mcp: 'ziggs_artifact_share' },
|
|
163
|
+
title: 'Share an artifact',
|
|
151
164
|
descriptions: {
|
|
152
165
|
sdk: 'Share an artifact you authored with another agent — just that artifact, no chat or agreement. An agent already connected to you (same owner, same org, or an active link) gets it immediately; anyone else is offered to your owner to approve.',
|
|
153
166
|
mcp: 'Share ONE artifact you authored with another agent, without sharing any chat or agreement ' +
|
|
@@ -214,6 +227,7 @@ export const shareArtifactCapability = {
|
|
|
214
227
|
export const attachArtifactCapability = {
|
|
215
228
|
key: 'artifact_attach',
|
|
216
229
|
names: { sdk: 'artifact_attach', mcp: 'ziggs_artifact_attach' },
|
|
230
|
+
title: 'Attach an artifact to a chat or task',
|
|
217
231
|
descriptions: {
|
|
218
232
|
sdk: 'Attach an artifact you can read to a chat or a task. Everyone in that chat / party to that task can read it from then on. Use artifact_share to give it to one specific agent instead.',
|
|
219
233
|
mcp: 'Attach an existing artifact to a chat or a task — the way a free-standing artifact (one you ' +
|
|
@@ -276,6 +290,7 @@ export const attachArtifactCapability = {
|
|
|
276
290
|
export const uploadArtifactUrlCapability = {
|
|
277
291
|
key: 'artifact_upload_url',
|
|
278
292
|
names: { sdk: 'artifact_upload_url', mcp: 'ziggs_artifact_upload_url' },
|
|
293
|
+
title: 'Start a file upload',
|
|
279
294
|
descriptions: {
|
|
280
295
|
sdk: 'Start a file artifact upload. Returns a short-lived uploadUrl. PUT the exact ' +
|
|
281
296
|
'byteSize bytes to that URL (Content-Type = mime), then call artifact_complete_file ' +
|
|
@@ -372,6 +387,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
372
387
|
export const completeArtifactFileCapability = {
|
|
373
388
|
key: 'artifact_complete_file',
|
|
374
389
|
names: { sdk: 'artifact_complete_file', mcp: 'ziggs_artifact_complete_file' },
|
|
390
|
+
title: 'Finish a file upload',
|
|
375
391
|
descriptions: {
|
|
376
392
|
sdk: 'Finish a file upload after the S3 PUT. Pass artifactId + sha256 hex of the bytes ' +
|
|
377
393
|
'you uploaded. Sets extractionStatus=pending and enqueues extract. Poll artifact_list ' +
|
|
@@ -410,6 +426,7 @@ export const completeArtifactFileCapability = {
|
|
|
410
426
|
export const downloadArtifactCapability = {
|
|
411
427
|
key: 'artifact_download',
|
|
412
428
|
names: { sdk: 'artifact_download', mcp: 'ziggs_artifact_download' },
|
|
429
|
+
title: 'Download a file artifact',
|
|
413
430
|
descriptions: {
|
|
414
431
|
sdk: 'Get a short-lived (60s) presigned download URL for a file artifact you can read. ' +
|
|
415
432
|
'Returns downloadUrl, expiresAt, filename — fetch the URL yourself; do not expect ' +
|
|
@@ -435,6 +452,7 @@ export const downloadArtifactCapability = {
|
|
|
435
452
|
export const reextractArtifactCapability = {
|
|
436
453
|
key: 'artifact_reextract',
|
|
437
454
|
names: { sdk: 'artifact_reextract', mcp: 'ziggs_artifact_reextract' },
|
|
455
|
+
title: 'Re-extract text from a file',
|
|
438
456
|
descriptions: {
|
|
439
457
|
sdk: 'Re-queue text extraction for a file artifact you authored when status is ok or failed ' +
|
|
440
458
|
'(pending → conflict). On success a new extracted-text row supersedes the previous one.',
|
|
@@ -11,9 +11,10 @@ import { fullCreds } from './types.js';
|
|
|
11
11
|
export const openConversationCapability = {
|
|
12
12
|
key: 'chat_open',
|
|
13
13
|
names: { sdk: 'chat_open', mcp: 'ziggs_chat_open' },
|
|
14
|
+
title: 'Open a chat',
|
|
14
15
|
descriptions: {
|
|
15
|
-
sdk: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat, so it is how you find the conversation you already have with someone — pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, establish a link first —
|
|
16
|
-
mcp: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat; pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, an unpublished agent must establish a link first —
|
|
16
|
+
sdk: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat, so it is how you find the conversation you already have with someone — pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, establish a link first — link_propose (if you have its agent id) or link_create_invite (if you do not), approved/claimed — otherwise this fails with AGENT_NOT_PUBLISHED. To list chats you can already read, use grant_list scopeKind=chat.',
|
|
17
|
+
mcp: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat; pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, an unpublished agent must establish a link first — ziggs_link_propose (if you have its agent id) or ziggs_link_create_invite (if you do not), approved/claimed — otherwise this fails with AGENT_NOT_PUBLISHED.',
|
|
17
18
|
},
|
|
18
19
|
annotation: 'write',
|
|
19
20
|
params: {
|
|
@@ -9,6 +9,7 @@ function client(env) {
|
|
|
9
9
|
export const connectionProxyCapability = {
|
|
10
10
|
key: 'connection_proxy',
|
|
11
11
|
names: { sdk: 'connection_proxy', mcp: 'ziggs_connection_proxy' },
|
|
12
|
+
title: 'Use a stored connection',
|
|
12
13
|
descriptions: {
|
|
13
14
|
sdk: "Use a named-connector stored connection (e.g. the owner's GitHub/Jira) without ever seeing the credential. " +
|
|
14
15
|
'Calls the backend connections proxy with a grant the owner issued to this agent. ' +
|
|
@@ -55,6 +56,7 @@ export const connectionProxyCapability = {
|
|
|
55
56
|
export const requestConnectionCapability = {
|
|
56
57
|
key: 'connection_request',
|
|
57
58
|
names: { sdk: 'connection_request', mcp: 'ziggs_connection_request' },
|
|
59
|
+
title: 'Ask your principal for a connection',
|
|
58
60
|
descriptions: {
|
|
59
61
|
sdk: 'Ask your principal (the human) to connect a remote MCP server and grant you the listed tools. ' +
|
|
60
62
|
'Opens a connection-consent agreement as an approvable card in the chat you pass — the human approves it there like any other agreement. ' +
|
|
@@ -60,6 +60,7 @@ const ARTIFACT_VIA_NOTE = 'via=artifact:<id> is a point read of one named artifa
|
|
|
60
60
|
export const contextReadCapability = {
|
|
61
61
|
key: 'context_read',
|
|
62
62
|
names: { sdk: 'context_read', mcp: 'ziggs_context_read' },
|
|
63
|
+
title: 'Read context you hold',
|
|
63
64
|
descriptions: {
|
|
64
65
|
sdk: `Read the contents of a scope you already hold a grant for: ${CONTEXT_READ_TYPES.join(' | ')}. Each type reads through its own entries — ${VIA_BY_TYPE}. Use grant_list first to see which scopes your grants cover, then read through any of them. ${ARTIFACT_VIA_NOTE}. Cursored; all access is grant-fenced server-side.`,
|
|
65
66
|
mcp: `Read the contents of a scope you already hold: ${CONTEXT_READ_TYPES.join(' | ')} (the type param). Each type accepts its own via entries — ${VIA_BY_TYPE} — and any other pairing is refused. ${ARTIFACT_VIA_NOTE} (e.g. an artifact someone shared with you; ziggs_grant_list scopeKind=artifact shows those). Forward-delta with after+direction=forward; cursor pagination; contextGrantId pins a grant. The response carries a \`readPlan\` with the next page and/or forward-delta call pre-filled (after=this page's latestSequence), so you can keep reading without rebuilding args. This is the single read path for all four types — to discover which scopes exist, use the listers: ziggs_chat_list, ziggs_task_list, ziggs_agreement_list, ziggs_grant_list, ziggs_link_list.`,
|
|
@@ -129,6 +130,7 @@ export const contextReadCapability = {
|
|
|
129
130
|
export const contextExpandReachCapability = {
|
|
130
131
|
key: 'context_expand_reach',
|
|
131
132
|
names: { sdk: 'context_expand_reach', mcp: 'ziggs_context_expand_reach' },
|
|
133
|
+
title: 'See what a grant reaches',
|
|
132
134
|
descriptions: {
|
|
133
135
|
sdk: 'Expand a grant you hold into the chat/agreement ids inside its scope, so you can read through it. grant_list tells you that you hold e.g. org:acme or agreement:x; this returns the actual { chats, agreements } (ids + labels only, no content) that scope covers — feed an id to context_read (via=chat:<id> / agreement:<id>). Org scope is capped: truncatedChats/truncatedAgreements say how many were left off. An artifact-scope grant returns empty by design — the grant IS one artifact, so read it directly with context_read via=artifact:<the scope id>. Holder-only, grant-fenced.',
|
|
134
136
|
mcp: 'Expand a grant you hold into the chat/agreement ids inside its scope, so you can actually read through it. ziggs_grant_list tells you that you hold e.g. org:acme or agreement:x; this returns the { chats, agreements } (ids + labels only, never content) that scope covers — feed an id to ziggs_context_read (via=chat:<id> / agreement:<id>). Org scope is capped: truncatedChats/truncatedAgreements say how many were left off. An artifact-scope grant returns empty by design — that grant IS a single artifact, so do not read the empty map as a dead grant: read the artifact with ziggs_context_read via=artifact:<the scope id>. Holder-only, grant-fenced.',
|
|
@@ -153,6 +155,7 @@ export const contextExpandReachCapability = {
|
|
|
153
155
|
export const contextDiscoverGrantableCapability = {
|
|
154
156
|
key: 'context_discover_grantable',
|
|
155
157
|
names: { sdk: 'context_discover_grantable', mcp: 'ziggs_context_discover_grantable' },
|
|
158
|
+
title: 'Find context you cannot read yet',
|
|
156
159
|
descriptions: {
|
|
157
160
|
sdk: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — the inverse of grant_list. Covers chats, agreements, and connections (type is one of "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only ({ type, label, scopeRef, orgId } per item), never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org), and excludes anything you already hold a grant for. Use it to notice you may be missing context, then either ask your human to grant a scopeRef, or (if you hold a broader grant) context_delegate using that scopeRef. Pair with grant_list (what you hold) and context_expand_reach (what a held grant covers).',
|
|
158
161
|
mcp: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — so you can ask for it instead of failing blind. Covers chats, agreements, and connections (type is "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only: { type, label, scopeRef, orgId } per item, never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org). To act on one, ask your human to grant it, or (if you hold a broader grant of your own) delegate via ziggs_context_delegate using the scopeRef. Use ziggs_grant_list for what you already hold; this is what you lack.',
|
|
@@ -169,6 +172,7 @@ export const contextDiscoverGrantableCapability = {
|
|
|
169
172
|
export const contextDelegateCapability = {
|
|
170
173
|
key: 'context_delegate',
|
|
171
174
|
names: { sdk: 'context_delegate', mcp: 'ziggs_context_delegate' },
|
|
175
|
+
title: 'Pass on a narrower grant',
|
|
172
176
|
descriptions: {
|
|
173
177
|
sdk: 'Delegate a narrower child context grant (tighter scope, shorter expiry, or from-now). Holder-only. Delegating a grant whose original owner is another party opens an approval request rather than minting immediately (status: pending_approval).',
|
|
174
178
|
mcp: 'Delegate a narrower child grant from one you hold (POST /context/grants/:id/delegate). Delegation only narrows scope/expiry/temporal — never broadens. If the grant\'s original owner is a different party, this does NOT grant — it opens a request that owner must approve, and returns { status: "pending_approval", agreementId }; surface that to the human and do not treat it as done.',
|
|
@@ -3,9 +3,10 @@ import { fullCreds } from './types.js';
|
|
|
3
3
|
export const agentSearchCapability = {
|
|
4
4
|
key: 'agent_search',
|
|
5
5
|
names: { sdk: 'agent_search', mcp: 'ziggs_agent_search' },
|
|
6
|
+
title: 'Search for agents',
|
|
6
7
|
descriptions: {
|
|
7
8
|
sdk: 'Search for agents by capability, name, or description. Returns ranked results with relevance scores. A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with. Passing an EXACT agent id resolves that one agent even if unpublished/private. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Use returned agentId in grant/issue tools — do not guess ids.',
|
|
8
|
-
mcp: 'Find agents (AgentSearchClient). A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with — so you can find a teammate or another user\'s delegate by name and ziggs_chat_open with it directly, even if it is unpublished/offline and has never been in a chat with you. Passing an EXACT agent id resolves that one agent even if unpublished/private — use this for a delegate someone shared an id for, then propose a link (
|
|
9
|
+
mcp: 'Find agents (AgentSearchClient). A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with — so you can find a teammate or another user\'s delegate by name and ziggs_chat_open with it directly, even if it is unpublished/offline and has never been in a chat with you. Passing an EXACT agent id resolves that one agent even if unpublished/private — use this for a delegate someone shared an id for, then propose a link (ziggs_link_propose) if not yet linked. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (ziggs_agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Each result carries a per-row `reachability` field derived from HOW you can reach it — `published` (store directory), `same-org`, `linked`, or `managed`; it is not a blanket "published" label. If an exact-id lookup matches an unpublished agent you cannot reach, the row is `reachability: "restricted"` and returns the id only with no name/profile. Use returned agentId in grant/issue tools — do not guess ids.',
|
|
9
10
|
},
|
|
10
11
|
annotation: 'read-only',
|
|
11
12
|
params: {
|
|
@@ -49,6 +50,7 @@ export const agentSearchCapability = {
|
|
|
49
50
|
export const agentGetCapability = {
|
|
50
51
|
key: 'agent_get',
|
|
51
52
|
names: { sdk: 'agent_get', mcp: 'ziggs_agent_get' },
|
|
53
|
+
title: 'Read an agent profile',
|
|
52
54
|
descriptions: {
|
|
53
55
|
sdk: 'Fetch the full profile of a specific agent by ID — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm capabilities and terms before engaging, when you already hold the agent id. An id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use agent_search.',
|
|
54
56
|
mcp: 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM via ziggs_agreement_claim — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm a candidate before engaging, when you already hold the agent id (from ziggs_agent_search, a grant, or an agreement party). Grant-scoped: an id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use ziggs_agent_search.',
|
|
@@ -37,6 +37,7 @@ function parseScopeKinds(raw) {
|
|
|
37
37
|
export const listGrantsCapability = {
|
|
38
38
|
key: 'grant_list',
|
|
39
39
|
names: { sdk: 'grant_list', mcp: 'ziggs_grant_list' },
|
|
40
|
+
title: 'List grants you hold',
|
|
40
41
|
descriptions: {
|
|
41
42
|
sdk: 'List grants this agent holds — or, with role=issuer, grants this agent caused (author-shares and delegate children). Context (chat/agreement/org/artifact), connection, and wallet — canonical grants (grantId, scope, caveats, expiresAt, health; no content or credentials). Default role=holder answers "what grants do I HOLD?", which is narrower than "what can I reach?": authorship, chat membership, agreement party, and org membership leave no grant row — an empty holder list means "no grants", never "no access". role=issuer answers "who did I share with / what did I mint?" after artifact_share. Filter by scopeKind, scopeId, and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails. Cursor-paginated.',
|
|
42
43
|
mcp: 'List grants this delegate holds — or, with role=issuer, grants this delegate caused (author-shares and delegate children). Context (chat/agreement/org/artifact), connection, and wallet — canonical grants (grantId, scope, caveats, expiresAt, health; no content or credentials). Default role=holder answers "what grants do I HOLD?", which is narrower than "what can I reach?": authorship, chat membership, agreement party, and org membership leave no grant row — an empty holder list means "no grants", never "no access". After ziggs_artifact_share, pass role=issuer (and usually scopeKind=["artifact"]) to recover grantIds and revoke with ziggs_context_revoke_grant. Filter by scopeKind, scopeId, and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails. Cursor-paginated.',
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { type CapabilitySurface, type CapabilityAnnotation, type CapabilityParam, type CapabilityEnv, type CapabilityDefinition, fullCreds, rethrowWithContext, } from './types.js';
|
|
2
|
+
export { nextCall, peerAgentId, type NextCall } from './nextCall.js';
|
|
3
|
+
export { AGREEMENT_VERB_CAPABILITIES, agreementCommissionCapability, agreementBidCapability, agreementBrokerCapability, agreementQuestCapability, agreementOfferCapability, agreementHandoffCapability, } from './agreementVerbs.js';
|
|
2
4
|
export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
|
|
3
|
-
export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, linkIsReachOnly, } from './links.js';
|
|
5
|
+
export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, proposeLinkCapability, linkIsReachOnly, } from './links.js';
|
|
4
6
|
export { AGREEMENT_CAPABILITIES, agreementClaimCapability } from './agreements.js';
|
|
5
7
|
export { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION } from './proposeProviderId.js';
|
|
6
8
|
export { MARKETPLACE_CAPABILITIES, marketplaceViewCapability } from './marketplace.js';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { fullCreds, rethrowWithContext, } from './types.js';
|
|
2
|
+
export { nextCall, peerAgentId } from './nextCall.js';
|
|
3
|
+
export { AGREEMENT_VERB_CAPABILITIES, agreementCommissionCapability, agreementBidCapability, agreementBrokerCapability, agreementQuestCapability, agreementOfferCapability, agreementHandoffCapability, } from './agreementVerbs.js';
|
|
2
4
|
export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
|
|
3
|
-
export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, linkIsReachOnly, } from './links.js';
|
|
5
|
+
export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, proposeLinkCapability, linkIsReachOnly, } from './links.js';
|
|
4
6
|
export { AGREEMENT_CAPABILITIES, agreementClaimCapability } from './agreements.js';
|
|
5
7
|
export { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION } from './proposeProviderId.js';
|
|
6
8
|
export { MARKETPLACE_CAPABILITIES, marketplaceViewCapability } from './marketplace.js';
|
|
@@ -12,4 +12,14 @@ import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
|
|
|
12
12
|
export declare function linkIsReachOnly(env: CapabilityEnv): string;
|
|
13
13
|
export declare const createLinkInviteCapability: CapabilityDefinition;
|
|
14
14
|
export declare const listLinksCapability: CapabilityDefinition;
|
|
15
|
+
/**
|
|
16
|
+
* A link proposed to an agent you can name.
|
|
17
|
+
*
|
|
18
|
+
* This used to ride the propose grammar as `engagementKind: "link"`, which put
|
|
19
|
+
* bilateral trust on the same verb as commercial terms it has none of: no
|
|
20
|
+
* price, no chat, no work. It belongs here, beside the invite and the list, so
|
|
21
|
+
* links have one rail. `link_create_invite` is the same act when you do NOT
|
|
22
|
+
* have an agent id and need a shareable page instead.
|
|
23
|
+
*/
|
|
24
|
+
export declare const proposeLinkCapability: CapabilityDefinition;
|
|
15
25
|
export declare const LINK_CAPABILITIES: CapabilityDefinition[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createAgreement, listAgreements } from '../http/AgreementClient.js';
|
|
2
|
+
import { nextCall, peerAgentId } from './nextCall.js';
|
|
2
3
|
import { fullCreds } from './types.js';
|
|
3
4
|
const DEFAULT_WEB_URL = 'https://ziggsai.com';
|
|
4
5
|
function webAppOrigin(env) {
|
|
@@ -43,14 +44,15 @@ const LINK_STATUSES = ['active', 'open', 'cancelled', 'all'];
|
|
|
43
44
|
const MAX_LINK_INVITE_CLAIMS = 25;
|
|
44
45
|
///1022 — the link rail shrank to two tools. Links are agreements, so
|
|
45
46
|
// the agreement verbs carry the rest: request a direct link with
|
|
46
|
-
//
|
|
47
|
+
// link_propose (counterparty = the agent id), claim
|
|
47
48
|
// an invite with agreement_claim, end a link with agreement_revoke.
|
|
48
49
|
export const createLinkInviteCapability = {
|
|
49
50
|
key: 'link_create_invite',
|
|
50
51
|
names: { sdk: 'link_create_invite', mcp: 'ziggs_link_create_invite' },
|
|
52
|
+
title: 'Create a link invite',
|
|
51
53
|
descriptions: {
|
|
52
|
-
sdk: "Create a shareable OPEN link invite (bilateral agent-to-agent trust) when you do NOT have the counterparty's agent id (e.g. connecting across orgs). Creates an open link agreement proposed to everyone and returns shareUrl — one public page that is the entire invite, for a person or for their assistant. Set maxClaims to let several people claim the same link — each gets their own separate connection. When you DO have the agent id, propose the link directly instead:
|
|
53
|
-
mcp: 'Create a shareable OPEN link invite (bilateral agent-to-agent trust, NOT a third-party service connection — see ziggs_connection_list for that) when you do NOT have the counterparty\'s agent id (e.g. connecting across orgs). Creates an open link agreement (POST /agreements {engagementKind:"link"}, proposedTo:"everyone") and returns shareUrl: one public page that is the entire invite — the recipient accepts from it with no account, and their assistant can read the connect instructions off the same URL. Give the human that link and nothing else. Set maxClaims to share ONE link with several people; each claimer gets their own separate connection, not a group. Revoke via ziggs_agreement_revoke to disable. When you DO have the agent id, propose the link directly instead:
|
|
54
|
+
sdk: "Create a shareable OPEN link invite (bilateral agent-to-agent trust) when you do NOT have the counterparty's agent id (e.g. connecting across orgs). Creates an open link agreement proposed to everyone and returns shareUrl — one public page that is the entire invite, for a person or for their assistant. Set maxClaims to let several people claim the same link — each gets their own separate connection. When you DO have the agent id, propose the link directly instead: link_propose with counterparty = that id.",
|
|
55
|
+
mcp: 'Create a shareable OPEN link invite (bilateral agent-to-agent trust, NOT a third-party service connection — see ziggs_connection_list for that) when you do NOT have the counterparty\'s agent id (e.g. connecting across orgs). Creates an open link agreement (POST /agreements {engagementKind:"link"}, proposedTo:"everyone") and returns shareUrl: one public page that is the entire invite — the recipient accepts from it with no account, and their assistant can read the connect instructions off the same URL. Give the human that link and nothing else. Set maxClaims to share ONE link with several people; each claimer gets their own separate connection, not a group. Revoke via ziggs_agreement_revoke to disable. When you DO have the agent id, propose the link directly instead: ziggs_link_propose with counterparty = that id.',
|
|
54
56
|
},
|
|
55
57
|
annotation: 'write',
|
|
56
58
|
params: {
|
|
@@ -93,9 +95,10 @@ export const createLinkInviteCapability = {
|
|
|
93
95
|
export const listLinksCapability = {
|
|
94
96
|
key: 'link_list',
|
|
95
97
|
names: { sdk: 'link_list', mcp: 'ziggs_link_list' },
|
|
98
|
+
title: 'List your links',
|
|
96
99
|
descriptions: {
|
|
97
|
-
sdk: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties. Request a new link with
|
|
98
|
-
mcp: 'List link agreements for this agent — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_connection_list for those) (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties.creatorAgent (requester), parties.providerAgent (target), parties.proposedTo (target owner). Approve pending links via ziggs_agreement_respond; request a new one with
|
|
100
|
+
sdk: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties. Request a new link with link_propose, or link_create_invite when you lack the agent id; end one with agreement_revoke.',
|
|
101
|
+
mcp: 'List link agreements for this agent — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_connection_list for those) (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties.creatorAgent (requester), parties.providerAgent (target), parties.proposedTo (target owner). Approve pending links via ziggs_agreement_respond; request a new one with ziggs_link_propose, or ziggs_link_create_invite when you lack the agent id; end one with ziggs_agreement_revoke.',
|
|
99
102
|
},
|
|
100
103
|
annotation: 'read-only',
|
|
101
104
|
params: {
|
|
@@ -115,17 +118,87 @@ export const listLinksCapability = {
|
|
|
115
118
|
engagementKind: 'link',
|
|
116
119
|
...(status === 'all' ? {} : { status }),
|
|
117
120
|
}, fullCreds(env));
|
|
118
|
-
const
|
|
121
|
+
const active = links.filter((a) => a.status === 'active');
|
|
122
|
+
// A link grants reach and nothing else, so the move after seeing one is
|
|
123
|
+
// always the same: open a room with that peer, or share context explicitly.
|
|
124
|
+
// Both were named in prose, and the peer id had to be dug out of
|
|
125
|
+
// `parties` by whoever read it — while being right here.
|
|
126
|
+
const readPlan = [];
|
|
127
|
+
for (const link of active.slice(0, 3)) {
|
|
128
|
+
const peer = peerAgentId(link.parties, env.creds.agentId);
|
|
129
|
+
if (!peer)
|
|
130
|
+
continue;
|
|
131
|
+
readPlan.push(nextCall(env, 'chat_open', { participantId: peer }, 'open a room with this linked peer — a link alone carries no context'));
|
|
132
|
+
}
|
|
133
|
+
if (active.length) {
|
|
134
|
+
readPlan.push(nextCall(env, 'context_issue_grant', undefined, 'share context that already exists: a link does not share any on its own'));
|
|
135
|
+
}
|
|
119
136
|
return {
|
|
120
137
|
count: links.length,
|
|
121
138
|
status,
|
|
122
139
|
links,
|
|
123
|
-
...(
|
|
140
|
+
...(readPlan.length ? { readPlan } : {}),
|
|
141
|
+
...(active.length ? { nextSteps: linkIsReachOnly(env) } : {}),
|
|
124
142
|
};
|
|
125
143
|
},
|
|
126
144
|
sdkOptions: { isGenericFallback: true },
|
|
127
145
|
};
|
|
146
|
+
/**
|
|
147
|
+
* A link proposed to an agent you can name.
|
|
148
|
+
*
|
|
149
|
+
* This used to ride the propose grammar as `engagementKind: "link"`, which put
|
|
150
|
+
* bilateral trust on the same verb as commercial terms it has none of: no
|
|
151
|
+
* price, no chat, no work. It belongs here, beside the invite and the list, so
|
|
152
|
+
* links have one rail. `link_create_invite` is the same act when you do NOT
|
|
153
|
+
* have an agent id and need a shareable page instead.
|
|
154
|
+
*/
|
|
155
|
+
export const proposeLinkCapability = {
|
|
156
|
+
key: 'link_propose',
|
|
157
|
+
names: { sdk: 'link_propose', mcp: 'ziggs_link_propose' },
|
|
158
|
+
title: 'Propose a link to an agent',
|
|
159
|
+
descriptions: {
|
|
160
|
+
sdk: "Propose bilateral trust to an agent you can name — no chat, no money, no work. Approval is routed to that agent's owner, because a person decides who their delegate trusts. When you do NOT have the agent id, use link_create_invite for a shareable page instead.",
|
|
161
|
+
mcp: "Propose bilateral trust to an agent you can name (NOT a third-party service connection — see ziggs_connection_list for that). No chat, no money, no work: a link is reach, and reach only. The server routes approval to that agent's owner human, because a person decides who their delegate trusts, so the id in the response may differ from the one you passed; `note` says so when it does. Approve via ziggs_agreement_respond. When you do NOT have the agent id, use ziggs_link_create_invite for a shareable page instead.",
|
|
162
|
+
},
|
|
163
|
+
annotation: 'write',
|
|
164
|
+
params: {
|
|
165
|
+
counterparty: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
required: true,
|
|
168
|
+
description: 'Agent id to link with.',
|
|
169
|
+
},
|
|
170
|
+
message: {
|
|
171
|
+
type: 'string',
|
|
172
|
+
description: 'Optional note shown to whoever approves it.',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
needsAgentId: true,
|
|
176
|
+
handler: async (args, env) => {
|
|
177
|
+
const counterparty = args['counterparty'];
|
|
178
|
+
const { agreement } = await createAgreement({
|
|
179
|
+
engagementKind: 'link',
|
|
180
|
+
providerId: counterparty,
|
|
181
|
+
...(args['message'] ? { description: args['message'] } : {}),
|
|
182
|
+
}, fullCreds(env));
|
|
183
|
+
// The owner rewrite is surfaced rather than left to be noticed: an agent
|
|
184
|
+
// that passed one id and reads back another otherwise concludes it was
|
|
185
|
+
// ignored.
|
|
186
|
+
const routedTo = agreement?.parties?.proposedTo;
|
|
187
|
+
const note = routedTo && routedTo !== counterparty
|
|
188
|
+
? `Approval routed to the target agent's owner (${routedTo}): a person decides who their delegate trusts. You passed ${counterparty}.`
|
|
189
|
+
: undefined;
|
|
190
|
+
return {
|
|
191
|
+
agreement,
|
|
192
|
+
...(note ? { note } : {}),
|
|
193
|
+
readPlan: [
|
|
194
|
+
nextCall(env, 'link_list', { status: 'open' }, 'check whether it has been approved yet'),
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
sdkOptions: { isAgreementCreation: true },
|
|
199
|
+
};
|
|
128
200
|
export const LINK_CAPABILITIES = [
|
|
201
|
+
proposeLinkCapability,
|
|
129
202
|
createLinkInviteCapability,
|
|
130
203
|
listLinksCapability,
|
|
131
204
|
];
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { pullOffers, pullQuests } from '../http/MarketplaceClient.js';
|
|
2
2
|
import { fullCreds } from './types.js';
|
|
3
|
+
import { nextCall } from './nextCall.js';
|
|
3
4
|
const VIEW_KINDS = ['all', 'quests', 'offers'];
|
|
4
5
|
function publishHint(env) {
|
|
5
|
-
const propose = env.surface === 'mcp' ? '
|
|
6
|
+
const propose = env.surface === 'mcp' ? 'ziggs_agreement_quest' : 'agreement_quest';
|
|
6
7
|
const claim = env.surface === 'mcp' ? 'ziggs_agreement_claim' : 'agreement_claim';
|
|
7
8
|
return (`Claim any row with ${claim} (agreementId). Publish your own with ${propose}: ` +
|
|
8
9
|
`proposedTo "everyone" or "org" with no providerId broadcasts a quest (claimer works, you pay); ` +
|
|
@@ -16,9 +17,10 @@ function publishHint(env) {
|
|
|
16
17
|
export const marketplaceViewCapability = {
|
|
17
18
|
key: 'marketplace_view',
|
|
18
19
|
names: { sdk: 'marketplace_view', mcp: 'ziggs_marketplace_view' },
|
|
20
|
+
title: 'Browse the marketplace',
|
|
19
21
|
descriptions: {
|
|
20
22
|
sdk: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Quests 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 quest).',
|
|
21
|
-
mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Quests 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
|
|
23
|
+
mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Quests 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_quest (the claimer does the work, you pay).',
|
|
22
24
|
},
|
|
23
25
|
annotation: 'read-only',
|
|
24
26
|
params: {
|
|
@@ -48,6 +50,16 @@ export const marketplaceViewCapability = {
|
|
|
48
50
|
return {
|
|
49
51
|
...(kind !== 'offers' ? { quests, questCount: quests.length } : {}),
|
|
50
52
|
...(kind !== 'quests' ? { offers, offerCount: offers.length } : {}),
|
|
53
|
+
// Claiming is the move after browsing, and the id is in the row the
|
|
54
|
+
// caller just received. The prose hint stays for the publish side, which
|
|
55
|
+
// is a choice rather than a call.
|
|
56
|
+
readPlan: [
|
|
57
|
+
...(quests.length || offers.length
|
|
58
|
+
? [
|
|
59
|
+
nextCall(env, 'agreement_claim', undefined, 'claim a listing from this view by passing its agreementId — listings are take-it-or-leave-it, never countered'),
|
|
60
|
+
]
|
|
61
|
+
: []),
|
|
62
|
+
],
|
|
51
63
|
nextSteps: publishHint(env),
|
|
52
64
|
};
|
|
53
65
|
},
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { CapabilityEnv } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* One runnable next step: a tool name, pre-filled arguments, and why.
|
|
4
|
+
*
|
|
5
|
+
* The inbox and the context read already answer this way, and it is the part of
|
|
6
|
+
* those tools that works best: a caller runs the entries verbatim instead of
|
|
7
|
+
* parsing a paragraph for a tool name and then digging the ids out of the
|
|
8
|
+
* response body it just received.
|
|
9
|
+
*
|
|
10
|
+
* Everywhere else said the same thing in prose, under two other field names, so
|
|
11
|
+
* an agent had to read English to find out that "open a chat with the peer"
|
|
12
|
+
* meant `chat_open` with a `participantId` it had to locate itself. Prose is
|
|
13
|
+
* still right when the next move is not a call at all (a human has to decide
|
|
14
|
+
* something); it is wrong when the call and its arguments are both already
|
|
15
|
+
* known here.
|
|
16
|
+
*/
|
|
17
|
+
export interface NextCall {
|
|
18
|
+
/** Registered tool name on the calling surface. */
|
|
19
|
+
tool: string;
|
|
20
|
+
/** Arguments, filled in from what the response already carries. */
|
|
21
|
+
args?: Record<string, unknown>;
|
|
22
|
+
/** One clause: what running this achieves. */
|
|
23
|
+
why: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build a next step naming the tool as the calling surface registers it.
|
|
27
|
+
*
|
|
28
|
+
* Takes the capability key, not a tool name, because the two surfaces spell the
|
|
29
|
+
* same capability differently (`chat_open` and `ziggs_chat_open`). Every one of
|
|
30
|
+
* the 31 capability definitions follows that one rule, so the key is enough and
|
|
31
|
+
* a caller cannot accidentally emit a name the surface does not have.
|
|
32
|
+
*/
|
|
33
|
+
export declare function nextCall(env: CapabilityEnv, capabilityKey: string, args: Record<string, unknown> | undefined, why: string): NextCall;
|
|
34
|
+
/**
|
|
35
|
+
* The other party in a two-party agreement, from the perspective of `selfId`.
|
|
36
|
+
*
|
|
37
|
+
* Returns null rather than guessing when the row does not identify one, because
|
|
38
|
+
* a pre-filled call naming the wrong counterparty is worse than no pre-filled
|
|
39
|
+
* call: the caller would run it, and it would do something they did not ask for.
|
|
40
|
+
*/
|
|
41
|
+
export declare function peerAgentId(parties: {
|
|
42
|
+
creatorAgent?: string | null;
|
|
43
|
+
providerAgent?: string | null;
|
|
44
|
+
} | undefined, selfId: string | undefined): string | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a next step naming the tool as the calling surface registers it.
|
|
3
|
+
*
|
|
4
|
+
* Takes the capability key, not a tool name, because the two surfaces spell the
|
|
5
|
+
* same capability differently (`chat_open` and `ziggs_chat_open`). Every one of
|
|
6
|
+
* the 31 capability definitions follows that one rule, so the key is enough and
|
|
7
|
+
* a caller cannot accidentally emit a name the surface does not have.
|
|
8
|
+
*/
|
|
9
|
+
export function nextCall(env, capabilityKey, args, why) {
|
|
10
|
+
return {
|
|
11
|
+
tool: env.surface === 'mcp' ? `ziggs_${capabilityKey}` : capabilityKey,
|
|
12
|
+
...(args && Object.keys(args).length ? { args } : {}),
|
|
13
|
+
why,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The other party in a two-party agreement, from the perspective of `selfId`.
|
|
18
|
+
*
|
|
19
|
+
* Returns null rather than guessing when the row does not identify one, because
|
|
20
|
+
* a pre-filled call naming the wrong counterparty is worse than no pre-filled
|
|
21
|
+
* call: the caller would run it, and it would do something they did not ask for.
|
|
22
|
+
*/
|
|
23
|
+
export function peerAgentId(parties, selfId) {
|
|
24
|
+
if (!parties || !selfId)
|
|
25
|
+
return null;
|
|
26
|
+
const { creatorAgent, providerAgent } = parties;
|
|
27
|
+
if (creatorAgent && creatorAgent !== selfId)
|
|
28
|
+
return creatorAgent;
|
|
29
|
+
if (providerAgent && providerAgent !== selfId)
|
|
30
|
+
return providerAgent;
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
@@ -32,6 +32,7 @@ const grantCaveatParams = {
|
|
|
32
32
|
export const paymentBalanceCapability = {
|
|
33
33
|
key: 'payment_balance',
|
|
34
34
|
names: { sdk: 'payment_balance', mcp: 'ziggs_payment_balance' },
|
|
35
|
+
title: 'Check your balance',
|
|
35
36
|
descriptions: {
|
|
36
37
|
sdk: "Check the caller's current wallet balance and available balance (total minus active holds). Use before a transfer to confirm sufficient funds.",
|
|
37
38
|
mcp: "Check the caller's current wallet balance and available balance (total minus active holds). Use before a transfer to confirm sufficient funds.",
|
|
@@ -50,6 +51,7 @@ export const paymentBalanceCapability = {
|
|
|
50
51
|
export const paymentResolveWalletCapability = {
|
|
51
52
|
key: 'payment_resolve_wallet',
|
|
52
53
|
names: { sdk: 'payment_resolve_wallet', mcp: 'ziggs_payment_resolve_wallet' },
|
|
54
|
+
title: 'Look up a wallet',
|
|
53
55
|
descriptions: {
|
|
54
56
|
sdk: 'Look up a walletId by userId or agentId. Use before a transfer when you only know the recipient by their platform ID.',
|
|
55
57
|
mcp: 'Look up a walletId by userId or agentId. Use before a transfer when you only know the recipient by their platform ID.',
|
|
@@ -82,6 +84,7 @@ export const paymentResolveWalletCapability = {
|
|
|
82
84
|
export const paymentTransferCapability = {
|
|
83
85
|
key: 'payment_transfer',
|
|
84
86
|
names: { sdk: 'payment_transfer', mcp: 'ziggs_payment_transfer' },
|
|
87
|
+
title: 'Transfer funds',
|
|
85
88
|
descriptions: {
|
|
86
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.',
|
|
87
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.',
|
|
@@ -169,6 +172,7 @@ export const paymentTransferCapability = {
|
|
|
169
172
|
export const paymentWaitForApprovalCapability = {
|
|
170
173
|
key: 'payment_wait_for_approval',
|
|
171
174
|
names: { sdk: 'payment_wait_for_approval', mcp: 'ziggs_payment_wait_for_approval' },
|
|
175
|
+
title: 'Wait on a payment approval',
|
|
172
176
|
descriptions: {
|
|
173
177
|
sdk: 'Poll a paused transfer (status "approval_required") until the human decides or the timeout passes. Returns executed | rejected | expired | timeout | gone.',
|
|
174
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.',
|
|
@@ -207,6 +211,7 @@ export const paymentWaitForApprovalCapability = {
|
|
|
207
211
|
export const paymentHoldCapability = {
|
|
208
212
|
key: 'payment_hold',
|
|
209
213
|
names: { sdk: 'payment_hold', mcp: 'ziggs_payment_hold' },
|
|
214
|
+
title: 'Hold funds in escrow',
|
|
210
215
|
descriptions: {
|
|
211
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.',
|
|
212
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.",
|
|
@@ -246,6 +251,7 @@ export const paymentHoldCapability = {
|
|
|
246
251
|
export const paymentReleaseCapability = {
|
|
247
252
|
key: 'payment_release',
|
|
248
253
|
names: { sdk: 'payment_release', mcp: 'ziggs_payment_release' },
|
|
254
|
+
title: 'Settle or refund a hold',
|
|
249
255
|
descriptions: {
|
|
250
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).",
|
|
251
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).",
|
|
@@ -296,6 +302,7 @@ export const paymentReleaseCapability = {
|
|
|
296
302
|
export const paymentIssueGrantCapability = {
|
|
297
303
|
key: 'payment_issue_grant',
|
|
298
304
|
names: { sdk: 'payment_issue_grant', mcp: 'ziggs_payment_issue_grant' },
|
|
305
|
+
title: 'Issue a spend grant',
|
|
299
306
|
descriptions: {
|
|
300
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.",
|
|
301
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.",
|
|
@@ -329,6 +336,7 @@ export const paymentIssueGrantCapability = {
|
|
|
329
336
|
export const paymentAttenuateGrantCapability = {
|
|
330
337
|
key: 'payment_attenuate_grant',
|
|
331
338
|
names: { sdk: 'payment_attenuate_grant', mcp: 'ziggs_payment_attenuate_grant' },
|
|
339
|
+
title: 'Pass on a tighter spend grant',
|
|
332
340
|
descriptions: {
|
|
333
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.',
|
|
334
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.',
|
|
@@ -372,6 +380,7 @@ export const paymentAttenuateGrantCapability = {
|
|
|
372
380
|
export const paymentRevokeGrantCapability = {
|
|
373
381
|
key: 'payment_revoke_grant',
|
|
374
382
|
names: { sdk: 'payment_revoke_grant', mcp: 'ziggs_payment_revoke_grant' },
|
|
383
|
+
title: 'Revoke a spend grant',
|
|
375
384
|
descriptions: {
|
|
376
385
|
sdk: 'Revoke a payment grant (and its attenuated children). The holder can no longer spend under it.',
|
|
377
386
|
mcp: 'Revoke a payment grant (and its attenuated children). The holder can no longer spend under it.',
|
|
@@ -59,6 +59,15 @@ export interface CapabilityDefinition {
|
|
|
59
59
|
sdk: string;
|
|
60
60
|
mcp: string;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Human-readable label a host shows instead of the raw `rail_verb` name.
|
|
64
|
+
* Required: a tool with no title displays as its wire name, and the
|
|
65
|
+
* connector directory rejects the surface for it. One title for both
|
|
66
|
+
* surfaces — the wire name differs per surface, the action it performs
|
|
67
|
+
* does not. Phrase it as that action, and keep it product copy: this is
|
|
68
|
+
* what a person reads in the tool picker.
|
|
69
|
+
*/
|
|
70
|
+
title: string;
|
|
62
71
|
/**
|
|
63
72
|
* Tool description per surface. Kept side by side deliberately: wording may
|
|
64
73
|
* reference surface-local tool names and MCP delegate-protocol guidance, but
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline `POST /artifacts` body cap (matches backend
|
|
3
|
+
* `ARTIFACT_PUBLIC_TEXT_MAX_CHARS`). Over this → file rail or multi-part; the
|
|
4
|
+
* server does not auto-split (ZIG-1320).
|
|
5
|
+
*/
|
|
6
|
+
export declare const ARTIFACT_INLINE_TEXT_MAX_CHARS = 50000;
|
|
7
|
+
/** ZIG-1320 — named escape hatch for agents that hit the inline cap. */
|
|
8
|
+
export declare const ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT: string;
|
|
1
9
|
export type ArtifactVisibility = 'chat' | 'agent-private';
|
|
2
10
|
export interface ListArtifactsOptions {
|
|
3
11
|
after?: string;
|
|
@@ -2,6 +2,17 @@ import { runtimeLog } from '../shared/runtimeLog.js';
|
|
|
2
2
|
import { throwApiError } from '../shared/apiError.js';
|
|
3
3
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
4
|
import { buildOperatorHeaders } from './operatorHeaders.js';
|
|
5
|
+
/**
|
|
6
|
+
* Inline `POST /artifacts` body cap (matches backend
|
|
7
|
+
* `ARTIFACT_PUBLIC_TEXT_MAX_CHARS`). Over this → file rail or multi-part; the
|
|
8
|
+
* server does not auto-split (ZIG-1320).
|
|
9
|
+
*/
|
|
10
|
+
export const ARTIFACT_INLINE_TEXT_MAX_CHARS = 50_000;
|
|
11
|
+
/** ZIG-1320 — named escape hatch for agents that hit the inline cap. */
|
|
12
|
+
export const ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT = `text exceeds ${ARTIFACT_INLINE_TEXT_MAX_CHARS} characters. ` +
|
|
13
|
+
'For larger content use ziggs_artifact_upload_url (file rail), or split into ' +
|
|
14
|
+
'an index artifact plus part artifacts and list the part ids in the index. ' +
|
|
15
|
+
'The server does not auto-split.';
|
|
5
16
|
function resolveUploadBytes(input) {
|
|
6
17
|
if (input.content != null) {
|
|
7
18
|
return Buffer.isBuffer(input.content)
|
|
@@ -122,12 +133,18 @@ export class ArtifactsClient {
|
|
|
122
133
|
throw new Error('ArtifactsClient.writeStrict: text is required');
|
|
123
134
|
}
|
|
124
135
|
this._assertScopeXor(input);
|
|
136
|
+
const text = input.text.trim();
|
|
137
|
+
// ZIG-1320: refuse before the wire so MCP/SDK get a named escape hatch
|
|
138
|
+
// instead of a bare class-validator string.
|
|
139
|
+
if (text.length > ARTIFACT_INLINE_TEXT_MAX_CHARS) {
|
|
140
|
+
throw new Error(`ArtifactsClient.writeStrict: ${ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT}`);
|
|
141
|
+
}
|
|
125
142
|
const url = `${getBackendUrl()}/artifacts`;
|
|
126
143
|
const res = await fetch(url, {
|
|
127
144
|
method: 'POST',
|
|
128
145
|
headers: this._headers(),
|
|
129
146
|
body: JSON.stringify({
|
|
130
|
-
text
|
|
147
|
+
text,
|
|
131
148
|
contentType: input.contentType ?? 'text',
|
|
132
149
|
visibility: input.visibility ?? 'chat',
|
|
133
150
|
chatId: input.chatId,
|
package/dist/http/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from './agreementFlows.js';
|
|
|
5
5
|
export * from './ChatClient.js';
|
|
6
6
|
export { MessagesClient } from './MessagesClient.js';
|
|
7
7
|
export type { ListMessagesOptions, ListMessagesResult } from './MessagesClient.js';
|
|
8
|
-
export { ArtifactsClient, artifactScopeForSession, AGREEMENT_LANE_PREFIX, } from './ArtifactsClient.js';
|
|
8
|
+
export { ArtifactsClient, artifactScopeForSession, AGREEMENT_LANE_PREFIX, ARTIFACT_INLINE_TEXT_MAX_CHARS, ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT, } from './ArtifactsClient.js';
|
|
9
9
|
export type { ArtifactVisibility, ListArtifactsOptions, ListArtifactsQuery, ListArtifactsResult, WriteArtifactInput, } from './ArtifactsClient.js';
|
|
10
10
|
export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, parseVia, viaHint, } from './ContextReadClient.js';
|
|
11
11
|
export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, ContextSnapshotResult, ViaKind, } from './ContextReadClient.js';
|
package/dist/http/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export * from './ChatClient.js';
|
|
|
6
6
|
export { MessagesClient } from './MessagesClient.js';
|
|
7
7
|
export { ArtifactsClient,
|
|
8
8
|
// agreement lanes are not chats — callers scope artifact writes with this.
|
|
9
|
-
artifactScopeForSession, AGREEMENT_LANE_PREFIX, } from './ArtifactsClient.js';
|
|
9
|
+
artifactScopeForSession, AGREEMENT_LANE_PREFIX, ARTIFACT_INLINE_TEXT_MAX_CHARS, ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT, } from './ArtifactsClient.js';
|
|
10
10
|
export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, parseVia, viaHint, } from './ContextReadClient.js';
|
|
11
11
|
export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
12
12
|
export { GrantsClient } from './GrantsClient.js';
|