probiai 0.1.0__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.
probiai-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ProbiAI
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.
probiai-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.5
2
+ Name: probiai
3
+ Version: 0.1.0
4
+ Summary: Sends ProbiAI a copy of each action your agent takes. Report-only, no dependencies.
5
+ Project-URL: Homepage, https://probiai-personalagent.vercel.app
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: agents,claude-agent-sdk,openai-agents,probiai,telemetry
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+
12
+ # probiai
13
+
14
+ Sends ProbiAI a copy of each action your agent takes, so your ProbiAI page shows what it did. For agents you build
15
+ with the Claude Agent SDK (Python or TypeScript) or the OpenAI Agents SDK (Python).
16
+
17
+ - Report-only: it never blocks, delays or changes your agent. If ProbiAI can't be reached, the copy is dropped.
18
+ - No dependencies.
19
+ - Contents and secrets in tool arguments (message bodies, file contents, passwords, card numbers, API keys) are
20
+ dropped before anything leaves your machine.
21
+
22
+ ## Set up
23
+
24
+ 1. On your ProbiAI page, choose your framework. It shows your key.
25
+ 2. Put the key in your agent's environment, not in your code:
26
+
27
+ ```bash
28
+ export PROBIAI_KEY=pk....
29
+ ```
30
+
31
+ 3. Pass the hooks to your agent (merge them with any hooks of your own).
32
+
33
+ ### Python
34
+
35
+ ```bash
36
+ pip install probiai
37
+ ```
38
+
39
+ ```python
40
+ import probiai
41
+
42
+ # Claude Agent SDK
43
+ options = ClaudeAgentOptions(hooks=probiai.claude_hooks())
44
+
45
+ # OpenAI Agents SDK
46
+ result = await Runner.run(agent, prompt, hooks=probiai.OpenAIHooks())
47
+ ```
48
+
49
+ ### TypeScript (Claude Agent SDK)
50
+
51
+ ```bash
52
+ npm install probiai
53
+ ```
54
+
55
+ ```ts
56
+ import { claudeHooks } from "probiai";
57
+
58
+ const options = { hooks: claudeHooks() };
59
+ ```
60
+
61
+ ## What is sent
62
+
63
+ For each tool call: the tool name, its arguments without contents or secrets, whether it worked, the first 500
64
+ characters of the result, and the model when known. Sub-agents and hand-offs are sent by name. Copies go to
65
+ `PROBIAI_URL` (default https://probiai-personalagent.vercel.app) with your key. Without a key, nothing is sent.
66
+
67
+ Using OpenClaw or Pi? Your ProbiAI page has a one-line install with your key built in.
68
+
69
+ ProbiAI is a pilot: it is being tested and is not yet an insurance product.
@@ -0,0 +1,58 @@
1
+ # probiai
2
+
3
+ Sends ProbiAI a copy of each action your agent takes, so your ProbiAI page shows what it did. For agents you build
4
+ with the Claude Agent SDK (Python or TypeScript) or the OpenAI Agents SDK (Python).
5
+
6
+ - Report-only: it never blocks, delays or changes your agent. If ProbiAI can't be reached, the copy is dropped.
7
+ - No dependencies.
8
+ - Contents and secrets in tool arguments (message bodies, file contents, passwords, card numbers, API keys) are
9
+ dropped before anything leaves your machine.
10
+
11
+ ## Set up
12
+
13
+ 1. On your ProbiAI page, choose your framework. It shows your key.
14
+ 2. Put the key in your agent's environment, not in your code:
15
+
16
+ ```bash
17
+ export PROBIAI_KEY=pk....
18
+ ```
19
+
20
+ 3. Pass the hooks to your agent (merge them with any hooks of your own).
21
+
22
+ ### Python
23
+
24
+ ```bash
25
+ pip install probiai
26
+ ```
27
+
28
+ ```python
29
+ import probiai
30
+
31
+ # Claude Agent SDK
32
+ options = ClaudeAgentOptions(hooks=probiai.claude_hooks())
33
+
34
+ # OpenAI Agents SDK
35
+ result = await Runner.run(agent, prompt, hooks=probiai.OpenAIHooks())
36
+ ```
37
+
38
+ ### TypeScript (Claude Agent SDK)
39
+
40
+ ```bash
41
+ npm install probiai
42
+ ```
43
+
44
+ ```ts
45
+ import { claudeHooks } from "probiai";
46
+
47
+ const options = { hooks: claudeHooks() };
48
+ ```
49
+
50
+ ## What is sent
51
+
52
+ For each tool call: the tool name, its arguments without contents or secrets, whether it worked, the first 500
53
+ characters of the result, and the model when known. Sub-agents and hand-offs are sent by name. Copies go to
54
+ `PROBIAI_URL` (default https://probiai-personalagent.vercel.app) with your key. Without a key, nothing is sent.
55
+
56
+ Using OpenClaw or Pi? Your ProbiAI page has a one-line install with your key built in.
57
+
58
+ ProbiAI is a pilot: it is being tested and is not yet an insurance product.
@@ -0,0 +1,117 @@
1
+ """ProbiAI add-on for agents you build in Python: a copy of each action your agent takes goes to ProbiAI automatically.
2
+
3
+ Claude Agent SDK: options = ClaudeAgentOptions(hooks=probiai.claude_hooks()) # merge with hooks of your own
4
+ OpenAI Agents SDK: result = await Runner.run(agent, prompt, hooks=probiai.OpenAIHooks())
5
+
6
+ Set PROBIAI_KEY (from your ProbiAI page). Standard library only. Report-only: it never blocks, delays or changes your
7
+ agent. Copies go out on a background thread (your program waits at most 5 seconds for the last ones when it exits);
8
+ failures are ignored. Contents and secrets in tool arguments are dropped before anything leaves your machine.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import os
14
+ import re
15
+ import threading
16
+ import urllib.request
17
+ from datetime import datetime, timezone
18
+
19
+ URL = os.environ.get("PROBIAI_URL", "https://probiai-personalagent.vercel.app").rstrip("/")
20
+ DROP = re.compile(r"^(body|text|content|contents|message|html|markdown|attachments?|file_?content|data|base64|password|"
21
+ r"passcode|pin|otp|token|secret|api_?key|card(_?number)?|cvv|cvc|ssn)$", re.I)
22
+
23
+
24
+ def facts(value, depth: int = 0):
25
+ """The arguments with contents and secrets removed, nested at most four levels, long strings cut."""
26
+ if depth > 3:
27
+ return "…"
28
+ if isinstance(value, (list, tuple)):
29
+ return [facts(v, depth + 1) for v in list(value)[:50]]
30
+ if isinstance(value, dict):
31
+ return {k: facts(v, depth + 1) for k, v in list(value.items())[:40] if not DROP.match(str(k))}
32
+ return value[:200] if isinstance(value, str) else value
33
+
34
+
35
+ def short(result) -> str | None:
36
+ """A tool result, short, so ProbiAI can read an amount or a booking reference from it."""
37
+ if result is None:
38
+ return None
39
+ try:
40
+ text = result if isinstance(result, str) else json.dumps(result, default=str)
41
+ except (TypeError, ValueError):
42
+ text = str(result)
43
+ return text[:500]
44
+
45
+
46
+ def send(copy: dict, key: str | None = None) -> None:
47
+ """Send one copy in the background. Does nothing without a key."""
48
+ key = key or os.environ.get("PROBIAI_KEY", "")
49
+ if key:
50
+ body = json.dumps({"v": 1, "ts": datetime.now(timezone.utc).isoformat(), **copy}, default=str).encode()
51
+ threading.Thread(target=_post, args=(body, key), name="probiai-copy").start()
52
+
53
+
54
+ def _post(body: bytes, key: str) -> None:
55
+ req = urllib.request.Request(f"{URL}/v1/copies", data=body, method="POST",
56
+ headers={"content-type": "application/json", "authorization": f"Bearer {key}"})
57
+ try:
58
+ urllib.request.urlopen(req, timeout=5).close()
59
+ except Exception: # noqa: BLE001 - a copy that can't be sent must never affect the agent
60
+ pass
61
+
62
+
63
+ def claude_hooks(key: str | None = None, model: str | None = None) -> dict:
64
+ """Claude Agent SDK: every tool call, failed tool call and finished sub-agent."""
65
+ from claude_agent_sdk import HookMatcher
66
+
67
+ def copy(i: dict, status: str) -> dict:
68
+ return {"harness": "claude-agent-sdk", "model": model, "tool": i.get("tool_name"),
69
+ "input": facts(i.get("tool_input") or {}), "status": status, "result": short(i.get("tool_response"))}
70
+
71
+ async def done(i, tool_use_id, context):
72
+ send(copy(i, "ok"), key)
73
+ return {}
74
+
75
+ async def failed(i, tool_use_id, context):
76
+ send(copy(i, "error"), key)
77
+ return {}
78
+
79
+ async def subagent(i, tool_use_id, context):
80
+ send({"harness": "claude-agent-sdk", "model": model,
81
+ "handoff": {"name": i.get("agent_type") or "sub-agent", "via": "own sub-agent"}}, key)
82
+ return {}
83
+
84
+ return {"PostToolUse": [HookMatcher(hooks=[done])], "PostToolUseFailure": [HookMatcher(hooks=[failed])],
85
+ "SubagentStop": [HookMatcher(hooks=[subagent])]}
86
+
87
+
88
+ try:
89
+ from agents import RunHooks as _RunHooks
90
+ except ImportError: # the OpenAI Agents SDK isn't installed: OpenAIHooks is never used then
91
+ _RunHooks = object
92
+
93
+
94
+ class OpenAIHooks(_RunHooks):
95
+ """OpenAI Agents SDK: every tool call and every hand-off to another agent."""
96
+
97
+ def __init__(self, key: str | None = None):
98
+ super().__init__()
99
+ self.key = key
100
+
101
+ async def on_tool_end(self, context, agent, tool, result) -> None:
102
+ args = getattr(context, "tool_arguments", None)
103
+ try:
104
+ args = json.loads(args) if isinstance(args, str) else {}
105
+ except ValueError:
106
+ args = {}
107
+ send({"harness": "openai-agents", "model": _model(agent), "tool": getattr(context, "tool_name", None)
108
+ or getattr(tool, "name", "tool"), "input": facts(args), "status": "ok", "result": short(result)}, self.key)
109
+
110
+ async def on_handoff(self, context, from_agent, to_agent) -> None:
111
+ send({"harness": "openai-agents", "model": _model(from_agent),
112
+ "handoff": {"name": getattr(to_agent, "name", "agent"), "via": "handoff"}}, self.key)
113
+
114
+
115
+ def _model(agent) -> str | None:
116
+ m = getattr(agent, "model", None)
117
+ return m if isinstance(m, str) else getattr(m, "model", None)
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "probiai"
7
+ version = "0.1.0"
8
+ description = "Sends ProbiAI a copy of each action your agent takes. Report-only, no dependencies."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.9"
13
+ keywords = ["claude-agent-sdk", "openai-agents", "agents", "telemetry", "probiai"]
14
+
15
+ [project.urls]
16
+ Homepage = "https://probiai-personalagent.vercel.app"
17
+
18
+ [tool.hatch.build.targets.wheel]
19
+ only-include = ["probiai.py"]