@hilbras/omninode 2.0.0-alpha.5 → 2.0.0-alpha.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/README.md +17 -3
- package/dist/cli/index.js +333 -71
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +156 -17
- package/dist/index.js +343 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,6 +125,7 @@ var providerConfigSchema = z.object({
|
|
|
125
125
|
type: z.enum(["openai-compatible", "omnihilbras", "openrouter", "local", "custom"]),
|
|
126
126
|
base_url: z.string().url(),
|
|
127
127
|
api_key_env_var: z.string().min(1).optional(),
|
|
128
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
128
129
|
headers: z.record(z.string()).optional(),
|
|
129
130
|
enabled: z.boolean().optional(),
|
|
130
131
|
metadata: z.record(z.unknown()).optional()
|
|
@@ -189,7 +190,8 @@ var projectConfigSchema = z.object({
|
|
|
189
190
|
memory: z.object({
|
|
190
191
|
provider: z.string().min(1).default("local"),
|
|
191
192
|
base_url: z.string().url().optional(),
|
|
192
|
-
api_key_env_var: z.string().min(1).optional()
|
|
193
|
+
api_key_env_var: z.string().min(1).optional(),
|
|
194
|
+
timeout_ms: z.number().int().positive().optional()
|
|
193
195
|
}).strict().optional()
|
|
194
196
|
}).strict();
|
|
195
197
|
var appConfigSchema = z.object({
|
|
@@ -302,6 +304,7 @@ function toProviderConfig(raw) {
|
|
|
302
304
|
type: raw.type,
|
|
303
305
|
baseUrl: raw.base_url,
|
|
304
306
|
apiKeyEnvVar: raw.api_key_env_var,
|
|
307
|
+
timeoutMs: raw.timeout_ms,
|
|
305
308
|
headers: raw.headers,
|
|
306
309
|
enabled: raw.enabled,
|
|
307
310
|
metadata: raw.metadata
|
|
@@ -394,57 +397,200 @@ function authHeaders(config, env = process.env) {
|
|
|
394
397
|
}
|
|
395
398
|
|
|
396
399
|
// src/providers/http.ts
|
|
400
|
+
var HttpResponseError = class extends Error {
|
|
401
|
+
constructor(message, status, cause) {
|
|
402
|
+
super(message, { cause });
|
|
403
|
+
this.status = status;
|
|
404
|
+
this.name = "HttpResponseError";
|
|
405
|
+
}
|
|
406
|
+
status;
|
|
407
|
+
};
|
|
397
408
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
398
409
|
async function requestJson(url, options = {}) {
|
|
399
410
|
const { method = "GET", headers = {}, body, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
411
|
-
});
|
|
412
|
-
} catch (error) {
|
|
413
|
-
const reason = error instanceof Error && error.name === "TimeoutError" ? `timed out after ${timeoutMs}ms` : error instanceof Error ? error.message : String(error);
|
|
414
|
-
throw new ProviderError("PROVIDER_UNAVAILABLE", `Request to ${url} failed: ${reason}.`, {
|
|
415
|
-
cause: error
|
|
416
|
-
});
|
|
417
|
-
}
|
|
411
|
+
const response = await fetch(url, {
|
|
412
|
+
method,
|
|
413
|
+
headers: {
|
|
414
|
+
accept: "application/json",
|
|
415
|
+
...body !== void 0 ? { "content-type": "application/json" } : {},
|
|
416
|
+
...headers
|
|
417
|
+
},
|
|
418
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
419
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
420
|
+
});
|
|
418
421
|
let parsed;
|
|
419
422
|
try {
|
|
420
423
|
parsed = await response.json();
|
|
421
424
|
} catch (error) {
|
|
422
|
-
throw new
|
|
423
|
-
cause: error,
|
|
424
|
-
details: { status: response.status }
|
|
425
|
-
});
|
|
425
|
+
throw new HttpResponseError(`Response from ${url} was not valid JSON.`, response.status, error);
|
|
426
426
|
}
|
|
427
427
|
return { status: response.status, body: parsed };
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
+
// src/providers/errors.ts
|
|
431
|
+
function kindToCode(kind) {
|
|
432
|
+
switch (kind) {
|
|
433
|
+
case "AUTHENTICATION_ERROR":
|
|
434
|
+
return "PROVIDER_AUTH_FAILED";
|
|
435
|
+
case "MODEL_NOT_FOUND":
|
|
436
|
+
return "MODEL_NOT_FOUND";
|
|
437
|
+
default:
|
|
438
|
+
return "PROVIDER_UNAVAILABLE";
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function isRetryable(kind) {
|
|
442
|
+
return kind === "RATE_LIMIT_ERROR" || kind === "SERVER_ERROR" || kind === "NETWORK_ERROR";
|
|
443
|
+
}
|
|
444
|
+
function kindFromStatus(status) {
|
|
445
|
+
if (status === 401 || status === 403) return "AUTHENTICATION_ERROR";
|
|
446
|
+
if (status === 429) return "RATE_LIMIT_ERROR";
|
|
447
|
+
if (status === 404) return "MODEL_NOT_FOUND";
|
|
448
|
+
if (status === 408 || status === 504) return "TIMEOUT";
|
|
449
|
+
if (status >= 500) return "SERVER_ERROR";
|
|
450
|
+
if (status >= 400) return "INVALID_REQUEST";
|
|
451
|
+
return "UNKNOWN_ERROR";
|
|
452
|
+
}
|
|
453
|
+
function extractMessage(body) {
|
|
454
|
+
if (body === null || typeof body !== "object") return void 0;
|
|
455
|
+
const root = body;
|
|
456
|
+
const error = root.error ?? root;
|
|
457
|
+
const message = error.message ?? error.detail ?? root.message;
|
|
458
|
+
return typeof message === "string" ? message : void 0;
|
|
459
|
+
}
|
|
460
|
+
function parseRetryAfter(value, now = Date.now()) {
|
|
461
|
+
if (!value) return void 0;
|
|
462
|
+
const seconds = Number(value);
|
|
463
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
464
|
+
const date = Date.parse(value);
|
|
465
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - now);
|
|
466
|
+
}
|
|
467
|
+
function isTimeoutError(error) {
|
|
468
|
+
return error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError") || typeof error?.code === "string" && error.code === "ABORT_ERR";
|
|
469
|
+
}
|
|
470
|
+
function isNetworkError(error) {
|
|
471
|
+
return error instanceof TypeError || typeof error?.cause === "object" && error instanceof Error && !error.code;
|
|
472
|
+
}
|
|
473
|
+
function fallbackMessage(kind, context, status) {
|
|
474
|
+
const { provider, operation } = context;
|
|
475
|
+
switch (kind) {
|
|
476
|
+
case "AUTHENTICATION_ERROR":
|
|
477
|
+
return `Authentication with provider "${provider}" failed (HTTP ${status}). Check that the referenced API key is set and valid.`;
|
|
478
|
+
case "RATE_LIMIT_ERROR":
|
|
479
|
+
return `Provider "${provider}" rate-limited ${operation} (HTTP ${status}). Retry later.`;
|
|
480
|
+
case "MODEL_NOT_FOUND":
|
|
481
|
+
return `Provider "${provider}" does not expose the requested model (HTTP ${status}).`;
|
|
482
|
+
case "TIMEOUT":
|
|
483
|
+
return `Provider "${provider}" timed out during ${operation} (HTTP ${status}).`;
|
|
484
|
+
case "SERVER_ERROR":
|
|
485
|
+
return `Provider "${provider}" returned a server error during ${operation} (HTTP ${status}).`;
|
|
486
|
+
case "INVALID_REQUEST":
|
|
487
|
+
return `Provider "${provider}" rejected ${operation} as invalid (HTTP ${status}).`;
|
|
488
|
+
default:
|
|
489
|
+
return `Provider "${provider}" failed during ${operation} (HTTP ${status}).`;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function providerHttpError(context) {
|
|
493
|
+
const status = context.status ?? 0;
|
|
494
|
+
const kind = kindFromStatus(status);
|
|
495
|
+
const detail = extractMessage(context.body);
|
|
496
|
+
const retryAfterMs = context.retryAfterMs ?? parseRetryAfter(void 0);
|
|
497
|
+
return new ProviderError(
|
|
498
|
+
context.code ?? kindToCode(kind),
|
|
499
|
+
detail ?? fallbackMessage(kind, context, status),
|
|
500
|
+
{
|
|
501
|
+
cause: context.cause,
|
|
502
|
+
details: {
|
|
503
|
+
kind,
|
|
504
|
+
provider: context.provider,
|
|
505
|
+
operation: context.operation,
|
|
506
|
+
status,
|
|
507
|
+
retryable: isRetryable(kind),
|
|
508
|
+
...retryAfterMs !== void 0 ? { retryAfterMs } : {},
|
|
509
|
+
...detail ? { providerMessage: detail } : {}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
function providerTransportError(context) {
|
|
515
|
+
const cause = context.cause;
|
|
516
|
+
const kind = isTimeoutError(cause) ? "TIMEOUT" : cause instanceof SyntaxError || cause?.name === "HttpResponseError" ? "UNKNOWN_ERROR" : "NETWORK_ERROR";
|
|
517
|
+
const message = context.cause instanceof Error ? context.cause.message : String(context.cause);
|
|
518
|
+
return new ProviderError("PROVIDER_UNAVAILABLE", `Provider request failed: ${message}`, {
|
|
519
|
+
cause: context.cause,
|
|
520
|
+
details: {
|
|
521
|
+
kind,
|
|
522
|
+
provider: context.provider,
|
|
523
|
+
operation: context.operation,
|
|
524
|
+
retryable: isRetryable(kind)
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
430
529
|
// src/providers/openai-compatible/index.ts
|
|
530
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
431
531
|
var OpenAICompatibleProvider = class {
|
|
432
532
|
config;
|
|
533
|
+
providerId;
|
|
534
|
+
authentication;
|
|
433
535
|
log;
|
|
434
|
-
|
|
536
|
+
/** Discovered models, so getModel() answers without another round-trip. */
|
|
537
|
+
discovered;
|
|
538
|
+
env;
|
|
539
|
+
constructor(config, log = logger, env = process.env) {
|
|
435
540
|
this.config = { ...config, baseUrl: normalizeBaseUrl(config.baseUrl) };
|
|
541
|
+
this.env = env;
|
|
542
|
+
this.providerId = config.providerId ?? config.name;
|
|
543
|
+
this.authentication = {
|
|
544
|
+
method: config.apiKeyEnvVar ? "bearer" : "none",
|
|
545
|
+
...config.apiKeyEnvVar ? { envVar: config.apiKeyEnvVar } : {},
|
|
546
|
+
configured: config.apiKeyEnvVar ? Boolean(env[config.apiKeyEnvVar]) : true
|
|
547
|
+
};
|
|
436
548
|
this.log = log.child({ provider: config.name });
|
|
437
549
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
550
|
+
/** Provider-level request timeout (roadmap §6.6/§11) with the shared default. */
|
|
551
|
+
get requestTimeoutMs() {
|
|
552
|
+
return this.config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
553
|
+
}
|
|
554
|
+
/** Authenticate + discover (roadmap §10, Model Discovery). */
|
|
555
|
+
async connect() {
|
|
556
|
+
authHeaders(this.config, this.env);
|
|
557
|
+
const models = await this.listModels();
|
|
558
|
+
this.discovered = models;
|
|
559
|
+
return models;
|
|
560
|
+
}
|
|
561
|
+
async getModel(modelId) {
|
|
562
|
+
const models = this.discovered ?? await this.connect();
|
|
563
|
+
return models.find((m) => m.id === modelId);
|
|
564
|
+
}
|
|
565
|
+
/** Raw /models body (protected so adapters can capture gateway-level metadata). */
|
|
566
|
+
async rawModelsResponse() {
|
|
567
|
+
const response = await this.modelsRequest();
|
|
568
|
+
return response.body;
|
|
569
|
+
}
|
|
570
|
+
async modelsRequest() {
|
|
571
|
+
let response;
|
|
572
|
+
try {
|
|
573
|
+
response = await requestJson(`${this.config.baseUrl}/models`, {
|
|
574
|
+
headers: authHeaders(this.config, this.env),
|
|
575
|
+
timeoutMs: this.requestTimeoutMs
|
|
576
|
+
});
|
|
577
|
+
} catch (error) {
|
|
578
|
+
if (error instanceof ProviderError) throw error;
|
|
579
|
+
throw providerTransportError({ provider: this.config.name, operation: "listModels", cause: error });
|
|
444
580
|
}
|
|
581
|
+
const { status, body } = response;
|
|
445
582
|
if (status !== 200) {
|
|
446
|
-
throw
|
|
583
|
+
throw providerHttpError({
|
|
584
|
+
provider: this.config.name,
|
|
585
|
+
operation: "listModels",
|
|
586
|
+
status,
|
|
587
|
+
body
|
|
588
|
+
});
|
|
447
589
|
}
|
|
590
|
+
return response;
|
|
591
|
+
}
|
|
592
|
+
async listModels() {
|
|
593
|
+
const body = await this.rawModelsResponse();
|
|
448
594
|
const entries = extractModelEntries(body, this.config);
|
|
449
595
|
const models = [];
|
|
450
596
|
let skipped = 0;
|
|
@@ -453,22 +599,44 @@ var OpenAICompatibleProvider = class {
|
|
|
453
599
|
skipped += 1;
|
|
454
600
|
continue;
|
|
455
601
|
}
|
|
456
|
-
models.push(
|
|
457
|
-
provider: this.config.name,
|
|
458
|
-
id: entry.id,
|
|
459
|
-
displayName: entry.id,
|
|
460
|
-
status: "available",
|
|
461
|
-
metadata: {
|
|
462
|
-
...typeof entry.owned_by === "string" ? { ownedBy: entry.owned_by } : {},
|
|
463
|
-
...typeof entry.created === "number" ? { createdAt: entry.created } : {}
|
|
464
|
-
}
|
|
465
|
-
});
|
|
602
|
+
models.push(this.toModelInfo(entry));
|
|
466
603
|
}
|
|
467
604
|
if (skipped > 0) {
|
|
468
605
|
this.log.warn(`Skipped ${skipped} model entr(y/ies) without a valid id.`);
|
|
469
606
|
}
|
|
470
607
|
return models;
|
|
471
608
|
}
|
|
609
|
+
/** Maps a raw model entry onto the normalized metadata shape (§10). */
|
|
610
|
+
toModelInfo(entry) {
|
|
611
|
+
const parameters = Array.isArray(entry.supported_parameters) ? entry.supported_parameters.filter((p) => typeof p === "string") : void 0;
|
|
612
|
+
const contextWindow = typeof entry.context_length === "number" ? entry.context_length : typeof entry.context_window === "number" ? entry.context_window : void 0;
|
|
613
|
+
const inputTypes = normalizeModalities(entry.input_modalities);
|
|
614
|
+
const outputTypes = normalizeModalities(entry.output_modalities);
|
|
615
|
+
return {
|
|
616
|
+
provider: this.config.name,
|
|
617
|
+
id: entry.id,
|
|
618
|
+
displayName: entry.id,
|
|
619
|
+
...typeof entry.name === "string" ? { name: entry.name } : {},
|
|
620
|
+
status: "available",
|
|
621
|
+
...contextWindow !== void 0 ? { contextWindow } : {},
|
|
622
|
+
...inputTypes !== void 0 ? { inputTypes } : {},
|
|
623
|
+
...outputTypes !== void 0 ? { outputTypes } : {},
|
|
624
|
+
...parameters !== void 0 ? {
|
|
625
|
+
supportsTools: parameters.includes("tools") || parameters.includes("tool_choice"),
|
|
626
|
+
supportsStructuredOutput: parameters.includes("response_format"),
|
|
627
|
+
supportsStreaming: parameters.includes("stream")
|
|
628
|
+
} : {},
|
|
629
|
+
metadata: {
|
|
630
|
+
...typeof entry.owned_by === "string" ? { ownedBy: entry.owned_by } : {},
|
|
631
|
+
...typeof entry.created === "number" ? { createdAt: entry.created } : {},
|
|
632
|
+
...parameters !== void 0 ? { supportedParameters: parameters } : {}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
/** Streaming where the gateway supports it (§11). */
|
|
637
|
+
stream(request, onChunk) {
|
|
638
|
+
return streamChatCompletion(this.config, request, onChunk, this.env);
|
|
639
|
+
}
|
|
472
640
|
async healthCheck() {
|
|
473
641
|
const lastCheckedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
474
642
|
try {
|
|
@@ -498,27 +666,35 @@ var OpenAICompatibleProvider = class {
|
|
|
498
666
|
}
|
|
499
667
|
}
|
|
500
668
|
async chat(request) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
);
|
|
669
|
+
let response;
|
|
670
|
+
try {
|
|
671
|
+
response = await requestJson(`${this.config.baseUrl}/chat/completions`, {
|
|
672
|
+
method: "POST",
|
|
673
|
+
headers: authHeaders(this.config, this.env),
|
|
674
|
+
timeoutMs: this.requestTimeoutMs,
|
|
675
|
+
body: {
|
|
676
|
+
model: request.model,
|
|
677
|
+
messages: request.messages,
|
|
678
|
+
...request.temperature !== void 0 ? { temperature: request.temperature } : {},
|
|
679
|
+
...request.maxTokens !== void 0 ? { max_tokens: request.maxTokens } : {},
|
|
680
|
+
...request.stop !== void 0 ? { stop: request.stop } : {}
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
} catch (error) {
|
|
684
|
+
if (error instanceof ProviderError) throw error;
|
|
685
|
+
throw providerTransportError({ provider: this.config.name, operation: "chat", cause: error });
|
|
519
686
|
}
|
|
687
|
+
const { status, body } = response;
|
|
520
688
|
if (status !== 200) {
|
|
521
|
-
throw
|
|
689
|
+
throw providerHttpError({
|
|
690
|
+
provider: this.config.name,
|
|
691
|
+
operation: "chat",
|
|
692
|
+
status,
|
|
693
|
+
body,
|
|
694
|
+
...status === 404 ? {
|
|
695
|
+
code: "MODEL_NOT_FOUND"
|
|
696
|
+
} : {}
|
|
697
|
+
});
|
|
522
698
|
}
|
|
523
699
|
const payload = body;
|
|
524
700
|
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
@@ -540,6 +716,81 @@ var OpenAICompatibleProvider = class {
|
|
|
540
716
|
};
|
|
541
717
|
}
|
|
542
718
|
};
|
|
719
|
+
async function streamChatCompletion(config, request, onChunk, env = process.env) {
|
|
720
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
721
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
722
|
+
let response;
|
|
723
|
+
try {
|
|
724
|
+
response = await fetch(`${baseUrl}/chat/completions`, {
|
|
725
|
+
method: "POST",
|
|
726
|
+
headers: {
|
|
727
|
+
accept: "text/event-stream",
|
|
728
|
+
"content-type": "application/json",
|
|
729
|
+
...authHeaders(config, env)
|
|
730
|
+
},
|
|
731
|
+
body: JSON.stringify({
|
|
732
|
+
model: request.model,
|
|
733
|
+
messages: request.messages,
|
|
734
|
+
stream: true,
|
|
735
|
+
...request.temperature !== void 0 ? { temperature: request.temperature } : {},
|
|
736
|
+
...request.maxTokens !== void 0 ? { max_tokens: request.maxTokens } : {}
|
|
737
|
+
}),
|
|
738
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
739
|
+
});
|
|
740
|
+
} catch (error) {
|
|
741
|
+
throw providerTransportError({ provider: config.name, operation: "stream", cause: error });
|
|
742
|
+
}
|
|
743
|
+
if (!response.ok) {
|
|
744
|
+
const body = await response.json().catch(() => void 0);
|
|
745
|
+
throw providerHttpError({ provider: config.name, operation: "stream", status: response.status, body });
|
|
746
|
+
}
|
|
747
|
+
if (!response.body) {
|
|
748
|
+
throw providerHttpError({
|
|
749
|
+
provider: config.name,
|
|
750
|
+
operation: "stream",
|
|
751
|
+
status: 500,
|
|
752
|
+
body: { error: { message: "streaming is not supported by this endpoint" } }
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
let content = "";
|
|
756
|
+
let model = request.model;
|
|
757
|
+
let finishReason;
|
|
758
|
+
const decoder = new TextDecoder();
|
|
759
|
+
let buffer = "";
|
|
760
|
+
for await (const piece of response.body) {
|
|
761
|
+
buffer += decoder.decode(piece, { stream: true });
|
|
762
|
+
let newline = buffer.indexOf("\n");
|
|
763
|
+
while (newline >= 0) {
|
|
764
|
+
const line = buffer.slice(0, newline).trim();
|
|
765
|
+
buffer = buffer.slice(newline + 1);
|
|
766
|
+
newline = buffer.indexOf("\n");
|
|
767
|
+
if (line.length === 0 || line.startsWith(":")) continue;
|
|
768
|
+
const data = line.startsWith("data:") ? line.slice(5).trim() : line;
|
|
769
|
+
if (data === "[DONE]") continue;
|
|
770
|
+
let event;
|
|
771
|
+
try {
|
|
772
|
+
event = JSON.parse(data);
|
|
773
|
+
} catch {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
if (typeof event.model === "string") model = event.model;
|
|
777
|
+
const choices = Array.isArray(event.choices) ? event.choices : [];
|
|
778
|
+
const first = choices[0];
|
|
779
|
+
const delta = typeof first?.delta?.content === "string" ? first.delta.content : "";
|
|
780
|
+
if (delta.length > 0) content += delta;
|
|
781
|
+
if (typeof first?.finish_reason === "string") finishReason = first.finish_reason;
|
|
782
|
+
onChunk({ delta, ...finishReason !== void 0 ? { finishReason } : {}, raw: event });
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
return { model, content, ...finishReason !== void 0 ? { finishReason } : {} };
|
|
786
|
+
}
|
|
787
|
+
function normalizeModalities(value) {
|
|
788
|
+
const list = Array.isArray(value) ? value : typeof value === "string" ? [value] : void 0;
|
|
789
|
+
if (!list) return void 0;
|
|
790
|
+
const allowed = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "embedding"]);
|
|
791
|
+
const modalities = list.filter((m) => typeof m === "string" && allowed.has(m));
|
|
792
|
+
return modalities.length > 0 ? modalities : void 0;
|
|
793
|
+
}
|
|
543
794
|
function normalizeBaseUrl(baseUrl) {
|
|
544
795
|
return baseUrl.replace(/\/+$/, "");
|
|
545
796
|
}
|
|
@@ -554,14 +805,6 @@ function extractModelEntries(body, config) {
|
|
|
554
805
|
{ details: { endpoint: "models" } }
|
|
555
806
|
);
|
|
556
807
|
}
|
|
557
|
-
function authFailed(config, status) {
|
|
558
|
-
const envHint = config.apiKeyEnvVar ? ` Check that $${config.apiKeyEnvVar} is set and valid.` : " The provider requires authentication; configure api_key_env_var for it.";
|
|
559
|
-
return new ProviderError(
|
|
560
|
-
"PROVIDER_AUTH_FAILED",
|
|
561
|
-
`Authentication with provider "${config.name}" failed (HTTP ${status}).${envHint}`,
|
|
562
|
-
{ details: { status } }
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
808
|
function unavailable(config, message, status) {
|
|
566
809
|
return new ProviderError("PROVIDER_UNAVAILABLE", `Provider "${config.name}": ${message}`, {
|
|
567
810
|
details: { status }
|
|
@@ -574,11 +817,33 @@ function inferHealth(error) {
|
|
|
574
817
|
|
|
575
818
|
// src/providers/omnihilbras/index.ts
|
|
576
819
|
var OmniHilbrasProvider = class extends OpenAICompatibleProvider {
|
|
820
|
+
gateway;
|
|
821
|
+
async listModels() {
|
|
822
|
+
const raw = await this.rawModelsResponse();
|
|
823
|
+
await this.extractGatewayMetadata(raw);
|
|
824
|
+
const models = await super.listModels();
|
|
825
|
+
return this.gateway ? models.map((model) => ({ ...model, metadata: { ...model.metadata, gateway: this.gateway } })) : models;
|
|
826
|
+
}
|
|
577
827
|
/**
|
|
578
828
|
* Run the full connect flow. Throws on authentication or transport failure
|
|
579
829
|
* (use healthCheck() for a non-throwing probe).
|
|
580
830
|
*/
|
|
581
|
-
|
|
831
|
+
/**
|
|
832
|
+
* Gateway metadata reported alongside the model list (gateway version, tier,
|
|
833
|
+
* region…), kept separate from per-model metadata (§11 — provider metadata).
|
|
834
|
+
*/
|
|
835
|
+
gatewayMetadata() {
|
|
836
|
+
return this.gateway;
|
|
837
|
+
}
|
|
838
|
+
async extractGatewayMetadata(body) {
|
|
839
|
+
if (body !== null && typeof body === "object") {
|
|
840
|
+
const gateway = body.gateway;
|
|
841
|
+
if (gateway !== null && typeof gateway === "object") {
|
|
842
|
+
this.gateway = gateway;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
async connectAndRegister(registry) {
|
|
582
847
|
const apiKey = resolveApiKey(this.config);
|
|
583
848
|
const discovered = await this.listModels();
|
|
584
849
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3325,7 +3590,7 @@ var ProjectStores = class {
|
|
|
3325
3590
|
};
|
|
3326
3591
|
|
|
3327
3592
|
// src/version.ts
|
|
3328
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
3593
|
+
var OMNINODE_VERSION = "2.0.0-alpha.7";
|
|
3329
3594
|
export {
|
|
3330
3595
|
AgentAdapterRegistry,
|
|
3331
3596
|
AgentError,
|
|
@@ -3395,22 +3660,30 @@ export {
|
|
|
3395
3660
|
encodeMessage,
|
|
3396
3661
|
envelope,
|
|
3397
3662
|
expandEnvRefs,
|
|
3663
|
+
extractMessage,
|
|
3398
3664
|
extractReportFromText,
|
|
3399
3665
|
findConfigFile,
|
|
3666
|
+
isNetworkError,
|
|
3400
3667
|
isOmniNodeError,
|
|
3668
|
+
isRetryable,
|
|
3401
3669
|
isSupportedProtocol,
|
|
3670
|
+
isTimeoutError,
|
|
3402
3671
|
keywords,
|
|
3403
3672
|
killTree,
|
|
3673
|
+
kindFromStatus,
|
|
3404
3674
|
loadConfig,
|
|
3405
3675
|
logger,
|
|
3406
3676
|
newMessageId,
|
|
3407
3677
|
parseHello,
|
|
3408
3678
|
parsePlanJson,
|
|
3679
|
+
parseRetryAfter,
|
|
3409
3680
|
pipelineConfigSchema,
|
|
3410
3681
|
pipelineStepConfigSchema,
|
|
3411
3682
|
plannerConfigSchema,
|
|
3412
3683
|
projectConfigSchema,
|
|
3413
3684
|
providerConfigSchema,
|
|
3685
|
+
providerHttpError,
|
|
3686
|
+
providerTransportError,
|
|
3414
3687
|
registryKey,
|
|
3415
3688
|
requestJson,
|
|
3416
3689
|
requireCompletion,
|