pinecall-protocol 0.3.0__tar.gz → 0.6.2__tar.gz

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.
Files changed (25) hide show
  1. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/PKG-INFO +1 -1
  2. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/_version.py +1 -1
  3. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/commands.py +1 -0
  4. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/defs.py +11 -8
  5. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/events.py +1 -0
  6. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/rest.py +317 -2
  7. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/.gitignore +0 -0
  8. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/.python-version +0 -0
  9. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/LICENSE +0 -0
  10. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/README.md +0 -0
  11. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/__init__.py +0 -0
  12. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/_base.py +0 -0
  13. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/codec.py +0 -0
  14. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/envelope.py +0 -0
  15. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/__init__.py +0 -0
  16. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/call-log-golden.json +0 -0
  17. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/call-log-golden.state.json +0 -0
  18. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/metrics.py +0 -0
  19. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/py.typed +0 -0
  20. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/registry.py +0 -0
  21. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/room.py +0 -0
  22. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/state.py +0 -0
  23. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/verbs.py +0 -0
  24. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pyproject.toml +0 -0
  25. {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pinecall-protocol
3
- Version: 0.3.0
3
+ Version: 0.6.2
4
4
  Summary: The Pinecall wire: pydantic models generated from the protocol schema
5
5
  Author-email: Bernardo Castro <me@bernardocastro.dev>
6
6
  License-Expression: Apache-2.0
@@ -1,4 +1,4 @@
1
1
  """The one place the version lives; hatch reads it from here at build time."""
2
2
 
3
3
  # 0.0.0 means "unreleased". The number is the maintainer's call and is never bumped from code.
4
- __version__ = "0.3.0"
4
+ __version__ = "0.6.2"
@@ -23,6 +23,7 @@ class AgentRegister(WireModel):
23
23
 
24
24
  routes: list[Route]
25
25
  sdk: str | None = None
26
+ host: str | None = None
26
27
  takes_unclaimed: bool = True
27
28
 
28
29
 
@@ -25,16 +25,15 @@ type Env = Literal["production", "sandbox"]
25
25
 
26
26
 
27
27
  # What a console may ask of the process standing in the agent's directory, relayed by the gateway: a
28
- # written call to the class mounted there (chat), a simulated caller from its personas, its goldens
29
- # and a suite of them, its knowledge folder pushed or its golden asked, its memory goldens, a call
30
- # promoted to a candidate file, the drift of the last two windows, and the reproductions a broken
31
- # run left on that disk. Everything else a console needs is a door of the gateway.
28
+ # written call to the class mounted there (chat), a simulated caller put on the class it holds, its
29
+ # goldens and a suite of them, its knowledge folder pushed or its golden asked, its memory goldens,
30
+ # a call promoted to a candidate file, the drift of the last two windows, and the reproductions a
31
+ # broken run left on that disk. Everything else a console needs is a door of the gateway.
32
32
  type DevVerb = Literal[
33
33
  "chat.roster",
34
34
  "chat.start",
35
35
  "chat.say",
36
36
  "chat.end",
37
- "simulate.roster",
38
37
  "simulate.start",
39
38
  "goldens.roster",
40
39
  "goldens.run",
@@ -337,7 +336,7 @@ class EventSpec(WireModel):
337
336
 
338
337
 
339
338
  class KnowledgeFile(WireModel):
340
- """One file of knowledge, sent whole: its path as the tenant keeps it, and its text."""
339
+ """One file of a base, as a push sends it: its path as the tenant keeps it, and its text."""
341
340
 
342
341
  path: str
343
342
  text: str
@@ -384,8 +383,11 @@ class MemoryConfig(WireModel):
384
383
  forget: list[str] = Field(default_factory=list[str])
385
384
 
386
385
 
387
- # What an app declares about its agent: the voice, the models, the language, the greeting, the
388
- # tools, and who may see and send what. Every field is optional so a configure can change one thing.
386
+ # What an app declares about its agent: the prompt's layout, the language, the tools, whether it
387
+ # searches its bases itself, and who may see and send what. Every field is optional so a configure
388
+ # can change one thing. The environment — voice, models, greeting, hangup, turn, says, hears,
389
+ # knowledge, docs, memory — is the world's, set in the agent's settings, and no longer read off this
390
+ # declaration.
389
391
  class AgentConfig(WireModel):
390
392
  """What an app declares about its agent."""
391
393
 
@@ -403,5 +405,6 @@ class AgentConfig(WireModel):
403
405
  memory: MemoryConfig | None = None
404
406
  hangup: HangupConfig | None = None
405
407
  tools: list[ToolSpec] | None = None
408
+ uses_knowledge: bool = False
406
409
  state_fields: list[StateFieldSpec] | None = None
407
410
  events: list[EventSpec] | None = None
@@ -159,6 +159,7 @@ class CallStarted(WireModel):
159
159
  from_: str = Field(alias="from")
160
160
  to: str
161
161
  run: str | None = None
162
+ persona: str | None = None
162
163
  caller: Contact | None
163
164
  started_at: float
164
165
  env: Env | None = None
@@ -10,10 +10,16 @@ from pinecall_protocol.defs import (
10
10
  Contact,
11
11
  Cost,
12
12
  Direction,
13
+ DocsConfig,
13
14
  EndReason,
14
15
  Env,
16
+ GreetingConfig,
17
+ HangupConfig,
15
18
  KnowledgeFile,
19
+ MemoryConfig,
16
20
  PlatformTool,
21
+ Pronunciation,
22
+ TurnConfig,
17
23
  )
18
24
  from pinecall_protocol.envelope import Entry
19
25
  from pinecall_protocol.state import CallStatus, State
@@ -412,6 +418,38 @@ class AgentList(WireModel):
412
418
  agents: list[HeldAgent]
413
419
 
414
420
 
421
+ # One app connected to the gateway right now: one process on one machine, holding one or more agents
422
+ # in one world.
423
+ class AppProcess(WireModel):
424
+ """One app connected to the gateway right now."""
425
+
426
+ app: str
427
+ agents: list[str]
428
+ env: Env
429
+ host: str | None
430
+ address: str | None
431
+ sdk: str | None
432
+ holder: LineHolder | None
433
+ connected_at: float
434
+
435
+
436
+ # GET /v1/apps: every app connected in the request's world that this key may see — its own corner's
437
+ # and the org's, every corner's with `team`.
438
+ class AppList(WireModel):
439
+ """GET /v1/apps."""
440
+
441
+ apps: list[AppProcess]
442
+
443
+
444
+ # POST /v1/apps/{app}/stop, the answer: the socket was closed with the stop code, and the app exits
445
+ # rather than reconnect.
446
+ class AppStopped(WireModel):
447
+ """POST /v1/apps/{app}/stop, the answer."""
448
+
449
+ app: str
450
+ stopped: bool
451
+
452
+
415
453
  # GET /v1/agents/{slug}/line: whose terminal a call that RINGS at this agent's doors lands in. An
416
454
  # org shares one sandbox number, so it rings in one place and which one is claimed.
417
455
  class TheLine(WireModel):
@@ -643,8 +681,9 @@ class ExtractionRun(WireModel):
643
681
 
644
682
 
645
683
  # POST /v1/calls/{call}/lookup, the body: which platform tool to run for this turn, and what to run
646
- # it with. Worker-only; the gateway runs it against its own stores and writes memory.ops or
647
- # docs.sources on the call's log itself.
684
+ # it with. Asked by the worker for the call it serves, and by the app for a call of its own org —
685
+ # `this.knowledge.search` in a tool; the gateway runs it against its own stores and writes
686
+ # memory.ops or docs.sources on the call's log itself.
648
687
  class LookupRequest(WireModel):
649
688
  """POST /v1/calls/{call}/lookup, the body."""
650
689
 
@@ -663,6 +702,22 @@ class LookupResult(WireModel):
663
702
  took_ms: float
664
703
 
665
704
 
705
+ class FoundChunk(WireModel):
706
+ """One chunk search found: the file it came from, the heading it sits under, and its text."""
707
+
708
+ path: str
709
+ heading: str | None
710
+ text: str
711
+
712
+
713
+ # What search answers in a lookup's output: the best chunks of every base the agent reads, the best
714
+ # first. The app's `this.knowledge.search` hands the chunks to the tool that asked.
715
+ class SearchFound(WireModel):
716
+ """What search answers in a lookup's output."""
717
+
718
+ chunks: list[FoundChunk]
719
+
720
+
666
721
  # POST /v1/calls/{call}/remember, the answer: what the call taught about the contact, counted.
667
722
  # Worker-only; the body is empty, the gateway reads the turns off its own log and writes memory.ops
668
723
  # itself.
@@ -713,3 +768,263 @@ class OutboundProvisioned(WireModel):
713
768
  ready: bool
714
769
  trunk: str | None = None
715
770
  address: str | None = None
771
+
772
+
773
+ # Every field is optional; one left out is not set, and the runtime's own default stands for it.
774
+ class TuningBody(WireModel):
775
+ """An agent's settings: what the org set, per world and per corner."""
776
+
777
+ voice: str | None = None
778
+ tts: str | None = None
779
+ tts_model: str | None = None
780
+ stt: str | None = None
781
+ llm: str | None = None
782
+ greeting: GreetingConfig | None = None
783
+ hangup: HangupConfig | None = None
784
+ turn: TurnConfig | None = None
785
+ memory: MemoryConfig | None = None
786
+ knowledge: str | None = None
787
+ bases: list[DocsConfig] | None = None
788
+
789
+
790
+ # One kept version of an agent's tuning: whose corner, which version, who set it and when, and what
791
+ # it says.
792
+ class TuningRow(WireModel):
793
+ """One kept version of an agent's tuning."""
794
+
795
+ holder: str
796
+ version: int
797
+ author: str
798
+ note: str | None
799
+ set_at: float
800
+ config: TuningBody
801
+
802
+
803
+ # GET /v1/agents/{slug}/settings: the agent's tuning as this key sees it — its own corner's, the
804
+ # team's and production's, each corner's own newest row, or null when that corner set nothing.
805
+ class TuningAnswer(WireModel):
806
+ """GET /v1/agents/{slug}/settings."""
807
+
808
+ world: Env
809
+ yours: TuningRow | None
810
+ team: TuningRow | None
811
+ production: TuningRow | None
812
+
813
+
814
+ # PUT /v1/agents/{slug}/settings, the body: the whole set, the version it was read at, why, and
815
+ # whose corner.
816
+ class TuningPut(WireModel):
817
+ """PUT /v1/agents/{slug}/settings, the body."""
818
+
819
+ config: TuningBody
820
+ if_version: int | None = None
821
+ note: str | None = None
822
+ team: bool = False
823
+
824
+
825
+ class TuningHistory(WireModel):
826
+ """GET /v1/agents/{slug}/settings/history: one corner's versions, newest first."""
827
+
828
+ world: Env
829
+ holder: str
830
+ rows: list[TuningRow]
831
+
832
+
833
+ # GET /v1/agents/{slug}/settings/diff: what this key's corner reads against another corner's newest,
834
+ # and which fields differ.
835
+ class TuningDiff(WireModel):
836
+ """GET /v1/agents/{slug}/settings/diff."""
837
+
838
+ ours: TuningRow | None
839
+ theirs: TuningRow | None
840
+ changed: list[str]
841
+
842
+
843
+ # It comes back as a NEW version; nothing is deleted.
844
+ class Rollback(WireModel):
845
+ """POST /v1/agents/{slug}/settings/rollback, the body: which version to bring back."""
846
+
847
+ version: int
848
+ team: bool = False
849
+
850
+
851
+ # The org's lexicon: how the voice says the words it would get wrong, and the words the ears must
852
+ # know. Shared by every agent of the org, laid over each one's own says and hears.
853
+ class LexiconBody(WireModel):
854
+ """The org's lexicon."""
855
+
856
+ said: list[Pronunciation]
857
+ heard: list[str]
858
+
859
+
860
+ class LexiconRow(WireModel):
861
+ """One kept version of the org's lexicon."""
862
+
863
+ holder: str
864
+ version: int
865
+ author: str
866
+ note: str | None
867
+ set_at: float
868
+ lexicon: LexiconBody
869
+
870
+
871
+ # GET /v1/lexicon: the org's words as this key sees them — its own corner's, the team's and
872
+ # production's, each corner's own newest, or null.
873
+ class LexiconAnswer(WireModel):
874
+ """GET /v1/lexicon."""
875
+
876
+ world: Env
877
+ yours: LexiconRow | None
878
+ team: LexiconRow | None
879
+ production: LexiconRow | None
880
+
881
+
882
+ # PUT /v1/lexicon, the body: the whole lexicon, the version it was read at, why, and whose corner.
883
+ class LexiconPut(WireModel):
884
+ """PUT /v1/lexicon, the body."""
885
+
886
+ lexicon: LexiconBody
887
+ if_version: int | None = None
888
+ note: str | None = None
889
+ team: bool = False
890
+
891
+
892
+ class LexiconHistory(WireModel):
893
+ """GET /v1/lexicon/history: one corner's versions, newest first."""
894
+
895
+ world: Env
896
+ holder: str
897
+ rows: list[LexiconRow]
898
+
899
+
900
+ # GET /v1/calls/{call}/settings: the exact tuning and lexicon a call was built on, by the versions
901
+ # its head row recorded.
902
+ class CallTuning(WireModel):
903
+ """GET /v1/calls/{call}/settings."""
904
+
905
+ config_version: int | None
906
+ lexicon_version: int | None
907
+ config: TuningRow | None
908
+ lexicon: LexiconRow | None
909
+
910
+
911
+ class KnowledgeFileRow(WireModel):
912
+ """One file of a base as the list draws it."""
913
+
914
+ path: str
915
+ chars: int
916
+ chunks: int
917
+ pushed_at: float
918
+
919
+
920
+ # GET /v1/knowledge/{base}: every file of the base, by path, with its size and what it became. Never
921
+ # the text: one file is read at a time.
922
+ class KnowledgeFiles(WireModel):
923
+ """GET /v1/knowledge/{base}."""
924
+
925
+ base: str
926
+ kept: bool
927
+ files: list[KnowledgeFileRow]
928
+
929
+
930
+ class KnowledgeFileRead(WireModel):
931
+ """GET /v1/knowledge/{base}/files/{path}: one file, text and all."""
932
+
933
+ path: str
934
+ text: str
935
+ chunks: int
936
+ pushed_at: float
937
+
938
+
939
+ # New under that path, or replaced in place; the base is begun when there is none.
940
+ class KnowledgeFilePut(WireModel):
941
+ """PUT /v1/knowledge/{base}/files/{path}, the body: the file's whole text."""
942
+
943
+ text: str
944
+
945
+
946
+ # PUT /v1/knowledge/{base}/files/{path}, the answer: which file, how many chunks it became, and how
947
+ # long that took.
948
+ class KnowledgeFilePushed(WireModel):
949
+ """PUT /v1/knowledge/{base}/files/{path}, the answer."""
950
+
951
+ base: str
952
+ path: str
953
+ chunks: int
954
+ took_ms: float
955
+
956
+
957
+ class KnowledgeUse(WireModel):
958
+ """One base and the agents whose settings attach it."""
959
+
960
+ base: str
961
+ agents: list[str]
962
+
963
+
964
+ # GET /v1/knowledge/attached: which agents read each base, off every agent's newest settings in this
965
+ # world.
966
+ class KnowledgeUses(WireModel):
967
+ """GET /v1/knowledge/attached."""
968
+
969
+ bases: list[KnowledgeUse]
970
+
971
+
972
+ # One synthetic caller of an ORG, kept by the gateway: what they want, how they talk, and what they
973
+ # may state about themselves. A model plays them turn by turn — there is no script — for `pinecall
974
+ # simulate` and the console's Simulations. A caller is a person on the phone, so who they are does
975
+ # not depend on which of the org's agents answers: every agent of the org calls with the same list.
976
+ class Persona(WireModel):
977
+ """One synthetic caller of an ORG, kept by the gateway."""
978
+
979
+ name: str
980
+ about: str
981
+ goal: str
982
+ style: str
983
+ facts: dict[str, str]
984
+ state: dict[str, Any]
985
+ author: str
986
+ set_at: float
987
+
988
+
989
+ # The same list for every agent of the org, and the same one in both worlds.
990
+ class PersonaList(WireModel):
991
+ """GET /v1/personas: every caller the org wrote, by name."""
992
+
993
+ personas: list[Persona]
994
+
995
+
996
+ # A name that exists is replaced; `was` renames the caller it names.
997
+ class PersonaPut(WireModel):
998
+ """PUT /v1/personas/{name}, the body: the caller, written whole."""
999
+
1000
+ about: str | None = None
1001
+ goal: str
1002
+ style: str
1003
+ facts: dict[str, str] | None = None
1004
+ state: dict[str, Any] | None = None
1005
+ was: str | None = None
1006
+
1007
+
1008
+ # Read off the call index, never off a log — the same row the sessions list is drawn from.
1009
+ class PersonaRun(WireModel):
1010
+ """One simulation this caller has run: the call it was, and what the call came to."""
1011
+
1012
+ call: str
1013
+ agent: str
1014
+ started_at: float
1015
+ ended_at: float | None
1016
+ turns: int
1017
+ end_reason: EndReason | None
1018
+ outcome: str | None
1019
+ cost_eur: float | None
1020
+ score: SessionScore | None
1021
+
1022
+
1023
+ # GET /v1/personas/{name}/runs, in the key's own world and corner, paged exactly as the sessions
1024
+ # list is.
1025
+ class PersonaRunList(WireModel):
1026
+ """Every simulation this caller has run, newest first, a page at a time."""
1027
+
1028
+ runs: list[PersonaRun]
1029
+ total: int
1030
+ next: str | None