@nirmos/sdk 0.1.0 → 0.3.1
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 +88 -32
- package/dist/cjs/client.js +120 -20
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/core/errors.js +4 -2
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/metadata.js +3 -3
- package/dist/cjs/core/metadata.js.map +1 -1
- package/dist/cjs/core/transport.js +36 -9
- package/dist/cjs/core/transport.js.map +1 -1
- package/dist/cjs/gateway/chat.js +18 -3
- package/dist/cjs/gateway/chat.js.map +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/management/contracts.js +3 -0
- package/dist/cjs/management/contracts.js.map +1 -0
- package/dist/cjs/management/execution-types.js +3 -0
- package/dist/cjs/management/execution-types.js.map +1 -0
- package/dist/cjs/management/manifest.js +1535 -0
- package/dist/cjs/management/manifest.js.map +1 -0
- package/dist/cjs/management/resources.js +197 -0
- package/dist/cjs/management/resources.js.map +1 -0
- package/dist/cjs/memory/memory.js +68 -0
- package/dist/cjs/memory/memory.js.map +1 -0
- package/dist/cjs/memory/types.js +3 -0
- package/dist/cjs/memory/types.js.map +1 -0
- package/dist/esm/client.d.ts +154 -13
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +119 -20
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/core/errors.d.ts +4 -0
- package/dist/esm/core/errors.d.ts.map +1 -1
- package/dist/esm/core/errors.js +4 -2
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/metadata.d.ts.map +1 -1
- package/dist/esm/core/metadata.js +3 -3
- package/dist/esm/core/metadata.js.map +1 -1
- package/dist/esm/core/transport.d.ts +9 -2
- package/dist/esm/core/transport.d.ts.map +1 -1
- package/dist/esm/core/transport.js +36 -9
- package/dist/esm/core/transport.js.map +1 -1
- package/dist/esm/gateway/chat.d.ts.map +1 -1
- package/dist/esm/gateway/chat.js +18 -3
- package/dist/esm/gateway/chat.js.map +1 -1
- package/dist/esm/gateway/types.d.ts +18 -2
- package/dist/esm/gateway/types.d.ts.map +1 -1
- package/dist/esm/index.d.ts +6 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/management/contracts.d.ts +18813 -0
- package/dist/esm/management/contracts.d.ts.map +1 -0
- package/dist/esm/management/contracts.js +2 -0
- package/dist/esm/management/contracts.js.map +1 -0
- package/dist/esm/management/execution-types.d.ts +246 -0
- package/dist/esm/management/execution-types.d.ts.map +1 -0
- package/dist/esm/management/execution-types.js +2 -0
- package/dist/esm/management/execution-types.js.map +1 -0
- package/dist/esm/management/manifest.d.ts +1339 -0
- package/dist/esm/management/manifest.d.ts.map +1 -0
- package/dist/esm/management/manifest.js +1532 -0
- package/dist/esm/management/manifest.js.map +1 -0
- package/dist/esm/management/resources.d.ts +288 -0
- package/dist/esm/management/resources.d.ts.map +1 -0
- package/dist/esm/management/resources.js +194 -0
- package/dist/esm/management/resources.js.map +1 -0
- package/dist/esm/memory/memory.d.ts +35 -0
- package/dist/esm/memory/memory.d.ts.map +1 -0
- package/dist/esm/memory/memory.js +64 -0
- package/dist/esm/memory/memory.js.map +1 -0
- package/dist/esm/memory/types.d.ts +135 -0
- package/dist/esm/memory/types.d.ts.map +1 -0
- package/dist/esm/memory/types.js +2 -0
- package/dist/esm/memory/types.js.map +1 -0
- package/package.json +2 -2
- package/src/client.ts +319 -36
- package/src/core/errors.ts +8 -2
- package/src/core/metadata.ts +3 -12
- package/src/core/transport.ts +47 -11
- package/src/gateway/chat.ts +23 -3
- package/src/gateway/types.ts +22 -2
- package/src/index.ts +58 -2
- package/src/management/contracts.ts +1084 -0
- package/src/management/execution-types.ts +10 -0
- package/src/management/manifest.ts +1531 -0
- package/src/management/resources.ts +196 -0
- package/src/memory/memory.ts +108 -0
- package/src/memory/types.ts +157 -0
package/src/client.ts
CHANGED
|
@@ -1,70 +1,303 @@
|
|
|
1
|
-
import { ConfigurationError } from "./core/errors.js";
|
|
1
|
+
import { ConfigurationError, type APIError } from "./core/errors.js";
|
|
2
2
|
import { HttpTransport } from "./core/transport.js";
|
|
3
|
-
import type { HeadersInput } from "./core/types.js";
|
|
3
|
+
import type { HeadersInput, RequestOptions } from "./core/types.js";
|
|
4
|
+
import { Memory } from "./memory/memory.js";
|
|
4
5
|
import { Gateway } from "./gateway/gateway.js";
|
|
5
6
|
import { Prompts } from "./prompts/prompts.js";
|
|
6
7
|
import type { PromptCacheConfig } from "./prompts/types.js";
|
|
8
|
+
import {
|
|
9
|
+
managementResources,
|
|
10
|
+
type ManagementResources,
|
|
11
|
+
} from "./management/resources.js";
|
|
12
|
+
import type {
|
|
13
|
+
StartEvaluationRunRequest,
|
|
14
|
+
RunMutationResponse,
|
|
15
|
+
EvaluationRun,
|
|
16
|
+
EvaluationRunResults,
|
|
17
|
+
EvaluationRunCases,
|
|
18
|
+
EvaluationRunCaseDetail,
|
|
19
|
+
EvaluationResultsQuery,
|
|
20
|
+
} from "./management/execution-types.js";
|
|
7
21
|
|
|
22
|
+
export type NirmosAuth =
|
|
23
|
+
| { type: "browser-session" }
|
|
24
|
+
| { type: "api-key"; key: string }
|
|
25
|
+
| { type: "access-token"; token: string };
|
|
8
26
|
export interface NirmosOptions {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
baseUrl?: string;
|
|
13
|
-
/** Default request timeout. Defaults to 60 seconds. Set to 0 to disable. */
|
|
27
|
+
auth: NirmosAuth;
|
|
28
|
+
apiBaseUrl?: string;
|
|
29
|
+
runtimeBaseUrl?: string;
|
|
14
30
|
timeoutMs?: number;
|
|
15
|
-
/** Retry count for safe GET requests. Defaults to 2. */
|
|
16
31
|
maxRetries?: number;
|
|
17
|
-
/** Custom fetch implementation for tests or specialized runtimes. */
|
|
18
32
|
fetch?: typeof globalThis.fetch;
|
|
19
|
-
/** Headers added to every request. */
|
|
20
33
|
headers?: HeadersInput;
|
|
21
|
-
/** In-memory managed prompt cache configuration. Set false to disable. */
|
|
22
34
|
promptCache?: PromptCacheConfig | false;
|
|
35
|
+
/** Observe HTTP failures centrally, without changing method error semantics. */
|
|
36
|
+
onError?: (error: APIError) => void;
|
|
23
37
|
}
|
|
24
38
|
|
|
25
39
|
export class Nirmos {
|
|
26
40
|
readonly gateway: Gateway;
|
|
27
|
-
readonly
|
|
41
|
+
readonly auth: ManagementResources["auth"];
|
|
42
|
+
readonly permissions: ManagementResources["permissions"];
|
|
43
|
+
/** Runtime prompt rendering/caching protocol; management uses prompts. */
|
|
44
|
+
readonly managedPrompts: Prompts;
|
|
45
|
+
readonly apiKeys: ManagementResources["apiKeys"];
|
|
46
|
+
readonly invitations: ManagementResources["invitations"];
|
|
47
|
+
readonly logs: ManagementResources["logs"];
|
|
48
|
+
readonly models: ManagementResources["models"];
|
|
49
|
+
readonly observability: ManagementResources["observability"];
|
|
50
|
+
readonly organizations: ManagementResources["organizations"];
|
|
51
|
+
readonly prompts: ManagementResources["prompts"] & {
|
|
52
|
+
test: (
|
|
53
|
+
body: PromptTestRequest,
|
|
54
|
+
options?: RequestOptions,
|
|
55
|
+
) => Promise<PromptTestResponse>;
|
|
56
|
+
};
|
|
57
|
+
readonly providerCredentials: ManagementResources["providerCredentials"];
|
|
58
|
+
readonly providers: ManagementResources["providers"];
|
|
59
|
+
readonly routes: ManagementResources["routes"];
|
|
60
|
+
readonly traces: ManagementResources["traces"];
|
|
61
|
+
readonly users: ManagementResources["users"];
|
|
62
|
+
readonly vectorStores: ManagementResources["vectorStores"];
|
|
63
|
+
readonly workspace: ManagementResources["workspace"];
|
|
64
|
+
readonly endpoints: ManagementResources["endpoints"] & {
|
|
65
|
+
execute: (
|
|
66
|
+
id: string,
|
|
67
|
+
body: {
|
|
68
|
+
variables?: Record<string, unknown>;
|
|
69
|
+
metadata?: Record<string, unknown>;
|
|
70
|
+
},
|
|
71
|
+
options?: RequestOptions,
|
|
72
|
+
) => Promise<EndpointExecution>;
|
|
73
|
+
};
|
|
74
|
+
readonly memory: Memory;
|
|
75
|
+
readonly knowledge: ManagementResources["knowledge"] & {
|
|
76
|
+
search: (
|
|
77
|
+
id: string,
|
|
78
|
+
body: {
|
|
79
|
+
query: string;
|
|
80
|
+
topK?: number;
|
|
81
|
+
minScore?: number;
|
|
82
|
+
filters?: Record<string, string | number | boolean>;
|
|
83
|
+
},
|
|
84
|
+
options?: RequestOptions,
|
|
85
|
+
) => Promise<KnowledgeMatch[]>;
|
|
86
|
+
};
|
|
87
|
+
readonly evaluations: Omit<ManagementResources["evaluations"], "runs"> & {
|
|
88
|
+
runs: ManagementResources["evaluations"]["runs"] & {
|
|
89
|
+
create: (
|
|
90
|
+
body: StartEvaluationRunRequest,
|
|
91
|
+
options?: RequestOptions,
|
|
92
|
+
) => Promise<RunMutationResponse>;
|
|
93
|
+
get: (id: string, options?: RequestOptions) => Promise<EvaluationRun>;
|
|
94
|
+
cancel: (
|
|
95
|
+
id: string,
|
|
96
|
+
options?: RequestOptions,
|
|
97
|
+
) => Promise<RunMutationResponse>;
|
|
98
|
+
retry: (
|
|
99
|
+
id: string,
|
|
100
|
+
options?: RequestOptions,
|
|
101
|
+
) => Promise<RunMutationResponse>;
|
|
102
|
+
results: (
|
|
103
|
+
id: string,
|
|
104
|
+
query?: EvaluationResultsQuery,
|
|
105
|
+
options?: RequestOptions,
|
|
106
|
+
) => Promise<EvaluationRunResults>;
|
|
107
|
+
cases: (
|
|
108
|
+
id: string,
|
|
109
|
+
query?: Pick<EvaluationResultsQuery, "page" | "pageSize">,
|
|
110
|
+
options?: RequestOptions,
|
|
111
|
+
) => Promise<EvaluationRunCases>;
|
|
112
|
+
case: (
|
|
113
|
+
id: string,
|
|
114
|
+
caseId: string,
|
|
115
|
+
options?: RequestOptions,
|
|
116
|
+
) => Promise<EvaluationRunCaseDetail>;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
28
119
|
|
|
29
120
|
constructor(options: NirmosOptions) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
121
|
+
if (
|
|
122
|
+
!options?.auth ||
|
|
123
|
+
typeof (options.fetch ?? globalThis.fetch) !== "function"
|
|
124
|
+
)
|
|
125
|
+
throw configError("Nirmos auth and a fetch implementation are required.");
|
|
126
|
+
if (options.auth.type === "api-key" && !options.auth.key.trim())
|
|
127
|
+
throw configError("Nirmos API key is required.");
|
|
128
|
+
if (options.auth.type === "access-token" && !options.auth.token.trim())
|
|
129
|
+
throw configError("Nirmos access token is required.");
|
|
130
|
+
const common = {
|
|
131
|
+
apiKey: options.auth.type === "api-key" ? options.auth.key : undefined,
|
|
132
|
+
accessToken:
|
|
133
|
+
options.auth.type === "access-token" ? options.auth.token : undefined,
|
|
134
|
+
credentials:
|
|
135
|
+
options.auth.type === "browser-session"
|
|
136
|
+
? ("include" as const)
|
|
137
|
+
: undefined,
|
|
34
138
|
timeoutMs: nonNegative(options.timeoutMs, 60_000),
|
|
35
139
|
maxRetries: nonNegativeInteger(options.maxRetries, 2),
|
|
36
140
|
fetch: options.fetch ?? globalThis.fetch,
|
|
37
141
|
headers: options.headers,
|
|
142
|
+
onError: options.onError,
|
|
143
|
+
};
|
|
144
|
+
const api = new HttpTransport({
|
|
145
|
+
...common,
|
|
146
|
+
baseUrl: normalizeBaseUrl(options.apiBaseUrl ?? "https://api.nirmos.com"),
|
|
38
147
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
148
|
+
const runtime = new HttpTransport({
|
|
149
|
+
...common,
|
|
150
|
+
runtime: true,
|
|
151
|
+
baseUrl: normalizeBaseUrl(
|
|
152
|
+
options.runtimeBaseUrl ?? "https://gateway.nirmos.com",
|
|
153
|
+
),
|
|
154
|
+
});
|
|
155
|
+
const resources = managementResources(api);
|
|
156
|
+
this.permissions = resources.permissions;
|
|
157
|
+
this.memory = new Memory(resources.memory, runtime);
|
|
158
|
+
this.auth = resources.auth;
|
|
159
|
+
this.apiKeys = resources.apiKeys;
|
|
160
|
+
this.invitations = resources.invitations;
|
|
161
|
+
this.logs = resources.logs;
|
|
162
|
+
this.models = resources.models;
|
|
163
|
+
this.observability = resources.observability;
|
|
164
|
+
this.organizations = resources.organizations;
|
|
165
|
+
this.prompts = {
|
|
166
|
+
...resources.prompts,
|
|
167
|
+
test: async (body, options) =>
|
|
168
|
+
(
|
|
169
|
+
await runtime.request<PromptTestResponse>({
|
|
170
|
+
method: "POST",
|
|
171
|
+
path: "/v1/test/prompt",
|
|
172
|
+
body,
|
|
173
|
+
options,
|
|
174
|
+
})
|
|
175
|
+
).data,
|
|
176
|
+
};
|
|
177
|
+
this.providerCredentials = resources.providerCredentials;
|
|
178
|
+
this.providers = resources.providers;
|
|
179
|
+
this.routes = resources.routes;
|
|
180
|
+
this.traces = resources.traces;
|
|
181
|
+
this.users = resources.users;
|
|
182
|
+
this.vectorStores = resources.vectorStores;
|
|
183
|
+
this.workspace = resources.workspace;
|
|
184
|
+
this.endpoints = {
|
|
185
|
+
...resources.endpoints,
|
|
186
|
+
execute: async (id, body, options) =>
|
|
187
|
+
(
|
|
188
|
+
await runtime.request<EndpointExecution>({
|
|
189
|
+
method: "POST",
|
|
190
|
+
path: `/v1/endpoints/${encodeURIComponent(id)}/execute`,
|
|
191
|
+
body,
|
|
192
|
+
options,
|
|
193
|
+
})
|
|
194
|
+
).data,
|
|
195
|
+
};
|
|
196
|
+
this.knowledge = {
|
|
197
|
+
...resources.knowledge,
|
|
198
|
+
search: (id, body, options) =>
|
|
199
|
+
runtime.data<KnowledgeMatch[]>({
|
|
200
|
+
method: "POST",
|
|
201
|
+
path: `/v1/knowledge-bases/${encodeURIComponent(id)}/search`,
|
|
202
|
+
body,
|
|
203
|
+
options,
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
const runPath = (id: string) =>
|
|
207
|
+
`/v1/evaluations/runs/${encodeURIComponent(id)}`;
|
|
208
|
+
const command = async (
|
|
209
|
+
path: string,
|
|
210
|
+
body: unknown,
|
|
211
|
+
options?: RequestOptions,
|
|
212
|
+
) =>
|
|
213
|
+
(
|
|
214
|
+
await runtime.request<RunMutationResponse>({
|
|
215
|
+
method: "POST",
|
|
216
|
+
path,
|
|
217
|
+
body,
|
|
218
|
+
options,
|
|
219
|
+
})
|
|
220
|
+
).data;
|
|
221
|
+
const read = async <T>(
|
|
222
|
+
path: string,
|
|
223
|
+
query?: EvaluationResultsQuery,
|
|
224
|
+
options?: RequestOptions,
|
|
225
|
+
) =>
|
|
226
|
+
(
|
|
227
|
+
await runtime.request<T>({
|
|
228
|
+
method: "GET",
|
|
229
|
+
path,
|
|
230
|
+
query: { ...query },
|
|
231
|
+
options,
|
|
232
|
+
})
|
|
233
|
+
).data;
|
|
234
|
+
this.evaluations = {
|
|
235
|
+
...resources.evaluations,
|
|
236
|
+
runs: {
|
|
237
|
+
...resources.evaluations.runs,
|
|
238
|
+
create: (body, options) =>
|
|
239
|
+
command("/v1/evaluations/runs", body, options),
|
|
240
|
+
get: (id, options) =>
|
|
241
|
+
read<EvaluationRun>(runPath(id), undefined, options),
|
|
242
|
+
cancel: (id, options) =>
|
|
243
|
+
command(runPath(id) + "/cancel", undefined, options),
|
|
244
|
+
retry: (id, options) =>
|
|
245
|
+
command(runPath(id) + "/retry", undefined, options),
|
|
246
|
+
results: (id, query, options) =>
|
|
247
|
+
read<EvaluationRunResults>(runPath(id) + "/results", query, options),
|
|
248
|
+
cases: (id, query, options) =>
|
|
249
|
+
read<EvaluationRunCases>(runPath(id) + "/cases", query, options),
|
|
250
|
+
case: (id, caseId, options) =>
|
|
251
|
+
read<EvaluationRunCaseDetail>(
|
|
252
|
+
runPath(id) + "/cases/" + encodeURIComponent(caseId),
|
|
253
|
+
undefined,
|
|
254
|
+
options,
|
|
255
|
+
),
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
this.managedPrompts = new Prompts(runtime, options.promptCache);
|
|
259
|
+
this.gateway = new Gateway(runtime, this.managedPrompts);
|
|
42
260
|
}
|
|
43
261
|
}
|
|
44
262
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
263
|
+
export interface KnowledgeMatch {
|
|
264
|
+
chunkId: string;
|
|
265
|
+
documentId: string;
|
|
266
|
+
content: string;
|
|
267
|
+
score: number;
|
|
268
|
+
metadata: Record<string, string | number | boolean> | null;
|
|
269
|
+
source: { title: string; uri: string | null; type: string };
|
|
270
|
+
}
|
|
271
|
+
export interface EndpointExecution {
|
|
272
|
+
success: boolean;
|
|
273
|
+
data: {
|
|
274
|
+
output: unknown;
|
|
275
|
+
raw_content?: string;
|
|
276
|
+
model: string;
|
|
277
|
+
provider: string;
|
|
278
|
+
output_valid: boolean;
|
|
279
|
+
repair_attempts: number;
|
|
280
|
+
};
|
|
281
|
+
usage: {
|
|
282
|
+
prompt_tokens: number;
|
|
283
|
+
completion_tokens: number;
|
|
284
|
+
total_tokens: number;
|
|
285
|
+
};
|
|
286
|
+
meta: {
|
|
287
|
+
endpoint_id: string;
|
|
288
|
+
version_id: string;
|
|
289
|
+
prompt_version_id: string;
|
|
290
|
+
request_id: string;
|
|
291
|
+
trace_id: string;
|
|
292
|
+
latency_ms: number;
|
|
293
|
+
};
|
|
60
294
|
}
|
|
61
|
-
|
|
62
295
|
function normalizeBaseUrl(value: string): string {
|
|
63
296
|
let url: URL;
|
|
64
297
|
try {
|
|
65
298
|
url = new URL(value);
|
|
66
299
|
} catch {
|
|
67
|
-
throw configError("Nirmos
|
|
300
|
+
throw configError("Nirmos base URL must be a valid absolute URL.");
|
|
68
301
|
}
|
|
69
302
|
return url.toString().replace(/\/+$/, "");
|
|
70
303
|
}
|
|
@@ -87,3 +320,53 @@ function nonNegativeInteger(
|
|
|
87
320
|
function configError(message: string): ConfigurationError {
|
|
88
321
|
return new ConfigurationError(message);
|
|
89
322
|
}
|
|
323
|
+
|
|
324
|
+
export interface PromptTestRequest {
|
|
325
|
+
messages: Array<{
|
|
326
|
+
role: string;
|
|
327
|
+
name?: string | null;
|
|
328
|
+
order?: number;
|
|
329
|
+
contentBlocks: Array<{
|
|
330
|
+
order?: number;
|
|
331
|
+
type: string;
|
|
332
|
+
text?: string | null;
|
|
333
|
+
uri?: string | null;
|
|
334
|
+
mimeType?: string | null;
|
|
335
|
+
data?: unknown;
|
|
336
|
+
}>;
|
|
337
|
+
}>;
|
|
338
|
+
selectedModel?: string;
|
|
339
|
+
temperature?: number;
|
|
340
|
+
maxTokens?: number;
|
|
341
|
+
topP?: number;
|
|
342
|
+
variables?: string[];
|
|
343
|
+
variablesInput?: Record<string, unknown>;
|
|
344
|
+
provider?: string;
|
|
345
|
+
structuredOutput?: unknown;
|
|
346
|
+
}
|
|
347
|
+
export interface PromptTestResponse {
|
|
348
|
+
success: boolean;
|
|
349
|
+
data?: {
|
|
350
|
+
output?: unknown;
|
|
351
|
+
raw_content?: string;
|
|
352
|
+
model?: string;
|
|
353
|
+
provider?: string;
|
|
354
|
+
output_valid?: boolean;
|
|
355
|
+
repair_attempts?: number;
|
|
356
|
+
structuredOutput?: {
|
|
357
|
+
validationPassed?: boolean;
|
|
358
|
+
validationErrors?: string[];
|
|
359
|
+
healingDetails?: {
|
|
360
|
+
llmRetryUsed?: boolean;
|
|
361
|
+
programmaticApplied?: boolean;
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
error?: string;
|
|
366
|
+
usage?: {
|
|
367
|
+
prompt_tokens?: number;
|
|
368
|
+
completion_tokens?: number;
|
|
369
|
+
total_tokens?: number;
|
|
370
|
+
};
|
|
371
|
+
meta?: { latency_ms?: number; request_id?: string; trace_id?: string };
|
|
372
|
+
}
|
package/src/core/errors.ts
CHANGED
|
@@ -5,12 +5,16 @@ export interface NirmosErrorOptions {
|
|
|
5
5
|
code?: string;
|
|
6
6
|
requestId?: string;
|
|
7
7
|
traceId?: string;
|
|
8
|
+
status?: number;
|
|
9
|
+
details?: unknown;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
export class NirmosError extends Error {
|
|
11
13
|
readonly code?: string;
|
|
12
14
|
readonly requestId?: string;
|
|
13
15
|
readonly traceId?: string;
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
readonly details?: unknown;
|
|
14
18
|
|
|
15
19
|
constructor(message: string, options: NirmosErrorOptions = {}) {
|
|
16
20
|
super(message, { cause: options.cause });
|
|
@@ -18,6 +22,8 @@ export class NirmosError extends Error {
|
|
|
18
22
|
this.code = options.code;
|
|
19
23
|
this.requestId = options.requestId;
|
|
20
24
|
this.traceId = options.traceId;
|
|
25
|
+
this.status = options.status;
|
|
26
|
+
this.details = options.details;
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
|
|
@@ -41,10 +47,10 @@ export interface APIErrorOptions extends NirmosErrorOptions {
|
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
export class APIError extends NirmosError {
|
|
44
|
-
readonly status: number;
|
|
50
|
+
declare readonly status: number;
|
|
45
51
|
readonly retryable: boolean;
|
|
46
52
|
readonly retryAfterMs?: number;
|
|
47
|
-
readonly details?: unknown;
|
|
53
|
+
declare readonly details?: unknown;
|
|
48
54
|
readonly metadata?: RequestMetadata;
|
|
49
55
|
readonly headers?: Headers;
|
|
50
56
|
|
package/src/core/metadata.ts
CHANGED
|
@@ -62,20 +62,11 @@ export function extractMetadata(
|
|
|
62
62
|
numericHeader(response, "x-nirmos-response-time", "x-response-time"),
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
const cacheStatus = header(
|
|
66
|
-
|
|
67
|
-
"x-nirmos-cache-status",
|
|
68
|
-
"x-promptnetra-cache-status",
|
|
69
|
-
);
|
|
70
|
-
const cacheLayer = header(
|
|
71
|
-
response,
|
|
72
|
-
"x-nirmos-cache-layer",
|
|
73
|
-
"x-promptnetra-cache-layer",
|
|
74
|
-
);
|
|
65
|
+
const cacheStatus = header(response, "nirmos-cache-status");
|
|
66
|
+
const cacheLayer = header(response, "nirmos-cache-layer");
|
|
75
67
|
const remainingTtlSeconds = numericHeader(
|
|
76
68
|
response,
|
|
77
|
-
"
|
|
78
|
-
"x-promptnetra-cache-remaining-ttl",
|
|
69
|
+
"nirmos-cache-remaining-ttl",
|
|
79
70
|
);
|
|
80
71
|
|
|
81
72
|
if (cacheStatus || cacheLayer || remainingTtlSeconds !== undefined) {
|
package/src/core/transport.ts
CHANGED
|
@@ -20,7 +20,11 @@ import {
|
|
|
20
20
|
import type { HeadersInput, RequestOptions } from "./types.js";
|
|
21
21
|
|
|
22
22
|
export interface TransportConfig {
|
|
23
|
-
apiKey
|
|
23
|
+
apiKey?: string;
|
|
24
|
+
accessToken?: string;
|
|
25
|
+
credentials?: RequestCredentials;
|
|
26
|
+
runtime?: boolean;
|
|
27
|
+
onError?: (error: APIError) => void;
|
|
24
28
|
baseUrl: string;
|
|
25
29
|
timeoutMs: number;
|
|
26
30
|
maxRetries: number;
|
|
@@ -31,7 +35,9 @@ export interface TransportConfig {
|
|
|
31
35
|
export interface TransportRequest {
|
|
32
36
|
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
|
|
33
37
|
path: string;
|
|
34
|
-
query?: Readonly<
|
|
38
|
+
query?: Readonly<
|
|
39
|
+
Record<string, string | number | boolean | readonly string[] | undefined>
|
|
40
|
+
>;
|
|
35
41
|
body?: unknown;
|
|
36
42
|
options?: RequestOptions;
|
|
37
43
|
}
|
|
@@ -41,7 +47,7 @@ export interface TransportResponse<T> {
|
|
|
41
47
|
response: Response;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
const SDK_VERSION = "
|
|
50
|
+
const SDK_VERSION = "0.3.0";
|
|
45
51
|
|
|
46
52
|
export class HttpTransport {
|
|
47
53
|
readonly #config: TransportConfig;
|
|
@@ -55,16 +61,26 @@ export class HttpTransport {
|
|
|
55
61
|
const data = await parseResponseBody(response);
|
|
56
62
|
|
|
57
63
|
if (!response.ok) {
|
|
58
|
-
|
|
64
|
+
const error = createApiError(response, data);
|
|
65
|
+
this.#config.onError?.(error);
|
|
66
|
+
throw error;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
return { data: data as T, response };
|
|
62
70
|
}
|
|
63
71
|
|
|
72
|
+
/** Control-plane and Knowledge envelope decoder; no raw Response at callsites. */
|
|
73
|
+
async data<T>(request: TransportRequest): Promise<T> {
|
|
74
|
+
const { data } = await this.request<{ data: T } | undefined>(request);
|
|
75
|
+
return data?.data as T;
|
|
76
|
+
}
|
|
77
|
+
|
|
64
78
|
async ensureSuccess(response: Response): Promise<Response> {
|
|
65
79
|
if (response.ok) return response;
|
|
66
80
|
const data = await parseResponseBody(response);
|
|
67
|
-
|
|
81
|
+
const error = createApiError(response, data);
|
|
82
|
+
this.#config.onError?.(error);
|
|
83
|
+
throw error;
|
|
68
84
|
}
|
|
69
85
|
|
|
70
86
|
async fetch(request: TransportRequest): Promise<Response> {
|
|
@@ -146,7 +162,12 @@ export class HttpTransport {
|
|
|
146
162
|
method: request.method,
|
|
147
163
|
headers: this.#headers(request),
|
|
148
164
|
body:
|
|
149
|
-
request.body === undefined
|
|
165
|
+
request.body === undefined
|
|
166
|
+
? undefined
|
|
167
|
+
: request.body instanceof FormData
|
|
168
|
+
? request.body
|
|
169
|
+
: JSON.stringify(request.body),
|
|
170
|
+
credentials: this.#config.credentials,
|
|
150
171
|
signal: controller.signal,
|
|
151
172
|
});
|
|
152
173
|
if (!response.body) return response;
|
|
@@ -207,7 +228,9 @@ export class HttpTransport {
|
|
|
207
228
|
`${this.#config.baseUrl}/`,
|
|
208
229
|
);
|
|
209
230
|
for (const [key, value] of Object.entries(request.query ?? {})) {
|
|
210
|
-
if (
|
|
231
|
+
if (Array.isArray(value))
|
|
232
|
+
for (const item of value) url.searchParams.append(key + "[]", item);
|
|
233
|
+
else if (value !== undefined) url.searchParams.set(key, String(value));
|
|
211
234
|
}
|
|
212
235
|
return url.toString();
|
|
213
236
|
}
|
|
@@ -215,14 +238,24 @@ export class HttpTransport {
|
|
|
215
238
|
#headers(request: TransportRequest): Headers {
|
|
216
239
|
const headers = createHeaders(this.#config.headers);
|
|
217
240
|
headers.set("accept", "application/json");
|
|
218
|
-
headers.set("x-api-key", this.#config.apiKey);
|
|
219
241
|
headers.set("x-nirmos-sdk-version", SDK_VERSION);
|
|
220
|
-
if (request.body !== undefined) {
|
|
242
|
+
if (request.body !== undefined && !(request.body instanceof FormData)) {
|
|
221
243
|
headers.set("content-type", "application/json");
|
|
222
244
|
}
|
|
223
245
|
createHeaders(request.options?.headers).forEach((value, key) => {
|
|
224
|
-
if (
|
|
246
|
+
if (!["x-api-key", "authorization"].includes(key.toLowerCase()))
|
|
247
|
+
headers.set(key, value);
|
|
225
248
|
});
|
|
249
|
+
if (this.#config.apiKey) headers.set("x-api-key", this.#config.apiKey);
|
|
250
|
+
if (this.#config.accessToken)
|
|
251
|
+
headers.set("authorization", `Bearer ${this.#config.accessToken}`);
|
|
252
|
+
if (
|
|
253
|
+
this.#config.runtime &&
|
|
254
|
+
!["GET", "HEAD", "OPTIONS"].includes(request.method)
|
|
255
|
+
) {
|
|
256
|
+
headers.set("x-request-timestamp", String(Date.now()));
|
|
257
|
+
headers.set("x-request-nonce", globalThis.crypto.randomUUID());
|
|
258
|
+
}
|
|
226
259
|
if (request.options?.idempotencyKey) {
|
|
227
260
|
headers.set("idempotency-key", request.options.idempotencyKey);
|
|
228
261
|
}
|
|
@@ -261,7 +294,10 @@ function createApiError(response: Response, payload: unknown): APIError {
|
|
|
261
294
|
retryAfterMs,
|
|
262
295
|
details: error.details,
|
|
263
296
|
metadata,
|
|
264
|
-
requestId:
|
|
297
|
+
requestId:
|
|
298
|
+
readString(error, "requestId") ??
|
|
299
|
+
readString(root, "requestId") ??
|
|
300
|
+
metadata.requestId,
|
|
265
301
|
traceId: metadata.traceId,
|
|
266
302
|
headers: response.headers,
|
|
267
303
|
};
|
package/src/gateway/chat.ts
CHANGED
|
@@ -53,10 +53,8 @@ export class Chat {
|
|
|
53
53
|
params: ChatCreateParams,
|
|
54
54
|
stream: boolean,
|
|
55
55
|
): Promise<Record<string, unknown>> {
|
|
56
|
+
validateTarget(params);
|
|
56
57
|
const messages = await this.#messages(params);
|
|
57
|
-
if (!params.model.trim()) {
|
|
58
|
-
throw localValidation("model", "Model is required.");
|
|
59
|
-
}
|
|
60
58
|
if (messages.length === 0) {
|
|
61
59
|
throw localValidation(
|
|
62
60
|
"messages",
|
|
@@ -66,6 +64,7 @@ export class Chat {
|
|
|
66
64
|
|
|
67
65
|
return {
|
|
68
66
|
model: params.model,
|
|
67
|
+
route: params.route,
|
|
69
68
|
messages: messages.map(toWireMessage),
|
|
70
69
|
stream,
|
|
71
70
|
temperature: params.temperature,
|
|
@@ -103,6 +102,27 @@ export class Chat {
|
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
|
|
105
|
+
function validateTarget(params: ChatCreateParams): void {
|
|
106
|
+
const hasModel = params.model !== undefined;
|
|
107
|
+
const hasRoute = params.route !== undefined;
|
|
108
|
+
|
|
109
|
+
if (hasModel && hasRoute) {
|
|
110
|
+
throw localValidation(
|
|
111
|
+
"model,route",
|
|
112
|
+
"Provide either model or route, but not both.",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (!hasModel && !hasRoute) {
|
|
116
|
+
throw localValidation("model,route", "Provide either model or route.");
|
|
117
|
+
}
|
|
118
|
+
if (hasModel && (typeof params.model !== "string" || !params.model.trim())) {
|
|
119
|
+
throw localValidation("model", "Model is required.");
|
|
120
|
+
}
|
|
121
|
+
if (hasRoute && (typeof params.route !== "string" || !params.route.trim())) {
|
|
122
|
+
throw localValidation("route", "Route is required.");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
106
126
|
function toWireResponseFormat(
|
|
107
127
|
format: ResponseFormat | undefined,
|
|
108
128
|
): Record<string, unknown> | undefined {
|