ollama-dsl 0.1.0 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 775de2cdc17ae09fb547faea949611649239240373f313ee83ed6bedab93dea6
4
- data.tar.gz: cf5aceffa25ece0e9cc72e5bbbcd9b84041a1fecc06029fef148f41ebfc970d9
3
+ metadata.gz: cc69d14a5c3e7e436b59da35482e5fc77d49689fefceb1fdb4bfab84a3ed7c76
4
+ data.tar.gz: dee5bee8fbc4401ce92644e18a7e92980ae8db1942d8f1877b2836d9ac999054
5
5
  SHA512:
6
- metadata.gz: 4577a9ba783ecaaaffe938808493f09d5f0683e14934a49fe2f2b651ecece665967ef1b9bd62e56b73f130b55cc5784fd4b5f2666e41dea77865bbc5e5bd2160
7
- data.tar.gz: d892cb895e152792a7e2316c94023da931e626de4be368b608b5b8178e73295f050be6b4e04151beb4caccd6cf83891f25a9752f57936497178bcc8e62e545b9
6
+ metadata.gz: 5409975d8ebd80860eecaa4a6fe9dd7a106701c108f85a2cdfd7bafe41280472059a419c06b5da6f9f51cbaf22b9fe784d6a82cde9f7e6c1f13f748124ad341c
7
+ data.tar.gz: '084f29acb614e165d63dc3bad4dd1cd5ead88a45f5642d60b8670114612ff810d790d8a4a666c167696fc16489f566d924c3d6f6eeff9b3d084cff530b1250f4'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
+ ```markdown
1
2
  ## [Unreleased]
2
3
 
4
+ ## [0.1.2] - 2026-10-04
5
+
6
+ - Added `Agent` with Ollama tool calling support
7
+ - Added `Tool` abstraction for executable tools
8
+ - Added tool execution loop
9
+ - Added tool definitions for Ollama
10
+ - Added RSpec tests for tools
11
+
12
+ ## [0.1.1] - 2025-11-04
13
+
14
+ - Updated client to support agent tool calling
15
+ - Updated DSL entry point
16
+ - Updated examples
17
+
3
18
  ## [0.1.0] - 2025-08-22
4
19
 
5
20
  - Initial release
21
+ ```
data/README.md CHANGED
@@ -1,37 +1,183 @@
1
1
  # Ollama::Dsl
2
2
 
3
- A Ruby DSL for interacting with Ollama LLMs, allowing streaming and structured prompts.
3
+ [![Gem Version](https://badge.fury.io/rb/ollama-dsl.svg)](https://badge.fury.io/rb/ollama-dsl)
4
+ [![Documentation](https://img.shields.io/badge/docs-rubydoc.info-blue)](https://rubydoc.info/gems/ollama-dsl)
4
5
 
5
- Ollama DSL provides an easy-to-use Ruby interface to communicate with Ollama local or remote language models. It supports building prompts with system/user roles, handling streaming responses, and chaining prompts seamlessly.
6
+ A Ruby DSL for interacting with Ollama LLMs, with support for streaming, structured prompts, agents, and tool calling.
6
7
 
7
- ## Installation
8
+ Ollama DSL provides an easy-to-use Ruby interface for communicating with local or remote Ollama language models. It supports system and user prompts, streaming responses, prompt chaining, and building agents that can execute custom Ruby tools.
8
9
 
10
+ ## Installation
9
11
 
10
- Install the gem and add to the application's Gemfile by executing:
12
+ Install the gem:
11
13
 
12
14
  ```bash
13
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
15
+ gem install ollama-dsl
14
16
  ```
15
17
 
16
- If bundler is not being used to manage dependencies, install the gem by executing:
18
+ Or add it to your `Gemfile`:
19
+
20
+ ```ruby
21
+ gem "ollama-dsl"
22
+ ```
23
+
24
+ Then run:
17
25
 
18
26
  ```bash
19
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
27
+ bundle install
20
28
  ```
21
29
 
22
- ## Usage
30
+ If you want to use it directly from GitHub:
31
+
32
+ ```ruby
33
+ gem "ollama-dsl", git: "https://github.com/rafaelmerlotto/ollama-dsl.git"
34
+ ```
35
+
36
+ ## Basic Example
37
+
38
+ ```ruby
39
+ require "ollama/dsl"
40
+
41
+ Ollama::Dsl.run do
42
+ model "llama3"
43
+
44
+ system "You are a marketing expert assistant."
45
+ user "Write a catchy Instagram post title about artisanal coffee."
46
+
47
+ on_chunk { |token| print token }
48
+
49
+ on_done do |text|
50
+ puts "\n\nFinal response:\n#{text}"
51
+ end
52
+
53
+ self
54
+ end
55
+ ```
56
+
57
+ ## Agents
58
+
59
+ Ollama DSL also provides an `Agent` abstraction for building tool-enabled automations.
60
+
61
+ An agent can:
62
+
63
+ * Receive a user instruction
64
+ * Decide which registered tool to use
65
+ * Execute the tool in Ruby
66
+ * Send the tool result back to Ollama
67
+ * Continue the execution loop until the task is completed
68
+
69
+ ### Example
70
+
71
+ ```ruby
72
+ require "ollama/dsl"
73
+
74
+ session = Ollama::Dsl::Session.new
75
+
76
+ agent = Ollama::Dsl::Agent.new(
77
+ session,
78
+ model: "gpt-oss:20b"
79
+ )
80
+
81
+ agent.tool(
82
+ "create_file",
83
+ "Create a text file with the given filename and content.",
84
+ parameters: {
85
+ type: "object",
86
+ properties: {
87
+ filename: {
88
+ type: "string",
89
+ description: "The name of the file to create."
90
+ },
91
+ content: {
92
+ type: "string",
93
+ description: "The content to write into the file."
94
+ }
95
+ },
96
+ required: ["filename", "content"]
97
+ }
98
+ ) do |filename:, content:|
99
+ File.write(filename, content)
100
+
101
+ "File #{filename} was created successfully."
102
+ end
103
+
104
+ puts agent.run(
105
+ "Create a file called hello.txt containing Hello from my AI agent."
106
+ )
107
+ ```
108
+
109
+ The agent uses Ollama's native tool calling capabilities to decide when a tool should be executed.
110
+
111
+ Tools are not limited to file operations. You can define tools for any Ruby automation your application needs.
112
+
113
+ For example:
114
+
115
+ ```ruby
116
+ agent.tool("get_time", "Get the current time.", parameters: {
117
+ type: "object",
118
+ properties: {}
119
+ }) do
120
+ Time.now.to_s
121
+ end
122
+ ```
123
+
124
+ ## Tool Calling
125
+
126
+ Tools consist of three main parts:
127
+
128
+ * A name
129
+ * A description
130
+ * A parameter schema and Ruby block
23
131
 
24
- TODO: Write usage instructions here
132
+ The description and parameter schema are sent to Ollama, allowing the model to decide when and how to use the tool.
133
+
134
+ The Ruby block contains the actual implementation that is executed by the agent.
25
135
 
26
136
  ## Development
27
137
 
28
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
138
+ After checking out the repo, run `bin/setup` to install dependencies.
139
+
140
+ Run the test suite with:
141
+
142
+ ```bash
143
+ bundle exec rspec
144
+ ```
145
+
146
+ You can also run:
147
+
148
+ ```bash
149
+ bundle exec rake
150
+ ```
151
+
152
+ for the project's Rake tasks.
153
+
154
+ To open an interactive console:
155
+
156
+ ```bash
157
+ bin/console
158
+ ```
159
+
160
+ To install this gem onto your local machine:
161
+
162
+ ```bash
163
+ bundle exec rake install
164
+ ```
29
165
 
30
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
166
+ To release a new version, update the version number in `version.rb`, then run:
167
+
168
+ ```bash
169
+ bundle exec rake release
170
+ ```
171
+
172
+ This will create a git tag for the version, push the git commits and tag, and publish the gem to RubyGems.
31
173
 
32
174
  ## Contributing
33
175
 
34
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ollama-dsl. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/ollama-dsl/blob/main/CODE_OF_CONDUCT.md).
176
+ Bug reports and pull requests are welcome on GitHub at:
177
+
178
+ https://github.com/rafaelmerlotto/ollama-dsl
179
+
180
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Code of Conduct](https://github.com/rafaelmerlotto/ollama-dsl/blob/main/CODE_OF_CONDUCT.md).
35
181
 
36
182
  ## License
37
183
 
@@ -39,4 +185,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
39
185
 
40
186
  ## Code of Conduct
41
187
 
42
- Everyone interacting in the Ollama::Dsl project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ollama-dsl/blob/main/CODE_OF_CONDUCT.md).
188
+ Everyone interacting with the Ollama::Dsl project's codebases, issue trackers and mailing lists is expected to adhere to the [Code of Conduct](https://github.com/rafaelmerlotto/ollama-dsl/blob/main/CODE_OF_CONDUCT.md).
data/examples/agent.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
4
+
5
+ require "ollama/dsl/session"
6
+ require "ollama/dsl/agent"
7
+
8
+ session = Ollama::Dsl::Session.new
9
+
10
+ agent = Ollama::Dsl::Agent.new(
11
+ session,
12
+ model: "gpt-oss:20b"
13
+ )
14
+
15
+ agent.tool(
16
+ "create_file",
17
+ "Create a text file with the given filename and content.",
18
+ parameters: {
19
+ type: "object",
20
+ properties: {
21
+ filename: {
22
+ type: "string",
23
+ description: "The name of the file to create."
24
+ },
25
+ content: {
26
+ type: "string",
27
+ description: "The content to write into the file."
28
+ }
29
+ },
30
+ required: ["filename", "content"]
31
+ }
32
+ ) do |filename:, content:|
33
+ File.write(filename, content)
34
+
35
+ "File #{filename} was created successfully."
36
+ end
37
+
38
+ result = agent.run(
39
+ "Create a file called hello.txt containing exactly: Hello from my AI agent."
40
+ )
41
+
42
+ puts result
data/examples/use_case.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
- $LOAD_PATH.unshift(File.expand_path(".", __dir__))
2
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
3
3
 
4
- require_relative "dsl/session"
5
- require_relative "dsl/dsl"
6
- require_relative "dsl/client"
4
+ require "ollama/dsl/session"
5
+ require "ollama/dsl/dsl"
6
+ require "ollama/dsl/client"
7
7
 
8
8
  session = Ollama::Dsl::Session.new
9
9
  dsl = Ollama::Dsl::DSL.new(session)
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tool"
4
+ require_relative "client"
5
+
6
+ module Ollama
7
+ module Dsl
8
+ class Agent
9
+ attr_reader :tools
10
+
11
+ def initialize(session, model: "llama3")
12
+ @session = session
13
+ @model = model
14
+ @tools = {}
15
+ @client = Client.new
16
+ end
17
+
18
+ def tool(name, description, parameters:, &block)
19
+ @tools[name.to_s] = Tool.new(
20
+ name,
21
+ description,
22
+ parameters: parameters,
23
+ &block
24
+ )
25
+ end
26
+
27
+ def run(instruction)
28
+ @session.add("user", instruction)
29
+
30
+ loop do
31
+ response = @client.chat(
32
+ model: @model,
33
+ messages: @session.messages,
34
+ tools: tool_definitions
35
+ )
36
+
37
+ message = response.fetch("message")
38
+
39
+ tool_calls = message["tool_calls"]
40
+
41
+ if tool_calls.nil? || tool_calls.empty?
42
+ final_answer = message["content"].to_s
43
+
44
+ @session.add("assistant", final_answer)
45
+
46
+ return final_answer
47
+ end
48
+
49
+ @session.messages << message
50
+
51
+ tool_calls.each do |tool_call|
52
+ execute_tool(tool_call)
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def tool_definitions
60
+ @tools.values.map(&:definition)
61
+ end
62
+
63
+ def execute_tool(tool_call)
64
+ function = tool_call.fetch("function")
65
+
66
+ name = function.fetch("name")
67
+ arguments = function["arguments"] || {}
68
+
69
+ tool = @tools[name]
70
+
71
+ raise "Unknown tool: #{name}" unless tool
72
+
73
+ result = tool.call(arguments)
74
+
75
+ @session.messages << {
76
+ role: "tool",
77
+ content: result.to_s
78
+ }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -11,17 +11,19 @@ module Ollama
11
11
  @ollama_host = URI(host)
12
12
  end
13
13
 
14
+ # Used by DSL for streaming responses
14
15
  def stream(path, payload)
15
-
16
16
  uri = URI("#{@ollama_host}#{path}")
17
17
 
18
- # POST request
19
- req = Net::HTTP::Post.new(uri, { "Content-Type" => "application/json" })
20
- req.body = payload.to_json
18
+ request = Net::HTTP::Post.new(
19
+ uri,
20
+ { "Content-Type" => "application/json" }
21
+ )
22
+
23
+ request.body = payload.merge(stream: true).to_json
21
24
 
22
- # Response streaming
23
25
  Net::HTTP.start(uri.hostname, uri.port) do |http|
24
- http.request(req) do |response|
26
+ http.request(request) do |response|
25
27
  response.read_body do |chunk|
26
28
  begin
27
29
  json = JSON.parse(chunk)
@@ -32,6 +34,42 @@ module Ollama
32
34
  end
33
35
  end
34
36
  end
37
+
38
+ # Used by Agent for tool calling
39
+ def chat(model:, messages:, tools: nil)
40
+ payload = {
41
+ model: model,
42
+ messages: messages,
43
+ stream: false
44
+ }
45
+
46
+ payload[:tools] = tools if tools && !tools.empty?
47
+
48
+ post("/api/chat", payload)
49
+ end
50
+
51
+ private
52
+
53
+ def post(path, payload)
54
+ uri = URI("#{@ollama_host}#{path}")
55
+
56
+ request = Net::HTTP::Post.new(
57
+ uri,
58
+ { "Content-Type" => "application/json" }
59
+ )
60
+
61
+ request.body = payload.to_json
62
+
63
+ response = Net::HTTP.start(uri.hostname, uri.port) do |http|
64
+ http.request(request)
65
+ end
66
+
67
+ unless response.is_a?(Net::HTTPSuccess)
68
+ raise "Ollama request failed: #{response.code} #{response.body}"
69
+ end
70
+
71
+ JSON.parse(response.body)
72
+ end
35
73
  end
36
74
  end
37
75
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ module Dsl
5
+ class Tool
6
+ attr_reader :name, :description, :parameters
7
+
8
+ def initialize(name, description, parameters:, &block)
9
+ @name = name.to_s
10
+ @description = description
11
+ @parameters = parameters
12
+ @block = block
13
+ end
14
+
15
+ def definition
16
+ {
17
+ type: "function",
18
+ function: {
19
+ name: @name,
20
+ description: @description,
21
+ parameters: @parameters
22
+ }
23
+ }
24
+ end
25
+
26
+ def call(arguments = {})
27
+ @block.call(**arguments.transform_keys(&:to_sym))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ollama
4
4
  module Dsl
5
- VERSION = "0.1.0"
5
+ VERSION = "0.1.2"
6
6
  end
7
7
  end
data/lib/ollama/dsl.rb CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  require 'json'
4
4
  require_relative "dsl/version"
5
+ require_relative "dsl/session"
6
+ require_relative "dsl/dsl"
7
+ require_relative "dsl/client"
8
+ require_relative "dsl/agent"
9
+ require_relative "dsl/tool"
10
+
5
11
 
6
12
 
7
13
  module Ollama
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafael
@@ -23,11 +23,14 @@ files:
23
23
  - LICENSE.txt
24
24
  - README.md
25
25
  - Rakefile
26
+ - examples/agent.rb
26
27
  - examples/use_case.rb
27
28
  - lib/ollama/dsl.rb
29
+ - lib/ollama/dsl/agent.rb
28
30
  - lib/ollama/dsl/client.rb
29
31
  - lib/ollama/dsl/dsl.rb
30
32
  - lib/ollama/dsl/session.rb
33
+ - lib/ollama/dsl/tool.rb
31
34
  - lib/ollama/dsl/version.rb
32
35
  - sig/ollama/dsl.rbs
33
36
  homepage: https://github.com/rafaelmerlotto/ollama-dsl