@ziggs-ai/agent-sdk 0.2.1 → 0.2.2
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/AgentHost.d.ts +9 -0
- package/dist/AgentHost.js +2 -0
- package/dist/adapters/McpAdapter.js +14 -13
- package/dist/agent/ClaudeSdkAgent.d.ts +5 -0
- package/dist/agent/ClaudeSdkAgent.js +12 -2
- package/dist/agent/claudeCognition.d.ts +7 -0
- package/dist/agent/claudeCognition.js +38 -7
- package/dist/agent/claudeSdkTools.js +17 -2
- package/dist/index.d.ts +2 -5
- package/dist/index.js +10 -4
- package/dist/server/tools/index.d.ts +7 -3
- package/dist/server/tools/index.js +13 -3
- package/dist/server/tools/tier2/artifactTools.d.ts +3 -0
- package/dist/server/tools/tier2/artifactTools.js +82 -0
- package/dist/server/tools/tier2/chatTools.d.ts +3 -0
- package/dist/server/tools/tier2/chatTools.js +37 -0
- package/dist/server/tools/tier2/connectionTools.d.ts +1 -0
- package/dist/server/tools/tier2/connectionTools.js +52 -5
- package/dist/server/tools/tier2/contextTools.d.ts +4 -2
- package/dist/server/tools/tier2/contextTools.js +105 -12
- package/dist/server/tools/tier2/grantsTools.d.ts +3 -0
- package/dist/server/tools/tier2/grantsTools.js +81 -0
- package/dist/server/tools/tier2/linkTools.d.ts +7 -0
- package/dist/server/tools/tier2/linkTools.js +156 -0
- package/dist/server/tools/tier2/paymentTools.d.ts +0 -1
- package/dist/server/tools/tier2/paymentTools.js +9 -13
- package/package.json +2 -2
- package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +0 -35
- package/dist/server/ziggsconnect/ZiggsConnectClient.js +0 -95
- package/dist/server/ziggscontext/ZiggsContextClient.d.ts +0 -53
- package/dist/server/ziggscontext/ZiggsContextClient.js +0 -124
- package/dist/server/ziggspay/ZiggsPayClient.d.ts +0 -82
- package/dist/server/ziggspay/ZiggsPayClient.js +0 -203
|
@@ -1,16 +1,78 @@
|
|
|
1
1
|
import { defineTool } from '../../../tools/defineTool.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ContextDiscoveryClient, ContextGrantsClient, ContextReadClient, } from '@ziggs-ai/api-client';
|
|
3
|
+
/**
|
|
4
|
+
* Context grant calls impersonate the grant holder, so both operatorKey (fleet
|
|
5
|
+
* or agent-scoped key) and agentId (X-Agent-Id) must be on the tool context.
|
|
6
|
+
* The same api-client clients back ziggs-mcp — one wire contract, no fork
|
|
7
|
+
* (ZIG-869 / ZIG-775).
|
|
8
|
+
*/
|
|
9
|
+
function creds(ctx) {
|
|
4
10
|
const operatorKey = ctx?.['operatorKey'];
|
|
11
|
+
const agentId = ctx?.['agentId'];
|
|
5
12
|
if (!operatorKey)
|
|
6
13
|
throw new Error('operatorKey missing from tool context');
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
});
|
|
14
|
+
if (!agentId)
|
|
15
|
+
throw new Error('agentId missing from tool context');
|
|
16
|
+
return { operatorKey, agentId };
|
|
11
17
|
}
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
const CONTEXT_READ_TYPES = [
|
|
19
|
+
'messages',
|
|
20
|
+
'artifacts',
|
|
21
|
+
'agreements',
|
|
22
|
+
'tasks',
|
|
23
|
+
];
|
|
24
|
+
export const contextReadTool = defineTool('context_read', {
|
|
25
|
+
type: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
required: true,
|
|
28
|
+
enum: [...CONTEXT_READ_TYPES],
|
|
29
|
+
description: 'Resource type to read from the scope',
|
|
30
|
+
},
|
|
31
|
+
via: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
required: true,
|
|
34
|
+
description: 'Scope entry you hold, e.g. chat:<id>, agreement:<id>, task:<id>',
|
|
35
|
+
},
|
|
36
|
+
cursor: { type: 'string', description: 'Opaque cursor from a prior nextCursor to page' },
|
|
37
|
+
after: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'ISO timestamp for forward-delta (messages/artifacts)',
|
|
40
|
+
},
|
|
41
|
+
direction: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
enum: ['forward'],
|
|
44
|
+
description: 'Use "forward" with after for a message forward-delta',
|
|
45
|
+
},
|
|
46
|
+
limit: { type: 'number', description: 'Page size (server default when omitted)' },
|
|
47
|
+
state: { type: 'string', description: 'Task state filter (tasks only)' },
|
|
48
|
+
contextGrantId: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Pin a specific grant when you hold several over the same scope',
|
|
51
|
+
},
|
|
52
|
+
}, async (args, ctx) => {
|
|
53
|
+
const { operatorKey, agentId } = creds(ctx);
|
|
54
|
+
const type = args['type'];
|
|
55
|
+
if (!CONTEXT_READ_TYPES.includes(type)) {
|
|
56
|
+
throw new Error(`type must be one of ${CONTEXT_READ_TYPES.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
const via = args['via'];
|
|
59
|
+
if (!via)
|
|
60
|
+
throw new Error('via is required');
|
|
61
|
+
const direction = args['direction'];
|
|
62
|
+
if (direction !== undefined && direction !== 'forward') {
|
|
63
|
+
throw new Error('direction must be "forward"');
|
|
64
|
+
}
|
|
65
|
+
return new ContextReadClient(operatorKey, agentId).read(type, {
|
|
66
|
+
via,
|
|
67
|
+
cursor: args['cursor'],
|
|
68
|
+
after: args['after'],
|
|
69
|
+
direction: direction,
|
|
70
|
+
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
71
|
+
state: args['state'],
|
|
72
|
+
contextGrantId: args['contextGrantId'],
|
|
73
|
+
});
|
|
74
|
+
}, {
|
|
75
|
+
description: '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.',
|
|
14
76
|
});
|
|
15
77
|
export const contextDelegateTool = defineTool('context_delegate', {
|
|
16
78
|
parentGrantId: { type: 'string', required: true },
|
|
@@ -29,8 +91,8 @@ export const contextDelegateTool = defineTool('context_delegate', {
|
|
|
29
91
|
if (scopeKind !== 'chat' && scopeKind !== 'agreement' && scopeKind !== 'org') {
|
|
30
92
|
throw new Error('scopeKind must be chat, agreement, or org');
|
|
31
93
|
}
|
|
32
|
-
|
|
33
|
-
|
|
94
|
+
const { operatorKey, agentId } = creds(ctx);
|
|
95
|
+
return new ContextGrantsClient(operatorKey, agentId).delegateGrant(args['parentGrantId'], {
|
|
34
96
|
holderId: args['holderId'],
|
|
35
97
|
scope: { kind: scopeKind, id: args['scopeId'] },
|
|
36
98
|
temporal,
|
|
@@ -38,9 +100,40 @@ export const contextDelegateTool = defineTool('context_delegate', {
|
|
|
38
100
|
watermarkAt: args['watermarkAt'],
|
|
39
101
|
});
|
|
40
102
|
}, {
|
|
41
|
-
description: 'Delegate a narrower child context grant (tighter scope, shorter expiry, or from-now). Holder-only.',
|
|
103
|
+
description: '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).',
|
|
104
|
+
});
|
|
105
|
+
export const contextExpandReachTool = defineTool('context_expand_reach', {
|
|
106
|
+
grantId: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
required: true,
|
|
109
|
+
description: 'A grant you hold (grantId from list_grants) to expand',
|
|
110
|
+
},
|
|
111
|
+
}, async (args, ctx) => {
|
|
112
|
+
const { operatorKey, agentId } = creds(ctx);
|
|
113
|
+
const grantId = args['grantId'];
|
|
114
|
+
if (!grantId)
|
|
115
|
+
throw new Error('grantId is required');
|
|
116
|
+
return new ContextGrantsClient(operatorKey, agentId).getReach(grantId);
|
|
117
|
+
}, {
|
|
118
|
+
description: '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.',
|
|
119
|
+
});
|
|
120
|
+
// ZIG-754 — the negative-space complement to the reach tools. list_grants /
|
|
121
|
+
// context_expand_reach answer "what CAN I read?"; this answers "what exists
|
|
122
|
+
// just outside my fence that I CAN'T read yet?" so the agent can flag missing
|
|
123
|
+
// context and make an informed widen request instead of silently
|
|
124
|
+
// under-delivering on partial context. The MCP surface has had this as
|
|
125
|
+
// ziggs_discover_grantable; this is its SDK/legibility complement, backed by
|
|
126
|
+
// the same ContextDiscoveryClient (one wire contract, no fork).
|
|
127
|
+
export const contextDiscoverGrantableTool = defineTool('context_discover_grantable', {}, async (_args, ctx) => {
|
|
128
|
+
const { operatorKey, agentId } = creds(ctx);
|
|
129
|
+
const items = await new ContextDiscoveryClient(operatorKey, agentId).discoverGrantable();
|
|
130
|
+
return { count: items.length, items };
|
|
131
|
+
}, {
|
|
132
|
+
description: 'See what context EXISTS in your orgs that you CANNOT read yet — the inverse of list_grants. 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).',
|
|
42
133
|
});
|
|
43
134
|
export const CONTEXT_TOOLS = [
|
|
44
|
-
|
|
135
|
+
contextReadTool,
|
|
45
136
|
contextDelegateTool,
|
|
137
|
+
contextExpandReachTool,
|
|
138
|
+
contextDiscoverGrantableTool,
|
|
46
139
|
];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { defineTool } from '../../../tools/defineTool.js';
|
|
2
|
+
import { GrantsClient, unreadableGrantRails, } from '@ziggs-ai/api-client';
|
|
3
|
+
/**
|
|
4
|
+
* ZIG-893 — the single "what authority do I hold?" tool. One name, every rail
|
|
5
|
+
* (context chat/agreement/org, connection, wallet), holder-scoped, cross-session.
|
|
6
|
+
* Wraps the unified `GET /grants` (GrantsClient) that already replaced the three
|
|
7
|
+
* per-rail listers server-side; this lifts that unification up to the tool layer
|
|
8
|
+
* so an agent no longer has to know three tool names — or, as in the 2026-07-20
|
|
9
|
+
* incident, tell its principal grant lookup doesn't exist because its config
|
|
10
|
+
* happened to omit the one rail's lister.
|
|
11
|
+
*/
|
|
12
|
+
function creds(ctx) {
|
|
13
|
+
const operatorKey = ctx?.['operatorKey'];
|
|
14
|
+
const agentId = ctx?.['agentId'];
|
|
15
|
+
if (!operatorKey)
|
|
16
|
+
throw new Error('operatorKey missing from tool context');
|
|
17
|
+
if (!agentId)
|
|
18
|
+
throw new Error('agentId missing from tool context');
|
|
19
|
+
return { operatorKey, agentId };
|
|
20
|
+
}
|
|
21
|
+
const SCOPE_KINDS = [
|
|
22
|
+
'chat',
|
|
23
|
+
'agreement',
|
|
24
|
+
'org',
|
|
25
|
+
'connection',
|
|
26
|
+
'wallet',
|
|
27
|
+
];
|
|
28
|
+
const HEALTHS = ['active', 'expired', 'revoked'];
|
|
29
|
+
function parseScopeKinds(raw) {
|
|
30
|
+
if (raw == null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const r of list) {
|
|
35
|
+
if (!SCOPE_KINDS.includes(r)) {
|
|
36
|
+
throw new Error(`scopeKind must be one of ${SCOPE_KINDS.join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
if (!out.includes(r))
|
|
39
|
+
out.push(r);
|
|
40
|
+
}
|
|
41
|
+
return out.length ? out : undefined;
|
|
42
|
+
}
|
|
43
|
+
export const listGrantsTool = defineTool('list_grants', {
|
|
44
|
+
scopeKind: {
|
|
45
|
+
type: 'array',
|
|
46
|
+
items: { type: 'string', enum: [...SCOPE_KINDS] },
|
|
47
|
+
description: 'Rail filter (repeatable): chat | agreement | org (context) | connection | wallet. Omit for every rail you can read.',
|
|
48
|
+
},
|
|
49
|
+
health: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
enum: [...HEALTHS],
|
|
52
|
+
description: 'Grant health filter. Defaults to active (live grants only).',
|
|
53
|
+
},
|
|
54
|
+
cursor: { type: 'string', description: 'Opaque cursor from a prior nextCursor to page' },
|
|
55
|
+
limit: { type: 'number', description: 'Page size (server default when omitted)' },
|
|
56
|
+
}, async (args, ctx) => {
|
|
57
|
+
const { operatorKey, agentId } = creds(ctx);
|
|
58
|
+
const scopeKind = parseScopeKinds(args['scopeKind']);
|
|
59
|
+
const healthArg = args['health'];
|
|
60
|
+
if (healthArg !== undefined && !HEALTHS.includes(healthArg)) {
|
|
61
|
+
throw new Error(`health must be one of ${HEALTHS.join(', ')}`);
|
|
62
|
+
}
|
|
63
|
+
const { items, nextCursor } = await new GrantsClient(operatorKey, agentId).listGrants({
|
|
64
|
+
scopeKind,
|
|
65
|
+
// Reach = live grants only by default; pass health to see expired/revoked.
|
|
66
|
+
health: healthArg ?? 'active',
|
|
67
|
+
cursor: args['cursor'],
|
|
68
|
+
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
69
|
+
});
|
|
70
|
+
const unreadable = unreadableGrantRails(operatorKey, scopeKind);
|
|
71
|
+
return {
|
|
72
|
+
count: items.length,
|
|
73
|
+
grants: items,
|
|
74
|
+
nextCursor,
|
|
75
|
+
...(unreadable && unreadable.length ? { unreadableRails: unreadable } : {}),
|
|
76
|
+
};
|
|
77
|
+
}, {
|
|
78
|
+
description: '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.',
|
|
79
|
+
isGenericFallback: true,
|
|
80
|
+
});
|
|
81
|
+
export const GRANTS_TOOLS = [listGrantsTool];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ToolDefinition } from '../../../tools/defineTool.js';
|
|
2
|
+
export declare const requestLinkTool: ToolDefinition;
|
|
3
|
+
export declare const createLinkInviteTool: ToolDefinition;
|
|
4
|
+
export declare const claimLinkInviteTool: ToolDefinition;
|
|
5
|
+
export declare const listLinksTool: ToolDefinition;
|
|
6
|
+
export declare const revokeLinkTool: ToolDefinition;
|
|
7
|
+
export declare const LINK_TOOLS: ToolDefinition[];
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { defineTool } from '../../../tools/defineTool.js';
|
|
2
|
+
import { createAgreement, claimAgreement, listAgreements, revokeAgreement, } from '@ziggs-ai/api-client';
|
|
3
|
+
/**
|
|
4
|
+
* ZIG-898 — link tools on the SDK surface, same base names as ziggs-mcp's
|
|
5
|
+
* trustTools (ziggs_request_link → request_link, …). Links are agreements with
|
|
6
|
+
* engagementKind 'link' — bilateral agent-to-agent trust that gives unpublished
|
|
7
|
+
* delegates cross-org reach. No new endpoints: everything rides the agreements
|
|
8
|
+
* rail exactly as the MCP tools do.
|
|
9
|
+
*
|
|
10
|
+
* A link is reach-only: it lets the peers find and message each other, never
|
|
11
|
+
* read context — grants stay separate (context_delegate / the owner's grant
|
|
12
|
+
* tools).
|
|
13
|
+
*/
|
|
14
|
+
function creds(ctx) {
|
|
15
|
+
const operatorKey = ctx?.['operatorKey'];
|
|
16
|
+
const agentId = ctx?.['agentId'];
|
|
17
|
+
if (!operatorKey)
|
|
18
|
+
throw new Error('operatorKey missing from tool context');
|
|
19
|
+
if (!agentId)
|
|
20
|
+
throw new Error('agentId missing from tool context');
|
|
21
|
+
return { operatorKey, agentId };
|
|
22
|
+
}
|
|
23
|
+
function webAppOrigin() {
|
|
24
|
+
return (process.env.ZIGGS_WEB_URL?.trim() || 'https://ziggsai.com').replace(/\/$/, '');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* ZIG-670 rule carried over from the MCP tools: link-shaped summaries, not raw
|
|
28
|
+
* agreement documents — the money block, approvals array, and Mongo internals
|
|
29
|
+
* are noise on a trust relationship.
|
|
30
|
+
*/
|
|
31
|
+
function linkSummary(a) {
|
|
32
|
+
return {
|
|
33
|
+
agreementId: a.agreementId,
|
|
34
|
+
status: a.status,
|
|
35
|
+
proposalStatus: a.proposalStatus,
|
|
36
|
+
parties: {
|
|
37
|
+
creatorAgent: a.parties?.creatorAgent ?? null,
|
|
38
|
+
providerAgent: a.parties?.providerAgent ?? null,
|
|
39
|
+
creator: a.parties?.creator ?? null,
|
|
40
|
+
proposedTo: a.parties?.proposedTo ?? null,
|
|
41
|
+
},
|
|
42
|
+
...(a.description ? { description: a.description } : {}),
|
|
43
|
+
createdAt: a.createdAt,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const LINK_IS_REACH_ONLY = 'A link is reach-only: it does not grant context. Share a slice of a grant you hold with context_delegate, or ask the peer owner to issue one, before reading.';
|
|
47
|
+
export const requestLinkTool = defineTool('request_link', {
|
|
48
|
+
providerId: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
required: true,
|
|
51
|
+
description: 'Bare agent id to link with (the target delegate). Use agent_search or a known delegate id — do not guess.',
|
|
52
|
+
},
|
|
53
|
+
message: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'Optional note shown to the counterparty human on approval (agreement description)',
|
|
56
|
+
},
|
|
57
|
+
}, async (args, ctx) => {
|
|
58
|
+
const { agreement } = await createAgreement({
|
|
59
|
+
engagementKind: 'link',
|
|
60
|
+
providerId: args['providerId'],
|
|
61
|
+
description: args['message'],
|
|
62
|
+
}, creds(ctx));
|
|
63
|
+
return {
|
|
64
|
+
status: 'pending',
|
|
65
|
+
message: 'Link agreement created — the counterparty owner must approve (agreement_respond on their side) before cross-org reach. Surface pending state to your principal.',
|
|
66
|
+
agreement: linkSummary(agreement),
|
|
67
|
+
};
|
|
68
|
+
}, {
|
|
69
|
+
description: 'Request a bilateral trust link with another agent before cross-org reach (party-to-party, NOT a third-party service connection — that is the connection rail). A link is just an agreement (engagementKind "link"). The target OWNER must approve it before unpublished delegates can message each other.',
|
|
70
|
+
isAgreementCreation: true,
|
|
71
|
+
});
|
|
72
|
+
export const createLinkInviteTool = defineTool('create_link_invite', {
|
|
73
|
+
message: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'Optional note shown to whoever opens the invite (agreement description)',
|
|
76
|
+
},
|
|
77
|
+
}, async (args, ctx) => {
|
|
78
|
+
const { agreement } = await createAgreement({ engagementKind: 'link', description: args['message'] }, creds(ctx));
|
|
79
|
+
return {
|
|
80
|
+
status: 'open',
|
|
81
|
+
inviteId: agreement.agreementId,
|
|
82
|
+
claimUrl: `${webAppOrigin()}/app/link-invites/${agreement.agreementId}`,
|
|
83
|
+
message: 'Open link invite created. Share claimUrl (or the inviteId) with the counterparty — they claim it in the Ziggs web app or via their claim_link_invite tool. No agent id needed on either side. Revoke with revoke_link to disable.',
|
|
84
|
+
agreement: linkSummary(agreement),
|
|
85
|
+
};
|
|
86
|
+
}, {
|
|
87
|
+
description: "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; the recipient forms the link by claiming the returned inviteId.",
|
|
88
|
+
isAgreementCreation: true,
|
|
89
|
+
});
|
|
90
|
+
export const claimLinkInviteTool = defineTool('claim_link_invite', {
|
|
91
|
+
agreementId: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
required: true,
|
|
94
|
+
description: 'The invite id (agreementId) shared by the issuer',
|
|
95
|
+
},
|
|
96
|
+
}, async (args, ctx) => {
|
|
97
|
+
const { agreement } = await claimAgreement(args['agreementId'], creds(ctx));
|
|
98
|
+
return {
|
|
99
|
+
status: 'linked',
|
|
100
|
+
message: `Link invite claimed — you are now linked. ${LINK_IS_REACH_ONLY}`,
|
|
101
|
+
agreement: linkSummary(agreement),
|
|
102
|
+
};
|
|
103
|
+
}, {
|
|
104
|
+
description: 'Claim an open link invite by its id to form a bilateral link. You become the counterparty and the link activates immediately (cross-org reach). You cannot claim your own invite.',
|
|
105
|
+
});
|
|
106
|
+
export const listLinksTool = defineTool('list_links', {
|
|
107
|
+
status: {
|
|
108
|
+
type: 'string',
|
|
109
|
+
enum: ['active', 'open', 'cancelled', 'all'],
|
|
110
|
+
description: 'active (default) = established links; open = pending proposals/invites awaiting approval or claim; cancelled = revoked; all = every link regardless of status',
|
|
111
|
+
},
|
|
112
|
+
}, async (args, ctx) => {
|
|
113
|
+
const status = args['status'] ?? 'active';
|
|
114
|
+
if (!['active', 'open', 'cancelled', 'all'].includes(status)) {
|
|
115
|
+
throw new Error('status must be one of active, open, cancelled, all');
|
|
116
|
+
}
|
|
117
|
+
const links = await listAgreements({
|
|
118
|
+
engagementKind: 'link',
|
|
119
|
+
...(status === 'all' ? {} : { status }),
|
|
120
|
+
}, creds(ctx));
|
|
121
|
+
const summaries = links.map(linkSummary);
|
|
122
|
+
const hasActive = links.some((a) => a.status === 'active');
|
|
123
|
+
return {
|
|
124
|
+
count: summaries.length,
|
|
125
|
+
status,
|
|
126
|
+
links: summaries,
|
|
127
|
+
...(hasActive ? { nextSteps: LINK_IS_REACH_ONLY } : {}),
|
|
128
|
+
};
|
|
129
|
+
}, {
|
|
130
|
+
description: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). 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.',
|
|
131
|
+
isGenericFallback: true,
|
|
132
|
+
});
|
|
133
|
+
export const revokeLinkTool = defineTool('revoke_link', {
|
|
134
|
+
agreementId: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
required: true,
|
|
137
|
+
description: 'agreementId of the link agreement (from list_links)',
|
|
138
|
+
},
|
|
139
|
+
}, async (args, ctx) => {
|
|
140
|
+
const result = await revokeAgreement(args['agreementId'], creds(ctx));
|
|
141
|
+
return {
|
|
142
|
+
status: 'revoked',
|
|
143
|
+
message: 'Link revoked — unpublished cross-org reach to this peer is blocked again.',
|
|
144
|
+
agreementId: args['agreementId'],
|
|
145
|
+
agreement: result.agreement ? linkSummary(result.agreement) : null,
|
|
146
|
+
};
|
|
147
|
+
}, {
|
|
148
|
+
description: 'Revoke a bilateral link agreement (DELETE /agreements/:agreementId). Either party may revoke; cross-org reach ends immediately. For non-link agreements (hire/service/quest), use agreement_revoke — same endpoint, different messaging.',
|
|
149
|
+
});
|
|
150
|
+
export const LINK_TOOLS = [
|
|
151
|
+
requestLinkTool,
|
|
152
|
+
createLinkInviteTool,
|
|
153
|
+
claimLinkInviteTool,
|
|
154
|
+
listLinksTool,
|
|
155
|
+
revokeLinkTool,
|
|
156
|
+
];
|
|
@@ -8,5 +8,4 @@ export declare const paymentReleaseTool: ToolDefinition;
|
|
|
8
8
|
export declare const paymentIssueGrantTool: ToolDefinition;
|
|
9
9
|
export declare const paymentAttenuateGrantTool: ToolDefinition;
|
|
10
10
|
export declare const paymentRevokeGrantTool: ToolDefinition;
|
|
11
|
-
export declare const paymentListGrantsTool: ToolDefinition;
|
|
12
11
|
export declare const PAYMENT_TOOLS: ToolDefinition[];
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { defineTool } from '../../../tools/defineTool.js';
|
|
2
|
-
import {
|
|
2
|
+
import { PaymentsClient } from '@ziggs-ai/api-client';
|
|
3
3
|
function clientFor(ctx) {
|
|
4
4
|
const operatorKey = ctx?.['operatorKey'];
|
|
5
5
|
if (!operatorKey)
|
|
6
6
|
throw new Error('operatorKey missing from tool context');
|
|
7
|
-
|
|
7
|
+
// BACKEND_URL / ZIGGS_BACKEND_URL are the SDK runner's overrides; the shared
|
|
8
|
+
// client defaults to HTTP_URL (api-client convention) when neither is set.
|
|
9
|
+
const baseUrl = process.env.BACKEND_URL || process.env.ZIGGS_BACKEND_URL || undefined;
|
|
10
|
+
return new PaymentsClient(operatorKey, ctx?.['agentId'] || undefined, baseUrl);
|
|
8
11
|
}
|
|
9
12
|
function rethrowWithContext(error, prefix) {
|
|
10
13
|
const e = error;
|
|
@@ -148,18 +151,11 @@ const revokeGrantHandler = async (args, ctx) => {
|
|
|
148
151
|
}
|
|
149
152
|
};
|
|
150
153
|
export const paymentRevokeGrantTool = defineTool('payment_revoke_grant', { grantId: { type: 'string', required: true } }, revokeGrantHandler);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return { grants: result || [] };
|
|
155
|
-
}
|
|
156
|
-
catch (e) {
|
|
157
|
-
rethrowWithContext(e, 'Failed to list payment grants');
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
export const paymentListGrantsTool = defineTool('payment_list_grants', {}, listGrantsHandler);
|
|
154
|
+
// ZIG-893 — payment_list_grants retired; the wallet rail is now part of the
|
|
155
|
+
// unified list_grants tool (scopeKind: 'wallet'). Grant *mutations* stay on the
|
|
156
|
+
// payment rail (issue/attenuate/revoke below).
|
|
161
157
|
export const PAYMENT_TOOLS = [
|
|
162
158
|
paymentBalanceTool, paymentTransferTool, paymentWaitForApprovalTool,
|
|
163
159
|
paymentHoldTool, paymentReleaseTool, paymentResolveWalletTool,
|
|
164
|
-
paymentIssueGrantTool, paymentAttenuateGrantTool, paymentRevokeGrantTool,
|
|
160
|
+
paymentIssueGrantTool, paymentAttenuateGrantTool, paymentRevokeGrantTool,
|
|
165
161
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@anthropic-ai/claude-agent-sdk": "^0.3.204",
|
|
27
27
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
-
"@ziggs-ai/api-client": "^0.1.
|
|
29
|
+
"@ziggs-ai/api-client": "^0.1.30",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
export interface ZiggsConnectClientOptions {
|
|
3
|
-
operatorKey: string;
|
|
4
|
-
actAsAgentId?: string;
|
|
5
|
-
baseUrl?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface ProxyParams {
|
|
8
|
-
connectionId: string;
|
|
9
|
-
grantId: string;
|
|
10
|
-
action: string;
|
|
11
|
-
payload?: unknown;
|
|
12
|
-
}
|
|
13
|
-
export declare class ZiggsConnectClient {
|
|
14
|
-
private operatorKey;
|
|
15
|
-
private actAsAgentId;
|
|
16
|
-
private baseUrl;
|
|
17
|
-
constructor({ operatorKey, actAsAgentId, baseUrl }: ZiggsConnectClientOptions);
|
|
18
|
-
/**
|
|
19
|
-
* Present a ConnectionGrant to the broker and perform a provider action.
|
|
20
|
-
* Returns the provider result — never the raw OAuth token.
|
|
21
|
-
*/
|
|
22
|
-
proxy({ connectionId, grantId, action, payload }: ProxyParams): Promise<unknown>;
|
|
23
|
-
/**
|
|
24
|
-
* List ConnectionGrants held by this agent for a connection.
|
|
25
|
-
* Requires actAsAgentId; filters server rows to holderId === agent.
|
|
26
|
-
*/
|
|
27
|
-
listGrants({ connectionId }: {
|
|
28
|
-
connectionId: string;
|
|
29
|
-
}): Promise<unknown[]>;
|
|
30
|
-
private _buildHeaders;
|
|
31
|
-
private _request;
|
|
32
|
-
private _get;
|
|
33
|
-
private _post;
|
|
34
|
-
}
|
|
35
|
-
export declare function createZiggsConnectClient(opts: ZiggsConnectClientOptions): ZiggsConnectClient;
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
function getDefaultBaseUrl() {
|
|
3
|
-
return process.env.BACKEND_URL || process.env.ZIGGS_BACKEND_URL || 'http://localhost:3000';
|
|
4
|
-
}
|
|
5
|
-
function parseError(text, fallback) {
|
|
6
|
-
if (!text)
|
|
7
|
-
return fallback;
|
|
8
|
-
try {
|
|
9
|
-
const parsed = JSON.parse(text);
|
|
10
|
-
return parsed['message'] || parsed['error'] || text;
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return text;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export class ZiggsConnectClient {
|
|
17
|
-
operatorKey;
|
|
18
|
-
actAsAgentId;
|
|
19
|
-
baseUrl;
|
|
20
|
-
constructor({ operatorKey, actAsAgentId, baseUrl }) {
|
|
21
|
-
if (!operatorKey || typeof operatorKey !== 'string') {
|
|
22
|
-
throw new Error('ZiggsConnectClient requires an operatorKey');
|
|
23
|
-
}
|
|
24
|
-
this.operatorKey = operatorKey;
|
|
25
|
-
this.actAsAgentId = actAsAgentId || null;
|
|
26
|
-
this.baseUrl = baseUrl || getDefaultBaseUrl();
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Present a ConnectionGrant to the broker and perform a provider action.
|
|
30
|
-
* Returns the provider result — never the raw OAuth token.
|
|
31
|
-
*/
|
|
32
|
-
async proxy({ connectionId, grantId, action, payload }) {
|
|
33
|
-
if (!connectionId)
|
|
34
|
-
throw new Error('proxy: connectionId is required');
|
|
35
|
-
if (!grantId)
|
|
36
|
-
throw new Error('proxy: grantId is required');
|
|
37
|
-
if (!action)
|
|
38
|
-
throw new Error('proxy: action is required');
|
|
39
|
-
if (!this.actAsAgentId) {
|
|
40
|
-
throw new Error('proxy: actAsAgentId is required — connection broker calls must impersonate the grant holder agent');
|
|
41
|
-
}
|
|
42
|
-
const res = (await this._post(`/connections/${encodeURIComponent(connectionId)}/proxy`, {
|
|
43
|
-
grantId,
|
|
44
|
-
action,
|
|
45
|
-
payload: payload ?? {},
|
|
46
|
-
}));
|
|
47
|
-
return res['result'] ?? res;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* List ConnectionGrants held by this agent for a connection.
|
|
51
|
-
* Requires actAsAgentId; filters server rows to holderId === agent.
|
|
52
|
-
*/
|
|
53
|
-
async listGrants({ connectionId }) {
|
|
54
|
-
if (!connectionId)
|
|
55
|
-
throw new Error('listGrants: connectionId is required');
|
|
56
|
-
if (!this.actAsAgentId) {
|
|
57
|
-
throw new Error('listGrants: actAsAgentId is required — grants are scoped to the impersonated agent');
|
|
58
|
-
}
|
|
59
|
-
const res = (await this._get(`/connections/${encodeURIComponent(connectionId)}/grants`));
|
|
60
|
-
const grants = res['grants'] || [];
|
|
61
|
-
return grants.filter((g) => g['holderId'] === this.actAsAgentId);
|
|
62
|
-
}
|
|
63
|
-
_buildHeaders(extra = {}) {
|
|
64
|
-
const h = { Authorization: `Bearer ${this.operatorKey}`, ...extra };
|
|
65
|
-
if (this.actAsAgentId)
|
|
66
|
-
h['X-Agent-Id'] = this.actAsAgentId;
|
|
67
|
-
return h;
|
|
68
|
-
}
|
|
69
|
-
async _request(method, path, body) {
|
|
70
|
-
const init = {
|
|
71
|
-
method,
|
|
72
|
-
headers: this._buildHeaders(body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
73
|
-
};
|
|
74
|
-
if (body !== undefined)
|
|
75
|
-
init.body = JSON.stringify(body);
|
|
76
|
-
const response = await fetch(`${this.baseUrl}${path}`, init);
|
|
77
|
-
const text = await response.text();
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
const err = new Error(parseError(text, `HTTP ${response.status}`));
|
|
80
|
-
err.status = response.status;
|
|
81
|
-
err.body = text;
|
|
82
|
-
throw err;
|
|
83
|
-
}
|
|
84
|
-
return text ? JSON.parse(text) : null;
|
|
85
|
-
}
|
|
86
|
-
_get(path) {
|
|
87
|
-
return this._request('GET', path, undefined);
|
|
88
|
-
}
|
|
89
|
-
_post(path, body) {
|
|
90
|
-
return this._request('POST', path, body ?? {});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
export function createZiggsConnectClient(opts) {
|
|
94
|
-
return new ZiggsConnectClient(opts);
|
|
95
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
export interface ZiggsContextClientOptions {
|
|
3
|
-
operatorKey: string;
|
|
4
|
-
actAsAgentId?: string;
|
|
5
|
-
baseUrl?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface ContextReachDescriptor {
|
|
8
|
-
grantId: string;
|
|
9
|
-
scope: {
|
|
10
|
-
kind: 'chat' | 'agreement' | 'org';
|
|
11
|
-
id: string;
|
|
12
|
-
};
|
|
13
|
-
temporal: 'from-now' | 'from-start';
|
|
14
|
-
watermarkAt: string;
|
|
15
|
-
expiresAt: string | null;
|
|
16
|
-
parentGrantId: string | null;
|
|
17
|
-
createdAt: string;
|
|
18
|
-
}
|
|
19
|
-
export interface DelegateContextGrantParams {
|
|
20
|
-
parentGrantId: string;
|
|
21
|
-
holderId: string;
|
|
22
|
-
scope: {
|
|
23
|
-
kind: 'chat' | 'agreement' | 'org';
|
|
24
|
-
id: string;
|
|
25
|
-
};
|
|
26
|
-
temporal: 'from-now' | 'from-start';
|
|
27
|
-
expiresAt?: string | null;
|
|
28
|
-
watermarkAt?: string;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* HTTP client for context grants (ZIG-413).
|
|
32
|
-
* Presentation model (signed bytes vs grant id) is intentionally not baked in here.
|
|
33
|
-
*/
|
|
34
|
-
export declare class ZiggsContextClient {
|
|
35
|
-
private operatorKey;
|
|
36
|
-
private actAsAgentId;
|
|
37
|
-
private baseUrl;
|
|
38
|
-
constructor({ operatorKey, actAsAgentId, baseUrl }: ZiggsContextClientOptions);
|
|
39
|
-
/**
|
|
40
|
-
* Scope descriptors for what this agent can reach (no content). GET
|
|
41
|
-
* /context/discovery was retired (ZIG-648); reach is now the agent's live
|
|
42
|
-
* context grants from the unified GET /grants, mapped back to the reach shape
|
|
43
|
-
* (temporal/watermark ride in caveats). Follows the cursor for completeness.
|
|
44
|
-
*/
|
|
45
|
-
discover(): Promise<ContextReachDescriptor[]>;
|
|
46
|
-
/** Holder delegates a narrower child grant. */
|
|
47
|
-
delegate(params: DelegateContextGrantParams): Promise<unknown>;
|
|
48
|
-
private requireActAsAgent;
|
|
49
|
-
private _buildHeaders;
|
|
50
|
-
private _request;
|
|
51
|
-
private _get;
|
|
52
|
-
private _post;
|
|
53
|
-
}
|