ollama_chat 0.0.66 → 0.0.67

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: f1a18f61aaf91ee38941a242b7ad2930db7e03e2070ce056f6c7e527fd669cdf
4
- data.tar.gz: f9d94af7c77f4639ed977a783d353f2be3a476fe027264f55a405537839f5cc3
3
+ metadata.gz: 3eb8ee4b480c19b26ba27b6d112da4038ed16615881425ba4f7142483d329a79
4
+ data.tar.gz: 85a7d64b19b3e751d51d7ada7af2ff536e578f3425218394b0aa3efcd5301626
5
5
  SHA512:
6
- metadata.gz: 9fc0f6fbb9f5b8afa6937f7f1a136f007b6ec41cc6085b4f8a72de1849624f41b3ff2212d0350ddf8eae3b2c181ed965e425d0fe33288d7960d6314db9e7cb3a
7
- data.tar.gz: 0257f7bdee23f896e40e6b6610d9561c9c9c77d925eb706514e61ec890865476cff3d989c9dcdb42063a68625a58b34e3ec6d82cbfa327dae0cd4262c742bd5f
6
+ metadata.gz: f374a3d58183068936222115a61e090ee3e45efd637401ffd97cebc147286b971025730d6393e95dc2b5eeb2e89cacc65d33a3dc76f6467fb23e1aedfe13fffd
7
+ data.tar.gz: fefa35f2e685dab9c4f3e8b97487f4a4a072f3b2b982864ae423b8d4aaba29ea3e46dc4065dedb7db3908f3192c56c922f92e123163272ef186771b862b7ffc4
data/CHANGES.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-02-18 v0.0.67
4
+
5
+ - Added `max_depth` option to directory listing tool
6
+ - Updated `OllamaChat::Tools::DirectoryStructure#execute` to accept `max_depth` parameter
7
+ - Enhanced `OllamaChat::Utils::AnalyzeDirectory#generate_structure` to handle `max_depth` limit
8
+ - Implemented depth and height computation for directory entries
9
+ - Added depth pruning functionality to remove children beyond the specified depth limit
10
+ - Attached `:depth` and `:height` metadata to each directory entry in JSON output
11
+ - Refactored internal helper method `recurse_generate_structure` to track entry depth
12
+ - Updated documentation comments to reflect new behavior
13
+ - Added comprehensive test coverage for `max_depth` functionality
14
+ - Added depth-pruning test cases in specification files
15
+
3
16
  ## 2026-02-16 v0.0.66
4
17
 
5
18
  - Updated `OllamaChat::Tools::GetCurrentWeather.execute` to return a JSON
@@ -24,7 +24,10 @@ class OllamaChat::Tools::DirectoryStructure
24
24
  type: 'function',
25
25
  function: Tool::Function.new(
26
26
  name:,
27
- description: 'Retrieve the directory structure and file hierarchy for a given path',
27
+ description: <<~EOT,
28
+ Retrieve the directory structure and file hierarchy for a given path,
29
+ for depth of max_depth (if given).
30
+ EOT
28
31
  parameters: Tool::Function::Parameters.new(
29
32
  type: 'object',
30
33
  properties: {
@@ -32,6 +35,13 @@ class OllamaChat::Tools::DirectoryStructure
32
35
  type: 'string',
33
36
  description: 'Path to directory to list (defaults to current directory)'
34
37
  ),
38
+ max_depth: Tool::Function::Parameters::Property.new(
39
+ type: 'integer',
40
+ description: <<~EOT,
41
+ Maximum depth of directory structure to return upto the total
42
+ height of the directory structure (defaults to disabled)
43
+ EOT
44
+ ),
35
45
  },
36
46
  required: []
37
47
  )
@@ -52,10 +62,11 @@ class OllamaChat::Tools::DirectoryStructure
52
62
  # @raise [StandardError] if there's an issue with directory traversal or JSON
53
63
  # serialization
54
64
  def execute(tool_call, **opts)
55
- config = opts[:config]
56
- path = Pathname.new(tool_call.function.arguments.path || '.')
65
+ config = opts[:config]
66
+ path = Pathname.new(tool_call.function.arguments.path || '.')
67
+ max_depth = tool_call.function.arguments.max_depth
57
68
 
58
- structure = generate_structure(path, exclude: config.tools.directory_structure.exclude?)
69
+ structure = generate_structure(path, max_depth:, exclude: config.tools.directory_structure.exclude?)
59
70
  structure.to_json
60
71
  end
61
72
 
@@ -1,64 +1,146 @@
1
- # A module that provides functionality for analyzing directory structures and
2
- # generating file listings.
3
- #
4
- # The AnalyzeDirectory module offers methods to traverse directory hierarchies
5
- # and create structured representations of file systems. It supports recursive
6
- # directory traversal, filtering of hidden files and symbolic links, and
7
- # generation of detailed file and directory information including paths, names,
8
- # and metadata.
9
- module OllamaChat::Utils::AnalyzeDirectory
10
- module_function
1
+ require 'pathname'
11
2
 
12
- # Generates a directory structure representation with files and
13
- # subdirectories.
14
- #
15
- # @param path [String] the path to start generating the structure from,
16
- # defaults to current directory
17
- #
18
- # @return [Array<Hash>, Hash] an array of hashes representing files and
19
- # directories, or a hash with error information if an exception occurs
20
- # @return [Array] an empty array if the path is invalid or has no children
21
- # @return [Hash] a hash with error details if an exception is raised during processing
22
- #
23
- # @example Generate structure for current directory
24
- # generate_structure
25
- #
26
- # @example Generate structure for a specific path
27
- # generate_structure('/path/to/directory')
28
- #
29
- # @note Hidden files and directories (starting with '.') are skipped
30
- # @note Symbolic links are skipped
31
- # @note The method uses recursive calls to traverse subdirectories
32
- # @note If an error occurs during traversal, it returns a hash with error details
33
- def generate_structure(path = ?., exclude: [])
34
- exclude = Array(exclude).map { Pathname.new(_1).expand_path }
35
- path = Pathname.new(path).expand_path
36
- entries = []
37
- path.children.sort.each do |child|
38
- # Skip hidden files/directories
39
- next if child.basename.to_s.start_with?('.')
40
- # Skip symlinks
41
- next if child.symlink?
42
- # Skip if excluded
43
- next if exclude.any? { child.fnmatch?(_1.to_s, File::FNM_PATHNAME) }
3
+ module OllamaChat
4
+ module Utils
5
+ # The `OllamaChat::Utils::AnalyzeDirectory` module provides a small,
6
+ # dependency‑free helper for walking a directory tree and producing a
7
+ # nested hash representation of the file system.
8
+ #
9
+ # It supports:
10
+ #
11
+ # * Recursive traversal of directories
12
+ # * Skipping hidden files/directories and symbolic links
13
+ # * Excluding arbitrary paths via glob patterns
14
+ # * Limiting the depth of the returned tree
15
+ #
16
+ # Example
17
+ #
18
+ # require_relative 'analyze_directory'
19
+ #
20
+ # include OllamaChat::Utils::AnalyzeDirectory
21
+ #
22
+ # structure = generate_structure(
23
+ # '/path/to/dir',
24
+ # exclude: ['tmp', 'vendor'],
25
+ # max_depth: 3
26
+ # )
27
+ #
28
+ # puts structure.inspect
29
+ #
30
+ # @api public
31
+ module AnalyzeDirectory
32
+ # Generate a nested hash representation of a directory tree.
33
+ #
34
+ # @param path [String, Pathname] The root directory to walk.
35
+ # Defaults to the current working directory (`"."`).
36
+ # @param exclude [Array<String, Pathname>] Glob patterns (relative to
37
+ # +path+) that should be ignored during traversal.
38
+ # @param max_depth [Integer, nil] Optional depth limit. If `nil`,
39
+ # the entire tree is returned. When an integer is supplied, all
40
+ # entries deeper than that depth are pruned.
41
+ #
42
+ # @return [Array<Hash>] An array of entry hashes. Each hash contains:
43
+ # * `:type` – "file" or "directory"
44
+ # * `:name` – Base name of the file/directory
45
+ # * `:path` – Absolute path
46
+ # * `:depth` – Depth relative to the root (root = 0)
47
+ # * `:height` – The maximum depth found in the entire tree
48
+ # * `:children` – Array of child entry hashes (only for directories)
49
+ #
50
+ # @raise [StandardError] Any exception raised during traversal is
51
+ # rescued and returned as a hash with `:error` and `:message`
52
+ # keys.
53
+ #
54
+ # @example Basic usage
55
+ # generate_structure(
56
+ # '/tmp',
57
+ # exclude: ['cache', 'logs'],
58
+ # max_depth: 2
59
+ # )
60
+ #
61
+ # @api public
62
+ def generate_structure(path = '.', exclude: [], max_depth: nil)
63
+ entries = recurse_generate_structure(path, exclude:)
64
+ height = 0
44
65
 
45
- if child.directory?
46
- entries << {
47
- type: 'directory',
48
- name: child.basename.to_s,
49
- path: child.expand_path.to_s,
50
- children: generate_structure(child)
51
- }
52
- elsif child.file?
53
- entries << {
54
- type: 'file',
55
- path: child.expand_path.to_s,
56
- name: child.basename.to_s
57
- }
66
+ structure_each_entry(entries) do |e|
67
+ height = e[:depth] if e[:depth] > height
68
+ end
69
+
70
+ structure_each_entry(entries) { |e| e[:height] = height }
71
+
72
+ if max_depth && max_depth < height
73
+ structure_each_entry(entries) do |e|
74
+ e[:children]&.reject! { |c| c[:depth] > max_depth }
75
+ end
76
+ end
77
+
78
+ entries
79
+ rescue => e
80
+ { error: e.class, message: e.message }
81
+ end
82
+
83
+ private
84
+
85
+ # Recursively walk *path* and build the tree.
86
+ #
87
+ # @param path [String, Pathname] Directory to traverse.
88
+ # @param exclude [Array<Pathname>] List of absolute paths to skip.
89
+ # @param depth [Integer] Current depth (root = 0).
90
+ #
91
+ # @return [Array<Hash>] Array of entry hashes.
92
+ #
93
+ # @api private
94
+ def recurse_generate_structure(path = '.', exclude: [], depth: 0)
95
+ exclude = Array(exclude).map { |p| Pathname.new(p).expand_path }
96
+ path = Pathname.new(path).expand_path
97
+ entries = []
98
+
99
+ path.children.sort.each do |child|
100
+ # Skip hidden files/directories
101
+ next if child.basename.to_s.start_with?('.')
102
+ # Skip symlinks
103
+ next if child.symlink?
104
+ # Skip user‑excluded paths
105
+ next if exclude.any? { |e| child.fnmatch?(e.to_s, File::FNM_PATHNAME) }
106
+
107
+ if child.directory?
108
+ entries << {
109
+ type: 'directory',
110
+ name: child.basename.to_s,
111
+ path: child.expand_path.to_s,
112
+ children: recurse_generate_structure(child, exclude:, depth: depth + 1),
113
+ depth:
114
+ }
115
+ elsif child.file?
116
+ entries << {
117
+ type: 'file',
118
+ name: child.basename.to_s,
119
+ path: child.expand_path.to_s,
120
+ depth:
121
+ }
122
+ end
123
+ end
124
+
125
+ entries
126
+ end
127
+
128
+ # Iterate over every entry in *entries* (depth‑first).
129
+ #
130
+ # @param entries [Array<Hash>] The root array of entries.
131
+ # @yield [Hash] Yields each entry hash.
132
+ #
133
+ # @return [Array<Hash>] The original +entries+ array.
134
+ #
135
+ # @api private
136
+ def structure_each_entry(entries, &block)
137
+ queue = entries.dup
138
+ while entry = queue.shift
139
+ block.(entry)
140
+ queue.concat(entry[:children]) if entry[:children]
141
+ end
142
+ entries
58
143
  end
59
144
  end
60
- entries
61
- rescue => e
62
- { error: e.class, message: e.message }
63
145
  end
64
146
  end
@@ -1,6 +1,6 @@
1
1
  module OllamaChat
2
2
  # OllamaChat version
3
- VERSION = '0.0.66'
3
+ VERSION = '0.0.67'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/ollama_chat.gemspec CHANGED
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: ollama_chat 0.0.66 ruby lib
2
+ # stub: ollama_chat 0.0.67 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "ollama_chat".freeze
6
- s.version = "0.0.66".freeze
6
+ s.version = "0.0.67".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
@@ -26,6 +26,7 @@ describe OllamaChat::Tools::DirectoryStructure do
26
26
  name: 'directory_structure',
27
27
  arguments: double(
28
28
  path: 'spec/assets',
29
+ max_depth: nil,
29
30
  )
30
31
  )
31
32
  )
@@ -45,6 +46,7 @@ describe OllamaChat::Tools::DirectoryStructure do
45
46
  name: 'directory_structure',
46
47
  arguments: double(
47
48
  path: nil, # Should default to '.'
49
+ max_depth: nil,
48
50
  )
49
51
  )
50
52
  )
@@ -64,6 +66,7 @@ describe OllamaChat::Tools::DirectoryStructure do
64
66
  name: 'directory_structure',
65
67
  arguments: double(
66
68
  path: '/nonexistent/path',
69
+ max_depth: nil,
67
70
  )
68
71
  )
69
72
  )
@@ -3,7 +3,11 @@ require 'tmpdir'
3
3
  require 'fileutils'
4
4
 
5
5
  describe OllamaChat::Utils::AnalyzeDirectory do
6
- let(:generate) { described_class.method(:generate_structure) }
6
+ let :generate do
7
+ obj = double
8
+ obj.extend(described_class)
9
+ obj.method(:generate_structure)
10
+ end
7
11
 
8
12
  context 'basic directory structure' do
9
13
  before do
@@ -28,9 +32,24 @@ describe OllamaChat::Utils::AnalyzeDirectory do
28
32
  expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'b.rb', 'sub')
29
33
 
30
34
  sub = result.find { |e| e[:name] == 'sub' }
35
+ expect(sub[:depth]).to eq 0
31
36
  expect(sub[:type]).to eq('directory')
32
37
  expect(sub[:children]).to be_an(Array)
33
38
  expect(sub[:children].map { |e| e[:name] }).to contain_exactly('c.md')
39
+ expect(sub[:children].map { |e| e[:depth] }).to eq [ 1 ]
40
+ end
41
+
42
+ it 'returns an array of entries with depth max_depth' do
43
+ result = generate.call(@tmp_dir, max_depth: 0)
44
+
45
+ expect(result).to be_an(Array)
46
+ expect(result.map { |e| e[:name] }).to contain_exactly('a.txt', 'b.rb', 'sub')
47
+
48
+ sub = result.find { |e| e[:name] == 'sub' }
49
+ expect(sub[:depth]).to eq 0
50
+ expect(sub[:type]).to eq('directory')
51
+ expect(sub[:children]).to be_an(Array)
52
+ expect(sub[:children]).to be_empty
34
53
  end
35
54
  end
36
55
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama_chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.66
4
+ version: 0.0.67
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank