@ziggs-ai/api-client 0.1.5 → 0.1.7
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/package.json +20 -14
- package/src/ConnectionManager.ts +0 -172
- package/src/http/AgentSearchClient.ts +0 -115
- package/src/http/AgreementClient.ts +0 -721
- package/src/http/ArtifactsClient.ts +0 -133
- package/src/http/ChatClient.ts +0 -147
- package/src/http/ContextDiscoveryClient.ts +0 -52
- package/src/http/ContextReadClient.ts +0 -83
- package/src/http/MarketplaceClient.ts +0 -94
- package/src/http/MessagesClient.ts +0 -71
- package/src/http/ScopeClient.ts +0 -64
- package/src/http/TaskClient.ts +0 -450
- package/src/http/TelemetryClient.ts +0 -57
- package/src/http/index.ts +0 -26
- package/src/index.ts +0 -27
- package/src/shared/runtimeLog.ts +0 -68
- package/src/types.ts +0 -158
- package/src/utils/urlUtils.ts +0 -9
- package/src/websocket/ControlSocket.ts +0 -51
- package/src/websocket/WebSocketClient.ts +0 -315
- package/src/websocket/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/api-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "HTTP and WebSocket client for the Ziggs backend API",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./http": {
|
|
15
|
+
"types": "./dist/http/index.d.ts",
|
|
16
|
+
"import": "./dist/http/index.js",
|
|
17
|
+
"default": "./dist/http/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./websocket": {
|
|
20
|
+
"types": "./dist/websocket/index.d.ts",
|
|
21
|
+
"import": "./dist/websocket/index.js",
|
|
22
|
+
"default": "./dist/websocket/index.js"
|
|
23
|
+
}
|
|
11
24
|
},
|
|
12
25
|
"engines": {
|
|
13
26
|
"node": ">=18"
|
|
@@ -24,16 +37,9 @@
|
|
|
24
37
|
},
|
|
25
38
|
"keywords": ["ziggs", "api", "client", "websocket"],
|
|
26
39
|
"license": "MIT",
|
|
27
|
-
"files": ["dist", "
|
|
40
|
+
"files": ["dist", "README.md"],
|
|
28
41
|
"publishConfig": {
|
|
29
42
|
"access": "public",
|
|
30
|
-
"registry": "https://registry.npmjs.org/"
|
|
31
|
-
"main": "dist/index.js",
|
|
32
|
-
"types": "dist/index.d.ts",
|
|
33
|
-
"exports": {
|
|
34
|
-
".": "./dist/index.js",
|
|
35
|
-
"./http": "./dist/http/index.js",
|
|
36
|
-
"./websocket": "./dist/websocket/index.js"
|
|
37
|
-
}
|
|
43
|
+
"registry": "https://registry.npmjs.org/"
|
|
38
44
|
}
|
|
39
45
|
}
|
package/src/ConnectionManager.ts
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { createControlSocket, type ControlSocketOptions, type ControlSocketHandle } from './websocket/ControlSocket.js';
|
|
2
|
-
import { runtimeLog } from './shared/runtimeLog.js';
|
|
3
|
-
|
|
4
|
-
type OpenFn = () => Promise<unknown>;
|
|
5
|
-
type CloseFn = (handle: unknown) => Promise<void>;
|
|
6
|
-
|
|
7
|
-
interface Entry {
|
|
8
|
-
openFn: OpenFn;
|
|
9
|
-
closeFn: CloseFn;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface ActiveEntry {
|
|
13
|
-
handle: unknown;
|
|
14
|
-
timer: ReturnType<typeof setTimeout> | null;
|
|
15
|
-
lastActive: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ConnectionManagerMeta {
|
|
19
|
-
domain?: string;
|
|
20
|
-
expertise?: string[];
|
|
21
|
-
tags?: string[];
|
|
22
|
-
[key: string]: unknown;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ConnectionManagerOptions {
|
|
26
|
-
maxActive?: number;
|
|
27
|
-
idleTimeoutMs?: number;
|
|
28
|
-
control?: Pick<ControlSocketOptions, 'wsUrl' | 'operatorKey'>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface QueryFilter {
|
|
32
|
-
domain?: string;
|
|
33
|
-
expertise?: string[];
|
|
34
|
-
tags?: string[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class ConnectionManager {
|
|
38
|
-
private maxActive: number;
|
|
39
|
-
private idleTimeoutMs: number;
|
|
40
|
-
private _controlOpts: Pick<ControlSocketOptions, 'wsUrl' | 'operatorKey'> | null;
|
|
41
|
-
private _controlHandle: ControlSocketHandle | null;
|
|
42
|
-
private _entries: Map<string, Entry>;
|
|
43
|
-
private _active: Map<string, ActiveEntry>;
|
|
44
|
-
private _meta: Map<string, ConnectionManagerMeta>;
|
|
45
|
-
private _waking: Map<string, Promise<unknown>>;
|
|
46
|
-
|
|
47
|
-
constructor({ maxActive = 50, idleTimeoutMs = 60_000, control }: ConnectionManagerOptions = {}) {
|
|
48
|
-
this.maxActive = maxActive;
|
|
49
|
-
this.idleTimeoutMs = idleTimeoutMs;
|
|
50
|
-
this._controlOpts = control ?? null;
|
|
51
|
-
this._controlHandle = null;
|
|
52
|
-
this._entries = new Map();
|
|
53
|
-
this._active = new Map();
|
|
54
|
-
this._meta = new Map();
|
|
55
|
-
this._waking = new Map();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
register(id: string, openFn: OpenFn, closeFn: CloseFn, meta?: ConnectionManagerMeta): void {
|
|
59
|
-
if (!id) throw new Error('[ConnectionManager] id is required');
|
|
60
|
-
if (typeof openFn !== 'function') throw new Error('[ConnectionManager] openFn must be a function');
|
|
61
|
-
if (typeof closeFn !== 'function') throw new Error('[ConnectionManager] closeFn must be a function');
|
|
62
|
-
this._entries.set(id, { openFn, closeFn });
|
|
63
|
-
if (meta) this._meta.set(id, meta);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
start(): void {
|
|
67
|
-
if (this._controlHandle || !this._controlOpts) return;
|
|
68
|
-
this._controlHandle = createControlSocket({
|
|
69
|
-
...this._controlOpts,
|
|
70
|
-
agentIds: () => this.list(),
|
|
71
|
-
onWake: (id) =>
|
|
72
|
-
this.wake(id).catch(err =>
|
|
73
|
-
runtimeLog.warn('ConnectionManager', `wake("${id}") failed: ${(err as Error).message}`),
|
|
74
|
-
),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async stop(): Promise<void> {
|
|
79
|
-
this._controlHandle?.close();
|
|
80
|
-
this._controlHandle = null;
|
|
81
|
-
await this.sleepAll();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async wake(id: string): Promise<unknown> {
|
|
85
|
-
const existing = this._active.get(id);
|
|
86
|
-
if (existing) {
|
|
87
|
-
this._resetTimer(id);
|
|
88
|
-
return existing.handle;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const pending = this._waking.get(id);
|
|
92
|
-
if (pending) return pending;
|
|
93
|
-
|
|
94
|
-
const entry = this._entries.get(id);
|
|
95
|
-
if (!entry) throw new Error(`[ConnectionManager] unknown id: "${id}"`);
|
|
96
|
-
|
|
97
|
-
if (this._active.size >= this.maxActive) await this._evictLRU();
|
|
98
|
-
|
|
99
|
-
const wakePromise = (async () => {
|
|
100
|
-
try {
|
|
101
|
-
const handle = await entry.openFn();
|
|
102
|
-
this._active.set(id, { handle, timer: null, lastActive: Date.now() });
|
|
103
|
-
this._scheduleIdle(id);
|
|
104
|
-
return handle;
|
|
105
|
-
} finally {
|
|
106
|
-
this._waking.delete(id);
|
|
107
|
-
}
|
|
108
|
-
})();
|
|
109
|
-
|
|
110
|
-
this._waking.set(id, wakePromise);
|
|
111
|
-
return wakePromise;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async sleep(id: string): Promise<void> {
|
|
115
|
-
const entry = this._active.get(id);
|
|
116
|
-
if (!entry) return;
|
|
117
|
-
clearTimeout(entry.timer!);
|
|
118
|
-
this._active.delete(id);
|
|
119
|
-
const reg = this._entries.get(id);
|
|
120
|
-
if (reg) await reg.closeFn(entry.handle);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async sleepAll(): Promise<void> {
|
|
124
|
-
await Promise.all([...this._active.keys()].map(id => this.sleep(id)));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
touch(id: string): void { this._resetTimer(id); }
|
|
128
|
-
|
|
129
|
-
list(): string[] { return [...this._entries.keys()]; }
|
|
130
|
-
listActive(): string[] { return [...this._active.keys()]; }
|
|
131
|
-
get size(): number { return this._entries.size; }
|
|
132
|
-
|
|
133
|
-
query({ domain, expertise, tags }: QueryFilter = {}): string[] {
|
|
134
|
-
const results: string[] = [];
|
|
135
|
-
for (const [id, meta] of this._meta) {
|
|
136
|
-
if (domain && meta.domain !== domain) continue;
|
|
137
|
-
if (expertise?.length && !expertise.some(e => meta.expertise?.includes(e))) continue;
|
|
138
|
-
if (tags?.length && !tags.some(t => meta.tags?.includes(t))) continue;
|
|
139
|
-
results.push(id);
|
|
140
|
-
}
|
|
141
|
-
return results;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
getMeta(id: string): ConnectionManagerMeta | undefined { return this._meta.get(id); }
|
|
145
|
-
|
|
146
|
-
private _scheduleIdle(id: string): void {
|
|
147
|
-
const entry = this._active.get(id);
|
|
148
|
-
if (!entry) return;
|
|
149
|
-
clearTimeout(entry.timer!);
|
|
150
|
-
entry.timer = setTimeout(() => {
|
|
151
|
-
this.sleep(id).catch(err =>
|
|
152
|
-
runtimeLog.warn('ConnectionManager', `idle sleep("${id}") failed: ${(err as Error).message}`),
|
|
153
|
-
);
|
|
154
|
-
}, this.idleTimeoutMs);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private _resetTimer(id: string): void {
|
|
158
|
-
const entry = this._active.get(id);
|
|
159
|
-
if (!entry) return;
|
|
160
|
-
entry.lastActive = Date.now();
|
|
161
|
-
this._scheduleIdle(id);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private async _evictLRU(): Promise<void> {
|
|
165
|
-
let oldest: string | null = null;
|
|
166
|
-
for (const [id, entry] of this._active) {
|
|
167
|
-
const oldestEntry = oldest ? this._active.get(oldest) : null;
|
|
168
|
-
if (!oldest || !oldestEntry || entry.lastActive < oldestEntry.lastActive) oldest = id;
|
|
169
|
-
}
|
|
170
|
-
if (oldest) await this.sleep(oldest);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
-
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
|
-
|
|
5
|
-
export interface AgentSearchOptions {
|
|
6
|
-
limit?: number;
|
|
7
|
-
minScore?: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface AgentSearchResult {
|
|
11
|
-
success: boolean;
|
|
12
|
-
agents?: AgentProfile[];
|
|
13
|
-
error?: string;
|
|
14
|
-
message?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface AgentProfile {
|
|
18
|
-
agentId: string;
|
|
19
|
-
name: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
tags?: string[];
|
|
22
|
-
matchScore?: number;
|
|
23
|
-
reliability?: {
|
|
24
|
-
sampleSize: number;
|
|
25
|
-
band: string;
|
|
26
|
-
medianResponseMs: number;
|
|
27
|
-
lastActivityDaysAgo: number;
|
|
28
|
-
};
|
|
29
|
-
category?: string;
|
|
30
|
-
version?: string;
|
|
31
|
-
recentTaskSamples?: unknown[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class AgentSearchClient {
|
|
35
|
-
private readonly operatorKey: string;
|
|
36
|
-
private readonly agentId: string;
|
|
37
|
-
private readonly baseUrl: string;
|
|
38
|
-
|
|
39
|
-
constructor(operatorKey: string, agentId: string) {
|
|
40
|
-
if (!operatorKey) throw new Error('AgentSearchClient: operatorKey is required');
|
|
41
|
-
if (!agentId) throw new Error('AgentSearchClient: agentId is required (operator-token impersonation)');
|
|
42
|
-
this.operatorKey = operatorKey;
|
|
43
|
-
this.agentId = agentId;
|
|
44
|
-
this.baseUrl = getBackendUrl();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async searchAgents(query: string, options: AgentSearchOptions = {}): Promise<AgentSearchResult> {
|
|
48
|
-
if (!query || typeof query !== 'string') {
|
|
49
|
-
return { success: false, error: 'query is required' };
|
|
50
|
-
}
|
|
51
|
-
const params = new URLSearchParams({ q: query });
|
|
52
|
-
if (typeof options.limit === 'number') params.set('limit', String(options.limit));
|
|
53
|
-
if (typeof options.minScore === 'number') params.set('minScore', String(options.minScore));
|
|
54
|
-
|
|
55
|
-
const url = `${this.baseUrl}/agent-api/v1/agents/search?${params}`;
|
|
56
|
-
try {
|
|
57
|
-
const response = await fetch(url, { method: 'GET', headers: this._buildHeaders() });
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
const errorText = await response.text().catch(() => '');
|
|
60
|
-
runtimeLog.warn(
|
|
61
|
-
'AgentSearchClient',
|
|
62
|
-
`⚠️ searchAgents failed agent=${this.agentId} ${response.status} ${response.statusText} url=${url} body=${errorText.slice(0, 200)}`,
|
|
63
|
-
);
|
|
64
|
-
return { success: false, error: `Search failed: ${response.status}`, message: errorText };
|
|
65
|
-
}
|
|
66
|
-
const { results = [] } = await response.json() as { results: AgentProfile[] };
|
|
67
|
-
return { success: true, agents: results };
|
|
68
|
-
} catch (error) {
|
|
69
|
-
runtimeLog.warn(
|
|
70
|
-
'AgentSearchClient',
|
|
71
|
-
`⚠️ searchAgents error agent=${this.agentId} url=${url} message=${(error as Error).message}`,
|
|
72
|
-
);
|
|
73
|
-
return { success: false, error: (error as Error).message || 'Failed to search agents' };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async getAgentById(agentId: string): Promise<AgentSearchResult & Partial<AgentProfile>> {
|
|
78
|
-
if (!agentId) return { success: false, error: 'agentId is required' };
|
|
79
|
-
const url = `${this.baseUrl}/agent-api/v1/agents/${encodeURIComponent(agentId)}`;
|
|
80
|
-
try {
|
|
81
|
-
const response = await fetch(url, { method: 'GET', headers: this._buildHeaders() });
|
|
82
|
-
if (response.status === 404) {
|
|
83
|
-
runtimeLog.warn(
|
|
84
|
-
'AgentSearchClient',
|
|
85
|
-
`⚠️ getAgentById 404 agent=${this.agentId} target=${agentId} url=${url}`,
|
|
86
|
-
);
|
|
87
|
-
return { success: false, error: 'agent not found' };
|
|
88
|
-
}
|
|
89
|
-
if (!response.ok) {
|
|
90
|
-
const body = await response.text().catch(() => '');
|
|
91
|
-
runtimeLog.warn(
|
|
92
|
-
'AgentSearchClient',
|
|
93
|
-
`⚠️ getAgentById failed agent=${this.agentId} target=${agentId} ${response.status} ${response.statusText} body=${body.slice(0, 200)}`,
|
|
94
|
-
);
|
|
95
|
-
return { success: false, error: `Failed to get agent details: ${response.status}` };
|
|
96
|
-
}
|
|
97
|
-
const agent = await response.json() as AgentProfile;
|
|
98
|
-
return { success: true, ...agent };
|
|
99
|
-
} catch (error) {
|
|
100
|
-
runtimeLog.warn(
|
|
101
|
-
'AgentSearchClient',
|
|
102
|
-
`⚠️ getAgentById error agent=${this.agentId} target=${agentId} url=${url} message=${(error as Error).message}`,
|
|
103
|
-
);
|
|
104
|
-
return { success: false, error: (error as Error).message || 'Failed to get agent details' };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
private _buildHeaders(): Record<string, string> {
|
|
109
|
-
return {
|
|
110
|
-
'Content-Type': 'application/json',
|
|
111
|
-
Authorization: `Bearer ${this.operatorKey}`,
|
|
112
|
-
'X-Agent-Id': this.agentId,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|