agent-harness 0.28.6 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0462522eb82540a1cc498c27663441e6aab837cabab94921e7deed4f31e2f29
4
- data.tar.gz: 14a84df84773fd4a64597d46733e4c4a0297ec3b4102dde5a9ded015e3a451e1
3
+ metadata.gz: ae26a14b4826681fbe36862291bfc6342afab2dd709e2386312ab072582fc3cb
4
+ data.tar.gz: b53f1b28bd4662e1522db2670e7f698e71937b600d80d1fa30de056a3e3d9deb
5
5
  SHA512:
6
- metadata.gz: 34f7e74dd1f62aed14782936a1d794c4e2406ddc05f274dbe39e28ac7938f7b00387cfdc05e7fb4c94bd1c3e79294fd9cbdfe25a0e8c235d6340b04de47e048f
7
- data.tar.gz: 7a3946d5a75fa84c6502e02ce409325e870c0bbd0a23a7ea8319cffbfe75128a9bf8c1889b8d9747c0f8fef13f04dc9e625ce7969f60a92b3728e75041e496ac
6
+ metadata.gz: e16d723dd4945831271b4d10cfc1de69042181796fecde7500c840060fe18f4ba637d567cec2ca342c015b3dde4d288e4716ae0471cded2cd43572f13bb7208f
7
+ data.tar.gz: 751f5a515d4ff3764a24fd21dba24733545d4da3fe06803d02d2d270504a7fcce12ea2a9dc1a08ede985aca4bd0e76c07e75fcb5be6e03ac7067e6ee005c38ae
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.28.6"
2
+ ".": "0.30.0"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -6,6 +6,20 @@
6
6
  * **auth:** add provider-owned PKCE code-exchange API for Claude OAuth (`AgentHarness::Authentication.exchange_code`). Takes an authorization code plus PKCE verifier (and `redirect_uri`/`client_id`), posts an `authorization_code` grant to the Claude token endpoint, and persists the resulting access/refresh tokens in the native `claudeAiOauth` shape. Adds `exchange_code_supported?` and a `code_exchange` key to `auth_capabilities` ([#266](https://github.com/viamin/agent-harness/issues/266)).
7
7
 
8
8
 
9
+ ## [0.30.0](https://github.com/viamin/agent-harness/compare/agent-harness/v0.29.0...agent-harness/v0.30.0) (2026-07-16)
10
+
11
+
12
+ ### Features
13
+
14
+ * Implement Oh My Pi execution, auth, and smoke-test contract ([#300](https://github.com/viamin/agent-harness/issues/300)) ([dc3f5ec](https://github.com/viamin/agent-harness/commit/dc3f5ecce4508f103a8b769727e31aaa3d694c7e))
15
+
16
+ ## [0.29.0](https://github.com/viamin/agent-harness/compare/agent-harness/v0.28.6...agent-harness/v0.29.0) (2026-07-16)
17
+
18
+
19
+ ### Features
20
+
21
+ * Add Oh My Pi provider metadata and install contract ([#298](https://github.com/viamin/agent-harness/issues/298)) ([3be62a8](https://github.com/viamin/agent-harness/commit/3be62a884f50ceeb903e199f4a9906cf3fecf014))
22
+
9
23
  ## [0.28.6](https://github.com/viamin/agent-harness/compare/agent-harness/v0.28.5...agent-harness/v0.28.6) (2026-07-12)
10
24
 
11
25
 
data/README.md CHANGED
@@ -5,7 +5,7 @@ A unified Ruby interface for CLI-based AI coding agents like Claude Code, Cursor
5
5
  ## Features
6
6
 
7
7
  - **Unified Interface**: Single API for multiple AI coding agents
8
- - **10 Built-in Providers**: Claude Code, Cursor, Gemini CLI, GitHub Copilot, Codex, Pi, Aider, OpenCode, Kilocode, Mistral Vibe
8
+ - **11 Built-in Providers**: Claude Code, Cursor, Gemini CLI, GitHub Copilot, Codex, Pi, Oh My Pi, Aider, OpenCode, Kilocode, Mistral Vibe
9
9
  - **Full Orchestration**: Provider switching, circuit breakers, rate limiting, and health monitoring
10
10
  - **Flexible Configuration**: YAML, Ruby DSL, or environment variables
11
11
  - **Token Tracking**: Monitor usage across providers for cost and limit management
@@ -105,6 +105,7 @@ end
105
105
  | `:github_copilot` | `copilot` | GitHub Copilot CLI |
106
106
  | `:codex` | `codex` | OpenAI Codex CLI |
107
107
  | `:pi` | `pi` | Pi coding agent CLI |
108
+ | `:omp` | `omp` | Oh My Pi coding agent CLI (Bun-based fork of Pi) |
108
109
  | `:aider` | `aider` | Aider coding assistant |
109
110
  | `:opencode` | `opencode` | OpenCode CLI |
110
111
  | `:kilocode` | `kilo` | Kilocode CLI |
@@ -188,7 +189,7 @@ puts contract[:supported_versions][:requirement]
188
189
 
189
190
  # List all registered providers
190
191
  AgentHarness::Providers::Registry.instance.all
191
- # => [:claude, :cursor, :gemini, :github_copilot, :pi, :codex, :opencode, :kilocode, :aider, :mistral_vibe]
192
+ # => [:claude, :cursor, :gemini, :github_copilot, :pi, :omp, :codex, :opencode, :kilocode, :aider, :mistral_vibe]
192
193
  ```
193
194
 
194
195
  For Claude, the install contract is the first-class source of truth for:
@@ -39,9 +39,35 @@ module AgentHarness
39
39
  normalized[:requires_postinstall] = contract[:requires_postinstall] if contract.key?(:requires_postinstall)
40
40
  normalized[:postinstall_command] = contract[:postinstall_command] if contract.key?(:postinstall_command)
41
41
 
42
+ if contract.key?(:runtime_requirements)
43
+ normalized[:runtime_requirements] =
44
+ normalize_metadata_runtime_requirements(contract[:runtime_requirements])
45
+ end
46
+
42
47
  normalized
43
48
  end
44
49
 
50
+ # Normalize an installation contract's `runtime_requirements` so the
51
+ # stable provider-metadata path exposes the same runtime prerequisites
52
+ # (e.g. Bun for the :omp provider) as the raw installation contract.
53
+ #
54
+ # Each entry is duplicated so consumers receive a self-contained hash
55
+ # they can mutate top-level keys on without aliasing the provider-owned
56
+ # contract, and the resulting array is frozen to signal that the
57
+ # normalized metadata is read-only.
58
+ #
59
+ # @param requirements [Array<Hash>, nil]
60
+ # @return [Array<Hash>, nil] normalized requirements, or nil when absent
61
+ def self.normalize_metadata_runtime_requirements(requirements)
62
+ return requirements unless requirements.is_a?(Array)
63
+
64
+ requirements.map do |requirement|
65
+ next requirement.dup if requirement.is_a?(Hash)
66
+
67
+ requirement
68
+ end.freeze
69
+ end
70
+
45
71
  def self.normalize_metadata_source_type(source)
46
72
  return source[:type]&.to_sym if source.is_a?(Hash)
47
73
 
@@ -0,0 +1,415 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubygems/requirement"
4
+
5
+ module AgentHarness
6
+ module Providers
7
+ # Oh My Pi coding agent CLI provider
8
+ #
9
+ # Provides integration with the Oh My Pi (can1357/oh-my-pi) terminal
10
+ # coding agent, a Bun-based fork of the Pi coding agent. Distinct from
11
+ # the {Pi} provider, which targets the upstream @mariozechner/pi-coding-agent
12
+ # CLI.
13
+ class OhMyPi < Base
14
+ CLI_PACKAGE = "@oh-my-pi/pi-coding-agent"
15
+ SUPPORTED_CLI_VERSION = "17.0.1"
16
+ SUPPORTED_CLI_REQUIREMENT = Gem::Requirement.new("= #{SUPPORTED_CLI_VERSION}").freeze
17
+
18
+ # Bun runtime requirements. The omp entrypoint is
19
+ # `#!/usr/bin/env bun` and the published package metadata requires
20
+ # Bun `>= 1.3.14`. Consumers must provision a compatible Bun runtime
21
+ # before installing the @oh-my-pi/pi-coding-agent package.
22
+ #
23
+ # The `bun` npm package relies on its `postinstall` script to fetch the
24
+ # platform binary; installing it with `npm install --ignore-scripts`
25
+ # ships only the Windows shims (`bin/bun.exe`, `bunx.exe`) and leaves
26
+ # Linux/macOS without a working `bun` binary. Provision Bun via the
27
+ # official installer script instead, which fetches the correct
28
+ # platform binary directly.
29
+ BUN_BINARY = "bun"
30
+ BUN_INSTALL_SCRIPT_URL = "https://bun.sh/install"
31
+ SUPPORTED_BUN_VERSION = "1.3.14"
32
+ BUN_REQUIREMENT_STRING = ">= #{SUPPORTED_BUN_VERSION}".freeze
33
+
34
+ # Smoke-test contract suitable for container health probes.
35
+ #
36
+ # Oh My Pi runs non-interactively via `-p` with `--no-session`, so the
37
+ # probe is a single deterministic round trip. The contract is tuned for
38
+ # a tight probe budget: a short prompt that elicits a predictable reply
39
+ # and a bounded timeout that accommodates a cold Bun runtime start.
40
+ SMOKE_TEST_CONTRACT = {
41
+ prompt: "Reply with exactly OK.",
42
+ expected_output: "OK",
43
+ timeout: 30,
44
+ require_output: true,
45
+ success_message: "Oh My Pi smoke test passed"
46
+ }.freeze
47
+
48
+ # Oh My Pi is a multi-provider CLI: it routes to a backend through
49
+ # `--provider` and surfaces that backend's error vocabulary. The
50
+ # patterns below extend the shared HTTP-style set with Oh My Pi /
51
+ # upstream-Pi specific phrasing observed for auth expiry, quota and
52
+ # rate-limit surfaces, model resolution failures, and transient
53
+ # network faults.
54
+ ERROR_PATTERNS = {
55
+ rate_limited: COMMON_ERROR_PATTERNS[:rate_limited],
56
+ auth_expired: COMMON_ERROR_PATTERNS[:auth_expired] + [
57
+ /\b401\b/,
58
+ /session.*(?:expired|invalid)/i,
59
+ /log(?:ged)?.?in.*required/i,
60
+ /api.?key.*(?:invalid|missing|expired|revoked)/i,
61
+ /token.*(?:expired|invalid|revoked)/i,
62
+ /credentials.*(?:expired|invalid|missing)/i
63
+ ],
64
+ quota_exceeded: COMMON_ERROR_PATTERNS[:quota_exceeded],
65
+ # Model resolution is surfaced by both the omp CLI (unknown
66
+ # `--model`/`--provider` combination) and the upstream backend.
67
+ # Treat it as a distinct, non-retryable category so callers can
68
+ # fall back to a known-good model instead of retrying the same id.
69
+ model_not_found: [
70
+ /model.*not.*found/i,
71
+ /no.*such.*model/i,
72
+ /unknown.*model/i,
73
+ /model.*does.*not.*exist/i,
74
+ /invalid.*model/i,
75
+ /model.*unavailable/i,
76
+ /provider.*does.*not.*support.*model/i
77
+ ],
78
+ transient: COMMON_ERROR_PATTERNS[:transient] + [
79
+ /connection.*reset/i,
80
+ /econnreset/i,
81
+ /socket.*hang.*up/i,
82
+ /network.*error/i
83
+ ]
84
+ }.tap { |patterns| patterns.each_value(&:freeze) }.freeze
85
+
86
+ # Non-actionable output that Oh My Pi writes while the Bun runtime and
87
+ # the agent bootstrap. Downstream consumers use these to filter probe
88
+ # and run output so startup banners do not masquerade as failures.
89
+ NOISY_OUTPUT_PATTERNS = [
90
+ /oh.?my.?pi\b/i,
91
+ /pi(?:-coding.?agent)?\s+v?\d+\.\d+/i,
92
+ /\bbun\s+v?\d+\.\d+/i,
93
+ /\bloading/i,
94
+ /\binitializing/i,
95
+ /\bwarming.?up/i,
96
+ /fetching.*model/i
97
+ ].freeze
98
+
99
+ class << self
100
+ def provider_name
101
+ :omp
102
+ end
103
+
104
+ def binary_name
105
+ "omp"
106
+ end
107
+
108
+ def available?
109
+ executor = AgentHarness.configuration.command_executor
110
+ !!executor.which(binary_name)
111
+ end
112
+
113
+ def provider_metadata_overrides
114
+ {
115
+ auth: {
116
+ service: :omp,
117
+ api_family: :multi_provider,
118
+ # Oh My Pi routes to a backend through `--provider` and reads
119
+ # that backend's API key from its conventional env var. The
120
+ # harness never reuses the upstream Pi credential store
121
+ # (paid_pi_auth_entry); callers pass backend keys per request
122
+ # through ProviderRuntime#env, which build_env materializes into
123
+ # the subprocess environment. This keeps the omp runner an
124
+ # independent entity from :pi.
125
+ #
126
+ # Deliberately do NOT advertise a harness-managed credential
127
+ # store here. Authentication has no omp read/write/validate path,
128
+ # so auth_status(:omp) reports "not implemented"; exposing
129
+ # credential_store would imply a session store that does not
130
+ # exist and let callers infer harness-managed session auth.
131
+ # Surface the implemented per-request env model instead.
132
+ api_key_source: :provider_runtime_env
133
+ }
134
+ }
135
+ end
136
+
137
+ def firewall_requirements
138
+ {
139
+ domains: [
140
+ "pi.dev"
141
+ ],
142
+ ip_ranges: []
143
+ }
144
+ end
145
+
146
+ def instruction_file_paths
147
+ [
148
+ {
149
+ path: "AGENTS.md",
150
+ description: "Oh My Pi agent instructions",
151
+ symlink: false
152
+ },
153
+ {
154
+ path: "SYSTEM.md",
155
+ description: "Oh My Pi system prompt override",
156
+ symlink: false
157
+ }
158
+ ]
159
+ end
160
+
161
+ def discover_models
162
+ return [] unless available?
163
+ []
164
+ end
165
+
166
+ def bun_runtime_contract
167
+ # The official Bun installer reads `BUN_VERSION` to pin the release
168
+ # it downloads, and fetches the platform-appropriate binary itself.
169
+ install_command_prefix = ["sh", "-c"].freeze
170
+ inner_script = "curl -fsSL #{BUN_INSTALL_SCRIPT_URL} | " \
171
+ "BUN_VERSION=#{SUPPORTED_BUN_VERSION} bash"
172
+ install_command = (install_command_prefix + [inner_script]).freeze
173
+
174
+ {
175
+ name: :bun,
176
+ binary_name: BUN_BINARY,
177
+ pinned_version: SUPPORTED_BUN_VERSION,
178
+ version_requirement: BUN_REQUIREMENT_STRING,
179
+ source: :script,
180
+ install_script_url: BUN_INSTALL_SCRIPT_URL,
181
+ install_command_prefix: install_command_prefix,
182
+ install_command: install_command,
183
+ install_command_string: inner_script,
184
+ rationale: "omp entrypoint is #!/usr/bin/env bun; the bun npm package relies on " \
185
+ "its postinstall script to fetch the platform binary, so install Bun " \
186
+ "via the official installer script rather than npm --ignore-scripts"
187
+ }.freeze
188
+ end
189
+
190
+ def installation_contract(version: SUPPORTED_CLI_VERSION)
191
+ version = version.strip if version.respond_to?(:strip)
192
+
193
+ unless version.is_a?(String) && !version.empty?
194
+ raise ArgumentError,
195
+ "Unsupported Oh My Pi CLI version #{version.inspect}; " \
196
+ "supported versions must satisfy #{SUPPORTED_CLI_REQUIREMENT}"
197
+ end
198
+
199
+ parsed_version = begin
200
+ Gem::Version.new(version)
201
+ rescue ArgumentError
202
+ raise ArgumentError,
203
+ "Unsupported Oh My Pi CLI version #{version.inspect}; " \
204
+ "supported versions must satisfy #{SUPPORTED_CLI_REQUIREMENT}"
205
+ end
206
+
207
+ unless SUPPORTED_CLI_REQUIREMENT.satisfied_by?(parsed_version)
208
+ raise ArgumentError,
209
+ "Unsupported Oh My Pi CLI version #{version.inspect}; " \
210
+ "supported versions must satisfy #{SUPPORTED_CLI_REQUIREMENT}"
211
+ end
212
+
213
+ package = "#{CLI_PACKAGE}@#{version}".freeze
214
+ install_command_prefix = ["npm", "install", "-g", "--ignore-scripts"].freeze
215
+ install_command = (install_command_prefix + [package]).freeze
216
+ supported_versions = [version].freeze
217
+ version_requirement = SUPPORTED_CLI_REQUIREMENT.requirements
218
+ .map { |op, ver| "#{op} #{ver}".freeze }
219
+ .freeze
220
+
221
+ contract = {
222
+ source: :npm,
223
+ package: package,
224
+ package_name: CLI_PACKAGE,
225
+ version: version,
226
+ version_requirement: version_requirement,
227
+ binary_name: binary_name,
228
+ install_command_prefix: install_command_prefix,
229
+ install_command: install_command,
230
+ supported_versions: supported_versions,
231
+ runtime_requirements: [bun_runtime_contract]
232
+ }
233
+
234
+ contract.each_value do |value|
235
+ value.freeze if value.is_a?(String)
236
+ end
237
+ contract.freeze
238
+ end
239
+
240
+ def smoke_test_contract
241
+ SMOKE_TEST_CONTRACT
242
+ end
243
+ end
244
+
245
+ def name
246
+ "omp"
247
+ end
248
+
249
+ def display_name
250
+ "Oh My Pi"
251
+ end
252
+
253
+ def configuration_schema
254
+ {
255
+ fields: [
256
+ {
257
+ name: :model,
258
+ type: :string,
259
+ label: "Model",
260
+ required: false,
261
+ hint: "Oh My Pi model pattern or ID passed to --model"
262
+ },
263
+ {
264
+ name: :provider,
265
+ type: :string,
266
+ label: "Provider",
267
+ required: false,
268
+ hint: "Oh My Pi provider name passed to --provider"
269
+ }
270
+ ],
271
+ auth_modes: %i[api_key oauth],
272
+ openai_compatible: false
273
+ }
274
+ end
275
+
276
+ def capabilities
277
+ {
278
+ streaming: false,
279
+ file_upload: true,
280
+ vision: true,
281
+ tool_use: true,
282
+ # Oh My Pi's non-interactive CLI currently exposes only text print mode.
283
+ # Keep JSON mode disabled until the CLI ships a structured output flag.
284
+ json_mode: false,
285
+ # MCP capability decision: the omp non-interactive print-mode path
286
+ # (`omp --no-session -p`) does not accept an MCP server config flag
287
+ # in the harness's supported CLI version. Keep MCP disabled here so
288
+ # callers do not attempt to attach servers that the runtime would
289
+ # reject. Revisit once omp ships a stable `--mcp-config` flag.
290
+ mcp: false,
291
+ dangerous_mode: false
292
+ }
293
+ end
294
+
295
+ def error_patterns
296
+ ERROR_PATTERNS
297
+ end
298
+
299
+ # Downstream-facing error classification. Augments the shared quota set
300
+ # with auth-expiry, model-resolution, and authentication-specific
301
+ # phrasing so consumers can route omp failures without re-deriving the
302
+ # CLI vocabulary. The inherited `:quota` set is deliberately preserved
303
+ # (not overridden) so omp's multi-provider backends surface their full
304
+ # credit/balance vocabulary (requires more credits, insufficient
305
+ # balance, spend limit reached, billing limit, etc.).
306
+ def error_classification_patterns
307
+ super.merge(
308
+ auth_expired: ERROR_PATTERNS[:auth_expired],
309
+ authentication: [
310
+ /api.?key.*not.*(?:set|configured)/i,
311
+ /no.*api.?key/i,
312
+ /missing.*credentials/i,
313
+ /log(?:ged)?.?in.*required/i
314
+ ],
315
+ model_not_found: ERROR_PATTERNS[:model_not_found]
316
+ )
317
+ end
318
+
319
+ # Oh My Pi emits a startup banner (version, Bun runtime, model fetch)
320
+ # that is not actionable. Expose it so callers can strip probe noise.
321
+ def noisy_error_patterns
322
+ NOISY_OUTPUT_PATTERNS
323
+ end
324
+
325
+ def translate_error(message)
326
+ if ERROR_PATTERNS[:model_not_found].any? { |p| message.match?(p) }
327
+ "Oh My Pi could not resolve the requested model. Check --model/--provider."
328
+ elsif /api.?key.*not.*(?:set|configured)/i.match?(message) || /no.*api.?key/i.match?(message)
329
+ "Oh My Pi API key not set for the selected provider."
330
+ else
331
+ message
332
+ end
333
+ end
334
+
335
+ # Oh My Pi runs stateless through `--no-session`; the harness does not
336
+ # expose session persistence, so callers cannot resume a session.
337
+ def supports_sessions?
338
+ false
339
+ end
340
+
341
+ def supports_tool_control?
342
+ true
343
+ end
344
+
345
+ def auth_type
346
+ :oauth
347
+ end
348
+
349
+ # Conventional backend API-key env vars the omp CLI reads. Oh My Pi is
350
+ # multi-provider: the effective var is the one matching the selected
351
+ # `--provider`, supplied per request through ProviderRuntime#env.
352
+ def api_key_env_var_names
353
+ [
354
+ "ANTHROPIC_API_KEY",
355
+ "OPENAI_API_KEY",
356
+ "GEMINI_API_KEY",
357
+ "GOOGLE_API_KEY",
358
+ "XAI_API_KEY",
359
+ "DEEPSEEK_API_KEY",
360
+ "OPENROUTER_API_KEY",
361
+ "GROQ_API_KEY",
362
+ "MISTRAL_API_KEY"
363
+ ]
364
+ end
365
+
366
+ # omp routes through `--provider` rather than an env-driven proxy/base
367
+ # URL, so there are no known proxy header vars to scrub when a caller
368
+ # supplies its own key.
369
+ def api_key_unset_vars
370
+ []
371
+ end
372
+
373
+ # When running against an OAuth/subscription session, drop backend
374
+ # API-key env vars so the CLI prefers the stored session credentials.
375
+ def subscription_unset_vars
376
+ api_key_env_var_names
377
+ end
378
+
379
+ def execution_semantics
380
+ {
381
+ prompt_delivery: :flag,
382
+ output_format: :text,
383
+ sandbox_aware: false,
384
+ uses_subcommand: false,
385
+ non_interactive_flag: "-p",
386
+ legitimate_exit_codes: [0],
387
+ stderr_is_diagnostic: true,
388
+ parses_rate_limit_reset: false
389
+ }
390
+ end
391
+
392
+ protected
393
+
394
+ def build_command(prompt, options)
395
+ runtime = options[:provider_runtime]
396
+ provider = runtime&.api_provider || @config.provider
397
+ model = runtime&.model || @config.model
398
+
399
+ cmd = [self.class.binary_name, "--no-session"]
400
+ cmd += @config.default_flags if @config.default_flags&.any?
401
+ cmd += runtime.flags if runtime
402
+ cmd += ["--provider", provider] if provider
403
+ cmd += ["--model", model] if model
404
+ cmd << "--no-tools" if options[:tools] == :none
405
+ cmd += ["-p", prompt]
406
+
407
+ cmd
408
+ end
409
+
410
+ def default_timeout
411
+ 300
412
+ end
413
+ end
414
+ end
415
+ end
@@ -28,6 +28,7 @@ module AgentHarness
28
28
  aliases: [:copilot]
29
29
  },
30
30
  {name: :pi, require_path: "agent_harness/providers/pi", class_name: :Pi, aliases: []},
31
+ {name: :omp, require_path: "agent_harness/providers/omp", class_name: :OhMyPi, aliases: []},
31
32
  {name: :codex, require_path: "agent_harness/providers/codex", class_name: :Codex, aliases: []},
32
33
  {name: :opencode, require_path: "agent_harness/providers/opencode", class_name: :Opencode, aliases: []},
33
34
  {name: :kilocode, require_path: "agent_harness/providers/kilocode", class_name: :Kilocode, aliases: []},
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentHarness
4
- VERSION = "0.28.6"
4
+ VERSION = "0.30.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent-harness
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.6
4
+ version: 0.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
@@ -134,6 +134,7 @@ files:
134
134
  - lib/agent_harness/providers/kilocode.rb
135
135
  - lib/agent_harness/providers/mcp_config_file_support.rb
136
136
  - lib/agent_harness/providers/mistral_vibe.rb
137
+ - lib/agent_harness/providers/omp.rb
137
138
  - lib/agent_harness/providers/opencode.rb
138
139
  - lib/agent_harness/providers/pi.rb
139
140
  - lib/agent_harness/providers/rate_limit_reset_parsing.rb