@nemesis-oss/ollama-sdk 1.6.0 → 1.8.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/README.md +31 -0
  3. package/dist/anthropic-B_UXplNF.d.ts +1647 -0
  4. package/dist/anthropic-CVDFy_a0.d.cts +1647 -0
  5. package/dist/generated-api.cjs +74 -6
  6. package/dist/generated-api.cjs.map +1 -1
  7. package/dist/generated-api.d.cts +230 -629
  8. package/dist/generated-api.d.ts +230 -629
  9. package/dist/generated-api.js +72 -7
  10. package/dist/generated-api.js.map +1 -1
  11. package/dist/generated-models-schemas.cjs +89 -1
  12. package/dist/generated-models-schemas.cjs.map +1 -1
  13. package/dist/generated-models-schemas.d.cts +121 -1
  14. package/dist/generated-models-schemas.d.ts +121 -1
  15. package/dist/generated-models-schemas.js +79 -2
  16. package/dist/generated-models-schemas.js.map +1 -1
  17. package/dist/generated-runtime.cjs +576 -57
  18. package/dist/generated-runtime.cjs.map +1 -1
  19. package/dist/generated-runtime.d.cts +21 -23
  20. package/dist/generated-runtime.d.ts +21 -23
  21. package/dist/generated-runtime.js +575 -58
  22. package/dist/generated-runtime.js.map +1 -1
  23. package/dist/index.cjs +1210 -81
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +395 -876
  26. package/dist/index.d.ts +395 -876
  27. package/dist/index.js +1207 -82
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp/tools.json +287 -73
  30. package/dist/mcp-generated.cjs +96 -7
  31. package/dist/mcp-generated.cjs.map +1 -1
  32. package/dist/mcp-generated.d.cts +3 -3
  33. package/dist/mcp-generated.d.ts +3 -3
  34. package/dist/mcp-generated.js +96 -7
  35. package/dist/mcp-generated.js.map +1 -1
  36. package/dist/mcp-http.cjs +43 -4
  37. package/dist/mcp-http.cjs.map +1 -1
  38. package/dist/mcp-http.d.cts +5 -1
  39. package/dist/mcp-http.d.ts +5 -1
  40. package/dist/mcp-http.js +43 -4
  41. package/dist/mcp-http.js.map +1 -1
  42. package/dist/mcp-stdio.cjs +43 -4
  43. package/dist/mcp-stdio.cjs.map +1 -1
  44. package/dist/mcp-stdio.d.cts +5 -1
  45. package/dist/mcp-stdio.d.ts +5 -1
  46. package/dist/mcp-stdio.js +43 -4
  47. package/dist/mcp-stdio.js.map +1 -1
  48. package/dist/{runtime-CVQkbYgF.d.ts → runtime-C6UYtBRB.d.ts} +222 -6
  49. package/dist/{runtime-IxRpUBjN.d.cts → runtime-DTmUeU6K.d.cts} +222 -6
  50. package/dist/skills.cjs.map +1 -1
  51. package/dist/skills.js.map +1 -1
  52. package/dist/types-CI-gM2u5.d.cts +139 -0
  53. package/dist/types-CI-gM2u5.d.ts +139 -0
  54. package/package.json +4 -2
  55. package/dist/types-MOsWXEE7.d.cts +0 -66
  56. package/dist/types-MOsWXEE7.d.ts +0 -66
package/dist/index.cjs CHANGED
@@ -184,6 +184,35 @@ var OllamaRequestValidationError = class extends OllamaClientError {
184
184
  this.issues = options.issues;
185
185
  }
186
186
  };
187
+ var OllamaRequestTooLargeError = class extends OllamaClientError {
188
+ operationId;
189
+ actualBytes;
190
+ maxBytes;
191
+ constructor(message, options) {
192
+ super(message, { ...options, code: "request_too_large", retryable: false, status: 413 });
193
+ this.operationId = options.operationId;
194
+ this.actualBytes = options.actualBytes;
195
+ this.maxBytes = options.maxBytes;
196
+ }
197
+ };
198
+ var OllamaResponseValidationError = class extends OllamaClientError {
199
+ operationId;
200
+ issues;
201
+ constructor(message, options) {
202
+ super(message, { ...options, code: "response_validation_error", retryable: false });
203
+ this.operationId = options.operationId;
204
+ this.issues = options.issues;
205
+ }
206
+ };
207
+ var OllamaServerVersionUnknownError = class extends OllamaClientError {
208
+ operationId;
209
+ minRequiredVersion;
210
+ constructor(message, options) {
211
+ super(message, { ...options, code: "server_version_unknown", retryable: false });
212
+ this.operationId = options.operationId;
213
+ this.minRequiredVersion = options.minRequiredVersion;
214
+ }
215
+ };
187
216
  var OllamaToolTimeoutError = class extends OllamaClientError {
188
217
  toolName;
189
218
  timeoutMs;
@@ -239,10 +268,12 @@ var OllamaAgentMaxIterationsError = class extends OllamaClientError {
239
268
  var OllamaMcpError = class extends OllamaClientError {
240
269
  mcpMethod;
241
270
  toolName;
271
+ issues;
242
272
  constructor(message, options) {
243
273
  super(message, { ...options, code: "mcp_error", retryable: options.retryable ?? false });
244
274
  this.mcpMethod = options.mcpMethod;
245
275
  this.toolName = options.toolName;
276
+ this.issues = options.issues;
246
277
  }
247
278
  };
248
279
  var OllamaSkillNotFoundError = class extends OllamaClientError {
@@ -1885,8 +1916,9 @@ var ModelsClient = class {
1885
1916
  { singleEndpoint: true }
1886
1917
  );
1887
1918
  return true;
1888
- } catch {
1889
- return false;
1919
+ } catch (err) {
1920
+ if (err instanceof OllamaNotFoundError) return false;
1921
+ throw err;
1890
1922
  }
1891
1923
  }
1892
1924
  };
@@ -2796,28 +2828,45 @@ var ChatRequestSchema = zod.z.object({
2796
2828
  logprobs: zod.z.boolean().optional(),
2797
2829
  top_logprobs: zod.z.number().optional()
2798
2830
  });
2799
- var GenerateRequestSchema = zod.z.object({
2800
- model: zod.z.string(),
2801
- prompt: zod.z.string().optional(),
2802
- suffix: zod.z.string().optional(),
2803
- images: zod.z.array(zod.z.string()).optional(),
2804
- format: zod.z.union([zod.z.string(), zod.z.object({})]).optional(),
2805
- system: zod.z.string().optional(),
2806
- stream: zod.z.boolean().optional(),
2807
- think: ThinkValueSchema.optional(),
2808
- raw: zod.z.boolean().optional(),
2809
- keep_alive: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
2810
- options: ModelOptionsSchema.optional(),
2811
- logprobs: zod.z.boolean().optional(),
2812
- top_logprobs: zod.z.number().optional()
2831
+ var TokenLogprobSchema = zod.z.object({
2832
+ token: zod.z.string().optional(),
2833
+ logprob: zod.z.number().optional(),
2834
+ bytes: zod.z.array(zod.z.number()).optional()
2813
2835
  });
2814
- var EmbedRequestSchema = zod.z.object({
2815
- model: zod.z.string(),
2816
- input: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]),
2817
- truncate: zod.z.boolean().optional(),
2818
- dimensions: zod.z.number().optional(),
2819
- keep_alive: zod.z.string().optional(),
2820
- options: ModelOptionsSchema.optional()
2836
+
2837
+ // src/generated/models/Logprob.schema.ts
2838
+ var LogprobSchema = zod.z.object({
2839
+ token: zod.z.string().optional(),
2840
+ logprob: zod.z.number().optional(),
2841
+ bytes: zod.z.array(zod.z.number()).optional(),
2842
+ top_logprobs: zod.z.array(TokenLogprobSchema).optional()
2843
+ });
2844
+
2845
+ // src/generated/models/ChatResponse.schema.ts
2846
+ var ChatResponseSchema = zod.z.object({
2847
+ model: zod.z.string().optional(),
2848
+ created_at: zod.z.string().optional(),
2849
+ message: zod.z.object({
2850
+ role: zod.z.enum(["assistant"]).optional(),
2851
+ content: zod.z.string().optional(),
2852
+ thinking: zod.z.string().optional(),
2853
+ tool_calls: zod.z.array(ToolCallSchema).optional(),
2854
+ images: zod.z.array(zod.z.string()).optional()
2855
+ }).optional(),
2856
+ done: zod.z.boolean().optional(),
2857
+ done_reason: zod.z.string().optional(),
2858
+ total_duration: zod.z.number().optional(),
2859
+ load_duration: zod.z.number().optional(),
2860
+ prompt_eval_count: zod.z.number().optional(),
2861
+ prompt_eval_cached_count: zod.z.number().optional(),
2862
+ prompt_eval_duration: zod.z.number().optional(),
2863
+ eval_count: zod.z.number().optional(),
2864
+ eval_duration: zod.z.number().optional(),
2865
+ logprobs: zod.z.array(LogprobSchema).optional()
2866
+ });
2867
+ var CopyRequestSchema = zod.z.object({
2868
+ source: zod.z.string(),
2869
+ destination: zod.z.string()
2821
2870
  });
2822
2871
  var CreateRequestSchema = zod.z.object({
2823
2872
  model: zod.z.string(),
@@ -2836,13 +2885,91 @@ var CreateRequestSchema = zod.z.object({
2836
2885
  requires: zod.z.string().optional(),
2837
2886
  stream: zod.z.boolean().optional()
2838
2887
  });
2839
- var CopyRequestSchema = zod.z.object({
2840
- source: zod.z.string(),
2841
- destination: zod.z.string()
2842
- });
2843
2888
  var DeleteRequestSchema = zod.z.object({
2844
2889
  model: zod.z.string()
2845
2890
  });
2891
+ var EmbedRequestSchema = zod.z.object({
2892
+ model: zod.z.string(),
2893
+ input: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]),
2894
+ truncate: zod.z.boolean().optional(),
2895
+ dimensions: zod.z.number().optional(),
2896
+ keep_alive: zod.z.string().optional(),
2897
+ options: ModelOptionsSchema.optional()
2898
+ });
2899
+ var EmbedResponseSchema = zod.z.object({
2900
+ model: zod.z.string().optional(),
2901
+ embeddings: zod.z.array(zod.z.array(zod.z.number())).optional(),
2902
+ total_duration: zod.z.number().optional(),
2903
+ load_duration: zod.z.number().optional(),
2904
+ prompt_eval_count: zod.z.number().optional()
2905
+ });
2906
+ var GenerateRequestSchema = zod.z.object({
2907
+ model: zod.z.string(),
2908
+ prompt: zod.z.string().optional(),
2909
+ suffix: zod.z.string().optional(),
2910
+ images: zod.z.array(zod.z.string()).optional(),
2911
+ format: zod.z.union([zod.z.string(), zod.z.object({})]).optional(),
2912
+ system: zod.z.string().optional(),
2913
+ stream: zod.z.boolean().optional(),
2914
+ think: ThinkValueSchema.optional(),
2915
+ raw: zod.z.boolean().optional(),
2916
+ keep_alive: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
2917
+ options: ModelOptionsSchema.optional(),
2918
+ logprobs: zod.z.boolean().optional(),
2919
+ top_logprobs: zod.z.number().optional()
2920
+ });
2921
+ var GenerateResponseSchema = zod.z.object({
2922
+ model: zod.z.string().optional(),
2923
+ created_at: zod.z.string().optional(),
2924
+ response: zod.z.string().optional(),
2925
+ thinking: zod.z.string().optional(),
2926
+ done: zod.z.boolean().optional(),
2927
+ done_reason: zod.z.string().optional(),
2928
+ total_duration: zod.z.number().optional(),
2929
+ load_duration: zod.z.number().optional(),
2930
+ prompt_eval_count: zod.z.number().optional(),
2931
+ prompt_eval_cached_count: zod.z.number().optional(),
2932
+ prompt_eval_duration: zod.z.number().optional(),
2933
+ eval_count: zod.z.number().optional(),
2934
+ eval_duration: zod.z.number().optional(),
2935
+ logprobs: zod.z.array(LogprobSchema).optional()
2936
+ });
2937
+ var ModelSummarySchema = zod.z.object({
2938
+ name: zod.z.string().optional(),
2939
+ model: zod.z.string().optional(),
2940
+ remote_model: zod.z.string().optional(),
2941
+ remote_host: zod.z.string().optional(),
2942
+ modified_at: zod.z.string().optional(),
2943
+ size: zod.z.number().optional(),
2944
+ digest: zod.z.string().optional(),
2945
+ details: zod.z.object({
2946
+ format: zod.z.string().optional(),
2947
+ family: zod.z.string().optional(),
2948
+ families: zod.z.array(zod.z.string()).optional(),
2949
+ parameter_size: zod.z.string().optional(),
2950
+ quantization_level: zod.z.string().optional()
2951
+ }).optional()
2952
+ });
2953
+
2954
+ // src/generated/models/ListResponse.schema.ts
2955
+ var ListResponseSchema = zod.z.object({
2956
+ models: zod.z.array(ModelSummarySchema).optional()
2957
+ });
2958
+ var PsSchema = zod.z.object({
2959
+ name: zod.z.string().optional(),
2960
+ model: zod.z.string().optional(),
2961
+ size: zod.z.number().optional(),
2962
+ digest: zod.z.string().optional(),
2963
+ details: zod.z.object({}).optional(),
2964
+ expires_at: zod.z.string().optional(),
2965
+ size_vram: zod.z.number().optional(),
2966
+ context_length: zod.z.number().optional()
2967
+ });
2968
+
2969
+ // src/generated/models/PsResponse.schema.ts
2970
+ var PsResponseSchema = zod.z.object({
2971
+ models: zod.z.array(PsSchema).optional()
2972
+ });
2846
2973
  var PullRequestSchema = zod.z.object({
2847
2974
  model: zod.z.string(),
2848
2975
  insecure: zod.z.boolean().optional(),
@@ -2857,27 +2984,164 @@ var ShowRequestSchema = zod.z.object({
2857
2984
  model: zod.z.string(),
2858
2985
  verbose: zod.z.boolean().optional()
2859
2986
  });
2987
+ var ThinkingSchema = zod.z.object({
2988
+ values: zod.z.array(zod.z.union([zod.z.boolean(), zod.z.string()])),
2989
+ default: zod.z.union([zod.z.boolean(), zod.z.string()])
2990
+ });
2991
+
2992
+ // src/generated/models/ShowResponse.schema.ts
2993
+ var ShowResponseSchema = zod.z.object({
2994
+ thinking: ThinkingSchema.optional(),
2995
+ parameters: zod.z.string().optional(),
2996
+ license: zod.z.string().optional(),
2997
+ modified_at: zod.z.string().optional(),
2998
+ details: zod.z.object({}).optional(),
2999
+ template: zod.z.string().optional(),
3000
+ capabilities: zod.z.array(zod.z.string()).optional(),
3001
+ model_info: zod.z.object({}).optional()
3002
+ });
3003
+ var StatusResponseSchema = zod.z.object({
3004
+ status: zod.z.string().optional()
3005
+ });
3006
+ var SystemOneContentSchema = zod.z.union([
3007
+ zod.z.string().regex(new RegExp("\\S")),
3008
+ zod.z.object({}).catchall(zod.z.unknown()),
3009
+ zod.z.array(zod.z.unknown())
3010
+ ]);
3011
+
3012
+ // src/generated/models/SystemOneChoiceQuestion.schema.ts
3013
+ var SystemOneChoiceQuestionSchema = zod.z.object({
3014
+ type: zod.z.enum(["choice"]),
3015
+ instructions: SystemOneContentSchema,
3016
+ criteria: zod.z.object({}).catchall(zod.z.union([zod.z.string(), zod.z.null()])).refine((v) => Object.keys(v).length >= 2, { message: "must have at least 2 properties" }).refine((v) => Object.keys(v).length <= 26, { message: "must have at most 26 properties" }).refine((v) => Object.keys(v).every((k) => new RegExp("\\S").test(k)), {
3017
+ message: 'property names must match pattern "\\S"'
3018
+ })
3019
+ });
3020
+ var SystemOneNoulQuestionSchema = zod.z.object({
3021
+ type: zod.z.enum(["noul"]),
3022
+ instructions: SystemOneContentSchema,
3023
+ criteria: zod.z.object({
3024
+ false: zod.z.string().optional(),
3025
+ true: zod.z.string().optional()
3026
+ }).optional()
3027
+ });
3028
+ var SystemOneScoreQuestionSchema = zod.z.object({
3029
+ type: zod.z.enum(["score"]),
3030
+ instructions: SystemOneContentSchema,
3031
+ criteria: zod.z.array(zod.z.string()).min(2).max(26)
3032
+ });
3033
+
3034
+ // src/generated/models/SystemOneRequest.schema.ts
3035
+ var SystemOneRequestSchema = zod.z.object({
3036
+ model: zod.z.string().regex(new RegExp("\\S")),
3037
+ state: SystemOneContentSchema,
3038
+ images: zod.z.array(zod.z.string()).optional(),
3039
+ questions: zod.z.object({}).catchall(
3040
+ zod.z.union([
3041
+ SystemOneChoiceQuestionSchema,
3042
+ SystemOneNoulQuestionSchema,
3043
+ SystemOneScoreQuestionSchema
3044
+ ])
3045
+ ).refine((v) => Object.keys(v).length >= 1, { message: "must have at least 1 properties" }).refine((v) => Object.keys(v).length <= 64, { message: "must have at most 64 properties" }).refine((v) => Object.keys(v).every((k) => new RegExp("\\S").test(k)), {
3046
+ message: 'property names must match pattern "\\S"'
3047
+ }),
3048
+ keep_alive: zod.z.union([zod.z.string(), zod.z.number()]).optional()
3049
+ });
3050
+ var SystemOneConfidenceSchema = zod.z.number().min(0).max(1);
3051
+ var SystemOneProbabilitiesSchema = zod.z.object({}).catchall(zod.z.number().min(0).max(1));
3052
+
3053
+ // src/generated/models/SystemOneChoiceAnswer.schema.ts
3054
+ var SystemOneChoiceAnswerSchema = zod.z.object({
3055
+ type: zod.z.enum(["choice"]),
3056
+ choice: zod.z.string(),
3057
+ probabilities: SystemOneProbabilitiesSchema,
3058
+ confidence: SystemOneConfidenceSchema
3059
+ });
3060
+ var SystemOneNoulAnswerSchema = zod.z.object({
3061
+ type: zod.z.enum(["noul"]),
3062
+ noul: zod.z.number().min(0).max(1)
3063
+ });
3064
+ var SystemOneScoreAnswerSchema = zod.z.object({
3065
+ type: zod.z.enum(["score"]),
3066
+ score: zod.z.number().min(0).max(25),
3067
+ legend: zod.z.object({}).catchall(zod.z.string()),
3068
+ probabilities: SystemOneProbabilitiesSchema,
3069
+ confidence: SystemOneConfidenceSchema
3070
+ });
3071
+
3072
+ // src/generated/models/SystemOneResponse.schema.ts
3073
+ var SystemOneResponseSchema = zod.z.object({
3074
+ model: zod.z.string(),
3075
+ answers: zod.z.object({}).catchall(
3076
+ zod.z.union([SystemOneChoiceAnswerSchema, SystemOneNoulAnswerSchema, SystemOneScoreAnswerSchema])
3077
+ ),
3078
+ usage: zod.z.object({
3079
+ input_tokens: zod.z.number().min(0),
3080
+ output_tokens: zod.z.number().min(0)
3081
+ })
3082
+ });
3083
+ var VersionResponseSchema = zod.z.object({
3084
+ version: zod.z.string().optional()
3085
+ });
3086
+ var WebFetchRequestSchema = zod.z.object({
3087
+ url: zod.z.string()
3088
+ });
3089
+ var WebFetchResponseSchema = zod.z.object({
3090
+ title: zod.z.string().optional(),
3091
+ content: zod.z.string().optional(),
3092
+ links: zod.z.array(zod.z.string()).optional()
3093
+ });
3094
+ var WebSearchRequestSchema = zod.z.object({
3095
+ query: zod.z.string(),
3096
+ max_results: zod.z.number().min(1).max(10).optional()
3097
+ });
3098
+ var WebSearchResultSchema = zod.z.object({
3099
+ title: zod.z.string().optional(),
3100
+ url: zod.z.string().optional(),
3101
+ content: zod.z.string().optional()
3102
+ });
3103
+
3104
+ // src/generated/models/WebSearchResponse.schema.ts
3105
+ var WebSearchResponseSchema = zod.z.object({
3106
+ results: zod.z.array(WebSearchResultSchema).optional()
3107
+ });
2860
3108
 
2861
3109
  // src/generated/runtime/schema-registry.ts
2862
3110
  var requestSchemas = {
2863
3111
  chat: ChatRequestSchema,
2864
- generate: GenerateRequestSchema,
2865
- embed: EmbedRequestSchema,
2866
- create: CreateRequestSchema,
2867
3112
  copy: CopyRequestSchema,
3113
+ create: CreateRequestSchema,
2868
3114
  delete: DeleteRequestSchema,
3115
+ embed: EmbedRequestSchema,
3116
+ generate: GenerateRequestSchema,
2869
3117
  pull: PullRequestSchema,
2870
3118
  push: PushRequestSchema,
2871
- show: ShowRequestSchema
2872
- // Operations without a registered request schema (blobs, ps, tags,
2873
- // version, systemOne, openai*, anthropic*) skip validation. This is
2874
- // deliberate — the OpenAPI spec doesn't define request bodies for
2875
- // GET/HEAD operations, and the compat-surface request schemas (OpenAI,
2876
- // Anthropic) are richer than what the IR currently models.
3119
+ show: ShowRequestSchema,
3120
+ systemOne: SystemOneRequestSchema,
3121
+ webFetch: WebFetchRequestSchema,
3122
+ webSearch: WebSearchRequestSchema
3123
+ };
3124
+ var responseSchemas = {
3125
+ chat: ChatResponseSchema,
3126
+ create: StatusResponseSchema,
3127
+ embed: EmbedResponseSchema,
3128
+ generate: GenerateResponseSchema,
3129
+ ps: PsResponseSchema,
3130
+ pull: StatusResponseSchema,
3131
+ push: StatusResponseSchema,
3132
+ show: ShowResponseSchema,
3133
+ systemOne: SystemOneResponseSchema,
3134
+ tags: ListResponseSchema,
3135
+ version: VersionResponseSchema,
3136
+ webFetch: WebFetchResponseSchema,
3137
+ webSearch: WebSearchResponseSchema
2877
3138
  };
2878
3139
  function getRequestSchema(operationId) {
2879
3140
  return requestSchemas[operationId];
2880
3141
  }
3142
+ function getResponseSchema(operationId) {
3143
+ return responseSchemas[operationId];
3144
+ }
2881
3145
 
2882
3146
  // src/generated/runtime/runtime.ts
2883
3147
  function compareVersions(a, b) {
@@ -2890,18 +3154,13 @@ function compareVersions(a, b) {
2890
3154
  }
2891
3155
  return 0;
2892
3156
  }
2893
- function assertOperationAllowed(operation, options) {
2894
- const localMode = options.localMode ?? true;
2895
- if (!localMode && !operation.environment.cloud) {
2896
- throw new OllamaGenericClientError(
2897
- `Operation ${operation.operationId} (${operation.method} ${operation.path}) is local-only and not supported in cloud mode.`
2898
- );
2899
- }
2900
- if (operation.constraints?.minOllamaVersion && options.serverVersion && compareVersions(options.serverVersion, operation.constraints.minOllamaVersion) < 0) {
2901
- throw new OllamaGenericClientError(
2902
- `Operation ${operation.operationId} (${operation.method} ${operation.path}) requires Ollama >= ${operation.constraints.minOllamaVersion} (server reports ${options.serverVersion}).`
2903
- );
2904
- }
3157
+ async function fetchServerVersion(http) {
3158
+ const result = await http.request({
3159
+ path: "/api/version",
3160
+ method: "GET"
3161
+ });
3162
+ if (result && typeof result.version === "string") return result.version;
3163
+ return void 0;
2905
3164
  }
2906
3165
  function shouldStream(req) {
2907
3166
  if (req.body && typeof req.body === "object" && "stream" in req.body) {
@@ -2924,6 +3183,35 @@ var OllamaRuntime = class {
2924
3183
  this.options = options;
2925
3184
  }
2926
3185
  options;
3186
+ /**
3187
+ * Cached promise of the Ollama server version, populated lazily the first
3188
+ * time a version-gated operation is invoked. `undefined` until then.
3189
+ *
3190
+ * Wave 12 (P0 #5): see {@link OllamaRuntimeOptions.enforceVersion}.
3191
+ */
3192
+ serverVersionCache;
3193
+ /**
3194
+ * Wave 15 (P0): resolve the HTTP backend for a given operation.
3195
+ *
3196
+ * Operations with a declared `host` (e.g. web search/fetch at
3197
+ * https://ollama.com) must route to a HttpClient pointed at that host,
3198
+ * not the default one. The runtime accepts an optional `cloudHttp`
3199
+ * backend for this purpose — if the operation declares a host and no
3200
+ * cloud backend is configured, the runtime throws rather than silently
3201
+ * sending the request to the wrong server.
3202
+ */
3203
+ resolveHttpBackend(operation) {
3204
+ if (operation.host) {
3205
+ const cloudHttp = this.options.cloudHttp;
3206
+ if (!cloudHttp) {
3207
+ throw new OllamaGenericClientError(
3208
+ `Operation ${operation.operationId} (${operation.method} ${operation.path}) targets host "${operation.host}" but the runtime has no cloudHttp backend configured. Use OllamaClient.webSearch() / OllamaClient.webFetch() for cloud-hosted operations, or construct OllamaRuntime with a cloudHttp option.`
3209
+ );
3210
+ }
3211
+ return cloudHttp;
3212
+ }
3213
+ return this.options.http;
3214
+ }
2927
3215
  /**
2928
3216
  * Invoke an operation. Called by every generated API method.
2929
3217
  *
@@ -2932,7 +3220,7 @@ var OllamaRuntime = class {
2932
3220
  * class's overloads pick the right return type at compile time.
2933
3221
  */
2934
3222
  async invoke(req) {
2935
- assertOperationAllowed(req.operation, this.options);
3223
+ await this.assertOperationAllowed(req.operation);
2936
3224
  let body = buildBody(req);
2937
3225
  if (this.options.validateRequests === true && body !== void 0) {
2938
3226
  const schema = getRequestSchema(req.operation.operationId);
@@ -2951,32 +3239,668 @@ var OllamaRuntime = class {
2951
3239
  body = result.data;
2952
3240
  }
2953
3241
  }
3242
+ if (body !== void 0) {
3243
+ const serialized = serializeForByteCount(body);
3244
+ const hasImages = bodyHasImages(body);
3245
+ const maxBytesWithImages = req.operation.constraints?.maxRequestBytesWithImages;
3246
+ const maxBytesBase = req.operation.constraints?.maxRequestBytes;
3247
+ const applicableLimit = hasImages && maxBytesWithImages !== void 0 ? maxBytesWithImages : maxBytesBase;
3248
+ if (applicableLimit !== void 0 && serialized.byteLength > applicableLimit) {
3249
+ throw new OllamaRequestTooLargeError(
3250
+ `Operation ${req.operation.operationId} (${req.operation.method} ${req.operation.path}) request body is ${serialized.byteLength} bytes, exceeding the contract limit of ${applicableLimit} bytes` + (hasImages ? " (images limit)." : "."),
3251
+ {
3252
+ operationId: req.operation.operationId,
3253
+ actualBytes: serialized.byteLength,
3254
+ maxBytes: applicableLimit,
3255
+ request: { method: req.operation.method, url: req.operation.path }
3256
+ }
3257
+ );
3258
+ }
3259
+ }
2954
3260
  const streaming = shouldStream(req);
3261
+ const resolvedPath = resolvePathParams(req.operation.path, req.pathParams);
3262
+ const model = req.model ?? extractModelFromBody(body);
2955
3263
  const httpReq = {
2956
- path: req.operation.path,
3264
+ path: resolvedPath,
2957
3265
  method: req.operation.method,
2958
3266
  ...body !== void 0 ? { body } : {},
2959
3267
  ...req.signal !== void 0 ? { signal: req.signal } : {},
2960
- // For streaming calls, request the raw Response so we can pipe it
2961
- // through parseNdjsonStream directly. This inherits middleware,
2962
- // retry, telemetry, and error-mapping from HttpClient — the
2963
- // previous Wave 3 implementation bypassed them with a direct
2964
- // `fetch()` call.
2965
- ...streaming ? { raw: true } : {}
3268
+ ...streaming ? { raw: true } : {},
3269
+ ...model !== void 0 ? { model } : {}
2966
3270
  };
2967
3271
  if (!streaming) {
2968
- return await this.options.http.request(httpReq);
3272
+ const result = await this.resolveHttpBackend(req.operation).request(httpReq);
3273
+ if (this.options.validateResponses === true) {
3274
+ const responseSchema = getResponseSchema(req.operation.operationId);
3275
+ if (responseSchema) {
3276
+ const result2 = responseSchema.safeParse(result);
3277
+ if (!result2.success) {
3278
+ throw new OllamaResponseValidationError(
3279
+ `Response validation failed for operation "${req.operation.operationId}" (${req.operation.method} ${req.operation.path}): ` + result2.error.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; "),
3280
+ {
3281
+ operationId: req.operation.operationId,
3282
+ issues: result2.error.issues,
3283
+ request: { method: req.operation.method, url: req.operation.path }
3284
+ }
3285
+ );
3286
+ }
3287
+ }
3288
+ }
3289
+ return result;
2969
3290
  }
2970
- const response = await this.options.http.request(httpReq);
3291
+ const response = await this.resolveHttpBackend(req.operation).request(httpReq);
2971
3292
  if (!response.body) {
2972
3293
  throw new OllamaGenericClientError(
2973
3294
  `Operation ${req.operation.operationId}: streaming response had no body.`
2974
3295
  );
2975
3296
  }
2976
- return parseNdjsonStream(response.body);
3297
+ return parseStreamByMode(req.operation.transport.mode, response.body);
3298
+ }
3299
+ /**
3300
+ * Apply environment + version guards before delegating to HttpClient.
3301
+ *
3302
+ * Throws {@link OllamaGenericClientError} when:
3303
+ * - The operation is local-only and the runtime is in cloud mode.
3304
+ * - The operation has `constraints.minOllamaVersion` and the server is older.
3305
+ *
3306
+ * Wave 12 (P0 #5): when `minOllamaVersion` is declared but the runtime's
3307
+ * `serverVersion` is unknown AND `enforceVersion` is `'auto'` or
3308
+ * `'strict'`, the runtime lazily fetches `/api/version` (cached on the
3309
+ * runtime instance) so the constraint is actually enforced even when the
3310
+ * caller didn't supply it. Previously the constraint was only enforced
3311
+ * when `serverVersion` was manually supplied — meaning in practice it was
3312
+ * almost never enforced.
3313
+ */
3314
+ async assertOperationAllowed(operation) {
3315
+ const localMode = this.options.localMode ?? true;
3316
+ if (!localMode && !operation.environment.cloud) {
3317
+ throw new OllamaGenericClientError(
3318
+ `Operation ${operation.operationId} (${operation.method} ${operation.path}) is local-only and not supported in cloud mode.`
3319
+ );
3320
+ }
3321
+ const minVersion = operation.constraints?.minOllamaVersion;
3322
+ if (!minVersion) return;
3323
+ let serverVersion = this.options.serverVersion;
3324
+ const policy = this.options.enforceVersion ?? "auto";
3325
+ if (!serverVersion && policy !== "off") {
3326
+ if (!this.serverVersionCache) {
3327
+ const p = fetchServerVersion(this.options.http).catch((err) => {
3328
+ if (policy === "strict") {
3329
+ throw new OllamaServerVersionUnknownError(
3330
+ `Operation ${operation.operationId} requires Ollama >= ${minVersion} but the runtime could not determine the server version (enforceVersion: 'strict').`,
3331
+ {
3332
+ operationId: operation.operationId,
3333
+ minRequiredVersion: minVersion,
3334
+ cause: err
3335
+ }
3336
+ );
3337
+ }
3338
+ return void 0;
3339
+ });
3340
+ this.serverVersionCache = p;
3341
+ }
3342
+ serverVersion = await this.serverVersionCache ?? void 0;
3343
+ }
3344
+ if (serverVersion && compareVersions(serverVersion, minVersion) < 0) {
3345
+ throw new OllamaGenericClientError(
3346
+ `Operation ${operation.operationId} (${operation.method} ${operation.path}) requires Ollama >= ${minVersion} (server reports ${serverVersion}).`
3347
+ );
3348
+ }
3349
+ }
3350
+ };
3351
+ function parseStreamByMode(mode, body) {
3352
+ if (mode === "ndjson") {
3353
+ return parseNdjsonStream(body);
3354
+ }
3355
+ if (mode === "sse") {
3356
+ return parseSseStreamAsJson(body);
3357
+ }
3358
+ throw new OllamaGenericClientError(
3359
+ `Transport mode "${mode}" is not a streaming mode; cannot parse a stream for it.`
3360
+ );
3361
+ }
3362
+ async function* parseSseStreamAsJson(body) {
3363
+ for await (const event of parseSseStream(body)) {
3364
+ const data = event.data;
3365
+ if (!data) continue;
3366
+ if (data === "[DONE]") return;
3367
+ try {
3368
+ yield JSON.parse(data);
3369
+ } catch (err) {
3370
+ throw new OllamaGenericClientError(`Failed to parse SSE event data as JSON: ${data}`, {
3371
+ cause: err
3372
+ });
3373
+ }
3374
+ }
3375
+ }
3376
+ function serializeForByteCount(body) {
3377
+ if (body instanceof Uint8Array) return body;
3378
+ if (typeof body === "string") return new TextEncoder().encode(body);
3379
+ const json = JSON.stringify(body);
3380
+ return new TextEncoder().encode(json);
3381
+ }
3382
+ function bodyHasImages(body) {
3383
+ if (typeof body !== "object" || body === null) return false;
3384
+ const obj = body;
3385
+ const images = obj.images;
3386
+ return Array.isArray(images) && images.length > 0;
3387
+ }
3388
+ function resolvePathParams(pathTemplate, pathParams) {
3389
+ if (!pathTemplate.includes("{")) return pathTemplate;
3390
+ const params = pathParams ?? {};
3391
+ return pathTemplate.replace(/\{([^}]+)\}/g, (_match, name) => {
3392
+ const value = params[name];
3393
+ if (value === void 0) {
3394
+ throw new OllamaGenericClientError(
3395
+ `Missing path parameter "${name}" for path template "${pathTemplate}". Provide it via the pathParams field on the invoke() request.`
3396
+ );
3397
+ }
3398
+ return encodeURIComponent(value);
3399
+ });
3400
+ }
3401
+ function extractModelFromBody(body) {
3402
+ if (typeof body !== "object" || body === null) return void 0;
3403
+ const obj = body;
3404
+ const model = obj.model;
3405
+ return typeof model === "string" ? model : void 0;
3406
+ }
3407
+
3408
+ // src/generated/api/operations.ts
3409
+ var blobsOp = {
3410
+ operationId: "blobs",
3411
+ method: "HEAD",
3412
+ path: "/api/blobs/{digest}",
3413
+ environment: { local: true, cloud: false },
3414
+ parameters: [{ name: "digest", in: "path", required: true, schema: { type: "string" } }],
3415
+ transport: { mode: "json", streaming: false },
3416
+ capabilities: {},
3417
+ status: { documented: true },
3418
+ domain: "native",
3419
+ notes: [
3420
+ "HEAD-only endpoint for blob existence checks; declared in OpenAPI but not in the legacy parity manifest."
3421
+ ]
3422
+ };
3423
+ var chatOp = {
3424
+ operationId: "chat",
3425
+ method: "POST",
3426
+ path: "/api/chat",
3427
+ request: { $ref: "#/schemas/ChatRequest" },
3428
+ response: { $ref: "#/schemas/ChatResponse" },
3429
+ environment: { local: true, cloud: true },
3430
+ transport: { mode: "ndjson", streaming: true, streamingDefault: true },
3431
+ capabilities: {
3432
+ thinking: "model-dependent",
3433
+ tools: "model-dependent",
3434
+ vision: "model-dependent",
3435
+ structuredOutput: "supported",
3436
+ logprobs: "supported"
3437
+ },
3438
+ status: { documented: true },
3439
+ domain: "native",
3440
+ notes: [
3441
+ "Use /api/show to discover model-specific thinking values and defaults.",
3442
+ "Structured output (format field) is rejected by Ollama Cloud."
3443
+ ]
3444
+ };
3445
+ var copyOp = {
3446
+ operationId: "copy",
3447
+ method: "POST",
3448
+ path: "/api/copy",
3449
+ request: { $ref: "#/schemas/CopyRequest" },
3450
+ environment: { local: true, cloud: false },
3451
+ transport: { mode: "json", streaming: false },
3452
+ capabilities: {},
3453
+ status: { documented: true },
3454
+ domain: "native"
3455
+ };
3456
+ var createOp = {
3457
+ operationId: "create",
3458
+ method: "POST",
3459
+ path: "/api/create",
3460
+ request: { $ref: "#/schemas/CreateRequest" },
3461
+ response: { $ref: "#/schemas/StatusResponse" },
3462
+ environment: { local: true, cloud: false },
3463
+ transport: { mode: "ndjson", streaming: true, streamingDefault: true },
3464
+ capabilities: { thinking: "unsupported", tools: "unsupported" },
3465
+ status: { documented: true },
3466
+ domain: "native",
3467
+ notes: ["Model creation is local-only; Ollama Cloud does not support it."]
3468
+ };
3469
+ var deleteOp = {
3470
+ operationId: "delete",
3471
+ method: "DELETE",
3472
+ path: "/api/delete",
3473
+ request: { $ref: "#/schemas/DeleteRequest" },
3474
+ environment: { local: true, cloud: false },
3475
+ transport: { mode: "json", streaming: false },
3476
+ capabilities: {},
3477
+ status: { documented: true },
3478
+ domain: "native"
3479
+ };
3480
+ var embedOp = {
3481
+ operationId: "embed",
3482
+ method: "POST",
3483
+ path: "/api/embed",
3484
+ request: { $ref: "#/schemas/EmbedRequest" },
3485
+ response: { $ref: "#/schemas/EmbedResponse" },
3486
+ environment: { local: true, cloud: true },
3487
+ transport: { mode: "json", streaming: false },
3488
+ capabilities: { embeddings: "supported" },
3489
+ status: { documented: true },
3490
+ domain: "native"
3491
+ };
3492
+ var generateOp = {
3493
+ operationId: "generate",
3494
+ method: "POST",
3495
+ path: "/api/generate",
3496
+ request: { $ref: "#/schemas/GenerateRequest" },
3497
+ response: { $ref: "#/schemas/GenerateResponse" },
3498
+ environment: { local: true, cloud: true },
3499
+ transport: { mode: "ndjson", streaming: true, streamingDefault: true },
3500
+ capabilities: {
3501
+ thinking: "model-dependent",
3502
+ vision: "supported",
3503
+ structuredOutput: "supported",
3504
+ logprobs: "supported"
3505
+ },
3506
+ status: { documented: true },
3507
+ domain: "native"
3508
+ };
3509
+ var psOp = {
3510
+ operationId: "ps",
3511
+ method: "GET",
3512
+ path: "/api/ps",
3513
+ response: { $ref: "#/schemas/PsResponse" },
3514
+ environment: { local: true, cloud: true },
3515
+ transport: { mode: "json", streaming: false },
3516
+ capabilities: {},
3517
+ status: { documented: true },
3518
+ domain: "native"
3519
+ };
3520
+ var pullOp = {
3521
+ operationId: "pull",
3522
+ method: "POST",
3523
+ path: "/api/pull",
3524
+ request: { $ref: "#/schemas/PullRequest" },
3525
+ response: { $ref: "#/schemas/StatusResponse" },
3526
+ environment: { local: true, cloud: false },
3527
+ transport: { mode: "ndjson", streaming: true, streamingDefault: true },
3528
+ capabilities: {},
3529
+ status: { documented: true },
3530
+ domain: "native"
3531
+ };
3532
+ var pushOp = {
3533
+ operationId: "push",
3534
+ method: "POST",
3535
+ path: "/api/push",
3536
+ request: { $ref: "#/schemas/PushRequest" },
3537
+ response: { $ref: "#/schemas/StatusResponse" },
3538
+ environment: { local: true, cloud: false },
3539
+ transport: { mode: "ndjson", streaming: true, streamingDefault: true },
3540
+ capabilities: {},
3541
+ status: { documented: true },
3542
+ domain: "native"
3543
+ };
3544
+ var showOp = {
3545
+ operationId: "show",
3546
+ method: "POST",
3547
+ path: "/api/show",
3548
+ request: { $ref: "#/schemas/ShowRequest" },
3549
+ response: { $ref: "#/schemas/ShowResponse" },
3550
+ environment: { local: true, cloud: true },
3551
+ transport: { mode: "json", streaming: false },
3552
+ capabilities: {},
3553
+ status: { documented: true },
3554
+ domain: "native",
3555
+ notes: [
3556
+ "Capabilities source: /api/show is the runtime source of truth for model-dependent capability values (tools, vision, thinking, embeddings)."
3557
+ ]
3558
+ };
3559
+ var systemOneOp = {
3560
+ operationId: "systemOne",
3561
+ method: "POST",
3562
+ path: "/v1/systemone",
3563
+ request: { $ref: "#/schemas/SystemOneRequest" },
3564
+ response: { $ref: "#/schemas/SystemOneResponse" },
3565
+ environment: { local: true, cloud: false },
3566
+ transport: { mode: "json", streaming: false },
3567
+ capabilities: {
3568
+ thinking: "unsupported",
3569
+ tools: "unsupported",
3570
+ vision: "model-dependent",
3571
+ structuredOutput: "unsupported",
3572
+ logprobs: "unsupported",
3573
+ embeddings: "unsupported"
3574
+ },
3575
+ constraints: {
3576
+ minOllamaVersion: "0.35.0",
3577
+ maxRequestBytes: 65536,
3578
+ maxRequestBytesWithImages: 33554432
3579
+ },
3580
+ status: { documented: true, experimental: true },
3581
+ domain: "native",
3582
+ notes: [
3583
+ "Local-only; Ollama Cloud rejects /v1/systemone.",
3584
+ "64 KiB request limit without images, 32 MiB with images (includes JSON/base64 overhead).",
3585
+ "No tools, no generation controls (temperature, top_p, etc.).",
3586
+ "Vision is model-dependent: images are accepted by vision-weighted models (Clef/Clef Flash) but not by text-only models.",
3587
+ "Experimental: behavioral surface may change between Ollama releases."
3588
+ ]
3589
+ };
3590
+ var tagsOp = {
3591
+ operationId: "tags",
3592
+ method: "GET",
3593
+ path: "/api/tags",
3594
+ response: { $ref: "#/schemas/ListResponse" },
3595
+ environment: { local: true, cloud: true },
3596
+ transport: { mode: "json", streaming: false },
3597
+ capabilities: {},
3598
+ status: { documented: true },
3599
+ domain: "native"
3600
+ };
3601
+ var versionOp = {
3602
+ operationId: "version",
3603
+ method: "GET",
3604
+ path: "/api/version",
3605
+ response: { $ref: "#/schemas/VersionResponse" },
3606
+ environment: { local: true, cloud: true },
3607
+ transport: { mode: "json", streaming: false },
3608
+ capabilities: {},
3609
+ status: { documented: true },
3610
+ domain: "native"
3611
+ };
3612
+
3613
+ // src/generated/api/native-api.ts
3614
+ var NativeApi = class {
3615
+ constructor(runtime) {
3616
+ this.runtime = runtime;
3617
+ }
3618
+ runtime;
3619
+ blobs(digest, options) {
3620
+ return this.runtime.invoke({
3621
+ operation: blobsOp,
3622
+ body: void 0,
3623
+ pathParams: { digest },
3624
+ ...options?.signal !== void 0 ? { signal: options.signal } : {}
3625
+ });
3626
+ }
3627
+ chat(request) {
3628
+ return this.runtime.invoke({
3629
+ operation: chatOp,
3630
+ body: request,
3631
+ streamingDefault: true
3632
+ });
3633
+ }
3634
+ copy(request) {
3635
+ return this.runtime.invoke({
3636
+ operation: copyOp,
3637
+ body: request
3638
+ });
3639
+ }
3640
+ create(request) {
3641
+ return this.runtime.invoke({
3642
+ operation: createOp,
3643
+ body: request,
3644
+ streamingDefault: true
3645
+ });
3646
+ }
3647
+ delete(request) {
3648
+ return this.runtime.invoke({
3649
+ operation: deleteOp,
3650
+ body: request
3651
+ });
3652
+ }
3653
+ embed(request) {
3654
+ return this.runtime.invoke({
3655
+ operation: embedOp,
3656
+ body: request
3657
+ });
3658
+ }
3659
+ generate(request) {
3660
+ return this.runtime.invoke({
3661
+ operation: generateOp,
3662
+ body: request,
3663
+ streamingDefault: true
3664
+ });
3665
+ }
3666
+ ps(options) {
3667
+ return this.runtime.invoke({
3668
+ operation: psOp,
3669
+ body: void 0,
3670
+ ...options?.signal !== void 0 ? { signal: options.signal } : {}
3671
+ });
3672
+ }
3673
+ pull(request) {
3674
+ return this.runtime.invoke({
3675
+ operation: pullOp,
3676
+ body: request,
3677
+ streamingDefault: true
3678
+ });
3679
+ }
3680
+ push(request) {
3681
+ return this.runtime.invoke({
3682
+ operation: pushOp,
3683
+ body: request,
3684
+ streamingDefault: true
3685
+ });
3686
+ }
3687
+ show(request) {
3688
+ return this.runtime.invoke({
3689
+ operation: showOp,
3690
+ body: request
3691
+ });
3692
+ }
3693
+ systemOne(request) {
3694
+ return this.runtime.invoke({
3695
+ operation: systemOneOp,
3696
+ body: request
3697
+ });
3698
+ }
3699
+ tags(options) {
3700
+ return this.runtime.invoke({
3701
+ operation: tagsOp,
3702
+ body: void 0,
3703
+ ...options?.signal !== void 0 ? { signal: options.signal } : {}
3704
+ });
3705
+ }
3706
+ version(options) {
3707
+ return this.runtime.invoke({
3708
+ operation: versionOp,
3709
+ body: void 0,
3710
+ ...options?.signal !== void 0 ? { signal: options.signal } : {}
3711
+ });
2977
3712
  }
2978
3713
  };
2979
3714
 
3715
+ // src/failover-http-client.ts
3716
+ var FailoverHttpClient = class {
3717
+ constructor(client, baseUrl) {
3718
+ this.client = client;
3719
+ this.baseUrl = baseUrl;
3720
+ }
3721
+ client;
3722
+ /**
3723
+ * The first candidate endpoint's base URL. Used for inferRuntimeMode()
3724
+ * checks (local vs cloud). The actual request routing picks the best
3725
+ * healthy endpoint per call.
3726
+ */
3727
+ baseUrl;
3728
+ /**
3729
+ * Route a request through OllamaClient's failover machinery.
3730
+ *
3731
+ * Each call to request() goes through executeWithFailover, which:
3732
+ * - Picks the best healthy endpoint from the registry
3733
+ * - Applies retry/backoff within that endpoint
3734
+ * - Fails over to the next candidate on retryable errors
3735
+ * - Reports success/failure to the endpoint health tracker
3736
+ *
3737
+ * Wave 15 (P1): the model is extracted from the request body by the
3738
+ * runtime and passed via the `model` field on the options. This lets
3739
+ * the failover layer filter endpoints by `OllamaEndpoint.models`
3740
+ * (credential-scoped routing). If no model is provided, all endpoints
3741
+ * are considered.
3742
+ *
3743
+ * The `raw` option (for streaming responses) is passed through
3744
+ * unchanged — executeWithFailover returns whatever the operation
3745
+ * callback returns, including raw Response objects.
3746
+ */
3747
+ async request(options) {
3748
+ const { model, ...httpOptions } = options;
3749
+ return this.client.executeWithFailover(
3750
+ async (http, signal) => {
3751
+ const mergedOptions = {
3752
+ ...httpOptions,
3753
+ ...httpOptions.signal !== void 0 ? { signal } : { signal }
3754
+ };
3755
+ return http.request(mergedOptions);
3756
+ },
3757
+ {
3758
+ singleEndpoint: false,
3759
+ ...model !== void 0 ? { model } : {}
3760
+ }
3761
+ );
3762
+ }
3763
+ };
3764
+
3765
+ // src/decision.ts
3766
+ function createDecision(client) {
3767
+ return {
3768
+ async choice(params) {
3769
+ const response = await client.systemOne({
3770
+ model: params.model,
3771
+ state: params.state,
3772
+ ...params.images ? { images: params.images } : {},
3773
+ questions: {
3774
+ decision: {
3775
+ type: "choice",
3776
+ instructions: params.instructions,
3777
+ criteria: params.criteria
3778
+ }
3779
+ },
3780
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3781
+ });
3782
+ const answer = response.answers.decision;
3783
+ return {
3784
+ choice: answer.choice,
3785
+ probabilities: answer.probabilities,
3786
+ confidence: answer.confidence,
3787
+ usage: response.usage
3788
+ };
3789
+ },
3790
+ async noul(params) {
3791
+ const response = await client.systemOne({
3792
+ model: params.model,
3793
+ state: params.state,
3794
+ ...params.images ? { images: params.images } : {},
3795
+ questions: {
3796
+ decision: {
3797
+ type: "noul",
3798
+ instructions: params.instructions
3799
+ }
3800
+ },
3801
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3802
+ });
3803
+ const answer = response.answers.decision;
3804
+ return {
3805
+ noul: answer.noul,
3806
+ bool: answer.noul >= 0.5,
3807
+ usage: response.usage
3808
+ };
3809
+ },
3810
+ async score(params) {
3811
+ const response = await client.systemOne({
3812
+ model: params.model,
3813
+ state: params.state,
3814
+ ...params.images ? { images: params.images } : {},
3815
+ questions: {
3816
+ decision: {
3817
+ type: "score",
3818
+ instructions: params.instructions,
3819
+ criteria: params.criteria
3820
+ }
3821
+ },
3822
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3823
+ });
3824
+ const answer = response.answers.decision;
3825
+ return {
3826
+ score: answer.score,
3827
+ legend: answer.legend,
3828
+ probabilities: answer.probabilities,
3829
+ confidence: answer.confidence,
3830
+ usage: response.usage
3831
+ };
3832
+ },
3833
+ async route(params) {
3834
+ const response = await client.systemOne({
3835
+ model: params.model,
3836
+ state: params.state,
3837
+ ...params.images ? { images: params.images } : {},
3838
+ questions: {
3839
+ decision: {
3840
+ type: "choice",
3841
+ instructions: params.instructions,
3842
+ criteria: params.criteria
3843
+ }
3844
+ },
3845
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3846
+ });
3847
+ const answer = response.answers.decision;
3848
+ return {
3849
+ route: answer.choice,
3850
+ confidence: answer.confidence
3851
+ };
3852
+ },
3853
+ async verify(params) {
3854
+ const state = {
3855
+ claim: params.claim,
3856
+ evidence: params.evidence
3857
+ };
3858
+ const response = await client.systemOne({
3859
+ model: params.model,
3860
+ state,
3861
+ ...params.images ? { images: params.images } : {},
3862
+ questions: {
3863
+ decision: {
3864
+ type: "noul",
3865
+ instructions: params.instructions ?? "Is the claim supported by the evidence?"
3866
+ }
3867
+ },
3868
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3869
+ });
3870
+ const answer = response.answers.decision;
3871
+ return {
3872
+ verified: answer.noul >= 0.5,
3873
+ probability: answer.noul
3874
+ };
3875
+ },
3876
+ async rank(params) {
3877
+ const promises = params.candidates.map(async (candidate) => {
3878
+ const response = await client.systemOne({
3879
+ model: params.model,
3880
+ state: candidate.state,
3881
+ ...params.images ? { images: params.images } : {},
3882
+ questions: {
3883
+ decision: {
3884
+ type: "score",
3885
+ instructions: params.instructions,
3886
+ criteria: params.criteria
3887
+ }
3888
+ },
3889
+ ...params.keepAlive !== void 0 ? { keep_alive: params.keepAlive } : {}
3890
+ });
3891
+ const answer = response.answers.decision;
3892
+ return {
3893
+ candidate: candidate.id,
3894
+ score: answer.score,
3895
+ confidence: answer.confidence
3896
+ };
3897
+ });
3898
+ const results = await Promise.all(promises);
3899
+ return results.sort((a, b) => b.score - a.score);
3900
+ }
3901
+ };
3902
+ }
3903
+
2980
3904
  // src/client.ts
2981
3905
  var logicalRequestSequence = 0;
2982
3906
  function createLogicalRequestId() {
@@ -3037,42 +3961,82 @@ var OllamaClient = class {
3037
3961
  * API with the generated `NativeApi` / `OpenAIApi` / `AnthropicApi`
3038
3962
  * surface without configuring two separate HttpClient instances.
3039
3963
  *
3040
- * The returned runtime is bound to the registry's first candidate
3041
- * endpoint (or the resolved single-endpoint config if no `endpoints`
3042
- * array was provided). For multi-endpoint configs that need per-call
3043
- * routing, prefer constructing `OllamaRuntime` directly with a
3044
- * specific HttpClient:
3045
- *
3046
- * ```ts
3047
- * const http = new HttpClient({ baseUrl: 'http://host-a:11434' });
3048
- * const runtime = new OllamaRuntime({ http });
3049
- * const api = new NativeApi(runtime);
3050
- * ```
3964
+ * Wave 14: the runtime now participates in multi-endpoint failover.
3965
+ * Each request is routed through this client's `executeWithFailover`
3966
+ * machinery via a {@link FailoverHttpClient} wrapper. If the first
3967
+ * candidate endpoint is down, requests automatically fail over to
3968
+ * the next healthy candidate — matching the behavior of the
3969
+ * hand-written OllamaClient methods (chat, generate, etc.).
3051
3970
  *
3052
3971
  * The runtime is cached on first call — subsequent calls return the
3053
- * same instance.
3972
+ * same instance. The `FailoverHttpClient` holds a reference to this
3973
+ * client, so it always sees the current endpoint registry state.
3054
3974
  */
3055
3975
  get runtime() {
3056
3976
  if (this._runtime === void 0) {
3057
3977
  const candidates = this.registry.candidates();
3058
3978
  const endpoint = candidates[0];
3059
3979
  const baseUrl = endpoint?.baseUrl ?? "http://localhost:11434";
3060
- const http = new HttpClient({
3061
- baseUrl,
3062
- ...endpoint?.apiKey !== void 0 ? { apiKey: endpoint.apiKey } : {},
3063
- ...endpoint?.headers !== void 0 ? { headers: endpoint.headers } : {},
3980
+ const http = new FailoverHttpClient(this, baseUrl);
3981
+ const cloudHttp = new HttpClient({
3982
+ baseUrl: OLLAMA_CLOUD_BASE_URL,
3983
+ ...this.cloudApiKey !== void 0 ? { apiKey: this.cloudApiKey } : {},
3064
3984
  fetch: this.fetchImpl,
3065
3985
  ...this.middleware !== void 0 ? { middleware: this.middleware } : {},
3066
3986
  ...this.onLifecycleEvent !== void 0 ? { onLifecycleEvent: this.onLifecycleEvent } : {}
3067
3987
  });
3068
3988
  this._runtime = new OllamaRuntime({
3069
3989
  http,
3990
+ cloudHttp,
3070
3991
  localMode: inferRuntimeMode(baseUrl) === "local"
3071
3992
  });
3072
3993
  }
3073
3994
  return this._runtime;
3074
3995
  }
3075
3996
  _runtime;
3997
+ /**
3998
+ * Lazily-constructed `NativeApi` bound to this client's runtime. Exposes
3999
+ * the full generated native API surface (chat, generate, embed, systemOne,
4000
+ * etc.) with contract-driven types and runtime enforcement.
4001
+ *
4002
+ * Wave 13: `systemOne()` delegates to this accessor.
4003
+ */
4004
+ get native() {
4005
+ if (this._nativeApi === void 0) {
4006
+ this._nativeApi = new NativeApi(this.runtime);
4007
+ }
4008
+ return this._nativeApi;
4009
+ }
4010
+ _nativeApi;
4011
+ /**
4012
+ * Higher-level System One decision helpers (Wave 14B).
4013
+ *
4014
+ * Ergonomic wrappers around `systemOne()` for the six most common
4015
+ * decision patterns: `choice()`, `noul()`, `score()`, `route()`,
4016
+ * `verify()`, `rank()`. Each constructs a single-question request
4017
+ * and extracts the typed answer.
4018
+ *
4019
+ * ```ts
4020
+ * const result = await client.decision.choice({
4021
+ * model: 'tev1:4b',
4022
+ * state: 'Customer was charged twice',
4023
+ * instructions: 'What is the primary intent?',
4024
+ * criteria: {
4025
+ * refund: 'Customer wants a refund',
4026
+ * duplicate_charge: 'Customer reports multiple charges',
4027
+ * },
4028
+ * });
4029
+ * console.log(result.choice); // 'duplicate_charge'
4030
+ * console.log(result.confidence); // 0.89
4031
+ * ```
4032
+ */
4033
+ get decision() {
4034
+ if (this._decision === void 0) {
4035
+ this._decision = createDecision(this);
4036
+ }
4037
+ return this._decision;
4038
+ }
4039
+ _decision;
3076
4040
  /**
3077
4041
  * Fail-fast guard for `format` (structured output) requests: throws before any network
3078
4042
  * call if the candidate endpoint is inferred as Ollama Cloud, which does not currently
@@ -3345,6 +4309,43 @@ var OllamaClient = class {
3345
4309
  version = () => this.models.version();
3346
4310
  createBlob = (digest, data) => this.models.createBlob(digest, data);
3347
4311
  checkBlob = (digest) => this.models.checkBlob(digest);
4312
+ // --- System One (Wave 13) ---
4313
+ /**
4314
+ * Ollama's System One decision layer (`POST /v1/systemone`) — evaluates
4315
+ * 1–64 typed questions (choice, noul, or score) against a provided state
4316
+ * and returns typed answers with probabilities and confidence.
4317
+ *
4318
+ * Local-only; requires Ollama >= 0.35.0. The runtime enforces the
4319
+ * version constraint automatically (lazily fetching `/api/version` when
4320
+ * `enforceVersion` is `'auto'` or `'strict'`) and rejects cloud-mode
4321
+ * calls. Request size is checked client-side: 64 KiB without images,
4322
+ * 32 MiB with images.
4323
+ *
4324
+ * The generic `Q` parameter captures the caller's question map at
4325
+ * compile time, giving key-safe answer access:
4326
+ *
4327
+ * ```ts
4328
+ * const result = await ollama.systemOne({
4329
+ * model: 'tev1:4b',
4330
+ * state: { ticket: 'Customer was charged twice' },
4331
+ * questions: {
4332
+ * intent: { type: 'choice', instructions: '...', criteria: { ... } },
4333
+ * urgent: { type: 'noul', instructions: '...' },
4334
+ * },
4335
+ * });
4336
+ * result.answers.intent // ✓ SystemOneAnswer (choice)
4337
+ * result.answers.urgent // ✓ SystemOneAnswer (noul)
4338
+ * result.answers.typo // ✗ TypeScript error
4339
+ * ```
4340
+ *
4341
+ * For the low-level generated API (without the generic wrapper), use
4342
+ * `client.native.systemOne(request)` directly.
4343
+ */
4344
+ async systemOne(request) {
4345
+ return this.native.systemOne(
4346
+ request
4347
+ );
4348
+ }
3348
4349
  // --- Web Endpoints ---
3349
4350
  /**
3350
4351
  * Ollama's hosted web search tool (`POST https://ollama.com/api/web_search`) — a fixed
@@ -4006,6 +5007,22 @@ async function listAllMcpTools(mcpClient, options = {}, signal) {
4006
5007
  const params = cursor !== void 0 ? { cursor } : void 0;
4007
5008
  const requestOptions = signal !== void 0 ? { signal } : void 0;
4008
5009
  const page = await mcpClient.listTools(params, requestOptions);
5010
+ const pageNames = /* @__PURE__ */ new Set();
5011
+ for (const tool of page.tools) {
5012
+ if (pageNames.has(tool.name)) {
5013
+ throw new OllamaMcpError(
5014
+ `MCP tools/list returned duplicate tool name "${tool.name}"`,
5015
+ { mcpMethod: "listTools", toolName: tool.name }
5016
+ );
5017
+ }
5018
+ pageNames.add(tool.name);
5019
+ if (tools.some((existing) => existing.name === tool.name)) {
5020
+ throw new OllamaMcpError(
5021
+ `MCP tools/list returned duplicate tool name "${tool.name}" across pages`,
5022
+ { mcpMethod: "listTools", toolName: tool.name }
5023
+ );
5024
+ }
5025
+ }
4009
5026
  tools.push(...page.tools);
4010
5027
  if (page.nextCursor === void 0) {
4011
5028
  return tools;
@@ -4019,6 +5036,9 @@ async function listAllMcpTools(mcpClient, options = {}, signal) {
4019
5036
  throw new Error("MCP tools/list exceeded maxPages (" + maxPages + ")");
4020
5037
  }
4021
5038
  function formatMcpToolResult(result) {
5039
+ if ("resultType" in result || "task" in result) {
5040
+ return JSON.stringify(result) ?? String(result);
5041
+ }
4022
5042
  const parts = result.content.map((block) => {
4023
5043
  if (block.type === "text" && typeof block.text === "string") {
4024
5044
  return block.text;
@@ -4040,6 +5060,20 @@ function formatMcpToolResult(result) {
4040
5060
  }
4041
5061
  return parts.join("\n");
4042
5062
  }
5063
+ function supportsTaskCalls(mcpClient) {
5064
+ return mcpClient.getServerCapabilities?.()?.tasks?.requests?.tools?.call !== void 0;
5065
+ }
5066
+ function shouldCallAsTask(descriptor, options, serverSupportsTasks) {
5067
+ const support = descriptor.execution?.taskSupport;
5068
+ if (support === "required" && !serverSupportsTasks) {
5069
+ throw new OllamaMcpError(
5070
+ `MCP tool "${descriptor.name}" requires task execution, but the server does not advertise tasks.requests.tools.call`,
5071
+ { mcpMethod: "callTool", toolName: descriptor.name }
5072
+ );
5073
+ }
5074
+ if (!serverSupportsTasks || support === void 0 || support === "forbidden") return false;
5075
+ return support === "required" || options.taskMode === "all-supported";
5076
+ }
4043
5077
  function createInputValidator(inputSchema) {
4044
5078
  return zod.z.custom().superRefine((value, ctx) => {
4045
5079
  const issues = validateJsonSchema(value, inputSchema);
@@ -4052,7 +5086,7 @@ function createInputValidator(inputSchema) {
4052
5086
  }
4053
5087
  });
4054
5088
  }
4055
- function convertMcpDescriptorToTool(descriptor, mcpClient, namePrefix = "", resultMode = "text") {
5089
+ function convertMcpDescriptorToTool(descriptor, mcpClient, namePrefix = "", resultMode = "text", validateOutputSchema = true, executeAsTask = false, taskTtlMs) {
4056
5090
  const toolName = `${namePrefix}${descriptor.name}`;
4057
5091
  const inputSchema = descriptor.inputSchema ?? { type: "object", properties: {} };
4058
5092
  const properties = inputSchema["properties"] ?? {};
@@ -4072,10 +5106,27 @@ function convertMcpDescriptorToTool(descriptor, mcpClient, namePrefix = "", resu
4072
5106
  const result = await mcpClient.callTool(
4073
5107
  {
4074
5108
  name: descriptor.name,
4075
- arguments: args
5109
+ arguments: args,
5110
+ ...executeAsTask ? { task: taskTtlMs !== void 0 ? { ttl: taskTtlMs } : {} } : {}
4076
5111
  },
4077
- context.signal !== void 0 ? { signal: context.signal } : void 0
5112
+ {
5113
+ ...context.signal !== void 0 ? { signal: context.signal } : {},
5114
+ allowInputRequired: true
5115
+ }
4078
5116
  );
5117
+ if (!("resultType" in result) && !("task" in result) && validateOutputSchema && descriptor.outputSchema !== void 0 && result.structuredContent !== void 0) {
5118
+ const issues = validateJsonSchema(result.structuredContent, descriptor.outputSchema);
5119
+ if (issues.length > 0) {
5120
+ throw new OllamaMcpError(
5121
+ `MCP tool "${descriptor.name}" returned structuredContent that violates outputSchema`,
5122
+ {
5123
+ mcpMethod: "tools/call",
5124
+ toolName: descriptor.name,
5125
+ issues
5126
+ }
5127
+ );
5128
+ }
5129
+ }
4079
5130
  return resultMode === "structured" ? result : formatMcpToolResult(result);
4080
5131
  } catch (err) {
4081
5132
  if (err instanceof OllamaMcpError) throw err;
@@ -4098,9 +5149,29 @@ function convertMcpDescriptorToTool(descriptor, mcpClient, namePrefix = "", resu
4098
5149
  }
4099
5150
  async function loadMcpTools(mcpClient, options = {}, signal) {
4100
5151
  try {
5152
+ if (options.taskTtlMs !== void 0 && (!Number.isFinite(options.taskTtlMs) || options.taskTtlMs <= 0)) {
5153
+ throw new RangeError("MCP taskTtlMs must be a positive finite number");
5154
+ }
4101
5155
  const tools = await listAllMcpTools(mcpClient, options, signal);
4102
- return tools.map((t) => convertMcpDescriptorToTool(t, mcpClient, options.namePrefix, options.resultMode));
5156
+ const serverSupportsTasks = supportsTaskCalls(mcpClient);
5157
+ return tools.map((tool) => {
5158
+ const taskCall = shouldCallAsTask(
5159
+ tool,
5160
+ options,
5161
+ serverSupportsTasks
5162
+ );
5163
+ return convertMcpDescriptorToTool(
5164
+ tool,
5165
+ mcpClient,
5166
+ options.namePrefix,
5167
+ options.resultMode,
5168
+ options.validateOutputSchema ?? true,
5169
+ taskCall,
5170
+ options.taskTtlMs
5171
+ );
5172
+ });
4103
5173
  } catch (err) {
5174
+ if (err instanceof OllamaMcpError) throw err;
4104
5175
  throw new OllamaMcpError("Failed listing MCP tools from client", {
4105
5176
  mcpMethod: "listTools",
4106
5177
  cause: err
@@ -4111,8 +5182,18 @@ async function registerMcpTools(registry, mcpClient, options = {}, signal) {
4111
5182
  const tools = await loadMcpTools(mcpClient, options, signal);
4112
5183
  registry.registerMany(tools);
4113
5184
  }
4114
-
4115
- // src/mcp/bridge.ts
5185
+ var taskSchema = zod.z.object({
5186
+ taskId: zod.z.string(),
5187
+ status: zod.z.enum(["working", "input_required", "completed", "failed", "cancelled"]),
5188
+ statusMessage: zod.z.string().optional(),
5189
+ createdAt: zod.z.string(),
5190
+ lastUpdatedAt: zod.z.string(),
5191
+ ttl: zod.z.number().optional(),
5192
+ pollInterval: zod.z.number().optional()
5193
+ }).passthrough();
5194
+ var callToolResultSchema = zod.z.custom(
5195
+ (value) => typeof value === "object" && value !== null && "content" in value && Array.isArray(value.content)
5196
+ );
4116
5197
  var McpBridge = class _McpBridge {
4117
5198
  constructor(client, options = {}) {
4118
5199
  this.client = client;
@@ -4147,6 +5228,50 @@ var McpBridge = class _McpBridge {
4147
5228
  async register(registry, signal) {
4148
5229
  await registry.registerMany(await this.loadTools(signal));
4149
5230
  }
5231
+ /** Refreshes the current MCP tool catalog into an existing registry without clearing local tools. */
5232
+ async refresh(registry, signal) {
5233
+ await registry.registerMany(await this.loadTools(signal));
5234
+ }
5235
+ /** Fetches one legacy MCP task's current status without starting a polling loop. */
5236
+ async getTaskStatus(taskId, signal) {
5237
+ return this.requestTask(
5238
+ "tasks/get",
5239
+ taskId,
5240
+ taskSchema,
5241
+ signal
5242
+ );
5243
+ }
5244
+ /** Retrieves a completed legacy MCP task's result. */
5245
+ async getTaskResult(taskId, signal) {
5246
+ return this.requestTask(
5247
+ "tasks/result",
5248
+ taskId,
5249
+ callToolResultSchema,
5250
+ signal
5251
+ );
5252
+ }
5253
+ /** Cancels one legacy MCP task. */
5254
+ async cancelTask(taskId, signal) {
5255
+ return this.requestTask(
5256
+ "tasks/cancel",
5257
+ taskId,
5258
+ taskSchema,
5259
+ signal
5260
+ );
5261
+ }
5262
+ requestTask(method, taskId, resultSchema, signal) {
5263
+ if (this.client.request === void 0) {
5264
+ throw new OllamaMcpError(
5265
+ `MCP client does not support ${method} requests`,
5266
+ { mcpMethod: method }
5267
+ );
5268
+ }
5269
+ return this.client.request(
5270
+ { method, params: { taskId } },
5271
+ resultSchema,
5272
+ signal !== void 0 ? { signal } : void 0
5273
+ );
5274
+ }
4150
5275
  };
4151
5276
 
4152
5277
  // src/skills/frontmatter.ts
@@ -4420,8 +5545,11 @@ exports.OllamaNetworkError = OllamaNetworkError;
4420
5545
  exports.OllamaNotFoundError = OllamaNotFoundError;
4421
5546
  exports.OllamaQuotaExceededError = OllamaQuotaExceededError;
4422
5547
  exports.OllamaRateLimitError = OllamaRateLimitError;
5548
+ exports.OllamaRequestTooLargeError = OllamaRequestTooLargeError;
4423
5549
  exports.OllamaRequestValidationError = OllamaRequestValidationError;
5550
+ exports.OllamaResponseValidationError = OllamaResponseValidationError;
4424
5551
  exports.OllamaServerError = OllamaServerError;
5552
+ exports.OllamaServerVersionUnknownError = OllamaServerVersionUnknownError;
4425
5553
  exports.OllamaSkillInvalidError = OllamaSkillInvalidError;
4426
5554
  exports.OllamaSkillNotFoundError = OllamaSkillNotFoundError;
4427
5555
  exports.OllamaStream = OllamaStream;
@@ -4442,6 +5570,7 @@ exports.calculateBackoff = calculateBackoff;
4442
5570
  exports.checkEndpointHealth = checkEndpointHealth;
4443
5571
  exports.composeMiddleware = composeMiddleware;
4444
5572
  exports.createConsoleLogger = createConsoleLogger;
5573
+ exports.createDecision = createDecision;
4445
5574
  exports.createOllamaCloudFreeTierQuota = createOllamaCloudFreeTierQuota;
4446
5575
  exports.createTimeoutSignal = createTimeoutSignal;
4447
5576
  exports.defineTool = defineTool;