ollama_agent 0.3.0 → 1.0.1
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 +4 -4
- data/.claude/scheduled_tasks.lock +1 -0
- data/.env.example +21 -1
- data/CHANGELOG.md +47 -0
- data/CONTRIBUTING.md +23 -0
- data/README.md +308 -9
- data/Rakefile +2 -0
- data/config/ollama_agent/owners.yml +53 -0
- data/containers/ollama_agent-verification-sandbox.Dockerfile +16 -0
- data/db/ollama_agent/migrations/0001_initial.sql +102 -0
- data/db/ollama_agent/migrations/0002_cost_ledger.sql +12 -0
- data/db/ollama_agent/schema.sql +1 -0
- data/docs/CAPABILITIES.md +91 -0
- data/docs/CLI.md +212 -0
- data/docs/FEATURES.md +1298 -0
- data/docs/OPERATIONS.md +179 -0
- data/docs/TOOLS.md +104 -1
- data/docs/TRADING_AGENT_PLAN.md +88 -0
- data/docs/USAGE.md +246 -0
- data/docs/agile/docker_spec_activation.md +55 -0
- data/docs/agile/release_rollout_runbook.md +125 -0
- data/docs/agile/runtime_kernel_backlog.md +173 -0
- data/docs/agile/runtime_kernel_risk_register.md +27 -0
- data/docs/agile/separate_server_strategy.md +25 -0
- data/docs/agile/sprint_0_setup.md +52 -0
- data/docs/agile/sprint_execution_map.md +24 -0
- data/docs/new_features copy.md +14446 -0
- data/docs/new_features.md +11771 -0
- data/docs/new_features_plan.md +246 -0
- data/docs/new_features_plan_v2.md +223 -0
- data/docs/superpowers/plans/2026-05-28-interactive-completion-system.md +697 -0
- data/docs/superpowers/plans/2026-05-29-session-runtime-integration.md +966 -0
- data/docs/superpowers/specs/2026-05-29-session-runtime-integration-design.md +318 -0
- data/docs/trading_agent.md +3180 -0
- data/examples/agentic_tool_calling.rb +104 -0
- data/lib/ollama_agent/agent/agent_config.rb +23 -2
- data/lib/ollama_agent/agent/chat_coordinator.rb +88 -0
- data/lib/ollama_agent/agent/client_wiring.rb +3 -8
- data/lib/ollama_agent/agent/prompt_wiring.rb +1 -1
- data/lib/ollama_agent/agent/session_wiring.rb +36 -6
- data/lib/ollama_agent/agent/turn_loop.rb +89 -0
- data/lib/ollama_agent/agent.rb +153 -85
- data/lib/ollama_agent/agent_root_resolver.rb +23 -0
- data/lib/ollama_agent/cli/health_command.rb +45 -0
- data/lib/ollama_agent/cli/repl.rb +159 -0
- data/lib/ollama_agent/cli/repl_shared.rb +336 -0
- data/lib/ollama_agent/cli/skill_command.rb +71 -0
- data/lib/ollama_agent/cli/tui_repl.rb +202 -0
- data/lib/ollama_agent/cli.rb +149 -53
- data/lib/ollama_agent/console.rb +2 -2
- data/lib/ollama_agent/context/token_counter.rb +5 -0
- data/lib/ollama_agent/core/action_envelope.rb +82 -0
- data/lib/ollama_agent/core/budget.rb +90 -0
- data/lib/ollama_agent/core/loop_detector.rb +67 -0
- data/lib/ollama_agent/core/schema_validator.rb +135 -0
- data/lib/ollama_agent/core/trace_logger.rb +140 -0
- data/lib/ollama_agent/errors.rb +61 -0
- data/lib/ollama_agent/external_agents/default_agents.yml +11 -2
- data/lib/ollama_agent/external_agents/path_validator.rb +1 -3
- data/lib/ollama_agent/external_agents/probe.rb +56 -8
- data/lib/ollama_agent/external_agents/runner.rb +22 -43
- data/lib/ollama_agent/external_agents.rb +4 -0
- data/lib/ollama_agent/gemma_thought_content_parser.rb +211 -0
- data/lib/ollama_agent/indexing/context_packer.rb +140 -0
- data/lib/ollama_agent/indexing/diff_summarizer.rb +125 -0
- data/lib/ollama_agent/indexing/file_indexer.rb +129 -0
- data/lib/ollama_agent/indexing/repo_scanner.rb +158 -0
- data/lib/ollama_agent/llm/anthropic_client.rb +263 -0
- data/lib/ollama_agent/llm/cloud_fallback_router.rb +111 -0
- data/lib/ollama_agent/llm/context_builder.rb +57 -0
- data/lib/ollama_agent/llm/first_json_object.rb +41 -0
- data/lib/ollama_agent/llm/planner.rb +140 -0
- data/lib/ollama_agent/llm/planner_schema.rb +90 -0
- data/lib/ollama_agent/llm/think_block_stripper.rb +16 -0
- data/lib/ollama_agent/memory/long_term.rb +113 -0
- data/lib/ollama_agent/memory/manager.rb +120 -0
- data/lib/ollama_agent/memory/session_memory.rb +93 -0
- data/lib/ollama_agent/memory/short_term.rb +66 -0
- data/lib/ollama_agent/ollama_chat_thinking_stream.rb +25 -0
- data/lib/ollama_agent/ollama_cloud_catalog.rb +85 -0
- data/lib/ollama_agent/ollama_connection.rb +39 -0
- data/lib/ollama_agent/plugins/loader.rb +95 -0
- data/lib/ollama_agent/plugins/registry.rb +107 -0
- data/lib/ollama_agent/providers/anthropic.rb +261 -0
- data/lib/ollama_agent/providers/base.rb +85 -0
- data/lib/ollama_agent/providers/credential.rb +156 -0
- data/lib/ollama_agent/providers/credential_pool.rb +96 -0
- data/lib/ollama_agent/providers/credential_router.rb +130 -0
- data/lib/ollama_agent/providers/error_classifier.rb +107 -0
- data/lib/ollama_agent/providers/health_monitor.rb +133 -0
- data/lib/ollama_agent/providers/model_descriptor.rb +45 -0
- data/lib/ollama_agent/providers/model_registry.rb +207 -0
- data/lib/ollama_agent/providers/ollama.rb +184 -0
- data/lib/ollama_agent/providers/openai.rb +232 -0
- data/lib/ollama_agent/providers/quota_tracker.rb +144 -0
- data/lib/ollama_agent/providers/rate_window.rb +57 -0
- data/lib/ollama_agent/providers/registry.rb +162 -0
- data/lib/ollama_agent/providers/router.rb +91 -0
- data/lib/ollama_agent/repo_list.rb +22 -10
- data/lib/ollama_agent/resilience/retry_middleware.rb +7 -0
- data/lib/ollama_agent/ruby_index_tool_support.rb +11 -1
- data/lib/ollama_agent/runner.rb +97 -10
- data/lib/ollama_agent/runtime/approval_gate.rb +74 -0
- data/lib/ollama_agent/runtime/atomic_mutator.rb +366 -0
- data/lib/ollama_agent/runtime/blob_store.rb +98 -0
- data/lib/ollama_agent/runtime/cas_guard.rb +52 -0
- data/lib/ollama_agent/runtime/compactor.rb +250 -0
- data/lib/ollama_agent/runtime/compactor_runner.rb +25 -0
- data/lib/ollama_agent/runtime/compensation_engine.rb +85 -0
- data/lib/ollama_agent/runtime/compensation_manifest.rb +66 -0
- data/lib/ollama_agent/runtime/cost_ledger.rb +53 -0
- data/lib/ollama_agent/runtime/criticality_policy.rb +51 -0
- data/lib/ollama_agent/runtime/database_registry.rb +74 -0
- data/lib/ollama_agent/runtime/event_store.rb +80 -0
- data/lib/ollama_agent/runtime/execution_context.rb +21 -0
- data/lib/ollama_agent/runtime/execution_manifest.rb +41 -0
- data/lib/ollama_agent/runtime/execution_mode.rb +22 -0
- data/lib/ollama_agent/runtime/fencing_allocator.rb +30 -0
- data/lib/ollama_agent/runtime/file_atomic_swap.rb +76 -0
- data/lib/ollama_agent/runtime/integration_queue.rb +61 -0
- data/lib/ollama_agent/runtime/intent_reservation.rb +115 -0
- data/lib/ollama_agent/runtime/intent_translator.rb +193 -0
- data/lib/ollama_agent/runtime/isolated_validator.rb +217 -0
- data/lib/ollama_agent/runtime/kernel_bridge.rb +280 -0
- data/lib/ollama_agent/runtime/kernel_event_logger.rb +53 -0
- data/lib/ollama_agent/runtime/kernel_feature.rb +19 -0
- data/lib/ollama_agent/runtime/kernel_health.rb +96 -0
- data/lib/ollama_agent/runtime/kernel_pipeline.rb +691 -0
- data/lib/ollama_agent/runtime/kernel_pipeline_assembly.rb +119 -0
- data/lib/ollama_agent/runtime/kernel_tool_seed.rb +235 -0
- data/lib/ollama_agent/runtime/lock_manager.rb +153 -0
- data/lib/ollama_agent/runtime/logical_clock.rb +22 -0
- data/lib/ollama_agent/runtime/mutation_classifier.rb +24 -0
- data/lib/ollama_agent/runtime/permission_bridge.rb +89 -0
- data/lib/ollama_agent/runtime/permissions.rb +103 -0
- data/lib/ollama_agent/runtime/policies.rb +96 -0
- data/lib/ollama_agent/runtime/post_condition_verifier.rb +52 -0
- data/lib/ollama_agent/runtime/rollback_signals.rb +87 -0
- data/lib/ollama_agent/runtime/saga_coordinator.rb +224 -0
- data/lib/ollama_agent/runtime/saga_recovery_daemon.rb +91 -0
- data/lib/ollama_agent/runtime/saga_state.rb +44 -0
- data/lib/ollama_agent/runtime/sandbox.rb +130 -0
- data/lib/ollama_agent/runtime/schema_migrator.rb +138 -0
- data/lib/ollama_agent/runtime/unified_diff_apply.rb +102 -0
- data/lib/ollama_agent/runtime/wal.rb +54 -0
- data/lib/ollama_agent/runtime/workspace_wal_replay.rb +72 -0
- data/lib/ollama_agent/runtime_command_system/ast.rb +96 -0
- data/lib/ollama_agent/runtime_command_system/command_palette.rb +53 -0
- data/lib/ollama_agent/runtime_command_system/command_registry.rb +48 -0
- data/lib/ollama_agent/runtime_command_system/completers.rb +83 -0
- data/lib/ollama_agent/runtime_command_system/dispatch/dispatcher.rb +36 -0
- data/lib/ollama_agent/runtime_command_system/dispatch/handlers/model_handler.rb +20 -0
- data/lib/ollama_agent/runtime_command_system/dispatch/handlers/provider_handler.rb +19 -0
- data/lib/ollama_agent/runtime_command_system/ghost_text.rb +34 -0
- data/lib/ollama_agent/runtime_command_system/input_buffer.rb +43 -0
- data/lib/ollama_agent/runtime_command_system/interactive_menu.rb +48 -0
- data/lib/ollama_agent/runtime_command_system/session/events.rb +32 -0
- data/lib/ollama_agent/runtime_command_system/session/runtime.rb +40 -0
- data/lib/ollama_agent/runtime_command_system/suggestion.rb +30 -0
- data/lib/ollama_agent/runtime_command_system/suggestion_engine.rb +41 -0
- data/lib/ollama_agent/runtime_command_system.rb +11 -0
- data/lib/ollama_agent/sandboxed_tools/search_text.rb +27 -4
- data/lib/ollama_agent/sandboxed_tools.rb +20 -7
- data/lib/ollama_agent/security/ownership_compile_validators.rb +77 -0
- data/lib/ollama_agent/security/ownership_compiler.rb +89 -0
- data/lib/ollama_agent/security/ownership_index.rb +63 -0
- data/lib/ollama_agent/security/ownership_rule_tree_flattener.rb +122 -0
- data/lib/ollama_agent/security/resource_guard.rb +55 -0
- data/lib/ollama_agent/skills/architecture_refactorer.rb +52 -0
- data/lib/ollama_agent/skills/base.rb +57 -0
- data/lib/ollama_agent/skills/debug_engineer.rb +53 -0
- data/lib/ollama_agent/skills/feature_builder.rb +59 -0
- data/lib/ollama_agent/skills/json_extractor.rb +81 -0
- data/lib/ollama_agent/skills/llm_client.rb +42 -0
- data/lib/ollama_agent/skills/performance_optimizer.rb +48 -0
- data/lib/ollama_agent/skills/registry.rb +39 -0
- data/lib/ollama_agent/skills/runner.rb +35 -0
- data/lib/ollama_agent/state/ast_summarizer.rb +167 -0
- data/lib/ollama_agent/state/git_changed_paths.rb +22 -0
- data/lib/ollama_agent/state/reconciler.rb +29 -0
- data/lib/ollama_agent/state/reentry_packet.rb +53 -0
- data/lib/ollama_agent/state/tree_digest.rb +20 -0
- data/lib/ollama_agent/state/workspace_fingerprint.rb +48 -0
- data/lib/ollama_agent/streaming/hooks.rb +3 -1
- data/lib/ollama_agent/synthesis/event_schema_registry.rb +98 -0
- data/lib/ollama_agent/synthesis/integration_extractor/concerns.rb +174 -0
- data/lib/ollama_agent/synthesis/integration_extractor.rb +106 -0
- data/lib/ollama_agent/synthesis/integration_scan.rb +8 -0
- data/lib/ollama_agent/synthesis/route_synthesizer.rb +58 -0
- data/lib/ollama_agent/synthesis/sidekiq_synthesizer.rb +24 -0
- data/lib/ollama_agent/think_param.rb +23 -1
- data/lib/ollama_agent/tool_arguments.rb +9 -0
- data/lib/ollama_agent/tool_runtime/supervisor.rb +111 -0
- data/lib/ollama_agent/tool_runtime/tool_registry.rb +52 -0
- data/lib/ollama_agent/tool_runtime.rb +4 -0
- data/lib/ollama_agent/tools/base.rb +106 -0
- data/lib/ollama_agent/tools/built_in_schemas.rb +234 -0
- data/lib/ollama_agent/tools/filesystem_explorer.rb +77 -0
- data/lib/ollama_agent/tools/git_tools.rb +176 -0
- data/lib/ollama_agent/tools/http_tools.rb +207 -0
- data/lib/ollama_agent/tools/memory_tools.rb +116 -0
- data/lib/ollama_agent/tools/safe_calculator.rb +203 -0
- data/lib/ollama_agent/tools/shell_tools.rb +257 -0
- data/lib/ollama_agent/tools_schema.rb +15 -144
- data/lib/ollama_agent/topology/class_node_merger.rb +54 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/concern_body.rb +45 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/ir_nodes_emitter.rb +65 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/mixin_dispatch.rb +101 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/navigation.rb +124 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/parameter_list.rb +71 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor/semantic_context.rb +40 -0
- data/lib/ollama_agent/topology/extractors/ruby_semantic_extractor.rb +67 -0
- data/lib/ollama_agent/topology/ir/callback_node.rb +38 -0
- data/lib/ollama_agent/topology/ir/class_node.rb +41 -0
- data/lib/ollama_agent/topology/ir/concern_node.rb +41 -0
- data/lib/ollama_agent/topology/ir/event_publisher_node.rb +38 -0
- data/lib/ollama_agent/topology/ir/module_node.rb +40 -0
- data/lib/ollama_agent/topology/ir/node.rb +30 -0
- data/lib/ollama_agent/topology/ir/route_node.rb +41 -0
- data/lib/ollama_agent/topology/ir/worker_node.rb +38 -0
- data/lib/ollama_agent/topology/linker/aggregate.rb +93 -0
- data/lib/ollama_agent/topology/linker/discovery.rb +33 -0
- data/lib/ollama_agent/topology/linker/extract.rb +35 -0
- data/lib/ollama_agent/topology/linker/link.rb +56 -0
- data/lib/ollama_agent/topology/linker/resolve.rb +42 -0
- data/lib/ollama_agent/topology/linker/validate.rb +97 -0
- data/lib/ollama_agent/topology/linker.rb +90 -0
- data/lib/ollama_agent/topology/signature_normalizer.rb +74 -0
- data/lib/ollama_agent/topology/staged_graph/symbol_ids.rb +111 -0
- data/lib/ollama_agent/topology/staged_graph.rb +115 -0
- data/lib/ollama_agent/topology/symbol_graph.rb +50 -0
- data/lib/ollama_agent/topology/symbol_identity.rb +42 -0
- data/lib/ollama_agent/topology/zeitwerk_inflector.rb +71 -0
- data/lib/ollama_agent/tui.rb +316 -0
- data/lib/ollama_agent/tui_slash_reader.rb +255 -0
- data/lib/ollama_agent/tui_user_prompt.rb +45 -0
- data/lib/ollama_agent/version.rb +1 -1
- data/lib/ollama_agent.rb +148 -3
- data/lib/tasks/docker_validator.rake +16 -0
- metadata +324 -6
- data/reproduce_429.rb +0 -40
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d56b99449761370899bf612059caed5b1d7f58e0f4495b71cee23409b5cfb14
|
|
4
|
+
data.tar.gz: 3944154608557316fcb1b6126a39a9e94d63e8cf5fb86b41e96875c229c9a74c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da1673330de3f111382ec58b124b5b37fa4b973b4bdba0a1931449a06fc54963b0f5af1887ba5515d6ebd9fc4b56469c70164ef3378e68dbcc9cb5ca6f0518dd
|
|
7
|
+
data.tar.gz: c880764ea78000b140118e542cd77e1b8d3a8d06c37ba79cdfe2966c5bde21fb5bd43af5485799ef5044f37cdb55e5eba33a27b12a3bd2701bd7dced1e9f0ca2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sessionId":"721fd992-6855-4945-b1c5-b7cef534bb84","pid":1585817,"procStart":"20606262","acquiredAt":1778253145677}
|
data/.env.example
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
# Example environment variables for OllamaAgent gem
|
|
2
|
+
#
|
|
3
|
+
# Dotenv precedence (highest first):
|
|
4
|
+
# 1. XDG global config: ~/.config/ollama_agent/.env (or $OLLAMA_AGENT_DOTENV_PATH)
|
|
5
|
+
# 2. Local project .env (loaded by ollama-client gem via Dotenv.overload)
|
|
6
|
+
# 3. Shell ENV
|
|
7
|
+
# To bypass the XDG global and use only the local project .env + shell ENV:
|
|
8
|
+
# OLLAMA_AGENT_USE_LOCAL_DOTENV=1
|
|
9
|
+
#
|
|
10
|
+
# Kernel runtime feature flag (see docs/USAGE.md):
|
|
11
|
+
# OLLAMA_AGENT_KERNEL=false # default — legacy tool path
|
|
12
|
+
# OLLAMA_AGENT_KERNEL=shadow # full saga FSM, no disk writes (observation)
|
|
13
|
+
# OLLAMA_AGENT_KERNEL=true # mutations route through saga + atomic mutator
|
|
14
|
+
#
|
|
15
|
+
# Docker validator opt-in (see docs/agile/docker_spec_activation.md):
|
|
16
|
+
# DOCKER_AVAILABLE=true
|
|
17
|
+
# OLLAMA_AGENT_VALIDATOR_IMAGE=ollama-agent-validator:dev
|
|
18
|
+
|
|
2
19
|
# Disable colored output (set to any value to respect https://no-color.org/)
|
|
3
20
|
NO_COLOR=
|
|
4
21
|
# Enable colored output (default: enabled). Set to "0" to disable.
|
|
@@ -11,8 +28,11 @@ OLLAMA_AGENT_THINKING_MARKDOWN=0
|
|
|
11
28
|
OLLAMA_BASE_URL=https://ollama.com
|
|
12
29
|
# API key for Ollama (if required)
|
|
13
30
|
OLLAMA_API_KEY=your_api_key_here
|
|
14
|
-
# Think parameter: true/false/high/medium/low (default: true)
|
|
31
|
+
# Think parameter: true/false/high/medium/low (default: true). gpt-oss ignores booleans in the API;
|
|
32
|
+
# when think resolves to true, we send low|medium|high (default medium, override below).
|
|
15
33
|
OLLAMA_AGENT_THINK=1
|
|
34
|
+
# gpt-oss only: low, medium, or high (used when OLLAMA_AGENT_THINK is true)
|
|
35
|
+
# OLLAMA_AGENT_GPT_OSS_THINK=medium
|
|
16
36
|
# Root directory for the agent (default: current working directory)
|
|
17
37
|
OLLAMA_AGENT_ROOT=.
|
|
18
38
|
# Debug mode (set to "1" for verbose output)
|
data/CHANGELOG.md
CHANGED
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.0.1] - 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Tool `list_directory_contents`** (`OllamaAgent::Tools::FilesystemExplorer`) — inspect files and subdirectories inside the current workspace. All paths are resolved relative to the project root (`context[:root]` / `OLLAMA_AGENT_ROOT`); traversal outside that boundary (including `../../etc` and absolute paths) is rejected before the filesystem is touched. Returns `[DIR]` / `[FILE]` entries with byte sizes.
|
|
8
|
+
- **Tool `calculate`** (`OllamaAgent::Tools::SafeCalculator`) — evaluate an arithmetic expression using a hand-written **Shunting-yard** tokenizer and RPN evaluator. Supports `+`, `-`, `*`, `/`, `**` (right-associative), parentheses, and unary `+`/`-`. **No `eval` is used at any point.** Right-associativity of `**` is correct: `2 ** 3 ** 2` → `512`. Division by zero returns a non-finite message rather than raising.
|
|
9
|
+
- Both tools are available in **all permission profiles** (`read_only`, `standard`, `developer`, `full`), registered in `CORE_TOOLS` so they appear in the Ollama tool schema automatically, and dispatched through the existing `SandboxedTools#execute_tool` loop.
|
|
10
|
+
- `examples/agentic_tool_calling.rb` — runnable demo covering filesystem inspection, arithmetic evaluation, and a combined prompt that chains both tools. Mirrors the KDnuggets *Easy Agentic Tool Calling with Gemma 4* article pattern, adapted to the `OllamaAgent` Ruby runtime.
|
|
11
|
+
- `docs/TOOLS.md` — new **Built-in agentic tools** section documenting `list_directory_contents` and `calculate` with Ruby API examples.
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
|
|
15
|
+
- **`trading_agent` extraction**: Removed the nested `trading_agent/` project/gem from the `ollama_agent` repository to a dedicated standalone sibling repository (`trading_agent`).
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
|
|
19
|
+
- **README:** New **Reasoning / thinking output** section—how to set `think` (including **GPT-OSS** `low`/`medium`/`high`), streaming vs one-shot, display env vars, troubleshooting when **Thinking** is missing, Gemma-style tags, and **`Runner.build`** example. **`OLLAMA_AGENT_STREAM`** and GPT-OSS notes added to the environment table; Ollama Cloud example sets **`OLLAMA_AGENT_THINK`**.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **RuboCop and Style Cleanups**: Fixed 424 RuboCop offenses and refined `.rubocop.yml` parameters.
|
|
24
|
+
- **CI/CD Correction**: Removed obsolete nested `trading_agent` job from CI/CD main workflow.
|
|
25
|
+
- **Thinking display:** Coerce non-string `message.thinking` from the API (e.g. array-shaped chunks) before deciding whether reasoning is present (`GemmaThoughtContentParser.merge_into_message_data!` + `ChatStreamThinkingFormat`). After a **streaming** chat completion, run the same merge so content-embedded reasoning tags still split into **Thinking** / **Assistant**.
|
|
26
|
+
|
|
27
|
+
## [1.0.0] - 2026-04-11
|
|
28
|
+
|
|
29
|
+
First **stable** release under [Semantic Versioning](https://semver.org/): within the **`1.x`** series, the documented public Ruby API and CLI behavior are intended to remain **backwards compatible** except where called out in the changelog.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **CLI default:** `ollama_agent` with no subcommand runs **`ask`** with the **interactive TUI** when no query is given (same as `ollama_agent ask` with no query). Use **`ask -i` without `--tui`** for the plain line REPL, **`ask "…"`** for a one-shot task, or another subcommand (`self_review`, `sessions`, …) for other workflows.
|
|
34
|
+
|
|
35
|
+
### Breaking changes (from 0.3.x)
|
|
36
|
+
|
|
37
|
+
- **`tty-spinner` removed** from the gem; **`OllamaAgent::TUI`** no longer exposes `with_spinner`, `dismiss_progress_spinner`, `pause_progress_for_user_prompt`, or `resume_progress_after_user_prompt`. Code that called those methods or relied on the transitive `tty-spinner` dependency must be updated.
|
|
38
|
+
- **`Agent#chat_assistant_message`** uses the streaming HTTP path **only** when something subscribes to **`on_token`** (not merely **`on_thinking`**). Integrations that registered only `on_thinking` expecting streamed chat must also subscribe to `on_token` or use another supported hook.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- TUI slash-command tab completion no longer raises `FrozenError` when editing a completed frozen candidate (e.g. `/help`).
|
|
43
|
+
|
|
3
44
|
## [0.3.0] - 2026-04-06
|
|
4
45
|
|
|
5
46
|
### Added
|
|
47
|
+
|
|
6
48
|
- `ToolRuntime` — JSON plan loop for custom tools (`OllamaJsonPlanner`, registry, executor); see `docs/TOOL_RUNTIME.md`
|
|
7
49
|
- Optional **ruby_mastery** context for `self_review` / `improve` (`OLLAMA_AGENT_RUBY_MASTERY`, `--no-ruby-mastery`)
|
|
8
50
|
- `OllamaAgent::ModelEnv` — shared model name resolution from environment
|
|
@@ -11,14 +53,17 @@
|
|
|
11
53
|
- External agents / argv expansion and related orchestration refinements
|
|
12
54
|
|
|
13
55
|
### Changed
|
|
56
|
+
|
|
14
57
|
- `SearchBackend` finds `rg` / `grep` by scanning `PATH` (avoids relying on a `command` executable on trimmed `PATH`)
|
|
15
58
|
|
|
16
59
|
### Fixed
|
|
60
|
+
|
|
17
61
|
- `SelfImprovement::Improver#run` accepts `max_tokens` and `context_summarize` from the CLI (Ruby 3 keyword compatibility)
|
|
18
62
|
|
|
19
63
|
## [0.2.0] - 2026-03-26
|
|
20
64
|
|
|
21
65
|
### Added
|
|
66
|
+
|
|
22
67
|
- `write_file` tool — create or overwrite files (complements `edit_file` for surgical diffs)
|
|
23
68
|
- `OllamaAgent::Tools.register` — extensible tool registry for library consumers
|
|
24
69
|
- `Streaming::Hooks` — event bus (`on_token`, `on_tool_call`, `on_tool_result`, `on_complete`, `on_error`, `on_retry`)
|
|
@@ -32,10 +77,12 @@
|
|
|
32
77
|
- `docs/ARCHITECTURE.md`, `docs/TOOLS.md`, `docs/SESSIONS.md`
|
|
33
78
|
|
|
34
79
|
### Changed
|
|
80
|
+
|
|
35
81
|
- `READ_ONLY_TOOLS` now excludes both `edit_file` and `write_file`
|
|
36
82
|
- `Agent` now exposes `#hooks` (`Streaming::Hooks`) and `#session_id`
|
|
37
83
|
|
|
38
84
|
### New environment variables
|
|
85
|
+
|
|
39
86
|
- `OLLAMA_AGENT_STREAM`, `OLLAMA_AGENT_MAX_TOKENS`
|
|
40
87
|
- `OLLAMA_AGENT_MAX_RETRIES`, `OLLAMA_AGENT_RETRY_BASE_DELAY`
|
|
41
88
|
- `OLLAMA_AGENT_AUDIT`, `OLLAMA_AGENT_AUDIT_LOG_PATH`
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Tests
|
|
4
|
+
|
|
5
|
+
- Run **`bundle exec rspec`** before opening a PR.
|
|
6
|
+
- Prefer **behavior-focused** examples; stub external binaries (`patch`, `rg`) when asserting failure paths.
|
|
7
|
+
- Add or extend specs when you change the agent loop, tool schemas, sandbox, or budget/loop detection.
|
|
8
|
+
|
|
9
|
+
## Style
|
|
10
|
+
|
|
11
|
+
- Run **`bundle exec rubocop`**. The repository is moving toward a clean full-tree baseline; CI currently runs RuboCop with **`continue-on-error: true`** until legacy offenses are cleared.
|
|
12
|
+
- Add **`# frozen_string_literal: true`** to new Ruby files.
|
|
13
|
+
|
|
14
|
+
## Error handling
|
|
15
|
+
|
|
16
|
+
- Do **not** use **`rescue Exception`** (it catches `Interrupt` / `SignalException`). Rescue **`StandardError`** (or narrower types) and either re-raise, wrap in **`OllamaAgent::Error`**, or log and return a safe value—never swallow signals.
|
|
17
|
+
|
|
18
|
+
## Architecture notes
|
|
19
|
+
|
|
20
|
+
- **Tools:** Prefer **`OllamaAgent::Tools::BuiltInSchemas.register`** for new first-party tool schemas instead of hard-coding branches in unrelated modules.
|
|
21
|
+
- **Logging:** Use the agent’s **`Logger`** (or `OllamaAgent::Agent`’s `logger` reader) instead of bare **`warn`** for user-relevant messages so embedders can stub or redirect output.
|
|
22
|
+
|
|
23
|
+
Thank you for helping improve `ollama_agent`.
|
data/README.md
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
# ollama_agent
|
|
2
2
|
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
|
|
5
5
|
Ruby gem that runs a **CLI coding agent** against a local [Ollama](https://ollama.com) model. It exposes tools to **list files**, **read files**, **search the tree** (ripgrep or grep), and **apply unified diffs** so the model can make small, reviewable edits.
|
|
6
6
|
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Kernel runtime (deterministic execution)](#kernel-runtime-deterministic-execution) — see also [CAPABILITIES](docs/CAPABILITIES.md), [CLI](docs/CLI.md), [OPERATIONS](docs/OPERATIONS.md), [USAGE](docs/USAGE.md)
|
|
11
|
+
- [Requirements](#requirements)
|
|
12
|
+
- [Security and sandbox](#security-and-sandbox)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Usage](#usage)
|
|
15
|
+
- [Agentic tool calling](#agentic-tool-calling-local-environment-tools)
|
|
16
|
+
- [Skills](#skills-deterministic-json-contract-pipelines)
|
|
17
|
+
- [Troubleshooting](#troubleshooting)
|
|
18
|
+
- [How it works](#how-it-works)
|
|
19
|
+
- [Development](#development)
|
|
20
|
+
- [License](#license)
|
|
21
|
+
|
|
7
22
|
## Features
|
|
8
23
|
|
|
9
24
|
- Tool `list_files` – list project files.
|
|
10
25
|
- Tool `read_file` – read file contents.
|
|
11
26
|
- Tool `search_code` – search code with ripgrep or grep.
|
|
12
27
|
- Tool `edit_file` – apply unified diffs safely.
|
|
28
|
+
- Tool `list_directory_contents` – sandboxed filesystem inspection; see [Agentic tool calling](#agentic-tool-calling-local-environment-tools).
|
|
29
|
+
- Tool `calculate` – safe arithmetic evaluator (Shunting-yard, no `eval`); see [Agentic tool calling](#agentic-tool-calling-local-environment-tools).
|
|
13
30
|
- CLI built with Thor, entry point `exe/ollama_agent`.
|
|
14
31
|
- **`self_review`** – self-review / improvement with a **`--mode`**:
|
|
15
32
|
- **`analysis`** (default, alias `1`) — read-only tools; report only; no writes.
|
|
@@ -19,9 +36,34 @@ Ruby gem that runs a **CLI coding agent** against a local [Ollama](https://ollam
|
|
|
19
36
|
- **`orchestrate`** / **`OLLAMA_AGENT_ORCHESTRATOR=1`** — optional **orchestrator** tools to probe and delegate to other local CLI agents (see [Orchestrator](#orchestrator-external-cli-agents)); **`agents`** lists availability.
|
|
20
37
|
- **Ruby API** — embed **`Runner`**, **`Agent`**, custom tools, hooks, sessions, and (optionally) **`ToolRuntime`**; see [Library usage (Ruby)](#library-usage-ruby).
|
|
21
38
|
|
|
39
|
+
## Kernel runtime (deterministic execution)
|
|
40
|
+
|
|
41
|
+
**Documentation (post-kernel):** [Capability matrix](docs/CAPABILITIES.md) · [CLI reference](docs/CLI.md) · [Operations / incidents](docs/OPERATIONS.md) · [Usage guide](docs/USAGE.md).
|
|
42
|
+
|
|
43
|
+
The **runtime kernel** is an optional execution layer behind `OLLAMA_AGENT_KERNEL`. It wraps file mutations in a **saga-style finite state machine**: intent reservation, **atomic writes** (CAS + pre-image hashes), ownership checks against compiled rules, **SQLite-backed WAL** and sagas, isolated post-mutation validation, and compensation on failure. The workspace root remains the **trust boundary**; the kernel adds structured **ownership** and **fencing** so replays and automation stay auditable. When cloud or validator paths fail, **circuit-breaker style** escalation limits (see the rollout runbook) keep bad states from compounding.
|
|
44
|
+
|
|
45
|
+
| `OLLAMA_AGENT_KERNEL` | Behavior |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| unset / `false` (default) | Legacy tool paths; kernel pipeline is not used for tool routing. |
|
|
48
|
+
| `shadow` | Same routing as `true`, but the pipeline runs in **shadow** mode: saga + WAL + observability run, while workspace bytes for certain mutations stay off the “real” path (see runbook). |
|
|
49
|
+
| `true` / `1` | Tool intents for configured mutation tools go through **`OllamaAgent::Runtime::KernelPipeline`**. |
|
|
50
|
+
|
|
51
|
+
**Quick start (kernel on):**
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
OLLAMA_AGENT_KERNEL=true bundle exec ollama_agent ask "Your task"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Design notes and roadmap items live in **`docs/new_features_plan_v2.md`**. Operational rollout, shadow mode, and rollback expectations are in **`docs/agile/release_rollout_runbook.md`** (incident SQL, health JSON, and compaction details are expanded in **`docs/OPERATIONS.md`**). For **E7 validator activation** (Docker-backed isolated checks), see **`docs/agile/docker_spec_activation.md`**.
|
|
58
|
+
|
|
59
|
+
**Compaction and disk bounds:** long-lived workspaces accumulate kernel SQLite rows and content-addressed blobs. Use **`OllamaAgent::Runtime::Compactor`** (logical `current_epoch` only — no wall clock) to prune sealed sagas, cold-archive old WAL rows into `event_store_archive.db`, purge expired recovery leases and stale intent reservations, and unlink blob files not referenced by compensations or in-flight mutation WAL payloads. **`OllamaAgent::Runtime::CompactorRunner`** wraps the compactor with an epoch interval for daemon loops (opt-in; nothing starts automatically).
|
|
60
|
+
|
|
61
|
+
**Permission unification:** when `OLLAMA_AGENT_KERNEL` is on and `config/ollama_agent/owners.yml` exists, **`OllamaAgent::Runtime::PermissionBridge`** reconciles legacy **`Runtime::Permissions` / `Runtime::Policies`** with **`Security::OwnershipIndex`** + **`CriticalityPolicy`** before pipeline execution. On divergence the bridge logs and **prefers the kernel decision** (stricter path wins). `OllamaAgent::PermissionConflictError` is raised only by the strict `#allow_mutation?` API for tests and diagnostics. With the kernel **off**, only the legacy permission path runs (no bridge).
|
|
62
|
+
|
|
22
63
|
## Requirements
|
|
23
64
|
|
|
24
65
|
- Ruby ≥ 3.2 (enforced in the gemspec as `required_ruby_version`)
|
|
66
|
+
- **Runtime kernel (SQLite):** the **sqlite3** gem is a runtime dependency; kernel storage uses `event_store.db` and `runtime.db` under `.ollama_agent/kernel/` in the configured project root.
|
|
25
67
|
- **Local:** Ollama running and a capable tool-calling model, **or**
|
|
26
68
|
- **Ollama Cloud:** API key and a cloud-capable model name (see below)
|
|
27
69
|
|
|
@@ -30,6 +72,15 @@ Ruby gem that runs a **CLI coding agent** against a local [Ollama](https://ollam
|
|
|
30
72
|
- **`patch`** — required for `edit_file` (GNU `patch` on `PATH`). On Windows, use Git Bash, WSL, GnuWin32, or another environment that provides `patch`.
|
|
31
73
|
- **`rg` (ripgrep) or `grep`** — text mode for `search_code` needs at least one of these on `PATH` (ripgrep is preferred when present).
|
|
32
74
|
|
|
75
|
+
## Security and sandbox
|
|
76
|
+
|
|
77
|
+
- **Project root** — File tools and search are constrained to the configured workspace (`--root` / `OLLAMA_AGENT_ROOT`). Treat that directory as the trust boundary: only aim the agent at trees you are willing to modify.
|
|
78
|
+
- **`list_directory_contents`** — Paths are resolved with `File.expand_path` relative to the project root and rejected before the filesystem is touched if they escape that boundary. `../../etc`, `/etc`, and any other traversal are caught by a prefix check, not a regex.
|
|
79
|
+
- **`calculate`** — Uses a hand-written tokenizer and Shunting-yard evaluator. `eval` is never called. Only numeric literals and the operators `+`, `-`, `*`, `/`, `**` are accepted; any other character is an error.
|
|
80
|
+
- **`run_shell` (optional tool)** — Commands are parsed into an argument vector (no shell) and must match an allowlist; a denylist blocks obviously dangerous patterns. You can still shoot yourself in the foot with an allowed prefix (for example `git` with destructive subcommands), so keep profiles and permissions tight in automated setups.
|
|
81
|
+
- **Timeouts** — Text search honors `OLLAMA_AGENT_SEARCH_TIMEOUT_SEC` (default 120). Shell execution has its own per-invocation timeout.
|
|
82
|
+
- **Logging** — Budget, loop-detection, and `list_local_model_names` failures go through Ruby’s `Logger` (stderr by default). Set `OLLAMA_AGENT_LOG_LEVEL=debug` or `OLLAMA_AGENT_DEBUG=1` for more detail.
|
|
83
|
+
|
|
33
84
|
## Installation
|
|
34
85
|
|
|
35
86
|
From RubyGems (when published) or from this repository:
|
|
@@ -40,6 +91,16 @@ bundle install
|
|
|
40
91
|
|
|
41
92
|
## Usage
|
|
42
93
|
|
|
94
|
+
**Default:** run the gem with **no subcommand** to open the **interactive TUI** (same as `ask` with no query):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
ollama_agent
|
|
98
|
+
# or from this repo:
|
|
99
|
+
bundle exec ruby exe/ollama_agent
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Other entry points are **opt-in**: pass a **subcommand** (`self_review`, `sessions`, …) or **`ask` / `orchestrate`** with a **query** for a one-shot task, or flags for a plain line REPL (see below).
|
|
103
|
+
|
|
43
104
|
From the project you want the agent to modify (set the working directory accordingly):
|
|
44
105
|
|
|
45
106
|
```bash
|
|
@@ -63,10 +124,26 @@ Long-running models (slow local inference):
|
|
|
63
124
|
bundle exec ruby exe/ollama_agent ask --timeout 300 "Your task"
|
|
64
125
|
```
|
|
65
126
|
|
|
66
|
-
|
|
127
|
+
### Agent budget (steps, tokens, cost)
|
|
128
|
+
|
|
129
|
+
Each **model round-trip** that runs during a session counts as one **step** toward `OLLAMA_AGENT_MAX_TURNS` (default **64**), enforced together with token and optional cost limits in `OllamaAgent::Core::Budget`. Exploratory tasks that **list, read, and search** across a **large repository** can burn through steps quickly; if you see `budget exceeded — step limit (64)`, raise the limit—for example:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
export OLLAMA_AGENT_MAX_TURNS=128
|
|
133
|
+
bundle exec ruby exe/ollama_agent ask "Your wide-ranging task"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Narrower prompts, **`--read-only`**, or a smaller `--root` also reduce step usage. With **`OLLAMA_AGENT_DEBUG=1`**, the agent prints an extra hint when the **maximum tool rounds** for a run are reached.
|
|
137
|
+
|
|
138
|
+
### `search_code` and regex patterns
|
|
139
|
+
|
|
140
|
+
In **text** mode, the tool passes your pattern to **ripgrep** (or **grep**). Patterns are **regular expressions**: literal parentheses, brackets, and unbalanced groups can trigger errors (for example `unclosed group`). Escape metacharacters or use **fixed-string** mode when your tool schema exposes it.
|
|
141
|
+
|
|
142
|
+
**Plain line REPL** (no TUI boxes / markdown shell): use **`ask` (or `orchestrate`) with `-i` and without `--tui`**—for example when you omit the query you must opt out of the default TUI this way:
|
|
67
143
|
|
|
68
144
|
```bash
|
|
69
145
|
bundle exec ruby exe/ollama_agent ask --interactive
|
|
146
|
+
# same idea: explicit -i, no --tui
|
|
70
147
|
```
|
|
71
148
|
|
|
72
149
|
Self-review modes (default project root is the **current working directory** unless you set `--root` or `OLLAMA_AGENT_ROOT`):
|
|
@@ -90,19 +167,62 @@ bundle exec ruby exe/ollama_agent improve --apply
|
|
|
90
167
|
|
|
91
168
|
For mode 3, `-y` skips all patch prompts; `--no-semi` prompts for every patch when not using `-y`.
|
|
92
169
|
|
|
93
|
-
|
|
170
|
+
### Reasoning / thinking output
|
|
171
|
+
|
|
172
|
+
On [thinking-capable models](https://docs.ollama.com/capabilities/thinking), Ollama can return **reasoning** separately from the final answer (`message.thinking` vs `message.content`). The CLI labels them **Thinking** (dim) and **Assistant** (green / Markdown).
|
|
173
|
+
|
|
174
|
+
#### Enable `think` on the request
|
|
175
|
+
|
|
176
|
+
The agent sends Ollama’s `think` field only when you set it (CLI or env). If you omit it, the server uses its own defaults—and some models then omit or change reasoning in the response.
|
|
177
|
+
|
|
178
|
+
| You want | CLI | Environment |
|
|
179
|
+
|----------|-----|-------------|
|
|
180
|
+
| Reasoning on (typical Qwen / DeepSeek-style) | `--think true` | `OLLAMA_AGENT_THINK=true` or `1` |
|
|
181
|
+
| Reasoning off | `--think false` | `OLLAMA_AGENT_THINK=false` or `0` |
|
|
182
|
+
| **GPT-OSS** style levels | `--think low`, `medium`, or `high` | `OLLAMA_AGENT_THINK=medium` (example) |
|
|
183
|
+
|
|
184
|
+
Examples:
|
|
94
185
|
|
|
95
186
|
```bash
|
|
96
187
|
OLLAMA_AGENT_THINK=true bundle exec ruby exe/ollama_agent ask -i
|
|
97
|
-
# or
|
|
98
188
|
bundle exec ruby exe/ollama_agent ask -i --think true
|
|
189
|
+
# GPT-OSS: prefer a level, not only true/false
|
|
190
|
+
bundle exec ruby exe/ollama_agent ask --think medium "Your task"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### Streaming vs one-shot (default)
|
|
194
|
+
|
|
195
|
+
| Mode | Flags | What you see |
|
|
196
|
+
|------|--------|----------------|
|
|
197
|
+
| **One-shot** (default) | neither `--stream` nor `OLLAMA_AGENT_STREAM=1` | Each model round completes over HTTP; **Thinking** / **Assistant** are printed from the assembled **`message`** (including Gemma-style reasoning tags stripped from `content` when the API omits `thinking`). |
|
|
198
|
+
| **Streaming** | `--stream` or `OLLAMA_AGENT_STREAM=1` | Reasoning streams in **dim** text under one **Thinking** line, then **Assistant** and the reply stream—similar to Cursor. Uses `hooks[:on_thinking]` on the ollama-client chat stream (see `OllamaAgent::OllamaChatThinkingStreamPatch`). |
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
OLLAMA_AGENT_THINK=medium OLLAMA_AGENT_STREAM=1 bundle exec ruby exe/ollama_agent ask "Your task"
|
|
99
202
|
```
|
|
100
203
|
|
|
101
|
-
|
|
204
|
+
**Note:** Subscribing only to `on_thinking` does **not** enable the streaming chat path; the agent uses streaming when something listens for **`on_token`** (the console streamer registers both). See CHANGELOG **1.0.0** if you embed the library.
|
|
102
205
|
|
|
103
|
-
|
|
206
|
+
#### Display style (TTY)
|
|
104
207
|
|
|
105
|
-
|
|
208
|
+
By default **`OLLAMA_AGENT_THINKING_STYLE=compact`**: one **Thinking** header per `ask` run; later reasoning chunks in the same run are separated by **blank lines** only (including after tool rounds). **`OLLAMA_AGENT_THINKING_STYLE=framed`** repeats the full boxed banner per message. Thinking body is **plain dim** unless **`OLLAMA_AGENT_THINKING_MARKDOWN=1`**.
|
|
209
|
+
|
|
210
|
+
The CLI uses **ANSI colors** on a TTY (banner, prompt, patch prompts). **Assistant** replies use **Markdown** via `tty-markdown` when stdout is a TTY and **`NO_COLOR`** is unset. Disable Markdown with **`OLLAMA_AGENT_MARKDOWN=0`**; disable colors with **`NO_COLOR`** or **`OLLAMA_AGENT_COLOR=0`**.
|
|
211
|
+
|
|
212
|
+
#### If you see no **Thinking** block
|
|
213
|
+
|
|
214
|
+
1. **Set `think` explicitly**—especially for **GPT-OSS** (`low` / `medium` / `high`).
|
|
215
|
+
2. **Confirm the model returns `message.thinking`** (e.g. `curl` / `ollama` CLI against `/api/chat` with the same `think` value). If the API never sends `thinking`, the agent has nothing to show.
|
|
216
|
+
3. **Try streaming** (`--stream` or `OLLAMA_AGENT_STREAM=1`) if you want live reasoning tokens.
|
|
217
|
+
4. **Embedded reasoning in `content`:** Some templates (e.g. Gemma) put tags such as `<|channel>thought` … `<channel|>` or `<redacted_thinking>` … `</redacted_thinking>` inside `content`. The agent strips those into **Thinking** when present (`OllamaAgent::GemmaThoughtContentParser`). If your model uses different delimiters, reasoning may stay inside the main reply until parsers are extended.
|
|
218
|
+
|
|
219
|
+
#### Ruby API
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
OllamaAgent::Runner.build(stream: true, think: "medium").run("Your task")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Custom subscribers can attach to **`hooks[:on_thinking]`** and **`hooks[:on_token]`** on the same **`Runner`** instance (see `OllamaAgent::Streaming::Hooks`).
|
|
106
226
|
|
|
107
227
|
### Ollama Cloud
|
|
108
228
|
|
|
@@ -115,9 +235,63 @@ With **`--stream`** / **`OLLAMA_AGENT_STREAM=1`**, reasoning streams in **dim**
|
|
|
115
235
|
export OLLAMA_BASE_URL="https://ollama.com"
|
|
116
236
|
export OLLAMA_API_KEY="your_key"
|
|
117
237
|
export OLLAMA_AGENT_MODEL="gpt-oss:120b-cloud" # example; pick a cloud model from `ollama list` / the catalog
|
|
238
|
+
# Reasoning for GPT-OSS: set a level (see "Reasoning / thinking output" above)
|
|
239
|
+
export OLLAMA_AGENT_THINK=medium
|
|
240
|
+
bundle exec ruby exe/ollama_agent ask "Your task"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### Multi-Key Provider Credential Orchestration & Failover
|
|
244
|
+
|
|
245
|
+
To handle rate limits (RPM/TPM window exhaustion), daily quotas, or network timeouts when using Ollama Cloud (or other providers like OpenAI and Anthropic), you can configure a thread-safe, quota-aware **Credential Pool** with automatic reactive failover.
|
|
246
|
+
|
|
247
|
+
The pool can be configured dynamically via the Ruby API or auto-detected from environment variables.
|
|
248
|
+
|
|
249
|
+
##### Environment Auto-Detection
|
|
250
|
+
|
|
251
|
+
If no explicit credentials are passed in, `ollama_agent` automatically scans the environment for keys indexed `1` to `5` and initializes a `CredentialPool`:
|
|
252
|
+
|
|
253
|
+
* **Ollama Cloud**: Configure keys `OLLAMA_API_KEY_1` through `OLLAMA_API_KEY_5`. When any of these are present, requests are routed to `"https://api.ollama.com"` (aliased as `"ollama_cloud"`).
|
|
254
|
+
* **OpenAI**: Configure keys `OPENAI_API_KEY_1` through `OPENAI_API_KEY_5`.
|
|
255
|
+
* **Anthropic**: Configure keys `ANTHROPIC_API_KEY_1` through `ANTHROPIC_API_KEY_5`.
|
|
256
|
+
|
|
257
|
+
Example for Ollama Cloud:
|
|
258
|
+
```bash
|
|
259
|
+
export OLLAMA_API_KEY_1="ollama_key_abc123"
|
|
260
|
+
export OLLAMA_API_KEY_2="ollama_key_def456"
|
|
118
261
|
bundle exec ruby exe/ollama_agent ask "Your task"
|
|
119
262
|
```
|
|
120
263
|
|
|
264
|
+
##### Ruby API Configuration
|
|
265
|
+
|
|
266
|
+
You can also pass a structured array of credential hashes to `OllamaAgent::Runner.build`:
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
runner = OllamaAgent::Runner.build(
|
|
270
|
+
credentials: [
|
|
271
|
+
{
|
|
272
|
+
id: "ollama-cloud-primary",
|
|
273
|
+
provider: "ollama_cloud",
|
|
274
|
+
api_key: "ollama_...",
|
|
275
|
+
weight: 2, # weighted round-robin priority (default: 1)
|
|
276
|
+
limits: { rpm: 10, tpm: 10000, daily_tokens: 1000000 } # automatic quota tracking
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "openai-backup",
|
|
280
|
+
provider: "openai",
|
|
281
|
+
api_key: "sk-...",
|
|
282
|
+
weight: 1
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
)
|
|
286
|
+
runner.run("Your task")
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
##### Failover Behavior
|
|
290
|
+
1. **Weighted Round-Robin**: Requests are balanced across healthy and available credentials.
|
|
291
|
+
2. **Quota Tracking**: Daily token/request and RPM/TPM sliding windows are tracked locally.
|
|
292
|
+
3. **Reactive Failover**: If a key encounters a rate limit (`HTTP 429`), temporary provider error (`HTTP 5xx`), or quota exhaustion, it is temporarily cooled down and the request is retried with the next available key.
|
|
293
|
+
4. **Permanent Disabling**: If a key encounters an authentication failure (`HTTP 401` or `HTTP 403`), it is permanently disabled to prevent dead-key hammering.
|
|
294
|
+
|
|
121
295
|
### Environment
|
|
122
296
|
|
|
123
297
|
| Variable | Purpose |
|
|
@@ -136,7 +310,8 @@ bundle exec ruby exe/ollama_agent ask "Your task"
|
|
|
136
310
|
| `OLLAMA_AGENT_MARKDOWN` | Set to `0` to disable Markdown formatting of assistant replies (plain text only) |
|
|
137
311
|
| `OLLAMA_AGENT_THINKING_STYLE` | `compact` (default) = one **Thinking** label per run, blank lines between later reasoning chunks; `framed` = repeat full banner/rulers each message |
|
|
138
312
|
| `OLLAMA_AGENT_THINKING_MARKDOWN` | Set to `1` to render **thinking** text with Markdown (muted); default is plain dim text |
|
|
139
|
-
| `
|
|
313
|
+
| `OLLAMA_AGENT_STREAM` | Set to `1` to stream tokens and reasoning to stdout (same as CLI **`--stream`** on `ask` / `self_review` / `improve`). |
|
|
314
|
+
| `OLLAMA_AGENT_THINK` | Model **thinking** mode for compatible models: `true` / `false`, or `high` / `medium` / `low` (see ollama-client `think:`). Empty = omit (server default). **GPT-OSS:** use `low` / `medium` / `high`. |
|
|
140
315
|
| `OLLAMA_AGENT_PATCH_RISK_MAX_DIFF_LINES` | Max changed-line count before a diff is treated as "large" for semi-auto patch risk (default **80**) |
|
|
141
316
|
| `OLLAMA_AGENT_INDEX_REBUILD` | Set to `1` to drop the cached Prism Ruby index before the next symbol search in this process |
|
|
142
317
|
| `OLLAMA_AGENT_RUBY_INDEX_MAX_FILES` | Max `.rb` files to parse per index build (default **5000**) |
|
|
@@ -178,6 +353,59 @@ Use the **`orchestrate`** command (or **`OLLAMA_AGENT_ORCHESTRATOR=1`** with **`
|
|
|
178
353
|
- Adjust **`argv` / `version_argv`** in YAML to match your real CLI (vendor flags differ). If a tool has no stable non-interactive mode, do not expose it in the registry.
|
|
179
354
|
- Tool contract version: **`OllamaAgent::ORCHESTRATOR_TOOLS_SCHEMA_VERSION`**.
|
|
180
355
|
|
|
356
|
+
### Agentic tool calling (local environment tools)
|
|
357
|
+
|
|
358
|
+
Two built-in tools let the model observe its environment and compute precisely — the pattern described in [Easy Agentic Tool Calling with Gemma 4](https://www.kdnuggets.com/easy-agentic-tool-calling-with-gemma-4) — adapted here for the Ruby runtime.
|
|
359
|
+
|
|
360
|
+
#### `list_directory_contents`
|
|
361
|
+
|
|
362
|
+
Lists files and subdirectories inside the current workspace. The model decides when to inspect the environment rather than guessing at what exists.
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
bundle exec ruby exe/ollama_agent ask \
|
|
366
|
+
"What scripts are in the current folder, and which one looks like it handles CSV processing?"
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
All paths are sandboxed to `OLLAMA_AGENT_ROOT`. Traversal attempts (`../../etc`, absolute paths) are rejected before the filesystem is touched.
|
|
370
|
+
|
|
371
|
+
#### `calculate`
|
|
372
|
+
|
|
373
|
+
Evaluates an arithmetic expression using a Shunting-yard parser. The model offloads precision arithmetic instead of computing in its weights.
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
bundle exec ruby exe/ollama_agent ask \
|
|
377
|
+
"What is the standard deviation of 12, 18, 23, 29, 31, 35, 44, 47 — compute it step by step using the formula."
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Supports `+`, `-`, `*`, `/`, `**` (right-associative), parentheses, and unary `+`/`-`. No `eval`.
|
|
381
|
+
|
|
382
|
+
#### Combining both tools
|
|
383
|
+
|
|
384
|
+
The model can chain the two tools in a single request — inspect the workspace first, then compute something about what it found:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
bundle exec ruby exe/ollama_agent ask \
|
|
388
|
+
"Look at the files in the current folder and tell me the total size in kilobytes, rounded to two decimal places."
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Internally: the model calls `list_directory_contents` to get byte sizes, then calls `calculate` with the sum and division by 1024.
|
|
392
|
+
|
|
393
|
+
#### Ruby API
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
require "ollama_agent"
|
|
397
|
+
|
|
398
|
+
runner = OllamaAgent::Runner.build(root: Dir.pwd)
|
|
399
|
+
|
|
400
|
+
# Filesystem inspection
|
|
401
|
+
puts runner.run("What files are in lib/ollama_agent/tools/?")
|
|
402
|
+
|
|
403
|
+
# Arithmetic
|
|
404
|
+
puts runner.run("What is (412 + 1834 + 10786 + 88 + 2210) / 1024, rounded to 2 decimal places?")
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
See `examples/agentic_tool_calling.rb` for a runnable end-to-end demo.
|
|
408
|
+
|
|
181
409
|
### Library usage (Ruby)
|
|
182
410
|
|
|
183
411
|
Most of this README is **CLI-first** (commands and environment variables above). The same capabilities exist as **Ruby APIs**—the [Features](#features) list (file tools, `self_review` / `improve`, orchestrator, skills, etc.) is implemented under `lib/ollama_agent/`. For a **layer diagram** (agent → tools → hooks → session), see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
@@ -236,6 +464,75 @@ last = OllamaAgent::ToolRuntime::Loop.new(
|
|
|
236
464
|
# last => e.g. { "status" => "done", "echo" => "bye" }
|
|
237
465
|
```
|
|
238
466
|
|
|
467
|
+
## Skills (deterministic JSON-contract pipelines)
|
|
468
|
+
|
|
469
|
+
Skills are single-purpose generators that bypass the tool-calling agent loop and
|
|
470
|
+
return **strict JSON** validated against a schema. They are meant for pipelines
|
|
471
|
+
that need predictable, parseable output — code review, refactoring suggestions,
|
|
472
|
+
performance audits, debugging triage — without the unpredictability of free-form
|
|
473
|
+
LLM prose.
|
|
474
|
+
|
|
475
|
+
Built-in skills:
|
|
476
|
+
|
|
477
|
+
- `architecture_refactor` — restructure code without changing behavior
|
|
478
|
+
- `performance_optimizer` — identify bottlenecks and emit optimized code
|
|
479
|
+
- `debug_engineer` — root-cause a bug and propose a fix
|
|
480
|
+
- `feature_builder` — design and implement a production-ready feature
|
|
481
|
+
|
|
482
|
+
Each skill:
|
|
483
|
+
|
|
484
|
+
1. Renders a deterministic prompt (LLM `temperature: 0` by default).
|
|
485
|
+
2. Extracts the first balanced JSON object from the response (tolerates prose
|
|
486
|
+
and ```` ```json ```` fences).
|
|
487
|
+
3. Validates against the skill's `SCHEMA` and raises `ContractError` on mismatch.
|
|
488
|
+
|
|
489
|
+
### CLI
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
# list registered skills
|
|
493
|
+
ollama_agent skill list
|
|
494
|
+
|
|
495
|
+
# run a single skill
|
|
496
|
+
ollama_agent skill run architecture_refactor --code-file lib/orders/manager.rb
|
|
497
|
+
|
|
498
|
+
# compose a pipeline; later skills receive earlier outputs merged in
|
|
499
|
+
ollama_agent skill pipeline architecture_refactor performance_optimizer \
|
|
500
|
+
--code-file lib/exit_management.rb
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Override the model with `--model`, `OLLAMA_AGENT_SKILL_MODEL`, or
|
|
504
|
+
`OLLAMA_AGENT_MODEL`.
|
|
505
|
+
|
|
506
|
+
### Ruby
|
|
507
|
+
|
|
508
|
+
```ruby
|
|
509
|
+
result = OllamaAgent::Skills::ArchitectureRefactorer.new.call(
|
|
510
|
+
code: File.read("lib/orders/manager.rb")
|
|
511
|
+
)
|
|
512
|
+
# => { folder_structure: [...], architecture_notes: "...", refactored_code: "..." }
|
|
513
|
+
|
|
514
|
+
OllamaAgent::Skills::Runner.new(
|
|
515
|
+
[:architecture_refactor, :performance_optimizer]
|
|
516
|
+
).call(code: File.read("lib/exit_management.rb"))
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Inject your own LLM client (anything responding to `#generate(prompt) → String`)
|
|
520
|
+
in tests:
|
|
521
|
+
|
|
522
|
+
```ruby
|
|
523
|
+
class FakeLlm
|
|
524
|
+
def generate(_prompt)
|
|
525
|
+
'{"bottlenecks": [], "optimizations": [], "optimized_code": "x"}'
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
OllamaAgent::Skills::PerformanceOptimizer.new(llm: FakeLlm.new).call(code: "...")
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
By default skills run against the local Ollama provider (local-first, auditable).
|
|
533
|
+
They go through `OllamaAgent::Providers::Registry`, so any registered provider
|
|
534
|
+
(OpenAI, Anthropic, custom) is usable by passing your own `LlmClient`.
|
|
535
|
+
|
|
239
536
|
## Troubleshooting
|
|
240
537
|
|
|
241
538
|
- **Use a tool-capable model** — Set `OLLAMA_AGENT_MODEL` to a model that supports function/tool calling (e.g. a recent coder-tuned variant). If the model only prints `{"name": "read_file", ...}` in plain text, tools never run unless you enable `OLLAMA_AGENT_PARSE_TOOL_JSON=1`.
|
|
@@ -256,6 +553,8 @@ bundle exec rspec
|
|
|
256
553
|
bundle exec rubocop
|
|
257
554
|
```
|
|
258
555
|
|
|
556
|
+
Ongoing refactors (contributors): the **`Agent`** class is a thin façade over **`TurnLoop`**, **`ChatCoordinator`**, session/client wiring, and **`Tools::BuiltInSchemas`** so new behavior should land in those collaborators instead of growing monolithic methods. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
557
|
+
|
|
259
558
|
### CI and RubyGems release
|
|
260
559
|
|
|
261
560
|
- **CI** — [`.github/workflows/main.yml`](.github/workflows/main.yml) runs **RSpec** and **RuboCop** on pushes to `main` / `master` and on pull requests (Ruby **3.3.4** and **3.2.0**).
|
|
@@ -271,7 +570,7 @@ Repository **secrets** (Settings → Secrets and variables → Actions):
|
|
|
271
570
|
Release steps:
|
|
272
571
|
|
|
273
572
|
1. Bump `OllamaAgent::VERSION` in `lib/ollama_agent/version.rb` and commit to `main`.
|
|
274
|
-
2. Tag: `git tag
|
|
573
|
+
2. Tag: `git tag v1.0.0` (must match the version string) and `git push origin v1.0.0`.
|
|
275
574
|
|
|
276
575
|
## License
|
|
277
576
|
|
data/Rakefile
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Example ownership graph for a typical Rails app (workspace-relative prefixes, no trailing slashes).
|
|
2
|
+
# Copy or extend for your repo; compile with OllamaAgent::Security::OwnershipCompiler.
|
|
3
|
+
|
|
4
|
+
version: 1
|
|
5
|
+
rules:
|
|
6
|
+
- prefix: app
|
|
7
|
+
owner: application
|
|
8
|
+
mutable_in_modes: [normal, replay, validation, dry_run]
|
|
9
|
+
criticality: routine
|
|
10
|
+
forbidden: false
|
|
11
|
+
children:
|
|
12
|
+
- prefix: app/models
|
|
13
|
+
owner: domain
|
|
14
|
+
mutable_in_modes: [normal, replay, validation]
|
|
15
|
+
criticality: sensitive
|
|
16
|
+
children: []
|
|
17
|
+
|
|
18
|
+
- prefix: config
|
|
19
|
+
owner: platform
|
|
20
|
+
mutable_in_modes: [normal, replay, validation, dry_run]
|
|
21
|
+
criticality: sensitive
|
|
22
|
+
children: []
|
|
23
|
+
|
|
24
|
+
- prefix: db/migrate
|
|
25
|
+
owner: data
|
|
26
|
+
mutable_in_modes: [normal, validation]
|
|
27
|
+
criticality: critical
|
|
28
|
+
children: []
|
|
29
|
+
|
|
30
|
+
- prefix: lib
|
|
31
|
+
owner: shared_libraries
|
|
32
|
+
mutable_in_modes: [normal, replay, validation, dry_run]
|
|
33
|
+
criticality: routine
|
|
34
|
+
children: []
|
|
35
|
+
|
|
36
|
+
- prefix: log
|
|
37
|
+
owner: observability
|
|
38
|
+
mutable_in_modes: [normal, dry_run]
|
|
39
|
+
criticality: routine
|
|
40
|
+
children: []
|
|
41
|
+
|
|
42
|
+
- prefix: tmp
|
|
43
|
+
owner: scratch
|
|
44
|
+
mutable_in_modes: [normal, dry_run]
|
|
45
|
+
criticality: routine
|
|
46
|
+
children: []
|
|
47
|
+
|
|
48
|
+
- prefix: .env
|
|
49
|
+
owner: secrets
|
|
50
|
+
mutable_in_modes: [normal, replay, validation, dry_run]
|
|
51
|
+
criticality: critical
|
|
52
|
+
forbidden: true
|
|
53
|
+
children: []
|