@ziggs-ai/api-client 0.1.4 → 0.1.5
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/ConnectionManager.d.ts +1 -0
- package/dist/ConnectionManager.js +18 -4
- package/dist/http/AgreementClient.js +33 -13
- package/dist/http/ChatClient.d.ts +20 -0
- package/dist/http/ChatClient.js +39 -4
- package/dist/http/ContextDiscoveryClient.d.ts +23 -0
- package/dist/http/ContextDiscoveryClient.js +35 -0
- package/dist/http/ContextReadClient.d.ts +33 -0
- package/dist/http/ContextReadClient.js +54 -0
- package/dist/http/MessagesClient.d.ts +6 -2
- package/dist/http/MessagesClient.js +14 -6
- package/dist/http/TaskClient.js +12 -3
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.js +2 -0
- package/dist/types.d.ts +17 -7
- package/dist/types.js +1 -1
- package/dist/websocket/ControlSocket.js +2 -1
- package/dist/websocket/WebSocketClient.js +23 -7
- package/package.json +15 -9
- package/src/ConnectionManager.ts +172 -0
- package/src/http/AgentSearchClient.ts +115 -0
- package/src/http/AgreementClient.ts +721 -0
- package/src/http/ArtifactsClient.ts +133 -0
- package/src/http/ChatClient.ts +147 -0
- package/src/http/ContextDiscoveryClient.ts +52 -0
- package/src/http/ContextReadClient.ts +83 -0
- package/src/http/MarketplaceClient.ts +94 -0
- package/src/http/MessagesClient.ts +71 -0
- package/src/http/ScopeClient.ts +64 -0
- package/src/http/TaskClient.ts +450 -0
- package/src/http/TelemetryClient.ts +57 -0
- package/src/http/index.ts +26 -0
- package/src/index.ts +27 -0
- package/src/shared/runtimeLog.ts +68 -0
- package/src/types.ts +158 -0
- package/src/utils/urlUtils.ts +9 -0
- package/src/websocket/ControlSocket.ts +51 -0
- package/src/websocket/WebSocketClient.ts +315 -0
- package/src/websocket/index.ts +1 -0
|
@@ -25,6 +25,7 @@ export declare class ConnectionManager {
|
|
|
25
25
|
private _entries;
|
|
26
26
|
private _active;
|
|
27
27
|
private _meta;
|
|
28
|
+
private _waking;
|
|
28
29
|
constructor({ maxActive, idleTimeoutMs, control }?: ConnectionManagerOptions);
|
|
29
30
|
register(id: string, openFn: OpenFn, closeFn: CloseFn, meta?: ConnectionManagerMeta): void;
|
|
30
31
|
start(): void;
|
|
@@ -8,6 +8,7 @@ export class ConnectionManager {
|
|
|
8
8
|
_entries;
|
|
9
9
|
_active;
|
|
10
10
|
_meta;
|
|
11
|
+
_waking;
|
|
11
12
|
constructor({ maxActive = 50, idleTimeoutMs = 60_000, control } = {}) {
|
|
12
13
|
this.maxActive = maxActive;
|
|
13
14
|
this.idleTimeoutMs = idleTimeoutMs;
|
|
@@ -16,6 +17,7 @@ export class ConnectionManager {
|
|
|
16
17
|
this._entries = new Map();
|
|
17
18
|
this._active = new Map();
|
|
18
19
|
this._meta = new Map();
|
|
20
|
+
this._waking = new Map();
|
|
19
21
|
}
|
|
20
22
|
register(id, openFn, closeFn, meta) {
|
|
21
23
|
if (!id)
|
|
@@ -48,15 +50,27 @@ export class ConnectionManager {
|
|
|
48
50
|
this._resetTimer(id);
|
|
49
51
|
return existing.handle;
|
|
50
52
|
}
|
|
53
|
+
const pending = this._waking.get(id);
|
|
54
|
+
if (pending)
|
|
55
|
+
return pending;
|
|
51
56
|
const entry = this._entries.get(id);
|
|
52
57
|
if (!entry)
|
|
53
58
|
throw new Error(`[ConnectionManager] unknown id: "${id}"`);
|
|
54
59
|
if (this._active.size >= this.maxActive)
|
|
55
60
|
await this._evictLRU();
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
const wakePromise = (async () => {
|
|
62
|
+
try {
|
|
63
|
+
const handle = await entry.openFn();
|
|
64
|
+
this._active.set(id, { handle, timer: null, lastActive: Date.now() });
|
|
65
|
+
this._scheduleIdle(id);
|
|
66
|
+
return handle;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
this._waking.delete(id);
|
|
70
|
+
}
|
|
71
|
+
})();
|
|
72
|
+
this._waking.set(id, wakePromise);
|
|
73
|
+
return wakePromise;
|
|
60
74
|
}
|
|
61
75
|
async sleep(id) {
|
|
62
76
|
const entry = this._active.get(id);
|
|
@@ -44,7 +44,9 @@ export async function proposeAgreement(proposalData, creds) {
|
|
|
44
44
|
const headers = buildHeaders(creds);
|
|
45
45
|
if (idempotencyKey)
|
|
46
46
|
headers['Idempotency-Key'] = idempotencyKey;
|
|
47
|
-
|
|
47
|
+
// ZIG-207: canonical REST path. Backend keeps /propose serving the
|
|
48
|
+
// identical handler with a Deprecation/Sunset header until PR-F removes it.
|
|
49
|
+
const res = await fetch(`${getAgreementBaseUrl()}/proposals`, {
|
|
48
50
|
method: 'POST',
|
|
49
51
|
headers,
|
|
50
52
|
body: JSON.stringify(bodyData),
|
|
@@ -55,7 +57,7 @@ export async function proposeAgreement(proposalData, creds) {
|
|
|
55
57
|
}
|
|
56
58
|
const data = await res.json().catch(() => null);
|
|
57
59
|
if (!data?.['agreement']) {
|
|
58
|
-
throw new Error('Invalid response: expected { agreement } from /agreements/
|
|
60
|
+
throw new Error('Invalid response: expected { agreement } from POST /agreements/proposals');
|
|
59
61
|
}
|
|
60
62
|
return data['agreement'];
|
|
61
63
|
}
|
|
@@ -70,15 +72,26 @@ export async function proposeBroadcast(input, creds) {
|
|
|
70
72
|
export async function delegateAgreement(proposalData, creds) {
|
|
71
73
|
if (!proposalData)
|
|
72
74
|
throw new Error('Proposal data is required for delegation');
|
|
75
|
+
if (!proposalData.parentAgreementId)
|
|
76
|
+
throw new Error('parentAgreementId is required for delegation');
|
|
73
77
|
assertCreds(creds, 'proposal creation');
|
|
74
|
-
const { idempotencyKey,
|
|
78
|
+
const { idempotencyKey, parentAgreementId } = proposalData;
|
|
75
79
|
const headers = buildHeaders(creds);
|
|
76
80
|
if (idempotencyKey)
|
|
77
81
|
headers['Idempotency-Key'] = idempotencyKey;
|
|
78
|
-
|
|
82
|
+
// ZIG-207 / ZIG-270: parentAgreementId in path AND body. Backend's
|
|
83
|
+
// `DelegateTaskDto` validates `parentAgreementId` as a required string;
|
|
84
|
+
// controller (`POST /agreements/:parentAgreementId/delegations`) merges
|
|
85
|
+
// path over body, so duplicating the value is harmless. Stripping it
|
|
86
|
+
// from the body (as ZIG-207 #72 did) trips DTO validation and returns
|
|
87
|
+
// `400: parentAgreementId must be a string` → infinite retry loop in
|
|
88
|
+
// `agreement_subcontract`. Send both, let the path win.
|
|
89
|
+
const bodyWithParent = { ...proposalData };
|
|
90
|
+
delete bodyWithParent.idempotencyKey;
|
|
91
|
+
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(parentAgreementId)}/delegations`, {
|
|
79
92
|
method: 'POST',
|
|
80
93
|
headers,
|
|
81
|
-
body: JSON.stringify(
|
|
94
|
+
body: JSON.stringify(bodyWithParent),
|
|
82
95
|
});
|
|
83
96
|
if (!res.ok) {
|
|
84
97
|
const body = await res.text().catch(() => '');
|
|
@@ -86,7 +99,7 @@ export async function delegateAgreement(proposalData, creds) {
|
|
|
86
99
|
}
|
|
87
100
|
const data = await res.json().catch(() => null);
|
|
88
101
|
if (!data?.['agreement']) {
|
|
89
|
-
throw new Error('Invalid response: expected { agreement } from /agreements/
|
|
102
|
+
throw new Error('Invalid response: expected { agreement } from POST /agreements/:parentAgreementId/delegations');
|
|
90
103
|
}
|
|
91
104
|
return data['agreement'];
|
|
92
105
|
}
|
|
@@ -154,7 +167,8 @@ export async function getAgreementStatus(agreementId, creds) {
|
|
|
154
167
|
export async function listAgreements(filters = {}, creds) {
|
|
155
168
|
assertCreds(creds, 'list agreements');
|
|
156
169
|
try {
|
|
157
|
-
|
|
170
|
+
// Canonical query path: GET /agreements?scope=&status=&engagementKind=&...
|
|
171
|
+
const url = new URL(getAgreementBaseUrl());
|
|
158
172
|
if (filters.status)
|
|
159
173
|
url.searchParams.set('status', filters.status);
|
|
160
174
|
if (filters.engagementKind)
|
|
@@ -180,7 +194,10 @@ export async function listAgreements(filters = {}, creds) {
|
|
|
180
194
|
export async function getMyAgreements(filters = {}, creds) {
|
|
181
195
|
assertCreds(creds, 'get my agreements');
|
|
182
196
|
try {
|
|
183
|
-
|
|
197
|
+
// Canonical query path: GET /agreements?scope=mine returns the enriched
|
|
198
|
+
// shape (tasks + originChatId + isYou flags).
|
|
199
|
+
const url = new URL(getAgreementBaseUrl());
|
|
200
|
+
url.searchParams.set('scope', 'mine');
|
|
184
201
|
if (filters.engagementKind)
|
|
185
202
|
url.searchParams.set('engagementKind', filters.engagementKind);
|
|
186
203
|
if (filters.proposalStatus)
|
|
@@ -229,7 +246,8 @@ export async function createAgreement(body, creds) {
|
|
|
229
246
|
if (!body)
|
|
230
247
|
throw new Error('Body is required for agreement creation');
|
|
231
248
|
assertCreds(creds, 'agreement creation');
|
|
232
|
-
|
|
249
|
+
// Canonical REST create: POST /agreements.
|
|
250
|
+
const res = await fetch(getAgreementBaseUrl(), {
|
|
233
251
|
method: 'POST',
|
|
234
252
|
headers: buildHeaders(creds),
|
|
235
253
|
body: JSON.stringify(body),
|
|
@@ -240,7 +258,7 @@ export async function createAgreement(body, creds) {
|
|
|
240
258
|
}
|
|
241
259
|
const data = await res.json().catch(() => null);
|
|
242
260
|
if (!data?.['agreement']) {
|
|
243
|
-
throw new Error('Invalid response: expected { ok, agreement } from /agreements
|
|
261
|
+
throw new Error('Invalid response: expected { ok, agreement } from POST /agreements');
|
|
244
262
|
}
|
|
245
263
|
return data;
|
|
246
264
|
}
|
|
@@ -248,8 +266,10 @@ export async function revokeAgreement(agreementId, creds) {
|
|
|
248
266
|
if (!agreementId)
|
|
249
267
|
throw new Error('agreementId is required for revocation');
|
|
250
268
|
assertCreds(creds, 'agreement revocation');
|
|
251
|
-
|
|
252
|
-
|
|
269
|
+
// ZIG-207: canonical REST verb. Legacy POST /agreements/:id/revoke stays
|
|
270
|
+
// serving the identical handler (with Deprecation headers) until PR-F.
|
|
271
|
+
const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}`, {
|
|
272
|
+
method: 'DELETE',
|
|
253
273
|
headers: buildHeaders(creds),
|
|
254
274
|
});
|
|
255
275
|
if (!res.ok) {
|
|
@@ -258,7 +278,7 @@ export async function revokeAgreement(agreementId, creds) {
|
|
|
258
278
|
}
|
|
259
279
|
const data = await res.json().catch(() => null);
|
|
260
280
|
if (!data?.['agreement']) {
|
|
261
|
-
throw new Error('Invalid response: expected { ok, agreement } from /agreements/:id
|
|
281
|
+
throw new Error('Invalid response: expected { ok, agreement } from DELETE /agreements/:id');
|
|
262
282
|
}
|
|
263
283
|
return data;
|
|
264
284
|
}
|
|
@@ -11,4 +11,24 @@ export interface ChatSummary {
|
|
|
11
11
|
export declare function openConversation(participantId: string, creds: Creds): Promise<{
|
|
12
12
|
chatId: string;
|
|
13
13
|
}>;
|
|
14
|
+
export interface SendChatMessageInput {
|
|
15
|
+
chatId: string;
|
|
16
|
+
receiverId: string;
|
|
17
|
+
text: string;
|
|
18
|
+
messageId: string;
|
|
19
|
+
entryType?: string;
|
|
20
|
+
contentType?: string;
|
|
21
|
+
underAgreementId?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SendChatMessageResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
message: string;
|
|
26
|
+
messageId: string;
|
|
27
|
+
chatId: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* POST /chats/:chatId/messages as an impersonated delegate agent.
|
|
31
|
+
* Requires operator token + X-Agent-Id (ZIG-222).
|
|
32
|
+
*/
|
|
33
|
+
export declare function sendChatMessage(input: SendChatMessageInput, creds: Creds): Promise<SendChatMessageResult>;
|
|
14
34
|
export declare function listMyChats(creds: Creds): Promise<ChatSummary[]>;
|
package/dist/http/ChatClient.js
CHANGED
|
@@ -32,7 +32,8 @@ export async function openConversation(participantId, creds) {
|
|
|
32
32
|
if (!participantId)
|
|
33
33
|
throw new Error('participantId is required for openConversation');
|
|
34
34
|
assertCreds(creds, 'open conversation');
|
|
35
|
-
|
|
35
|
+
// Canonical REST: POST /chats with { participantId }, returns { chatId }.
|
|
36
|
+
const res = await fetch(`${getBackendUrl()}/chats`, {
|
|
36
37
|
method: 'POST',
|
|
37
38
|
headers: buildHeaders(creds),
|
|
38
39
|
body: JSON.stringify({ participantId }),
|
|
@@ -43,15 +44,49 @@ export async function openConversation(participantId, creds) {
|
|
|
43
44
|
}
|
|
44
45
|
const data = await res.json().catch(() => null);
|
|
45
46
|
if (!data?.['chatId'] || typeof data['chatId'] !== 'string') {
|
|
46
|
-
throw new Error('Invalid response: expected { chatId } from /
|
|
47
|
+
throw new Error('Invalid response: expected { chatId } from POST /chats');
|
|
47
48
|
}
|
|
48
49
|
return { chatId: data['chatId'] };
|
|
49
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* POST /chats/:chatId/messages as an impersonated delegate agent.
|
|
53
|
+
* Requires operator token + X-Agent-Id (ZIG-222).
|
|
54
|
+
*/
|
|
55
|
+
export async function sendChatMessage(input, creds) {
|
|
56
|
+
assertCreds(creds, 'send chat message');
|
|
57
|
+
const entryType = input.entryType ?? 'message';
|
|
58
|
+
const contentType = input.contentType ?? 'text';
|
|
59
|
+
const res = await fetch(`${getBackendUrl()}/chats/${encodeURIComponent(input.chatId)}/messages`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: buildHeaders(creds),
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
chatId: input.chatId,
|
|
64
|
+
messageId: input.messageId,
|
|
65
|
+
text: input.text,
|
|
66
|
+
entryType,
|
|
67
|
+
contentType,
|
|
68
|
+
receiver: input.receiverId,
|
|
69
|
+
underAgreementId: input.underAgreementId,
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
const body = await res.text().catch(() => '');
|
|
74
|
+
throwApiError(res, body, `sendChatMessage failed: ${res.status} ${res.statusText}`);
|
|
75
|
+
}
|
|
76
|
+
const data = (await res.json().catch(() => null));
|
|
77
|
+
return {
|
|
78
|
+
success: Boolean(data?.['success']),
|
|
79
|
+
message: String(data?.['message'] ?? 'ok'),
|
|
80
|
+
messageId: String(data?.['messageId'] ?? input.messageId),
|
|
81
|
+
chatId: String(data?.['chatId'] ?? input.chatId),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
50
84
|
export async function listMyChats(creds) {
|
|
51
85
|
assertCreds(creds, 'list my chats');
|
|
52
86
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
87
|
+
// Canonical REST: GET /chats/mine.
|
|
88
|
+
const res = await fetch(`${getBackendUrl()}/chats/mine`, {
|
|
89
|
+
method: 'GET',
|
|
55
90
|
headers: buildHeaders(creds),
|
|
56
91
|
});
|
|
57
92
|
if (!res.ok) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
export interface ContextReachDescriptor {
|
|
3
|
+
grantId: string;
|
|
4
|
+
scope: {
|
|
5
|
+
kind: 'chat' | 'agreement' | 'org';
|
|
6
|
+
id: string;
|
|
7
|
+
};
|
|
8
|
+
temporal: 'from-now' | 'from-start';
|
|
9
|
+
watermarkAt: string;
|
|
10
|
+
expiresAt: string | null;
|
|
11
|
+
parentGrantId: string | null;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* ZIG-412 discovery — scope descriptors only, no content.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ContextDiscoveryClient {
|
|
18
|
+
private readonly operatorKey;
|
|
19
|
+
private readonly agentId;
|
|
20
|
+
private readonly baseUrl;
|
|
21
|
+
constructor(operatorKey: string, agentId: string, baseUrl?: string);
|
|
22
|
+
discover(): Promise<ContextReachDescriptor[]>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
|
+
/**
|
|
4
|
+
* ZIG-412 discovery — scope descriptors only, no content.
|
|
5
|
+
*/
|
|
6
|
+
export class ContextDiscoveryClient {
|
|
7
|
+
operatorKey;
|
|
8
|
+
agentId;
|
|
9
|
+
baseUrl;
|
|
10
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
11
|
+
if (!operatorKey) {
|
|
12
|
+
throw new Error('ContextDiscoveryClient: operatorKey is required');
|
|
13
|
+
}
|
|
14
|
+
if (!agentId) {
|
|
15
|
+
throw new Error('ContextDiscoveryClient: agentId is required (operator-token impersonation)');
|
|
16
|
+
}
|
|
17
|
+
this.operatorKey = operatorKey;
|
|
18
|
+
this.agentId = agentId;
|
|
19
|
+
this.baseUrl = baseUrl || getBackendUrl();
|
|
20
|
+
}
|
|
21
|
+
async discover() {
|
|
22
|
+
const res = await fetch(`${this.baseUrl}/context/discovery`, {
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${this.operatorKey}`,
|
|
25
|
+
'X-Agent-Id': this.agentId,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const body = await res.text().catch(() => '');
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
throw new Error(`ContextDiscoveryClient.discover ${res.status} ${body.slice(0, 200)}`);
|
|
31
|
+
}
|
|
32
|
+
const parsed = JSON.parse(body);
|
|
33
|
+
return parsed.reach ?? [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
export type ContextReadType = 'messages' | 'artifacts' | 'agreements' | 'tasks';
|
|
3
|
+
export interface ContextReadQuery {
|
|
4
|
+
via: string;
|
|
5
|
+
cursor?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
after?: string;
|
|
8
|
+
direction?: 'forward';
|
|
9
|
+
state?: string;
|
|
10
|
+
contextGrantId?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ContextReadEnvelope<T = unknown> {
|
|
13
|
+
type: ContextReadType;
|
|
14
|
+
via: {
|
|
15
|
+
kind: string;
|
|
16
|
+
id: string;
|
|
17
|
+
};
|
|
18
|
+
items: T[];
|
|
19
|
+
hasMore: boolean;
|
|
20
|
+
nextCursor: string | null;
|
|
21
|
+
latestSequence?: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Protocol-first uniform context reads (ZIG-427).
|
|
25
|
+
* Wraps `GET /context/read/:type` — one client, one envelope, four types.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ContextReadClient {
|
|
28
|
+
private readonly operatorKey;
|
|
29
|
+
private readonly agentId;
|
|
30
|
+
private readonly baseUrl;
|
|
31
|
+
constructor(operatorKey: string, agentId: string, baseUrl?: string);
|
|
32
|
+
read<T = unknown>(type: ContextReadType, query: ContextReadQuery): Promise<ContextReadEnvelope<T>>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Protocol-first uniform context reads (ZIG-427).
|
|
5
|
+
* Wraps `GET /context/read/:type` — one client, one envelope, four types.
|
|
6
|
+
*/
|
|
7
|
+
export class ContextReadClient {
|
|
8
|
+
operatorKey;
|
|
9
|
+
agentId;
|
|
10
|
+
baseUrl;
|
|
11
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
12
|
+
if (!operatorKey)
|
|
13
|
+
throw new Error('ContextReadClient: operatorKey is required');
|
|
14
|
+
if (!agentId) {
|
|
15
|
+
throw new Error('ContextReadClient: agentId is required (operator-token impersonation)');
|
|
16
|
+
}
|
|
17
|
+
this.operatorKey = operatorKey;
|
|
18
|
+
this.agentId = agentId;
|
|
19
|
+
this.baseUrl = baseUrl || getBackendUrl();
|
|
20
|
+
}
|
|
21
|
+
async read(type, query) {
|
|
22
|
+
if (!query.via?.trim()) {
|
|
23
|
+
throw new Error('ContextReadClient.read: via is required');
|
|
24
|
+
}
|
|
25
|
+
const url = new URL(`${this.baseUrl}/context/read/${encodeURIComponent(type)}`);
|
|
26
|
+
url.searchParams.set('via', query.via.trim());
|
|
27
|
+
if (query.cursor)
|
|
28
|
+
url.searchParams.set('cursor', query.cursor);
|
|
29
|
+
if (query.limit != null)
|
|
30
|
+
url.searchParams.set('limit', String(query.limit));
|
|
31
|
+
if (query.after)
|
|
32
|
+
url.searchParams.set('after', query.after);
|
|
33
|
+
if (query.direction)
|
|
34
|
+
url.searchParams.set('direction', query.direction);
|
|
35
|
+
if (query.state)
|
|
36
|
+
url.searchParams.set('state', query.state);
|
|
37
|
+
if (query.contextGrantId) {
|
|
38
|
+
url.searchParams.set('contextGrantId', query.contextGrantId);
|
|
39
|
+
}
|
|
40
|
+
const headers = {
|
|
41
|
+
Authorization: `Bearer ${this.operatorKey}`,
|
|
42
|
+
'X-Agent-Id': this.agentId,
|
|
43
|
+
};
|
|
44
|
+
if (query.contextGrantId) {
|
|
45
|
+
headers['X-Context-Grant-Id'] = query.contextGrantId;
|
|
46
|
+
}
|
|
47
|
+
const res = await fetch(url.toString(), { headers });
|
|
48
|
+
const body = await res.text().catch(() => '');
|
|
49
|
+
if (!res.ok) {
|
|
50
|
+
throw new Error(`ContextReadClient.read ${type} ${res.status} ${body.slice(0, 200)}`);
|
|
51
|
+
}
|
|
52
|
+
return JSON.parse(body);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -10,8 +10,12 @@ export interface ListMessagesResult {
|
|
|
10
10
|
latestSequence: string | null;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Read-side client for
|
|
14
|
-
*
|
|
13
|
+
* Read-side client for forward-delta message reads.
|
|
14
|
+
*
|
|
15
|
+
* Hits the canonical `GET /chats/:chatId/messages?after=&direction=forward&limit=`
|
|
16
|
+
* endpoint and returns a `{ messages, latestSequence }` envelope
|
|
17
|
+
* (`chat-messaging.controller.listMessagesForward` →
|
|
18
|
+
* `MessagesService.listForChat`).
|
|
15
19
|
*/
|
|
16
20
|
export declare class MessagesClient {
|
|
17
21
|
private readonly operatorKey;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import 'dotenv/config';
|
|
2
2
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
3
|
/**
|
|
4
|
-
* Read-side client for
|
|
5
|
-
*
|
|
4
|
+
* Read-side client for forward-delta message reads.
|
|
5
|
+
*
|
|
6
|
+
* Hits the canonical `GET /chats/:chatId/messages?after=&direction=forward&limit=`
|
|
7
|
+
* endpoint and returns a `{ messages, latestSequence }` envelope
|
|
8
|
+
* (`chat-messaging.controller.listMessagesForward` →
|
|
9
|
+
* `MessagesService.listForChat`).
|
|
6
10
|
*/
|
|
7
11
|
export class MessagesClient {
|
|
8
12
|
operatorKey;
|
|
@@ -18,10 +22,14 @@ export class MessagesClient {
|
|
|
18
22
|
async list(chatId, opts = {}) {
|
|
19
23
|
if (!chatId)
|
|
20
24
|
return { messages: [], latestSequence: null };
|
|
21
|
-
const url = new URL(`${getBackendUrl()}/messages`);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const url = new URL(`${getBackendUrl()}/chats/${encodeURIComponent(chatId)}/messages`);
|
|
26
|
+
// Forward-delta read mode. Backend routes to `listMessagesForward`
|
|
27
|
+
// only when BOTH `after` and `direction=forward` are present; without
|
|
28
|
+
// `after` the same handler falls into backward pagination and returns
|
|
29
|
+
// a different envelope. Default `after` to the unix epoch so the
|
|
30
|
+
// forward branch always wins when callers want "from the beginning".
|
|
31
|
+
url.searchParams.set('direction', 'forward');
|
|
32
|
+
url.searchParams.set('after', opts.after || '1970-01-01T00:00:00.000Z');
|
|
25
33
|
if (opts.limit != null)
|
|
26
34
|
url.searchParams.set('limit', String(opts.limit));
|
|
27
35
|
const res = await fetch(url.toString(), { headers: this._headers() });
|
package/dist/http/TaskClient.js
CHANGED
|
@@ -302,10 +302,19 @@ export async function setTaskSatisfaction(taskId, satisfaction, creds) {
|
|
|
302
302
|
}
|
|
303
303
|
export async function countTasks(filters = {}, creds) {
|
|
304
304
|
assertCreds(creds, 'count tasks');
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
// Canonical REST: GET /tasks/count.
|
|
306
|
+
const url = new URL(`${getTaskBaseUrl()}/count`);
|
|
307
|
+
if (filters.chatId)
|
|
308
|
+
url.searchParams.set('chatId', filters.chatId);
|
|
309
|
+
if (filters.state)
|
|
310
|
+
url.searchParams.set('state', filters.state);
|
|
311
|
+
if (filters.userId)
|
|
312
|
+
url.searchParams.set('userId', filters.userId);
|
|
313
|
+
if (filters.agentId)
|
|
314
|
+
url.searchParams.set('agentId', filters.agentId);
|
|
315
|
+
const res = await fetch(url.toString(), {
|
|
316
|
+
method: 'GET',
|
|
307
317
|
headers: buildHeaders(creds),
|
|
308
|
-
body: JSON.stringify(filters),
|
|
309
318
|
});
|
|
310
319
|
if (!res.ok) {
|
|
311
320
|
const body = await res.text().catch(() => '');
|
package/dist/http/index.d.ts
CHANGED
|
@@ -8,5 +8,9 @@ export { ArtifactsClient } from './ArtifactsClient.js';
|
|
|
8
8
|
export type { ArtifactVisibility, ListArtifactsOptions, ListArtifactsQuery, ListArtifactsResult, WriteArtifactInput, } from './ArtifactsClient.js';
|
|
9
9
|
export { ScopeClient } from './ScopeClient.js';
|
|
10
10
|
export type { ScopeKind, ScopeResult, PartyRef } from './ScopeClient.js';
|
|
11
|
+
export { ContextReadClient } from './ContextReadClient.js';
|
|
12
|
+
export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, } from './ContextReadClient.js';
|
|
13
|
+
export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
14
|
+
export type { ContextReachDescriptor } from './ContextDiscoveryClient.js';
|
|
11
15
|
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
12
16
|
export { TelemetryClient } from './TelemetryClient.js';
|
package/dist/http/index.js
CHANGED
|
@@ -5,5 +5,7 @@ export * from './ChatClient.js';
|
|
|
5
5
|
export { MessagesClient } from './MessagesClient.js';
|
|
6
6
|
export { ArtifactsClient } from './ArtifactsClient.js';
|
|
7
7
|
export { ScopeClient } from './ScopeClient.js';
|
|
8
|
+
export { ContextReadClient } from './ContextReadClient.js';
|
|
9
|
+
export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
8
10
|
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
9
11
|
export { TelemetryClient } from './TelemetryClient.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -49,11 +49,19 @@ export interface Agreement {
|
|
|
49
49
|
engagementKind?: EngagementKind;
|
|
50
50
|
proposalStatus?: ProposalStatus;
|
|
51
51
|
parties?: {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
proposedTo?: string;
|
|
53
|
+
provider?: string;
|
|
54
|
+
payer?: string;
|
|
55
|
+
creator?: string;
|
|
56
|
+
creatorAgent?: string;
|
|
57
|
+
};
|
|
58
|
+
/** Legacy root-level price — always null in practice. Use money.price instead. */
|
|
59
|
+
price?: number | null;
|
|
60
|
+
/** Price and payment state. price is in cents (e.g. 6000 = 6000 KRW). */
|
|
61
|
+
money?: {
|
|
62
|
+
price?: number | null;
|
|
63
|
+
paymentStatus?: string;
|
|
55
64
|
};
|
|
56
|
-
price?: number;
|
|
57
65
|
lifecycle?: string;
|
|
58
66
|
expiresAt?: string;
|
|
59
67
|
maxExecutions?: number;
|
|
@@ -87,7 +95,7 @@ export declare const ContentTypes: {
|
|
|
87
95
|
export type ContentType = (typeof ContentTypes)[keyof typeof ContentTypes];
|
|
88
96
|
/** ⚠️ SYNC: Mirrors backend src/chat/chat.types.ts isValidContentType */
|
|
89
97
|
export declare function isValidContentType(contentType: string, entryType: string): boolean;
|
|
90
|
-
/** ⚠️ SYNC: Keep in sync with backend
|
|
98
|
+
/** ⚠️ SYNC: Keep in sync with backend. This is the canonical SDK-side definition. */
|
|
91
99
|
export declare const OPEN_AGREEMENT_TARGET: "everyone";
|
|
92
100
|
export interface MessageMetadata {
|
|
93
101
|
chatId: string;
|
|
@@ -111,10 +119,12 @@ export interface MessageMetadata {
|
|
|
111
119
|
* `normalizeIncomingEvent` reads `metadata.task` to upgrade structured
|
|
112
120
|
* task notifications into `task_result` events (so executors see
|
|
113
121
|
* `task-assigned` outcomes when the orchestrator calls `task_spawn`),
|
|
114
|
-
* and
|
|
115
|
-
*
|
|
122
|
+
* and maps explicit wire `operation` + `agreementId` lifecycle fields
|
|
123
|
+
* into `agreement_lifecycle` events for proposal approve/reject.
|
|
116
124
|
*/
|
|
117
125
|
task?: Record<string, unknown> | null;
|
|
118
126
|
agreement?: Record<string, unknown> | null;
|
|
127
|
+
operation?: string | null;
|
|
128
|
+
agreementId?: string | null;
|
|
119
129
|
}
|
|
120
130
|
export type MessageHandler = (text: string, metadata: MessageMetadata) => Promise<void>;
|
package/dist/types.js
CHANGED
|
@@ -46,5 +46,5 @@ const VALID_CONTENT_TYPES = {
|
|
|
46
46
|
export function isValidContentType(contentType, entryType) {
|
|
47
47
|
return VALID_CONTENT_TYPES[entryType]?.includes(contentType) ?? false;
|
|
48
48
|
}
|
|
49
|
-
/** ⚠️ SYNC: Keep in sync with backend
|
|
49
|
+
/** ⚠️ SYNC: Keep in sync with backend. This is the canonical SDK-side definition. */
|
|
50
50
|
export const OPEN_AGREEMENT_TARGET = 'everyone';
|
|
@@ -14,7 +14,8 @@ export function createControlSocket({ wsUrl, operatorKey, agentIds, onWake }) {
|
|
|
14
14
|
transports: ['websocket'],
|
|
15
15
|
reconnection: true,
|
|
16
16
|
reconnectionDelay: 1000,
|
|
17
|
-
reconnectionDelayMax:
|
|
17
|
+
reconnectionDelayMax: 30000,
|
|
18
|
+
randomizationFactor: 0.5,
|
|
18
19
|
});
|
|
19
20
|
socket.on('connect', () => {
|
|
20
21
|
const ids = agentIds();
|