@ziggs-ai/api-client 0.1.26 → 0.1.28
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/http/AgreementClient.d.ts +0 -2
- package/dist/http/AgreementClient.js +0 -27
- package/dist/http/ContextReadClient.d.ts +26 -0
- package/dist/http/ContextReadClient.js +35 -0
- package/dist/http/TaskClient.js +7 -1
- package/dist/http/index.d.ts +1 -3
- package/dist/http/index.js +0 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/relay/provisionRelayWorkers.d.ts +53 -0
- package/dist/relay/provisionRelayWorkers.js +147 -0
- package/dist/types.d.ts +8 -0
- package/dist/websocket/WebSocketClient.js +6 -1
- package/package.json +1 -1
- package/dist/http/ScopeClient.d.ts +0 -37
- package/dist/http/ScopeClient.js +0 -40
|
@@ -170,7 +170,6 @@ export declare function claimAgreement(agreementId: string, creds: Creds): Promi
|
|
|
170
170
|
ok: boolean;
|
|
171
171
|
agreement: Agreement;
|
|
172
172
|
}>;
|
|
173
|
-
export declare function getAgreementsByChat(chatId: string, creds: Creds): Promise<unknown[]>;
|
|
174
173
|
export type ChatLinkType = 'origin' | 'mention' | 'delegation' | 'join';
|
|
175
174
|
export declare function linkAgreementToChat(agreementId: string, chatId: string, linkType: ChatLinkType | undefined, creds: Creds): Promise<unknown | null>;
|
|
176
175
|
export declare function getChatsForAgreement(agreementId: string, creds: Creds): Promise<unknown[]>;
|
|
@@ -219,7 +218,6 @@ export declare class AgreementClient {
|
|
|
219
218
|
ok: boolean;
|
|
220
219
|
agreement: Agreement;
|
|
221
220
|
}>;
|
|
222
|
-
listByChat(chatId: string): Promise<unknown[]>;
|
|
223
221
|
linkToChat(id: string, chatId: string, linkType?: ChatLinkType): Promise<unknown>;
|
|
224
222
|
listChats(id: string): Promise<unknown[]>;
|
|
225
223
|
join(id: string): Promise<{
|
|
@@ -414,32 +414,6 @@ export async function claimAgreement(agreementId, creds) {
|
|
|
414
414
|
}
|
|
415
415
|
return data;
|
|
416
416
|
}
|
|
417
|
-
// ---------------------------------------------------------------------------
|
|
418
|
-
// Chat links
|
|
419
|
-
// ---------------------------------------------------------------------------
|
|
420
|
-
export async function getAgreementsByChat(chatId, creds) {
|
|
421
|
-
if (!chatId)
|
|
422
|
-
return [];
|
|
423
|
-
assertCreds(creds, 'get agreements by chat');
|
|
424
|
-
try {
|
|
425
|
-
const res = await fetch(`${getAgreementBaseUrl()}/by-chat/${encodeURIComponent(chatId)}`, {
|
|
426
|
-
method: 'GET',
|
|
427
|
-
headers: buildHeaders(creds),
|
|
428
|
-
});
|
|
429
|
-
if (!res.ok) {
|
|
430
|
-
const body = await res.text().catch(() => '');
|
|
431
|
-
runtimeLog.warn('AgreementClient', `⚠️ Get agreements by chat failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
432
|
-
return [];
|
|
433
|
-
}
|
|
434
|
-
const data = await res.json().catch(() => null);
|
|
435
|
-
const links = data?.['links'] ?? data?.['agreements'];
|
|
436
|
-
return Array.isArray(links) ? links : [];
|
|
437
|
-
}
|
|
438
|
-
catch (e) {
|
|
439
|
-
runtimeLog.warn('AgreementClient', `⚠️ Get agreements by chat failed: ${e.message}`);
|
|
440
|
-
return [];
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
417
|
export async function linkAgreementToChat(agreementId, chatId, linkType = 'mention', creds) {
|
|
444
418
|
if (!agreementId || !chatId)
|
|
445
419
|
return null;
|
|
@@ -618,7 +592,6 @@ export class AgreementClient {
|
|
|
618
592
|
revoke(id) { return revokeAgreement(id, this.creds); }
|
|
619
593
|
fulfill(id) { return fulfillAgreement(id, this.creds); }
|
|
620
594
|
claimAgreement(id) { return claimAgreement(id, this.creds); }
|
|
621
|
-
listByChat(chatId) { return getAgreementsByChat(chatId, this.creds); }
|
|
622
595
|
linkToChat(id, chatId, linkType) { return linkAgreementToChat(id, chatId, linkType ?? 'mention', this.creds); }
|
|
623
596
|
listChats(id) { return getChatsForAgreement(id, this.creds); }
|
|
624
597
|
join(id) { return joinAgreement(id, this.creds); }
|
|
@@ -20,6 +20,22 @@ export interface ContextReadEnvelope<T = unknown> {
|
|
|
20
20
|
nextCursor: string | null;
|
|
21
21
|
latestSequence?: string | null;
|
|
22
22
|
}
|
|
23
|
+
/** Aggregated chat snapshot from `GET /context/snapshot` (ZIG-775 follow-up). */
|
|
24
|
+
export interface ContextSnapshotResult {
|
|
25
|
+
history: unknown[];
|
|
26
|
+
agreements: unknown[];
|
|
27
|
+
agents: Array<{
|
|
28
|
+
agentId: string;
|
|
29
|
+
role: string;
|
|
30
|
+
isYou: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
users: Array<{
|
|
33
|
+
userId: string;
|
|
34
|
+
role: string;
|
|
35
|
+
}>;
|
|
36
|
+
latestSequence?: string | null;
|
|
37
|
+
chatMissing?: boolean;
|
|
38
|
+
}
|
|
23
39
|
/**
|
|
24
40
|
* Protocol-first uniform context reads (ZIG-427).
|
|
25
41
|
* Wraps `GET /context/read/:type` — one client, one envelope, four types.
|
|
@@ -34,4 +50,14 @@ export declare class ContextReadClient {
|
|
|
34
50
|
*/
|
|
35
51
|
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
36
52
|
read<T = unknown>(type: ContextReadType, query: ContextReadQuery): Promise<ContextReadEnvelope<T>>;
|
|
53
|
+
/**
|
|
54
|
+
* Aggregated chat snapshot — `GET /context/snapshot?via=chat:<id>`. The
|
|
55
|
+
* server composes history + agreements + roster through the same grant-fenced
|
|
56
|
+
* readers as {@link read}, so hosted agents pull one fenced view per wake.
|
|
57
|
+
* Rejects with an `Error & { status }` on non-OK so callers can branch (404).
|
|
58
|
+
*/
|
|
59
|
+
snapshot(chatId: string, opts?: {
|
|
60
|
+
maxMessages?: number;
|
|
61
|
+
contextGrantId?: string;
|
|
62
|
+
}): Promise<ContextSnapshotResult>;
|
|
37
63
|
}
|
|
@@ -53,4 +53,39 @@ export class ContextReadClient {
|
|
|
53
53
|
}
|
|
54
54
|
return JSON.parse(body);
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Aggregated chat snapshot — `GET /context/snapshot?via=chat:<id>`. The
|
|
58
|
+
* server composes history + agreements + roster through the same grant-fenced
|
|
59
|
+
* readers as {@link read}, so hosted agents pull one fenced view per wake.
|
|
60
|
+
* Rejects with an `Error & { status }` on non-OK so callers can branch (404).
|
|
61
|
+
*/
|
|
62
|
+
async snapshot(chatId, opts = {}) {
|
|
63
|
+
if (!chatId?.trim()) {
|
|
64
|
+
throw new Error('ContextReadClient.snapshot: chatId is required');
|
|
65
|
+
}
|
|
66
|
+
const url = new URL(`${this.baseUrl}/context/snapshot`);
|
|
67
|
+
url.searchParams.set('via', `chat:${chatId}`);
|
|
68
|
+
if (opts.maxMessages != null) {
|
|
69
|
+
url.searchParams.set('maxMessages', String(opts.maxMessages));
|
|
70
|
+
}
|
|
71
|
+
if (opts.contextGrantId) {
|
|
72
|
+
url.searchParams.set('contextGrantId', opts.contextGrantId);
|
|
73
|
+
}
|
|
74
|
+
const headers = {
|
|
75
|
+
Authorization: `Bearer ${this.operatorKey}`,
|
|
76
|
+
};
|
|
77
|
+
if (this.agentId)
|
|
78
|
+
headers['X-Agent-Id'] = this.agentId;
|
|
79
|
+
if (opts.contextGrantId) {
|
|
80
|
+
headers['X-Context-Grant-Id'] = opts.contextGrantId;
|
|
81
|
+
}
|
|
82
|
+
const res = await fetch(url.toString(), { headers });
|
|
83
|
+
const body = await res.text().catch(() => '');
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
const err = new Error(`ContextReadClient.snapshot ${res.status} ${body.slice(0, 200)}`);
|
|
86
|
+
err.status = res.status;
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
return JSON.parse(body);
|
|
90
|
+
}
|
|
56
91
|
}
|
package/dist/http/TaskClient.js
CHANGED
|
@@ -20,7 +20,13 @@ function parseErrorMessage(responseBody, defaultMessage) {
|
|
|
20
20
|
return defaultMessage;
|
|
21
21
|
try {
|
|
22
22
|
const d = JSON.parse(responseBody);
|
|
23
|
-
|
|
23
|
+
// NestJS ValidationPipe returns { message: string[] | string, error: 'Bad
|
|
24
|
+
// Request', statusCode }. Prefer the detailed `message` over the generic
|
|
25
|
+
// `error` so the real cause (which field failed validation) is surfaced
|
|
26
|
+
// instead of a bare "Bad Request". (ZIG-832)
|
|
27
|
+
const msg = d['message'];
|
|
28
|
+
const detailed = Array.isArray(msg) ? msg.join('; ') : (typeof msg === 'string' ? msg : undefined);
|
|
29
|
+
return d['details'] || detailed || d['error'] || defaultMessage;
|
|
24
30
|
}
|
|
25
31
|
catch {
|
|
26
32
|
return responseBody || defaultMessage;
|
package/dist/http/index.d.ts
CHANGED
|
@@ -6,10 +6,8 @@ export { MessagesClient } from './MessagesClient.js';
|
|
|
6
6
|
export type { ListMessagesOptions, ListMessagesResult } from './MessagesClient.js';
|
|
7
7
|
export { ArtifactsClient } from './ArtifactsClient.js';
|
|
8
8
|
export type { ArtifactVisibility, ListArtifactsOptions, ListArtifactsQuery, ListArtifactsResult, WriteArtifactInput, } from './ArtifactsClient.js';
|
|
9
|
-
export { ScopeClient } from './ScopeClient.js';
|
|
10
|
-
export type { ScopeKind, ScopeResult, PartyRef } from './ScopeClient.js';
|
|
11
9
|
export { ContextReadClient } from './ContextReadClient.js';
|
|
12
|
-
export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, } from './ContextReadClient.js';
|
|
10
|
+
export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, ContextSnapshotResult, } from './ContextReadClient.js';
|
|
13
11
|
export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
14
12
|
export type { ContextReachDescriptor } from './ContextDiscoveryClient.js';
|
|
15
13
|
export { ContextGrantsClient } from './ContextGrantsClient.js';
|
package/dist/http/index.js
CHANGED
|
@@ -4,7 +4,6 @@ export * from './MarketplaceClient.js';
|
|
|
4
4
|
export * from './ChatClient.js';
|
|
5
5
|
export { MessagesClient } from './MessagesClient.js';
|
|
6
6
|
export { ArtifactsClient } from './ArtifactsClient.js';
|
|
7
|
-
export { ScopeClient } from './ScopeClient.js';
|
|
8
7
|
export { ContextReadClient } from './ContextReadClient.js';
|
|
9
8
|
export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
10
9
|
export { ContextGrantsClient } from './ContextGrantsClient.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './http/index.js';
|
|
2
|
+
export * from './relay/provisionRelayWorkers.js';
|
|
2
3
|
export { WebSocketClient } from './websocket/index.js';
|
|
3
4
|
export { createControlSocket } from './websocket/ControlSocket.js';
|
|
4
5
|
export { ConnectionManager } from './ConnectionManager.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './http/index.js';
|
|
2
|
+
export * from './relay/provisionRelayWorkers.js';
|
|
2
3
|
export { WebSocketClient } from './websocket/index.js';
|
|
3
4
|
export { createControlSocket } from './websocket/ControlSocket.js';
|
|
4
5
|
export { ConnectionManager } from './ConnectionManager.js';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Agreement, Creds } from '../types.js';
|
|
2
|
+
import { claimOffer, delegateAgreement, getMyAgreements, pullOffers } from '../http/index.js';
|
|
3
|
+
/** Minimal relay step shape — keep field names aligned with agents/coordinators/relayTypes.ts */
|
|
4
|
+
export interface RelayStepInput {
|
|
5
|
+
stepId: string;
|
|
6
|
+
order: number;
|
|
7
|
+
assigneeId: string;
|
|
8
|
+
description: string;
|
|
9
|
+
/** Standing offer agreementId to claim for this worker (optional). */
|
|
10
|
+
offerAgreementId?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RelayPayloadShape {
|
|
13
|
+
inputArtifactIds?: string[];
|
|
14
|
+
steps: Array<{
|
|
15
|
+
stepId: string;
|
|
16
|
+
order: number;
|
|
17
|
+
agreementId: string;
|
|
18
|
+
assigneeId: string;
|
|
19
|
+
description: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
export type ProvisionMethod = 'existing' | 'claim' | 'delegate';
|
|
23
|
+
export type StepProvisionStatus = 'active' | 'pending_approval';
|
|
24
|
+
export type ProvisionedRelayStep = RelayPayloadShape['steps'][number] & {
|
|
25
|
+
provisionMethod: ProvisionMethod;
|
|
26
|
+
status: StepProvisionStatus;
|
|
27
|
+
};
|
|
28
|
+
export interface RelayProvisionDeps {
|
|
29
|
+
getMyAgreements: typeof getMyAgreements;
|
|
30
|
+
pullOffers: typeof pullOffers;
|
|
31
|
+
claimOffer: typeof claimOffer;
|
|
32
|
+
delegateAgreement: typeof delegateAgreement;
|
|
33
|
+
}
|
|
34
|
+
export interface ProvisionRelayWorkersInput {
|
|
35
|
+
creds: Creds;
|
|
36
|
+
hireAgreementId: string;
|
|
37
|
+
chatId?: string;
|
|
38
|
+
steps: RelayStepInput[];
|
|
39
|
+
inputArtifactIds?: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface ProvisionRelayWorkersResult {
|
|
42
|
+
payload: RelayPayloadShape;
|
|
43
|
+
steps: ProvisionedRelayStep[];
|
|
44
|
+
pendingApprovals: string[];
|
|
45
|
+
readyForKickoff: boolean;
|
|
46
|
+
}
|
|
47
|
+
type AgreementWithParent = Agreement & {
|
|
48
|
+
parentAgreementId?: string;
|
|
49
|
+
};
|
|
50
|
+
export declare function findExistingWorkerDelegation(hireAgreementId: string, assigneeId: string, agreements: AgreementWithParent[]): AgreementWithParent | null;
|
|
51
|
+
export declare function findOpenOfferForAgent(assigneeId: string, offers: Agreement[]): Agreement | null;
|
|
52
|
+
export declare function provisionRelayWorkers(input: ProvisionRelayWorkersInput, deps?: RelayProvisionDeps): Promise<ProvisionRelayWorkersResult>;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { claimOffer, delegateAgreement, getMyAgreements, pullOffers, } from '../http/index.js';
|
|
2
|
+
function providerAgentId(agreement) {
|
|
3
|
+
return agreement.parties?.providerAgent ?? agreement.parties?.provider ?? null;
|
|
4
|
+
}
|
|
5
|
+
function isActiveAgreement(agreement) {
|
|
6
|
+
return agreement.status === 'active';
|
|
7
|
+
}
|
|
8
|
+
export function findExistingWorkerDelegation(hireAgreementId, assigneeId, agreements) {
|
|
9
|
+
const matches = agreements.filter((a) => {
|
|
10
|
+
if (a.parentAgreementId !== hireAgreementId)
|
|
11
|
+
return false;
|
|
12
|
+
if (!isActiveAgreement(a))
|
|
13
|
+
return false;
|
|
14
|
+
return providerAgentId(a) === assigneeId;
|
|
15
|
+
});
|
|
16
|
+
matches.sort((a, b) => {
|
|
17
|
+
const ta = a.updatedAt ?? a.createdAt ?? '';
|
|
18
|
+
const tb = b.updatedAt ?? b.createdAt ?? '';
|
|
19
|
+
return tb.localeCompare(ta);
|
|
20
|
+
});
|
|
21
|
+
return matches[0] ?? null;
|
|
22
|
+
}
|
|
23
|
+
export function findOpenOfferForAgent(assigneeId, offers) {
|
|
24
|
+
return (offers.find((o) => {
|
|
25
|
+
if (o.status !== 'open' && o.status !== 'active')
|
|
26
|
+
return false;
|
|
27
|
+
return providerAgentId(o) === assigneeId;
|
|
28
|
+
}) ?? null);
|
|
29
|
+
}
|
|
30
|
+
export async function provisionRelayWorkers(input, deps = {
|
|
31
|
+
getMyAgreements,
|
|
32
|
+
pullOffers,
|
|
33
|
+
claimOffer,
|
|
34
|
+
delegateAgreement,
|
|
35
|
+
}) {
|
|
36
|
+
const { creds, hireAgreementId, chatId, steps, inputArtifactIds } = input;
|
|
37
|
+
if (!steps.length)
|
|
38
|
+
throw new Error('steps must not be empty');
|
|
39
|
+
const myAgreements = (await deps.getMyAgreements({}, creds));
|
|
40
|
+
let offersCache = null;
|
|
41
|
+
const provisioned = [];
|
|
42
|
+
const pendingApprovals = [];
|
|
43
|
+
for (const step of steps) {
|
|
44
|
+
const existing = findExistingWorkerDelegation(hireAgreementId, step.assigneeId, myAgreements);
|
|
45
|
+
if (existing?.agreementId) {
|
|
46
|
+
provisioned.push({
|
|
47
|
+
stepId: step.stepId,
|
|
48
|
+
order: step.order,
|
|
49
|
+
agreementId: existing.agreementId,
|
|
50
|
+
assigneeId: step.assigneeId,
|
|
51
|
+
description: step.description,
|
|
52
|
+
provisionMethod: 'existing',
|
|
53
|
+
status: 'active',
|
|
54
|
+
});
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (step.offerAgreementId) {
|
|
58
|
+
const claimed = await deps.claimOffer(step.offerAgreementId, creds);
|
|
59
|
+
const agreementId = claimed.agreementId;
|
|
60
|
+
const status = isActiveAgreement(claimed)
|
|
61
|
+
? 'active'
|
|
62
|
+
: 'pending_approval';
|
|
63
|
+
if (status === 'pending_approval')
|
|
64
|
+
pendingApprovals.push(agreementId);
|
|
65
|
+
provisioned.push({
|
|
66
|
+
stepId: step.stepId,
|
|
67
|
+
order: step.order,
|
|
68
|
+
agreementId,
|
|
69
|
+
assigneeId: step.assigneeId,
|
|
70
|
+
description: step.description,
|
|
71
|
+
provisionMethod: 'claim',
|
|
72
|
+
status,
|
|
73
|
+
});
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (!offersCache) {
|
|
77
|
+
offersCache = await deps.pullOffers({ limit: 100 }, creds);
|
|
78
|
+
}
|
|
79
|
+
const openOffer = findOpenOfferForAgent(step.assigneeId, offersCache);
|
|
80
|
+
if (openOffer?.agreementId) {
|
|
81
|
+
const claimed = await deps.claimOffer(openOffer.agreementId, creds);
|
|
82
|
+
const agreementId = claimed.agreementId;
|
|
83
|
+
const status = isActiveAgreement(claimed)
|
|
84
|
+
? 'active'
|
|
85
|
+
: 'pending_approval';
|
|
86
|
+
if (status === 'pending_approval')
|
|
87
|
+
pendingApprovals.push(agreementId);
|
|
88
|
+
provisioned.push({
|
|
89
|
+
stepId: step.stepId,
|
|
90
|
+
order: step.order,
|
|
91
|
+
agreementId,
|
|
92
|
+
assigneeId: step.assigneeId,
|
|
93
|
+
description: step.description,
|
|
94
|
+
provisionMethod: 'claim',
|
|
95
|
+
status,
|
|
96
|
+
});
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (!chatId?.trim()) {
|
|
100
|
+
throw new Error(`No standing offer found for ${step.assigneeId} and chatId is required to propose a delegation under the hire`);
|
|
101
|
+
}
|
|
102
|
+
const delegated = await deps.delegateAgreement({
|
|
103
|
+
description: step.description,
|
|
104
|
+
executorId: step.assigneeId,
|
|
105
|
+
chatId: chatId.trim(),
|
|
106
|
+
parentAgreementId: hireAgreementId,
|
|
107
|
+
agreementDescription: `Relay step ${step.stepId}: ${step.description}`,
|
|
108
|
+
lifecycle: 'count-bound',
|
|
109
|
+
maxExecutions: 50,
|
|
110
|
+
price: 0,
|
|
111
|
+
}, creds);
|
|
112
|
+
const agreementId = delegated.agreementId;
|
|
113
|
+
const status = isActiveAgreement(delegated)
|
|
114
|
+
? 'active'
|
|
115
|
+
: 'pending_approval';
|
|
116
|
+
if (status === 'pending_approval')
|
|
117
|
+
pendingApprovals.push(agreementId);
|
|
118
|
+
provisioned.push({
|
|
119
|
+
stepId: step.stepId,
|
|
120
|
+
order: step.order,
|
|
121
|
+
agreementId,
|
|
122
|
+
assigneeId: step.assigneeId,
|
|
123
|
+
description: step.description,
|
|
124
|
+
provisionMethod: 'delegate',
|
|
125
|
+
status,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
provisioned.sort((a, b) => a.order - b.order);
|
|
129
|
+
const payload = {
|
|
130
|
+
inputArtifactIds,
|
|
131
|
+
steps: provisioned.map(({ stepId, order, agreementId, assigneeId, description }) => ({
|
|
132
|
+
stepId,
|
|
133
|
+
order,
|
|
134
|
+
agreementId,
|
|
135
|
+
assigneeId,
|
|
136
|
+
description,
|
|
137
|
+
})),
|
|
138
|
+
};
|
|
139
|
+
const readyForKickoff = pendingApprovals.length === 0 &&
|
|
140
|
+
provisioned.every((s) => s.status === 'active');
|
|
141
|
+
return {
|
|
142
|
+
payload,
|
|
143
|
+
steps: provisioned,
|
|
144
|
+
pendingApprovals,
|
|
145
|
+
readyForKickoff,
|
|
146
|
+
};
|
|
147
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -173,5 +173,13 @@ export interface MessageMetadata {
|
|
|
173
173
|
agreement?: Record<string, unknown> | null;
|
|
174
174
|
operation?: string | null;
|
|
175
175
|
agreementId?: string | null;
|
|
176
|
+
/**
|
|
177
|
+
* Message send time from the wire payload (ZIG-860). The live-path inbox
|
|
178
|
+
* watermark ack (AgentHost, ZIG-832 P4) needs it — without a timestamp the
|
|
179
|
+
* ack never fires and catch-up re-delivers the chat's whole backlog after a
|
|
180
|
+
* host eviction, re-running already-answered goals.
|
|
181
|
+
*/
|
|
182
|
+
timestamp?: string;
|
|
183
|
+
sentTimestamp?: string;
|
|
176
184
|
}
|
|
177
185
|
export type MessageHandler = (text: string, metadata: MessageMetadata) => Promise<void>;
|
|
@@ -191,7 +191,7 @@ export class WebSocketClient {
|
|
|
191
191
|
const agreement = p['agreement'] ?? null;
|
|
192
192
|
const operation = p['operation'] ?? null;
|
|
193
193
|
const agreementId = p['agreementId'] ?? null;
|
|
194
|
-
runtimeLog.info(this.label, `[wire-debug] incoming chatId=${chatId} sender=${senderId} content_type=${p['content_type'] ?? p['contentType'] ?? '<none>'} entryType=${p['entryType'] ?? '<none>'} task?=${task ? `taskId=${task['taskId']} state=${task['state']}` : 'no'} agreement?=${agreement ? `agreementId=${agreement['agreementId']} status=${agreement['status']}` : 'no'} operation?=${operation ?? 'no'}`);
|
|
194
|
+
runtimeLog.info(this.label, `[wire-debug] incoming chatId=${chatId} sender=${senderId} content_type=${p['content_type'] ?? p['contentType'] ?? '<none>'} entryType=${p['entryType'] ?? '<none>'} ts=${typeof p['timestamp']}/${typeof p['sentTimestamp']} keys=${Object.keys(p).join(',')} task?=${task ? `taskId=${task['taskId']} state=${task['state']}` : 'no'} agreement?=${agreement ? `agreementId=${agreement['agreementId']} status=${agreement['status']}` : 'no'} operation?=${operation ?? 'no'}`);
|
|
195
195
|
const metadata = {
|
|
196
196
|
chatId,
|
|
197
197
|
messageId: typeof p['messageId'] === 'string' ? p['messageId'] : undefined,
|
|
@@ -208,6 +208,11 @@ export class WebSocketClient {
|
|
|
208
208
|
agreement,
|
|
209
209
|
operation,
|
|
210
210
|
agreementId,
|
|
211
|
+
// ZIG-860: carry the send time through — the live-path watermark ack
|
|
212
|
+
// (AgentHost, ZIG-832 P4) reads it, and dropping it here meant the ack
|
|
213
|
+
// never fired for any live message.
|
|
214
|
+
timestamp: typeof p['timestamp'] === 'string' ? p['timestamp'] : undefined,
|
|
215
|
+
sentTimestamp: typeof p['sentTimestamp'] === 'string' ? p['sentTimestamp'] : undefined,
|
|
211
216
|
};
|
|
212
217
|
await this.messageHandler(p['text'], metadata);
|
|
213
218
|
}
|
package/package.json
CHANGED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
export type ScopeKind = 'chat' | 'agreement' | 'task' | 'counterparty';
|
|
3
|
-
export interface PartyRef {
|
|
4
|
-
id: string;
|
|
5
|
-
role: 'payer' | 'provider' | 'creator' | 'proposedTo' | 'providerPrincipal';
|
|
6
|
-
}
|
|
7
|
-
export interface ScopeResult {
|
|
8
|
-
via: {
|
|
9
|
-
kind: ScopeKind;
|
|
10
|
-
id: string;
|
|
11
|
-
};
|
|
12
|
-
agent: string;
|
|
13
|
-
accessible: {
|
|
14
|
-
chats: string[];
|
|
15
|
-
agreements: string[];
|
|
16
|
-
tasks: string[];
|
|
17
|
-
counterparties: PartyRef[];
|
|
18
|
-
};
|
|
19
|
-
permissions: string[];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Client for `GET /scope?via=<kind>:<id>`. Returns the access graph reachable
|
|
23
|
-
* from an entry point for the impersonated agent. Used by `runTurn` to
|
|
24
|
-
* bootstrap "what does my current session-key resolve to" before fanning out
|
|
25
|
-
* to primitive reads.
|
|
26
|
-
*/
|
|
27
|
-
export declare class ScopeClient {
|
|
28
|
-
private readonly operatorKey;
|
|
29
|
-
private readonly agentId?;
|
|
30
|
-
/**
|
|
31
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
32
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
33
|
-
*/
|
|
34
|
-
constructor(operatorKey: string, agentId?: string);
|
|
35
|
-
get(kind: ScopeKind, id: string): Promise<ScopeResult>;
|
|
36
|
-
private _headers;
|
|
37
|
-
}
|
package/dist/http/ScopeClient.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
|
-
import { buildOperatorHeaders } from './operatorHeaders.js';
|
|
4
|
-
/**
|
|
5
|
-
* Client for `GET /scope?via=<kind>:<id>`. Returns the access graph reachable
|
|
6
|
-
* from an entry point for the impersonated agent. Used by `runTurn` to
|
|
7
|
-
* bootstrap "what does my current session-key resolve to" before fanning out
|
|
8
|
-
* to primitive reads.
|
|
9
|
-
*/
|
|
10
|
-
export class ScopeClient {
|
|
11
|
-
operatorKey;
|
|
12
|
-
agentId;
|
|
13
|
-
/**
|
|
14
|
-
* @param operatorKey Agent-scoped or fleet operator key.
|
|
15
|
-
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
16
|
-
*/
|
|
17
|
-
constructor(operatorKey, agentId) {
|
|
18
|
-
if (!operatorKey)
|
|
19
|
-
throw new Error('ScopeClient: operatorKey is required');
|
|
20
|
-
this.operatorKey = operatorKey;
|
|
21
|
-
this.agentId = agentId;
|
|
22
|
-
}
|
|
23
|
-
async get(kind, id) {
|
|
24
|
-
if (!id)
|
|
25
|
-
throw new Error('ScopeClient.get: id is required');
|
|
26
|
-
const url = new URL(`${getBackendUrl()}/scope`);
|
|
27
|
-
url.searchParams.set('via', `${kind}:${id}`);
|
|
28
|
-
const res = await fetch(url.toString(), { headers: this._headers() });
|
|
29
|
-
if (!res.ok) {
|
|
30
|
-
const body = await res.text().catch(() => '');
|
|
31
|
-
throw new Error(`ScopeClient.get ${res.status} ${res.statusText} ${body.slice(0, 200)}`);
|
|
32
|
-
}
|
|
33
|
-
return (await res.json());
|
|
34
|
-
}
|
|
35
|
-
_headers() {
|
|
36
|
-
return buildOperatorHeaders(this.operatorKey, this.agentId, {
|
|
37
|
-
'content-type': 'application/json',
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|