hellm 0.0.3 → 0.0.5

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: 85820167c185b4609e3b81e23a3280063d41c85d70c5880b9e3b676dc378a193
4
- data.tar.gz: e24df7e76af2cae1500adfc01bc9f4ef75ffe8641acdbc8a33fad7ffc92c028a
3
+ metadata.gz: 7e145f6843dcffe58f1bcd576ca4c945d2e9727caf765500cf228cbb44d77c9e
4
+ data.tar.gz: 6ce567f6e7d01083a5a9b21b2ef82476b17e1ccbac249c201291b436f15b6055
5
5
  SHA512:
6
- metadata.gz: 6c0bedef17b6862c8302f14f51c3c9cdfaace1a07f40523574c9316ce6b3d775e0000edce7f83168bb7da50e1c24c5458ab29d0ce19fde3bdf1290a648e9cc53
7
- data.tar.gz: 50342bcd317ac5427189e1318233e6902e73a80cd3d9bca2cd6521331c95d34d72cf4ae43daf72bbf181df640a4a06fa785c0673e52d96051b42c19bb296fd19
6
+ metadata.gz: 4cfd84c50054e316c6e402f9360599bca016e3f1b8f36db599bd97f1ffe8a4bc951b110c6c462b7e9846a7485fe6394c74c72fac41391795c24e1bdbcf807322
7
+ data.tar.gz: 268ad8d66f1a59e8583a46d09b06efa1114d68c6c9e182b998bb818da6e2a1b24b6519494da34695c5aba6c4d71b95bfd9563b41b9280a27935ee62240480786
data/ARCHITECTURE.md CHANGED
@@ -23,8 +23,8 @@ Main source folders:
23
23
 
24
24
  ```mermaid
25
25
  flowchart TD
26
- A[CLI: bin/hellm] --> B[Hellm.build_agent]
27
- B --> C[Hellm::Builder]
26
+ A[CLI: bin/hellm] --> B[Hellm.open_project]
27
+ B --> C[Hellm::Project]
28
28
  C --> D[Load agents from .hellm/agents]
29
29
  C --> E[Load skills from .hellm/skills/**/SKILL.md]
30
30
  C --> F[Register builtin tools in Registry]
@@ -45,14 +45,14 @@ Location: lib/hellm.rb
45
45
 
46
46
  Responsibilities:
47
47
  - Stores global API key fallback from OPENAI_API_KEY
48
- - Builds an agent through Hellm::Builder
48
+ - Builds an agent through Hellm::Project
49
49
  - Exposes logger and log-level integration with Langchain
50
50
 
51
51
  Design notes:
52
52
  - Global mutable state is limited to logger and API key.
53
53
  - Agent construction delegates to Builder to keep orchestration out of the top-level API.
54
54
 
55
- ### Hellm::Builder
55
+ ### Hellm::Project
56
56
 
57
57
  Location: lib/hellm/builder.rb
58
58
 
@@ -76,7 +76,6 @@ Responsibilities:
76
76
  - Wraps Langchain::Assistant lifecycle and message exchange
77
77
  - Converts configured tool names to tool instances via Registry
78
78
  - Adds text and image input messages
79
- - Streams callbacks through StreamAdapter
80
79
  - Executes with retry logic for transient rate-limit errors
81
80
 
82
81
  Behavior details:
@@ -100,13 +99,13 @@ Location: lib/hellm/skill.rb
100
99
  Responsibilities:
101
100
  - Value object representing skill metadata and markdown content
102
101
 
103
- ### Hellm::StreamAdapter
102
+ ### Hellm::Sesstion
104
103
 
105
- Location: lib/hellm/stream_adapter.rb
104
+ Location: lib/hellm/session.rb
106
105
 
107
106
  Responsibilities:
108
- - Callback interface for streamed assistant messages and tool calls
109
- - Base implementation is intentionally empty and intended for customization
107
+ - Callback interface for streamed assistant messages
108
+ - Base implementation is intended for customization
110
109
 
111
110
  ## Tooling Architecture
112
111
 
@@ -121,7 +120,6 @@ Responsibilities:
121
120
  - Creates and registers sub-agent tools
122
121
 
123
122
  Key implications:
124
- - Tool instances are shared after first creation.
125
123
  - Custom tools should avoid mutable request-specific state.
126
124
 
127
125
  ### Hellm::Tools::SkillTool
@@ -140,6 +138,24 @@ Responsibilities:
140
138
  - Builds dynamic Langchain tools that proxy calls into sub-agents
141
139
  - Starts a fresh sub-agent session per invocation
142
140
 
141
+ ### Hellm::Tools::WebFetchTool
142
+
143
+ Location: lib/hellm/tools/web_fetch_tool.rb
144
+
145
+ Responsibilities:
146
+ - Reads raw content from HTTP(S) URLs
147
+ - Extracts plain text from HTML pages using Nokogiri
148
+ - Returns resilient error strings for network/parsing failures
149
+
150
+ ### Hellm::Tools::BraveSearchTool
151
+
152
+ Location: lib/hellm/tools/brave_search_tool.rb
153
+
154
+ Responsibilities:
155
+ - Calls Brave::SearchApi for web search requests
156
+ - Exposes query/count/offset/country parameters as a tool function
157
+ - Serializes search responses to JSON for agent consumption
158
+
143
159
  ## Configuration Model
144
160
 
145
161
  Project configuration is stored in a `.hellm` directory with the following structure:
@@ -160,10 +176,10 @@ Project configuration is stored in a `.hellm` directory with the following struc
160
176
  ## Extension Points
161
177
 
162
178
  Supported extension seams:
163
- - Register additional tools via Hellm::Tools::Registry.instance.add
179
+ - Register additional tools via Hellm::Tools::Registry#add
164
180
  - Add new agents by placing markdown files in .hellm/agents
165
181
  - Add new skills by placing SKILL.md files in .hellm/skills
166
- - Provide a custom StreamAdapter implementation for telemetry or UI streaming
182
+ - Provide a custom Session implementation for telemetry/UI streaming/restorability/resumeability
167
183
 
168
184
  ## Known Risks And Gaps
169
185
 
@@ -172,8 +188,8 @@ Current technical risks:
172
188
  - Minimal validation of markdown frontmatter means malformed config errors may surface late.
173
189
 
174
190
  Testing status:
175
- - RSpec covers core behavior for Builder, Registry, tools, and LLM-free Agent logic.
176
- - SimpleCov runs with the suite and writes coverage output to log/coverage.
191
+ - RSpec covers core behavior for Builder, Registry, tool classes (including WebFetchTool and BraveSearchTool), and LLM-free Agent logic.
192
+ - SimpleCov runs with the suite and writes coverage output to log/reports/coverage.
177
193
 
178
194
  ## Future Hardening Priorities
179
195
 
data/README.md CHANGED
@@ -47,8 +47,12 @@ hellm Alfred "Tell me your favorite color and which month fits it."
47
47
 
48
48
  The framework provides the following tools for agents to use:
49
49
 
50
- * `calculator` - a simple calculator for basic arithmetic operations.
51
- * `web` - fetches web pages or other content from URLs.
50
+ | Tool Name | Aliases | Description |
51
+ | ------------- | ----------------------- | ------------------------------------------------------- |
52
+ | `calculator` | | a simple calculator for basic arithmetic operations. |
53
+ | `webfetch` | `web` | fetches web pages or other content from URLs. |
54
+ | `websearch` | `web` | performs web searches and returns search results. utilizes [Brave Search API](https://brave.com/search/api/), which needs environment variable BRAVE_API_KEY to be set to a valid API key. |
55
+ | `web` | | combines `webfetch` and `websearch` capabilities. |
52
56
 
53
57
 
54
58
  ### Custom Tools
@@ -56,7 +60,9 @@ The framework provides the following tools for agents to use:
56
60
  Custom tools can be defined using `Langchain::ToolDefinition`, like it is described in the [Langchain documentation](https://github.com/patterns-ai-core/langchainrb#creating-custom-tools). Such tools need to be registered in `Hellm` before they can be used by agents:
57
61
 
58
62
  ```ruby
59
- Hellm::Tools::Registry.instance.add(:calculator) do
63
+ project = Hellm.open_project("/path/to/project")
64
+
65
+ project.registry.add(:calculator) do
60
66
  Langchain::Tool::Calculator.new
61
67
  end
62
68
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.5
@@ -0,0 +1,34 @@
1
+ module Brave
2
+ module SearchApi
3
+ class Client
4
+ BASE_URL = "https://api.search.brave.com/res/v1/web/search"
5
+
6
+ def initialize(api_key)
7
+ @api_key = api_key
8
+ end
9
+
10
+ def search(query, country: nil, count: 10, offset: 0)
11
+ uri = URI(BASE_URL)
12
+ params = {
13
+ q: query,
14
+ count: count,
15
+ offset: offset,
16
+ country: country
17
+ }
18
+
19
+ headers = {
20
+ "X-Subscription-Token" => @api_key,
21
+ "Content-Type" => "application/json"
22
+ }
23
+
24
+ response = Net::HTTP.post(uri, params.to_json, headers)
25
+
26
+ if response.is_a?(Net::HTTPSuccess)
27
+ JSON.parse(response.body)
28
+ else
29
+ raise "Brave Search API request failed with status #{response.code}: #{response.message}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "search_api/client"
2
+
3
+ module Brave
4
+ module SearchApi
5
+ def self.search(query, country: nil, count: 10, offset: 0)
6
+ client = Client.new(Brave.api_key)
7
+ client.search(query, country: country, count: count, offset: offset)
8
+ end
9
+ end
10
+ end
data/lib/brave.rb ADDED
@@ -0,0 +1,7 @@
1
+ require_relative "brave/search_api"
2
+
3
+ module Brave
4
+ def self.api_key
5
+ ENV["BRAVE_API_KEY"]
6
+ end
7
+ end
data/lib/hellm/agent.rb CHANGED
@@ -1,13 +1,10 @@
1
- require_relative "stream_adapter"
1
+ require_relative "session"
2
2
  require_relative "tools/registry"
3
3
  require "base64"
4
4
  require "langchain"
5
5
 
6
6
  class Hellm::Agent
7
- attr_accessor :name, :llm, :description, :agents
8
-
9
- # @param stream_adapter [Hellm::StreamAdapter] an object that responds to `message` and `tool_call` for streaming messages and tool calls
10
- attr_accessor :stream_adapter
7
+ attr_accessor :name, :llm, :description, :agents, :registry
11
8
 
12
9
  # instructions (string) for the agent.
13
10
  attr_accessor :instructions
@@ -28,7 +25,7 @@ class Hellm::Agent
28
25
  #
29
26
  attr_accessor :tools
30
27
 
31
- def initialize(model: nil, name: nil, description: nil, stream_adapter: nil, openai_api_key: nil, agents: nil, tools: nil, instructions: nil)
28
+ def initialize(model: nil, name: nil, description: nil, session: nil, openai_api_key: nil, agents: nil, tools: nil, instructions: nil, registry: nil)
32
29
  model ||= "gpt-5-nano"
33
30
  Hellm.logger.debug("Initializing agent #{name} (#{model})")
34
31
  @llm = Langchain::LLM::OpenAI.new(
@@ -38,11 +35,11 @@ class Hellm::Agent
38
35
  self.name = name || self.class.name
39
36
  self.description = description || ""
40
37
  self.instructions = instructions || ""
41
- self.stream_adapter = stream_adapter || Hellm::StreamAdapter.new
38
+ self.session = session || Hellm::Session.new
42
39
  self.agents = agents || []
43
40
  self.tools = tools || []
44
- # remove "agent" from tools, this ability is controlled by the presence of agents
45
- self.tools.reject!{|t| t == "agent"}
41
+ self.registry = registry || Hellm::Tools::Registry.new
42
+ @replaying_session = false
46
43
  end
47
44
 
48
45
 
@@ -66,15 +63,40 @@ class Hellm::Agent
66
63
  end
67
64
 
68
65
  def new_session
66
+ @session = nil
69
67
  @assistant = nil
70
68
  end
71
69
 
70
+ def session=(value)
71
+ @session = value
72
+ @replaying_session = true
73
+ @session.messages.each do |message|
74
+ attributes = {
75
+ role: fetch_indifferent(message, :role),
76
+ content: fetch_indifferent(message, :content),
77
+ image_url: fetch_indifferent(message, :image_url),
78
+ tool_calls: fetch_indifferent(message, :tool_calls),
79
+ tool_call_id: fetch_indifferent(message, :tool_call_id)
80
+ }
81
+ assistant.add_message(**attributes)
82
+ end
83
+ @replaying_session = false
84
+ end
85
+
86
+ def session
87
+ @session ||= Hellm::Session.new
88
+ end
89
+
72
90
  protected
91
+ def fetch_indifferent(hash, key)
92
+ hash[key.to_sym] || hash[key.to_s]
93
+ end
94
+
73
95
  def assistant
74
96
  if @assistant.nil?
75
97
  tool_instances = [
76
- *Hellm::Tools::Registry.instance.get(*tools),
77
- *Hellm::Tools::Registry.instance.get_agent_tools(*agents)
98
+ *self.registry.get(*tools),
99
+ *self.registry.get_agent_tools(*agents)
78
100
  ]
79
101
  @assistant = Langchain::Assistant.new(
80
102
  llm: llm,
@@ -83,24 +105,24 @@ class Hellm::Agent
83
105
  )
84
106
  @assistant.add_message_callback = ->(message) {
85
107
  Hellm.logger.debug("[Agent #{name} message] #{message.inspect}")
86
- self.stream_adapter.message(message)
108
+ if @replaying_session != true
109
+ self.session.add_message({
110
+ agent: name,
111
+ role: message.role,
112
+ content: message.content,
113
+ image_url: message.image_url,
114
+ tool_calls: message.tool_calls,
115
+ tool_call_id: message.tool_call_id
116
+ })
117
+ end
87
118
  }
88
119
  @assistant.tool_execution_callback = ->(call_id, name, method, args) {
89
120
  Hellm.logger.debug("[Agent #{self.name} tool_call] call_id: #{call_id}, name: #{name}, method: #{method}, args: #{args}")
90
- self.stream_adapter.tool_call(call_id, name, method, args)
91
121
  }
92
122
  end
93
123
  @assistant
94
124
  end
95
125
 
96
- def build_instruction_preface(agent_tool)
97
- preamble = "# Hints\n\n"
98
- preamble = "#{preamble}You are an AI agent named #{name}. You have access to the following skills and sub-agents:\n\n"
99
- preamble << agent_tool.instructions_for_agents(*agents)
100
- preamble << "\n\n"
101
- preamble
102
- end
103
-
104
126
  def normalize_image_input(image_input)
105
127
  return image_input if image_input.start_with?("http://", "https://", "data:image/")
106
128
 
@@ -1,54 +1,61 @@
1
1
  require_relative "markdown_file"
2
- require_relative "stream_adapter"
2
+ require_relative "session"
3
3
  require_relative "agent"
4
4
  require_relative "skill"
5
5
  require_relative "tools/skill_tool"
6
- require_relative "tools/web_tool"
6
+ require_relative "tools/web_fetch_tool"
7
+ require_relative "tools/brave_search_tool"
8
+ require_relative "tools/registry"
7
9
 
8
- class Hellm::Builder
9
- attr_accessor :project_dir, :hellm_dir, :stream_adapter
10
+ class Hellm::Project
11
+ attr_accessor :project_dir, :hellm_dir, :agents, :registry
10
12
 
11
13
  SUPPORTED_SKILL_ATTRIBUTEES = ["name", "description", "argument_hint"]
12
14
  SUPPORTED_AGENT_ATTRIBUTEES = ["model", "name", "description", "tools", "agents"]
13
15
 
14
- def initialize(project_dir: nil, stream_adapter: nil, openai_api_key: nil)
15
- @project_dir = project_dir
16
- @hellm_dir = File.join(project_dir, ".hellm")
17
- @hellm_dir = File.join(project_dir, ".github") if !Dir.exist?(@hellm_dir)
18
- raise ArgumentError, "not found: #{project_dir}/.hellm" unless Dir.exist?(@hellm_dir)
16
+ def initialize(project_dir: nil, openai_api_key: nil)
17
+ self.registry = Hellm::Tools::Registry.new
18
+ self.project_dir = project_dir
19
+ self.hellm_dir = File.join(project_dir, ".hellm")
20
+ self.hellm_dir = File.join(project_dir, ".github") if !Dir.exist?(self.hellm_dir)
21
+ raise ArgumentError, "not found: #{project_dir}/.hellm" unless Dir.exist?(self.hellm_dir)
19
22
 
20
- @stream_adapter = stream_adapter
21
23
  @openai_api_key = openai_api_key
22
-
23
24
  add_builtin_tools_to_registry
25
+ self.agents = build_project
24
26
  end
25
27
 
26
- def build(talking_to: nil)
27
- agents = get_agents_from_project_dir
28
- skills = get_skills_from_project_dir
29
- skill_tool = Hellm::Tools::SkillTool.new
30
- skill_tool.add(*skills)
31
- Hellm::Tools::Registry.instance.add(:skill, skill_tool)
32
- Hellm::Tools::Registry.instance.add_agents(*agents)
33
-
34
- if agents.empty?
28
+ def find_agent(name)
29
+ if self.agents.empty?
35
30
  agent = Hellm::Agent.new
36
31
  else
37
- agent = agents.find{ |agent| agent.name == talking_to }
38
- raise ArgumentError, "Agent not found: #{talking_to}" if agent.nil?
32
+ agent = self.agents.find{ |agent| agent.name == name }
33
+ raise ArgumentError, "Agent not found: #{name}" if agent.nil?
39
34
  end
40
35
  agent
41
36
  end
42
37
 
43
38
  private
39
+ def build_project
40
+ skills = build_skills_from_project_dir
41
+ skill_tool = Hellm::Tools::SkillTool.new
42
+ skill_tool.add(*skills)
43
+ self.registry.add(:skill, skill_tool)
44
+
45
+ agents = build_agents_from_project_dir(skill_tool)
46
+ self.registry.add_agents(*agents)
47
+ agents
48
+ end
49
+
44
50
  def add_builtin_tools_to_registry
45
- Hellm::Tools::Registry.instance.add(:calculator) { Langchain::Tool::Calculator.new }
46
- Hellm::Tools::Registry.instance.add(:web) { Hellm::Tools::WebTool.new }
51
+ self.registry.add(:calculator) { Langchain::Tool::Calculator.new }
52
+ self.registry.add(:bravesearch) { Hellm::Tools::BraveSearchTool.new }
53
+ self.registry.add(:webfetch) { Hellm::Tools::WebFetchTool.new }
47
54
  end
48
55
 
49
- def get_skills_from_project_dir
56
+ def build_skills_from_project_dir
50
57
  skills_dir = File.join(hellm_dir, "skills")
51
- return unless Dir.exist?(skills_dir)
58
+ return [] unless Dir.exist?(skills_dir)
52
59
 
53
60
  Dir.glob(File.join(skills_dir, "**/SKILL.md")).map do |file|
54
61
  markdown_dir = File.dirname(file)
@@ -63,15 +70,15 @@ class Hellm::Builder
63
70
  end
64
71
  end
65
72
 
66
- def get_agents_from_project_dir
73
+ def build_agents_from_project_dir(skill_tool)
67
74
  agents_dir = File.join(hellm_dir, "agents")
68
- return unless Dir.exist?(agents_dir)
75
+ return [] unless Dir.exist?(agents_dir)
69
76
 
70
77
  Dir.glob(File.join(agents_dir, "*.md")).map do |file|
71
78
  markdown_file = Hellm::MarkdownFile.read(file)
72
79
 
73
80
  tools = markdown_file.fetch("tools", [])
74
- tools << "skill"
81
+ tools << "default"
75
82
 
76
83
  Hellm::Agent.new(
77
84
  model: markdown_file.fetch("model"),
@@ -80,8 +87,8 @@ class Hellm::Builder
80
87
  tools: tools,
81
88
  agents: markdown_file.fetch("agents", []),
82
89
  instructions: markdown_file.content.strip,
83
- stream_adapter: stream_adapter,
84
- openai_api_key: @openai_api_key
90
+ openai_api_key: @openai_api_key,
91
+ registry: self.registry
85
92
  )
86
93
  end
87
94
  end
@@ -0,0 +1,17 @@
1
+ class Hellm::Session
2
+ def initialize(messages = [])
3
+ @messages = messages
4
+ end
5
+
6
+ def messages
7
+ @messages
8
+ end
9
+
10
+ def messages=(value)
11
+ @messages = value
12
+ end
13
+
14
+ def add_message(message)
15
+ @messages << message
16
+ end
17
+ end
@@ -1,32 +1,31 @@
1
1
  module Hellm::Tools
2
2
  require "langchain"
3
3
 
4
+
4
5
  class AgentToolFactory
5
- def self.create_sub_agent_tool(agent_name, agent)
6
- klass = Class.new do
7
- @@agent_name = agent_name
6
+ class AgentBase
7
+ extend Langchain::ToolDefinition
8
8
 
9
- extend Langchain::ToolDefinition
9
+ def initialize(agent)
10
+ @agent = agent
11
+ end
10
12
 
11
- def self.tool_name
12
- @@agent_name
13
- end
13
+ def run_agent(content: nil, image: nil)
14
+ @agent.new_session
15
+ @agent.add(content: content, image: image)
16
+ @agent.run
17
+ @agent.response
18
+ end
19
+ end
20
+
21
+ def self.create_sub_agent_tool(agent_name, agent)
22
+ klass = Class.new(AgentBase) do
23
+ define_singleton_method(:tool_name) { agent_name }
14
24
 
15
25
  define_function "run_agent", description: "Run the agent #{agent.name} and return its response.\n#{agent.description}" do
16
26
  property :content, type: "string", description: "Textual content to pass to the agent.", required: false
17
27
  property :image, type: "string", description: "Image URL or path to pass to the agent.", required: false
18
28
  end
19
-
20
- def initialize(agent)
21
- @agent = agent
22
- end
23
-
24
- def run_agent(content: nil, image: nil)
25
- @agent.new_session
26
- @agent.add(content: content, image: image)
27
- @agent.run
28
- @agent.response
29
- end
30
29
  end
31
30
  klass.new(agent)
32
31
  end
@@ -0,0 +1,20 @@
1
+ require "brave"
2
+
3
+ module Hellm::Tools
4
+ class BraveSearchTool
5
+ extend Langchain::ToolDefinition
6
+
7
+ define_function :search, description: "Performs a web search using 'Brave Search' search engine." do
8
+ property :query, type: "string", description: "The search query.", required: true
9
+ property :count, type: "integer", description: "The number of search results to return.", required: false
10
+ property :offset, type: "integer", description: "The offset for the search results.", required: false
11
+ property :country, type: "string", description: "The 2-letter country code for the search results.", required: false
12
+ end
13
+
14
+ def search(query:, count: 10, offset: 0, country: nil)
15
+ results = Brave::SearchApi.search(query, count: count, offset: offset, country: country)
16
+ results.to_json
17
+ end
18
+
19
+ end
20
+ end
@@ -2,13 +2,19 @@ require_relative "agent_tool_factory"
2
2
 
3
3
  module Hellm::Tools
4
4
  class Registry
5
- def self.instance
6
- @instance ||= new
7
- end
5
+ ALIASES = {
6
+ "default" => ["skill", "calculator"],
7
+ "web" => ["webfetch", "bravesearch"],
8
+ "websearch" => ["bravesearch"],
9
+ "agent" => [] # agent tools are dynamically generated from registered agents
10
+ }
8
11
 
9
12
  def initialize
10
13
  @tools = {}
11
- @agent_tools = {}
14
+ end
15
+
16
+ def available_tools
17
+ @tools.keys
12
18
  end
13
19
 
14
20
  def add(tool_name, instance=nil, &factory)
@@ -19,6 +25,7 @@ module Hellm::Tools
19
25
  end
20
26
 
21
27
  def get(*tool_names)
28
+ tool_names = resolve_aliases(*tool_names)
22
29
  tools = tool_names.map do |tool_name|
23
30
  entry = @tools[tool_name.to_s]
24
31
  if entry.nil?
@@ -49,5 +56,11 @@ module Hellm::Tools
49
56
  def agent_tool_name(agent_name)
50
57
  "agent_tool_" + agent_name.gsub(/[\s-]+/, "_").downcase
51
58
  end
59
+
60
+ def resolve_aliases(*tool_names)
61
+ tool_names.map do |tool_name|
62
+ ALIASES.fetch(tool_name.to_s, [tool_name.to_s])
63
+ end.flatten
64
+ end
52
65
  end
53
66
  end
@@ -4,6 +4,12 @@ module Hellm::Tools
4
4
  class SkillTool
5
5
  extend Langchain::ToolDefinition
6
6
 
7
+ attr_reader :skills
8
+
9
+ def initialize
10
+ @skills = []
11
+ end
12
+
7
13
  def add(*skills)
8
14
  skills.each do |skill|
9
15
  add_skill(skill)
@@ -12,6 +18,7 @@ module Hellm::Tools
12
18
 
13
19
  private
14
20
  def add_skill(skill)
21
+ @skills << skill
15
22
  skill_name = skill.name.gsub(/[\s-]+/, "_").downcase
16
23
  method_name = "get_skill_#{skill_name}"
17
24
  self.class.class_eval(
@@ -2,7 +2,7 @@ require "open-uri"
2
2
  require "nokogiri"
3
3
 
4
4
  module Hellm::Tools
5
- class WebTool
5
+ class WebFetchTool
6
6
  extend Langchain::ToolDefinition
7
7
 
8
8
  define_function :read, description: "Reads content from a URL. Use this function when you want to get text/binary raw data from the response, e.g. to check the HTML-code of a page." do
data/lib/hellm.rb CHANGED
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "hellm/version"
4
- require_relative "hellm/builder"
4
+ require_relative "hellm/project"
5
5
 
6
6
  module Hellm
7
7
  class Error < StandardError; end
8
- # Your code goes here...
9
8
 
10
9
  def self.openai_api_key=(key)
11
10
  @api_key = key if !key.nil? && !key.empty?
@@ -15,10 +14,9 @@ module Hellm
15
14
  @api_key ||= ENV["OPENAI_API_KEY"]
16
15
  end
17
16
 
18
- def self.build_agent(agent_name, project_dir, stream_adapter: nil, openai_api_key: nil)
17
+ def self.open_project(project_dir, openai_api_key: nil)
19
18
  self.openai_api_key = openai_api_key
20
- builder = Hellm::Builder.new(project_dir: project_dir, stream_adapter: stream_adapter, openai_api_key: openai_api_key)
21
- builder.build(talking_to: agent_name)
19
+ Hellm::Project.new(project_dir: project_dir, openai_api_key: openai_api_key)
22
20
  end
23
21
 
24
22
  def self.logger=(logger)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hellm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - ubity UG
@@ -81,19 +81,19 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.19.4
83
83
  - !ruby/object:Gem::Dependency
84
- name: google_search_results
84
+ name: gsearch-parser
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 2.2.0
89
+ version: 0.2.2
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 2.2.0
96
+ version: 0.2.2
97
97
  description: |
98
98
  Declarative agentic framework for LLMs, allowing you to build autonomous agents that can perform complex tasks and interact with the world, without writing code.
99
99
  Agents and skills are defined in markdown files, quite similar to how Github Copilot works.
@@ -118,16 +118,20 @@ files:
118
118
  - example/.hellm/skills/farben/SKILL.md
119
119
  - example/example1.sh
120
120
  - example/example2.sh
121
+ - lib/brave.rb
122
+ - lib/brave/search_api.rb
123
+ - lib/brave/search_api/client.rb
121
124
  - lib/hellm.rb
122
125
  - lib/hellm/agent.rb
123
- - lib/hellm/builder.rb
124
126
  - lib/hellm/markdown_file.rb
127
+ - lib/hellm/project.rb
128
+ - lib/hellm/session.rb
125
129
  - lib/hellm/skill.rb
126
- - lib/hellm/stream_adapter.rb
127
130
  - lib/hellm/tools/agent_tool_factory.rb
131
+ - lib/hellm/tools/brave_search_tool.rb
128
132
  - lib/hellm/tools/registry.rb
129
133
  - lib/hellm/tools/skill_tool.rb
130
- - lib/hellm/tools/web_tool.rb
134
+ - lib/hellm/tools/web_fetch_tool.rb
131
135
  - lib/hellm/version.rb
132
136
  - sig/hellm.rbs
133
137
  homepage: https://gitlab.com/ubity/gems/hellm
@@ -1,7 +0,0 @@
1
- class Hellm::StreamAdapter
2
- def message(message)
3
- end
4
-
5
- def tool_call(call_id, name, method, args)
6
- end
7
- end