coach_zed 0.5.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69d270a2c1faceaf9fe421555cad487672b9ffaf3a6771a1b41c8cc764dea4d8
4
- data.tar.gz: 6505699644e8594c33f3ea411d9d2933c6fcaf51424fb9654d35582431779c1c
3
+ metadata.gz: b449cb8b006ea91556af3a2fce2505db17f8827179c6fd185fd686f19ca4a3c4
4
+ data.tar.gz: bb46ed11b4ef7170119bea7497229816577971fd88890e5b4d3d4bc9ff3354cc
5
5
  SHA512:
6
- metadata.gz: c74981e4c6ebe99a2fe4cae454f7ead27f250bd3f72e5ae70295eb7dce0330957c5d8008743f328b4852f9d4257e248954da29ee3399bfed9a0b5721f3508601
7
- data.tar.gz: eb77954549836c2fdc3865f1473dcf1f7fbbead19adb45100f5dd1a75cb0d494df1a14283f1535e64980884e1b167ee99e4d8ca55be929af5af4110965176bd1
6
+ metadata.gz: fbe54bc46704d9c1fd4bd3584b9596dbb66cd322a0d2fe4589a0b120e2381d2cc51e036ae0dff4805a2861ea00331f15d0884d2f2fe71bee23550dddfc5dccaa
7
+ data.tar.gz: 0abbbb09b564c3e8540dc316c2e1e04c923c29223d3f70d53ac40ab3b16e4ae55ed7f303351edce0d7a1d9cd647fa3e0fbc4f911b1d419703ee009bbd09d68ec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [](https://github.com/rossta/coach_zed/compare/v0.5.0...v) (2026-06-16)
2
+
3
+ ### Bug Fixes
4
+
5
+ * advertise structured JSON schema ([af719a5](https://github.com/rossta/coach_zed/commit/af719a535cfadab87a7013207132c08e1d6c9ae0))
1
6
  ## [](https://github.com/rossta/coach_zed/compare/v0.4.6...v) (2026-06-16)
2
7
 
3
8
  ### Features
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../schedule_schema"
4
+
3
5
  class CoachZed
4
6
  module Clients
5
7
  class RubyOpenAI
@@ -11,7 +13,15 @@ class CoachZed
11
13
  def generate(prompt:)
12
14
  response = client.chat(parameters: {
13
15
  model: model,
14
- messages: [{role: "user", content: prompt}]
16
+ messages: [{role: "user", content: prompt}],
17
+ response_format: {
18
+ type: "json_schema",
19
+ json_schema: {
20
+ name: "coach_zed_schedule",
21
+ schema: CoachZed::ScheduleSchema.to_h,
22
+ strict: true
23
+ }
24
+ }
15
25
  })
16
26
  extract_content(response)
17
27
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require_relative "schedule_schema"
4
5
 
5
6
  class CoachZed
6
7
  class PromptBuilder
@@ -17,26 +18,11 @@ class CoachZed
17
18
  <<~PROMPT
18
19
  You are a training coach. Build a daily training schedule for the athlete using only the provided catalog.
19
20
 
20
- Return JSON only. Do not wrap it in markdown fences or commentary.
21
+ Return strict JSON only. Do not wrap it in markdown fences or commentary.
22
+ Every string value must be valid JSON text on a single line. Do not emit literal newlines, tabs, or other control characters inside string values.
21
23
 
22
- Required schema:
23
- {
24
- "program_name": string,
25
- "program_length_days": integer,
26
- "days": [
27
- {
28
- "day_number": integer,
29
- "day_type": "workout" or "rest",
30
- "workout": {
31
- "title": string,
32
- "catalog_path": string,
33
- "domain": string,
34
- "session_duration": string
35
- } or null,
36
- "notes": string
37
- }
38
- ]
39
- }
24
+ Required JSON Schema:
25
+ #{JSON.pretty_generate(CoachZed::ScheduleSchema.to_h)}
40
26
 
41
27
  Rules:
42
28
  - Produce exactly #{generation_days} entries for the requested time period.
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CoachZed
4
+ module ScheduleSchema
5
+ module_function
6
+
7
+ def to_h
8
+ {
9
+ type: "object",
10
+ properties: {
11
+ program_name: {type: "string"},
12
+ program_length_days: {type: "integer"},
13
+ days: {
14
+ type: "array",
15
+ items: {
16
+ type: "object",
17
+ properties: {
18
+ day_number: {type: "integer"},
19
+ day_type: {
20
+ type: "string",
21
+ enum: %w[workout rest]
22
+ },
23
+ workout: {
24
+ anyOf: [
25
+ {
26
+ type: "object",
27
+ properties: {
28
+ title: {type: "string"},
29
+ catalog_path: {type: "string"},
30
+ domain: {type: "string"},
31
+ session_duration: {type: "string"}
32
+ },
33
+ required: %w[title catalog_path domain session_duration],
34
+ additionalProperties: false
35
+ },
36
+ {type: "null"}
37
+ ]
38
+ },
39
+ notes: {type: "string"}
40
+ },
41
+ required: %w[day_number day_type workout notes],
42
+ additionalProperties: false
43
+ }
44
+ }
45
+ },
46
+ required: %w[program_name program_length_days days],
47
+ additionalProperties: false
48
+ }
49
+ end
50
+ end
51
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class CoachZed
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.1"
5
5
  end
data/lib/coach_zed.rb CHANGED
@@ -11,6 +11,7 @@ require_relative "coach_zed/catalog"
11
11
  require_relative "coach_zed/clients/ruby_openai"
12
12
  require_relative "coach_zed/feed_reader"
13
13
  require_relative "coach_zed/feed_writer"
14
+ require_relative "coach_zed/schedule_schema"
14
15
  require_relative "coach_zed/prompt_builder"
15
16
  require_relative "coach_zed/schedule_parser"
16
17
 
data/sig/coach_zed.rbs CHANGED
@@ -1,6 +1,11 @@
1
1
  class CoachZed
2
2
  VERSION: String
3
3
 
4
+ module ScheduleSchema
5
+ def to_h: -> Hash[Symbol, untyped]
6
+ def self.to_h: -> Hash[Symbol, untyped]
7
+ end
8
+
4
9
  class Result
5
10
  attr_reader schedule_path: Pathname
6
11
  attr_reader ics_path: Pathname
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coach_zed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Kaffenberger
@@ -27,6 +27,7 @@ files:
27
27
  - lib/coach_zed/feed_writer.rb
28
28
  - lib/coach_zed/prompt_builder.rb
29
29
  - lib/coach_zed/schedule_parser.rb
30
+ - lib/coach_zed/schedule_schema.rb
30
31
  - lib/coach_zed/version.rb
31
32
  - sig/coach_zed.rbs
32
33
  homepage: https://example.com/coach_zed