@ziggs-ai/api-client 0.22.3 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/agreementVerbs.js +20 -1
- package/dist/capabilities/agreements.js +2 -3
- package/dist/capabilities/artifacts.js +34 -4
- package/dist/capabilities/context.js +3 -0
- package/dist/capabilities/marketplace.js +1 -0
- package/dist/capabilities/types.d.ts +2 -0
- package/dist/http/AgreementClient.d.ts +13 -0
- package/dist/http/AgreementClient.js +3 -1
- package/dist/http/ArtifactsClient.d.ts +15 -1
- package/dist/http/ArtifactsClient.js +8 -0
- package/dist/http/ChatClient.d.ts +4 -0
- package/dist/http/ChatClient.js +3 -0
- package/dist/http/ContextReadClient.d.ts +7 -0
- package/dist/http/ContextReadClient.js +9 -1
- package/dist/http/MarketplaceClient.d.ts +4 -0
- package/dist/http/TaskClient.d.ts +16 -0
- package/dist/http/TaskClient.js +24 -0
- package/dist/http/agreementFlows.js +3 -0
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
|
@@ -50,6 +50,9 @@ const TERMS_PARAMS = {
|
|
|
50
50
|
type: 'string',
|
|
51
51
|
description: 'ISO timestamp after which this can no longer be acted on.',
|
|
52
52
|
},
|
|
53
|
+
interactionMode: { type: 'string', enum: ['messages', 'tasks', 'both'], description: 'Accepted interface. Task-only services need no chat or negotiation.' },
|
|
54
|
+
conversationAllowanceScope: { type: 'string', enum: ['direct', 'subtree'], description: 'Direct by default; subtree explicitly shares the allowance with descendants.' },
|
|
55
|
+
conversationAllowance: { type: 'number', description: 'Shared incoming-message limit across covered rooms. Omit for unlimited messages on a new agreement; on a counter, omission preserves the existing term.' },
|
|
53
56
|
maxExecutions: {
|
|
54
57
|
type: 'number',
|
|
55
58
|
description: 'End the engagement after this many tasks.',
|
|
@@ -69,6 +72,9 @@ function termsFrom(args) {
|
|
|
69
72
|
...(args['expiresAt'] === undefined
|
|
70
73
|
? {}
|
|
71
74
|
: { expiresAt: args['expiresAt'] }),
|
|
75
|
+
...(args['interactionMode'] === undefined ? {} : { interactionMode: args['interactionMode'] }),
|
|
76
|
+
...(args['conversationAllowanceScope'] === undefined ? {} : { conversationAllowanceScope: args['conversationAllowanceScope'] }),
|
|
77
|
+
...(args['conversationAllowance'] === undefined ? {} : { conversationAllowance: args['conversationAllowance'] }),
|
|
72
78
|
...(args['maxExecutions'] === undefined
|
|
73
79
|
? {}
|
|
74
80
|
: { maxExecutions: args['maxExecutions'] }),
|
|
@@ -96,7 +102,7 @@ const MANDATE_PARAM = {
|
|
|
96
102
|
};
|
|
97
103
|
/** Pull the declared mandate off a validated arg bag, as the wire field. */
|
|
98
104
|
function mandateFrom(args) {
|
|
99
|
-
const declared = args['mandateAgreementId'];
|
|
105
|
+
const declared = args['parentAgreementId'] ?? args['mandateAgreementId'];
|
|
100
106
|
return typeof declared === 'string' && declared ? { parentAgreementId: declared } : {};
|
|
101
107
|
}
|
|
102
108
|
/** The audience a broadcast reaches. */
|
|
@@ -165,6 +171,7 @@ export const agreementBuyCapability = {
|
|
|
165
171
|
chatId: CHAT_PARAM,
|
|
166
172
|
...TERMS_PARAMS,
|
|
167
173
|
mandateAgreementId: MANDATE_PARAM,
|
|
174
|
+
parentAgreementId: { type: 'string', description: 'Governing agreement, including a link or negotiation agreement. This placement does not grant spending consent.' },
|
|
168
175
|
},
|
|
169
176
|
needsAgentId: true,
|
|
170
177
|
handler: async (args, env) => {
|
|
@@ -196,6 +203,7 @@ export const agreementBidCapability = {
|
|
|
196
203
|
chatId: CHAT_PARAM,
|
|
197
204
|
...TERMS_PARAMS,
|
|
198
205
|
mandateAgreementId: MANDATE_PARAM,
|
|
206
|
+
parentAgreementId: { type: 'string', description: 'Governing agreement, including a link or negotiation agreement. This placement does not grant spending consent.' },
|
|
199
207
|
},
|
|
200
208
|
needsAgentId: true,
|
|
201
209
|
handler: async (args, env) => {
|
|
@@ -235,6 +243,7 @@ export const agreementBrokerCapability = {
|
|
|
235
243
|
chatId: CHAT_PARAM,
|
|
236
244
|
...TERMS_PARAMS,
|
|
237
245
|
mandateAgreementId: MANDATE_PARAM,
|
|
246
|
+
parentAgreementId: { type: 'string', description: 'Governing agreement, including a link or negotiation agreement. This placement does not grant spending consent.' },
|
|
238
247
|
},
|
|
239
248
|
needsAgentId: true,
|
|
240
249
|
handler: async (args, env) => {
|
|
@@ -265,6 +274,7 @@ export const agreementRequestCapability = {
|
|
|
265
274
|
...TERMS_PARAMS,
|
|
266
275
|
match: MATCH_PARAM,
|
|
267
276
|
mandateAgreementId: MANDATE_PARAM,
|
|
277
|
+
parentAgreementId: { type: 'string', description: 'Governing agreement, including a link or negotiation agreement. This placement does not grant spending consent.' },
|
|
268
278
|
},
|
|
269
279
|
needsAgentId: true,
|
|
270
280
|
handler: async (args, env) => {
|
|
@@ -315,6 +325,9 @@ export const agreementOfferCapability = {
|
|
|
315
325
|
lifecycle: terms.lifecycle,
|
|
316
326
|
expiresAt: terms.expiresAt,
|
|
317
327
|
maxExecutions: terms.maxExecutions,
|
|
328
|
+
conversationAllowance: terms.conversationAllowance,
|
|
329
|
+
conversationAllowanceScope: terms.conversationAllowanceScope,
|
|
330
|
+
interactionMode: terms.interactionMode,
|
|
318
331
|
billing: terms.billing,
|
|
319
332
|
engagementKind: engagementKindFrom(args),
|
|
320
333
|
audience: args['audience'],
|
|
@@ -428,6 +441,9 @@ export const agreementSubcontractCapability = {
|
|
|
428
441
|
},
|
|
429
442
|
expiresAt: { type: 'string' },
|
|
430
443
|
maxExecutions: { type: 'number' },
|
|
444
|
+
interactionMode: { type: 'string', enum: ['messages', 'tasks', 'both'], description: 'Accepted interface. Task-only services need no chat or negotiation.' },
|
|
445
|
+
conversationAllowanceScope: { type: 'string', enum: ['direct', 'subtree'], description: 'Direct by default; subtree explicitly shares the allowance with descendants.' },
|
|
446
|
+
conversationAllowance: { type: 'number', description: 'Message allowance; direct to this agreement unless conversationAllowanceScope explicitly says subtree.' },
|
|
431
447
|
agreementDescription: { type: 'string' },
|
|
432
448
|
payerId: {
|
|
433
449
|
type: 'string',
|
|
@@ -451,6 +467,9 @@ export const agreementSubcontractCapability = {
|
|
|
451
467
|
...(args['expiresAt'] === undefined
|
|
452
468
|
? {}
|
|
453
469
|
: { expiresAt: args['expiresAt'] }),
|
|
470
|
+
...(args['interactionMode'] === undefined ? {} : { interactionMode: args['interactionMode'] }),
|
|
471
|
+
...(args['conversationAllowanceScope'] === undefined ? {} : { conversationAllowanceScope: args['conversationAllowanceScope'] }),
|
|
472
|
+
...(args['conversationAllowance'] === undefined ? {} : { conversationAllowance: args['conversationAllowance'] }),
|
|
454
473
|
...(args['maxExecutions'] === undefined
|
|
455
474
|
? {}
|
|
456
475
|
: { maxExecutions: args['maxExecutions'] }),
|
|
@@ -83,6 +83,7 @@ export const agreementClaimCapability = {
|
|
|
83
83
|
// doing needs — waited on a human every time. It authorizes; it does not
|
|
84
84
|
// re-parent: the row belongs to whoever posted it, and a claimer cannot move
|
|
85
85
|
// somebody else's agreement into its own tree.
|
|
86
|
+
parentAgreementId: { type: 'string', description: 'Place the new service-listing claim under this governing relationship or work agreement. Requires separate consent to the posted terms.' },
|
|
86
87
|
mandateAgreementId: {
|
|
87
88
|
type: 'string',
|
|
88
89
|
description: 'The active agreement whose work this claim is part of — the job you are doing. Claiming for a job your human already approved needs no second approval from them, but you have to name the job: the server checks you are a party to it, and a wrong name simply earns nothing. Leave it out when the claim belongs to no job.',
|
|
@@ -91,9 +92,7 @@ export const agreementClaimCapability = {
|
|
|
91
92
|
needsAgentId: true,
|
|
92
93
|
handler: async (args, env) => {
|
|
93
94
|
const declaredMandate = args['mandateAgreementId'];
|
|
94
|
-
const { agreement, kind } = await claimOpenAgreement(args['agreementId'], fullCreds(env), typeof declaredMandate === 'string' && declaredMandate
|
|
95
|
-
? { mandateAgreementId: declaredMandate }
|
|
96
|
-
: {});
|
|
95
|
+
const { agreement, kind } = await claimOpenAgreement(args['agreementId'], fullCreds(env), { ...(typeof declaredMandate === 'string' && declaredMandate ? { mandateAgreementId: declaredMandate } : {}), ...(typeof args['parentAgreementId'] === 'string' ? { parentAgreementId: args['parentAgreementId'] } : {}) });
|
|
97
96
|
return presentClaimResult(agreement, kind, env);
|
|
98
97
|
},
|
|
99
98
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArtifactsClient } from '../http/ArtifactsClient.js';
|
|
1
|
+
import { ARTIFACT_FILE_FORMATS, ArtifactsClient, } from '../http/ArtifactsClient.js';
|
|
2
2
|
import { ContextGrantsClient } from '../http/ContextGrantsClient.js';
|
|
3
3
|
import { ContextDiscoveryClient, } from '../http/ContextDiscoveryClient.js';
|
|
4
4
|
import { fullCreds } from './types.js';
|
|
@@ -105,6 +105,7 @@ async function recordFileArtifact(args, env, visibility) {
|
|
|
105
105
|
visibility,
|
|
106
106
|
chatId: args['chatId'],
|
|
107
107
|
agreementId: args['agreementId'],
|
|
108
|
+
serviceAgreementId: args['serviceAgreementId'] ?? (!taskId && !args['agreementId'] ? env.serviceAgreementId : undefined),
|
|
108
109
|
taskId,
|
|
109
110
|
idempotencyKey: args['idempotencyKey'],
|
|
110
111
|
// ArtifactsClient does the PUT and hands back the sha256 of what it sent,
|
|
@@ -129,6 +130,23 @@ async function recordFileArtifact(args, env, visibility) {
|
|
|
129
130
|
reportingHint: reportingHint(env, args['contentType'], taskId),
|
|
130
131
|
};
|
|
131
132
|
}
|
|
133
|
+
/** Both fields or neither. Shape is taught in the param description. */
|
|
134
|
+
function parseExternalRef(raw) {
|
|
135
|
+
if (raw == null)
|
|
136
|
+
return undefined;
|
|
137
|
+
if (typeof raw !== 'object' || Array.isArray(raw)) {
|
|
138
|
+
throw new Error('externalRef must be { provider, url }');
|
|
139
|
+
}
|
|
140
|
+
const rec = raw;
|
|
141
|
+
const provider = typeof rec.provider === 'string' ? rec.provider.trim() : '';
|
|
142
|
+
const url = typeof rec.url === 'string' ? rec.url.trim() : '';
|
|
143
|
+
if (!provider && !url)
|
|
144
|
+
return undefined;
|
|
145
|
+
if (!provider || !url) {
|
|
146
|
+
throw new Error('externalRef needs both provider and url');
|
|
147
|
+
}
|
|
148
|
+
return { provider, url };
|
|
149
|
+
}
|
|
132
150
|
export const recordArtifactCapability = {
|
|
133
151
|
key: 'artifact_record',
|
|
134
152
|
names: { sdk: 'artifact_record', mcp: 'ziggs_artifact_record' },
|
|
@@ -176,7 +194,7 @@ export const recordArtifactCapability = {
|
|
|
176
194
|
},
|
|
177
195
|
format: {
|
|
178
196
|
type: 'string',
|
|
179
|
-
enum: [
|
|
197
|
+
enum: [...ARTIFACT_FILE_FORMATS],
|
|
180
198
|
description: 'Optional file format; inferred from filename when omitted',
|
|
181
199
|
},
|
|
182
200
|
visibility: {
|
|
@@ -186,6 +204,7 @@ export const recordArtifactCapability = {
|
|
|
186
204
|
description: 'chat = the scope’s parties can read it; agent-private = not shared with them. ' +
|
|
187
205
|
'Neither is permanent: you can share any artifact later with a specific agent.',
|
|
188
206
|
},
|
|
207
|
+
serviceAgreementId: { type: 'string', description: 'Agreement authorizing this work, separate from the destination chat. Defaults to the SDK wake agreement when no task/agreement scope is supplied.' },
|
|
189
208
|
chatId: { type: 'string', description: 'Optional chat scope' },
|
|
190
209
|
agreementId: {
|
|
191
210
|
type: 'string',
|
|
@@ -204,6 +223,12 @@ export const recordArtifactCapability = {
|
|
|
204
223
|
description: 'Optional dedup key: a redelivered record with the same key no-ops and returns the original artifact. Derive it deterministically (e.g. from the source event + step) — not a random value — so a crash-replay reproduces it. ' +
|
|
205
224
|
'A task-bound result artifact is one deliverable per task: recordReport keys it `task-result:<taskId>`, so a retry after a partial failure reuses that row. A later revision of the same task still returns the original artifact — change the key if you mean a new deliverable.',
|
|
206
225
|
},
|
|
226
|
+
externalRef: {
|
|
227
|
+
type: 'object',
|
|
228
|
+
description: 'When the deliverable lives in another system: { provider, url }. Both required. ' +
|
|
229
|
+
'text is the in-Ziggs summary. Ziggs stores the link and does not fetch it. ' +
|
|
230
|
+
'A grant on this artifact does not open the other system.',
|
|
231
|
+
},
|
|
207
232
|
},
|
|
208
233
|
needsAgentId: true,
|
|
209
234
|
handler: async (args, env) => {
|
|
@@ -238,6 +263,7 @@ export const recordArtifactCapability = {
|
|
|
238
263
|
}
|
|
239
264
|
const contentType = args['contentType'];
|
|
240
265
|
const taskId = args['taskId'];
|
|
266
|
+
const externalRef = parseExternalRef(args['externalRef']);
|
|
241
267
|
const creds = fullCreds(env);
|
|
242
268
|
const { artifactId } = await new ArtifactsClient(creds.operatorKey, creds.agentId, creds.laneId).writeStrict({
|
|
243
269
|
text,
|
|
@@ -246,8 +272,10 @@ export const recordArtifactCapability = {
|
|
|
246
272
|
chatId,
|
|
247
273
|
agreementId,
|
|
248
274
|
taskId,
|
|
275
|
+
serviceAgreementId: args['serviceAgreementId'] ?? (!taskId && !agreementId ? env.serviceAgreementId : undefined),
|
|
249
276
|
contentType,
|
|
250
277
|
idempotencyKey: args['idempotencyKey'],
|
|
278
|
+
...(externalRef ? { externalRef } : {}),
|
|
251
279
|
});
|
|
252
280
|
return {
|
|
253
281
|
ok: true,
|
|
@@ -605,7 +633,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
605
633
|
'large to travel inside a tool call. Returns a short-lived uploadUrl: PUT the exact byteSize ' +
|
|
606
634
|
'bytes to it (Content-Type = mime), then call artifact_complete_file with the sha256 hex of ' +
|
|
607
635
|
'those bytes.',
|
|
608
|
-
mcp:
|
|
636
|
+
mcp: `Large-file escape hatch (${ARTIFACT_FILE_FORMATS.join('/')}). Ordinary files go through ` +
|
|
609
637
|
'ziggs_artifact_record (filename + mime + contentBase64), which presigns, uploads and ' +
|
|
610
638
|
'completes in one call — use this only when the bytes are too large to travel inside a tool ' +
|
|
611
639
|
'call. Returns uploadUrl + artifactId: PUT the bytes with the declared mime, then call ' +
|
|
@@ -628,7 +656,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
628
656
|
},
|
|
629
657
|
format: {
|
|
630
658
|
type: 'string',
|
|
631
|
-
enum: [
|
|
659
|
+
enum: [...ARTIFACT_FILE_FORMATS],
|
|
632
660
|
description: 'Optional; inferred from filename when omitted',
|
|
633
661
|
},
|
|
634
662
|
visibility: {
|
|
@@ -641,6 +669,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
641
669
|
type: 'string',
|
|
642
670
|
description: 'Optional agreement scope; mutually exclusive with chatId',
|
|
643
671
|
},
|
|
672
|
+
serviceAgreementId: { type: 'string', description: 'Agreement authorizing this work, separate from the destination chat.' },
|
|
644
673
|
taskId: { type: 'string', description: 'Optional task binding' },
|
|
645
674
|
idempotencyKey: {
|
|
646
675
|
type: 'string',
|
|
@@ -679,6 +708,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
679
708
|
chatId: args['chatId'],
|
|
680
709
|
agreementId: args['agreementId'],
|
|
681
710
|
taskId: args['taskId'],
|
|
711
|
+
serviceAgreementId: args['serviceAgreementId'] ?? (!args['taskId'] && !args['agreementId'] ? env.serviceAgreementId : undefined),
|
|
682
712
|
idempotencyKey: args['idempotencyKey'],
|
|
683
713
|
contentBase64: args['contentBase64'],
|
|
684
714
|
});
|
|
@@ -79,6 +79,7 @@ export const contextReadCapability = {
|
|
|
79
79
|
required: true,
|
|
80
80
|
description: `Scope entry you hold, as <kind>:<id>. Accepted per type — ${VIA_BY_TYPE}.`,
|
|
81
81
|
},
|
|
82
|
+
agreementId: { type: 'string', description: 'Filter message history to this exact work agreement. Use cursor pagination to expand a wake packet.' },
|
|
82
83
|
cursor: { type: 'string', description: 'Opaque cursor from a prior nextCursor to page' },
|
|
83
84
|
after: { type: 'string', description: 'ISO timestamp for forward-delta (messages/artifacts)' },
|
|
84
85
|
direction: {
|
|
@@ -119,6 +120,7 @@ export const contextReadCapability = {
|
|
|
119
120
|
}
|
|
120
121
|
return new ContextReadClient(creds.operatorKey, creds.agentId, undefined, creds.laneId).read(type, {
|
|
121
122
|
via,
|
|
123
|
+
agreementId: args['agreementId'],
|
|
122
124
|
cursor: args['cursor'],
|
|
123
125
|
after: args['after'],
|
|
124
126
|
direction: direction,
|
|
@@ -310,6 +312,7 @@ export const openCapability = {
|
|
|
310
312
|
annotation: 'read-only',
|
|
311
313
|
params: {
|
|
312
314
|
...OPEN_ID_PARAMS,
|
|
315
|
+
agreementId: { type: 'string', description: 'Filter message history to this exact work agreement. Use cursor pagination to expand a wake packet.' },
|
|
313
316
|
cursor: { type: 'string', description: 'Opaque cursor from a prior open page' },
|
|
314
317
|
after: { type: 'string', description: 'ISO timestamp for a forward-delta' },
|
|
315
318
|
limit: { type: 'number', description: 'Page size' },
|
|
@@ -47,6 +47,7 @@ function toListingRow(a, kind) {
|
|
|
47
47
|
engagementKind: a?.engagementKind,
|
|
48
48
|
lifecycle: terms.lifecycle,
|
|
49
49
|
...(terms.expiresAt ? { expiresAt: terms.expiresAt } : {}),
|
|
50
|
+
...(terms.conversationAllowance !== undefined ? { conversationAllowance: terms.conversationAllowance } : {}),
|
|
50
51
|
...(terms.maxExecutions != null ? { maxExecutions: terms.maxExecutions } : {}),
|
|
51
52
|
// Who does the work on an offer, who is paying on a request. The other slot is
|
|
52
53
|
// the open one you would be filling by claiming, so it carries no name yet.
|
|
@@ -40,6 +40,8 @@ export interface CapabilityParam {
|
|
|
40
40
|
* that impersonate set `needsAgentId` so the adapter fails early instead.
|
|
41
41
|
*/
|
|
42
42
|
export interface CapabilityEnv {
|
|
43
|
+
/** Validated wake scope supplied by the host; never a resource-access grant. */
|
|
44
|
+
serviceAgreementId?: string;
|
|
43
45
|
creds: {
|
|
44
46
|
operatorKey: string;
|
|
45
47
|
agentId?: string;
|
|
@@ -12,6 +12,10 @@ export interface ProposeTerms {
|
|
|
12
12
|
lifecycle?: string;
|
|
13
13
|
expiresAt?: string;
|
|
14
14
|
maxExecutions?: number;
|
|
15
|
+
/** Shared incoming-message allowance; null means unlimited. */
|
|
16
|
+
conversationAllowance?: number | null;
|
|
17
|
+
conversationAllowanceScope?: 'direct' | 'subtree';
|
|
18
|
+
interactionMode?: 'messages' | 'tasks' | 'both';
|
|
15
19
|
/**
|
|
16
20
|
* How `price` reads. `total` (default) escrows one price for the whole
|
|
17
21
|
* engagement and pays at fulfillment; `per_task` is a RATE settled as each
|
|
@@ -127,6 +131,10 @@ export interface DelegateAgreementData {
|
|
|
127
131
|
lifecycle?: string;
|
|
128
132
|
expiresAt?: string;
|
|
129
133
|
maxExecutions?: number;
|
|
134
|
+
/** Shared incoming-message allowance; null means unlimited. */
|
|
135
|
+
conversationAllowance?: number | null;
|
|
136
|
+
conversationAllowanceScope?: 'direct' | 'subtree';
|
|
137
|
+
interactionMode?: 'messages' | 'tasks' | 'both';
|
|
130
138
|
agreementDescription?: string;
|
|
131
139
|
payerId?: string;
|
|
132
140
|
idempotencyKey?: string;
|
|
@@ -193,6 +201,10 @@ export interface CounterAgreementData {
|
|
|
193
201
|
expiresAt?: string;
|
|
194
202
|
lifecycle?: string;
|
|
195
203
|
maxExecutions?: number;
|
|
204
|
+
/** Shared incoming-message allowance; null means unlimited. */
|
|
205
|
+
conversationAllowance?: number | null;
|
|
206
|
+
conversationAllowanceScope?: 'direct' | 'subtree';
|
|
207
|
+
interactionMode?: 'messages' | 'tasks' | 'both';
|
|
196
208
|
description?: string;
|
|
197
209
|
}
|
|
198
210
|
export declare function counterAgreement(agreementId: string, counter: CounterAgreementData, creds: Creds): Promise<Agreement>;
|
|
@@ -298,6 +310,7 @@ export type ClaimedKind = 'link' | 'offer' | 'request' | 'hand-off';
|
|
|
298
310
|
* agreement belongs to whoever posted it.
|
|
299
311
|
*/
|
|
300
312
|
export interface ClaimOptions {
|
|
313
|
+
parentAgreementId?: string;
|
|
301
314
|
/**
|
|
302
315
|
* The active agreement whose work this claim is part of. An agent acting
|
|
303
316
|
* inside a job its human approved does not need a second consent for the
|
|
@@ -92,6 +92,7 @@ export function linkSummary(a) {
|
|
|
92
92
|
*/
|
|
93
93
|
export function shapeAgreement(a) {
|
|
94
94
|
const wire = a;
|
|
95
|
+
const conversationAllowance = wire.terms?.conversationAllowance;
|
|
95
96
|
const lifted = {
|
|
96
97
|
...a,
|
|
97
98
|
...(wire.terms?.description != null
|
|
@@ -106,6 +107,7 @@ export function shapeAgreement(a) {
|
|
|
106
107
|
...(wire.terms?.maxExecutions != null
|
|
107
108
|
? { maxExecutions: wire.terms.maxExecutions }
|
|
108
109
|
: {}),
|
|
110
|
+
...(conversationAllowance !== undefined ? { conversationAllowance } : {}),
|
|
109
111
|
// A price with no billing mode is two different offers. Lifted
|
|
110
112
|
// beside the executions cap because they are read together: "ϟ5 a task, up
|
|
111
113
|
// to 10" and "ϟ5 for the lot" are the same three fields otherwise.
|
|
@@ -546,7 +548,7 @@ export async function claimAgreement(agreementId, creds, opts = {}) {
|
|
|
546
548
|
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/claim`, {
|
|
547
549
|
method: 'POST',
|
|
548
550
|
headers: buildHeaders(creds),
|
|
549
|
-
body: JSON.stringify(opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {}),
|
|
551
|
+
body: JSON.stringify({ ...(opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {}), ...(opts.parentAgreementId ? { parentAgreementId: opts.parentAgreementId } : {}) }),
|
|
550
552
|
});
|
|
551
553
|
if (!res.ok) {
|
|
552
554
|
const body = await res.text().catch(() => '');
|
|
@@ -16,6 +16,7 @@ export interface ListArtifactsQuery {
|
|
|
16
16
|
chatId?: string;
|
|
17
17
|
agreementId?: string;
|
|
18
18
|
taskId?: string;
|
|
19
|
+
serviceAgreementId?: string;
|
|
19
20
|
/**
|
|
20
21
|
* `'me'` lists artifacts YOU authored, in any scope or none. The
|
|
21
22
|
* only listing that surfaces a free-standing artifact, since the others read
|
|
@@ -76,6 +77,7 @@ export interface WriteArtifactInput {
|
|
|
76
77
|
agreementId?: string;
|
|
77
78
|
/** Optional task binding — creates a TaskArtifactLink alongside the primary scope link. */
|
|
78
79
|
taskId?: string;
|
|
80
|
+
serviceAgreementId?: string;
|
|
79
81
|
service?: Record<string, unknown>;
|
|
80
82
|
/**
|
|
81
83
|
* Optional idempotency key. A redelivered write with the same key (same
|
|
@@ -84,8 +86,18 @@ export interface WriteArtifactInput {
|
|
|
84
86
|
* reproduces it.
|
|
85
87
|
*/
|
|
86
88
|
idempotencyKey?: string;
|
|
89
|
+
/**
|
|
90
|
+
* When the deliverable lives outside Ziggs: both provider and http(s) URL.
|
|
91
|
+
* The `text` is the in-Ziggs summary. Ziggs does not fetch the URL.
|
|
92
|
+
*/
|
|
93
|
+
externalRef?: {
|
|
94
|
+
provider: string;
|
|
95
|
+
url: string;
|
|
96
|
+
};
|
|
87
97
|
}
|
|
88
|
-
|
|
98
|
+
/** Every file format the server stores, in its order. One list for the type and the tool enums. */
|
|
99
|
+
export declare const ARTIFACT_FILE_FORMATS: readonly ["pdf", "docx", "hwpx", "pptx", "md", "txt", "html", "mp3"];
|
|
100
|
+
export type ArtifactFileFormat = (typeof ARTIFACT_FILE_FORMATS)[number];
|
|
89
101
|
export interface ArtifactUploadUrlInput {
|
|
90
102
|
/** Short list name. Defaults to filename on the server when omitted. */
|
|
91
103
|
name?: string;
|
|
@@ -98,6 +110,7 @@ export interface ArtifactUploadUrlInput {
|
|
|
98
110
|
chatId?: string;
|
|
99
111
|
agreementId?: string;
|
|
100
112
|
taskId?: string;
|
|
113
|
+
serviceAgreementId?: string;
|
|
101
114
|
service?: Record<string, unknown>;
|
|
102
115
|
idempotencyKey?: string;
|
|
103
116
|
/**
|
|
@@ -170,6 +183,7 @@ export declare class ArtifactsClient {
|
|
|
170
183
|
*/
|
|
171
184
|
recordThought(sessionId: string, text: string, opts?: {
|
|
172
185
|
idempotencyKey?: string;
|
|
186
|
+
serviceAgreementId?: string;
|
|
173
187
|
}): Promise<void>;
|
|
174
188
|
write(input: WriteArtifactInput): Promise<void>;
|
|
175
189
|
/**
|
|
@@ -13,6 +13,8 @@ export const ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT = `text exceeds ${ARTIFACT_INL
|
|
|
13
13
|
'For larger content use ziggs_artifact_upload_url (file rail), or split into ' +
|
|
14
14
|
'an index artifact plus part artifacts and list the part ids in the index. ' +
|
|
15
15
|
'The server does not auto-split.';
|
|
16
|
+
/** Every file format the server stores, in its order. One list for the type and the tool enums. */
|
|
17
|
+
export const ARTIFACT_FILE_FORMATS = ['pdf', 'docx', 'hwpx', 'pptx', 'md', 'txt', 'html', 'mp3'];
|
|
16
18
|
function resolveUploadBytes(input) {
|
|
17
19
|
if (input.content != null) {
|
|
18
20
|
return Buffer.isBuffer(input.content)
|
|
@@ -140,6 +142,7 @@ export class ArtifactsClient {
|
|
|
140
142
|
contentType: 'thought',
|
|
141
143
|
visibility: 'agent-private',
|
|
142
144
|
idempotencyKey: opts.idempotencyKey,
|
|
145
|
+
serviceAgreementId: opts.serviceAgreementId,
|
|
143
146
|
});
|
|
144
147
|
}
|
|
145
148
|
async write(input) {
|
|
@@ -185,8 +188,12 @@ export class ArtifactsClient {
|
|
|
185
188
|
chatId: input.chatId,
|
|
186
189
|
agreementId: input.agreementId,
|
|
187
190
|
taskId: input.taskId,
|
|
191
|
+
serviceAgreementId: input.serviceAgreementId,
|
|
188
192
|
service: input.service,
|
|
189
193
|
...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
|
|
194
|
+
...(input.externalRef
|
|
195
|
+
? { externalRef: input.externalRef }
|
|
196
|
+
: {}),
|
|
190
197
|
}),
|
|
191
198
|
});
|
|
192
199
|
const body = await res.text().catch(() => '');
|
|
@@ -257,6 +264,7 @@ export class ArtifactsClient {
|
|
|
257
264
|
chatId: input.chatId,
|
|
258
265
|
agreementId: input.agreementId,
|
|
259
266
|
taskId: input.taskId,
|
|
267
|
+
serviceAgreementId: input.serviceAgreementId,
|
|
260
268
|
service: input.service,
|
|
261
269
|
...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
|
|
262
270
|
}, 'artifact upload-url');
|
|
@@ -44,6 +44,10 @@ export interface SendChatMessageInput {
|
|
|
44
44
|
entryType?: string;
|
|
45
45
|
contentType?: string;
|
|
46
46
|
underAgreementId?: string;
|
|
47
|
+
/** Governing service agreement; independent of representation. */
|
|
48
|
+
conversationAgreementId?: string;
|
|
49
|
+
taskId?: string;
|
|
50
|
+
replyToMessageId?: string;
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Where the server says a send landed.
|
package/dist/http/ChatClient.js
CHANGED
|
@@ -105,6 +105,9 @@ export async function sendChatMessage(input, creds) {
|
|
|
105
105
|
// clients send the object.
|
|
106
106
|
receiver: input.receiverId ? { id: input.receiverId } : undefined,
|
|
107
107
|
underAgreementId: input.underAgreementId,
|
|
108
|
+
conversationAgreementId: input.conversationAgreementId,
|
|
109
|
+
taskId: input.taskId,
|
|
110
|
+
replyToMessageId: input.replyToMessageId,
|
|
108
111
|
}),
|
|
109
112
|
});
|
|
110
113
|
if (!res.ok) {
|
|
@@ -23,6 +23,7 @@ export declare function parseVia(via: string): {
|
|
|
23
23
|
id: string;
|
|
24
24
|
} | null;
|
|
25
25
|
export interface ContextReadQuery {
|
|
26
|
+
agreementId?: string;
|
|
26
27
|
via: string;
|
|
27
28
|
cursor?: string;
|
|
28
29
|
limit?: number;
|
|
@@ -56,6 +57,7 @@ export interface ContextSnapshotParticipant {
|
|
|
56
57
|
[key: string]: unknown;
|
|
57
58
|
}
|
|
58
59
|
export interface ContextSnapshotResult {
|
|
60
|
+
work?: Record<string, unknown>;
|
|
59
61
|
history: unknown[];
|
|
60
62
|
agreements: unknown[];
|
|
61
63
|
/** Bounded room inventory, without bodies. Absent on older backends. */
|
|
@@ -102,5 +104,10 @@ export declare class ContextReadClient {
|
|
|
102
104
|
snapshot(chatId: string, opts?: {
|
|
103
105
|
maxMessages?: number;
|
|
104
106
|
contextGrantId?: string;
|
|
107
|
+
agreementId?: string;
|
|
108
|
+
taskId?: string;
|
|
109
|
+
messageId?: string;
|
|
110
|
+
artifactId?: string;
|
|
111
|
+
via?: string;
|
|
105
112
|
}): Promise<ContextSnapshotResult>;
|
|
106
113
|
}
|
|
@@ -80,6 +80,8 @@ export class ContextReadClient {
|
|
|
80
80
|
}
|
|
81
81
|
const url = new URL(`${this.baseUrl}/context/read/${encodeURIComponent(type)}`);
|
|
82
82
|
url.searchParams.set('via', query.via.trim());
|
|
83
|
+
if (query.agreementId)
|
|
84
|
+
url.searchParams.set('agreementId', query.agreementId);
|
|
83
85
|
if (query.cursor)
|
|
84
86
|
url.searchParams.set('cursor', query.cursor);
|
|
85
87
|
if (query.limit != null)
|
|
@@ -119,7 +121,13 @@ export class ContextReadClient {
|
|
|
119
121
|
throw new Error('ContextReadClient.snapshot: chatId is required');
|
|
120
122
|
}
|
|
121
123
|
const url = new URL(`${this.baseUrl}/context/snapshot`);
|
|
122
|
-
url.searchParams.set('via', `chat:${chatId}`);
|
|
124
|
+
url.searchParams.set('via', opts.taskId ? `task:${opts.taskId}` : opts.via ?? (chatId.startsWith('agrn-') ? `agreement:${opts.agreementId ?? chatId.slice(5)}` : `chat:${chatId}`));
|
|
125
|
+
if (opts.agreementId)
|
|
126
|
+
url.searchParams.set('agreementId', opts.agreementId);
|
|
127
|
+
if (opts.messageId)
|
|
128
|
+
url.searchParams.set('messageId', opts.messageId);
|
|
129
|
+
if (opts.artifactId)
|
|
130
|
+
url.searchParams.set('artifactId', opts.artifactId);
|
|
123
131
|
if (opts.maxMessages != null) {
|
|
124
132
|
url.searchParams.set('maxMessages', String(opts.maxMessages));
|
|
125
133
|
}
|
|
@@ -5,6 +5,10 @@ export interface PublishOfferPayload {
|
|
|
5
5
|
lifecycle?: string;
|
|
6
6
|
expiresAt?: string;
|
|
7
7
|
maxExecutions?: number;
|
|
8
|
+
/** Shared incoming-message allowance; null means unlimited. */
|
|
9
|
+
conversationAllowance?: number | null;
|
|
10
|
+
conversationAllowanceScope?: 'direct' | 'subtree';
|
|
11
|
+
interactionMode?: 'messages' | 'tasks' | 'both';
|
|
8
12
|
/** `hire` = claimer becomes the provider's principal on claim. Defaults to `service` server-side. */
|
|
9
13
|
engagementKind?: 'hire' | 'service';
|
|
10
14
|
/**
|
|
@@ -20,6 +20,20 @@ export interface TaskWriteConfirm {
|
|
|
20
20
|
terminalState?: string;
|
|
21
21
|
[key: string]: unknown;
|
|
22
22
|
}
|
|
23
|
+
export interface TaskControl {
|
|
24
|
+
requestId: string;
|
|
25
|
+
action: 'pause' | 'resume' | 'stop';
|
|
26
|
+
status: 'requested' | 'acknowledged' | 'unsupported';
|
|
27
|
+
requestedAt: string;
|
|
28
|
+
acknowledgedAt: string | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function requestTaskControl(taskId: string, request: {
|
|
31
|
+
action: TaskControl['action'];
|
|
32
|
+
requestId: string;
|
|
33
|
+
previousRequestId: string | null;
|
|
34
|
+
}, creds: Creds): Promise<TaskWriteConfirm>;
|
|
35
|
+
/** Runtime-only: call after all work for this task has quiesced, never on receipt alone. */
|
|
36
|
+
export declare function acknowledgeTaskControl(taskId: string, requestId: string, supported: boolean, creds: Creds): Promise<TaskWriteConfirm>;
|
|
23
37
|
/**
|
|
24
38
|
* When the buyer reviews a task's plan. Task-rail only — an agreement has no
|
|
25
39
|
* plan to review, which is why cut this from the propose/counter/
|
|
@@ -185,6 +199,8 @@ export declare class TaskClient {
|
|
|
185
199
|
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
186
200
|
*/
|
|
187
201
|
constructor(operatorKey: string, agentId?: string);
|
|
202
|
+
requestControl(taskId: string, request: Parameters<typeof requestTaskControl>[1]): Promise<TaskWriteConfirm>;
|
|
203
|
+
acknowledgeControl(taskId: string, requestId: string, supported?: boolean): Promise<TaskWriteConfirm>;
|
|
188
204
|
createTask(data: CreateTaskData): Promise<Task>;
|
|
189
205
|
getTask(taskId: string): Promise<Task>;
|
|
190
206
|
updateTaskState(taskId: string, state: TaskState, data?: UpdateTaskStateData): Promise<TaskWriteConfirm>;
|
package/dist/http/TaskClient.js
CHANGED
|
@@ -25,6 +25,27 @@ function extractTask(data) {
|
|
|
25
25
|
}
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
|
+
export async function requestTaskControl(taskId, request, creds) {
|
|
29
|
+
return writeTaskControl(taskId, 'control', 'PATCH', request, creds);
|
|
30
|
+
}
|
|
31
|
+
/** Runtime-only: call after all work for this task has quiesced, never on receipt alone. */
|
|
32
|
+
export async function acknowledgeTaskControl(taskId, requestId, supported, creds) {
|
|
33
|
+
return writeTaskControl(taskId, 'control/ack', 'POST', { requestId, supported }, creds);
|
|
34
|
+
}
|
|
35
|
+
async function writeTaskControl(taskId, path, method, body, creds) {
|
|
36
|
+
if (!taskId)
|
|
37
|
+
throw new Error('Task control requires a taskId');
|
|
38
|
+
assertCreds(creds, 'task control');
|
|
39
|
+
const res = await fetch(`${getTaskBaseUrl()}/${encodeURIComponent(taskId)}/${path}`, {
|
|
40
|
+
method, headers: buildHeaders(creds), body: JSON.stringify(body),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
throwApiError(res, await res.text().catch(() => ''), `Task control failed: ${res.status}`);
|
|
44
|
+
const result = extractWriteConfirm(await res.json());
|
|
45
|
+
if (!result)
|
|
46
|
+
throw new Error('Invalid task control response');
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
28
49
|
function extractWriteConfirm(data) {
|
|
29
50
|
if (!data || typeof data !== 'object')
|
|
30
51
|
return null;
|
|
@@ -36,6 +57,7 @@ function extractWriteConfirm(data) {
|
|
|
36
57
|
d['description'] === undefined) {
|
|
37
58
|
return {
|
|
38
59
|
ok: true,
|
|
60
|
+
...(d['control'] ? { control: d['control'] } : {}),
|
|
39
61
|
taskId: d['taskId'],
|
|
40
62
|
...(typeof d['agreementId'] === 'string' ? { agreementId: d['agreementId'] } : {}),
|
|
41
63
|
state: d['state'],
|
|
@@ -454,6 +476,8 @@ export class TaskClient {
|
|
|
454
476
|
// standalone functions still assert it per call.
|
|
455
477
|
this.creds = { operatorKey, agentId };
|
|
456
478
|
}
|
|
479
|
+
requestControl(taskId, request) { return requestTaskControl(taskId, request, this.creds); }
|
|
480
|
+
acknowledgeControl(taskId, requestId, supported = true) { return acknowledgeTaskControl(taskId, requestId, supported, this.creds); }
|
|
457
481
|
createTask(data) { return createTask(data, this.creds); }
|
|
458
482
|
getTask(taskId) { return getTask(taskId, this.creds); }
|
|
459
483
|
updateTaskState(taskId, state, data) { return updateTaskState(taskId, state, data ?? {}, this.creds); }
|
|
@@ -20,6 +20,9 @@ export async function proposeUnified(input, creds) {
|
|
|
20
20
|
lifecycle: terms.lifecycle,
|
|
21
21
|
expiresAt: terms.expiresAt,
|
|
22
22
|
maxExecutions: terms.maxExecutions,
|
|
23
|
+
conversationAllowance: terms.conversationAllowance,
|
|
24
|
+
conversationAllowanceScope: terms.conversationAllowanceScope,
|
|
25
|
+
interactionMode: terms.interactionMode,
|
|
23
26
|
engagementKind: engagementKind,
|
|
24
27
|
billing: terms.billing,
|
|
25
28
|
audience,
|
package/dist/types.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ export interface PlanStep {
|
|
|
55
55
|
result?: unknown;
|
|
56
56
|
}
|
|
57
57
|
export interface Task {
|
|
58
|
+
executorIsYou?: boolean;
|
|
59
|
+
control?: import('./http/TaskClient.js').TaskControl | null;
|
|
58
60
|
taskId: string;
|
|
59
61
|
description: string;
|
|
60
62
|
/**
|
|
@@ -216,6 +218,10 @@ export interface Agreement {
|
|
|
216
218
|
lifecycle?: string;
|
|
217
219
|
expiresAt?: string;
|
|
218
220
|
maxExecutions?: number;
|
|
221
|
+
conversationAllowance?: number | null;
|
|
222
|
+
conversationUsage?: {
|
|
223
|
+
messages: number;
|
|
224
|
+
};
|
|
219
225
|
/**
|
|
220
226
|
* What `money.price` MEANS: `total` is the whole engagement, settled once;
|
|
221
227
|
* `per_task` is a rate charged as each task completes.
|