@ziggs-ai/api-client 0.38.0 → 0.39.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/CHANGELOG.md +34 -0
- package/README.md +14 -36
- package/dist/capabilities/agreementVerbs.js +13 -21
- package/dist/capabilities/agreements.d.ts +2 -3
- package/dist/capabilities/agreements.js +8 -43
- package/dist/capabilities/artifacts.d.ts +6 -0
- package/dist/capabilities/artifacts.js +84 -43
- package/dist/capabilities/connections.js +10 -7
- package/dist/capabilities/context.d.ts +1 -1
- package/dist/capabilities/context.js +52 -45
- package/dist/capabilities/discovery.js +5 -5
- package/dist/capabilities/everyday.d.ts +1 -1
- package/dist/capabilities/everyday.js +1 -2
- package/dist/capabilities/index.d.ts +3 -4
- package/dist/capabilities/index.js +3 -4
- package/dist/capabilities/introductions.d.ts +1 -0
- package/dist/capabilities/introductions.js +64 -17
- package/dist/capabilities/links.d.ts +1 -9
- package/dist/capabilities/links.js +40 -39
- package/dist/capabilities/mcpBriefs.js +41 -34
- package/dist/capabilities/messaging.d.ts +9 -0
- package/dist/capabilities/messaging.js +11 -0
- package/dist/capabilities/nextCall.js +8 -17
- package/dist/capabilities/sources.d.ts +2 -3
- package/dist/capabilities/sources.js +1 -2
- package/dist/capabilities/tasks.d.ts +1 -0
- package/dist/capabilities/tasks.js +43 -2
- package/dist/capabilities/toolLane.js +2 -2
- package/dist/engagementGuide.d.ts +2 -2
- package/dist/engagementGuide.js +6 -6
- package/dist/handles.d.ts +1 -1
- package/dist/handles.js +2 -2
- package/dist/http/AgreementClient.d.ts +25 -63
- package/dist/http/AgreementClient.js +14 -65
- package/dist/http/ArtifactsClient.d.ts +31 -19
- package/dist/http/ArtifactsClient.js +43 -62
- package/dist/http/ConnectionsClient.d.ts +6 -7
- package/dist/http/ConnectionsClient.js +5 -3
- package/dist/http/ContextDiscoveryClient.d.ts +2 -2
- package/dist/http/ContextGrantsClient.d.ts +9 -15
- package/dist/http/ContextGrantsClient.js +3 -5
- package/dist/http/ContextOpenClient.d.ts +5 -6
- package/dist/http/ContextOpenClient.js +11 -4
- package/dist/http/ContextReadClient.d.ts +23 -27
- package/dist/http/ContextReadClient.js +24 -23
- package/dist/http/ExecutionContextClient.d.ts +5 -1
- package/dist/http/ExecutionContextClient.js +48 -1
- package/dist/http/IntroductionsClient.d.ts +33 -4
- package/dist/http/IntroductionsClient.js +6 -2
- package/dist/http/MessageRecordsClient.d.ts +36 -0
- package/dist/http/MessageRecordsClient.js +30 -0
- package/dist/http/SessionsClient.d.ts +5 -5
- package/dist/http/SessionsClient.js +6 -6
- package/dist/http/TaskClient.d.ts +35 -6
- package/dist/http/TaskClient.js +38 -36
- package/dist/http/agreementFlows.d.ts +2 -3
- package/dist/http/agreementFlows.js +5 -5
- package/dist/http/index.d.ts +3 -5
- package/dist/http/index.js +3 -4
- package/dist/http/operatorHeaders.d.ts +3 -0
- package/dist/http/operatorHeaders.js +14 -5
- package/dist/inboxAck.d.ts +2 -2
- package/dist/inboxAck.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/types.d.ts +25 -55
- package/package.json +2 -2
- package/dist/capabilities/chat.d.ts +0 -43
- package/dist/capabilities/chat.js +0 -196
- package/dist/capabilities/chatListFields.d.ts +0 -14
- package/dist/capabilities/chatListFields.js +0 -61
- package/dist/http/ChatClient.d.ts +0 -187
- package/dist/http/ChatClient.js +0 -219
- package/dist/http/MessagesClient.d.ts +0 -40
- package/dist/http/MessagesClient.js +0 -81
|
@@ -43,17 +43,8 @@ export interface ProposeTerms {
|
|
|
43
43
|
/** 1:1 proposal to a specific user or agent (`proposedTo` = their id). */
|
|
44
44
|
export interface ProposeDirectInput extends ProposeTerms {
|
|
45
45
|
proposedTo: string;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
* Optional, matching the server, which has always accepted a proposal
|
|
50
|
-
* without one. Delivery does not depend on it: the create-time agreement
|
|
51
|
-
* event targets the party slots, so the counterparty is told either way; a
|
|
52
|
-
* room only gives them somewhere to talk about it. Required here was what
|
|
53
|
-
* forced a bookkeeping agreement between parties with no conversation to
|
|
54
|
-
* invent a chat id in order to exist.
|
|
55
|
-
*/
|
|
56
|
-
chatId?: string;
|
|
46
|
+
/** Optional display-reference context for resolving a masked party; does not publish or share. */
|
|
47
|
+
addressId?: string;
|
|
57
48
|
}
|
|
58
49
|
/**
|
|
59
50
|
* Open buyer-broadcast. `audience` selects who may see/claim it:
|
|
@@ -133,8 +124,6 @@ export interface DelegateAgreementData {
|
|
|
133
124
|
/** What this text drew on. See {@link WriteSource}. */
|
|
134
125
|
sources?: WriteSource[];
|
|
135
126
|
executorId: string;
|
|
136
|
-
/** Omit it and the server uses the parent agreement's own chat. */
|
|
137
|
-
chatId?: string;
|
|
138
127
|
parentAgreementId: string;
|
|
139
128
|
price?: number;
|
|
140
129
|
lifecycle?: string;
|
|
@@ -258,6 +247,20 @@ export interface CreateLinkBody {
|
|
|
258
247
|
description?: string;
|
|
259
248
|
/** Open invites only: how many people may claim this one link. Default 1. */
|
|
260
249
|
maxClaims?: number;
|
|
250
|
+
/**
|
|
251
|
+
* A chat, task or agreement you hold. Approving the link lets the person
|
|
252
|
+
* and the agent named in `to` into it; already linked, they are in now.
|
|
253
|
+
* Needs `to`.
|
|
254
|
+
*/
|
|
255
|
+
about?: {
|
|
256
|
+
kind: 'agreement' | 'task' | 'address';
|
|
257
|
+
id: string;
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
export interface WriteSuccess {
|
|
261
|
+
success: boolean;
|
|
262
|
+
/** @deprecated Use success. */
|
|
263
|
+
ok: boolean;
|
|
261
264
|
}
|
|
262
265
|
/**
|
|
263
266
|
* The route's answer.
|
|
@@ -278,8 +281,7 @@ export interface CreateLinkBody {
|
|
|
278
281
|
* Without it a caller could not reference what it had just created, check on it
|
|
279
282
|
* later, or tell a repeat from a first attempt.
|
|
280
283
|
*/
|
|
281
|
-
export interface CreateLinkResult {
|
|
282
|
-
ok: boolean;
|
|
284
|
+
export interface CreateLinkResult extends WriteSuccess {
|
|
283
285
|
status: 'sent';
|
|
284
286
|
/** The link row, for a named agent id or an open invite. Null for an email. */
|
|
285
287
|
agreementId: string | null;
|
|
@@ -295,14 +297,12 @@ export interface CreateLinkResult {
|
|
|
295
297
|
* carries links and nothing else.
|
|
296
298
|
*/
|
|
297
299
|
export declare function createLink(body: CreateLinkBody, creds: Creds): Promise<CreateLinkResult>;
|
|
298
|
-
export declare function revokeAgreement(agreementId: string, creds: Creds): Promise<{
|
|
299
|
-
ok: boolean;
|
|
300
|
+
export declare function revokeAgreement(agreementId: string, creds: Creds): Promise<WriteSuccess & {
|
|
300
301
|
agreement: Agreement;
|
|
301
302
|
}>;
|
|
302
303
|
/** mark an agreement fulfilled (complete). A provider closing its own
|
|
303
304
|
* delivered work — party-gated server-side. */
|
|
304
|
-
export declare function fulfillAgreement(agreementId: string, creds: Creds): Promise<{
|
|
305
|
-
ok: boolean;
|
|
305
|
+
export declare function fulfillAgreement(agreementId: string, creds: Creds): Promise<WriteSuccess & {
|
|
306
306
|
agreement: Agreement;
|
|
307
307
|
}>;
|
|
308
308
|
/** What an open-broadcast claim resolved to. ⚠️ Mirrors the server; it is authoritative. */
|
|
@@ -335,11 +335,6 @@ export interface ClaimOptions {
|
|
|
335
335
|
* verifies the claim against the acting agent and never guesses one.
|
|
336
336
|
*/
|
|
337
337
|
mandateAgreementId?: string;
|
|
338
|
-
/**
|
|
339
|
-
* The room a hire of a listing is made in. On activation its
|
|
340
|
-
* agent joins that room; the claimer must take part in it.
|
|
341
|
-
*/
|
|
342
|
-
chatId?: string;
|
|
343
338
|
/**
|
|
344
339
|
* Your connection for each kind of access the listing asks for,
|
|
345
340
|
* `{ <kind>: <connectionId> }`. The hire is granted exactly that connection. A claim made inside a job (mandateAgreementId)
|
|
@@ -347,42 +342,15 @@ export interface ClaimOptions {
|
|
|
347
342
|
*/
|
|
348
343
|
connections?: Record<string, string>;
|
|
349
344
|
/**
|
|
350
|
-
* Who a hire
|
|
351
|
-
*
|
|
352
|
-
* every member.
|
|
345
|
+
* Who a hire is for. `me` keeps the agreement private; `workspace` makes
|
|
346
|
+
* the workspace the payer and shares work with its members.
|
|
353
347
|
*/
|
|
354
348
|
hireFor?: 'me' | 'workspace';
|
|
355
349
|
}
|
|
356
|
-
|
|
357
|
-
* Where a hire made in a room stands on getting its agent in.
|
|
358
|
-
* `ready` only once the agent is in; `admission_failed` names the action that
|
|
359
|
-
* resumes it without hiring or charging again.
|
|
360
|
-
*/
|
|
361
|
-
export interface ClaimRoom {
|
|
362
|
-
chatId?: string;
|
|
363
|
-
status: 'awaiting_approval' | 'ready' | 'admission_failed' | 'preparation_failed' | 'unavailable';
|
|
364
|
-
message?: string;
|
|
365
|
-
recovery?: {
|
|
366
|
-
method: string;
|
|
367
|
-
path: string;
|
|
368
|
-
tool?: string;
|
|
369
|
-
args?: Record<string, unknown>;
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
export declare function claimAgreement(agreementId: string, creds: Creds, opts?: ClaimOptions): Promise<{
|
|
373
|
-
ok: boolean;
|
|
350
|
+
export declare function claimAgreement(agreementId: string, creds: Creds, opts?: ClaimOptions): Promise<WriteSuccess & {
|
|
374
351
|
agreement: Agreement;
|
|
375
352
|
kind?: ClaimedKind;
|
|
376
|
-
room?: ClaimRoom;
|
|
377
353
|
}>;
|
|
378
|
-
/**
|
|
379
|
-
* Link types a caller may ask for. `origin` and `delegation` are workflow-owned;
|
|
380
|
-
* callers may only pin an agreement into a chat as a reference (`mention`).
|
|
381
|
-
*/
|
|
382
|
-
export declare const CHAT_LINK_TYPES: readonly ["mention"];
|
|
383
|
-
export type ChatLinkType = (typeof CHAT_LINK_TYPES)[number];
|
|
384
|
-
export declare function linkAgreementToChat(agreementId: string, chatId: string, linkType: ChatLinkType | undefined, creds: Creds): Promise<unknown | null>;
|
|
385
|
-
export declare function getChatsForAgreement(agreementId: string, creds: Creds): Promise<unknown[]>;
|
|
386
354
|
export declare const ARTIFACT_LINK_TYPES: readonly ["produced", "referenced"];
|
|
387
355
|
export type ArtifactLinkType = (typeof ARTIFACT_LINK_TYPES)[number];
|
|
388
356
|
export declare function linkArtifactToAgreement(agreementId: string, artifactId: string, linkType: ArtifactLinkType | undefined, creds: Creds): Promise<unknown | null>;
|
|
@@ -408,22 +376,16 @@ export declare class AgreementClient {
|
|
|
408
376
|
listMine(filters?: GetMyAgreementsFilters): Promise<Agreement[]>;
|
|
409
377
|
get(id: string): Promise<Agreement | null>;
|
|
410
378
|
createLink(data: CreateLinkBody): Promise<CreateLinkResult>;
|
|
411
|
-
revoke(id: string): Promise<{
|
|
412
|
-
ok: boolean;
|
|
379
|
+
revoke(id: string): Promise<WriteSuccess & {
|
|
413
380
|
agreement: Agreement;
|
|
414
381
|
}>;
|
|
415
|
-
fulfill(id: string): Promise<{
|
|
416
|
-
ok: boolean;
|
|
382
|
+
fulfill(id: string): Promise<WriteSuccess & {
|
|
417
383
|
agreement: Agreement;
|
|
418
384
|
}>;
|
|
419
|
-
claimAgreement(id: string): Promise<{
|
|
420
|
-
ok: boolean;
|
|
385
|
+
claimAgreement(id: string): Promise<WriteSuccess & {
|
|
421
386
|
agreement: Agreement;
|
|
422
387
|
kind?: ClaimedKind;
|
|
423
|
-
room?: ClaimRoom;
|
|
424
388
|
}>;
|
|
425
|
-
linkToChat(id: string, chatId: string, linkType?: ChatLinkType): Promise<unknown>;
|
|
426
|
-
listChats(id: string): Promise<unknown[]>;
|
|
427
389
|
linkArtifact(id: string, artifactId: string, linkType?: ArtifactLinkType): Promise<unknown>;
|
|
428
390
|
listArtifacts(id: string): Promise<unknown[]>;
|
|
429
391
|
}
|
|
@@ -472,6 +472,10 @@ export async function getAgreement(agreementId, creds) {
|
|
|
472
472
|
const agreement = await getAgreementDocument(agreementId, creds);
|
|
473
473
|
return agreement ? shapeAgreement(agreement) : null;
|
|
474
474
|
}
|
|
475
|
+
function writeSuccess(data) {
|
|
476
|
+
const success = data['success'] === true || (data['success'] === undefined && data['ok'] === true);
|
|
477
|
+
return { success, ok: success };
|
|
478
|
+
}
|
|
475
479
|
/**
|
|
476
480
|
* Connect with someone — by email, by agent id, or with a shareable invite.
|
|
477
481
|
*
|
|
@@ -496,12 +500,12 @@ export async function createLink(body, creds) {
|
|
|
496
500
|
}
|
|
497
501
|
const data = await res.json().catch(() => null);
|
|
498
502
|
if (data?.['status'] !== 'sent') {
|
|
499
|
-
throw new Error('Invalid response: expected {
|
|
503
|
+
throw new Error('Invalid response: expected { success, status: "sent", shareUrl } from POST /agreements/links');
|
|
500
504
|
}
|
|
501
505
|
const shareUrl = data['shareUrl'];
|
|
502
506
|
const agreementId = data['agreementId'];
|
|
503
507
|
return {
|
|
504
|
-
|
|
508
|
+
...writeSuccess(data),
|
|
505
509
|
status: 'sent',
|
|
506
510
|
agreementId: typeof agreementId === 'string' ? agreementId : null,
|
|
507
511
|
shareUrl: typeof shareUrl === 'string' ? shareUrl : null,
|
|
@@ -511,8 +515,7 @@ export async function revokeAgreement(agreementId, creds) {
|
|
|
511
515
|
if (!agreementId)
|
|
512
516
|
throw new Error('agreementId is required for revocation');
|
|
513
517
|
assertCreds(creds, 'agreement revocation');
|
|
514
|
-
//
|
|
515
|
-
// serving the identical handler (with Deprecation headers) until PR-F.
|
|
518
|
+
// Revocation uses the resource DELETE operation.
|
|
516
519
|
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}`, {
|
|
517
520
|
method: 'DELETE',
|
|
518
521
|
headers: buildHeaders(creds),
|
|
@@ -523,10 +526,10 @@ export async function revokeAgreement(agreementId, creds) {
|
|
|
523
526
|
}
|
|
524
527
|
const data = await res.json().catch(() => null);
|
|
525
528
|
if (!data?.['agreement']) {
|
|
526
|
-
throw new Error('Invalid response: expected {
|
|
529
|
+
throw new Error('Invalid response: expected { success, agreement } from DELETE /agreements/:id');
|
|
527
530
|
}
|
|
528
531
|
const envelope = data;
|
|
529
|
-
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
532
|
+
return { ...envelope, ...writeSuccess(data), agreement: shapeAgreement(envelope.agreement) };
|
|
530
533
|
}
|
|
531
534
|
/** mark an agreement fulfilled (complete). A provider closing its own
|
|
532
535
|
* delivered work — party-gated server-side. */
|
|
@@ -544,10 +547,10 @@ export async function fulfillAgreement(agreementId, creds) {
|
|
|
544
547
|
}
|
|
545
548
|
const data = await res.json().catch(() => null);
|
|
546
549
|
if (!data?.['agreement']) {
|
|
547
|
-
throw new Error('Invalid response: expected {
|
|
550
|
+
throw new Error('Invalid response: expected { success, agreement } from POST /agreements/:id/fulfill');
|
|
548
551
|
}
|
|
549
552
|
const envelope = data;
|
|
550
|
-
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
553
|
+
return { ...envelope, ...writeSuccess(data), agreement: shapeAgreement(envelope.agreement) };
|
|
551
554
|
}
|
|
552
555
|
export async function claimAgreement(agreementId, creds, opts = {}) {
|
|
553
556
|
if (!agreementId)
|
|
@@ -556,7 +559,7 @@ export async function claimAgreement(agreementId, creds, opts = {}) {
|
|
|
556
559
|
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/claim`, {
|
|
557
560
|
method: 'POST',
|
|
558
561
|
headers: buildHeaders(creds),
|
|
559
|
-
body: JSON.stringify({ ...(opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {}), ...(opts.parentAgreementId ? { parentAgreementId: opts.parentAgreementId } : {}), ...(opts.
|
|
562
|
+
body: JSON.stringify({ ...(opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {}), ...(opts.parentAgreementId ? { parentAgreementId: opts.parentAgreementId } : {}), ...(opts.connections && Object.keys(opts.connections).length ? { connections: opts.connections } : {}), ...(opts.hireFor === 'workspace' ? { hireFor: 'workspace' } : {}) }),
|
|
560
563
|
});
|
|
561
564
|
if (!res.ok) {
|
|
562
565
|
const body = await res.text().catch(() => '');
|
|
@@ -564,66 +567,14 @@ export async function claimAgreement(agreementId, creds, opts = {}) {
|
|
|
564
567
|
}
|
|
565
568
|
const data = await res.json().catch(() => null);
|
|
566
569
|
if (!data?.['agreement']) {
|
|
567
|
-
throw new Error('Invalid response: expected {
|
|
570
|
+
throw new Error('Invalid response: expected { success, agreement } from POST /agreements/:id/claim');
|
|
568
571
|
}
|
|
569
572
|
// the route reports which kind of broadcast this turned out to be.
|
|
570
573
|
// A caller cannot work it out from the row — post-claim no sentinel is left,
|
|
571
574
|
// and a request (you do the work) reads the same shape as a standing offer (you
|
|
572
575
|
// pay for it) unless you know which slot you landed in.
|
|
573
576
|
const envelope = data;
|
|
574
|
-
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
575
|
-
}
|
|
576
|
-
// ---------------------------------------------------------------------------
|
|
577
|
-
// Chat links
|
|
578
|
-
// ---------------------------------------------------------------------------
|
|
579
|
-
/**
|
|
580
|
-
* Link types a caller may ask for. `origin` and `delegation` are workflow-owned;
|
|
581
|
-
* callers may only pin an agreement into a chat as a reference (`mention`).
|
|
582
|
-
*/
|
|
583
|
-
export const CHAT_LINK_TYPES = ['mention'];
|
|
584
|
-
export async function linkAgreementToChat(agreementId, chatId, linkType = 'mention', creds) {
|
|
585
|
-
if (!agreementId || !chatId)
|
|
586
|
-
return null;
|
|
587
|
-
assertCreds(creds, 'link agreement to chat');
|
|
588
|
-
try {
|
|
589
|
-
const res = await fetch(`${getAgreementBaseUrl()}/${agreementId}/link`, {
|
|
590
|
-
method: 'POST',
|
|
591
|
-
headers: buildHeaders(creds),
|
|
592
|
-
body: JSON.stringify({ chatId, linkType }),
|
|
593
|
-
});
|
|
594
|
-
if (!res.ok) {
|
|
595
|
-
const body = await res.text().catch(() => '');
|
|
596
|
-
runtimeLog.warn('AgreementClient', `⚠️ Link agreement to chat failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
597
|
-
return null;
|
|
598
|
-
}
|
|
599
|
-
return await res.json().catch(() => null);
|
|
600
|
-
}
|
|
601
|
-
catch (e) {
|
|
602
|
-
runtimeLog.warn('AgreementClient', `⚠️ Link agreement to chat failed: ${e.message}`);
|
|
603
|
-
return null;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
export async function getChatsForAgreement(agreementId, creds) {
|
|
607
|
-
if (!agreementId)
|
|
608
|
-
return [];
|
|
609
|
-
assertCreds(creds, 'get chats for agreement');
|
|
610
|
-
try {
|
|
611
|
-
const res = await fetch(`${getAgreementBaseUrl()}/${agreementId}/chats`, {
|
|
612
|
-
method: 'GET',
|
|
613
|
-
headers: buildHeaders(creds),
|
|
614
|
-
});
|
|
615
|
-
if (!res.ok) {
|
|
616
|
-
const body = await res.text().catch(() => '');
|
|
617
|
-
runtimeLog.warn('AgreementClient', `⚠️ Get chats for agreement failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
618
|
-
return [];
|
|
619
|
-
}
|
|
620
|
-
const data = await res.json().catch(() => null);
|
|
621
|
-
return Array.isArray(data?.['links']) ? data['links'] : [];
|
|
622
|
-
}
|
|
623
|
-
catch (e) {
|
|
624
|
-
runtimeLog.warn('AgreementClient', `⚠️ Get chats for agreement failed: ${e.message}`);
|
|
625
|
-
return [];
|
|
626
|
-
}
|
|
577
|
+
return { ...envelope, ...writeSuccess(data), agreement: shapeAgreement(envelope.agreement) };
|
|
627
578
|
}
|
|
628
579
|
// ---------------------------------------------------------------------------
|
|
629
580
|
// Artifact links
|
|
@@ -701,8 +652,6 @@ export class AgreementClient {
|
|
|
701
652
|
revoke(id) { return revokeAgreement(id, this.creds); }
|
|
702
653
|
fulfill(id) { return fulfillAgreement(id, this.creds); }
|
|
703
654
|
claimAgreement(id) { return claimAgreement(id, this.creds); }
|
|
704
|
-
linkToChat(id, chatId, linkType) { return linkAgreementToChat(id, chatId, linkType ?? 'mention', this.creds); }
|
|
705
|
-
listChats(id) { return getChatsForAgreement(id, this.creds); }
|
|
706
655
|
linkArtifact(id, artifactId, linkType) { return linkArtifactToAgreement(id, artifactId, linkType ?? 'produced', this.creds); }
|
|
707
656
|
listArtifacts(id) { return getArtifactsForAgreement(id, this.creds); }
|
|
708
657
|
}
|
|
@@ -8,13 +8,12 @@ import type { ListReachableArtifactsResult } from '@ziggs-ai/contracts';
|
|
|
8
8
|
export declare const ARTIFACT_INLINE_TEXT_MAX_CHARS = 50000;
|
|
9
9
|
/** Named escape hatch for agents that hit the inline cap. */
|
|
10
10
|
export declare const ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT: string;
|
|
11
|
-
export type ArtifactVisibility = '
|
|
11
|
+
export type ArtifactVisibility = 'address' | 'agent-private';
|
|
12
12
|
export interface ListArtifactsOptions {
|
|
13
13
|
after?: string;
|
|
14
14
|
limit?: number;
|
|
15
15
|
}
|
|
16
16
|
export interface ListArtifactsQuery {
|
|
17
|
-
chatId?: string;
|
|
18
17
|
agreementId?: string;
|
|
19
18
|
taskId?: string;
|
|
20
19
|
serviceAgreementId?: string;
|
|
@@ -73,7 +72,6 @@ export interface WriteArtifactInput {
|
|
|
73
72
|
contentType?: string;
|
|
74
73
|
visibility?: ArtifactVisibility;
|
|
75
74
|
/** When the artifact is associated with a chat. */
|
|
76
|
-
chatId?: string;
|
|
77
75
|
/** When the artifact is associated with an agreement. */
|
|
78
76
|
agreementId?: string;
|
|
79
77
|
/** Optional task binding — creates a TaskArtifactLink alongside the primary scope link. */
|
|
@@ -106,7 +104,6 @@ export interface ArtifactUploadUrlInput {
|
|
|
106
104
|
byteSize: number;
|
|
107
105
|
format?: ArtifactFileFormat;
|
|
108
106
|
visibility?: ArtifactVisibility;
|
|
109
|
-
chatId?: string;
|
|
110
107
|
agreementId?: string;
|
|
111
108
|
taskId?: string;
|
|
112
109
|
serviceAgreementId?: string;
|
|
@@ -136,12 +133,18 @@ export type ArtifactFileView = Record<string, unknown> & {
|
|
|
136
133
|
extractionError?: string | null;
|
|
137
134
|
filename?: string | null;
|
|
138
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Replaces `ContextReader`'s artifact reads + `ContextWriter`'s breadcrumb
|
|
138
|
+
* writes. `visibility: 'agent-private'` is the new home for agent thoughts —
|
|
139
|
+
* they persist, are searchable, but are not visible to other chat parties.
|
|
140
|
+
*/
|
|
141
|
+
/** Artifact scope is explicit selected work. */
|
|
139
142
|
import type { ArtifactExternalRef, ArtifactFileFormat } from '@ziggs-ai/contracts';
|
|
140
143
|
export { AGREEMENT_LANE_PREFIX } from '@ziggs-ai/contracts';
|
|
141
|
-
export declare function
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
agreementId
|
|
144
|
+
export declare function artifactScope(target?: {
|
|
145
|
+
agreementId?: string;
|
|
146
|
+
}): {
|
|
147
|
+
agreementId?: string;
|
|
145
148
|
};
|
|
146
149
|
export declare class ArtifactsClient {
|
|
147
150
|
private readonly operatorKey;
|
|
@@ -158,7 +161,7 @@ export declare class ArtifactsClient {
|
|
|
158
161
|
* This is not `list()` with a query string. `list()` answers "what is in this
|
|
159
162
|
* container"; a person's cross-container view lives behind `reach` arms that
|
|
160
163
|
* an agent has no business asking for. The server refuses `reach`,
|
|
161
|
-
* `authoredBy` and `
|
|
164
|
+
* `authoredBy` and `addressId` here rather than ignoring them, so a narrowing
|
|
162
165
|
* filter can never be silently dropped — hence no options for them.
|
|
163
166
|
*
|
|
164
167
|
* The result always carries `coverage`. An empty `artifacts` is a statement
|
|
@@ -174,7 +177,7 @@ export declare class ArtifactsClient {
|
|
|
174
177
|
* endpoint is updated to accept `visibility`, this falls back to logging
|
|
175
178
|
* locally (operators can still wire their own sink).
|
|
176
179
|
*/
|
|
177
|
-
recordThought(
|
|
180
|
+
recordThought(text: string, opts?: {
|
|
178
181
|
idempotencyKey?: string;
|
|
179
182
|
serviceAgreementId?: string;
|
|
180
183
|
}): Promise<void>;
|
|
@@ -190,19 +193,29 @@ export declare class ArtifactsClient {
|
|
|
190
193
|
artifactId?: string;
|
|
191
194
|
}>;
|
|
192
195
|
/**
|
|
193
|
-
* attach an existing artifact to a
|
|
196
|
+
* attach an existing artifact to a task or agreement.
|
|
194
197
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* reaches anyone without granting it to one specific agent.
|
|
198
|
+
* A chat link is a presentation reference, never an access grant. Task and
|
|
199
|
+
* agreement associations use their work authority and source-disclosure policy.
|
|
200
|
+
* Explicit artifact sharing grants access to the selected holder.
|
|
199
201
|
*/
|
|
200
|
-
attachToChat(artifactId: string, chatId: string): Promise<{
|
|
201
|
-
success: boolean;
|
|
202
|
-
}>;
|
|
203
202
|
attachToTask(artifactId: string, taskId: string, role?: 'input' | 'output'): Promise<{
|
|
204
203
|
success: boolean;
|
|
205
204
|
}>;
|
|
205
|
+
/** Inspect the exact-output approvals without dropping the source execution. */
|
|
206
|
+
reviewContribution(artifactId: string, agreementId: string): Promise<{
|
|
207
|
+
artifactId: string;
|
|
208
|
+
target: import('@ziggs-ai/contracts').ContributionTarget;
|
|
209
|
+
ready: boolean;
|
|
210
|
+
releaseSources: import('@ziggs-ai/contracts').ContributionSource[];
|
|
211
|
+
privateSourceCount: number;
|
|
212
|
+
}>;
|
|
213
|
+
/** Delivers only this immutable artifact after all required consent is live. */
|
|
214
|
+
contribute(artifactId: string, agreementId: string): Promise<{
|
|
215
|
+
artifactId: string;
|
|
216
|
+
agreementId: string;
|
|
217
|
+
outcome: 'created' | 'existing';
|
|
218
|
+
}>;
|
|
206
219
|
attachToAgreement(artifactId: string, agreementId: string): Promise<{
|
|
207
220
|
success: boolean;
|
|
208
221
|
}>;
|
|
@@ -232,6 +245,5 @@ export declare class ArtifactsClient {
|
|
|
232
245
|
* binds it to a task. Both containers at once is still a mistake worth naming,
|
|
233
246
|
* since only one of them would take effect.
|
|
234
247
|
*/
|
|
235
|
-
private _assertScopeXor;
|
|
236
248
|
private _headers;
|
|
237
249
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
2
2
|
import { throwApiError } from '../shared/apiError.js';
|
|
3
3
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
|
-
import { buildOperatorHeaders } from './operatorHeaders.js';
|
|
4
|
+
import { buildOperatorHeaders, currentWorkExecution } from './operatorHeaders.js';
|
|
5
5
|
/**
|
|
6
6
|
* Inline `POST /artifacts` body cap (matches backend
|
|
7
7
|
* `ARTIFACT_PUBLIC_TEXT_MAX_CHARS`). Over this → file rail or multi-part; the
|
|
@@ -26,28 +26,22 @@ function resolveUploadBytes(input) {
|
|
|
26
26
|
}
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Replaces `ContextReader`'s artifact reads + `ContextWriter`'s breadcrumb
|
|
31
|
-
* writes. `visibility: 'agent-private'` is the new home for agent thoughts —
|
|
32
|
-
* they persist, are searchable, but are not visible to other chat parties.
|
|
33
|
-
*/
|
|
34
|
-
/**
|
|
35
|
-
* turn a runtime lane id into a scope the backend can accept.
|
|
36
|
-
*
|
|
37
|
-
* A task with no origin chat runs on the lane `agrn-<agreementId>` (see
|
|
38
|
-
* Agent.laneSessionIdForTask). That is a routing key, not a chat: no such
|
|
39
|
-
* chat row exists, so passing it as `chatId` made every breadcrumb and recorded
|
|
40
|
-
* thought on an agreement lane come back 403 "not authorized for this scope" —
|
|
41
|
-
* a fictional scope reading like an auth failure. The work is agreement-scoped,
|
|
42
|
-
* so say so; same rule settled for deliverables.
|
|
43
|
-
*/
|
|
44
|
-
import { agreementIdFromLane } from '@ziggs-ai/contracts';
|
|
45
29
|
export { AGREEMENT_LANE_PREFIX } from '@ziggs-ai/contracts';
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
function rejectRoomScope(input) {
|
|
31
|
+
if ('addressId' in input)
|
|
32
|
+
throw new Error('addressId is retired; use explicit task/agreement work or an exact message artifact reference');
|
|
33
|
+
}
|
|
34
|
+
export function artifactScope(target = {}) {
|
|
35
|
+
rejectRoomScope(target);
|
|
36
|
+
const execution = currentWorkExecution();
|
|
37
|
+
if (execution?.agreementId)
|
|
38
|
+
return { agreementId: execution.agreementId };
|
|
39
|
+
if (execution)
|
|
40
|
+
return {};
|
|
41
|
+
if (target.agreementId)
|
|
42
|
+
return { agreementId: target.agreementId };
|
|
43
|
+
// An unattached artifact is private to its owner; a container is optional.
|
|
44
|
+
return {};
|
|
51
45
|
}
|
|
52
46
|
export class ArtifactsClient {
|
|
53
47
|
operatorKey;
|
|
@@ -60,13 +54,12 @@ export class ArtifactsClient {
|
|
|
60
54
|
this.agentId = agentId;
|
|
61
55
|
}
|
|
62
56
|
async list(q, opts = {}) {
|
|
63
|
-
|
|
57
|
+
rejectRoomScope(q);
|
|
58
|
+
const selectors = [q.agreementId, q.taskId, q.authoredBy].filter(Boolean);
|
|
64
59
|
if (selectors.length !== 1) {
|
|
65
|
-
throw new Error('ArtifactsClient.list: pass exactly one of
|
|
60
|
+
throw new Error('ArtifactsClient.list: pass exactly one of agreementId, taskId, or authoredBy');
|
|
66
61
|
}
|
|
67
62
|
const url = new URL(`${getBackendUrl()}/artifacts`);
|
|
68
|
-
if (q.chatId)
|
|
69
|
-
url.searchParams.set('chatId', q.chatId);
|
|
70
63
|
if (q.agreementId)
|
|
71
64
|
url.searchParams.set('agreementId', q.agreementId);
|
|
72
65
|
if (q.taskId)
|
|
@@ -93,7 +86,7 @@ export class ArtifactsClient {
|
|
|
93
86
|
* This is not `list()` with a query string. `list()` answers "what is in this
|
|
94
87
|
* container"; a person's cross-container view lives behind `reach` arms that
|
|
95
88
|
* an agent has no business asking for. The server refuses `reach`,
|
|
96
|
-
* `authoredBy` and `
|
|
89
|
+
* `authoredBy` and `addressId` here rather than ignoring them, so a narrowing
|
|
97
90
|
* filter can never be silently dropped — hence no options for them.
|
|
98
91
|
*
|
|
99
92
|
* The result always carries `coverage`. An empty `artifacts` is a statement
|
|
@@ -126,10 +119,9 @@ export class ArtifactsClient {
|
|
|
126
119
|
* endpoint is updated to accept `visibility`, this falls back to logging
|
|
127
120
|
* locally (operators can still wire their own sink).
|
|
128
121
|
*/
|
|
129
|
-
async recordThought(
|
|
130
|
-
// `sessionId` may be an agreement lane, which is not a chat.
|
|
122
|
+
async recordThought(text, opts = {}) {
|
|
131
123
|
return this.write({
|
|
132
|
-
...
|
|
124
|
+
...artifactScope({ agreementId: opts.serviceAgreementId }),
|
|
133
125
|
text,
|
|
134
126
|
contentType: 'thought',
|
|
135
127
|
visibility: 'agent-private',
|
|
@@ -138,9 +130,9 @@ export class ArtifactsClient {
|
|
|
138
130
|
});
|
|
139
131
|
}
|
|
140
132
|
async write(input) {
|
|
133
|
+
rejectRoomScope(input);
|
|
141
134
|
if (!input.text || !input.text.trim())
|
|
142
135
|
return;
|
|
143
|
-
this._assertScopeXor(input);
|
|
144
136
|
try {
|
|
145
137
|
await this.writeStrict(input);
|
|
146
138
|
}
|
|
@@ -161,7 +153,7 @@ export class ArtifactsClient {
|
|
|
161
153
|
if (!input.text || !input.text.trim()) {
|
|
162
154
|
throw new Error('ArtifactsClient.writeStrict: text is required');
|
|
163
155
|
}
|
|
164
|
-
|
|
156
|
+
rejectRoomScope(input);
|
|
165
157
|
const text = input.text.trim();
|
|
166
158
|
// Refuse before the wire so MCP/SDK get a named escape hatch
|
|
167
159
|
// instead of a bare class-validator string.
|
|
@@ -176,8 +168,7 @@ export class ArtifactsClient {
|
|
|
176
168
|
text,
|
|
177
169
|
...(input.name?.trim() ? { name: input.name.trim() } : {}),
|
|
178
170
|
contentType: input.contentType ?? 'text',
|
|
179
|
-
visibility: input.visibility ?? '
|
|
180
|
-
chatId: input.chatId,
|
|
171
|
+
visibility: input.visibility ?? 'address',
|
|
181
172
|
agreementId: input.agreementId,
|
|
182
173
|
taskId: input.taskId,
|
|
183
174
|
serviceAgreementId: input.serviceAgreementId,
|
|
@@ -202,24 +193,31 @@ export class ArtifactsClient {
|
|
|
202
193
|
}
|
|
203
194
|
}
|
|
204
195
|
/**
|
|
205
|
-
* attach an existing artifact to a
|
|
196
|
+
* attach an existing artifact to a task or agreement.
|
|
206
197
|
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* reaches anyone without granting it to one specific agent.
|
|
198
|
+
* A chat link is a presentation reference, never an access grant. Task and
|
|
199
|
+
* agreement associations use their work authority and source-disclosure policy.
|
|
200
|
+
* Explicit artifact sharing grants access to the selected holder.
|
|
211
201
|
*/
|
|
212
|
-
async attachToChat(artifactId, chatId) {
|
|
213
|
-
return this._attach(`/chats/${encodeURIComponent(chatId)}/artifacts`, {
|
|
214
|
-
artifactId,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
202
|
async attachToTask(artifactId, taskId, role = 'output') {
|
|
218
203
|
return this._attach(`/tasks/${encodeURIComponent(taskId)}/artifacts`, {
|
|
219
204
|
artifactId,
|
|
220
205
|
role,
|
|
221
206
|
});
|
|
222
207
|
}
|
|
208
|
+
/** Inspect the exact-output approvals without dropping the source execution. */
|
|
209
|
+
async reviewContribution(artifactId, agreementId) {
|
|
210
|
+
const url = new URL(`${getBackendUrl()}/artifacts/${encodeURIComponent(artifactId)}/contribution-review`);
|
|
211
|
+
url.searchParams.set('agreementId', agreementId);
|
|
212
|
+
const response = await fetch(url, { headers: this._headers() });
|
|
213
|
+
if (!response.ok)
|
|
214
|
+
throwApiError(response, await response.text(), 'reviewContribution failed');
|
|
215
|
+
return response.json();
|
|
216
|
+
}
|
|
217
|
+
/** Delivers only this immutable artifact after all required consent is live. */
|
|
218
|
+
async contribute(artifactId, agreementId) {
|
|
219
|
+
return this._post(`/agreements/${encodeURIComponent(agreementId)}/contributions`, { artifactId }, 'contributeArtifact');
|
|
220
|
+
}
|
|
223
221
|
async attachToAgreement(artifactId, agreementId) {
|
|
224
222
|
return this._attach(`/agreements/${encodeURIComponent(agreementId)}/artifacts`, { artifactId });
|
|
225
223
|
}
|
|
@@ -229,6 +227,7 @@ export class ArtifactsClient {
|
|
|
229
227
|
* S3 PUT here and returns a sha256 so complete can follow immediately.
|
|
230
228
|
*/
|
|
231
229
|
async uploadUrl(input) {
|
|
230
|
+
rejectRoomScope(input);
|
|
232
231
|
if (!input.filename?.trim()) {
|
|
233
232
|
throw new Error('ArtifactsClient.uploadUrl: filename is required');
|
|
234
233
|
}
|
|
@@ -238,11 +237,6 @@ export class ArtifactsClient {
|
|
|
238
237
|
if (!Number.isInteger(input.byteSize) || input.byteSize < 1) {
|
|
239
238
|
throw new Error('ArtifactsClient.uploadUrl: byteSize must be a positive integer');
|
|
240
239
|
}
|
|
241
|
-
this._assertScopeXor({
|
|
242
|
-
text: '.',
|
|
243
|
-
chatId: input.chatId,
|
|
244
|
-
agreementId: input.agreementId,
|
|
245
|
-
});
|
|
246
240
|
const bytes = resolveUploadBytes(input);
|
|
247
241
|
if (bytes && bytes.byteLength !== input.byteSize) {
|
|
248
242
|
throw new Error(`ArtifactsClient.uploadUrl: byteSize ${input.byteSize} does not match content length ${bytes.byteLength}`);
|
|
@@ -254,7 +248,6 @@ export class ArtifactsClient {
|
|
|
254
248
|
byteSize: input.byteSize,
|
|
255
249
|
format: input.format,
|
|
256
250
|
visibility: input.visibility,
|
|
257
|
-
chatId: input.chatId,
|
|
258
251
|
agreementId: input.agreementId,
|
|
259
252
|
taskId: input.taskId,
|
|
260
253
|
serviceAgreementId: input.serviceAgreementId,
|
|
@@ -343,18 +336,6 @@ export class ArtifactsClient {
|
|
|
343
336
|
* binds it to a task. Both containers at once is still a mistake worth naming,
|
|
344
337
|
* since only one of them would take effect.
|
|
345
338
|
*/
|
|
346
|
-
_assertScopeXor(input) {
|
|
347
|
-
if (input.chatId && input.agreementId) {
|
|
348
|
-
// the refusal names the recovery, because this is the one gate
|
|
349
|
-
// for every caller — the exposed tool surfaces inherit it rather than each
|
|
350
|
-
// wording their own. Wording matters: this fires at the last step of a
|
|
351
|
-
// finished task, where a bare "pick one" leaves the deliverable unfiled.
|
|
352
|
-
throw new Error('pass at most one of chatId or agreementId — a deliverable under an ' +
|
|
353
|
-
'agreement wants agreementId alone (its parties see it); use chatId ' +
|
|
354
|
-
'only for a chat-scoped note. To put it in both places, record it ' +
|
|
355
|
-
'with agreementId, then attach it to the chat.');
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
339
|
_headers() {
|
|
359
340
|
return buildOperatorHeaders(this.operatorKey, this.agentId, { 'content-type': 'application/json' });
|
|
360
341
|
}
|
|
@@ -38,11 +38,10 @@ export interface McpConnectionRequestParams {
|
|
|
38
38
|
* per-user relay may send it as `onBehalfOfUserId` instead.
|
|
39
39
|
*/
|
|
40
40
|
recipientId?: string;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
chatId?: string;
|
|
41
|
+
context: {
|
|
42
|
+
kind: 'message' | 'task' | 'agreement';
|
|
43
|
+
id: string;
|
|
44
|
+
};
|
|
46
45
|
/**
|
|
47
46
|
* Target the consent request at this end-user (X-On-Behalf-Of-User) instead
|
|
48
47
|
* of the operator — the per-user MCP gateway's connect prompt.
|
|
@@ -112,10 +111,10 @@ export declare class ConnectionsClient {
|
|
|
112
111
|
/**
|
|
113
112
|
* agent-initiated MCP connection request: ask the principal to
|
|
114
113
|
* connect a remote MCP server and grant this agent the listed tools. Opens a
|
|
115
|
-
* connection-consent agreement
|
|
114
|
+
* connection-consent agreement for explicit work/message context; on approval the
|
|
116
115
|
* server is connected (if needed) and the agent is granted the tools.
|
|
117
116
|
*/
|
|
118
|
-
requestMcpConnection({ serverUrl, tools, reason,
|
|
117
|
+
requestMcpConnection({ serverUrl, tools, reason, context, recipientId, onBehalfOfUserId, }: McpConnectionRequestParams): Promise<Record<string, unknown>>;
|
|
119
118
|
private _requestRaw;
|
|
120
119
|
private _request;
|
|
121
120
|
}
|