@ziggs-ai/api-client 0.37.28 → 0.38.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 +6 -0
- package/dist/capabilities/artifacts.js +9 -9
- package/dist/capabilities/connections.js +3 -8
- package/dist/capabilities/context.js +15 -4
- package/dist/capabilities/grants.js +1 -4
- package/dist/capabilities/mcpBriefs.js +1 -1
- package/dist/capabilities/payments.js +2 -7
- package/dist/http/AgreementClient.d.ts +10 -2
- package/dist/http/AgreementClient.js +6 -4
- package/dist/http/ArtifactsClient.d.ts +2 -9
- package/dist/http/ArtifactsClient.js +3 -11
- package/dist/http/AssistantConnectionClient.d.ts +1 -1
- package/dist/http/AssistantConnectionClient.js +2 -2
- package/dist/http/ConnectionsClient.d.ts +2 -12
- package/dist/http/ConnectionsClient.js +4 -15
- package/dist/http/ContextGrantsClient.d.ts +1 -0
- package/dist/http/ContextGrantsClient.js +1 -1
- package/dist/http/ContextOpenClient.d.ts +2 -3
- package/dist/http/ContextOpenClient.js +2 -4
- package/dist/http/ContextReadClient.d.ts +5 -13
- package/dist/http/ContextReadClient.js +4 -19
- package/dist/http/ExecutionContextClient.d.ts +3 -0
- package/dist/http/ExecutionContextClient.js +17 -0
- package/dist/http/GrantsClient.d.ts +2 -10
- package/dist/http/GrantsClient.js +3 -12
- package/dist/http/InboxClient.d.ts +2 -2
- package/dist/http/InboxClient.js +1 -3
- package/dist/http/PaymentsClient.d.ts +2 -15
- package/dist/http/PaymentsClient.js +4 -18
- package/dist/http/TelemetryClient.js +3 -3
- package/dist/http/ToolPickClient.js +2 -2
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/operatorHeaders.d.ts +14 -36
- package/dist/http/operatorHeaders.js +26 -50
- package/dist/inboxAck.d.ts +14 -46
- package/dist/inboxAck.js +12 -102
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/types.d.ts +15 -16
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.38.0
|
|
6
|
+
|
|
7
|
+
- `respondToAgreement` and `approveAgreementAsParty` accept `mandateAgreementId`: the hire whose setting lets an agent answer without a person. It is sent in the request body and never inferred from the selected execution.
|
|
8
|
+
- Clarify that connection work consent applies to every selected execution, including personal work.
|
|
9
|
+
- Document owner-approved `work_context` consent for connection discovery and proxy calls during a selected execution.
|
|
10
|
+
|
|
5
11
|
## 0.37.28
|
|
6
12
|
|
|
7
13
|
- `SessionsClient` lists sibling assistant windows and holds a chat in this window (`GET/POST /agents/:id/sessions`). Used by MCP `ziggs_session_list` / `ziggs_session_hold`. Not on the directory connector surface.
|
|
@@ -92,7 +92,7 @@ async function recordFileArtifact(args, env, visibility) {
|
|
|
92
92
|
// can be tens of megabytes.
|
|
93
93
|
const bytes = decodeFileBytes(contentBase64);
|
|
94
94
|
const creds = fullCreds(env);
|
|
95
|
-
const client = new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
95
|
+
const client = new ArtifactsClient(creds.operatorKey, creds.agentId);
|
|
96
96
|
const taskId = args['taskId'];
|
|
97
97
|
const byteSize = bytes.byteLength;
|
|
98
98
|
const uploaded = await client.uploadUrl({
|
|
@@ -255,7 +255,7 @@ export const recordArtifactCapability = {
|
|
|
255
255
|
const taskId = args['taskId'];
|
|
256
256
|
const externalRef = parseExternalRef(args['externalRef']);
|
|
257
257
|
const creds = fullCreds(env);
|
|
258
|
-
const { artifactId } = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
258
|
+
const { artifactId } = await new ArtifactsClient(creds.operatorKey, creds.agentId).writeStrict({
|
|
259
259
|
text,
|
|
260
260
|
name: args['name']?.trim() || undefined,
|
|
261
261
|
visibility,
|
|
@@ -305,7 +305,7 @@ export const listArtifactsCapability = {
|
|
|
305
305
|
needsAgentId: true,
|
|
306
306
|
handler: async (args, env) => {
|
|
307
307
|
const creds = fullCreds(env);
|
|
308
|
-
const listed = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
308
|
+
const listed = await new ArtifactsClient(creds.operatorKey, creds.agentId).list({ authoredBy: 'me' }, {
|
|
309
309
|
after: args['after'],
|
|
310
310
|
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
311
311
|
});
|
|
@@ -429,7 +429,7 @@ export const findArtifactsCapability = {
|
|
|
429
429
|
needsAgentId: true,
|
|
430
430
|
handler: async (args, env) => {
|
|
431
431
|
const creds = fullCreds(env);
|
|
432
|
-
const found = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
432
|
+
const found = await new ArtifactsClient(creds.operatorKey, creds.agentId).find(args['q'], {
|
|
433
433
|
limit: typeof args['limit'] === 'number' ? args['limit'] : undefined,
|
|
434
434
|
before: args['before'],
|
|
435
435
|
});
|
|
@@ -568,7 +568,7 @@ export const attachArtifactCapability = {
|
|
|
568
568
|
throw new Error('role must be input or output');
|
|
569
569
|
}
|
|
570
570
|
const creds = fullCreds(env);
|
|
571
|
-
const client = new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
571
|
+
const client = new ArtifactsClient(creds.operatorKey, creds.agentId);
|
|
572
572
|
if (chatId) {
|
|
573
573
|
await client.attachToChat(artifactId, chatId);
|
|
574
574
|
return {
|
|
@@ -672,7 +672,7 @@ export const uploadArtifactUrlCapability = {
|
|
|
672
672
|
throw new Error('visibility must be chat or agent-private');
|
|
673
673
|
}
|
|
674
674
|
const creds = fullCreds(env);
|
|
675
|
-
const result = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
675
|
+
const result = await new ArtifactsClient(creds.operatorKey, creds.agentId).uploadUrl({
|
|
676
676
|
filename,
|
|
677
677
|
mime,
|
|
678
678
|
byteSize: Math.trunc(byteSize),
|
|
@@ -722,7 +722,7 @@ export const completeArtifactFileCapability = {
|
|
|
722
722
|
if (!checksum)
|
|
723
723
|
throw new Error('checksum is required');
|
|
724
724
|
const creds = fullCreds(env);
|
|
725
|
-
const artifact = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
725
|
+
const artifact = await new ArtifactsClient(creds.operatorKey, creds.agentId).completeFile(artifactId, checksum);
|
|
726
726
|
return {
|
|
727
727
|
ok: true,
|
|
728
728
|
artifact,
|
|
@@ -749,7 +749,7 @@ export const downloadArtifactCapability = {
|
|
|
749
749
|
if (!artifactId)
|
|
750
750
|
throw new Error('artifactId is required');
|
|
751
751
|
const creds = fullCreds(env);
|
|
752
|
-
const out = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
752
|
+
const out = await new ArtifactsClient(creds.operatorKey, creds.agentId).download(artifactId);
|
|
753
753
|
return { ok: true, ...out };
|
|
754
754
|
},
|
|
755
755
|
};
|
|
@@ -771,7 +771,7 @@ export const reextractArtifactCapability = {
|
|
|
771
771
|
if (!artifactId)
|
|
772
772
|
throw new Error('artifactId is required');
|
|
773
773
|
const creds = fullCreds(env);
|
|
774
|
-
const artifact = await new ArtifactsClient(creds.operatorKey, creds.agentId
|
|
774
|
+
const artifact = await new ArtifactsClient(creds.operatorKey, creds.agentId).reExtract(artifactId);
|
|
775
775
|
return { ok: true, artifact };
|
|
776
776
|
},
|
|
777
777
|
};
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { ConnectionsClient } from "../http/ConnectionsClient.js";
|
|
2
2
|
import { rethrowWithContext, } from "./types.js";
|
|
3
3
|
function client(env) {
|
|
4
|
-
|
|
5
|
-
// in, and the broker reads off it who the agent is acting for — which is what
|
|
6
|
-
// tells one hirer's grant from another's: an agent that serves several hirers
|
|
7
|
-
// is the holder of every grant it has been given, so the holder check alone
|
|
8
|
-
// cannot separate them. Every other Creds-based client already carries it.
|
|
9
|
-
const { operatorKey, agentId, laneId } = env.creds;
|
|
4
|
+
const { operatorKey, agentId } = env.creds;
|
|
10
5
|
if (!operatorKey)
|
|
11
6
|
throw new Error("operatorKey missing from tool context");
|
|
12
|
-
return new ConnectionsClient(operatorKey, agentId, env.baseUrl
|
|
7
|
+
return new ConnectionsClient(operatorKey, agentId, env.baseUrl);
|
|
13
8
|
}
|
|
14
9
|
export const connectionProxyCapability = {
|
|
15
10
|
key: "connection_proxy",
|
|
@@ -17,7 +12,7 @@ export const connectionProxyCapability = {
|
|
|
17
12
|
title: "Use a stored connection",
|
|
18
13
|
descriptions: {
|
|
19
14
|
sdk: "Use a named-connector stored connection (e.g. the owner's GitHub/Jira) without ever seeing the credential. " +
|
|
20
|
-
"Calls the backend connections proxy with a grant the owner issued to this agent. " +
|
|
15
|
+
"Calls the backend connections proxy with a grant the owner issued to this agent. In selected work, the grant must also carry owner-approved work_context consent for that work and its readers, or be the grant the hire itself minted for it. Keep the execution context on discovery and calls. " +
|
|
21
16
|
'Not for remote MCP servers (provider "mcp") — those use mcp_tool_call / mcp_tools_list; proxy refuses them with "Unknown provider: mcp". ' +
|
|
22
17
|
"Don't know connectionId/grantId yet? Use grant_list (scopeKind [\"connection\"]) or connection_list_grants first.",
|
|
23
18
|
},
|
|
@@ -119,7 +119,7 @@ export const contextReadCapability = {
|
|
|
119
119
|
if (direction !== undefined && direction !== 'forward' && direction !== 'backward') {
|
|
120
120
|
throw new Error('direction must be "forward" or "backward"');
|
|
121
121
|
}
|
|
122
|
-
return new ContextReadClient(creds.operatorKey, creds.agentId, undefined
|
|
122
|
+
return new ContextReadClient(creds.operatorKey, creds.agentId, undefined).read(type, {
|
|
123
123
|
via,
|
|
124
124
|
agreementId: args['agreementId'],
|
|
125
125
|
cursor: args['cursor'],
|
|
@@ -307,7 +307,7 @@ export async function explainRefusedRead(kind, id, env) {
|
|
|
307
307
|
const creds = fullCreds(env);
|
|
308
308
|
let presented;
|
|
309
309
|
try {
|
|
310
|
-
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl
|
|
310
|
+
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl);
|
|
311
311
|
presented = presentOpenResult(await client.explain({ [`${kind}Id`]: id }), env);
|
|
312
312
|
}
|
|
313
313
|
catch {
|
|
@@ -348,7 +348,7 @@ export const openCapability = {
|
|
|
348
348
|
needsAgentId: true,
|
|
349
349
|
handler: async (args, env) => {
|
|
350
350
|
const creds = fullCreds(env);
|
|
351
|
-
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl
|
|
351
|
+
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl);
|
|
352
352
|
return presentOpenResult(await client.open(args), env);
|
|
353
353
|
},
|
|
354
354
|
};
|
|
@@ -364,7 +364,7 @@ export const accessExplainCapability = {
|
|
|
364
364
|
needsAgentId: true,
|
|
365
365
|
handler: async (args, env) => {
|
|
366
366
|
const creds = fullCreds(env);
|
|
367
|
-
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl
|
|
367
|
+
const client = new ContextOpenClient(creds.operatorKey, creds.agentId, env.baseUrl);
|
|
368
368
|
const result = await client.explain(args);
|
|
369
369
|
return presentOpenResult(result, env);
|
|
370
370
|
},
|
|
@@ -418,6 +418,9 @@ export const accessRequestCapability = {
|
|
|
418
418
|
// comes back refused with the people this agent may ask. Required in the
|
|
419
419
|
// schema, a host refused the call before that list could arrive.
|
|
420
420
|
recipientId: { type: 'string', description: 'Who to ask: workBrief.actingFor.customer.id (the customer of this hire) or workBrief.actingFor.operator.id (your operator). Omit when only one approver is available; otherwise the response lists choices.' },
|
|
421
|
+
contributionTo: {
|
|
422
|
+
type: 'object', description: 'Artifact only: { kind: "chat" | "agreement", id }. Ask its owner to approve use in this shared work. Name all destination readers and yourself in holders. Existing read access does not replace this consent.',
|
|
423
|
+
},
|
|
421
424
|
holders: {
|
|
422
425
|
type: 'array',
|
|
423
426
|
description: 'Artifact only, read only: up to 20 readers, each { kind: "agent" | "user" | "org", id }. Leave yourself out to arrange it for others. Omit to ask for yourself.',
|
|
@@ -461,6 +464,13 @@ export const accessRequestCapability = {
|
|
|
461
464
|
const holders = args.holders === undefined ? undefined : readersOf(args.holders);
|
|
462
465
|
if (holders && (scopeKind !== 'artifact' || agreementId || permission !== 'read'))
|
|
463
466
|
throw new Error('holders is for one artifact named by scopeId, to read');
|
|
467
|
+
let contributionTo;
|
|
468
|
+
if (args.contributionTo !== undefined) {
|
|
469
|
+
const target = args.contributionTo;
|
|
470
|
+
if (!target || !['chat', 'agreement'].includes(String(target.kind)) || typeof target.id !== 'string' || !target.id.trim() || !holders || scopeKind !== 'artifact' || agreementId || permission !== 'read')
|
|
471
|
+
throw new Error('contributionTo requires an artifact, named readers, and a chat or agreement destination');
|
|
472
|
+
contributionTo = { kind: target.kind, id: target.id.trim() };
|
|
473
|
+
}
|
|
464
474
|
const creds = fullCreds(env);
|
|
465
475
|
const result = await new ContextGrantsClient(creds.operatorKey, creds.agentId, env.baseUrl).requestAccess({
|
|
466
476
|
scopeKind, scopeId, agreementId, reason: String(args.reason).trim(),
|
|
@@ -468,6 +478,7 @@ export const accessRequestCapability = {
|
|
|
468
478
|
durationHours, chatId: args.chatId,
|
|
469
479
|
recipientId: typeof args.recipientId === 'string' ? args.recipientId.trim() : undefined,
|
|
470
480
|
...(holders ? { holders } : {}),
|
|
481
|
+
...(contributionTo ? { contributionTo } : {}),
|
|
471
482
|
}, { idempotencyKey: args.idempotencyKey, laneId: creds.laneId });
|
|
472
483
|
const actingAgentId = result.actingAgentId ?? (creds.agentId || undefined);
|
|
473
484
|
if (result.status === 'already_readable') {
|
|
@@ -81,10 +81,7 @@ export const listGrantsCapability = {
|
|
|
81
81
|
if (roleArg !== undefined && roleArg !== 'holder' && roleArg !== 'issuer') {
|
|
82
82
|
throw new Error('role must be holder or issuer');
|
|
83
83
|
}
|
|
84
|
-
const { items, nextCursor, unreadableRails } = await new GrantsClient(creds.operatorKey, creds.agentId, env.baseUrl
|
|
85
|
-
// The lane, so the server answers with the grants THIS wake may spend
|
|
86
|
-
// rather than everything the agent holds across every customer.
|
|
87
|
-
creds.laneId).listGrants({
|
|
84
|
+
const { items, nextCursor, unreadableRails } = await new GrantsClient(creds.operatorKey, creds.agentId, env.baseUrl).listGrants({
|
|
88
85
|
scopeKind,
|
|
89
86
|
scopeId: typeof args['scopeId'] === 'string' ? args['scopeId'] : undefined,
|
|
90
87
|
role: roleArg,
|
|
@@ -45,7 +45,7 @@ const BRIEFS = {
|
|
|
45
45
|
next: 'ziggs_inbox_ack after handling',
|
|
46
46
|
},
|
|
47
47
|
ziggs_inbox_ack: {
|
|
48
|
-
does: 'Hands back handled deliveries: ackTo exactly as received, plus
|
|
48
|
+
does: 'Hands back handled deliveries: ackTo exactly as received, plus handledDeliveryIds for each one assigned to you (empty is safe when none is).',
|
|
49
49
|
changes: 'moves the watermark; an older ackTo is a no-op; skipping your rows is refused (INBOX_ACK_UNHANDLED)',
|
|
50
50
|
},
|
|
51
51
|
ziggs_inbox_defer: {
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { PaymentsClient } from '../http/PaymentsClient.js';
|
|
2
2
|
import { rethrowWithContext, } from './types.js';
|
|
3
3
|
function client(env) {
|
|
4
|
-
|
|
5
|
-
// on this surface today, and a read does not spend — but the lane is what
|
|
6
|
-
// fences a spend to the job it was authorised in, so it is wired here rather
|
|
7
|
-
// than left for whoever brings a spending verb back to remember. Omitting it
|
|
8
|
-
// can only leave a spend unfenced; it can never widen one.
|
|
9
|
-
const { operatorKey, agentId, laneId } = env.creds;
|
|
4
|
+
const { operatorKey, agentId } = env.creds;
|
|
10
5
|
if (!operatorKey)
|
|
11
6
|
throw new Error('operatorKey missing from tool context');
|
|
12
|
-
return new PaymentsClient(operatorKey, agentId, env.baseUrl
|
|
7
|
+
return new PaymentsClient(operatorKey, agentId, env.baseUrl);
|
|
13
8
|
}
|
|
14
9
|
/**
|
|
15
10
|
* Reading the balance is the whole rail on an agent surface.
|
|
@@ -161,6 +161,8 @@ export declare function respondToAgreement(agreementId: string, action: 'approve
|
|
|
161
161
|
agreement?: Agreement | null;
|
|
162
162
|
/** Where to send the human when the decision is theirs. */
|
|
163
163
|
appUrl?: string;
|
|
164
|
+
/** The hire whose setting lets this agent answer without a person. */
|
|
165
|
+
mandateAgreementId?: string;
|
|
164
166
|
}): Promise<Agreement>;
|
|
165
167
|
/**
|
|
166
168
|
* The approval facts a "who decides this?" question is answered from: the party
|
|
@@ -202,7 +204,11 @@ export declare function resolveMyPendingApprovalPartyId(agreement: Agreement, op
|
|
|
202
204
|
* approval authority even for their own slot; the server rechecks it on PUT.
|
|
203
205
|
* Canonical for hire, service, link, and request proposals.
|
|
204
206
|
*/
|
|
205
|
-
export declare function approveAgreementAsParty(agreementId: string, partyId: string, status: 'approved' | 'rejected', creds: Creds
|
|
207
|
+
export declare function approveAgreementAsParty(agreementId: string, partyId: string, status: 'approved' | 'rejected', creds: Creds,
|
|
208
|
+
/** The hire whose setting lets this agent answer without a person. Named, never inferred from the execution. */
|
|
209
|
+
opts?: {
|
|
210
|
+
mandateAgreementId?: string;
|
|
211
|
+
}): Promise<Agreement>;
|
|
206
212
|
export interface CounterAgreementData {
|
|
207
213
|
price?: number;
|
|
208
214
|
agreementDescription?: string;
|
|
@@ -392,7 +398,9 @@ export declare class AgreementClient {
|
|
|
392
398
|
proposeDirect(data: ProposeDirectInput): Promise<Agreement>;
|
|
393
399
|
proposeBroadcast(data: ProposeBroadcastInput): Promise<Agreement>;
|
|
394
400
|
delegate(data: DelegateAgreementData): Promise<Agreement>;
|
|
395
|
-
respond(id: string, action: 'approve' | 'reject'
|
|
401
|
+
respond(id: string, action: 'approve' | 'reject', opts?: {
|
|
402
|
+
mandateAgreementId?: string;
|
|
403
|
+
}): Promise<Agreement>;
|
|
396
404
|
approveAsParty(id: string, partyId: string, status: 'approved' | 'rejected'): Promise<Agreement>;
|
|
397
405
|
counter(id: string, data: CounterAgreementData): Promise<Agreement>;
|
|
398
406
|
getStatus(id: string): Promise<unknown>;
|
|
@@ -255,7 +255,7 @@ export async function respondToAgreement(agreementId, action, creds, opts = {})
|
|
|
255
255
|
// If the slot is the principal's, the server accepts
|
|
256
256
|
// only under a live approval-authority grant (else 403). Do not pre-refuse
|
|
257
257
|
// here; the PUT is the source of truth.
|
|
258
|
-
return approveAgreementAsParty(agreementId, partyId, action === 'approve' ? 'approved' : 'rejected', creds);
|
|
258
|
+
return approveAgreementAsParty(agreementId, partyId, action === 'approve' ? 'approved' : 'rejected', creds, opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {});
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Which of `candidateIds` holds the pending approval slot, first match wins —
|
|
@@ -298,7 +298,9 @@ export function resolveMyPendingApprovalPartyId(agreement, opts) {
|
|
|
298
298
|
* approval authority even for their own slot; the server rechecks it on PUT.
|
|
299
299
|
* Canonical for hire, service, link, and request proposals.
|
|
300
300
|
*/
|
|
301
|
-
export async function approveAgreementAsParty(agreementId, partyId, status, creds
|
|
301
|
+
export async function approveAgreementAsParty(agreementId, partyId, status, creds,
|
|
302
|
+
/** The hire whose setting lets this agent answer without a person. Named, never inferred from the execution. */
|
|
303
|
+
opts = {}) {
|
|
302
304
|
if (!agreementId)
|
|
303
305
|
throw new Error('agreementId is required for approval');
|
|
304
306
|
if (!partyId)
|
|
@@ -307,7 +309,7 @@ export async function approveAgreementAsParty(agreementId, partyId, status, cred
|
|
|
307
309
|
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/approvals/${encodeURIComponent(partyId)}`, {
|
|
308
310
|
method: 'PUT',
|
|
309
311
|
headers: buildHeaders(creds),
|
|
310
|
-
body: JSON.stringify({ status }),
|
|
312
|
+
body: JSON.stringify({ status, ...(opts.mandateAgreementId ? { mandateAgreementId: opts.mandateAgreementId } : {}) }),
|
|
311
313
|
});
|
|
312
314
|
if (!res.ok) {
|
|
313
315
|
const body = await res.text().catch(() => '');
|
|
@@ -688,7 +690,7 @@ export class AgreementClient {
|
|
|
688
690
|
proposeDirect(data) { return proposeDirectTo(data, this.creds); }
|
|
689
691
|
proposeBroadcast(data) { return proposeBroadcast(data, this.creds); }
|
|
690
692
|
delegate(data) { return delegateAgreement(data, this.creds); }
|
|
691
|
-
respond(id, action) { return respondToAgreement(id, action, this.creds); }
|
|
693
|
+
respond(id, action, opts = {}) { return respondToAgreement(id, action, this.creds, opts); }
|
|
692
694
|
approveAsParty(id, partyId, status) { return approveAgreementAsParty(id, partyId, status, this.creds); }
|
|
693
695
|
counter(id, data) { return counterAgreement(id, data, this.creds); }
|
|
694
696
|
getStatus(id) { return getAgreementStatus(id, this.creds); }
|
|
@@ -146,15 +146,8 @@ export declare function artifactScopeForSession(sessionId: string): {
|
|
|
146
146
|
export declare class ArtifactsClient {
|
|
147
147
|
private readonly operatorKey;
|
|
148
148
|
private readonly agentId?;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
152
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
153
|
-
* @param laneId the wake's lane (chat id, or `agrn-<agreementId>`),
|
|
154
|
-
* sent as X-Ziggs-Lane so `authoredBy=me` is fenced to this engagement
|
|
155
|
-
* rather than spanning every engagement the agent has authored in.
|
|
156
|
-
*/
|
|
157
|
-
constructor(operatorKey: string, agentId?: string, laneId?: string);
|
|
149
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
150
|
+
constructor(operatorKey: string, agentId?: string);
|
|
158
151
|
list(q: ListArtifactsQuery, opts?: ListArtifactsOptions): Promise<ListArtifactsResult>;
|
|
159
152
|
/**
|
|
160
153
|
* `GET /artifacts/find` — lexical search over the artifacts this agent can
|
|
@@ -52,20 +52,12 @@ export function artifactScopeForSession(sessionId) {
|
|
|
52
52
|
export class ArtifactsClient {
|
|
53
53
|
operatorKey;
|
|
54
54
|
agentId;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
58
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
59
|
-
* @param laneId the wake's lane (chat id, or `agrn-<agreementId>`),
|
|
60
|
-
* sent as X-Ziggs-Lane so `authoredBy=me` is fenced to this engagement
|
|
61
|
-
* rather than spanning every engagement the agent has authored in.
|
|
62
|
-
*/
|
|
63
|
-
constructor(operatorKey, agentId, laneId) {
|
|
55
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
56
|
+
constructor(operatorKey, agentId) {
|
|
64
57
|
if (!operatorKey)
|
|
65
58
|
throw new Error('ArtifactsClient: operatorKey is required');
|
|
66
59
|
this.operatorKey = operatorKey;
|
|
67
60
|
this.agentId = agentId;
|
|
68
|
-
this.laneId = laneId;
|
|
69
61
|
}
|
|
70
62
|
async list(q, opts = {}) {
|
|
71
63
|
const selectors = [q.chatId, q.agreementId, q.taskId, q.authoredBy].filter(Boolean);
|
|
@@ -364,6 +356,6 @@ export class ArtifactsClient {
|
|
|
364
356
|
}
|
|
365
357
|
}
|
|
366
358
|
_headers() {
|
|
367
|
-
return buildOperatorHeaders(this.operatorKey, this.agentId, { 'content-type': 'application/json' }
|
|
359
|
+
return buildOperatorHeaders(this.operatorKey, this.agentId, { 'content-type': 'application/json' });
|
|
368
360
|
}
|
|
369
361
|
}
|
|
@@ -55,7 +55,7 @@ export declare class AssistantConnectionClient {
|
|
|
55
55
|
getChanges(options?: InboxChangesOptions): Promise<InboxChangesResult>;
|
|
56
56
|
/** Receipt diagnostics only: this does not subscribe, renew or wake a host. */
|
|
57
57
|
eventStatus(orgId: string, signal?: AbortSignal): Promise<McpEventStatus>;
|
|
58
|
-
ack(upTo: string,
|
|
58
|
+
ack(upTo: string, handledDeliveryIds?: string[]): Promise<unknown>;
|
|
59
59
|
park(agreementId: string): Promise<{
|
|
60
60
|
agreementId: string;
|
|
61
61
|
parked: true;
|
|
@@ -60,8 +60,8 @@ export class AssistantConnectionClient {
|
|
|
60
60
|
eventStatus(orgId, signal) {
|
|
61
61
|
return this.request(`events/status?${new URLSearchParams({ orgId })}`, undefined, signal);
|
|
62
62
|
}
|
|
63
|
-
ack(upTo,
|
|
64
|
-
return this.request('inbox/ack', { upTo,
|
|
63
|
+
ack(upTo, handledDeliveryIds = []) {
|
|
64
|
+
return this.request('inbox/ack', { upTo, handledDeliveryIds });
|
|
65
65
|
}
|
|
66
66
|
park(agreementId) {
|
|
67
67
|
return this.request('inbox/park', { agreementId });
|
|
@@ -62,18 +62,8 @@ export declare class ConnectionsClient {
|
|
|
62
62
|
private readonly operatorKey;
|
|
63
63
|
private readonly agentId?;
|
|
64
64
|
private readonly baseUrl;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
* @param laneId the wake's lane (a chat id, or `agrn-<agreementId>`), sent as
|
|
68
|
-
* X-Ziggs-Lane. It tells the broker which hire this wake is in, and the
|
|
69
|
-
* broker reads off it WHO the agent is acting for: an agent that serves
|
|
70
|
-
* several hirers holds all of their grants at once and is the holder of
|
|
71
|
-
* every one, so without a lane one hirer's grant is indistinguishable from
|
|
72
|
-
* another's, and a grant one customer gave can be spent while working for
|
|
73
|
-
* somebody else.
|
|
74
|
-
* ArtifactsClient sends the same header for the same reason.
|
|
75
|
-
*/
|
|
76
|
-
constructor(operatorKey: string, agentId?: string, baseUrl?: string, laneId?: string);
|
|
65
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
66
|
+
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
77
67
|
/**
|
|
78
68
|
* Present a ConnectionGrant to the broker and perform a provider action.
|
|
79
69
|
* Returns the provider result — never the raw OAuth token. Requires an
|
|
@@ -35,24 +35,13 @@ export class ConnectionsClient {
|
|
|
35
35
|
operatorKey;
|
|
36
36
|
agentId;
|
|
37
37
|
baseUrl;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* @param laneId the wake's lane (a chat id, or `agrn-<agreementId>`), sent as
|
|
41
|
-
* X-Ziggs-Lane. It tells the broker which hire this wake is in, and the
|
|
42
|
-
* broker reads off it WHO the agent is acting for: an agent that serves
|
|
43
|
-
* several hirers holds all of their grants at once and is the holder of
|
|
44
|
-
* every one, so without a lane one hirer's grant is indistinguishable from
|
|
45
|
-
* another's, and a grant one customer gave can be spent while working for
|
|
46
|
-
* somebody else.
|
|
47
|
-
* ArtifactsClient sends the same header for the same reason.
|
|
48
|
-
*/
|
|
49
|
-
constructor(operatorKey, agentId, baseUrl, laneId) {
|
|
38
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
39
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
50
40
|
if (!operatorKey)
|
|
51
41
|
throw new Error("ConnectionsClient: operatorKey is required");
|
|
52
42
|
this.operatorKey = operatorKey;
|
|
53
43
|
this.agentId = agentId;
|
|
54
44
|
this.baseUrl = baseUrl || getBackendUrl();
|
|
55
|
-
this.laneId = laneId;
|
|
56
45
|
}
|
|
57
46
|
/**
|
|
58
47
|
* Present a ConnectionGrant to the broker and perform a provider action.
|
|
@@ -104,7 +93,7 @@ export class ConnectionsClient {
|
|
|
104
93
|
* defensively for leaked secrets, as `proxy` does.
|
|
105
94
|
*/
|
|
106
95
|
async listForHolder() {
|
|
107
|
-
const grantsClient = new GrantsClient(this.operatorKey, this.agentId, this.baseUrl
|
|
96
|
+
const grantsClient = new GrantsClient(this.operatorKey, this.agentId, this.baseUrl);
|
|
108
97
|
// All pages of the agent's live connection grants (not just the first page).
|
|
109
98
|
const { items, unreadableRails } = await grantsClient.listAllGrantsWithRails({
|
|
110
99
|
scopeKind: "connection",
|
|
@@ -188,7 +177,7 @@ export class ConnectionsClient {
|
|
|
188
177
|
headers: buildOperatorHeaders(this.operatorKey, this.agentId, {
|
|
189
178
|
...(body !== undefined ? { "content-type": "application/json" } : {}),
|
|
190
179
|
...extraHeaders,
|
|
191
|
-
}
|
|
180
|
+
}),
|
|
192
181
|
};
|
|
193
182
|
if (body !== undefined)
|
|
194
183
|
init.body = JSON.stringify(body);
|
|
@@ -111,6 +111,7 @@ export declare class ContextGrantsClient {
|
|
|
111
111
|
recipientId?: string;
|
|
112
112
|
/** Artifact only: who should read it, if not only the caller. One grant each. */
|
|
113
113
|
holders?: AccessReader[];
|
|
114
|
+
contributionTo?: import('@ziggs-ai/contracts').ContributionTarget;
|
|
114
115
|
}, opts?: {
|
|
115
116
|
idempotencyKey?: string;
|
|
116
117
|
laneId?: string;
|
|
@@ -70,7 +70,7 @@ export class ContextGrantsClient {
|
|
|
70
70
|
headers: buildOperatorHeaders(this.operatorKey, this.agentId, {
|
|
71
71
|
'content-type': 'application/json',
|
|
72
72
|
...(opts?.idempotencyKey ? { 'Idempotency-Key': opts.idempotencyKey } : {}),
|
|
73
|
-
}
|
|
73
|
+
}),
|
|
74
74
|
body: JSON.stringify(input),
|
|
75
75
|
});
|
|
76
76
|
const body = await res.text().catch(() => '');
|
|
@@ -67,7 +67,7 @@ export interface ContextOpenResult {
|
|
|
67
67
|
ref: ContextOpenRef;
|
|
68
68
|
access: ContextOpenAccess;
|
|
69
69
|
workContext: {
|
|
70
|
-
|
|
70
|
+
executionContextId: string | null;
|
|
71
71
|
};
|
|
72
72
|
page?: {
|
|
73
73
|
type: string;
|
|
@@ -90,8 +90,7 @@ export declare class ContextOpenClient {
|
|
|
90
90
|
private readonly operatorKey;
|
|
91
91
|
private readonly agentId?;
|
|
92
92
|
private readonly baseUrl?;
|
|
93
|
-
|
|
94
|
-
constructor(operatorKey: string, agentId?: string | undefined, baseUrl?: string | undefined, laneId?: string | undefined);
|
|
93
|
+
constructor(operatorKey: string, agentId?: string | undefined, baseUrl?: string | undefined);
|
|
95
94
|
open(body: ContextOpenBody): Promise<ContextOpenResult>;
|
|
96
95
|
explain(body: ContextOpenBody): Promise<ContextExplainResult>;
|
|
97
96
|
private post;
|
|
@@ -16,12 +16,10 @@ export class ContextOpenClient {
|
|
|
16
16
|
operatorKey;
|
|
17
17
|
agentId;
|
|
18
18
|
baseUrl;
|
|
19
|
-
|
|
20
|
-
constructor(operatorKey, agentId, baseUrl, laneId) {
|
|
19
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
21
20
|
this.operatorKey = operatorKey;
|
|
22
21
|
this.agentId = agentId;
|
|
23
22
|
this.baseUrl = baseUrl;
|
|
24
|
-
this.laneId = laneId;
|
|
25
23
|
if (!operatorKey)
|
|
26
24
|
throw new Error('ContextOpenClient: operatorKey is required');
|
|
27
25
|
}
|
|
@@ -37,7 +35,7 @@ export class ContextOpenClient {
|
|
|
37
35
|
const res = await fetch(url, {
|
|
38
36
|
method: 'POST',
|
|
39
37
|
headers: {
|
|
40
|
-
...buildOperatorHeaders(this.operatorKey, this.agentId, { 'Content-Type': 'application/json' }
|
|
38
|
+
...buildOperatorHeaders(this.operatorKey, this.agentId, { 'Content-Type': 'application/json' }),
|
|
41
39
|
},
|
|
42
40
|
body: JSON.stringify(normalized),
|
|
43
41
|
});
|
|
@@ -58,7 +58,9 @@ export interface ContextSnapshotParticipant {
|
|
|
58
58
|
}
|
|
59
59
|
export interface ContextSnapshotResult {
|
|
60
60
|
/** Server-resolved orientation; writes recheck authority. */
|
|
61
|
-
workBrief?: Record<string, unknown
|
|
61
|
+
workBrief?: Record<string, unknown> & {
|
|
62
|
+
position?: import('@ziggs-ai/contracts').WorkPositionView;
|
|
63
|
+
};
|
|
62
64
|
work?: Record<string, unknown>;
|
|
63
65
|
history: unknown[];
|
|
64
66
|
agreements: unknown[];
|
|
@@ -95,18 +97,8 @@ export declare class ContextReadClient {
|
|
|
95
97
|
private readonly operatorKey;
|
|
96
98
|
private readonly agentId?;
|
|
97
99
|
private readonly baseUrl;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
101
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
102
|
-
* @param laneId the wake's lane, sent as X-Ziggs-Lane. The server fences a
|
|
103
|
-
* read to the lane's parties; without it, reach falls back to a wider
|
|
104
|
-
* test and a read can be authorised on a weaker basis than the caller
|
|
105
|
-
* intended. Send it on every read made while acting on a wake.
|
|
106
|
-
*/
|
|
107
|
-
constructor(operatorKey: string, agentId?: string, baseUrl?: string, laneId?: string);
|
|
108
|
-
/** The same reader acting on one wake's lane. */
|
|
109
|
-
withLane(laneId: string | undefined): ContextReadClient;
|
|
100
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
101
|
+
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
110
102
|
read<T = unknown>(type: ContextReadType, query: ContextReadQuery): Promise<ContextReadEnvelope<T>>;
|
|
111
103
|
/**
|
|
112
104
|
* Aggregated chat snapshot — `GET /context/snapshot?via=chat:<id>`. The
|
|
@@ -57,28 +57,13 @@ export class ContextReadClient {
|
|
|
57
57
|
operatorKey;
|
|
58
58
|
agentId;
|
|
59
59
|
baseUrl;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
63
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
64
|
-
* @param laneId the wake's lane, sent as X-Ziggs-Lane. The server fences a
|
|
65
|
-
* read to the lane's parties; without it, reach falls back to a wider
|
|
66
|
-
* test and a read can be authorised on a weaker basis than the caller
|
|
67
|
-
* intended. Send it on every read made while acting on a wake.
|
|
68
|
-
*/
|
|
69
|
-
constructor(operatorKey, agentId, baseUrl, laneId) {
|
|
60
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
61
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
70
62
|
if (!operatorKey)
|
|
71
63
|
throw new Error('ContextReadClient: operatorKey is required');
|
|
72
64
|
this.operatorKey = operatorKey;
|
|
73
65
|
this.agentId = agentId;
|
|
74
66
|
this.baseUrl = baseUrl || getBackendUrl();
|
|
75
|
-
this.laneId = laneId;
|
|
76
|
-
}
|
|
77
|
-
/** The same reader acting on one wake's lane. */
|
|
78
|
-
withLane(laneId) {
|
|
79
|
-
if (!laneId || laneId === this.laneId)
|
|
80
|
-
return this;
|
|
81
|
-
return new ContextReadClient(this.operatorKey, this.agentId, this.baseUrl, laneId);
|
|
82
67
|
}
|
|
83
68
|
async read(type, query) {
|
|
84
69
|
if (!query.via?.trim()) {
|
|
@@ -101,7 +86,7 @@ export class ContextReadClient {
|
|
|
101
86
|
if (query.contextGrantId) {
|
|
102
87
|
url.searchParams.set('contextGrantId', query.contextGrantId);
|
|
103
88
|
}
|
|
104
|
-
const headers = buildOperatorHeaders(this.operatorKey, this.agentId, undefined
|
|
89
|
+
const headers = buildOperatorHeaders(this.operatorKey, this.agentId, undefined);
|
|
105
90
|
if (query.contextGrantId) {
|
|
106
91
|
headers['X-Context-Grant-Id'] = query.contextGrantId;
|
|
107
92
|
}
|
|
@@ -138,7 +123,7 @@ export class ContextReadClient {
|
|
|
138
123
|
if (opts.contextGrantId) {
|
|
139
124
|
url.searchParams.set('contextGrantId', opts.contextGrantId);
|
|
140
125
|
}
|
|
141
|
-
const headers = buildOperatorHeaders(this.operatorKey, this.agentId, undefined
|
|
126
|
+
const headers = buildOperatorHeaders(this.operatorKey, this.agentId, undefined);
|
|
142
127
|
if (opts.contextGrantId) {
|
|
143
128
|
headers['X-Context-Grant-Id'] = opts.contextGrantId;
|
|
144
129
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { WorkExecutionContext } from '@ziggs-ai/contracts';
|
|
2
|
+
/** Fail closed before resuming model state, including timers and recorded wakes. */
|
|
3
|
+
export declare function validateWorkExecution(context: WorkExecutionContext, operatorKey: string, baseUrl?: string): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
2
|
+
import { buildOperatorHeaders, withWorkExecution } from './operatorHeaders.js';
|
|
3
|
+
import { throwApiError } from '../shared/apiError.js';
|
|
4
|
+
/** Fail closed before resuming model state, including timers and recorded wakes. */
|
|
5
|
+
export async function validateWorkExecution(context, operatorKey, baseUrl = getBackendUrl()) {
|
|
6
|
+
await withWorkExecution(context, async () => {
|
|
7
|
+
const response = await fetch(`${baseUrl}/execution/context`, {
|
|
8
|
+
headers: buildOperatorHeaders(operatorKey, context.actorId),
|
|
9
|
+
});
|
|
10
|
+
const text = await response.text();
|
|
11
|
+
if (!response.ok)
|
|
12
|
+
throwApiError(response, text, 'Execution context is no longer valid');
|
|
13
|
+
const body = JSON.parse(text);
|
|
14
|
+
if (body.contextId !== context.contextId)
|
|
15
|
+
throw new Error('Execution preflight returned a different context');
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -56,16 +56,8 @@ export declare class GrantsClient {
|
|
|
56
56
|
private readonly operatorKey;
|
|
57
57
|
private readonly agentId?;
|
|
58
58
|
private readonly baseUrl;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* @param laneId the wake's lane (a chat id, or `agrn-<agreementId>`), sent as
|
|
62
|
-
* X-Ziggs-Lane. The server reads off it who the agent is acting for, and
|
|
63
|
-
* answers the spendable rails with only the grants this wake may spend —
|
|
64
|
-
* so an agent serving several customers is never handed a list it has to
|
|
65
|
-
* choose between. Without it the list is everything the agent holds, and
|
|
66
|
-
* the grant it picks may then be refused with nothing saying why.
|
|
67
|
-
*/
|
|
68
|
-
constructor(operatorKey: string, agentId?: string, baseUrl?: string, laneId?: string);
|
|
59
|
+
/** Authority is supplied by withWorkExecution / withWorkExecutionId. */
|
|
60
|
+
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
69
61
|
listGrants(query?: ListGrantsQuery): Promise<ListGrantsResult>;
|
|
70
62
|
/**
|
|
71
63
|
* Every grant matching `query`, following the cursor to completion. Use when a
|