@ziggs-ai/api-client 0.1.3 → 0.1.4
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/README.md +13 -7
- package/dist/ConnectionManager.d.ts +45 -0
- package/dist/ConnectionManager.js +118 -0
- package/dist/http/AgentSearchClient.d.ts +36 -0
- package/dist/http/AgentSearchClient.js +72 -0
- package/dist/http/AgreementClient.d.ts +153 -0
- package/dist/http/AgreementClient.js +457 -0
- package/dist/http/ArtifactsClient.d.ts +48 -0
- package/dist/http/ArtifactsClient.js +90 -0
- package/dist/http/ChatClient.d.ts +14 -0
- package/dist/http/ChatClient.js +69 -0
- package/dist/http/MarketplaceClient.d.ts +19 -0
- package/dist/http/MarketplaceClient.js +72 -0
- package/dist/http/MessagesClient.d.ts +22 -0
- package/dist/http/MessagesClient.js +41 -0
- package/dist/http/ScopeClient.d.ts +33 -0
- package/dist/http/ScopeClient.js +39 -0
- package/dist/http/TaskClient.d.ts +75 -0
- package/dist/http/TaskClient.js +343 -0
- package/dist/http/TelemetryClient.d.ts +11 -0
- package/dist/http/TelemetryClient.js +53 -0
- package/dist/http/index.d.ts +12 -0
- package/dist/http/index.js +9 -0
- package/dist/index.d.ts +9 -0
- package/{src → dist}/index.js +2 -12
- package/dist/shared/runtimeLog.d.ts +14 -0
- package/dist/shared/runtimeLog.js +64 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.js +50 -0
- package/dist/utils/urlUtils.d.ts +2 -0
- package/dist/utils/urlUtils.js +8 -0
- package/dist/websocket/ControlSocket.d.ts +13 -0
- package/dist/websocket/ControlSocket.js +36 -0
- package/dist/websocket/WebSocketClient.d.ts +71 -0
- package/dist/websocket/WebSocketClient.js +217 -0
- package/dist/websocket/index.js +1 -0
- package/package.json +13 -6
- package/src/ConnectionManager.js +0 -179
- package/src/http/AgentSearchClient.js +0 -113
- package/src/http/ContextReader.js +0 -99
- package/src/http/ContextWriter.js +0 -98
- package/src/http/TaskClient.js +0 -612
- package/src/http/TelemetryClient.js +0 -43
- package/src/http/index.js +0 -6
- package/src/types.js +0 -28
- package/src/utils/urlUtils.js +0 -17
- package/src/websocket/ControlSocket.js +0 -55
- package/src/websocket/WebSocketClient.js +0 -318
- /package/{src/websocket/index.js → dist/websocket/index.d.ts} +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
|
+
export class TelemetryClient {
|
|
5
|
+
operatorKey;
|
|
6
|
+
agentId;
|
|
7
|
+
_queue;
|
|
8
|
+
_flushing;
|
|
9
|
+
constructor(operatorKey, agentId) {
|
|
10
|
+
if (!operatorKey)
|
|
11
|
+
throw new Error('TelemetryClient: operatorKey is required');
|
|
12
|
+
if (!agentId)
|
|
13
|
+
throw new Error('TelemetryClient: agentId is required (operator-token impersonation)');
|
|
14
|
+
this.operatorKey = operatorKey;
|
|
15
|
+
this.agentId = agentId;
|
|
16
|
+
this._queue = [];
|
|
17
|
+
this._flushing = false;
|
|
18
|
+
}
|
|
19
|
+
async send(payload) {
|
|
20
|
+
this._queue.push(payload);
|
|
21
|
+
if (!this._flushing)
|
|
22
|
+
this._flush();
|
|
23
|
+
}
|
|
24
|
+
async _flush() {
|
|
25
|
+
this._flushing = true;
|
|
26
|
+
while (this._queue.length > 0) {
|
|
27
|
+
const batch = this._queue.splice(0, 10);
|
|
28
|
+
await Promise.allSettled(batch.map((p) => this._post(p)));
|
|
29
|
+
}
|
|
30
|
+
this._flushing = false;
|
|
31
|
+
}
|
|
32
|
+
async _post(payload) {
|
|
33
|
+
const url = `${getBackendUrl()}/agents/monitoring/ingest`;
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(url, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: {
|
|
38
|
+
'content-type': 'application/json',
|
|
39
|
+
Authorization: `Bearer ${this.operatorKey}`,
|
|
40
|
+
'X-Agent-Id': this.agentId,
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({ payload }),
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const body = await res.text().catch(() => '');
|
|
46
|
+
runtimeLog.warn('TelemetryClient', `⚠️ ingest failed agent=${this.agentId} ${res.status} ${res.statusText} body=${body.slice(0, 200)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
runtimeLog.warn('TelemetryClient', `⚠️ ingest error agent=${this.agentId} message=${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './TaskClient.js';
|
|
2
|
+
export * from './AgreementClient.js';
|
|
3
|
+
export * from './MarketplaceClient.js';
|
|
4
|
+
export * from './ChatClient.js';
|
|
5
|
+
export { MessagesClient } from './MessagesClient.js';
|
|
6
|
+
export type { ListMessagesOptions, ListMessagesResult } from './MessagesClient.js';
|
|
7
|
+
export { ArtifactsClient } from './ArtifactsClient.js';
|
|
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
|
+
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
12
|
+
export { TelemetryClient } from './TelemetryClient.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './TaskClient.js';
|
|
2
|
+
export * from './AgreementClient.js';
|
|
3
|
+
export * from './MarketplaceClient.js';
|
|
4
|
+
export * from './ChatClient.js';
|
|
5
|
+
export { MessagesClient } from './MessagesClient.js';
|
|
6
|
+
export { ArtifactsClient } from './ArtifactsClient.js';
|
|
7
|
+
export { ScopeClient } from './ScopeClient.js';
|
|
8
|
+
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
9
|
+
export { TelemetryClient } from './TelemetryClient.js';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './http/index.js';
|
|
2
|
+
export { WebSocketClient } from './websocket/index.js';
|
|
3
|
+
export { createControlSocket } from './websocket/ControlSocket.js';
|
|
4
|
+
export { ConnectionManager } from './ConnectionManager.js';
|
|
5
|
+
export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, AGREEMENT_ENGAGEMENT_KIND, isValidContentType } from './types.js';
|
|
6
|
+
export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
|
|
7
|
+
export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
|
|
8
|
+
export type { Creds, Task, TaskState, PlanStep, PlanStepStatus, Agreement, EngagementKind, EntryType, ContentType, MessageMetadata, MessageHandler, ApiError, } from './types.js';
|
|
9
|
+
export type { ProposeTerms, ProposeDirectInput, ProposeBroadcastInput, ProposeAgreementData, } from './http/AgreementClient.js';
|
package/{src → dist}/index.js
RENAMED
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
// Main entry point for @ziggs-ai/api-client
|
|
2
|
-
|
|
3
|
-
// HTTP Clients
|
|
4
1
|
export * from './http/index.js';
|
|
5
|
-
|
|
6
|
-
// WebSocket Client
|
|
7
2
|
export { WebSocketClient } from './websocket/index.js';
|
|
8
3
|
export { createControlSocket } from './websocket/ControlSocket.js';
|
|
9
|
-
|
|
10
|
-
// Connection management (optional — generic pool + control socket)
|
|
11
4
|
export { ConnectionManager } from './ConnectionManager.js';
|
|
12
|
-
|
|
13
|
-
// Types
|
|
14
|
-
export { EntryTypes, ContentTypes } from './types.js';
|
|
15
|
-
|
|
16
|
-
// Utilities
|
|
5
|
+
export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, AGREEMENT_ENGAGEMENT_KIND, isValidContentType } from './types.js';
|
|
17
6
|
export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
|
|
7
|
+
export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same semantics as `@ziggs-ai/agent-sdk` `shared/runtimeLog.ts` (duplicated
|
|
3
|
+
* here so this package stays dependency-free).
|
|
4
|
+
*
|
|
5
|
+
* @see agent-sdk/src/shared/runtimeLog.ts
|
|
6
|
+
*/
|
|
7
|
+
export type RuntimeLogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
8
|
+
export declare function resetRuntimeLogLevelCache(): void;
|
|
9
|
+
export declare const runtimeLog: {
|
|
10
|
+
debug(scope: string, msg: string, ...rest: unknown[]): void;
|
|
11
|
+
info(scope: string, msg: string, ...rest: unknown[]): void;
|
|
12
|
+
warn(scope: string, msg: string, ...rest: unknown[]): void;
|
|
13
|
+
error(scope: string, msg: string, ...rest: unknown[]): void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same semantics as `@ziggs-ai/agent-sdk` `shared/runtimeLog.ts` (duplicated
|
|
3
|
+
* here so this package stays dependency-free).
|
|
4
|
+
*
|
|
5
|
+
* @see agent-sdk/src/shared/runtimeLog.ts
|
|
6
|
+
*/
|
|
7
|
+
const SEVERITY = {
|
|
8
|
+
debug: 0,
|
|
9
|
+
info: 1,
|
|
10
|
+
warn: 2,
|
|
11
|
+
error: 3,
|
|
12
|
+
};
|
|
13
|
+
function parseThreshold() {
|
|
14
|
+
if (process.env.DEBUG_AGENTPLUS === '1' || process.env.AGENTPLUS_DEBUG === '1') {
|
|
15
|
+
return SEVERITY.debug;
|
|
16
|
+
}
|
|
17
|
+
const raw = (process.env.LOG_LEVEL ||
|
|
18
|
+
process.env.AGENTPLUS_LOG_LEVEL ||
|
|
19
|
+
'info').toLowerCase();
|
|
20
|
+
if (raw === 'silent' || raw === 'none')
|
|
21
|
+
return SEVERITY.error;
|
|
22
|
+
if (raw === 'debug' || raw === 'trace')
|
|
23
|
+
return SEVERITY.debug;
|
|
24
|
+
if (raw === 'warn')
|
|
25
|
+
return SEVERITY.warn;
|
|
26
|
+
if (raw === 'error')
|
|
27
|
+
return SEVERITY.error;
|
|
28
|
+
return SEVERITY.info;
|
|
29
|
+
}
|
|
30
|
+
let cachedThreshold = null;
|
|
31
|
+
function threshold() {
|
|
32
|
+
if (cachedThreshold === null)
|
|
33
|
+
cachedThreshold = parseThreshold();
|
|
34
|
+
return cachedThreshold;
|
|
35
|
+
}
|
|
36
|
+
export function resetRuntimeLogLevelCache() {
|
|
37
|
+
cachedThreshold = null;
|
|
38
|
+
}
|
|
39
|
+
function shouldEmit(level) {
|
|
40
|
+
return SEVERITY[level] >= threshold();
|
|
41
|
+
}
|
|
42
|
+
function fmt(scope, msg) {
|
|
43
|
+
return `[${scope}] ${msg}`;
|
|
44
|
+
}
|
|
45
|
+
export const runtimeLog = {
|
|
46
|
+
debug(scope, msg, ...rest) {
|
|
47
|
+
if (!shouldEmit('debug'))
|
|
48
|
+
return;
|
|
49
|
+
console.log(fmt(scope, msg), ...rest);
|
|
50
|
+
},
|
|
51
|
+
info(scope, msg, ...rest) {
|
|
52
|
+
if (!shouldEmit('info'))
|
|
53
|
+
return;
|
|
54
|
+
console.log(fmt(scope, msg), ...rest);
|
|
55
|
+
},
|
|
56
|
+
warn(scope, msg, ...rest) {
|
|
57
|
+
if (!shouldEmit('warn'))
|
|
58
|
+
return;
|
|
59
|
+
console.warn(fmt(scope, msg), ...rest);
|
|
60
|
+
},
|
|
61
|
+
error(scope, msg, ...rest) {
|
|
62
|
+
console.error(fmt(scope, msg), ...rest);
|
|
63
|
+
},
|
|
64
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly body?: string | undefined;
|
|
4
|
+
constructor(message: string, status: number, body?: string | undefined);
|
|
5
|
+
}
|
|
6
|
+
export interface Creds {
|
|
7
|
+
operatorKey: string;
|
|
8
|
+
agentId: string;
|
|
9
|
+
}
|
|
10
|
+
export type TaskState = 'active' | 'proposal' | 'completed' | 'failed' | 'cancelled' | 'ledger_open';
|
|
11
|
+
export type PlanStepStatus = 'pending' | 'in_progress' | 'completed' | 'skipped';
|
|
12
|
+
export interface PlanStep {
|
|
13
|
+
stepId: string;
|
|
14
|
+
status: PlanStepStatus;
|
|
15
|
+
result?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface Task {
|
|
18
|
+
taskId: string;
|
|
19
|
+
description: string;
|
|
20
|
+
agentId?: string;
|
|
21
|
+
executorId?: string;
|
|
22
|
+
payerId?: string;
|
|
23
|
+
agreementId?: string;
|
|
24
|
+
agreement?: Agreement;
|
|
25
|
+
state: TaskState;
|
|
26
|
+
processing?: boolean;
|
|
27
|
+
deleted?: boolean;
|
|
28
|
+
result?: unknown;
|
|
29
|
+
errorMessage?: string;
|
|
30
|
+
createdAt?: string;
|
|
31
|
+
updatedAt?: string;
|
|
32
|
+
parentTaskId?: string;
|
|
33
|
+
rootTaskId?: string;
|
|
34
|
+
plan?: PlanStep[];
|
|
35
|
+
history?: unknown[];
|
|
36
|
+
}
|
|
37
|
+
export type AgreementStatus = 'pending' | 'active' | 'fulfilled' | 'cancelled' | 'rejected' | (string & {});
|
|
38
|
+
export type ProposalStatus = 'pending' | 'approved' | 'rejected' | 'countered' | 'expired' | (string & {});
|
|
39
|
+
/** ⚠️ SYNC: backend src/agreements/agreements.constants.ts AGREEMENT_ENGAGEMENT_KIND */
|
|
40
|
+
export declare const AGREEMENT_ENGAGEMENT_KIND: {
|
|
41
|
+
readonly HIRE: "hire";
|
|
42
|
+
readonly SERVICE: "service";
|
|
43
|
+
};
|
|
44
|
+
export type EngagementKind = (typeof AGREEMENT_ENGAGEMENT_KIND)[keyof typeof AGREEMENT_ENGAGEMENT_KIND];
|
|
45
|
+
export interface Agreement {
|
|
46
|
+
agreementId: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
status?: AgreementStatus;
|
|
49
|
+
engagementKind?: EngagementKind;
|
|
50
|
+
proposalStatus?: ProposalStatus;
|
|
51
|
+
parties?: {
|
|
52
|
+
proposedToId?: string;
|
|
53
|
+
providerId?: string;
|
|
54
|
+
payerId?: string;
|
|
55
|
+
};
|
|
56
|
+
price?: number;
|
|
57
|
+
lifecycle?: string;
|
|
58
|
+
expiresAt?: string;
|
|
59
|
+
maxExecutions?: number;
|
|
60
|
+
metadata?: Record<string, unknown>;
|
|
61
|
+
createdAt?: string;
|
|
62
|
+
updatedAt?: string;
|
|
63
|
+
}
|
|
64
|
+
/** ⚠️ SYNC: Keep in sync with backend src/chat/chat.types.ts ENTRY_TYPE */
|
|
65
|
+
export declare const EntryTypes: {
|
|
66
|
+
readonly MESSAGE: "message";
|
|
67
|
+
readonly NOTIFICATION: "notification";
|
|
68
|
+
readonly ARTIFACT: "artifact";
|
|
69
|
+
readonly AGREEMENT_HISTORY: "agreement_history";
|
|
70
|
+
/** @deprecated legacy alias for AGREEMENT_HISTORY */
|
|
71
|
+
readonly TASK_HISTORY: "task_history";
|
|
72
|
+
};
|
|
73
|
+
export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes];
|
|
74
|
+
/** ⚠️ SYNC: Keep in sync with backend src/chat/chat.types.ts CONTENT_TYPE */
|
|
75
|
+
export declare const ContentTypes: {
|
|
76
|
+
readonly TEXT: "text";
|
|
77
|
+
readonly OPERATION: "operation";
|
|
78
|
+
readonly CONTEXT: "context";
|
|
79
|
+
readonly RESULT: "result";
|
|
80
|
+
readonly AGREEMENT_UPDATE: "agreement_update";
|
|
81
|
+
readonly TASK: "task";
|
|
82
|
+
readonly PROPOSAL: "proposal";
|
|
83
|
+
readonly THOUGHT: "thought";
|
|
84
|
+
/** @deprecated legacy alias for AGREEMENT_UPDATE */
|
|
85
|
+
readonly TASK_UPDATE: "task_update";
|
|
86
|
+
};
|
|
87
|
+
export type ContentType = (typeof ContentTypes)[keyof typeof ContentTypes];
|
|
88
|
+
/** ⚠️ SYNC: Mirrors backend src/chat/chat.types.ts isValidContentType */
|
|
89
|
+
export declare function isValidContentType(contentType: string, entryType: string): boolean;
|
|
90
|
+
/** ⚠️ SYNC: Keep in sync with backend and agent-sdk/src/tasks/taskCore.js */
|
|
91
|
+
export declare const OPEN_AGREEMENT_TARGET: "everyone";
|
|
92
|
+
export interface MessageMetadata {
|
|
93
|
+
chatId: string;
|
|
94
|
+
userId: string;
|
|
95
|
+
sender: {
|
|
96
|
+
id: string;
|
|
97
|
+
type?: string;
|
|
98
|
+
};
|
|
99
|
+
senderId: string;
|
|
100
|
+
senderType?: string;
|
|
101
|
+
receiver?: {
|
|
102
|
+
id: string;
|
|
103
|
+
} | null;
|
|
104
|
+
receiverId?: string | null;
|
|
105
|
+
entryType?: string;
|
|
106
|
+
content_type?: string;
|
|
107
|
+
taskId?: string | null;
|
|
108
|
+
/**
|
|
109
|
+
* Optional task / agreement snapshot pinned by the backend on
|
|
110
|
+
* `task.notify.chat` / `agreement.notify.direct` traffic. The agent SDK's
|
|
111
|
+
* `normalizeIncomingEvent` reads `metadata.task` to upgrade structured
|
|
112
|
+
* task notifications into `task_result` events (so executors see
|
|
113
|
+
* `task-assigned` outcomes when the orchestrator calls `task_spawn`),
|
|
114
|
+
* and the agent FSM treats `metadata.agreement` as the source of truth
|
|
115
|
+
* for proposal lifecycle without needing a separate fetch.
|
|
116
|
+
*/
|
|
117
|
+
task?: Record<string, unknown> | null;
|
|
118
|
+
agreement?: Record<string, unknown> | null;
|
|
119
|
+
}
|
|
120
|
+
export type MessageHandler = (text: string, metadata: MessageMetadata) => Promise<void>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
body;
|
|
4
|
+
constructor(message, status, body) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.status = status;
|
|
7
|
+
this.body = body;
|
|
8
|
+
this.name = 'ApiError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** ⚠️ SYNC: backend src/agreements/agreements.constants.ts AGREEMENT_ENGAGEMENT_KIND */
|
|
12
|
+
export const AGREEMENT_ENGAGEMENT_KIND = {
|
|
13
|
+
HIRE: 'hire',
|
|
14
|
+
SERVICE: 'service',
|
|
15
|
+
};
|
|
16
|
+
/** ⚠️ SYNC: Keep in sync with backend src/chat/chat.types.ts ENTRY_TYPE */
|
|
17
|
+
export const EntryTypes = {
|
|
18
|
+
MESSAGE: 'message',
|
|
19
|
+
NOTIFICATION: 'notification',
|
|
20
|
+
ARTIFACT: 'artifact',
|
|
21
|
+
AGREEMENT_HISTORY: 'agreement_history',
|
|
22
|
+
/** @deprecated legacy alias for AGREEMENT_HISTORY */
|
|
23
|
+
TASK_HISTORY: 'task_history',
|
|
24
|
+
};
|
|
25
|
+
/** ⚠️ SYNC: Keep in sync with backend src/chat/chat.types.ts CONTENT_TYPE */
|
|
26
|
+
export const ContentTypes = {
|
|
27
|
+
TEXT: 'text',
|
|
28
|
+
OPERATION: 'operation',
|
|
29
|
+
CONTEXT: 'context',
|
|
30
|
+
RESULT: 'result',
|
|
31
|
+
AGREEMENT_UPDATE: 'agreement_update',
|
|
32
|
+
TASK: 'task',
|
|
33
|
+
PROPOSAL: 'proposal',
|
|
34
|
+
THOUGHT: 'thought',
|
|
35
|
+
/** @deprecated legacy alias for AGREEMENT_UPDATE */
|
|
36
|
+
TASK_UPDATE: 'task_update',
|
|
37
|
+
};
|
|
38
|
+
const VALID_CONTENT_TYPES = {
|
|
39
|
+
[EntryTypes.MESSAGE]: [ContentTypes.TEXT],
|
|
40
|
+
[EntryTypes.NOTIFICATION]: [ContentTypes.TEXT, ContentTypes.TASK, ContentTypes.PROPOSAL],
|
|
41
|
+
[EntryTypes.ARTIFACT]: [ContentTypes.OPERATION, ContentTypes.CONTEXT, ContentTypes.RESULT, ContentTypes.TEXT, ContentTypes.THOUGHT],
|
|
42
|
+
[EntryTypes.AGREEMENT_HISTORY]: [ContentTypes.AGREEMENT_UPDATE, ContentTypes.TASK_UPDATE],
|
|
43
|
+
[EntryTypes.TASK_HISTORY]: [ContentTypes.AGREEMENT_UPDATE, ContentTypes.TASK_UPDATE],
|
|
44
|
+
};
|
|
45
|
+
/** ⚠️ SYNC: Mirrors backend src/chat/chat.types.ts isValidContentType */
|
|
46
|
+
export function isValidContentType(contentType, entryType) {
|
|
47
|
+
return VALID_CONTENT_TYPES[entryType]?.includes(contentType) ?? false;
|
|
48
|
+
}
|
|
49
|
+
/** ⚠️ SYNC: Keep in sync with backend and agent-sdk/src/tasks/taskCore.js */
|
|
50
|
+
export const OPEN_AGREEMENT_TARGET = 'everyone';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function getBackendUrl() {
|
|
2
|
+
const url = process.env.HTTP_URL || 'https://api.ziggsai.com';
|
|
3
|
+
return url.startsWith('http') ? url : `https://${url}`;
|
|
4
|
+
}
|
|
5
|
+
export function getWebSocketUrl() {
|
|
6
|
+
const wsUrl = process.env.WS_URL || 'wss://api.ziggsai.com';
|
|
7
|
+
return wsUrl.startsWith('ws') ? wsUrl : `wss://${wsUrl}`;
|
|
8
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Socket } from 'socket.io-client';
|
|
2
|
+
export interface ControlSocketOptions {
|
|
3
|
+
wsUrl: string;
|
|
4
|
+
operatorKey: string;
|
|
5
|
+
agentIds: () => string[];
|
|
6
|
+
onWake: (agentId: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ControlSocketHandle {
|
|
9
|
+
socket: Socket;
|
|
10
|
+
close: () => void;
|
|
11
|
+
resync: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare function createControlSocket({ wsUrl, operatorKey, agentIds, onWake }: ControlSocketOptions): ControlSocketHandle;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
export function createControlSocket({ wsUrl, operatorKey, agentIds, onWake }) {
|
|
4
|
+
if (!wsUrl || !operatorKey)
|
|
5
|
+
throw new Error('[createControlSocket] wsUrl and operatorKey are required');
|
|
6
|
+
if (typeof agentIds !== 'function')
|
|
7
|
+
throw new Error('[createControlSocket] agentIds must be a function returning string[]');
|
|
8
|
+
if (typeof onWake !== 'function')
|
|
9
|
+
throw new Error('[createControlSocket] onWake must be a function');
|
|
10
|
+
const socket = io(wsUrl, {
|
|
11
|
+
auth: { token: `Bearer ${operatorKey}` },
|
|
12
|
+
query: { token: operatorKey, role: 'launcher' },
|
|
13
|
+
extraHeaders: { Authorization: `Bearer ${operatorKey}` },
|
|
14
|
+
transports: ['websocket'],
|
|
15
|
+
reconnection: true,
|
|
16
|
+
reconnectionDelay: 1000,
|
|
17
|
+
reconnectionDelayMax: 5000,
|
|
18
|
+
});
|
|
19
|
+
socket.on('connect', () => {
|
|
20
|
+
const ids = agentIds();
|
|
21
|
+
runtimeLog.info('ControlSocket', `connected (${socket.id}); registering ${ids.length} agent(s)`);
|
|
22
|
+
socket.emit('launcher:register', { agentIds: ids });
|
|
23
|
+
});
|
|
24
|
+
socket.on('launcher:wake', ({ agentId }) => {
|
|
25
|
+
if (agentId)
|
|
26
|
+
onWake(agentId);
|
|
27
|
+
});
|
|
28
|
+
socket.on('disconnect', (reason) => runtimeLog.debug('ControlSocket', `disconnected: ${reason}`));
|
|
29
|
+
socket.on('connect_error', (err) => runtimeLog.warn('ControlSocket', `connect error: ${err.message}`));
|
|
30
|
+
return {
|
|
31
|
+
socket,
|
|
32
|
+
close: () => socket.disconnect(),
|
|
33
|
+
resync: () => { if (socket.connected)
|
|
34
|
+
socket.emit('launcher:register', { agentIds: agentIds() }); },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { type MessageHandler } from '../types.js';
|
|
3
|
+
export interface WebSocketClientOptions {
|
|
4
|
+
wsUrl?: string;
|
|
5
|
+
operatorKey?: string;
|
|
6
|
+
agentId?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional user JWT (from `POST /users/login`). When set, the socket
|
|
9
|
+
* authenticates as that user — the gateway populates `socket.userId` and
|
|
10
|
+
* routes messages to them as a human user. Mutually exclusive with
|
|
11
|
+
* `operatorKey` + `agentId`. Used by the eval harness to seed chats as a
|
|
12
|
+
* real user instead of impersonating an agent.
|
|
13
|
+
*/
|
|
14
|
+
userToken?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Mirrors the backend `ResourceEvent` shape. Emitted on the wire as
|
|
19
|
+
* `resource_changed` when a resource the agent has access to mutates.
|
|
20
|
+
*/
|
|
21
|
+
export interface ResourceEvent {
|
|
22
|
+
kind: 'message' | 'artifact' | 'task-state' | 'agreement';
|
|
23
|
+
ts: string;
|
|
24
|
+
resourceId: string;
|
|
25
|
+
chatId?: string;
|
|
26
|
+
agreementId?: string;
|
|
27
|
+
taskId?: string;
|
|
28
|
+
change?: 'created' | 'updated' | 'state-changed';
|
|
29
|
+
reason?: string;
|
|
30
|
+
}
|
|
31
|
+
export type ResourceEventHandler = (event: ResourceEvent) => void | Promise<void>;
|
|
32
|
+
export interface SendOptions {
|
|
33
|
+
entryType?: string;
|
|
34
|
+
content_type?: string;
|
|
35
|
+
contentType?: string;
|
|
36
|
+
taskId?: string;
|
|
37
|
+
/**
|
|
38
|
+
* When true, emits a 'chat:chunk' event instead of 'chat'.
|
|
39
|
+
* Use for streaming partial responses; send a final message
|
|
40
|
+
* (partial: false or omitted) to signal end of stream.
|
|
41
|
+
* Requires backend streaming support.
|
|
42
|
+
*/
|
|
43
|
+
partial?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare class WebSocketClient {
|
|
46
|
+
private wsUrl;
|
|
47
|
+
private operatorKey;
|
|
48
|
+
private agentId;
|
|
49
|
+
private userToken;
|
|
50
|
+
private label;
|
|
51
|
+
private socket;
|
|
52
|
+
private messageHandler;
|
|
53
|
+
private resourceEventHandler;
|
|
54
|
+
constructor(options?: WebSocketClientOptions);
|
|
55
|
+
setMessageHandler(handler: MessageHandler): void;
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to `resource_changed` notifications — the unified push channel
|
|
58
|
+
* for non-message resource changes (artifact, task-state, agreement). The
|
|
59
|
+
* agent decides whether to pull the corresponding primitive based on
|
|
60
|
+
* `event.kind` + ids. Replaces cursor-based polling for delta detection.
|
|
61
|
+
*/
|
|
62
|
+
setResourceEventHandler(handler: ResourceEventHandler): void;
|
|
63
|
+
private _connect;
|
|
64
|
+
connectAsync(timeout?: number): Promise<this>;
|
|
65
|
+
disconnect(): void;
|
|
66
|
+
send(chatId: string, receiverId: string, content: string, options?: SendOptions): void;
|
|
67
|
+
isConnected(): boolean;
|
|
68
|
+
handleIncomingMessage(payload: unknown): Promise<void>;
|
|
69
|
+
private buildSocketOptions;
|
|
70
|
+
private generateMessageId;
|
|
71
|
+
}
|