ollama_agent 1.0.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 +24 -0
- data/CONTRIBUTING.md +23 -0
- data/README.md +294 -6
- 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 +6 -2
- data/lib/ollama_agent/agent/chat_coordinator.rb +88 -0
- data/lib/ollama_agent/agent/prompt_wiring.rb +1 -1
- data/lib/ollama_agent/agent/session_wiring.rb +5 -9
- data/lib/ollama_agent/agent/turn_loop.rb +89 -0
- data/lib/ollama_agent/agent.rb +112 -120
- 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_shared.rb +137 -30
- data/lib/ollama_agent/cli/skill_command.rb +71 -0
- data/lib/ollama_agent/cli/tui_repl.rb +59 -6
- data/lib/ollama_agent/cli.rb +20 -4
- data/lib/ollama_agent/console.rb +2 -2
- data/lib/ollama_agent/context/token_counter.rb +5 -0
- data/lib/ollama_agent/core/budget.rb +2 -2
- data/lib/ollama_agent/core/loop_detector.rb +2 -2
- data/lib/ollama_agent/core/schema_validator.rb +11 -12
- data/lib/ollama_agent/core/trace_logger.rb +4 -2
- 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 +33 -5
- 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 +2 -2
- data/lib/ollama_agent/indexing/diff_summarizer.rb +8 -8
- data/lib/ollama_agent/indexing/file_indexer.rb +7 -7
- data/lib/ollama_agent/indexing/repo_scanner.rb +37 -37
- 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 +7 -3
- data/lib/ollama_agent/memory/manager.rb +1 -2
- data/lib/ollama_agent/ollama_chat_thinking_stream.rb +25 -0
- data/lib/ollama_agent/ollama_cloud_catalog.rb +23 -4
- data/lib/ollama_agent/ollama_connection.rb +19 -10
- data/lib/ollama_agent/plugins/registry.rb +6 -2
- data/lib/ollama_agent/providers/anthropic.rb +44 -28
- data/lib/ollama_agent/providers/base.rb +8 -2
- 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 +82 -16
- data/lib/ollama_agent/providers/openai.rb +49 -32
- 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 +96 -10
- data/lib/ollama_agent/providers/router.rb +6 -8
- data/lib/ollama_agent/repo_list.rb +22 -10
- data/lib/ollama_agent/resilience/retry_middleware.rb +2 -0
- data/lib/ollama_agent/ruby_index_tool_support.rb +11 -1
- data/lib/ollama_agent/runner.rb +80 -14
- 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 +12 -12
- data/lib/ollama_agent/runtime/policies.rb +4 -8
- 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 +1 -1
- 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/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 +8 -10
- 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/http_tools.rb +64 -59
- data/lib/ollama_agent/tools/memory_tools.rb +28 -28
- data/lib/ollama_agent/tools/safe_calculator.rb +203 -0
- data/lib/ollama_agent/tools/shell_tools.rb +105 -56
- 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 +148 -15
- data/lib/ollama_agent/tui_slash_reader.rb +111 -3
- data/lib/ollama_agent/version.rb +1 -1
- data/lib/ollama_agent.rb +104 -4
- data/lib/tasks/docker_validator.rake +16 -0
- metadata +184 -3
- 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,5 +1,29 @@
|
|
|
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
|
+
|
|
3
27
|
## [1.0.0] - 2026-04-11
|
|
4
28
|
|
|
5
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.
|
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
|
@@ -4,12 +4,29 @@ 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:
|
|
@@ -73,6 +124,21 @@ Long-running models (slow local inference):
|
|
|
73
124
|
bundle exec ruby exe/ollama_agent ask --timeout 300 "Your task"
|
|
74
125
|
```
|
|
75
126
|
|
|
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
|
+
|
|
76
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:
|
|
77
143
|
|
|
78
144
|
```bash
|
|
@@ -101,19 +167,62 @@ bundle exec ruby exe/ollama_agent improve --apply
|
|
|
101
167
|
|
|
102
168
|
For mode 3, `-y` skips all patch prompts; `--no-semi` prompts for every patch when not using `-y`.
|
|
103
169
|
|
|
104
|
-
|
|
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:
|
|
105
185
|
|
|
106
186
|
```bash
|
|
107
187
|
OLLAMA_AGENT_THINK=true bundle exec ruby exe/ollama_agent ask -i
|
|
108
|
-
# or
|
|
109
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"
|
|
110
202
|
```
|
|
111
203
|
|
|
112
|
-
|
|
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.
|
|
205
|
+
|
|
206
|
+
#### Display style (TTY)
|
|
207
|
+
|
|
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`**.
|
|
113
211
|
|
|
114
|
-
|
|
212
|
+
#### If you see no **Thinking** block
|
|
115
213
|
|
|
116
|
-
|
|
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`).
|
|
117
226
|
|
|
118
227
|
### Ollama Cloud
|
|
119
228
|
|
|
@@ -126,9 +235,63 @@ With **`--stream`** / **`OLLAMA_AGENT_STREAM=1`**, reasoning streams in **dim**
|
|
|
126
235
|
export OLLAMA_BASE_URL="https://ollama.com"
|
|
127
236
|
export OLLAMA_API_KEY="your_key"
|
|
128
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"
|
|
129
261
|
bundle exec ruby exe/ollama_agent ask "Your task"
|
|
130
262
|
```
|
|
131
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
|
+
|
|
132
295
|
### Environment
|
|
133
296
|
|
|
134
297
|
| Variable | Purpose |
|
|
@@ -147,7 +310,8 @@ bundle exec ruby exe/ollama_agent ask "Your task"
|
|
|
147
310
|
| `OLLAMA_AGENT_MARKDOWN` | Set to `0` to disable Markdown formatting of assistant replies (plain text only) |
|
|
148
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 |
|
|
149
312
|
| `OLLAMA_AGENT_THINKING_MARKDOWN` | Set to `1` to render **thinking** text with Markdown (muted); default is plain dim text |
|
|
150
|
-
| `
|
|
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`. |
|
|
151
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**) |
|
|
152
316
|
| `OLLAMA_AGENT_INDEX_REBUILD` | Set to `1` to drop the cached Prism Ruby index before the next symbol search in this process |
|
|
153
317
|
| `OLLAMA_AGENT_RUBY_INDEX_MAX_FILES` | Max `.rb` files to parse per index build (default **5000**) |
|
|
@@ -189,6 +353,59 @@ Use the **`orchestrate`** command (or **`OLLAMA_AGENT_ORCHESTRATOR=1`** with **`
|
|
|
189
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.
|
|
190
354
|
- Tool contract version: **`OllamaAgent::ORCHESTRATOR_TOOLS_SCHEMA_VERSION`**.
|
|
191
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
|
+
|
|
192
409
|
### Library usage (Ruby)
|
|
193
410
|
|
|
194
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).
|
|
@@ -247,6 +464,75 @@ last = OllamaAgent::ToolRuntime::Loop.new(
|
|
|
247
464
|
# last => e.g. { "status" => "done", "echo" => "bye" }
|
|
248
465
|
```
|
|
249
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
|
+
|
|
250
536
|
## Troubleshooting
|
|
251
537
|
|
|
252
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`.
|
|
@@ -267,6 +553,8 @@ bundle exec rspec
|
|
|
267
553
|
bundle exec rubocop
|
|
268
554
|
```
|
|
269
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
|
+
|
|
270
558
|
### CI and RubyGems release
|
|
271
559
|
|
|
272
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**).
|
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: []
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Minimal sandbox for post-condition / isolated validation (array-exec only at the Docker CLI).
|
|
2
|
+
# Build: docker build -f containers/ollama_agent-verification-sandbox.Dockerfile -t ollama-agent-validator:local .
|
|
3
|
+
#
|
|
4
|
+
# ruby:3.3-slim is smaller than the default non-slim image while keeping glibc compatibility.
|
|
5
|
+
FROM ruby:3.3-slim-bookworm
|
|
6
|
+
|
|
7
|
+
RUN groupadd --system --gid 65532 sandbox \
|
|
8
|
+
&& useradd --system --uid 65532 --gid sandbox --home-dir /workspace --shell /usr/sbin/nologin sandbox
|
|
9
|
+
|
|
10
|
+
WORKDIR /workspace
|
|
11
|
+
|
|
12
|
+
# Replace with a concrete argv at `docker run ... image <cmd...>`; this is only a smoke default.
|
|
13
|
+
ENTRYPOINT []
|
|
14
|
+
CMD ["ruby", "-rjson", "-e", "puts JSON.dump({ok: true})"]
|
|
15
|
+
|
|
16
|
+
USER sandbox
|