@digilogiclabs/platform-core 1.15.0 → 1.17.0

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.
@@ -1,4 +1,4 @@
1
- import { x as AIToolCall, y as AITool, e as AIChatResponse, w as AIMessage, c as IAI, I as ICache, a as ILogger, d as AIChatRequest, b as ITracing, K as ISpan, D as AIUsageInfo } from './IAI-D8wA_i8N.mjs';
1
+ import { x as AIToolCall, y as AITool, e as AIChatResponse, w as AIMessage, c as IAI, I as ICache, a as ILogger, d as AIChatRequest, b as ITracing, K as ISpan, D as AIUsageInfo, f as AIStreamChunk, g as AIStreamCallback, h as AICompletionRequest, i as AICompletionResponse, j as AIEmbeddingRequest, k as AIEmbeddingResponse, l as AIModelConfig, m as AIModelType, n as AIProvider } from './IAI-D8wA_i8N.js';
2
2
 
3
3
  /**
4
4
  * IAIUsage - Per-tenant AI token tracking and cost allocation
@@ -861,4 +861,61 @@ interface TracedAIOptions {
861
861
  */
862
862
  declare function createTracedAI(options: TracedAIOptions): IAI;
863
863
 
864
- export { type AIUsageConfig as A, type Budget as B, type CostBreakdown as C, DEFAULT_AGENT_LOOP_OPTIONS as D, type AgentUsageRecordParams as E, type AgentBudget as F, type AgentUsageTracker as G, createAgentUsageTracker as H, type IAIUsage as I, type TracedAIOptions as J, createTracedAI as K, MemoryAIUsage as M, type Quota as Q, type ToolExecutor as T, type UsageRecord as U, type UsageQuery as a, type UsageQueryResult as b, type QuotaType as c, type UsageCategory as d, type QuotaStatus as e, type BudgetStatus as f, type UsageInterval as g, type UsageSummary as h, type UsageTrend as i, type UsageInvoice as j, type AlertType as k, type UsageAlert as l, type UsageInvoiceItem as m, type AgentTool as n, type AgentToolResult as o, type AgentCumulativeUsage as p, type AgentIterationEvent as q, type AgentIterationCallback as r, type AgentStopReason as s, type AgentLoopOptions as t, type AgentLoopResult as u, runAgentLoop as v, type AgentTracerOptions as w, type AgentTracer as x, createAgentTracer as y, type AgentUsageTrackerOptions as z };
864
+ /**
865
+ * Ollama Adapter — Local LLM inference via Ollama REST API
866
+ *
867
+ * Zero API cost. Runs against a local Ollama instance.
868
+ * Supports chat, completion, and embedding operations.
869
+ *
870
+ * @example
871
+ * ```typescript
872
+ * import { OllamaAdapter } from '@digilogiclabs/platform-core';
873
+ *
874
+ * const ai = new OllamaAdapter({ baseUrl: 'http://localhost:11434' });
875
+ * const response = await ai.chat({
876
+ * messages: [{ role: 'user', content: 'Hello' }],
877
+ * model: 'qwen2.5:3b',
878
+ * });
879
+ * ```
880
+ */
881
+
882
+ interface OllamaAdapterConfig {
883
+ /** Ollama API base URL @default "http://localhost:11434" */
884
+ baseUrl?: string;
885
+ /** Default chat model @default "qwen2.5:3b" */
886
+ defaultModel?: string;
887
+ /** Default embedding model @default "nomic-embed-text" */
888
+ defaultEmbeddingModel?: string;
889
+ /** Request timeout in ms @default 120000 */
890
+ timeoutMs?: number;
891
+ }
892
+ declare class OllamaAdapter implements IAI {
893
+ private readonly baseUrl;
894
+ private readonly defaultModel;
895
+ private readonly defaultEmbeddingModel;
896
+ private readonly timeoutMs;
897
+ constructor(config?: OllamaAdapterConfig);
898
+ chat(request: AIChatRequest): Promise<AIChatResponse>;
899
+ chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk>;
900
+ chatWithCallback(request: AIChatRequest, callback: AIStreamCallback): Promise<AIChatResponse>;
901
+ complete(request: AICompletionRequest): Promise<AICompletionResponse>;
902
+ completeStream(request: AICompletionRequest): AsyncIterable<AIStreamChunk>;
903
+ embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse>;
904
+ similarity(text1: string, text2: string, model?: string): Promise<number>;
905
+ listModels(): Promise<AIModelConfig[]>;
906
+ getModel(modelId: string): Promise<AIModelConfig | null>;
907
+ supportsCapability(modelId: string, capability: AIModelType): Promise<boolean>;
908
+ estimateTokens(text: string, _model?: string): Promise<number>;
909
+ estimateCost(): Promise<number>;
910
+ healthCheck(): Promise<{
911
+ healthy: boolean;
912
+ providers: Record<AIProvider, {
913
+ available: boolean;
914
+ latencyMs?: number;
915
+ error?: string;
916
+ }>;
917
+ }>;
918
+ private fetch;
919
+ }
920
+
921
+ export { type AIUsageConfig as A, type Budget as B, type CostBreakdown as C, DEFAULT_AGENT_LOOP_OPTIONS as D, type AgentUsageTrackerOptions as E, type AgentUsageRecordParams as F, type AgentBudget as G, type AgentUsageTracker as H, type IAIUsage as I, createAgentUsageTracker as J, type TracedAIOptions as K, createTracedAI as L, MemoryAIUsage as M, OllamaAdapter as O, type Quota as Q, type ToolExecutor as T, type UsageRecord as U, type UsageQuery as a, type UsageQueryResult as b, type QuotaType as c, type UsageCategory as d, type QuotaStatus as e, type BudgetStatus as f, type UsageInterval as g, type UsageSummary as h, type UsageTrend as i, type UsageInvoice as j, type AlertType as k, type UsageAlert as l, type UsageInvoiceItem as m, type OllamaAdapterConfig as n, type AgentTool as o, type AgentToolResult as p, type AgentCumulativeUsage as q, type AgentIterationEvent as r, type AgentIterationCallback as s, type AgentStopReason as t, type AgentLoopOptions as u, type AgentLoopResult as v, runAgentLoop as w, type AgentTracerOptions as x, type AgentTracer as y, createAgentTracer as z };
@@ -1,4 +1,4 @@
1
- import { x as AIToolCall, y as AITool, e as AIChatResponse, w as AIMessage, c as IAI, I as ICache, a as ILogger, d as AIChatRequest, b as ITracing, K as ISpan, D as AIUsageInfo } from './IAI-D8wA_i8N.js';
1
+ import { x as AIToolCall, y as AITool, e as AIChatResponse, w as AIMessage, c as IAI, I as ICache, a as ILogger, d as AIChatRequest, b as ITracing, K as ISpan, D as AIUsageInfo, f as AIStreamChunk, g as AIStreamCallback, h as AICompletionRequest, i as AICompletionResponse, j as AIEmbeddingRequest, k as AIEmbeddingResponse, l as AIModelConfig, m as AIModelType, n as AIProvider } from './IAI-D8wA_i8N.mjs';
2
2
 
3
3
  /**
4
4
  * IAIUsage - Per-tenant AI token tracking and cost allocation
@@ -861,4 +861,61 @@ interface TracedAIOptions {
861
861
  */
862
862
  declare function createTracedAI(options: TracedAIOptions): IAI;
863
863
 
864
- export { type AIUsageConfig as A, type Budget as B, type CostBreakdown as C, DEFAULT_AGENT_LOOP_OPTIONS as D, type AgentUsageRecordParams as E, type AgentBudget as F, type AgentUsageTracker as G, createAgentUsageTracker as H, type IAIUsage as I, type TracedAIOptions as J, createTracedAI as K, MemoryAIUsage as M, type Quota as Q, type ToolExecutor as T, type UsageRecord as U, type UsageQuery as a, type UsageQueryResult as b, type QuotaType as c, type UsageCategory as d, type QuotaStatus as e, type BudgetStatus as f, type UsageInterval as g, type UsageSummary as h, type UsageTrend as i, type UsageInvoice as j, type AlertType as k, type UsageAlert as l, type UsageInvoiceItem as m, type AgentTool as n, type AgentToolResult as o, type AgentCumulativeUsage as p, type AgentIterationEvent as q, type AgentIterationCallback as r, type AgentStopReason as s, type AgentLoopOptions as t, type AgentLoopResult as u, runAgentLoop as v, type AgentTracerOptions as w, type AgentTracer as x, createAgentTracer as y, type AgentUsageTrackerOptions as z };
864
+ /**
865
+ * Ollama Adapter — Local LLM inference via Ollama REST API
866
+ *
867
+ * Zero API cost. Runs against a local Ollama instance.
868
+ * Supports chat, completion, and embedding operations.
869
+ *
870
+ * @example
871
+ * ```typescript
872
+ * import { OllamaAdapter } from '@digilogiclabs/platform-core';
873
+ *
874
+ * const ai = new OllamaAdapter({ baseUrl: 'http://localhost:11434' });
875
+ * const response = await ai.chat({
876
+ * messages: [{ role: 'user', content: 'Hello' }],
877
+ * model: 'qwen2.5:3b',
878
+ * });
879
+ * ```
880
+ */
881
+
882
+ interface OllamaAdapterConfig {
883
+ /** Ollama API base URL @default "http://localhost:11434" */
884
+ baseUrl?: string;
885
+ /** Default chat model @default "qwen2.5:3b" */
886
+ defaultModel?: string;
887
+ /** Default embedding model @default "nomic-embed-text" */
888
+ defaultEmbeddingModel?: string;
889
+ /** Request timeout in ms @default 120000 */
890
+ timeoutMs?: number;
891
+ }
892
+ declare class OllamaAdapter implements IAI {
893
+ private readonly baseUrl;
894
+ private readonly defaultModel;
895
+ private readonly defaultEmbeddingModel;
896
+ private readonly timeoutMs;
897
+ constructor(config?: OllamaAdapterConfig);
898
+ chat(request: AIChatRequest): Promise<AIChatResponse>;
899
+ chatStream(request: AIChatRequest): AsyncIterable<AIStreamChunk>;
900
+ chatWithCallback(request: AIChatRequest, callback: AIStreamCallback): Promise<AIChatResponse>;
901
+ complete(request: AICompletionRequest): Promise<AICompletionResponse>;
902
+ completeStream(request: AICompletionRequest): AsyncIterable<AIStreamChunk>;
903
+ embed(request: AIEmbeddingRequest): Promise<AIEmbeddingResponse>;
904
+ similarity(text1: string, text2: string, model?: string): Promise<number>;
905
+ listModels(): Promise<AIModelConfig[]>;
906
+ getModel(modelId: string): Promise<AIModelConfig | null>;
907
+ supportsCapability(modelId: string, capability: AIModelType): Promise<boolean>;
908
+ estimateTokens(text: string, _model?: string): Promise<number>;
909
+ estimateCost(): Promise<number>;
910
+ healthCheck(): Promise<{
911
+ healthy: boolean;
912
+ providers: Record<AIProvider, {
913
+ available: boolean;
914
+ latencyMs?: number;
915
+ error?: string;
916
+ }>;
917
+ }>;
918
+ private fetch;
919
+ }
920
+
921
+ export { type AIUsageConfig as A, type Budget as B, type CostBreakdown as C, DEFAULT_AGENT_LOOP_OPTIONS as D, type AgentUsageTrackerOptions as E, type AgentUsageRecordParams as F, type AgentBudget as G, type AgentUsageTracker as H, type IAIUsage as I, createAgentUsageTracker as J, type TracedAIOptions as K, createTracedAI as L, MemoryAIUsage as M, OllamaAdapter as O, type Quota as Q, type ToolExecutor as T, type UsageRecord as U, type UsageQuery as a, type UsageQueryResult as b, type QuotaType as c, type UsageCategory as d, type QuotaStatus as e, type BudgetStatus as f, type UsageInterval as g, type UsageSummary as h, type UsageTrend as i, type UsageInvoice as j, type AlertType as k, type UsageAlert as l, type UsageInvoiceItem as m, type OllamaAdapterConfig as n, type AgentTool as o, type AgentToolResult as p, type AgentCumulativeUsage as q, type AgentIterationEvent as r, type AgentIterationCallback as s, type AgentStopReason as t, type AgentLoopOptions as u, type AgentLoopResult as v, runAgentLoop as w, type AgentTracerOptions as x, type AgentTracer as y, createAgentTracer as z };
package/dist/agents.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export { F as AgentBudget, p as AgentCumulativeUsage, r as AgentIterationCallback, q as AgentIterationEvent, t as AgentLoopOptions, u as AgentLoopResult, s as AgentStopReason, n as AgentTool, o as AgentToolResult, x as AgentTracer, w as AgentTracerOptions, E as AgentUsageRecordParams, G as AgentUsageTracker, z as AgentUsageTrackerOptions, D as DEFAULT_AGENT_LOOP_OPTIONS, T as ToolExecutor, J as TracedAIOptions, y as createAgentTracer, H as createAgentUsageTracker, K as createTracedAI, v as runAgentLoop } from './agents-Cd2eEX5M.mjs';
1
+ export { G as AgentBudget, q as AgentCumulativeUsage, s as AgentIterationCallback, r as AgentIterationEvent, u as AgentLoopOptions, v as AgentLoopResult, t as AgentStopReason, o as AgentTool, p as AgentToolResult, y as AgentTracer, x as AgentTracerOptions, F as AgentUsageRecordParams, H as AgentUsageTracker, E as AgentUsageTrackerOptions, D as DEFAULT_AGENT_LOOP_OPTIONS, O as OllamaAdapter, n as OllamaAdapterConfig, T as ToolExecutor, K as TracedAIOptions, z as createAgentTracer, J as createAgentUsageTracker, L as createTracedAI, w as runAgentLoop } from './agents-DGciJI27.mjs';
2
2
  import './IAI-D8wA_i8N.mjs';
package/dist/agents.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { F as AgentBudget, p as AgentCumulativeUsage, r as AgentIterationCallback, q as AgentIterationEvent, t as AgentLoopOptions, u as AgentLoopResult, s as AgentStopReason, n as AgentTool, o as AgentToolResult, x as AgentTracer, w as AgentTracerOptions, E as AgentUsageRecordParams, G as AgentUsageTracker, z as AgentUsageTrackerOptions, D as DEFAULT_AGENT_LOOP_OPTIONS, T as ToolExecutor, J as TracedAIOptions, y as createAgentTracer, H as createAgentUsageTracker, K as createTracedAI, v as runAgentLoop } from './agents-CntmA45w.js';
1
+ export { G as AgentBudget, q as AgentCumulativeUsage, s as AgentIterationCallback, r as AgentIterationEvent, u as AgentLoopOptions, v as AgentLoopResult, t as AgentStopReason, o as AgentTool, p as AgentToolResult, y as AgentTracer, x as AgentTracerOptions, F as AgentUsageRecordParams, H as AgentUsageTracker, E as AgentUsageTrackerOptions, D as DEFAULT_AGENT_LOOP_OPTIONS, O as OllamaAdapter, n as OllamaAdapterConfig, T as ToolExecutor, K as TracedAIOptions, z as createAgentTracer, J as createAgentUsageTracker, L as createTracedAI, w as runAgentLoop } from './agents-Cc65YUoW.js';
2
2
  import './IAI-D8wA_i8N.js';
package/dist/agents.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var agents_exports = {};
22
22
  __export(agents_exports, {
23
23
  DEFAULT_AGENT_LOOP_OPTIONS: () => DEFAULT_AGENT_LOOP_OPTIONS,
24
+ OllamaAdapter: () => OllamaAdapter,
24
25
  createAgentTracer: () => createAgentTracer,
25
26
  createAgentUsageTracker: () => createAgentUsageTracker,
26
27
  createTracedAI: () => createTracedAI,
@@ -468,9 +469,342 @@ function createTracedAI(options) {
468
469
  }
469
470
  };
470
471
  }
472
+
473
+ // src/interfaces/IAI.ts
474
+ var AIErrorMessages = {
475
+ invalid_request: "The request was invalid or malformed",
476
+ authentication_error: "Authentication failed - check your API key",
477
+ rate_limit_exceeded: "Rate limit exceeded - try again later",
478
+ quota_exceeded: "Usage quota exceeded for this billing period",
479
+ model_not_found: "The specified model was not found",
480
+ context_length_exceeded: "Input exceeds the model context length",
481
+ content_filter: "Content was filtered due to policy violations",
482
+ server_error: "The AI provider encountered an internal error",
483
+ timeout: "The request timed out",
484
+ network_error: "Network error connecting to AI provider",
485
+ provider_unavailable: "The AI provider is currently unavailable",
486
+ unknown: "An unknown error occurred"
487
+ };
488
+ function createAIError(code, message, options) {
489
+ const error = new Error(message || AIErrorMessages[code]);
490
+ error.name = "AIError";
491
+ error.code = code;
492
+ error.provider = options?.provider;
493
+ error.model = options?.model;
494
+ error.statusCode = options?.statusCode;
495
+ error.retryable = options?.retryable ?? [
496
+ "rate_limit_exceeded",
497
+ "server_error",
498
+ "timeout",
499
+ "network_error"
500
+ ].includes(code);
501
+ error.retryAfterMs = options?.retryAfterMs;
502
+ if (options?.cause) {
503
+ error.cause = options.cause;
504
+ }
505
+ return error;
506
+ }
507
+
508
+ // src/adapters/ollama/OllamaAdapter.ts
509
+ var OllamaAdapter = class {
510
+ baseUrl;
511
+ defaultModel;
512
+ defaultEmbeddingModel;
513
+ timeoutMs;
514
+ constructor(config) {
515
+ this.baseUrl = (config?.baseUrl ?? "http://localhost:11434").replace(
516
+ /\/$/,
517
+ ""
518
+ );
519
+ this.defaultModel = config?.defaultModel ?? "qwen2.5:3b";
520
+ this.defaultEmbeddingModel = config?.defaultEmbeddingModel ?? "nomic-embed-text";
521
+ this.timeoutMs = config?.timeoutMs ?? 12e4;
522
+ }
523
+ async chat(request) {
524
+ const model = request.model ?? this.defaultModel;
525
+ const ollamaReq = {
526
+ model,
527
+ messages: request.messages.map((m) => ({
528
+ role: m.role === "tool" ? "assistant" : m.role,
529
+ content: m.content
530
+ })),
531
+ stream: false,
532
+ options: {
533
+ temperature: request.temperature,
534
+ num_predict: request.maxTokens,
535
+ top_p: request.topP,
536
+ stop: request.stop ? Array.isArray(request.stop) ? request.stop : [request.stop] : void 0
537
+ }
538
+ };
539
+ const response = await this.fetch(
540
+ "/api/chat",
541
+ ollamaReq
542
+ );
543
+ const usage = {
544
+ promptTokens: response.prompt_eval_count ?? 0,
545
+ completionTokens: response.eval_count ?? 0,
546
+ totalTokens: (response.prompt_eval_count ?? 0) + (response.eval_count ?? 0),
547
+ estimatedCostUsd: 0
548
+ // Local — zero cost
549
+ };
550
+ return {
551
+ id: `ollama-${Date.now()}`,
552
+ model: response.model ?? model,
553
+ provider: "custom",
554
+ choices: [
555
+ {
556
+ index: 0,
557
+ message: {
558
+ role: "assistant",
559
+ content: response.message.content
560
+ },
561
+ finishReason: "stop"
562
+ }
563
+ ],
564
+ usage,
565
+ created: /* @__PURE__ */ new Date(),
566
+ finishReason: "stop"
567
+ };
568
+ }
569
+ async *chatStream(request) {
570
+ const model = request.model ?? this.defaultModel;
571
+ const ollamaReq = {
572
+ model,
573
+ messages: request.messages.map((m) => ({
574
+ role: m.role === "tool" ? "assistant" : m.role,
575
+ content: m.content
576
+ })),
577
+ stream: true,
578
+ options: {
579
+ temperature: request.temperature,
580
+ num_predict: request.maxTokens,
581
+ top_p: request.topP
582
+ }
583
+ };
584
+ const controller = new AbortController();
585
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
586
+ try {
587
+ const res = await fetch(`${this.baseUrl}/api/chat`, {
588
+ method: "POST",
589
+ headers: { "Content-Type": "application/json" },
590
+ body: JSON.stringify(ollamaReq),
591
+ signal: controller.signal
592
+ });
593
+ if (!res.ok) {
594
+ throw createAIError("server_error", `Ollama error: ${res.status}`);
595
+ }
596
+ const reader = res.body?.getReader();
597
+ if (!reader) return;
598
+ const decoder = new TextDecoder();
599
+ let buffer = "";
600
+ while (true) {
601
+ const { done, value } = await reader.read();
602
+ if (done) break;
603
+ buffer += decoder.decode(value, { stream: true });
604
+ const lines = buffer.split("\n");
605
+ buffer = lines.pop() ?? "";
606
+ for (const line of lines) {
607
+ if (!line.trim()) continue;
608
+ const chunk = JSON.parse(line);
609
+ yield {
610
+ id: `ollama-stream-${Date.now()}`,
611
+ model,
612
+ provider: "custom",
613
+ delta: {
614
+ content: chunk.message?.content ?? ""
615
+ },
616
+ finishReason: chunk.done ? "stop" : void 0
617
+ };
618
+ }
619
+ }
620
+ } finally {
621
+ clearTimeout(timer);
622
+ }
623
+ }
624
+ async chatWithCallback(request, callback) {
625
+ let fullContent = "";
626
+ for await (const chunk of this.chatStream(request)) {
627
+ await callback(chunk);
628
+ if (chunk.delta.content) {
629
+ fullContent += chunk.delta.content;
630
+ }
631
+ }
632
+ const model = request.model ?? this.defaultModel;
633
+ return {
634
+ id: `ollama-${Date.now()}`,
635
+ model,
636
+ provider: "custom",
637
+ choices: [
638
+ {
639
+ index: 0,
640
+ message: { role: "assistant", content: fullContent },
641
+ finishReason: "stop"
642
+ }
643
+ ],
644
+ usage: {
645
+ promptTokens: 0,
646
+ completionTokens: 0,
647
+ totalTokens: 0,
648
+ estimatedCostUsd: 0
649
+ },
650
+ created: /* @__PURE__ */ new Date(),
651
+ finishReason: "stop"
652
+ };
653
+ }
654
+ async complete(request) {
655
+ const response = await this.chat({
656
+ messages: [{ role: "user", content: request.prompt }],
657
+ model: request.model,
658
+ temperature: request.temperature,
659
+ maxTokens: request.maxTokens
660
+ });
661
+ return {
662
+ id: response.id,
663
+ model: response.model,
664
+ provider: "custom",
665
+ text: response.choices[0]?.message.content ?? "",
666
+ usage: response.usage,
667
+ created: response.created,
668
+ finishReason: response.finishReason
669
+ };
670
+ }
671
+ async *completeStream(request) {
672
+ yield* this.chatStream({
673
+ messages: [{ role: "user", content: request.prompt }],
674
+ model: request.model,
675
+ temperature: request.temperature,
676
+ maxTokens: request.maxTokens
677
+ });
678
+ }
679
+ async embed(request) {
680
+ const model = request.model ?? this.defaultEmbeddingModel;
681
+ const response = await this.fetch("/api/embed", {
682
+ model,
683
+ input: request.input
684
+ });
685
+ return {
686
+ id: `ollama-emb-${Date.now()}`,
687
+ model,
688
+ provider: "custom",
689
+ embeddings: response.embeddings,
690
+ usage: {
691
+ promptTokens: 0,
692
+ completionTokens: 0,
693
+ totalTokens: 0,
694
+ estimatedCostUsd: 0
695
+ },
696
+ created: /* @__PURE__ */ new Date()
697
+ };
698
+ }
699
+ async similarity(text1, text2, model) {
700
+ const response = await this.embed({ input: [text1, text2], model });
701
+ const [a, b] = response.embeddings;
702
+ if (!a || !b) return 0;
703
+ let dot = 0, normA = 0, normB = 0;
704
+ for (let i = 0; i < a.length; i++) {
705
+ dot += a[i] * b[i];
706
+ normA += a[i] * a[i];
707
+ normB += b[i] * b[i];
708
+ }
709
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB));
710
+ }
711
+ async listModels() {
712
+ try {
713
+ const response = await this.fetch(
714
+ "/api/tags",
715
+ null,
716
+ "GET"
717
+ );
718
+ return response.models.map((m) => ({
719
+ modelId: m.name,
720
+ provider: "custom",
721
+ capabilities: ["chat", "completion"],
722
+ maxContextTokens: 4096,
723
+ maxOutputTokens: 2048,
724
+ inputCostPer1K: 0,
725
+ outputCostPer1K: 0,
726
+ supportsStreaming: true,
727
+ supportsTools: false,
728
+ supportsVision: false
729
+ }));
730
+ } catch {
731
+ return [];
732
+ }
733
+ }
734
+ async getModel(modelId) {
735
+ const models = await this.listModels();
736
+ return models.find((m) => m.modelId === modelId) ?? null;
737
+ }
738
+ async supportsCapability(modelId, capability) {
739
+ const model = await this.getModel(modelId);
740
+ return model?.capabilities.includes(capability) ?? false;
741
+ }
742
+ async estimateTokens(text, _model) {
743
+ return Math.ceil(text.length / 4);
744
+ }
745
+ async estimateCost() {
746
+ return 0;
747
+ }
748
+ async healthCheck() {
749
+ try {
750
+ const start = Date.now();
751
+ await this.fetch("/api/tags", null, "GET");
752
+ const latency = Date.now() - start;
753
+ return {
754
+ healthy: true,
755
+ providers: {
756
+ custom: { available: true, latencyMs: latency },
757
+ openai: { available: false, error: "Not configured" },
758
+ anthropic: { available: false, error: "Not configured" },
759
+ google: { available: false, error: "Not configured" },
760
+ azure: { available: false, error: "Not configured" },
761
+ bedrock: { available: false, error: "Not configured" }
762
+ }
763
+ };
764
+ } catch (err) {
765
+ return {
766
+ healthy: false,
767
+ providers: {
768
+ custom: {
769
+ available: false,
770
+ error: err instanceof Error ? err.message : "Ollama unavailable"
771
+ },
772
+ openai: { available: false, error: "Not configured" },
773
+ anthropic: { available: false, error: "Not configured" },
774
+ google: { available: false, error: "Not configured" },
775
+ azure: { available: false, error: "Not configured" },
776
+ bedrock: { available: false, error: "Not configured" }
777
+ }
778
+ };
779
+ }
780
+ }
781
+ async fetch(path, body, method = "POST") {
782
+ const controller = new AbortController();
783
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
784
+ try {
785
+ const res = await fetch(`${this.baseUrl}${path}`, {
786
+ method,
787
+ headers: body ? { "Content-Type": "application/json" } : void 0,
788
+ body: body ? JSON.stringify(body) : void 0,
789
+ signal: controller.signal
790
+ });
791
+ if (!res.ok) {
792
+ const text = await res.text().catch(() => "");
793
+ throw createAIError(
794
+ "server_error",
795
+ `Ollama ${method} ${path}: ${res.status} ${text}`
796
+ );
797
+ }
798
+ return await res.json();
799
+ } finally {
800
+ clearTimeout(timer);
801
+ }
802
+ }
803
+ };
471
804
  // Annotate the CommonJS export names for ESM import in node:
472
805
  0 && (module.exports = {
473
806
  DEFAULT_AGENT_LOOP_OPTIONS,
807
+ OllamaAdapter,
474
808
  createAgentTracer,
475
809
  createAgentUsageTracker,
476
810
  createTracedAI,