@ziggs-ai/api-client 0.1.8 → 0.1.10
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/ContextReadClient.d.ts +6 -2
- package/dist/http/ContextReadClient.js +6 -4
- package/dist/http/InboxClient.d.ts +66 -0
- package/dist/http/InboxClient.js +56 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/websocket/WebSocketClient.d.ts +9 -0
- package/dist/websocket/WebSocketClient.js +22 -1
- package/package.json +1 -1
|
@@ -26,8 +26,12 @@ export interface ContextReadEnvelope<T = unknown> {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare class ContextReadClient {
|
|
28
28
|
private readonly operatorKey;
|
|
29
|
-
private readonly agentId
|
|
29
|
+
private readonly agentId?;
|
|
30
30
|
private readonly baseUrl;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* @param operatorKey Agent-scoped or fleet operator key.
|
|
33
|
+
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
34
|
+
*/
|
|
35
|
+
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
32
36
|
read<T = unknown>(type: ContextReadType, query: ContextReadQuery): Promise<ContextReadEnvelope<T>>;
|
|
33
37
|
}
|
|
@@ -8,12 +8,13 @@ export class ContextReadClient {
|
|
|
8
8
|
operatorKey;
|
|
9
9
|
agentId;
|
|
10
10
|
baseUrl;
|
|
11
|
+
/**
|
|
12
|
+
* @param operatorKey Agent-scoped or fleet operator key.
|
|
13
|
+
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
14
|
+
*/
|
|
11
15
|
constructor(operatorKey, agentId, baseUrl) {
|
|
12
16
|
if (!operatorKey)
|
|
13
17
|
throw new Error('ContextReadClient: operatorKey is required');
|
|
14
|
-
if (!agentId) {
|
|
15
|
-
throw new Error('ContextReadClient: agentId is required (operator-token impersonation)');
|
|
16
|
-
}
|
|
17
18
|
this.operatorKey = operatorKey;
|
|
18
19
|
this.agentId = agentId;
|
|
19
20
|
this.baseUrl = baseUrl || getBackendUrl();
|
|
@@ -39,8 +40,9 @@ export class ContextReadClient {
|
|
|
39
40
|
}
|
|
40
41
|
const headers = {
|
|
41
42
|
Authorization: `Bearer ${this.operatorKey}`,
|
|
42
|
-
'X-Agent-Id': this.agentId,
|
|
43
43
|
};
|
|
44
|
+
if (this.agentId)
|
|
45
|
+
headers['X-Agent-Id'] = this.agentId;
|
|
44
46
|
if (query.contextGrantId) {
|
|
45
47
|
headers['X-Context-Grant-Id'] = query.contextGrantId;
|
|
46
48
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
export type InboxScopeKind = 'chat' | 'agreement' | 'org';
|
|
3
|
+
export interface InboxScopeEntry {
|
|
4
|
+
scope: {
|
|
5
|
+
kind: InboxScopeKind;
|
|
6
|
+
id: string;
|
|
7
|
+
};
|
|
8
|
+
newMessages: number;
|
|
9
|
+
newArtifacts: number;
|
|
10
|
+
latestAt: string | null;
|
|
11
|
+
since: string;
|
|
12
|
+
}
|
|
13
|
+
export interface InboxProposalRef {
|
|
14
|
+
agreementId: string;
|
|
15
|
+
title: string;
|
|
16
|
+
proposedAt: string | null;
|
|
17
|
+
}
|
|
18
|
+
/** Pull-only MCP: prompt the human when proposals need a decision (ZIG-482). */
|
|
19
|
+
export interface InboxHumanAttention {
|
|
20
|
+
required: true;
|
|
21
|
+
reason: 'proposals_awaiting_me';
|
|
22
|
+
proposalCount: number;
|
|
23
|
+
truncatedProposals: number;
|
|
24
|
+
promptUser: string;
|
|
25
|
+
}
|
|
26
|
+
export interface InboxEnvelope {
|
|
27
|
+
asOf: string;
|
|
28
|
+
scopes: InboxScopeEntry[];
|
|
29
|
+
truncatedScopes: number;
|
|
30
|
+
countCap: number;
|
|
31
|
+
proposalsAwaitingMe: InboxProposalRef[];
|
|
32
|
+
truncatedProposals: number;
|
|
33
|
+
humanAttention?: InboxHumanAttention;
|
|
34
|
+
}
|
|
35
|
+
export interface InboxAck {
|
|
36
|
+
kind: InboxScopeKind;
|
|
37
|
+
id: string;
|
|
38
|
+
upTo: string;
|
|
39
|
+
}
|
|
40
|
+
export interface InboxAckResult {
|
|
41
|
+
acked: Array<{
|
|
42
|
+
scope: {
|
|
43
|
+
kind: InboxScopeKind;
|
|
44
|
+
id: string;
|
|
45
|
+
};
|
|
46
|
+
ackedUpTo: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The doorbell, not the door (ZIG-434): references and counts since the
|
|
51
|
+
* agent's last ack — never content. Flow: inbox → read → act → ack (ZIG-446).
|
|
52
|
+
* Wraps `GET /agent-api/v1/inbox` and `POST /agent-api/v1/inbox/ack`.
|
|
53
|
+
*/
|
|
54
|
+
export declare class InboxClient {
|
|
55
|
+
private readonly operatorKey;
|
|
56
|
+
private readonly agentId?;
|
|
57
|
+
private readonly baseUrl;
|
|
58
|
+
/**
|
|
59
|
+
* @param operatorKey Agent-scoped or fleet operator key.
|
|
60
|
+
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
61
|
+
*/
|
|
62
|
+
constructor(operatorKey: string, agentId?: string, baseUrl?: string);
|
|
63
|
+
private headers;
|
|
64
|
+
getInbox(): Promise<InboxEnvelope>;
|
|
65
|
+
ack(scopes: InboxAck[]): Promise<InboxAckResult>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
|
+
/**
|
|
4
|
+
* The doorbell, not the door (ZIG-434): references and counts since the
|
|
5
|
+
* agent's last ack — never content. Flow: inbox → read → act → ack (ZIG-446).
|
|
6
|
+
* Wraps `GET /agent-api/v1/inbox` and `POST /agent-api/v1/inbox/ack`.
|
|
7
|
+
*/
|
|
8
|
+
export class InboxClient {
|
|
9
|
+
operatorKey;
|
|
10
|
+
agentId;
|
|
11
|
+
baseUrl;
|
|
12
|
+
/**
|
|
13
|
+
* @param operatorKey Agent-scoped or fleet operator key.
|
|
14
|
+
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
15
|
+
*/
|
|
16
|
+
constructor(operatorKey, agentId, baseUrl) {
|
|
17
|
+
if (!operatorKey)
|
|
18
|
+
throw new Error('InboxClient: operatorKey is required');
|
|
19
|
+
this.operatorKey = operatorKey;
|
|
20
|
+
this.agentId = agentId;
|
|
21
|
+
this.baseUrl = baseUrl || getBackendUrl();
|
|
22
|
+
}
|
|
23
|
+
headers() {
|
|
24
|
+
const headers = {
|
|
25
|
+
Authorization: `Bearer ${this.operatorKey}`,
|
|
26
|
+
'Content-Type': 'application/json',
|
|
27
|
+
};
|
|
28
|
+
if (this.agentId)
|
|
29
|
+
headers['X-Agent-Id'] = this.agentId;
|
|
30
|
+
return headers;
|
|
31
|
+
}
|
|
32
|
+
async getInbox() {
|
|
33
|
+
const res = await fetch(`${this.baseUrl}/agent-api/v1/inbox`, {
|
|
34
|
+
headers: this.headers(),
|
|
35
|
+
});
|
|
36
|
+
const body = await res.text().catch(() => '');
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(`InboxClient.getInbox ${res.status} ${body.slice(0, 200)}`);
|
|
39
|
+
}
|
|
40
|
+
return JSON.parse(body);
|
|
41
|
+
}
|
|
42
|
+
async ack(scopes) {
|
|
43
|
+
if (!scopes.length)
|
|
44
|
+
throw new Error('InboxClient.ack: scopes are required');
|
|
45
|
+
const res = await fetch(`${this.baseUrl}/agent-api/v1/inbox/ack`, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: this.headers(),
|
|
48
|
+
body: JSON.stringify({ scopes }),
|
|
49
|
+
});
|
|
50
|
+
const body = await res.text().catch(() => '');
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
throw new Error(`InboxClient.ack ${res.status} ${body.slice(0, 200)}`);
|
|
53
|
+
}
|
|
54
|
+
return JSON.parse(body);
|
|
55
|
+
}
|
|
56
|
+
}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -16,3 +16,5 @@ export { ContextGrantsClient } from './ContextGrantsClient.js';
|
|
|
16
16
|
export type { ContextGrantRecord, ContextGrantScope, ContextGrantScopeKind, ContextTemporal, IssueContextGrantInput, DelegateContextGrantInput, } from './ContextGrantsClient.js';
|
|
17
17
|
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
18
18
|
export { TelemetryClient } from './TelemetryClient.js';
|
|
19
|
+
export { InboxClient } from './InboxClient.js';
|
|
20
|
+
export type { InboxScopeKind, InboxScopeEntry, InboxProposalRef, InboxEnvelope, InboxAck, InboxAckResult, } from './InboxClient.js';
|
package/dist/http/index.js
CHANGED
|
@@ -10,3 +10,4 @@ export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
|
|
|
10
10
|
export { ContextGrantsClient } from './ContextGrantsClient.js';
|
|
11
11
|
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
12
12
|
export { TelemetryClient } from './TelemetryClient.js';
|
|
13
|
+
export { InboxClient } from './InboxClient.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -99,6 +99,8 @@ export declare function isValidContentType(contentType: string, entryType: strin
|
|
|
99
99
|
export declare const OPEN_AGREEMENT_TARGET: "everyone";
|
|
100
100
|
export interface MessageMetadata {
|
|
101
101
|
chatId: string;
|
|
102
|
+
/** Stable id for dedup across push + inbox catch-up (ZIG-454). */
|
|
103
|
+
messageId?: string;
|
|
102
104
|
userId: string;
|
|
103
105
|
sender: {
|
|
104
106
|
id: string;
|
|
@@ -41,6 +41,8 @@ export interface SendOptions {
|
|
|
41
41
|
* Requires backend streaming support.
|
|
42
42
|
*/
|
|
43
43
|
partial?: boolean;
|
|
44
|
+
/** Pre-allocated messageId for streaming continuity — links chunks to the final message. */
|
|
45
|
+
messageId?: string;
|
|
44
46
|
}
|
|
45
47
|
export declare class WebSocketClient {
|
|
46
48
|
private wsUrl;
|
|
@@ -60,6 +62,13 @@ export declare class WebSocketClient {
|
|
|
60
62
|
* `event.kind` + ids. Replaces cursor-based polling for delta detection.
|
|
61
63
|
*/
|
|
62
64
|
setResourceEventHandler(handler: ResourceEventHandler): void;
|
|
65
|
+
private connectHandlers;
|
|
66
|
+
/**
|
|
67
|
+
* Called on every socket connect, including socket.io reconnects.
|
|
68
|
+
* Used for inbox catch-up (ZIG-454) so missed pushes are recovered from MongoDB.
|
|
69
|
+
*/
|
|
70
|
+
onConnect(handler: () => void | Promise<void>): void;
|
|
71
|
+
private _emitConnect;
|
|
63
72
|
private _connect;
|
|
64
73
|
connectAsync(timeout?: number): Promise<this>;
|
|
65
74
|
disconnect(): void;
|
|
@@ -33,6 +33,25 @@ export class WebSocketClient {
|
|
|
33
33
|
setResourceEventHandler(handler) {
|
|
34
34
|
this.resourceEventHandler = handler;
|
|
35
35
|
}
|
|
36
|
+
connectHandlers = [];
|
|
37
|
+
/**
|
|
38
|
+
* Called on every socket connect, including socket.io reconnects.
|
|
39
|
+
* Used for inbox catch-up (ZIG-454) so missed pushes are recovered from MongoDB.
|
|
40
|
+
*/
|
|
41
|
+
onConnect(handler) {
|
|
42
|
+
this.connectHandlers.push(handler);
|
|
43
|
+
}
|
|
44
|
+
async _emitConnect() {
|
|
45
|
+
for (const handler of this.connectHandlers) {
|
|
46
|
+
try {
|
|
47
|
+
await handler();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
51
|
+
runtimeLog.warn(this.label, `connect handler error: ${msg}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
36
55
|
_connect() {
|
|
37
56
|
if (this.socket?.connected)
|
|
38
57
|
return;
|
|
@@ -41,6 +60,7 @@ export class WebSocketClient {
|
|
|
41
60
|
this.socket = io(this.wsUrl, socketOptions);
|
|
42
61
|
this.socket.on('connect', () => {
|
|
43
62
|
runtimeLog.info(this.label, 'Connected');
|
|
63
|
+
void this._emitConnect();
|
|
44
64
|
});
|
|
45
65
|
this.socket.on('connect_error', (error) => {
|
|
46
66
|
runtimeLog.error(this.label, `Connection error: ${error.message}`);
|
|
@@ -119,7 +139,7 @@ export class WebSocketClient {
|
|
|
119
139
|
throw new Error('send: socket is not initialized. Call connect() first.');
|
|
120
140
|
if (!this.socket.connected)
|
|
121
141
|
throw new Error('send: socket is not connected. Call connect() and wait for connection.');
|
|
122
|
-
const messageId = this.generateMessageId();
|
|
142
|
+
const messageId = options.messageId ?? this.generateMessageId();
|
|
123
143
|
if (!messageId || typeof messageId !== 'string')
|
|
124
144
|
throw new Error('send: failed to generate valid messageId');
|
|
125
145
|
const message = {
|
|
@@ -174,6 +194,7 @@ export class WebSocketClient {
|
|
|
174
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'}`);
|
|
175
195
|
const metadata = {
|
|
176
196
|
chatId,
|
|
197
|
+
messageId: typeof p['messageId'] === 'string' ? p['messageId'] : undefined,
|
|
177
198
|
userId: senderId,
|
|
178
199
|
sender: { id: senderId, type: senderType },
|
|
179
200
|
senderId,
|