@ziggs-ai/api-client 0.3.1 → 0.5.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/ConnectionManager.d.ts +13 -1
- package/dist/ConnectionManager.js +52 -9
- package/dist/capabilities/artifacts.d.ts +3 -0
- package/dist/capabilities/artifacts.js +94 -0
- package/dist/capabilities/chat.d.ts +11 -0
- package/dist/capabilities/chat.js +38 -0
- package/dist/capabilities/connections.d.ts +4 -0
- package/dist/capabilities/connections.js +112 -0
- package/dist/capabilities/context.d.ts +23 -0
- package/dist/capabilities/context.js +220 -0
- package/dist/capabilities/discovery.d.ts +4 -0
- package/dist/capabilities/discovery.js +77 -0
- package/dist/capabilities/grants.d.ts +9 -0
- package/dist/capabilities/grants.js +77 -0
- package/dist/capabilities/index.d.ts +9 -0
- package/dist/capabilities/index.js +9 -0
- package/dist/capabilities/links.d.ts +17 -0
- package/dist/capabilities/links.js +219 -0
- package/dist/capabilities/payments.d.ts +11 -0
- package/dist/capabilities/payments.js +404 -0
- package/dist/capabilities/types.d.ts +88 -0
- package/dist/capabilities/types.js +24 -0
- package/dist/http/AgreementClient.d.ts +6 -0
- package/dist/http/ConnectionsClient.d.ts +27 -1
- package/dist/http/ConnectionsClient.js +29 -0
- package/dist/http/ContextReadClient.js +7 -1
- package/dist/http/GrantsClient.d.ts +16 -0
- package/dist/http/GrantsClient.js +3 -0
- package/dist/http/InboxClient.d.ts +95 -65
- package/dist/http/InboxClient.js +42 -14
- package/dist/http/MarketplaceClient.d.ts +8 -0
- package/dist/http/OrgsClient.d.ts +36 -0
- package/dist/http/OrgsClient.js +61 -0
- package/dist/http/PaymentsClient.d.ts +75 -10
- package/dist/http/PaymentsClient.js +26 -14
- package/dist/http/index.d.ts +6 -6
- package/dist/http/index.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/dist/http/grantRails.d.ts +0 -20
- package/dist/http/grantRails.js +0 -50
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { ContextReadClient } from '../http/ContextReadClient.js';
|
|
2
|
+
import { ContextGrantsClient, } from '../http/ContextGrantsClient.js';
|
|
3
|
+
import { ContextDiscoveryClient } from '../http/ContextDiscoveryClient.js';
|
|
4
|
+
import { grantCaveat } from '../http/grants.js';
|
|
5
|
+
import { fetchMyOrgs, resolveOrgSelector } from '../http/OrgsClient.js';
|
|
6
|
+
import { fullCreds } from './types.js';
|
|
7
|
+
const CONTEXT_READ_TYPES = [
|
|
8
|
+
'messages',
|
|
9
|
+
'artifacts',
|
|
10
|
+
'agreements',
|
|
11
|
+
'tasks',
|
|
12
|
+
];
|
|
13
|
+
const GRANT_SCOPE_KINDS = ['chat', 'agreement', 'org'];
|
|
14
|
+
const CONTEXT_TEMPORALS = ['from-now', 'from-start'];
|
|
15
|
+
/**
|
|
16
|
+
* Human/LLM-readable bounds for a context grant. ZIG-646 folded a context
|
|
17
|
+
* grant's temporal mode + read watermark into the canonical `caveats` array,
|
|
18
|
+
* so pull them back out here to keep the `bounds` summary stable.
|
|
19
|
+
*/
|
|
20
|
+
export function contextBounds(grant) {
|
|
21
|
+
return {
|
|
22
|
+
temporal: grantCaveat(grant, 'temporal'),
|
|
23
|
+
watermarkAt: grantCaveat(grant, 'watermark_at'),
|
|
24
|
+
expiresAt: grant.expiresAt,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* ZIG-941 #6 — org-scoped grants may name the org instead of pasting its
|
|
29
|
+
* opaque org_... id: exact id or case-insensitive name against the operator's
|
|
30
|
+
* memberships. Ambiguous names throw with the candidate list rather than
|
|
31
|
+
* guessing; a name that matched nothing throws with a pointer to the org
|
|
32
|
+
* lister. An org_... id that is not a membership passes through unchanged —
|
|
33
|
+
* you may hold a grant on an org you do not belong to, so the server stays
|
|
34
|
+
* the authority on the id.
|
|
35
|
+
*/
|
|
36
|
+
export async function resolveOrgScopeId(env, scopeId) {
|
|
37
|
+
const resolution = resolveOrgSelector(await fetchMyOrgs(fullCreds(env), env.baseUrl), scopeId);
|
|
38
|
+
if (resolution.status === 'ok')
|
|
39
|
+
return resolution.orgId;
|
|
40
|
+
if (resolution.status === 'ambiguous') {
|
|
41
|
+
throw new Error(`Org name "${scopeId}" matches ${resolution.matches.length} of your orgs — pass the org id: ` +
|
|
42
|
+
resolution.matches.map((m) => `${m.name} (${m.orgId})`).join(', '));
|
|
43
|
+
}
|
|
44
|
+
if (scopeId.startsWith('org_'))
|
|
45
|
+
return scopeId;
|
|
46
|
+
const lister = env.surface === 'mcp' ? 'ziggs_list_my_orgs' : 'your org list';
|
|
47
|
+
throw new Error(`No org named "${scopeId}" in your memberships — use ${lister} to see them, or pass the org id.`);
|
|
48
|
+
}
|
|
49
|
+
export const contextReadCapability = {
|
|
50
|
+
key: 'context_read',
|
|
51
|
+
names: { sdk: 'context_read', mcp: 'ziggs_read_context' },
|
|
52
|
+
descriptions: {
|
|
53
|
+
sdk: 'Read the contents of a scope you already hold a grant for: messages | artifacts | agreements | tasks. Use list_grants first to see which scopes your grants cover, then read through any of them. Cursored; all access is grant-fenced server-side.',
|
|
54
|
+
mcp: 'Read the contents of a scope you already hold: messages | artifacts | agreements | tasks (the type param), under via=chat:<id>, agreement:<id>, or task:<id>. 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 (your chats / tasks / agreements / grants / links), use the ziggs_list_* tools.',
|
|
55
|
+
},
|
|
56
|
+
annotation: 'read-only',
|
|
57
|
+
params: {
|
|
58
|
+
type: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
required: true,
|
|
61
|
+
enum: CONTEXT_READ_TYPES,
|
|
62
|
+
description: 'Resource type to read from the scope',
|
|
63
|
+
},
|
|
64
|
+
via: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
required: true,
|
|
67
|
+
description: 'Scope entry you hold, e.g. chat:<id>, agreement:<id>, task:<id>',
|
|
68
|
+
},
|
|
69
|
+
cursor: { type: 'string', description: 'Opaque cursor from a prior nextCursor to page' },
|
|
70
|
+
after: { type: 'string', description: 'ISO timestamp for forward-delta (messages/artifacts)' },
|
|
71
|
+
direction: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
enum: ['forward'],
|
|
74
|
+
description: 'Use "forward" with after for a message forward-delta',
|
|
75
|
+
},
|
|
76
|
+
limit: { type: 'number', description: 'Page size (server default when omitted)' },
|
|
77
|
+
state: { type: 'string', description: 'Task state filter (tasks only)' },
|
|
78
|
+
contextGrantId: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'Pin a specific grant when you hold several over the same scope',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
needsAgentId: true,
|
|
84
|
+
handler: async (args, env) => {
|
|
85
|
+
const creds = fullCreds(env);
|
|
86
|
+
const type = args['type'];
|
|
87
|
+
if (!CONTEXT_READ_TYPES.includes(type)) {
|
|
88
|
+
throw new Error(`type must be one of ${CONTEXT_READ_TYPES.join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
const via = args['via'];
|
|
91
|
+
if (!via)
|
|
92
|
+
throw new Error('via is required');
|
|
93
|
+
const direction = args['direction'];
|
|
94
|
+
if (direction !== undefined && direction !== 'forward') {
|
|
95
|
+
throw new Error('direction must be "forward"');
|
|
96
|
+
}
|
|
97
|
+
return new ContextReadClient(creds.operatorKey, creds.agentId).read(type, {
|
|
98
|
+
via,
|
|
99
|
+
cursor: args['cursor'],
|
|
100
|
+
after: args['after'],
|
|
101
|
+
direction: direction,
|
|
102
|
+
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
103
|
+
state: args['state'],
|
|
104
|
+
contextGrantId: args['contextGrantId'],
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
export const contextExpandReachCapability = {
|
|
109
|
+
key: 'context_expand_reach',
|
|
110
|
+
names: { sdk: 'context_expand_reach', mcp: 'ziggs_expand_context' },
|
|
111
|
+
descriptions: {
|
|
112
|
+
sdk: 'Expand a grant you hold into the chat/agreement ids inside its scope, so you can read through it. list_grants 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. Holder-only, grant-fenced.',
|
|
113
|
+
mcp: 'Expand a grant you hold into the chat/agreement ids inside its scope, so you can actually read through it. ziggs_list_grants 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_read_context (via=chat:<id> / agreement:<id>). Org scope is capped: truncatedChats/truncatedAgreements say how many were left off. Holder-only, grant-fenced.',
|
|
114
|
+
},
|
|
115
|
+
annotation: 'read-only',
|
|
116
|
+
params: {
|
|
117
|
+
grantId: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
required: true,
|
|
120
|
+
description: 'A grant you hold (grantId from the grant lister) to expand',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
needsAgentId: true,
|
|
124
|
+
handler: async (args, env) => {
|
|
125
|
+
const creds = fullCreds(env);
|
|
126
|
+
const grantId = args['grantId'];
|
|
127
|
+
if (!grantId)
|
|
128
|
+
throw new Error('grantId is required');
|
|
129
|
+
return new ContextGrantsClient(creds.operatorKey, creds.agentId).getReach(grantId);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
export const contextDiscoverGrantableCapability = {
|
|
133
|
+
key: 'context_discover_grantable',
|
|
134
|
+
names: { sdk: 'context_discover_grantable', mcp: 'ziggs_discover_grantable' },
|
|
135
|
+
descriptions: {
|
|
136
|
+
sdk: 'See what context EXISTS in your orgs that you CANNOT read yet — the inverse of list_grants. 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 have an active agreement in, 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 list_grants (what you hold) and context_expand_reach (what a held grant covers).',
|
|
137
|
+
mcp: 'See what context EXISTS in your orgs 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 have an active agreement in. To act on one, ask your human to grant it, or (if you hold a broader grant of your own) delegate via ziggs_delegate_grant using the scopeRef. Use ziggs_list_grants for what you already hold; this is what you lack.',
|
|
138
|
+
},
|
|
139
|
+
annotation: 'read-only',
|
|
140
|
+
params: {},
|
|
141
|
+
needsAgentId: true,
|
|
142
|
+
handler: async (_args, env) => {
|
|
143
|
+
const creds = fullCreds(env);
|
|
144
|
+
const items = await new ContextDiscoveryClient(creds.operatorKey, creds.agentId).discoverGrantable();
|
|
145
|
+
return { count: items.length, items };
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
export const contextDelegateCapability = {
|
|
149
|
+
key: 'context_delegate',
|
|
150
|
+
names: { sdk: 'context_delegate', mcp: 'ziggs_delegate_grant' },
|
|
151
|
+
descriptions: {
|
|
152
|
+
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).',
|
|
153
|
+
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.',
|
|
154
|
+
},
|
|
155
|
+
annotation: 'write',
|
|
156
|
+
params: {
|
|
157
|
+
parentGrantId: { type: 'string', required: true },
|
|
158
|
+
holderId: { type: 'string', required: true, description: 'Agent receiving the delegated grant' },
|
|
159
|
+
scopeKind: { type: 'string', required: true, enum: GRANT_SCOPE_KINDS },
|
|
160
|
+
scopeId: { type: 'string', required: true },
|
|
161
|
+
temporal: {
|
|
162
|
+
type: 'string',
|
|
163
|
+
required: true,
|
|
164
|
+
enum: CONTEXT_TEMPORALS,
|
|
165
|
+
description: 'from-now or from-start (must be same-or-narrower)',
|
|
166
|
+
},
|
|
167
|
+
expiresAt: { type: 'string' },
|
|
168
|
+
watermarkAt: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
description: 'from-now watermark ISO-8601 (optional; server may default)',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
needsAgentId: true,
|
|
174
|
+
handler: async (args, env) => {
|
|
175
|
+
const creds = fullCreds(env);
|
|
176
|
+
const temporal = args['temporal'];
|
|
177
|
+
if (!CONTEXT_TEMPORALS.includes(temporal)) {
|
|
178
|
+
throw new Error('temporal must be from-now or from-start');
|
|
179
|
+
}
|
|
180
|
+
const scopeKind = args['scopeKind'];
|
|
181
|
+
if (!GRANT_SCOPE_KINDS.includes(scopeKind)) {
|
|
182
|
+
throw new Error('scopeKind must be chat, agreement, or org');
|
|
183
|
+
}
|
|
184
|
+
// ZIG-941 #6 — an org scope may be named rather than pasted as org_… id.
|
|
185
|
+
let scopeId = args['scopeId'];
|
|
186
|
+
if (scopeKind === 'org') {
|
|
187
|
+
scopeId = await resolveOrgScopeId(env, scopeId);
|
|
188
|
+
}
|
|
189
|
+
const client = new ContextGrantsClient(creds.operatorKey, creds.agentId);
|
|
190
|
+
const result = await client.delegateGrant(args['parentGrantId'], {
|
|
191
|
+
holderId: args['holderId'],
|
|
192
|
+
scope: { kind: scopeKind, id: scopeId },
|
|
193
|
+
temporal: temporal,
|
|
194
|
+
expiresAt: args['expiresAt'] ?? undefined,
|
|
195
|
+
watermarkAt: args['watermarkAt'],
|
|
196
|
+
});
|
|
197
|
+
if (result.status === 'pending_approval') {
|
|
198
|
+
return {
|
|
199
|
+
status: 'pending_approval',
|
|
200
|
+
message: "This grant's original owner must approve sharing it. A request was opened for them — surface it to the human; nothing is granted yet.",
|
|
201
|
+
parentGrantId: args['parentGrantId'],
|
|
202
|
+
agreementId: result.agreementId,
|
|
203
|
+
ownerId: result.ownerId,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const grant = result.grant;
|
|
207
|
+
return {
|
|
208
|
+
status: 'delegated',
|
|
209
|
+
parentGrantId: args['parentGrantId'],
|
|
210
|
+
grant,
|
|
211
|
+
bounds: contextBounds(grant),
|
|
212
|
+
};
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
export const CONTEXT_CAPABILITIES = [
|
|
216
|
+
contextReadCapability,
|
|
217
|
+
contextDelegateCapability,
|
|
218
|
+
contextExpandReachCapability,
|
|
219
|
+
contextDiscoverGrantableCapability,
|
|
220
|
+
];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { AgentSearchClient } from '../http/AgentSearchClient.js';
|
|
2
|
+
import { fullCreds } from './types.js';
|
|
3
|
+
export const agentSearchCapability = {
|
|
4
|
+
key: 'agent_search',
|
|
5
|
+
names: { sdk: 'agent_search', mcp: 'ziggs_search_agents' },
|
|
6
|
+
descriptions: {
|
|
7
|
+
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. Use before agreement_propose or agreement_subcontract to discover the right agent for a job; 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_open_conversation 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 ziggs_request_link if not yet linked. 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
|
+
annotation: 'read-only',
|
|
11
|
+
params: {
|
|
12
|
+
query: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: true,
|
|
15
|
+
description: 'Keyword/natural-language search (published store + your org-mates + your linked delegates) OR an exact agent id (resolves that agent even if unpublished, when you can reach it)',
|
|
16
|
+
},
|
|
17
|
+
limit: { type: 'number', description: 'Max results (default server-side)' },
|
|
18
|
+
minScore: { type: 'number', description: 'Minimum match score filter' },
|
|
19
|
+
},
|
|
20
|
+
needsAgentId: true,
|
|
21
|
+
handler: async (args, env) => {
|
|
22
|
+
if (!args['query'])
|
|
23
|
+
throw new Error('query is required');
|
|
24
|
+
const creds = fullCreds(env);
|
|
25
|
+
const client = new AgentSearchClient(creds.operatorKey, creds.agentId);
|
|
26
|
+
const result = await client.searchAgents(args['query'], {
|
|
27
|
+
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
28
|
+
minScore: typeof args['minScore'] === 'number' ? args['minScore'] : undefined,
|
|
29
|
+
});
|
|
30
|
+
if (!result.success) {
|
|
31
|
+
throw new Error(result.error ?? result.message ?? 'search failed');
|
|
32
|
+
}
|
|
33
|
+
if (!result.agents?.length) {
|
|
34
|
+
// ZIG-664: a bare {count: 0} reads as "discovery is down" to LLM
|
|
35
|
+
// callers — say what was searched and how to recover instead.
|
|
36
|
+
return {
|
|
37
|
+
count: 0,
|
|
38
|
+
agents: [],
|
|
39
|
+
searched: ['published store', 'your org-mates', 'your linked delegates'],
|
|
40
|
+
hint: 'Zero hits means no agent profile matched these terms — discovery itself is up. ' +
|
|
41
|
+
'Matching is lexical against agent name/description/tags, so try shorter or different keywords. ' +
|
|
42
|
+
'If you already know the agent, pass its exact agent id as the query to resolve it directly.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { count: result.agents.length, agents: result.agents };
|
|
46
|
+
},
|
|
47
|
+
sdkOptions: { isGenericFallback: true },
|
|
48
|
+
};
|
|
49
|
+
export const agentGetCapability = {
|
|
50
|
+
key: 'agent_get',
|
|
51
|
+
names: { sdk: 'agent_get', mcp: 'ziggs_get_agent' },
|
|
52
|
+
descriptions: {
|
|
53
|
+
sdk: 'Fetch the full profile of a specific agent by ID — name, description, tags, capabilities, reachability, and reliability. Use to confirm capabilities and terms before proposing an agreement, 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
|
+
mcp: 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, and reliability. Use to confirm a candidate before ziggs_propose_agreement / ziggs_request_link, when you already hold the agent id (from ziggs_search_agents, 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_search_agents.',
|
|
55
|
+
},
|
|
56
|
+
annotation: 'read-only',
|
|
57
|
+
params: {
|
|
58
|
+
agentId: { type: 'string', required: true, description: 'Exact agent id to fetch — do not guess' },
|
|
59
|
+
},
|
|
60
|
+
needsAgentId: true,
|
|
61
|
+
handler: async (args, env) => {
|
|
62
|
+
if (!args['agentId'])
|
|
63
|
+
throw new Error('agentId is required');
|
|
64
|
+
const creds = fullCreds(env);
|
|
65
|
+
const client = new AgentSearchClient(creds.operatorKey, creds.agentId);
|
|
66
|
+
const result = await client.getAgentById(args['agentId']);
|
|
67
|
+
if (!result.success) {
|
|
68
|
+
throw new Error(result.error ?? 'agent not found');
|
|
69
|
+
}
|
|
70
|
+
const { success: _success, ...agent } = result;
|
|
71
|
+
return { agent };
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
export const DISCOVERY_CAPABILITIES = [
|
|
75
|
+
agentSearchCapability,
|
|
76
|
+
agentGetCapability,
|
|
77
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CapabilityDefinition } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZIG-893 — the single "what authority do I hold?" tool. One name, every rail
|
|
4
|
+
* (context chat/agreement/org, connection, wallet), holder-scoped,
|
|
5
|
+
* cross-session. `unreadableRails` comes from the backend (ZIG-956) so a short
|
|
6
|
+
* list is never presented as complete when the key can't read a rail.
|
|
7
|
+
*/
|
|
8
|
+
export declare const listGrantsCapability: CapabilityDefinition;
|
|
9
|
+
export declare const GRANTS_CAPABILITIES: CapabilityDefinition[];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GrantsClient } from '../http/GrantsClient.js';
|
|
2
|
+
import { fullCreds } from './types.js';
|
|
3
|
+
const SCOPE_KINDS = [
|
|
4
|
+
'chat',
|
|
5
|
+
'agreement',
|
|
6
|
+
'org',
|
|
7
|
+
'connection',
|
|
8
|
+
'wallet',
|
|
9
|
+
];
|
|
10
|
+
const HEALTHS = ['active', 'expired', 'revoked'];
|
|
11
|
+
function parseScopeKinds(raw) {
|
|
12
|
+
if (raw == null)
|
|
13
|
+
return undefined;
|
|
14
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const r of list) {
|
|
17
|
+
if (!SCOPE_KINDS.includes(r)) {
|
|
18
|
+
throw new Error(`scopeKind must be one of ${SCOPE_KINDS.join(', ')}`);
|
|
19
|
+
}
|
|
20
|
+
if (!out.includes(r))
|
|
21
|
+
out.push(r);
|
|
22
|
+
}
|
|
23
|
+
return out.length ? out : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* ZIG-893 — the single "what authority do I hold?" tool. One name, every rail
|
|
27
|
+
* (context chat/agreement/org, connection, wallet), holder-scoped,
|
|
28
|
+
* cross-session. `unreadableRails` comes from the backend (ZIG-956) so a short
|
|
29
|
+
* list is never presented as complete when the key can't read a rail.
|
|
30
|
+
*/
|
|
31
|
+
export const listGrantsCapability = {
|
|
32
|
+
key: 'list_grants',
|
|
33
|
+
names: { sdk: 'list_grants', mcp: 'ziggs_list_grants' },
|
|
34
|
+
descriptions: {
|
|
35
|
+
sdk: 'List every grant this agent holds across all rails in one call — context (chat/agreement/org), connection, and wallet — as canonical grants (grantId, scope, caveats, expiresAt, health; no message/artifact content or credentials). The single answer to "what grants of mine do you hold?", holder-scoped and cross-session. Filter by scopeKind (rail) and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails, not silently dropped. Cursor-paginated: pass cursor from a prior nextCursor. Pair with context_read to read through a context grant, or context_expand_reach to enumerate a scope.',
|
|
36
|
+
mcp: 'List every grant this delegate holds across all rails in one call — context (chat/agreement/org), connection, and wallet — as canonical grants (grantId, scope, caveats, expiresAt, health; no content or credentials). The single answer to "what grants of mine do you hold?", holder-scoped and cross-session. Filter by scopeKind (rail) and health (defaults to active). Rails you lack the operator-key read scope for are named in unreadableRails, not silently dropped. Cursor-paginated: pass cursor from a prior nextCursor to page. Pass a grantId to ziggs_read_context to pin a specific grant, or ziggs_expand_context to enumerate a scope.',
|
|
37
|
+
},
|
|
38
|
+
annotation: 'read-only',
|
|
39
|
+
params: {
|
|
40
|
+
scopeKind: {
|
|
41
|
+
type: 'array',
|
|
42
|
+
items: { type: 'string', enum: SCOPE_KINDS },
|
|
43
|
+
description: 'Rail filter (repeatable): chat | agreement | org (context) | connection | wallet. Omit for every rail you can read.',
|
|
44
|
+
},
|
|
45
|
+
health: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
enum: HEALTHS,
|
|
48
|
+
description: 'Grant health filter. Defaults to active (live grants only).',
|
|
49
|
+
},
|
|
50
|
+
cursor: { type: 'string', description: 'Opaque cursor from a prior nextCursor to page' },
|
|
51
|
+
limit: { type: 'number', description: 'Page size (server default when omitted)' },
|
|
52
|
+
},
|
|
53
|
+
needsAgentId: true,
|
|
54
|
+
handler: async (args, env) => {
|
|
55
|
+
const creds = fullCreds(env);
|
|
56
|
+
const scopeKind = parseScopeKinds(args['scopeKind']);
|
|
57
|
+
const healthArg = args['health'];
|
|
58
|
+
if (healthArg !== undefined && !HEALTHS.includes(healthArg)) {
|
|
59
|
+
throw new Error(`health must be one of ${HEALTHS.join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
const { items, nextCursor, unreadableRails } = await new GrantsClient(creds.operatorKey, creds.agentId, env.baseUrl).listGrants({
|
|
62
|
+
scopeKind,
|
|
63
|
+
// Reach = live grants only by default; pass health to see expired/revoked.
|
|
64
|
+
health: healthArg ?? 'active',
|
|
65
|
+
cursor: args['cursor'],
|
|
66
|
+
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
count: items.length,
|
|
70
|
+
grants: items,
|
|
71
|
+
nextCursor,
|
|
72
|
+
...(unreadableRails?.length ? { unreadableRails } : {}),
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
sdkOptions: { isGenericFallback: true },
|
|
76
|
+
};
|
|
77
|
+
export const GRANTS_CAPABILITIES = [listGrantsCapability];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { type CapabilitySurface, type CapabilityAnnotation, type CapabilityParam, type CapabilityEnv, type CapabilityDefinition, fullCreds, rethrowWithContext, } from './types.js';
|
|
2
|
+
export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
|
|
3
|
+
export { LINK_CAPABILITIES, requestLinkCapability, createLinkInviteCapability, claimLinkInviteCapability, listLinksCapability, revokeLinkCapability, linkSummary, linkIsReachOnly, } from './links.js';
|
|
4
|
+
export { GRANTS_CAPABILITIES, listGrantsCapability } from './grants.js';
|
|
5
|
+
export { CONTEXT_CAPABILITIES, contextReadCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, contextBounds, resolveOrgScopeId, } from './context.js';
|
|
6
|
+
export { CONNECTION_CAPABILITIES, connectionProxyCapability, requestConnectionCapability, } from './connections.js';
|
|
7
|
+
export { DISCOVERY_CAPABILITIES, agentSearchCapability, agentGetCapability, } from './discovery.js';
|
|
8
|
+
export { ARTIFACT_CAPABILITIES, recordArtifactCapability } from './artifacts.js';
|
|
9
|
+
export { CHAT_CAPABILITIES, openConversationCapability } from './chat.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { fullCreds, rethrowWithContext, } from './types.js';
|
|
2
|
+
export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
|
|
3
|
+
export { LINK_CAPABILITIES, requestLinkCapability, createLinkInviteCapability, claimLinkInviteCapability, listLinksCapability, revokeLinkCapability, linkSummary, linkIsReachOnly, } from './links.js';
|
|
4
|
+
export { GRANTS_CAPABILITIES, listGrantsCapability } from './grants.js';
|
|
5
|
+
export { CONTEXT_CAPABILITIES, contextReadCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, contextBounds, resolveOrgScopeId, } from './context.js';
|
|
6
|
+
export { CONNECTION_CAPABILITIES, connectionProxyCapability, requestConnectionCapability, } from './connections.js';
|
|
7
|
+
export { DISCOVERY_CAPABILITIES, agentSearchCapability, agentGetCapability, } from './discovery.js';
|
|
8
|
+
export { ARTIFACT_CAPABILITIES, recordArtifactCapability } from './artifacts.js';
|
|
9
|
+
export { CHAT_CAPABILITIES, openConversationCapability } from './chat.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Agreement } from '../types.js';
|
|
2
|
+
import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* ZIG-670 — link-shaped summaries, not raw agreement documents: the money
|
|
5
|
+
* block, approvals array, and Mongo internals are noise on a trust
|
|
6
|
+
* relationship. ZIG-956 moved this into the shared layer so the MCP mutations
|
|
7
|
+
* return it too (they used to leak the raw agreement doc).
|
|
8
|
+
*/
|
|
9
|
+
export declare function linkSummary(a: Agreement): Record<string, unknown>;
|
|
10
|
+
/** A link is reach-only — the follow-up move differs by surface tool names. */
|
|
11
|
+
export declare function linkIsReachOnly(env: CapabilityEnv): string;
|
|
12
|
+
export declare const requestLinkCapability: CapabilityDefinition;
|
|
13
|
+
export declare const createLinkInviteCapability: CapabilityDefinition;
|
|
14
|
+
export declare const claimLinkInviteCapability: CapabilityDefinition;
|
|
15
|
+
export declare const listLinksCapability: CapabilityDefinition;
|
|
16
|
+
export declare const revokeLinkCapability: CapabilityDefinition;
|
|
17
|
+
export declare const LINK_CAPABILITIES: CapabilityDefinition[];
|