tina4ruby 3.13.136 → 3.13.137

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: 76e4848167cfc04c327d95658f37ec1e8c95448f143000eaec69218527b86b9f
4
- data.tar.gz: 97775ba90cbd5c991b44d27af3c5a94db4288f3e70feb07147fc4fe3df672ba0
3
+ metadata.gz: 20aca573e3cde8679e7391e5a6678adaee5900575f6c4859adbe910bc0338687
4
+ data.tar.gz: b49f226dd8fdb7d873b3a23d7e0c2eb23678f37738ae78f84c7de2a880e4e189
5
5
  SHA512:
6
- metadata.gz: f548932ee5b0b890a972e09727b2c73264cc30188e8a9ee24ef7f61cfa165a71b52797cf8e0c69c6331e3a7be2d5b82b5bc41c791c32ef88ef3e2760a44d6c65
7
- data.tar.gz: cd7ab7cb88ca3775bbdd49ed1e1a187e0a5846383815735eec415edfc12bd3318c36f85b6b77d479659c2fdf86bc38fcb8b0caa2838d138c2de9eb4ea8eba46e
6
+ metadata.gz: 2ec416a1fc6f9d397258e688015e5af18139d7b6379c9f7a473c35c44f615711db5301e2cc18a9d4c654bea226473c0849ed61ab57daa246829ec27208a45c7d
7
+ data.tar.gz: 27c9a2952ce239f555cc9e9977623c4e66cc5e9505d43b96212ad571ea43afd75d6ceb04f4527fcf9dbc6fffbb8b4b6e9a900ff8314828804793d49591d267c4
data/CHANGELOG.md CHANGED
@@ -6,6 +6,24 @@ number means the same thing everywhere.
6
6
  **The authoritative release notes for every shipped version live in the documentation:**
7
7
  https://tina4.com/ruby/36-releases
8
8
 
9
+ ## 3.13.137
10
+
11
+ Gemini joins the Ai client as a first-class provider. Set TINA4_AI_PROVIDER=gemini with a
12
+ TINA4_AI_KEY and the AI client reaches Google Gemini through its OpenAI-compatible endpoint,
13
+ with the same normalised responses, streaming, tool-use, retries and embeddings every other
14
+ provider gets and no new dependency. Gemini rides the existing OpenAI wire family, so the
15
+ whole provider is a thin alias: the base URL, the endpoint suffix, and the Bearer key.
16
+
17
+ ## 3.13.136
18
+
19
+ The AI skills learn to build to the user journeys. The tina4-architect skill now maps goals,
20
+ user journeys, and system flows with a completeness net before it scaffolds a file (a visible
21
+ map marker flags that work while it happens), the developer skills build to those journeys,
22
+ and a new tina4-design skill runs the visual-identity chain (brand guidelines plus an
23
+ interactive UI guide). Framework fixes: the bundled Swagger UI no longer answers a route miss
24
+ with a document that cannot load (#46); and a spec proves the gemspec names no third-party
25
+ runtime dependency. Full notes: https://tina4.com/ruby/36-releases
26
+
9
27
  ## 3.13.135
10
28
 
11
29
  Fix release. The dev-admin version check returns no version and a reason when it cannot
@@ -27,7 +27,7 @@ module Tina4
27
27
  # shape); ADR-0060 extended it with typed streaming events and multimodal
28
28
  # content parts. Both live here so the AI surface is a single file.
29
29
  class Ai
30
- PROVIDERS = %w[local openai anthropic].freeze
30
+ PROVIDERS = %w[local openai anthropic gemini].freeze
31
31
 
32
32
  class << self
33
33
  # chat(stream: false) still returns a ChatResponse (ADR-0053).
@@ -219,16 +219,20 @@ module Tina4
219
219
 
220
220
  def resolve_config(capability, model, timeout, provider)
221
221
  selected = (provider || ENV["TINA4_AI_PROVIDER"] || "local").strip.downcase
222
- raise AiConfigError, "TINA4_AI_PROVIDER must be local, openai, or anthropic" unless PROVIDERS.include?(selected)
222
+ raise AiConfigError, "TINA4_AI_PROVIDER must be local, openai, anthropic, or gemini" unless PROVIDERS.include?(selected)
223
223
 
224
224
  key = ENV["TINA4_AI_KEY"]
225
- if %w[openai anthropic].include?(selected) && (key.nil? || key.empty?)
225
+ if %w[openai anthropic gemini].include?(selected) && (key.nil? || key.empty?)
226
226
  raise AiConfigError, "TINA4_AI_KEY is required for the #{selected} provider"
227
227
  end
228
228
  defaults = {
229
229
  "local" => ["http://localhost:11437", "llama3.2"],
230
230
  "openai" => ["https://api.openai.com/v1", "gpt-4o-mini"],
231
- "anthropic" => ["https://api.anthropic.com/v1", "claude-3-5-haiku-latest"]
231
+ "anthropic" => ["https://api.anthropic.com/v1", "claude-3-5-haiku-latest"],
232
+ # Gemini speaks the OpenAI wire format at its OpenAI-compatible base, so it
233
+ # rides the openai body/parse/stream path — only the base URL, the endpoint
234
+ # suffix append, and the Bearer key differ.
235
+ "gemini" => ["https://generativelanguage.googleapis.com/v1beta/openai", "gemini-2.5-flash"]
232
236
  }
233
237
  value = capability == "embed" && ENV["TINA4_EMBED_URL"] ? ENV["TINA4_EMBED_URL"] : (ENV["TINA4_AI_URL"] || defaults[selected][0])
234
238
  total = timeout.nil? ? number("TINA4_AI_TIMEOUT", 60, 0.001) : Float(timeout)
@@ -255,7 +259,11 @@ module Tina4
255
259
  raise AiConfigError, "AI URL must be an http or https URL" unless %w[http https].include?(uri.scheme) && uri.host
256
260
 
257
261
  path = uri.path.to_s.sub(%r{/+$}, "")
258
- if ["", "/v1", "/api"].include?(path)
262
+ # "/v1beta/openai" is Gemini's OpenAI-compatible base; append the suffix onto
263
+ # it exactly as onto a bare host / "/v1" / "/api", so the default gemini base
264
+ # resolves to .../v1beta/openai/chat/completions (or /embeddings). A full
265
+ # endpoint URL the caller supplies verbatim still passes through untouched.
266
+ if ["", "/v1", "/api", "/v1beta/openai"].include?(path)
259
267
  suffix = provider == "anthropic" ? "/messages" : (capability == "embed" ? "/embeddings" : "/chat/completions")
260
268
  uri.path = (path.empty? ? "/v1" : path) + suffix
261
269
  end
@@ -266,7 +274,7 @@ module Tina4
266
274
 
267
275
  def headers(config)
268
276
  result = { "Content-Type" => "application/json", "Accept" => "application/json" }
269
- if config[:provider] == "openai"
277
+ if %w[openai gemini].include?(config[:provider])
270
278
  result["Authorization"] = "Bearer #{config[:key]}"
271
279
  elsif config[:provider] == "anthropic"
272
280
  result["x-api-key"] = config[:key]
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.13.136"
4
+ VERSION = "3.13.137"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.136
4
+ version: 3.13.137
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-09 00:00:00.000000000 Z
11
+ date: 2026-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack