pinecall 0.0.5 → 0.0.6

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: 0571abe150af681966473dd3a8e8123137743bbecf63d6c4144632f986eb304a
4
- data.tar.gz: 55c632d74f2440250049ecc84bad96d611b7d270cea5130d01154674b84761ad
3
+ metadata.gz: e3afca7edf6bc33bb5b6fc9ebed23d76eecac2bb6039fb243d252d379e509e50
4
+ data.tar.gz: f3a39bb373fa2565bc6f49f04429d8f560dcc5cd8d01f9cc8d874f3ae452808d
5
5
  SHA512:
6
- metadata.gz: c476476012157ce39d48b2e1b07ccd33c5533d217ff2d33037e423d05b48a49986e556638fbca2410890c739aeb00b13da0076415e1c2f62c6a8f1a0452a239e
7
- data.tar.gz: d42a9901721b9e179fbddd3ffba1b2c4ff1805c3abceaaafe4b5d77aecf0990dc1265685e762164cdbad4d11b3a4b77a20f6bba5ceeab06ccd5b95cc8ee7445e
6
+ metadata.gz: bd6ea499f8cdbe11a9faf6e25715848c470755e8318705beee191db517446096866e79bd830c32ba77ed4c38c7da134ccdacf90ae973c7169d18baa5a58abd93
7
+ data.tar.gz: 9ee25075169e9581cafd1c58a67eee8b47705cc82bbd3d6aa8568b1a35db6ac20039089bb72de8004bbd973772679725208c3fdca5d469a8b292b2de53badd63
data/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ version number is the human's call.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.0.6] — A greeting is words or :improvise, a hangup is words or true, and the ears choose who ends the turn (2026-10-10)
10
+
11
+ - `greeting "…"` (said as written), `greeting :improvise` (the model opens on its prompt) and
12
+ `greeting improvise("…")` (with an instruction); `interruptible: true` for an opening the caller
13
+ may cut short, which by default they cannot. The `say:` / `reply:` keywords are gone.
14
+ - `hangup "…"` (when, in your words) or `hangup true` (whenever the model judges); `when:` is gone.
15
+ - `stt "…", end_of_turn: :stt | :livekit | :smart_turn`: who says the caller's turn is over, as
16
+ @pinecall/agents 0.9.26 says it. Needs runtime 0.1.43.
17
+
9
18
  ## [0.0.5] — The class declares its voice, its models and the rest, and wins (2026-10-10)
10
19
 
11
20
  - **A class declares its environment again, and it wins over the settings.** Class macros `voice
@@ -16,12 +16,38 @@ module Pinecall
16
16
  ENVIRONMENT = %i[language voice llm stt greeting hangup turn says hears knowledge docs memory record].freeze
17
17
 
18
18
  # The ones written as the wire's own fields, keyword by keyword: `greeting say: "…"`.
19
- AS_KEYWORDS = %i[greeting hangup turn knowledge docs memory].freeze
19
+ AS_KEYWORDS = %i[turn knowledge docs memory].freeze
20
20
 
21
21
  NO_VOICE = "a voice the class declares names its vendor and the voice: voice \"<vendor>\", \"<voice id>\""
22
22
 
23
+ NO_OPENING = "a greeting is the words, as a string, or :improvise for the model's own: improvise(\"…\") gives it an instruction"
24
+ NO_ENDING = "hangup is when the model may end the call, in your words, or true whenever it judges the call done"
25
+
26
+ # The model opens the call: on its prompt alone (an empty instruction), or with this one.
27
+ Improvised = Data.define(:instruction, :interruptible)
28
+
23
29
  NOTHING = Object.new.freeze
24
30
 
31
+ # An opening as the wire says it: words to `say`, or a `reply` the model opens on.
32
+ def self.greeting_of(opening, interruptible)
33
+ said = case opening
34
+ when :improvise then { reply: "" }
35
+ when Improvised then { reply: opening.instruction }
36
+ when String then { say: opening }
37
+ else raise DeclarationRefused, NO_OPENING
38
+ end
39
+ given = opening.is_a?(Improvised) ? opening.interruptible : interruptible
40
+ given.nil? ? said : { **said, allow_interruptions: given }
41
+ end
42
+
43
+ # When the model may end the call: an empty `when` is whenever it judges.
44
+ def self.hangup_of(ending)
45
+ return { when: "" } if ending == true
46
+ raise DeclarationRefused, NO_ENDING unless ending.is_a?(String) && !ending.strip.empty?
47
+
48
+ { when: ending }
49
+ end
50
+
25
51
  # `vendor/model`, or a vendor alone; the model id keeps every slash after the vendor's.
26
52
  def self.model_of(named)
27
53
  provider, _slash, model = named.to_s.partition("/")
@@ -55,11 +81,31 @@ module Pinecall
55
81
  environment[:llm] = { **Config.model_of(model), temperature:, builds:, options: }.compact
56
82
  end
57
83
 
58
- # The ears, `vendor/model` or a vendor alone.
59
- def stt(model = NOTHING, builds: nil, options: nil)
84
+ # The ears, `vendor/model` or a vendor alone, and who says the caller's turn is over:
85
+ # `end_of_turn: "stt"` the ears themselves (Deepgram Flux), `"livekit"` or `"smart-turn"`.
86
+ def stt(model = NOTHING, builds: nil, options: nil, end_of_turn: nil)
60
87
  return environment[:stt] if model.equal?(NOTHING)
61
88
 
62
- environment[:stt] = { **Config.model_of(model), builds:, options: }.compact
89
+ ends = end_of_turn&.to_s&.tr("_", "-")
90
+ environment[:stt] = { **Config.model_of(model), builds:, options:, end_of_turn: ends }.compact
91
+ end
92
+
93
+ # How a call opens: the words, said as written, or :improvise for the model's own. The
94
+ # caller cannot cut it short unless `interruptible: true`.
95
+ def greeting(opening = NOTHING, interruptible: nil)
96
+ return environment[:greeting] if opening.equal?(NOTHING)
97
+
98
+ environment[:greeting] = Config.greeting_of(opening, interruptible)
99
+ end
100
+
101
+ # The model opens the call with this instruction: `greeting improvise("…")`.
102
+ def improvise(instruction = "", interruptible: nil) = Improvised.new(instruction, interruptible)
103
+
104
+ # When the model may end the call: in your words, or `true` whenever it judges it done.
105
+ def hangup(ending = NOTHING)
106
+ return environment[:hangup] if ending.equal?(NOTHING)
107
+
108
+ environment[:hangup] = Config.hangup_of(ending)
63
109
  end
64
110
 
65
111
  # `language "es"`, `says [{ word: "GSA", spoken: "ge ese a" }]`, `record false`.
@@ -78,8 +124,8 @@ module Pinecall
78
124
  environment[:hears] = words.flatten
79
125
  end
80
126
 
81
- # `greeting say: "…"`, `hangup when: "…"`, `turn endpointing_ms: 300`, `docs base: "…", k: 4`,
82
- # `memory remember: […], forget: […]`, `knowledge path: "…", text: "…"`.
127
+ # `turn endpointing_ms: 300`, `docs base: "…", k: 4`, `memory remember: […], forget: […]`,
128
+ # `knowledge path: "…", text: "…"`.
83
129
  AS_KEYWORDS.each do |field|
84
130
  define_method(field) do |**given|
85
131
  return environment[field] if given.empty?
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pinecall
4
4
  # Set by the maintainer at release time.
5
- VERSION = "0.0.5"
5
+ VERSION = "0.0.6"
6
6
  end
@@ -23,7 +23,8 @@ module Pinecall
23
23
  model: { kind: :str, required: true },
24
24
  temperature: { kind: :float },
25
25
  builds: { kind: :str },
26
- options: { kind: :json }
26
+ options: { kind: :json },
27
+ end_of_turn: { kind: :enum, values: %w[stt livekit smart-turn] }
27
28
  }.freeze,
28
29
  "TurnConfig" => {
29
30
  min_interruption_words: { kind: :int },
data/sig/pinecall.rbs CHANGED
@@ -87,13 +87,14 @@ module Pinecall
87
87
  # the environment the class declares, each over the agent's settings
88
88
  def self.voice: (?String, ?String?, ?model: String?, ?builds: String?, ?options: Hash[untyped, untyped]?) -> untyped
89
89
  def self.llm: (?String, ?temperature: Float?, ?builds: String?, ?options: Hash[untyped, untyped]?) -> untyped
90
- def self.stt: (?String, ?builds: String?, ?options: Hash[untyped, untyped]?) -> untyped
90
+ def self.stt: (?String, ?builds: String?, ?options: Hash[untyped, untyped]?, ?end_of_turn: (String | Symbol)?) -> untyped
91
91
  def self.language: (?String) -> untyped
92
92
  def self.says: (?Array[Hash[Symbol, String]]) -> untyped
93
93
  def self.record: (?bool) -> untyped
94
94
  def self.hears: (*String | Array[String]) -> untyped
95
- def self.greeting: (**untyped) -> untyped
96
- def self.hangup: (**untyped) -> untyped
95
+ def self.greeting: (?(String | Symbol | untyped), ?interruptible: bool?) -> untyped
96
+ def self.improvise: (?String, ?interruptible: bool?) -> untyped
97
+ def self.hangup: (?(String | true)) -> untyped
97
98
  def self.turn: (**untyped) -> untyped
98
99
  def self.knowledge: (**untyped) -> untyped
99
100
  def self.docs: (**untyped) -> untyped
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinecall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pinecall