pinecall 0.0.4 → 0.0.5
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/CHANGELOG.md +12 -0
- data/lib/pinecall/agent/config.rb +68 -26
- data/lib/pinecall/version.rb +1 -1
- data/lib/pinecall/wire/shapes_config.rb +6 -2
- data/lib/pinecall/wire/shapes_doors.rb +1 -0
- data/sig/pinecall.rbs +15 -12
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0571abe150af681966473dd3a8e8123137743bbecf63d6c4144632f986eb304a
|
|
4
|
+
data.tar.gz: 55c632d74f2440250049ecc84bad96d611b7d270cea5130d01154674b84761ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c476476012157ce39d48b2e1b07ccd33c5533d217ff2d33037e423d05b48a49986e556638fbca2410890c739aeb00b13da0076415e1c2f62c6a8f1a0452a239e
|
|
7
|
+
data.tar.gz: d42a9901721b9e179fbddd3ffba1b2c4ff1805c3abceaaafe4b5d77aecf0990dc1265685e762164cdbad4d11b3a4b77a20f6bba5ceeab06ccd5b95cc8ee7445e
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ version number is the human's call.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.0.5] — The class declares its voice, its models and the rest, and wins (2026-10-10)
|
|
10
|
+
|
|
11
|
+
- **A class declares its environment again, and it wins over the settings.** Class macros `voice
|
|
12
|
+
"<vendor>", "<id>", model:`, `llm "<vendor>/<model>", temperature:`, `stt "<vendor>/<model>"`,
|
|
13
|
+
`language`, `greeting`, `hangup`, `turn`, `says`, `hears`, `knowledge`, `docs`, `memory` and
|
|
14
|
+
`record`, sent on `agent.configure`. A field the class declares is not read from the settings,
|
|
15
|
+
the console shows it "set by the class", and `pinecall agent set` of it is refused. Needs runtime
|
|
16
|
+
0.1.42.
|
|
17
|
+
- `builds:` and `options:` on `voice`, `llm` and `stt`: a class of the vendor's plugin and its
|
|
18
|
+
keyword arguments (`llm "openai/gpt-5.4-mini", builds: "responses.LLM", options: { use_websocket:
|
|
19
|
+
true }`), only on the org's own key for the vendor. The refusal that named a CLI verb is gone.
|
|
20
|
+
|
|
9
21
|
## [0.0.4] — A tool announces itself (2026-10-09)
|
|
10
22
|
|
|
11
23
|
### Added
|
|
@@ -4,35 +4,28 @@ module Pinecall
|
|
|
4
4
|
class Agent
|
|
5
5
|
# Class-level configuration (state lives on the instance).
|
|
6
6
|
#
|
|
7
|
-
# A class declares its contract: tools, state, view.
|
|
8
|
-
# language, greeting, memory, knowledge
|
|
9
|
-
#
|
|
7
|
+
# A class declares its contract: tools, state, view. It may also declare its environment —
|
|
8
|
+
# voice, models, language, greeting, memory, knowledge — and whatever it declares wins over the
|
|
9
|
+
# agent's settings for that field.
|
|
10
10
|
module Config
|
|
11
11
|
# `phone`, `whatsapp` and `web` are accepted for compatibility but ignored. `channel_rules
|
|
12
12
|
# false` leaves the `<channel>` block out of the prompt.
|
|
13
13
|
AS_WRITTEN = %i[phone whatsapp web channel_rules].freeze
|
|
14
14
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
greeting: "pinecall agent set --greeting '…' (or --reply '…')",
|
|
23
|
-
hangup: "pinecall agent set --hangup '…'",
|
|
24
|
-
says: "pinecall lexicon add <word> --say '…'",
|
|
25
|
-
hears: "pinecall lexicon hear <word> …",
|
|
26
|
-
memory: "pinecall memory policy --remember '…' --forget '…'",
|
|
27
|
-
record: "pinecall agent set --record on|off",
|
|
28
|
-
knowledge: "pinecall agent knowledge edit — what the agent knows by heart is a setting, not a file",
|
|
29
|
-
docs: "pinecall docs push, then pinecall docs attach <base>"
|
|
30
|
-
}.freeze
|
|
15
|
+
# The settings a class may declare. Must match the TypeScript package's `ENVIRONMENT`.
|
|
16
|
+
ENVIRONMENT = %i[language voice llm stt greeting hangup turn says hears knowledge docs memory record].freeze
|
|
17
|
+
|
|
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
|
|
20
|
+
|
|
21
|
+
NO_VOICE = "a voice the class declares names its vendor and the voice: voice \"<vendor>\", \"<voice id>\""
|
|
31
22
|
|
|
32
23
|
NOTHING = Object.new.freeze
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
# `vendor/model`, or a vendor alone; the model id keeps every slash after the vendor's.
|
|
26
|
+
def self.model_of(named)
|
|
27
|
+
provider, _slash, model = named.to_s.partition("/")
|
|
28
|
+
{ provider:, model: }
|
|
36
29
|
end
|
|
37
30
|
|
|
38
31
|
module Declaring
|
|
@@ -45,13 +38,61 @@ module Pinecall
|
|
|
45
38
|
end
|
|
46
39
|
end
|
|
47
40
|
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
# The voice, by its vendor and the vendor's own id for it. Declared, it wins over the
|
|
42
|
+
# agent's settings; `builds` and `options` reach the vendor's plugin.
|
|
43
|
+
def voice(provider = NOTHING, voice_id = nil, model: nil, builds: nil, options: nil)
|
|
44
|
+
return environment[:voice] if provider.equal?(NOTHING)
|
|
45
|
+
raise DeclarationRefused, NO_VOICE if voice_id.nil?
|
|
46
|
+
|
|
47
|
+
environment[:voice] = { provider:, voice_id:, model:, builds:, options: }.compact
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The model that answers, `vendor/model` or a vendor alone:
|
|
51
|
+
# `llm "openai/gpt-5.4-mini", builds: "responses.LLM", options: { use_websocket: true }`.
|
|
52
|
+
def llm(model = NOTHING, temperature: nil, builds: nil, options: nil)
|
|
53
|
+
return environment[:llm] if model.equal?(NOTHING)
|
|
54
|
+
|
|
55
|
+
environment[:llm] = { **Config.model_of(model), temperature:, builds:, options: }.compact
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The ears, `vendor/model` or a vendor alone.
|
|
59
|
+
def stt(model = NOTHING, builds: nil, options: nil)
|
|
60
|
+
return environment[:stt] if model.equal?(NOTHING)
|
|
61
|
+
|
|
62
|
+
environment[:stt] = { **Config.model_of(model), builds:, options: }.compact
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# `language "es"`, `says [{ word: "GSA", spoken: "ge ese a" }]`, `record false`.
|
|
66
|
+
%i[language says record].each do |field|
|
|
67
|
+
define_method(field) do |value = NOTHING|
|
|
68
|
+
return environment[field] if value.equal?(NOTHING)
|
|
69
|
+
|
|
70
|
+
environment[field] = value
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The words the ears must know: `hears "Vidal", "Sanitas"`.
|
|
75
|
+
def hears(*words)
|
|
76
|
+
return environment[:hears] if words.empty?
|
|
77
|
+
|
|
78
|
+
environment[:hears] = words.flatten
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# `greeting say: "…"`, `hangup when: "…"`, `turn endpointing_ms: 300`, `docs base: "…", k: 4`,
|
|
82
|
+
# `memory remember: […], forget: […]`, `knowledge path: "…", text: "…"`.
|
|
83
|
+
AS_KEYWORDS.each do |field|
|
|
84
|
+
define_method(field) do |**given|
|
|
85
|
+
return environment[field] if given.empty?
|
|
86
|
+
|
|
87
|
+
environment[field] = given
|
|
52
88
|
end
|
|
53
89
|
end
|
|
54
90
|
|
|
91
|
+
# What the class declares of its environment, including inherited values.
|
|
92
|
+
def environment
|
|
93
|
+
@environment ||= superclass.respond_to?(:environment) ? superclass.environment.dup : {}
|
|
94
|
+
end
|
|
95
|
+
|
|
55
96
|
# Set the class docstring explicitly, for classes with no source file.
|
|
56
97
|
def doc(text = NOTHING)
|
|
57
98
|
return Doc.for_class(self) if text.equal?(NOTHING)
|
|
@@ -84,9 +125,10 @@ module Pinecall
|
|
|
84
125
|
@slug = name
|
|
85
126
|
end
|
|
86
127
|
|
|
87
|
-
# The AgentConfig sent to the gateway.
|
|
128
|
+
# The AgentConfig sent to the gateway: the contract, and the environment the class declares.
|
|
88
129
|
def wire_config(tools: nil)
|
|
89
130
|
{
|
|
131
|
+
**environment,
|
|
90
132
|
prompt: Prompt::FRAMEWORK,
|
|
91
133
|
tools:,
|
|
92
134
|
state_fields: state_field_specs,
|
data/lib/pinecall/version.rb
CHANGED
|
@@ -14,12 +14,16 @@ module Pinecall
|
|
|
14
14
|
name: { kind: :str },
|
|
15
15
|
provider: { kind: :str },
|
|
16
16
|
model: { kind: :str },
|
|
17
|
-
voice_id: { kind: :str }
|
|
17
|
+
voice_id: { kind: :str },
|
|
18
|
+
builds: { kind: :str },
|
|
19
|
+
options: { kind: :json }
|
|
18
20
|
}.freeze,
|
|
19
21
|
"ModelConfig" => {
|
|
20
22
|
provider: { kind: :str, required: true },
|
|
21
23
|
model: { kind: :str, required: true },
|
|
22
|
-
temperature: { kind: :float }
|
|
24
|
+
temperature: { kind: :float },
|
|
25
|
+
builds: { kind: :str },
|
|
26
|
+
options: { kind: :json }
|
|
23
27
|
}.freeze,
|
|
24
28
|
"TurnConfig" => {
|
|
25
29
|
min_interruption_words: { kind: :int },
|
|
@@ -18,6 +18,7 @@ module Pinecall
|
|
|
18
18
|
}.freeze,
|
|
19
19
|
"AgentConfig" => {
|
|
20
20
|
prompt: { kind: :list, items: { kind: :ref, ref: "PromptBlockSpec" } },
|
|
21
|
+
language: { kind: :str },
|
|
21
22
|
greeting: { kind: :ref, ref: "GreetingConfig" },
|
|
22
23
|
voice: { kind: :ref, ref: "VoiceConfig" },
|
|
23
24
|
llm: { kind: :ref, ref: "ModelConfig" },
|
data/sig/pinecall.rbs
CHANGED
|
@@ -84,18 +84,21 @@ module Pinecall
|
|
|
84
84
|
def self.panel: (?String) { (Panel::Who) -> void } -> Panel::Declared
|
|
85
85
|
def self.declared_panel: () -> Panel::Declared?
|
|
86
86
|
|
|
87
|
-
# the
|
|
88
|
-
def self.voice: (
|
|
89
|
-
def self.llm: (
|
|
90
|
-
def self.stt: (
|
|
91
|
-
def self.
|
|
92
|
-
def self.
|
|
93
|
-
def self.
|
|
94
|
-
def self.hears: (*
|
|
95
|
-
def self.
|
|
96
|
-
def self.
|
|
97
|
-
def self.
|
|
98
|
-
def self.
|
|
87
|
+
# the environment the class declares, each over the agent's settings
|
|
88
|
+
def self.voice: (?String, ?String?, ?model: String?, ?builds: String?, ?options: Hash[untyped, untyped]?) -> untyped
|
|
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
|
|
91
|
+
def self.language: (?String) -> untyped
|
|
92
|
+
def self.says: (?Array[Hash[Symbol, String]]) -> untyped
|
|
93
|
+
def self.record: (?bool) -> untyped
|
|
94
|
+
def self.hears: (*String | Array[String]) -> untyped
|
|
95
|
+
def self.greeting: (**untyped) -> untyped
|
|
96
|
+
def self.hangup: (**untyped) -> untyped
|
|
97
|
+
def self.turn: (**untyped) -> untyped
|
|
98
|
+
def self.knowledge: (**untyped) -> untyped
|
|
99
|
+
def self.docs: (**untyped) -> untyped
|
|
100
|
+
def self.memory: (**untyped) -> untyped
|
|
101
|
+
def self.environment: () -> Hash[Symbol, untyped]
|
|
99
102
|
|
|
100
103
|
def self.doc: (?String) -> String?
|
|
101
104
|
def self.slug: (?String) -> String
|