@bpmsoftwaresolutions/ai-engine-client 1.1.71 → 1.1.74
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 +118 -0
- package/package.json +1 -1
- package/src/client.js +11633 -0
- package/src/constants/agent-communications.js +40 -0
- package/src/constants/client.js +18 -0
- package/src/constants/governance.js +17 -0
- package/src/constants/loga.js +4 -0
- package/src/domains/actions.js +5 -0
- package/src/domains/benchmarks.js +13 -0
- package/src/domains/capabilities.js +7 -0
- package/src/domains/context-assembly.js +10 -0
- package/src/domains/database/backups.js +11 -0
- package/src/domains/database.js +14 -0
- package/src/domains/design-intelligence.js +16 -0
- package/src/domains/execution-telemetry.js +8 -0
- package/src/domains/gateway.js +8 -0
- package/src/domains/health.js +5 -0
- package/src/domains/implementation-tasks.js +10 -0
- package/src/domains/loga.js +13 -0
- package/src/domains/notes-lab.js +7 -0
- package/src/domains/operator/current-project.js +5 -0
- package/src/domains/operator-status.js +15 -0
- package/src/domains/performance.js +8 -0
- package/src/domains/projections.js +13 -0
- package/src/domains/repo.js +25 -0
- package/src/domains/reports.js +5 -0
- package/src/domains/retrieval-management.js +14 -0
- package/src/domains/retrieval-wrapper.js +7 -0
- package/src/domains/script-discovery.js +9 -0
- package/src/domains/scripts.js +8 -0
- package/src/domains/search-contacts.js +7 -0
- package/src/domains/self-learning.js +10 -0
- package/src/domains/self-optimization.js +8 -0
- package/src/domains/skill-governance.js +7 -0
- package/src/domains/skills.js +13 -0
- package/src/domains/tool-registry.js +14 -0
- package/src/index.js +14 -6455
- package/src/transport/index.js +176 -0
- package/src/utils/http.js +83 -0
- package/src/utils/text.js +30 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { appendQuery, extractLogaProjectionMetadata, isJsonBody, parseContentDispositionFilename, readJson } from '../utils/http.js';
|
|
2
|
+
|
|
3
|
+
export async function resolveAccessToken(client) {
|
|
4
|
+
if (typeof client.tokenProvider === 'function') {
|
|
5
|
+
const provided = await client.tokenProvider();
|
|
6
|
+
if (!provided) return null;
|
|
7
|
+
if (typeof provided === 'string') return provided;
|
|
8
|
+
if (typeof provided === 'object' && typeof provided.token === 'string') return provided.token;
|
|
9
|
+
if (typeof provided === 'object' && typeof provided.accessToken === 'string') return provided.accessToken;
|
|
10
|
+
throw new Error('tokenProvider must return a token string or an object with a token or accessToken field.');
|
|
11
|
+
}
|
|
12
|
+
return client.accessToken;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function buildHeaders(client, { headers, body, accept }) {
|
|
16
|
+
const token = await resolveAccessToken(client);
|
|
17
|
+
const resolvedHeaders = {
|
|
18
|
+
accept: accept || 'application/json',
|
|
19
|
+
'x-actor-id': client.actorId,
|
|
20
|
+
...(client.agentSessionId ? { 'x-agent-session-id': client.agentSessionId } : {}),
|
|
21
|
+
'x-ai-engine-client-version': client.clientVersion,
|
|
22
|
+
'x-ai-engine-client-capabilities': client.clientCapabilities.join(','),
|
|
23
|
+
...(isJsonBody(body) ? { 'content-type': 'application/json' } : {}),
|
|
24
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
25
|
+
...(!token && client.clientId ? { 'x-client-id': client.clientId } : {}),
|
|
26
|
+
...(!token && client.apiKey ? { 'x-api-key': client.apiKey } : {}),
|
|
27
|
+
...headers,
|
|
28
|
+
};
|
|
29
|
+
for (const [key, value] of Object.entries(resolvedHeaders)) {
|
|
30
|
+
if (value === undefined) delete resolvedHeaders[key];
|
|
31
|
+
}
|
|
32
|
+
return resolvedHeaders;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function requestJson(client, path, { method = 'GET', query, headers, body } = {}) {
|
|
36
|
+
const url = appendQuery(`${client.baseUrl}${path}`, query);
|
|
37
|
+
const controller = new AbortController();
|
|
38
|
+
const timeoutHandle = setTimeout(() => controller.abort(), client.timeoutMs);
|
|
39
|
+
try {
|
|
40
|
+
const resolvedHeaders = await buildHeaders(client, { headers, body, accept: 'application/json' });
|
|
41
|
+
const response = await client.fetchImpl(url, {
|
|
42
|
+
method,
|
|
43
|
+
headers: resolvedHeaders,
|
|
44
|
+
body: isJsonBody(body) ? JSON.stringify(body) : body,
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
});
|
|
47
|
+
const payload = await readJson(response);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const error = new Error(payload?.message || payload?.error || `Request failed with status ${response.status}.`);
|
|
50
|
+
error.status = response.status;
|
|
51
|
+
error.payload = payload;
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
return payload;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error?.name === 'AbortError') {
|
|
57
|
+
const timeoutError = new Error(`Request to ${url.pathname} timed out after ${client.timeoutMs}ms.`);
|
|
58
|
+
timeoutError.code = 'REQUEST_TIMEOUT';
|
|
59
|
+
timeoutError.status = 0;
|
|
60
|
+
throw timeoutError;
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
} finally {
|
|
64
|
+
clearTimeout(timeoutHandle);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function requestText(client, path, { method = 'GET', query, headers, body } = {}) {
|
|
69
|
+
const url = appendQuery(`${client.baseUrl}${path}`, query);
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
const timeoutHandle = setTimeout(() => controller.abort(), client.timeoutMs);
|
|
72
|
+
try {
|
|
73
|
+
const resolvedHeaders = await buildHeaders(client, {
|
|
74
|
+
headers,
|
|
75
|
+
body,
|
|
76
|
+
accept: 'text/markdown, text/plain;q=0.9, application/json;q=0.8',
|
|
77
|
+
});
|
|
78
|
+
const response = await client.fetchImpl(url, {
|
|
79
|
+
method,
|
|
80
|
+
headers: resolvedHeaders,
|
|
81
|
+
body: isJsonBody(body) ? JSON.stringify(body) : body,
|
|
82
|
+
signal: controller.signal,
|
|
83
|
+
});
|
|
84
|
+
const contentType = response.headers.get('content-type') || '';
|
|
85
|
+
const contentDisposition = response.headers.get('content-disposition') || '';
|
|
86
|
+
const readResponseText = async () => {
|
|
87
|
+
if (typeof response.text === 'function') {
|
|
88
|
+
return response.text();
|
|
89
|
+
}
|
|
90
|
+
if (typeof response.json === 'function') {
|
|
91
|
+
const payload = await response.json();
|
|
92
|
+
return typeof payload === 'string' ? payload : JSON.stringify(payload);
|
|
93
|
+
}
|
|
94
|
+
return '';
|
|
95
|
+
};
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
const payload = contentType.includes('application/json')
|
|
98
|
+
? await response.json()
|
|
99
|
+
: { message: await readResponseText() };
|
|
100
|
+
const error = new Error(payload?.message || payload?.error || `Request failed with status ${response.status}.`);
|
|
101
|
+
error.status = response.status;
|
|
102
|
+
error.payload = payload;
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
text: await readResponseText(),
|
|
107
|
+
contentType,
|
|
108
|
+
fileName: parseContentDispositionFilename(contentDisposition),
|
|
109
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
110
|
+
};
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (error?.name === 'AbortError') {
|
|
113
|
+
const timeoutError = new Error(`Request to ${url.pathname} timed out after ${client.timeoutMs}ms.`);
|
|
114
|
+
timeoutError.code = 'REQUEST_TIMEOUT';
|
|
115
|
+
timeoutError.status = 0;
|
|
116
|
+
throw timeoutError;
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
} finally {
|
|
120
|
+
clearTimeout(timeoutHandle);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function requestLogaProjection(client, path, options = {}) {
|
|
125
|
+
const result = await requestText(client, path, options);
|
|
126
|
+
return {
|
|
127
|
+
...result,
|
|
128
|
+
...extractLogaProjectionMetadata(new Headers(result.headers || {})),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function requestBinary(client, path, { method = 'GET', query, headers, body } = {}) {
|
|
133
|
+
const url = appendQuery(`${client.baseUrl}${path}`, query);
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
const timeoutHandle = setTimeout(() => controller.abort(), client.timeoutMs);
|
|
136
|
+
try {
|
|
137
|
+
const resolvedHeaders = await buildHeaders(client, {
|
|
138
|
+
headers,
|
|
139
|
+
body,
|
|
140
|
+
accept: 'audio/mpeg, application/octet-stream;q=0.9, application/json;q=0.8',
|
|
141
|
+
});
|
|
142
|
+
const response = await client.fetchImpl(url, {
|
|
143
|
+
method,
|
|
144
|
+
headers: resolvedHeaders,
|
|
145
|
+
body: isJsonBody(body) ? JSON.stringify(body) : body,
|
|
146
|
+
signal: controller.signal,
|
|
147
|
+
});
|
|
148
|
+
const contentType = response.headers.get('content-type') || '';
|
|
149
|
+
const contentDisposition = response.headers.get('content-disposition') || '';
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const payload = contentType.includes('application/json')
|
|
152
|
+
? await response.json()
|
|
153
|
+
: { message: await response.text() };
|
|
154
|
+
const error = new Error(payload?.message || payload?.error || `Request failed with status ${response.status}.`);
|
|
155
|
+
error.status = response.status;
|
|
156
|
+
error.payload = payload;
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
160
|
+
return {
|
|
161
|
+
arrayBuffer,
|
|
162
|
+
contentType,
|
|
163
|
+
fileName: parseContentDispositionFilename(contentDisposition),
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (error?.name === 'AbortError') {
|
|
167
|
+
const timeoutError = new Error(`Request to ${url.pathname} timed out after ${client.timeoutMs}ms.`);
|
|
168
|
+
timeoutError.code = 'REQUEST_TIMEOUT';
|
|
169
|
+
timeoutError.status = 0;
|
|
170
|
+
throw timeoutError;
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
} finally {
|
|
174
|
+
clearTimeout(timeoutHandle);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export function appendQuery(url, query) {
|
|
2
|
+
const target = new URL(url);
|
|
3
|
+
for (const [key, value] of Object.entries(query || {})) {
|
|
4
|
+
if (value === undefined || value === null || value === '') continue;
|
|
5
|
+
target.searchParams.set(key, String(value));
|
|
6
|
+
}
|
|
7
|
+
return target;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function parseContentDispositionFilename(headerValue) {
|
|
11
|
+
const value = String(headerValue || '');
|
|
12
|
+
const quotedMatch = value.match(/filename="([^"]+)"/i);
|
|
13
|
+
if (quotedMatch) return quotedMatch[1];
|
|
14
|
+
const plainMatch = value.match(/filename=([^;]+)/i);
|
|
15
|
+
return plainMatch ? plainMatch[1].trim() : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function readResponseHeader(headers, name) {
|
|
19
|
+
if (!headers || typeof headers.get !== 'function') return null;
|
|
20
|
+
return headers.get(name) || headers.get(name.toLowerCase()) || null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function extractLogaProjectionMetadata(headers) {
|
|
24
|
+
const projectionWorkflow = readResponseHeader(headers, 'x-projection-workflow');
|
|
25
|
+
const projectionVersion = readResponseHeader(headers, 'x-projection-version');
|
|
26
|
+
const sourceVersion = readResponseHeader(headers, 'x-source-version');
|
|
27
|
+
const correlationId = readResponseHeader(headers, 'x-correlation-id');
|
|
28
|
+
const logaContract = readResponseHeader(headers, 'x-loga-contract');
|
|
29
|
+
const navigationContract = readResponseHeader(headers, 'x-navigation-contract');
|
|
30
|
+
const projectionType = readResponseHeader(headers, 'x-projection-type');
|
|
31
|
+
const sourceTruth = readResponseHeader(headers, 'x-source-truth');
|
|
32
|
+
const refreshPolicy = readResponseHeader(headers, 'x-refresh-policy');
|
|
33
|
+
const generatedAt = readResponseHeader(headers, 'x-generated-at');
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
logaContract,
|
|
37
|
+
navigationContract,
|
|
38
|
+
interactionContract: 'loga-choreography/v1',
|
|
39
|
+
projectionType,
|
|
40
|
+
projectionWorkflow,
|
|
41
|
+
projectionVersion,
|
|
42
|
+
sourceTruth,
|
|
43
|
+
sourceVersion,
|
|
44
|
+
correlationId,
|
|
45
|
+
refreshPolicy,
|
|
46
|
+
generatedAt,
|
|
47
|
+
provenance: {
|
|
48
|
+
sourceTruth,
|
|
49
|
+
sourceVersion,
|
|
50
|
+
projectionVersion,
|
|
51
|
+
projectionWorkflow,
|
|
52
|
+
correlationId,
|
|
53
|
+
generatedAt,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isFormDataBody(value) {
|
|
59
|
+
return typeof FormData !== 'undefined' && value instanceof FormData;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function isBinaryBody(value) {
|
|
63
|
+
return (
|
|
64
|
+
value instanceof ArrayBuffer
|
|
65
|
+
|| ArrayBuffer.isView(value)
|
|
66
|
+
|| (typeof Blob !== 'undefined' && value instanceof Blob)
|
|
67
|
+
|| value instanceof URLSearchParams
|
|
68
|
+
|| typeof value === 'string'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isJsonBody(value) {
|
|
73
|
+
if (value === undefined || value === null) return false;
|
|
74
|
+
if (isFormDataBody(value) || isBinaryBody(value)) return false;
|
|
75
|
+
return typeof value === 'object';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function readJson(response) {
|
|
79
|
+
const contentType = response.headers.get('content-type') || '';
|
|
80
|
+
if (contentType.includes('application/json')) return response.json();
|
|
81
|
+
const text = await response.text();
|
|
82
|
+
return { message: text };
|
|
83
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function cleanText(value) {
|
|
2
|
+
const text = String(value || '').trim();
|
|
3
|
+
return text || null;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function cleanList(value) {
|
|
7
|
+
if (!Array.isArray(value)) return [];
|
|
8
|
+
return value.map(cleanText).filter(Boolean);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isPlainObject(value) {
|
|
12
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function trimTrailingSlash(value) {
|
|
16
|
+
return String(value || '').replace(/\/+$/, '');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function normalizeEnum(value, allowed, defaultValue, fieldName, aliases = {}) {
|
|
20
|
+
const text = cleanText(value);
|
|
21
|
+
if (!text) return defaultValue;
|
|
22
|
+
let normalized = text.toLowerCase();
|
|
23
|
+
if (Object.prototype.hasOwnProperty.call(aliases, normalized)) {
|
|
24
|
+
normalized = aliases[normalized];
|
|
25
|
+
}
|
|
26
|
+
if (!allowed.includes(normalized)) {
|
|
27
|
+
throw new Error(`${fieldName} must be one of ${allowed.join(', ')}.`);
|
|
28
|
+
}
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|