pi-python-core 0.8.1__py3-none-any.whl
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.
- pi_python/__init__.py +160 -0
- pi_python/_version.py +1 -0
- pi_python/agent.py +396 -0
- pi_python/cancellation.py +24 -0
- pi_python/data/models.json +3315 -0
- pi_python/errors.py +49 -0
- pi_python/estimate.py +144 -0
- pi_python/events.py +138 -0
- pi_python/function_tools.py +438 -0
- pi_python/hooks.py +44 -0
- pi_python/limits.py +28 -0
- pi_python/loop.py +431 -0
- pi_python/lowlevel.py +179 -0
- pi_python/mcp.py +187 -0
- pi_python/messages.py +405 -0
- pi_python/models.py +155 -0
- pi_python/provider.py +123 -0
- pi_python/providers/__init__.py +21 -0
- pi_python/providers/anthropic.py +673 -0
- pi_python/providers/common.py +201 -0
- pi_python/providers/completions.py +1149 -0
- pi_python/providers/oauth.py +542 -0
- pi_python/providers/openai.py +681 -0
- pi_python/providers/transport.py +574 -0
- pi_python/proxy.py +304 -0
- pi_python/py.typed +0 -0
- pi_python/queues.py +76 -0
- pi_python/recovery.py +209 -0
- pi_python/run.py +419 -0
- pi_python/stream.py +251 -0
- pi_python/sync.py +78 -0
- pi_python/testing.py +25 -0
- pi_python/tools.py +546 -0
- pi_python/transcript.py +167 -0
- pi_python_core-0.8.1.dist-info/METADATA +119 -0
- pi_python_core-0.8.1.dist-info/RECORD +39 -0
- pi_python_core-0.8.1.dist-info/WHEEL +4 -0
- pi_python_core-0.8.1.dist-info/licenses/LICENSE +21 -0
- pi_python_core-0.8.1.dist-info/licenses/NOTICE +8 -0
pi_python/transcript.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""System replay adapted from Pi a13d35a (MIT); see NOTICE."""
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from .messages import Message, SystemMessage, TextContent, ToolDeclaration
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def system_text(content: str | list[TextContent]) -> str:
|
|
8
|
+
"""Pi's contentText: text blocks of one message joined by a single newline."""
|
|
9
|
+
return content if isinstance(content, str) else "\n".join(b.text for b in content)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def system_message_text(message: SystemMessage) -> str:
|
|
13
|
+
"""A complete prompt: content followed by the sections that are set."""
|
|
14
|
+
parts = [system_text(message.content), *(v for v in message.sections.values() if v is not None)]
|
|
15
|
+
return "\n\n".join(p for p in parts if p)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def render_system_update(message: SystemMessage) -> str:
|
|
19
|
+
"""A later system message as sent in place; section changes are framed by name."""
|
|
20
|
+
parts = [system_text(message.content)] if system_text(message.content) else []
|
|
21
|
+
for name, value in message.sections.items():
|
|
22
|
+
parts.append(
|
|
23
|
+
f'Removed system prompt section "{name}".'
|
|
24
|
+
if value is None
|
|
25
|
+
else f'Updated system prompt section "{name}":\n\n{value}'
|
|
26
|
+
)
|
|
27
|
+
return "\n\n".join(parts)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def current_tools(messages: list[Message]) -> list[ToolDeclaration]:
|
|
31
|
+
tools: dict[str, ToolDeclaration] = {}
|
|
32
|
+
for m in messages:
|
|
33
|
+
if isinstance(m, SystemMessage):
|
|
34
|
+
for name in m.tools_removed:
|
|
35
|
+
tools.pop(name, None)
|
|
36
|
+
for tool in m.tools_added:
|
|
37
|
+
tools[tool.name] = tool
|
|
38
|
+
return deepcopy(list(tools.values()))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def current_system_message(messages: list[Message]) -> SystemMessage | None:
|
|
42
|
+
systems = [m for m in messages if isinstance(m, SystemMessage)]
|
|
43
|
+
if not systems:
|
|
44
|
+
return None
|
|
45
|
+
sections: dict[str, str | None] = {}
|
|
46
|
+
for m in systems:
|
|
47
|
+
for name, text in m.sections.items():
|
|
48
|
+
if text is None:
|
|
49
|
+
sections.pop(name, None)
|
|
50
|
+
else:
|
|
51
|
+
sections[name] = text
|
|
52
|
+
return SystemMessage(
|
|
53
|
+
"\n\n".join(system_text(m.content) for m in systems if system_text(m.content)),
|
|
54
|
+
sections,
|
|
55
|
+
current_tools(messages),
|
|
56
|
+
timestamp=systems[0].timestamp,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def current_system_prompt(messages: list[Message]) -> str:
|
|
61
|
+
m = current_system_message(messages)
|
|
62
|
+
return system_message_text(m) if m else ""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def initial_system_message(messages: list[Message]) -> SystemMessage | None:
|
|
66
|
+
return messages[0] if messages and isinstance(messages[0], SystemMessage) else None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def collapse_system_messages(messages: list[Message]) -> list[Message]:
|
|
70
|
+
"""For APIs without mid-conversation system messages: one replayed leading message."""
|
|
71
|
+
head = current_system_message(messages)
|
|
72
|
+
rest: list[Message] = [deepcopy(m) for m in messages if not isinstance(m, SystemMessage)]
|
|
73
|
+
return [head, *rest] if head else rest
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def resolve_transcript(messages: list[Message], mid_conversation: bool) -> list[Message]:
|
|
77
|
+
return deepcopy(messages) if mid_conversation else collapse_system_messages(messages)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def declared_tools(messages: list[Message]) -> list[ToolDeclaration]:
|
|
81
|
+
"""Every definition referenced by transcript tool state, in first-declaration order."""
|
|
82
|
+
tools: dict[str, ToolDeclaration] = {}
|
|
83
|
+
for m in messages:
|
|
84
|
+
if isinstance(m, SystemMessage):
|
|
85
|
+
for tool in m.tools_added:
|
|
86
|
+
tools[tool.name] = tool
|
|
87
|
+
return deepcopy(list(tools.values()))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def has_tool_redefinitions(messages: list[Message]) -> bool:
|
|
91
|
+
"""A name declared twice with different definitions cannot be referenced by name."""
|
|
92
|
+
seen: dict[str, ToolDeclaration] = {}
|
|
93
|
+
for m in messages:
|
|
94
|
+
if isinstance(m, SystemMessage):
|
|
95
|
+
for tool in m.tools_added:
|
|
96
|
+
if tool.name in seen and seen[tool.name] != tool:
|
|
97
|
+
return True
|
|
98
|
+
seen[tool.name] = tool
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def has_non_additive_tool_changes(messages: list[Message]) -> bool:
|
|
103
|
+
"""A removal or same-name redeclaration that an addition-only transport cannot replay."""
|
|
104
|
+
seen: set[str] = set()
|
|
105
|
+
for m in messages:
|
|
106
|
+
if isinstance(m, SystemMessage):
|
|
107
|
+
if m.tools_removed:
|
|
108
|
+
return True
|
|
109
|
+
for tool in m.tools_added:
|
|
110
|
+
if tool.name in seen:
|
|
111
|
+
return True
|
|
112
|
+
seen.add(tool.name)
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def resolve_transcript_tools(
|
|
117
|
+
messages: list[Message], supports_additions: bool
|
|
118
|
+
) -> tuple[list[ToolDeclaration], bool]:
|
|
119
|
+
"""Top-level request tools, and whether later additions are anchored in place."""
|
|
120
|
+
anchors = supports_additions and not has_non_additive_tool_changes(messages)
|
|
121
|
+
initial = initial_system_message(messages)
|
|
122
|
+
tools = (
|
|
123
|
+
(deepcopy(initial.tools_added) if initial else []) if anchors else current_tools(messages)
|
|
124
|
+
)
|
|
125
|
+
return tools, anchors
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def with_request_tools(messages: list[Message], tools: list[ToolDeclaration]) -> list[Message]:
|
|
129
|
+
"""Pi's normalizeContext: fold request-level tools into the leading system message.
|
|
130
|
+
|
|
131
|
+
Requests built by Agent already carry their tools in the transcript; this covers a
|
|
132
|
+
direct Provider call that passes `tools` without declaring them in system messages.
|
|
133
|
+
"""
|
|
134
|
+
if not tools or any(isinstance(m, SystemMessage) and m.tools_added for m in messages):
|
|
135
|
+
return deepcopy(messages)
|
|
136
|
+
messages = deepcopy(messages)
|
|
137
|
+
head = initial_system_message(messages)
|
|
138
|
+
if head is None:
|
|
139
|
+
return [SystemMessage(tools_added=deepcopy(tools), timestamp=0), *messages]
|
|
140
|
+
head.tools_added = deepcopy(tools)
|
|
141
|
+
return messages
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def declare_tool_changes(
|
|
145
|
+
history: list[Message], pending: list[Message], tools: list[ToolDeclaration]
|
|
146
|
+
) -> list[Message]:
|
|
147
|
+
pending = deepcopy(pending)
|
|
148
|
+
systems = [i for i, m in enumerate(pending) if isinstance(m, SystemMessage)]
|
|
149
|
+
index = systems[-1] if systems else None
|
|
150
|
+
if index is not None:
|
|
151
|
+
m = pending[index]
|
|
152
|
+
assert isinstance(m, SystemMessage)
|
|
153
|
+
m.tools_added, m.tools_removed = [], []
|
|
154
|
+
previous = {t.name: t for t in current_tools(history + pending)}
|
|
155
|
+
current = {t.name: t for t in tools}
|
|
156
|
+
added = [t for t in tools if previous.get(t.name) != t]
|
|
157
|
+
removed = [name for name, t in previous.items() if current.get(name) != t]
|
|
158
|
+
if index is not None:
|
|
159
|
+
m = pending[index]
|
|
160
|
+
assert isinstance(m, SystemMessage)
|
|
161
|
+
m.tools_added, m.tools_removed = deepcopy(added), removed
|
|
162
|
+
elif added or removed:
|
|
163
|
+
index = next(
|
|
164
|
+
(i for i, m in enumerate(pending) if not isinstance(m, SystemMessage)), len(pending)
|
|
165
|
+
)
|
|
166
|
+
pending.insert(index, SystemMessage(tools_added=deepcopy(added), tools_removed=removed))
|
|
167
|
+
return pending
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pi-python-core
|
|
3
|
+
Version: 0.8.1
|
|
4
|
+
Summary: An embeddable asyncio agent core with opt-in Claude and OpenAI providers
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
License-File: NOTICE
|
|
8
|
+
Classifier: Framework :: AsyncIO
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: jsonschema<5,>=4.18
|
|
22
|
+
Provides-Extra: mcp
|
|
23
|
+
Requires-Dist: mcp>=1.10; extra == 'mcp'
|
|
24
|
+
Provides-Extra: providers
|
|
25
|
+
Requires-Dist: httpx<1,>=0.27; extra == 'providers'
|
|
26
|
+
Requires-Dist: pyjwt[crypto]<3,>=2.8; extra == 'providers'
|
|
27
|
+
Requires-Dist: websockets>=14.2; extra == 'providers'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# pi-python-core
|
|
31
|
+
|
|
32
|
+
一个可嵌入的 Python agent 核心,移植自 [Pi](https://github.com/earendil-works/pi)(固定参照 `v1.0.0`)。它负责一件事:把对话发给模型,执行模型要求的工具,把结果交回模型,直到得到回答。工具就是普通的 Python 函数;模型可以是 Claude、GPT、DeepSeek,也可以是本机或集群上的开源模型。
|
|
33
|
+
|
|
34
|
+
PyPI 上的 `pi-agent-core` 是另一个独立项目,移植的是 2026 年初 pi-mono 中的旧版本。本库对照 Pi v1.0.0 的行为,与上游的实际运行结果逐组比较;并自带 Claude、OpenAI、DeepSeek 和本地模型的接入,不需要安装任何模型 SDK。
|
|
35
|
+
|
|
36
|
+
## 安装
|
|
37
|
+
|
|
38
|
+
支持 Python 3.11–3.14(包括无 GIL 的 3.14t)和 PyPy 3.11,不需要 Node 或任何模型 SDK。
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install 'pi-python-core[providers]' # 或 uv add 'pi-python-core[providers]'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
安装名是 `pi-python-core`,导入名是 `pi_python`。
|
|
45
|
+
|
|
46
|
+
| 安装选项 | 带来什么 |
|
|
47
|
+
|---|---|
|
|
48
|
+
| 不加选项 | 执行核心,只依赖 `jsonschema` |
|
|
49
|
+
| `[providers]` | 真实模型接入:Claude、OpenAI、Codex、DeepSeek,以及任何 OpenAI 兼容服务(Ollama、vLLM、llama.cpp 等) |
|
|
50
|
+
| `[mcp]` | 把 MCP 服务器的工具交给 agent |
|
|
51
|
+
|
|
52
|
+
依赖写的是版本范围而不是固定版本,能和大多数已有环境共存。
|
|
53
|
+
|
|
54
|
+
## 五分钟上手
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from pi_python import Agent, tool
|
|
58
|
+
from pi_python.providers import AnthropicProvider
|
|
59
|
+
|
|
60
|
+
@tool
|
|
61
|
+
def word_count(text: str) -> int:
|
|
62
|
+
"""Count the words in a text."""
|
|
63
|
+
return len(text.split())
|
|
64
|
+
|
|
65
|
+
agent = Agent(provider=AnthropicProvider(api_key="..."), model="claude-sonnet-4-5", tools=[word_count])
|
|
66
|
+
result = agent.prompt_sync("How many words are in 'to be or not to be'?")
|
|
67
|
+
print(result.messages[-1].content[0].text)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`@tool` 从函数签名和文档字符串生成工具;普通函数和 `async` 函数都可以。在异步程序里用 `await agent.prompt(...)`。换成本地模型只改两行:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from pi_python.providers import OpenAICompletionsProvider
|
|
74
|
+
|
|
75
|
+
llm = OpenAICompletionsProvider(base_url="http://localhost:11434/v1", name="ollama")
|
|
76
|
+
agent = Agent(provider=llm, model=llm.model("qwen3:8b", context_window=40960), tools=[word_count])
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
不联网也能先跑起来:`python examples/quickstart.py`。
|
|
80
|
+
|
|
81
|
+
## 能做什么
|
|
82
|
+
|
|
83
|
+
| 需要 | 怎么做 | 示例 |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| 写工具 | `@tool` 装饰普通函数;pydantic 模型、dataclass、枚举、日期等参数自动转换;也接受手写或 MCP 生成的 JSON Schema | [quickstart](examples/quickstart.py) |
|
|
86
|
+
| 接模型 | Claude 与 GPT 的 API key 或订阅登录;DeepSeek;任何 OpenAI 兼容服务 | [local_model](examples/local_model.py),[provider_chat](examples/provider_chat.py) |
|
|
87
|
+
| 用 MCP 工具 | `async with connect_stdio(...) as tools` | [mcp_tools](examples/mcp_tools.py) |
|
|
88
|
+
| 让一个 agent 调用另一个 | 把子 agent 包成工具,取消会一路传下去 | [subagent](examples/subagent.py) |
|
|
89
|
+
| 中途干预 | `steer` 插入指导,`follow_up` 排队后续任务,`abort` 随时取消(任何线程都可以调用) | |
|
|
90
|
+
| 上下文满了、服务出错 | `is_context_overflow`、`is_retryable_error` 判断原因,`continue_run()` 重试,`transform_context` 压缩 | [recovery](examples/recovery.py) |
|
|
91
|
+
| 保存与恢复对话 | `encode_messages` / `decode_messages`,应用决定存在哪里 | [save_restore](examples/save_restore.py) |
|
|
92
|
+
| 观察与审计 | 订阅事件;执行前后的钩子可以阻止、改写工具调用 | |
|
|
93
|
+
|
|
94
|
+
除 `provider_chat` 需要真实凭据外,示例都能离线运行,不需要 API key;测试会逐个运行它们。
|
|
95
|
+
|
|
96
|
+
## 与 Pi 的关系
|
|
97
|
+
|
|
98
|
+
执行循环、事件顺序、钩子、队列、出错与取消的处理都与 Pi 一致,并用差分验证:同一组输入分别交给固定版本的上游代码和本库运行,逐项比较模型请求、工具调用、事件和最终记录。目前核心循环 25 组、模型接入 50 组、WebSocket 多轮 2 组、出错判断 44 条样例全部一致。
|
|
99
|
+
|
|
100
|
+
有几处是有意的差异,例如工具参数严格校验、不自动转换类型,返回给调用者的状态是副本;另一些是为 Python 用户加的,例如 `@tool`、同步调用、失败后直接 `continue_run()`。逐项记录见[验收映射](compat/COVERAGE.md)。Pi 放在应用层的功能(终端界面、会话文件格式、上下文压缩)不在本库核心里;压缩可以用钩子实现,示例里有完整做法。本项目使用自己的版本号,并非 Pi 官方发行版。
|
|
101
|
+
|
|
102
|
+
## 文档
|
|
103
|
+
|
|
104
|
+
- [一页看懂:五个概念和一轮的流程](docs/CONCEPTS.md)
|
|
105
|
+
- [公开 API](docs/API.md)
|
|
106
|
+
- [模型接入、订阅登录与本地模型](docs/PROVIDERS.md)
|
|
107
|
+
- [实施与验证结果](docs/IMPLEMENTATION.md)
|
|
108
|
+
- [与 Pi 的逐项对照和有意差异](compat/COVERAGE.md)
|
|
109
|
+
- [参照重建与候选版本验证](reference/README.md)
|
|
110
|
+
|
|
111
|
+
## 开发
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uv sync --locked --extra providers --extra mcp
|
|
115
|
+
uv run pytest -q
|
|
116
|
+
uv run python scripts/verify.py # 全部检查,含与上游的差分(需要 Node)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
CI 配置在 `.github/workflows/ci.yml`,每次推送都在 GitHub Actions 上运行,覆盖 Linux 上的各个 Python 版本(含 3.14t 和 PyPy)以及 macOS 和 Windows。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
pi_python/__init__.py,sha256=jmQw2LTIjdt9Sn3lTAaAUAvgDrNqfZ1rDGvccAAuPOY,3751
|
|
2
|
+
pi_python/_version.py,sha256=Ocl79hbbH8_jdr5dGC90VR1cAvZc05Rc0tkZttUnMjo,22
|
|
3
|
+
pi_python/agent.py,sha256=eFbmkO5prBbWssaIycgTRWd4VRJ6I3FJMDU414kpL1w,15264
|
|
4
|
+
pi_python/cancellation.py,sha256=DoQVdX7DcQdVLkl4OvhcpMhKZJEW0Kscl2-xxF6i6Y0,608
|
|
5
|
+
pi_python/errors.py,sha256=65lT0nYfzqxRfUlFG-Y9vgYxfDHEuFiBfgqmFnX9_O8,675
|
|
6
|
+
pi_python/estimate.py,sha256=dQQJ9UEGp57F3wO_CcU2oubgPe841ttgpUseK3Fu_0w,5048
|
|
7
|
+
pi_python/events.py,sha256=t05VE-km2ZcsdIXCviVzNFQCob4xBghDfNeBRWpLrCA,4594
|
|
8
|
+
pi_python/function_tools.py,sha256=MQgNwz6PgT2gnbXRe0-SNVLnedkui4jaclL9dGOZa1s,17633
|
|
9
|
+
pi_python/hooks.py,sha256=jm6ep78NjdHxIPZvcOXTZIPxkfBMkffVTNzLvnHS9mM,1321
|
|
10
|
+
pi_python/limits.py,sha256=K1aP1cFH4fVhtWIXqpWMmpkB9AI0wK-bz3Xd2hxnOs4,1157
|
|
11
|
+
pi_python/loop.py,sha256=H9UK8XqvnTFC8JgKoziqqD4s7xOZy-xPciTqaSiP_9c,17622
|
|
12
|
+
pi_python/lowlevel.py,sha256=56wtwqD0Ur1AGAXGa7zclb1IpmRPFpSEss_nspkAdrI,5514
|
|
13
|
+
pi_python/mcp.py,sha256=Nn0cDdNswsCFP-HXvDXiudMYtQvWEyt9bh6kFR028EQ,8084
|
|
14
|
+
pi_python/messages.py,sha256=w5e-lc9DLW_4vYZ73Wj32RXfNYzDHdp4HCYsF5qkfHY,15665
|
|
15
|
+
pi_python/models.py,sha256=IejtaWvbURM9vv_2kkoDzfto2TR0OSLjuQeOh3IJZ1k,6094
|
|
16
|
+
pi_python/provider.py,sha256=k_VfJu5WOQla_LkglTDAq5s-77ejCj4YRTyhJ8onZBo,4259
|
|
17
|
+
pi_python/proxy.py,sha256=kpEUoE1oDkJW7VVaV72slN3uJUFgYR4Q6jtYOEe8LmQ,12159
|
|
18
|
+
pi_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
pi_python/queues.py,sha256=nQ5xRSA3MMOHMs_ZJnG9sT3-d_yKn72oSnxXqiKPrcI,3032
|
|
20
|
+
pi_python/recovery.py,sha256=z5ht-6FoKtC5BPEaSgXiRE2KVf94mZDiKMSxV0mkZ-4,8138
|
|
21
|
+
pi_python/run.py,sha256=gR4udFeg1oFSh8CNkS5O-DCoOHrn6vTnaMsGH3nWbSs,17702
|
|
22
|
+
pi_python/stream.py,sha256=R3v-qjCHFQJhHQk83qATz7lC3yr8paJguaHwk8RoHow,10729
|
|
23
|
+
pi_python/sync.py,sha256=HXr6sh9fkom6SD3rSfBzM-jg2IKkim-QifCUP9nJMW0,2557
|
|
24
|
+
pi_python/testing.py,sha256=XfTSOkEv0CenqrBILI_T205jOhyitW53YQZ9yiMXir4,1046
|
|
25
|
+
pi_python/tools.py,sha256=7hpquuOoVeRAhVxlYOXsooFvTcXEgfVkVBrTjvMbqa8,20503
|
|
26
|
+
pi_python/transcript.py,sha256=g6Tg8eiyMCAK43iLpcBv220MHBq8kO7Ty-6OYLCzw2A,6685
|
|
27
|
+
pi_python/data/models.json,sha256=oa_LGv7vaRrS-l7_Z7iu8f7WTyoJJLPhUQyptUz7OmE,77549
|
|
28
|
+
pi_python/providers/__init__.py,sha256=6oB-gHkWn5o_01sLRKUnss-uTMcuyyzie-uSF1cPRdk,673
|
|
29
|
+
pi_python/providers/anthropic.py,sha256=35ZwPGh2VUg-86iNROyHz5MAv1bYZB2XGLR-DHYELAY,30204
|
|
30
|
+
pi_python/providers/common.py,sha256=z8dB2pIc-dRscPAppnA3ZwF_wJygunQb9pI9Wl4CvaA,8051
|
|
31
|
+
pi_python/providers/completions.py,sha256=7tFrS_j2u6mV90mSE8uZYZDfj6DqRVxJXbIrUDay3mg,50289
|
|
32
|
+
pi_python/providers/oauth.py,sha256=_xRiqxG3PIhxgrUYDoI9iKDEnXA12DQS6fPFBwSn8rQ,22822
|
|
33
|
+
pi_python/providers/openai.py,sha256=36KBHaFUgM_QGKBSTxVxAfroCzmcoh5DPKuX667WmLs,30112
|
|
34
|
+
pi_python/providers/transport.py,sha256=R9AbUmlTXwuGXJEv9Q1joZrTJAd1shxnz7Uxwuzl0nA,21990
|
|
35
|
+
pi_python_core-0.8.1.dist-info/METADATA,sha256=SEo2GGTCg7wTUWqDc95QtzmQQqEKKwlNNuLE76ujxow,6437
|
|
36
|
+
pi_python_core-0.8.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
37
|
+
pi_python_core-0.8.1.dist-info/licenses/LICENSE,sha256=BFf1vOw7OyEWBd-10aSQQv1jjzaGpBD-CZwkolrxPEg,1069
|
|
38
|
+
pi_python_core-0.8.1.dist-info/licenses/NOTICE,sha256=fJna16fm1ECHN7zVZhtyNmjLw8KGxGp8mL9blISF1K0,633
|
|
39
|
+
pi_python_core-0.8.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pi-python-core is an independent Python implementation, not an official Pi release.
|
|
2
|
+
Agent execution and transcript behavior are adapted from earendil-works/pi:
|
|
3
|
+
https://github.com/earendil-works/pi/tree/a13d35a742c6ef8462812a28fbe1d8c8b7431c32
|
|
4
|
+
Copyright (c) 2025 Mario Zechner. MIT license; see LICENSE.
|
|
5
|
+
The complete upstream source is fetched only for development under reference/pi.
|
|
6
|
+
Provider request conversion (Claude Messages, OpenAI and Codex Responses), the cached
|
|
7
|
+
WebSocket continuation, transcript replay helpers and the context estimate/shortHash in
|
|
8
|
+
src/pi_python/estimate.py are adapted from packages/ai of the same commit.
|