a2ea-py 0.1.0__tar.gz → 0.2.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.
a2ea_py-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: a2ea-py
3
+ Version: 0.2.0
4
+ Summary: Official Python client for the A2EA telemetry and attribution platform.
5
+ Author: AI Blockchain Ventures
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: requests>=2.31.0
9
+ Provides-Extra: langchain
10
+ Requires-Dist: langchain-core>=0.3; extra == "langchain"
11
+ Provides-Extra: crewai
12
+ Requires-Dist: crewai>=1.0; extra == "crewai"
13
+ Provides-Extra: openai-agents
14
+ Requires-Dist: openai-agents>=0.2; extra == "openai-agents"
15
+
16
+ # a2ea-py
17
+
18
+ Official Python SDK for sending A2EA telemetry to the backend.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ pip install a2ea-py
24
+ ```
25
+
26
+ ## Quickstart
27
+
28
+ ```python
29
+ from a2ea import A2EAClient
30
+
31
+ client = A2EAClient(
32
+ api_key="your X-A2EA-API-Key"
33
+ )
34
+
35
+
36
+ @client.track_agent(task_type="data_processing")
37
+ def run_agent(payload):
38
+ return process(payload)
39
+
40
+
41
+ client.flush(timeout=5)
42
+ client.close()
43
+ ```
44
+
45
+ Send many completed tasks in one request when a worker already has a result batch:
46
+
47
+ ```python
48
+ client.send_batch("data_processing", [
49
+ {"event_id": "evt_101", "duration_ms": 840, "outcome": "success"},
50
+ {"event_id": "evt_102", "duration_ms": 910, "outcome": "success"},
51
+ ])
52
+ client.flush(timeout=5)
53
+ ```
54
+
55
+ ### Optional configuration
56
+
57
+ - `base_url`
58
+ - Defaults to `https://a2ea-backend-526z2hkxna-uc.a.run.app`
59
+ - Set this when testing locally against `http://127.0.0.1:4080`
60
+ - `agent_id`
61
+ - Optional override if you want to assign a fixed agent identifier instead of the default host/process-based value
62
+
63
+ Example for local development:
64
+
65
+ ```python
66
+ from a2ea import A2EAClient
67
+
68
+ client = A2EAClient(
69
+ api_key="your X-A2EA-API-Key",
70
+ base_url="http://127.0.0.1:4080",
71
+ agent_id="agent_pipeline_014",
72
+ )
73
+ ```
74
+
75
+ Use `A2EA_BASE_URL=https://a2ea-backend-526z2hkxna-uc.a.run.app` explicitly if your deployment pins runtime configuration through environment variables.
76
+
77
+ ## Route work by A2EA shares
78
+
79
+ When workload management is on for a task type (Dashboard > Workload), A2EA publishes a routing share for each agent. A managing agent can pick the next agent with:
80
+
81
+ ```python
82
+ agent_id = client.choose_agent("invoice_review", eligible_agent_ids=agents_allowed_for_this_task)
83
+ if agent_id is None:
84
+ agent_id = my_default_router(task) # workload management is off or no share applies
85
+ ```
86
+
87
+ `choose_agent` only picks among `eligible_agent_ids`, so your own permission rules still decide which agents may run a task. Use `client.get_allocation(task_type)` to read the full policy, shares and history. In automatic mode, reading the shares applies the next change once the cooldown has passed.
88
+
89
+ ## Credit shared jobs
90
+
91
+ When several agents work on one job, give each of their events the same `workflow_id`. A2EA splits the job's value among them (by share of events, time, or criticality) and the credits always add up to the job total.
92
+
93
+ ```python
94
+ client.send_telemetry("invoice_intake", 8000, "success", workflow_id="invoice_6040")
95
+ review_client.send_telemetry("invoice_review", 30000, "success", workflow_id="invoice_6040", criticality=5)
96
+
97
+ split = client.get_workflow("invoice_6040") # credits under the saved method
98
+ preview = client.get_workflow("invoice_6040", method="time_share")
99
+ totals = client.get_workflow_credits(days=30) # each agent's credit across workflows
100
+ ```
101
+
102
+ `criticality` is a whole number from 1 to 10 (1 when not set). Both fields are signed with the event. Batch events accept `workflow_id` and `criticality` keys too.
103
+
104
+ ## Check a score
105
+
106
+ Every request that stores new events saves a score record with all its inputs. The score response includes `scoreRecordId` and `recordHash`.
107
+
108
+ ```python
109
+ records = client.list_score_records(agent_id="agent_review")
110
+ record = client.get_score_record(records["records"][0]["id"])
111
+ for step in record["explanation"]:
112
+ print(step["title"], step["value"])
113
+
114
+ result = client.verify_score_record(record["id"]) # recomputes the score, checks hash, chain and events
115
+ assert result["valid"]
116
+
117
+ # Re-check the hash yourself:
118
+ assert A2EAClient.score_record_hash(record["recordJson"], record["previousHash"]) == record["recordHash"]
119
+ ```
120
+
121
+ ## Weekly report
122
+
123
+ ```python
124
+ report = client.get_weekly_report() # last complete week, as a dict
125
+ csv_text = client.get_weekly_report(week_start="2026-10-26", as_csv=True)
126
+ print(report["summary"]["netValueUsd"], report["reportHash"])
127
+ ```
128
+
129
+ The JSON and CSV carry the same `reportHash`, report version and calculation version.
130
+
131
+ ## Framework connectors
132
+
133
+ Thin connectors record agent framework runs with the same A2EA fields as the client: task type, agent, duration, success or failure, and a workflow ID so agents working on one job can share credit. Telemetry problems are logged and never raised into your agent. Each run gets a stable event ID, so it is never counted twice.
134
+
135
+ ```bash
136
+ pip install "a2ea-py[langchain]" # or [crewai], [openai-agents]
137
+ ```
138
+
139
+ **LangChain**: a callback handler. One result per top-level run (chain, agent, model or tool); `track="tools"` records each tool call instead.
140
+
141
+ ```python
142
+ from a2ea.integrations.langchain import A2EACallbackHandler
143
+
144
+ handler = A2EACallbackHandler(task_type="invoice_review", agent_id="invoice_chain")
145
+ chain.invoke(invoice, config={"callbacks": [handler], "metadata": {"a2ea_workflow_id": f"invoice_{invoice_id}"}})
146
+ ```
147
+
148
+ **CrewAI** (1.x): an event listener. One result per task, with the agent's role as the agent ID; tasks in one kickoff share a workflow ID. `track="crews"` records whole kickoffs.
149
+
150
+ ```python
151
+ from a2ea.integrations.crewai import instrument
152
+
153
+ instrument(task_type="market_research", task_types={"summary": "report_writing"}) # once
154
+ crew.kickoff()
155
+ ```
156
+
157
+ **OpenAI Agents SDK**: a tracing processor. One result per agent that runs (including handoffs); a run's `group_id` becomes the workflow ID. `track="tools"` records function-tool calls.
158
+
159
+ ```python
160
+ from a2ea.integrations.openai_agents import install
161
+
162
+ install(task_type="support_triage") # once
163
+ await Runner.run(agent, "...", run_config=RunConfig(group_id=f"ticket_{ticket_id}"))
164
+ ```
165
+
166
+ Per run, metadata keys `a2ea_task_type`, `a2ea_workflow_id` and `a2ea_criticality` override the defaults (LangChain also reads `a2ea_agent_id`). Runnable examples, which work offline with stand-in models, are in `examples/`.
167
+
168
+ ## What the client sends
169
+
170
+ Each tracked function call produces:
171
+
172
+ - `eventId`
173
+ - `agentId`
174
+ - `timestamp`
175
+ - `durationMs`
176
+ - `taskType`
177
+ - `outcome`
178
+ - `verification`
179
+ - `workflowId`, `criticality` and `parentEventId` (the step this one came from), when set (and a per-result `agent_id` when one client reports several agents)
180
+
181
+ The verification payload is signed locally with HMAC-SHA256 using the workspace API key so the backend can verify the telemetry envelope.
182
+
183
+ ## Reliability behavior
184
+
185
+ - submission runs in a background thread
186
+ - transient failures are retried with backoff
187
+ - exhausted events are retained in a local fallback buffer
188
+
189
+ ## Local package test commands
190
+
191
+ ```bash
192
+ python -m unittest discover tests
193
+ python -m build
194
+ pip install dist/a2ea_py-0.1.0-py3-none-any.whl
195
+ ```
@@ -0,0 +1,180 @@
1
+ # a2ea-py
2
+
3
+ Official Python SDK for sending A2EA telemetry to the backend.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install a2ea-py
9
+ ```
10
+
11
+ ## Quickstart
12
+
13
+ ```python
14
+ from a2ea import A2EAClient
15
+
16
+ client = A2EAClient(
17
+ api_key="your X-A2EA-API-Key"
18
+ )
19
+
20
+
21
+ @client.track_agent(task_type="data_processing")
22
+ def run_agent(payload):
23
+ return process(payload)
24
+
25
+
26
+ client.flush(timeout=5)
27
+ client.close()
28
+ ```
29
+
30
+ Send many completed tasks in one request when a worker already has a result batch:
31
+
32
+ ```python
33
+ client.send_batch("data_processing", [
34
+ {"event_id": "evt_101", "duration_ms": 840, "outcome": "success"},
35
+ {"event_id": "evt_102", "duration_ms": 910, "outcome": "success"},
36
+ ])
37
+ client.flush(timeout=5)
38
+ ```
39
+
40
+ ### Optional configuration
41
+
42
+ - `base_url`
43
+ - Defaults to `https://a2ea-backend-526z2hkxna-uc.a.run.app`
44
+ - Set this when testing locally against `http://127.0.0.1:4080`
45
+ - `agent_id`
46
+ - Optional override if you want to assign a fixed agent identifier instead of the default host/process-based value
47
+
48
+ Example for local development:
49
+
50
+ ```python
51
+ from a2ea import A2EAClient
52
+
53
+ client = A2EAClient(
54
+ api_key="your X-A2EA-API-Key",
55
+ base_url="http://127.0.0.1:4080",
56
+ agent_id="agent_pipeline_014",
57
+ )
58
+ ```
59
+
60
+ Use `A2EA_BASE_URL=https://a2ea-backend-526z2hkxna-uc.a.run.app` explicitly if your deployment pins runtime configuration through environment variables.
61
+
62
+ ## Route work by A2EA shares
63
+
64
+ When workload management is on for a task type (Dashboard > Workload), A2EA publishes a routing share for each agent. A managing agent can pick the next agent with:
65
+
66
+ ```python
67
+ agent_id = client.choose_agent("invoice_review", eligible_agent_ids=agents_allowed_for_this_task)
68
+ if agent_id is None:
69
+ agent_id = my_default_router(task) # workload management is off or no share applies
70
+ ```
71
+
72
+ `choose_agent` only picks among `eligible_agent_ids`, so your own permission rules still decide which agents may run a task. Use `client.get_allocation(task_type)` to read the full policy, shares and history. In automatic mode, reading the shares applies the next change once the cooldown has passed.
73
+
74
+ ## Credit shared jobs
75
+
76
+ When several agents work on one job, give each of their events the same `workflow_id`. A2EA splits the job's value among them (by share of events, time, or criticality) and the credits always add up to the job total.
77
+
78
+ ```python
79
+ client.send_telemetry("invoice_intake", 8000, "success", workflow_id="invoice_6040")
80
+ review_client.send_telemetry("invoice_review", 30000, "success", workflow_id="invoice_6040", criticality=5)
81
+
82
+ split = client.get_workflow("invoice_6040") # credits under the saved method
83
+ preview = client.get_workflow("invoice_6040", method="time_share")
84
+ totals = client.get_workflow_credits(days=30) # each agent's credit across workflows
85
+ ```
86
+
87
+ `criticality` is a whole number from 1 to 10 (1 when not set). Both fields are signed with the event. Batch events accept `workflow_id` and `criticality` keys too.
88
+
89
+ ## Check a score
90
+
91
+ Every request that stores new events saves a score record with all its inputs. The score response includes `scoreRecordId` and `recordHash`.
92
+
93
+ ```python
94
+ records = client.list_score_records(agent_id="agent_review")
95
+ record = client.get_score_record(records["records"][0]["id"])
96
+ for step in record["explanation"]:
97
+ print(step["title"], step["value"])
98
+
99
+ result = client.verify_score_record(record["id"]) # recomputes the score, checks hash, chain and events
100
+ assert result["valid"]
101
+
102
+ # Re-check the hash yourself:
103
+ assert A2EAClient.score_record_hash(record["recordJson"], record["previousHash"]) == record["recordHash"]
104
+ ```
105
+
106
+ ## Weekly report
107
+
108
+ ```python
109
+ report = client.get_weekly_report() # last complete week, as a dict
110
+ csv_text = client.get_weekly_report(week_start="2026-10-26", as_csv=True)
111
+ print(report["summary"]["netValueUsd"], report["reportHash"])
112
+ ```
113
+
114
+ The JSON and CSV carry the same `reportHash`, report version and calculation version.
115
+
116
+ ## Framework connectors
117
+
118
+ Thin connectors record agent framework runs with the same A2EA fields as the client: task type, agent, duration, success or failure, and a workflow ID so agents working on one job can share credit. Telemetry problems are logged and never raised into your agent. Each run gets a stable event ID, so it is never counted twice.
119
+
120
+ ```bash
121
+ pip install "a2ea-py[langchain]" # or [crewai], [openai-agents]
122
+ ```
123
+
124
+ **LangChain**: a callback handler. One result per top-level run (chain, agent, model or tool); `track="tools"` records each tool call instead.
125
+
126
+ ```python
127
+ from a2ea.integrations.langchain import A2EACallbackHandler
128
+
129
+ handler = A2EACallbackHandler(task_type="invoice_review", agent_id="invoice_chain")
130
+ chain.invoke(invoice, config={"callbacks": [handler], "metadata": {"a2ea_workflow_id": f"invoice_{invoice_id}"}})
131
+ ```
132
+
133
+ **CrewAI** (1.x): an event listener. One result per task, with the agent's role as the agent ID; tasks in one kickoff share a workflow ID. `track="crews"` records whole kickoffs.
134
+
135
+ ```python
136
+ from a2ea.integrations.crewai import instrument
137
+
138
+ instrument(task_type="market_research", task_types={"summary": "report_writing"}) # once
139
+ crew.kickoff()
140
+ ```
141
+
142
+ **OpenAI Agents SDK**: a tracing processor. One result per agent that runs (including handoffs); a run's `group_id` becomes the workflow ID. `track="tools"` records function-tool calls.
143
+
144
+ ```python
145
+ from a2ea.integrations.openai_agents import install
146
+
147
+ install(task_type="support_triage") # once
148
+ await Runner.run(agent, "...", run_config=RunConfig(group_id=f"ticket_{ticket_id}"))
149
+ ```
150
+
151
+ Per run, metadata keys `a2ea_task_type`, `a2ea_workflow_id` and `a2ea_criticality` override the defaults (LangChain also reads `a2ea_agent_id`). Runnable examples, which work offline with stand-in models, are in `examples/`.
152
+
153
+ ## What the client sends
154
+
155
+ Each tracked function call produces:
156
+
157
+ - `eventId`
158
+ - `agentId`
159
+ - `timestamp`
160
+ - `durationMs`
161
+ - `taskType`
162
+ - `outcome`
163
+ - `verification`
164
+ - `workflowId`, `criticality` and `parentEventId` (the step this one came from), when set (and a per-result `agent_id` when one client reports several agents)
165
+
166
+ The verification payload is signed locally with HMAC-SHA256 using the workspace API key so the backend can verify the telemetry envelope.
167
+
168
+ ## Reliability behavior
169
+
170
+ - submission runs in a background thread
171
+ - transient failures are retried with backoff
172
+ - exhausted events are retained in a local fallback buffer
173
+
174
+ ## Local package test commands
175
+
176
+ ```bash
177
+ python -m unittest discover tests
178
+ python -m build
179
+ pip install dist/a2ea_py-0.1.0-py3-none-any.whl
180
+ ```