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.
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/PKG-INFO +1 -1
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/_version.py +1 -1
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/commands.py +1 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/defs.py +11 -8
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/events.py +1 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/rest.py +317 -2
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/.gitignore +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/.python-version +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/LICENSE +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/README.md +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/__init__.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/_base.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/codec.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/envelope.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/__init__.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/call-log-golden.json +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/call-log-golden.state.json +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/metrics.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/py.typed +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/registry.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/room.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/state.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/verbs.py +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pyproject.toml +0 -0
- {pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/uv.lock +0 -0
|
@@ -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
|
|
29
|
-
# and a suite of them, its knowledge folder pushed or its golden asked, its memory goldens,
|
|
30
|
-
# promoted to a candidate file, the drift of the last two windows, and the reproductions a
|
|
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
|
|
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
|
|
388
|
-
#
|
|
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
|
|
@@ -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.
|
|
647
|
-
#
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pinecall_protocol-0.3.0 → pinecall_protocol-0.6.2}/pinecall_protocol/fixtures/call-log-golden.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|