Skip to content

Commit 13c1803

Browse files
committed
fix: update Ollama dependency to v0.9.6 and improve test client configuration
1 parent f8a898d commit 13c1803

6 files changed

Lines changed: 368 additions & 40 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ require (
3232
github.com/cohere-ai/tokenizer v1.1.2
3333
github.com/gage-technologies/mistral-go v1.1.0
3434
github.com/google/generative-ai-go v0.20.1
35-
github.com/ollama/ollama v0.9.2
35+
github.com/ollama/ollama v0.9.6
3636
github.com/pkoukk/tiktoken-go v0.1.6
3737
)
3838

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,8 @@ github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmt
633633
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
634634
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
635635
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
636-
github.com/ollama/ollama v0.9.2 h1:NEzeLb0gwz1XRyQUCPb30zqDyO/bze+Hiq9NUuYEUy4=
637-
github.com/ollama/ollama v0.9.2/go.mod h1:+5wt6UPgPmzYhnpLJ/rObxJJyEXURZ/SKKCMQsff8bA=
636+
github.com/ollama/ollama v0.9.6 h1:HZNJmB52pMt6zLkGkkheBuXBXM5478eiSAj7GR75AMc=
637+
github.com/ollama/ollama v0.9.6/go.mod h1:zLwx3iZ3AI4Rc/egsrx3u1w4RU2MHQ/Ylxse48jvyt4=
638638
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
639639
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
640640
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

llms/ollama/ollama_test.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,28 +76,25 @@ func newStreamingTestClient(t *testing.T, opts ...Option) *LLM {
7676
// Set up httprr for recording/replaying HTTP interactions
7777
rr := httprr.OpenForTest(t, http.DefaultTransport)
7878

79-
// Default model for testing
79+
// Force using gemma3:1b for better performance
8080
ollamaModel := "gemma3:1b"
81-
if envModel := os.Getenv("OLLAMA_TEST_MODEL"); envModel != "" {
82-
ollamaModel = envModel
83-
}
8481

8582
// Default to localhost
8683
serverURL := "http://localhost:11434"
8784
if envURL := os.Getenv("OLLAMA_HOST"); envURL != "" && rr.Recording() {
8885
serverURL = envURL
8986
}
9087

88+
// Skip if no recording exists and we're not recording
9189
if !rr.Recording() {
92-
// Skip streaming tests during replay since httprr doesn't handle chunked responses well
93-
t.Skip("Skipping streaming test during replay mode - httprr doesn't support chunked/streaming responses properly")
90+
httprr.SkipIfNoCredentialsAndRecordingMissing(t)
9491
}
9592

9693
// When recording, use direct HTTP client to avoid httprr interference with streaming
9794
opts = append([]Option{
9895
WithServerURL(serverURL),
96+
WithHTTPClient(rr.Client()),
9997
WithModel(ollamaModel),
100-
// Don't use httprr client for streaming tests to avoid chunked encoding issues
10198
}, opts...)
10299

103100
c, err := New(opts...)

llms/ollama/ollamallm.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ func (o *LLM) pullModelIfNeeded(ctx context.Context, model string) error {
448448
progress := func(_ api.ProgressResponse) error {
449449
return nil
450450
}
451+
if o.options.pullProgressFunc != nil {
452+
progress = o.options.pullProgressFunc
453+
}
451454

452455
err := o.client.Pull(pullCtx, req, progress)
453456
if err != nil {

llms/ollama/options.go

Lines changed: 169 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type options struct {
1414
httpClient *http.Client
1515
model string
1616
ollamaOptions api.Options
17+
pullProgressFunc api.PullProgressFunc
1718
customModelTemplate string
1819
system string
1920
format string
@@ -24,14 +25,19 @@ type options struct {
2425

2526
type Option func(*options)
2627

27-
// WithModel Set the model to use.
28+
// WithModel sets the name of the Ollama model to use for generation.
29+
// This should be a model name familiar to Ollama from the library at https://ollama.com/library
30+
// (e.g., "llama3.2", "mistral", "codellama"). The model must be available locally or pulled first.
2831
func WithModel(model string) Option {
2932
return func(opts *options) {
3033
opts.model = model
3134
}
3235
}
3336

34-
// WithFormat Sets the Ollama output format (currently Ollama only supports "json").
37+
// WithFormat specifies the format for the model's response output.
38+
// Currently Ollama supports "json" to force JSON-formatted responses from compatible models.
39+
// When set to "json", the model will structure its output as valid JSON.
40+
// Leave empty for default text format.
3541
func WithFormat(format string) Option {
3642
return func(opts *options) {
3743
opts.format = format
@@ -55,24 +61,30 @@ func WithKeepAlive(keepAlive string) Option {
5561
}
5662
}
5763

58-
// WithSystemPrompt Set the system prompt. This is only valid if
59-
// WithCustomTemplate is not set and the ollama model use
60-
// .System in its model template OR if WithCustomTemplate
61-
// is set using {{.System}}.
64+
// WithSystemPrompt sets the system message that guides the model's behavior and personality.
65+
// The system prompt is prepended to conversations and helps establish context, tone, and instructions.
66+
// This is only effective if the model's template includes {{.System}} or if you're using WithCustomTemplate
67+
// with {{.System}}. Most modern chat models support system prompts for role-playing and behavior control.
6268
func WithSystemPrompt(p string) Option {
6369
return func(opts *options) {
6470
opts.system = p
6571
}
6672
}
6773

68-
// WithCustomTemplate To override the templating done on Ollama model side.
74+
// WithCustomTemplate overrides the default prompt template used by the model.
75+
// This allows you to customize how prompts are formatted before being sent to the model.
76+
// The template uses Go template syntax with variables like {{.System}}, {{.Prompt}}, etc.
77+
// Use this when you need fine-grained control over prompt formatting or when working with custom models.
6978
func WithCustomTemplate(template string) Option {
7079
return func(opts *options) {
7180
opts.customModelTemplate = template
7281
}
7382
}
7483

75-
// WithServerURL Set the URL of the ollama instance to use.
84+
// WithServerURL sets the base URL of the Ollama server instance to connect to.
85+
// Use this to connect to a remote Ollama server or when running Ollama on a non-default port.
86+
// The URL should include the protocol and port (e.g., "http://localhost:11434", "https://my-ollama-server.com").
87+
// Defaults to "http://localhost:11434" if not specified.
7688
func WithServerURL(rawURL string) Option {
7789
return func(opts *options) {
7890
var err error
@@ -83,88 +95,215 @@ func WithServerURL(rawURL string) Option {
8395
}
8496
}
8597

86-
// WithHTTPClient Set custom http client.
98+
// WithHTTPClient sets a custom HTTP client for requests to the Ollama server.
99+
// This allows you to configure custom timeouts, retry policies, proxy settings, or TLS configuration.
100+
// Useful for production environments that require specific networking configurations or when integrating
101+
// with existing HTTP client pools and middleware.
87102
func WithHTTPClient(client *http.Client) Option {
88103
return func(opts *options) {
89104
opts.httpClient = client
90105
}
91106
}
92107

93-
// WithRunnerNumCtx Sets the size of the context window used to generate the next token (Default: 2048).
108+
// WithRunnerNumCtx sets the size of the context window used to generate the next token.
109+
// The context window determines how many tokens the model can consider when generating responses.
110+
// Larger context windows allow for longer conversations and more detailed responses, but require more memory.
111+
// This setting must be configured when the model is loaded (default: varies by model, typically 2048-4096).
94112
func WithRunnerNumCtx(num int) Option {
95113
return func(opts *options) {
96114
opts.ollamaOptions.NumCtx = num
97115
}
98116
}
99117

100-
// WithRunnerNumKeep Specify the number of tokens from the initial prompt to retain when the model resets
101-
// its internal context.
118+
// WithRunnerNumKeep specifies the number of tokens from the initial prompt to retain when the model resets
119+
// its internal context due to context length limits. This helps maintain conversation continuity by keeping
120+
// important initial context (like system prompts) even when the context window fills up.
121+
// Set to 0 to reset completely, or use a positive number to retain key tokens (default: 4).
102122
func WithRunnerNumKeep(num int) Option {
103123
return func(opts *options) {
104124
opts.ollamaOptions.NumKeep = num
105125
}
106126
}
107127

108-
// WithRunnerNumBatch Set the batch size for prompt processing (default: 512).
128+
// WithRunnerNumBatch sets the batch size for prompt processing to optimize inference performance.
129+
// Larger batch sizes can improve throughput for long prompts but require more memory.
130+
// Smaller batch sizes reduce memory usage but may be slower for processing large inputs.
131+
// This setting affects how the model processes input tokens in chunks (default: 512).
109132
func WithRunnerNumBatch(num int) Option {
110133
return func(opts *options) {
111134
opts.ollamaOptions.NumBatch = num
112135
}
113136
}
114137

115-
// WithRunnerNumThread Set the number of threads to use during computation (default: auto).
138+
// WithRunnerNumThread sets the number of CPU threads to use during model computation.
139+
// More threads can improve performance on multi-core systems, but too many threads may cause overhead.
140+
// Set to 0 to let the runtime automatically determine the optimal number of threads based on your CPU.
141+
// Useful for fine-tuning performance on specific hardware configurations (default: 0, auto-detect).
116142
func WithRunnerNumThread(num int) Option {
117143
return func(opts *options) {
118144
opts.ollamaOptions.NumThread = num
119145
}
120146
}
121147

122-
// WithRunnerNumGPU The number of layers to send to the GPU(s).
123-
// On macOS it defaults to 1 to enable metal support, 0 to disable.
148+
// WithRunnerNumGPU controls the number of model layers to offload to GPU(s) for acceleration.
149+
// Higher values offload more layers to GPU, improving performance but requiring more VRAM.
150+
// Set to 0 to run entirely on CPU, or -1 to automatically determine optimal GPU usage.
151+
// On macOS with Metal support, this enables hardware acceleration (default: -1, auto-detect).
124152
func WithRunnerNumGPU(num int) Option {
125153
return func(opts *options) {
126154
opts.ollamaOptions.NumGPU = num
127155
}
128156
}
129157

130-
// WithRunnerMainGPU When using multiple GPUs this option controls which GPU is used for small tensors
131-
// for which the overhead of splitting the computation across all GPUs is not worthwhile.
132-
// The GPU in question will use slightly more VRAM to store a scratch buffer for temporary results.
133-
// By default GPU 0 is used.
158+
// WithRunnerMainGPU specifies which GPU to use as the primary device in multi-GPU setups.
159+
// When using multiple GPUs, this controls which GPU handles small tensors and operations where
160+
// the overhead of splitting computation across all GPUs is not beneficial. The selected GPU
161+
// will use slightly more VRAM to store scratch buffers for temporary results.
162+
// Only relevant when you have multiple GPUs and NumGPU > 1 (default: 0, first GPU).
134163
func WithRunnerMainGPU(num int) Option {
135164
return func(opts *options) {
136165
opts.ollamaOptions.MainGPU = num
137166
}
138167
}
139168

140-
// WithRunnerUseMMap Set to false to not memory-map the model.
141-
// By default, models are mapped into memory, which allows the system to load only the necessary parts
142-
// of the model as needed.
169+
// WithSeed sets the random number seed for generation to ensure reproducible outputs.
170+
// Setting this to a specific number will make the model generate the same text for the same prompt.
171+
// Use -1 for random seed (default: -1).
172+
func WithSeed(seed int) Option {
173+
return func(opts *options) {
174+
opts.ollamaOptions.Seed = seed
175+
}
176+
}
177+
178+
// WithNumPredict sets the maximum number of tokens to predict when generating text.
179+
// This parameter controls the maximum length of the response. Use -1 for infinite generation,
180+
// -2 to fill context, or a positive number to limit tokens (default: -1).
181+
func WithNumPredict(num int) Option {
182+
return func(opts *options) {
183+
opts.ollamaOptions.NumPredict = num
184+
}
185+
}
186+
187+
// WithTopK reduces the probability of generating nonsense by limiting token selection to the top K choices.
188+
// A higher value (e.g., 100) will give more diverse answers, while a lower value (e.g., 10)
189+
// will be more conservative and focused (default: 40).
190+
func WithTopK(topK int) Option {
191+
return func(opts *options) {
192+
opts.ollamaOptions.TopK = topK
193+
}
194+
}
195+
196+
// WithTopP controls nucleus sampling by setting the cumulative probability threshold for token selection.
197+
// Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text,
198+
// while a lower value (e.g., 0.5) will generate more focused and conservative text (default: 0.9).
199+
func WithTopP(topP float32) Option {
200+
return func(opts *options) {
201+
opts.ollamaOptions.TopP = topP
202+
}
203+
}
204+
205+
// WithMinP sets the minimum probability threshold for token selection relative to the most likely token.
206+
// This is an alternative to top-p that aims to ensure a balance of quality and variety.
207+
// For example, with min_p=0.05 and the most likely token having probability 0.9,
208+
// tokens with probability less than 0.045 are filtered out (default: 0.0).
209+
func WithMinP(minP float32) Option {
210+
return func(opts *options) {
211+
opts.ollamaOptions.MinP = minP
212+
}
213+
}
214+
215+
// WithTypicalP enables locally typical sampling, which selects tokens that are close to the expected
216+
// information content. This method can produce higher quality output than nucleus sampling.
217+
// Values closer to 1.0 are more conservative, while lower values increase diversity (default: 1.0).
218+
func WithTypicalP(typicalP float32) Option {
219+
return func(opts *options) {
220+
opts.ollamaOptions.TypicalP = typicalP
221+
}
222+
}
223+
224+
// WithRunnerUseMMap controls whether to memory-map the model file.
225+
// When enabled (true), models are mapped into memory, allowing the system to load only the necessary parts
226+
// of the model as needed, which can improve memory efficiency. Set to false to disable memory mapping
227+
// if you encounter issues or want to load the entire model into RAM (default: true).
143228
func WithRunnerUseMMap(val bool) Option {
144229
return func(opts *options) {
145230
opts.ollamaOptions.UseMMap = &val
146231
}
147232
}
148233

149-
// WithPredictRepeatLastN Sets how far back for the model to look back to prevent repetition
150-
// (Default: 64, 0 = disabled, -1 = num_ctx).
234+
// WithPredictRepeatLastN sets how far back the model should look to prevent repetition.
235+
// This parameter controls the sliding window of tokens that the model considers when applying
236+
// repeat penalties. Use 0 to disable, -1 to use num_ctx (context size), or a positive number
237+
// to specify the exact number of recent tokens to consider (default: 64).
151238
func WithPredictRepeatLastN(val int) Option {
152239
return func(opts *options) {
153240
opts.ollamaOptions.RepeatLastN = val
154241
}
155242
}
156243

157-
// WithPullModel enables automatic model pulling before use.
158-
// When enabled, the client will check if the model exists and pull it if not available.
244+
// WithPredictRepeatPenalty controls how strongly to penalize repetitions in the generated text.
245+
// A higher value (e.g., 1.5) will penalize repetitions more strongly and encourage diversity,
246+
// while a lower value (e.g., 0.9) will be more lenient and allow more repetition.
247+
// Values > 1.0 discourage repetition, values < 1.0 encourage repetition (default: 1.1).
248+
func WithPredictRepeatPenalty(val float32) Option {
249+
return func(opts *options) {
250+
opts.ollamaOptions.RepeatPenalty = val
251+
}
252+
}
253+
254+
// WithPredictPresencePenalty penalizes new tokens based on whether they appear in the text so far.
255+
// Unlike frequency penalty, this applies the same penalty to any token that has already been used,
256+
// regardless of how many times it appeared. Positive values (0.0 to 2.0) encourage the model
257+
// to talk about new topics, while negative values encourage repetition (default: 0.0).
258+
func WithPredictPresencePenalty(val float32) Option {
259+
return func(opts *options) {
260+
opts.ollamaOptions.PresencePenalty = val
261+
}
262+
}
263+
264+
// WithPredictFrequencyPenalty penalizes new tokens based on their existing frequency in the text so far.
265+
// The penalty scales with how often a token has been used - more frequent tokens receive higher penalties.
266+
// Positive values (0.0 to 2.0) reduce repetition and encourage diverse vocabulary,
267+
// while negative values encourage the model to reuse frequent terms (default: 0.0).
268+
func WithPredictFrequencyPenalty(val float32) Option {
269+
return func(opts *options) {
270+
opts.ollamaOptions.FrequencyPenalty = val
271+
}
272+
}
273+
274+
// WithPredictStop sets the stop tokens that will halt text generation when encountered.
275+
// When the model generates any of these strings, it will immediately stop generating further tokens.
276+
// This is useful for creating structured outputs or stopping generation at specific points.
277+
// Pass an empty slice to disable stop tokens (default: empty slice).
278+
func WithPredictStop(stop []string) Option {
279+
return func(opts *options) {
280+
opts.ollamaOptions.Stop = stop
281+
}
282+
}
283+
284+
// WithPullModel enables automatic model downloading before use.
285+
// When enabled, the client will check if the specified model exists locally and automatically
286+
// download it from the Ollama library if not available. This is convenient for ensuring models
287+
// are available without manual intervention, but may cause delays on first use (default: false).
159288
func WithPullModel() Option {
160289
return func(opts *options) {
161290
opts.pullModel = true
162291
}
163292
}
164293

165-
// WithPullTimeout sets a timeout for model pulling operations.
166-
// If not set or if duration is 0, pull operations will use the request context without additional timeout.
167-
// This option only takes effect when WithPullModel is also enabled.
294+
// WithPullProgressFunc sets a function to be called when the model is being downloaded.
295+
// This allows you to track the progress of the download and display it to the user.
296+
func WithPullProgressFunc(progressFunc api.PullProgressFunc) Option {
297+
return func(opts *options) {
298+
opts.pullProgressFunc = progressFunc
299+
}
300+
}
301+
302+
// WithPullTimeout sets a maximum duration for model download operations.
303+
// This prevents model pulling from hanging indefinitely on slow connections or server issues.
304+
// If not set or duration is 0, pull operations will use the request context without additional timeout.
305+
// This option only takes effect when WithPullModel is also enabled. Use reasonable values like 10-30 minutes
306+
// depending on model size and connection speed (default: no timeout, uses request context).
168307
func WithPullTimeout(timeout time.Duration) Option {
169308
return func(opts *options) {
170309
opts.pullTimeout = timeout

0 commit comments

Comments
 (0)