feedback-manager 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.
- feedback_manager-0.1.0/PKG-INFO +380 -0
- feedback_manager-0.1.0/README.md +352 -0
- feedback_manager-0.1.0/pyproject.toml +120 -0
- feedback_manager-0.1.0/pyproject.toml.orig +103 -0
- feedback_manager-0.1.0/src/feedback_manager/__init__.py +75 -0
- feedback_manager-0.1.0/src/feedback_manager/_logging.py +31 -0
- feedback_manager-0.1.0/src/feedback_manager/api/__init__.py +7 -0
- feedback_manager-0.1.0/src/feedback_manager/api/manager.py +339 -0
- feedback_manager-0.1.0/src/feedback_manager/api/queries.py +11 -0
- feedback_manager-0.1.0/src/feedback_manager/api/subscription.py +27 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/__init__.py +32 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/correlator.py +20 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/handler.py +46 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/policy.py +33 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/router.py +27 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/serializer.py +35 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/store.py +106 -0
- feedback_manager-0.1.0/src/feedback_manager/contracts/subscriber.py +22 -0
- feedback_manager-0.1.0/src/feedback_manager/core/__init__.py +32 -0
- feedback_manager-0.1.0/src/feedback_manager/core/_open_value.py +37 -0
- feedback_manager-0.1.0/src/feedback_manager/core/categories.py +55 -0
- feedback_manager-0.1.0/src/feedback_manager/core/context.py +60 -0
- feedback_manager-0.1.0/src/feedback_manager/core/events.py +71 -0
- feedback_manager-0.1.0/src/feedback_manager/core/lifecycle.py +114 -0
- feedback_manager-0.1.0/src/feedback_manager/core/provenance.py +34 -0
- feedback_manager-0.1.0/src/feedback_manager/core/sources.py +42 -0
- feedback_manager-0.1.0/src/feedback_manager/core/status.py +36 -0
- feedback_manager-0.1.0/src/feedback_manager/core/targets.py +65 -0
- feedback_manager-0.1.0/src/feedback_manager/correlation/__init__.py +5 -0
- feedback_manager-0.1.0/src/feedback_manager/correlation/correlator.py +41 -0
- feedback_manager-0.1.0/src/feedback_manager/errors/__init__.py +27 -0
- feedback_manager-0.1.0/src/feedback_manager/errors/exceptions.py +99 -0
- feedback_manager-0.1.0/src/feedback_manager/handlers/__init__.py +5 -0
- feedback_manager-0.1.0/src/feedback_manager/handlers/audit.py +41 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/__init__.py +5 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langchain/__init__.py +6 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langchain/adapter.py +24 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langchain/callbacks.py +118 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langchain/tools.py +48 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langgraph/__init__.py +7 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langgraph/adapter.py +54 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langgraph/interrupt.py +93 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/langgraph/streaming.py +32 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/xai/__init__.py +5 -0
- feedback_manager-0.1.0/src/feedback_manager/integrations/xai/adapter.py +96 -0
- feedback_manager-0.1.0/src/feedback_manager/observability/__init__.py +29 -0
- feedback_manager-0.1.0/src/feedback_manager/observability/hooks.py +78 -0
- feedback_manager-0.1.0/src/feedback_manager/policies/__init__.py +7 -0
- feedback_manager-0.1.0/src/feedback_manager/policies/delivery.py +23 -0
- feedback_manager-0.1.0/src/feedback_manager/policies/failure.py +96 -0
- feedback_manager-0.1.0/src/feedback_manager/policies/retention.py +35 -0
- feedback_manager-0.1.0/src/feedback_manager/py.typed +0 -0
- feedback_manager-0.1.0/src/feedback_manager/routing/__init__.py +19 -0
- feedback_manager-0.1.0/src/feedback_manager/routing/default_router.py +50 -0
- feedback_manager-0.1.0/src/feedback_manager/routing/rules.py +51 -0
- feedback_manager-0.1.0/src/feedback_manager/storage/__init__.py +5 -0
- feedback_manager-0.1.0/src/feedback_manager/storage/memory.py +94 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: feedback-manager
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production-grade feedback infrastructure for LangChain/LangGraph applications: capture, correlate, persist, route, and resolve feedback as a first-class domain concern.
|
|
5
|
+
Keywords: langchain,langgraph,feedback,hitl,human-in-the-loop,provenance
|
|
6
|
+
Author: S MUNI HARISH
|
|
7
|
+
Author-email: S MUNI HARISH <samamuniharish@gmail.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: langchain-core>=1.6,<2
|
|
17
|
+
Requires-Dist: langgraph>=1.2.11,<1.3
|
|
18
|
+
Requires-Dist: langgraph-xai>=0.1.0,<0.2
|
|
19
|
+
Requires-Dist: pydantic>=2.12,<3
|
|
20
|
+
Requires-Dist: structlog>=25.1,<27
|
|
21
|
+
Requires-Python: >=3.12, <3.15
|
|
22
|
+
Project-URL: Homepage, https://github.com/samamuniharish/feedback-manager
|
|
23
|
+
Project-URL: Documentation, https://feedback-manager.readthedocs.io
|
|
24
|
+
Project-URL: Repository, https://github.com/samamuniharish/feedback-manager
|
|
25
|
+
Project-URL: Issues, https://github.com/samamuniharish/feedback-manager/issues
|
|
26
|
+
Project-URL: Changelog, https://github.com/samamuniharish/feedback-manager/blob/main/CHANGELOG.md
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# feedback-manager
|
|
30
|
+
|
|
31
|
+
Production-grade feedback infrastructure for LangChain and LangGraph applications.
|
|
32
|
+
|
|
33
|
+
`feedback-manager` treats feedback as a first-class domain concern: capture it, correlate it to execution context, persist it, route it to handlers, and move it through an explicit lifecycle.
|
|
34
|
+
|
|
35
|
+
It is a **library**, not an agent framework or runtime.
|
|
36
|
+
|
|
37
|
+
## What it solves
|
|
38
|
+
|
|
39
|
+
Agent applications often need to handle feedback from many places:
|
|
40
|
+
|
|
41
|
+
- human corrections on generated answers
|
|
42
|
+
- approval or rejection decisions in human-in-the-loop flows
|
|
43
|
+
- tool failures and timeouts
|
|
44
|
+
- evaluator scores and critiques
|
|
45
|
+
- generation interruptions or partial results
|
|
46
|
+
- provenance-linked review or audit events
|
|
47
|
+
|
|
48
|
+
Without a dedicated feedback model, that data usually ends up fragmented across logs, UIs, tickets, and one-off tables.
|
|
49
|
+
|
|
50
|
+
`feedback-manager` gives you:
|
|
51
|
+
|
|
52
|
+
- a typed feedback event model
|
|
53
|
+
- correlation to runs, threads, checkpoints, nodes, tools, and generations
|
|
54
|
+
- explicit lifecycle management
|
|
55
|
+
- pluggable storage, routing, handlers, policies, and observability
|
|
56
|
+
- framework helpers for LangChain callbacks and LangGraph human-in-the-loop
|
|
57
|
+
flows
|
|
58
|
+
- provenance correlation backed exclusively by `langgraph-xai`
|
|
59
|
+
|
|
60
|
+
## What it does not do
|
|
61
|
+
|
|
62
|
+
`feedback-manager` does **not**:
|
|
63
|
+
|
|
64
|
+
- execute agents
|
|
65
|
+
- orchestrate graphs
|
|
66
|
+
- replace LangGraph interrupts, checkpoints, or streaming
|
|
67
|
+
- implement evaluators or LLM-as-judge systems
|
|
68
|
+
- perform self-improvement or policy learning
|
|
69
|
+
- own your application's business workflow
|
|
70
|
+
|
|
71
|
+
LangChain, LangGraph, `langgraph-xai`, and your application code keep those responsibilities.
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
Requirements:
|
|
76
|
+
|
|
77
|
+
- Python `>=3.12,<3.15`
|
|
78
|
+
|
|
79
|
+
Install the package:
|
|
80
|
+
|
|
81
|
+
```powershell
|
|
82
|
+
pip install .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
or for local development:
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
uv sync --all-groups
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Runtime dependencies are mandatory, not optional extras:
|
|
92
|
+
|
|
93
|
+
- `langchain-core>=1.6,<2`
|
|
94
|
+
- `langgraph>=1.2.11,<1.3`
|
|
95
|
+
- `langgraph-xai>=0.1.0,<0.2`
|
|
96
|
+
- `pydantic>=2.12,<3`
|
|
97
|
+
|
|
98
|
+
## How it fits
|
|
99
|
+
|
|
100
|
+
Applications interact with a small public surface:
|
|
101
|
+
|
|
102
|
+
- create and query feedback through `FeedbackManager`
|
|
103
|
+
- describe feedback using `FeedbackEvent`, source, category, target, and
|
|
104
|
+
execution-context types
|
|
105
|
+
- replace documented persistence, routing, handler, policy, and
|
|
106
|
+
observability contracts when production infrastructure requires it
|
|
107
|
+
- pass `XAIRuntime` directly to `FeedbackManager` for provenance
|
|
108
|
+
- opt into the documented LangChain or LangGraph helpers where useful
|
|
109
|
+
|
|
110
|
+
The happy-path lifecycle is:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
RECEIVED -> ACKNOWLEDGED -> HANDLED -> RESOLVED
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`resolve()` requires the event to already be `HANDLED`.
|
|
117
|
+
|
|
118
|
+
## Core concepts
|
|
119
|
+
|
|
120
|
+
### Source
|
|
121
|
+
|
|
122
|
+
Who or what produced the feedback:
|
|
123
|
+
|
|
124
|
+
- `human`
|
|
125
|
+
- `tool`
|
|
126
|
+
- `generation`
|
|
127
|
+
- `evaluator`
|
|
128
|
+
- `system`
|
|
129
|
+
- and custom open values
|
|
130
|
+
|
|
131
|
+
### Category
|
|
132
|
+
|
|
133
|
+
What kind of feedback it is:
|
|
134
|
+
|
|
135
|
+
- `correction`
|
|
136
|
+
- `approval`
|
|
137
|
+
- `rejection`
|
|
138
|
+
- `timeout`
|
|
139
|
+
- `quality`
|
|
140
|
+
- `interruption`
|
|
141
|
+
- and custom open values
|
|
142
|
+
|
|
143
|
+
### Target
|
|
144
|
+
|
|
145
|
+
What the feedback is about:
|
|
146
|
+
|
|
147
|
+
- graph
|
|
148
|
+
- run
|
|
149
|
+
- node
|
|
150
|
+
- tool call
|
|
151
|
+
- generation
|
|
152
|
+
- message
|
|
153
|
+
- state
|
|
154
|
+
|
|
155
|
+
### Correlation
|
|
156
|
+
|
|
157
|
+
Feedback can be linked to:
|
|
158
|
+
|
|
159
|
+
- `run_id`
|
|
160
|
+
- `thread_id`
|
|
161
|
+
- `checkpoint_id`
|
|
162
|
+
- `node_id`
|
|
163
|
+
- `tool_call_id`
|
|
164
|
+
- `generation_id`
|
|
165
|
+
|
|
166
|
+
### Provenance
|
|
167
|
+
|
|
168
|
+
When used with `langgraph-xai`, feedback can carry a `FeedbackProvenanceReference` resolved from an active run or from a provenance store by `run_id`.
|
|
169
|
+
|
|
170
|
+
## Quick start
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
import asyncio
|
|
174
|
+
|
|
175
|
+
from feedback_manager import (
|
|
176
|
+
ExecutionContext,
|
|
177
|
+
FeedbackCategory,
|
|
178
|
+
FeedbackManager,
|
|
179
|
+
FeedbackSource,
|
|
180
|
+
FeedbackTarget,
|
|
181
|
+
FeedbackTargetType,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
async def main() -> None:
|
|
186
|
+
manager = FeedbackManager()
|
|
187
|
+
|
|
188
|
+
feedback = await manager.submit(
|
|
189
|
+
source=FeedbackSource.HUMAN,
|
|
190
|
+
category=FeedbackCategory.CORRECTION,
|
|
191
|
+
target=FeedbackTarget(type=FeedbackTargetType.GENERATION, id="gen-42"),
|
|
192
|
+
payload={
|
|
193
|
+
"original_text": "The capital of Australia is Sydney.",
|
|
194
|
+
"corrected_text": "The capital of Australia is Canberra.",
|
|
195
|
+
},
|
|
196
|
+
execution_context=ExecutionContext(generation_id="gen-42"),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
await manager.acknowledge(feedback.feedback_id)
|
|
200
|
+
await manager.mark_handled(feedback.feedback_id)
|
|
201
|
+
resolved = await manager.resolve(
|
|
202
|
+
feedback.feedback_id,
|
|
203
|
+
resolution={"applied": True, "channel": "manual_review"},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
print(resolved.status)
|
|
207
|
+
print(resolved.metadata["resolution"])
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
asyncio.run(main())
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## LangChain example
|
|
214
|
+
|
|
215
|
+
`FeedbackCallbackHandler` turns real LangChain callback errors into feedback:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
import asyncio
|
|
219
|
+
|
|
220
|
+
from langchain_core.tools import tool
|
|
221
|
+
|
|
222
|
+
from feedback_manager import FeedbackManager
|
|
223
|
+
from feedback_manager.integrations.langchain import FeedbackCallbackHandler
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@tool
|
|
227
|
+
async def fetch_weather(city: str) -> str:
|
|
228
|
+
raise TimeoutError(f"weather service timed out looking up {city!r}")
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
async def main() -> None:
|
|
232
|
+
manager = FeedbackManager()
|
|
233
|
+
handler = FeedbackCallbackHandler(manager)
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
await fetch_weather.ainvoke({"city": "Canberra"}, config={"callbacks": [handler]})
|
|
237
|
+
except TimeoutError:
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
events = await manager.list()
|
|
241
|
+
print(events[0].source, events[0].category, events[0].target.type)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
asyncio.run(main())
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## LangGraph example
|
|
248
|
+
|
|
249
|
+
Extract execution identifiers from a `RunnableConfig`:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from feedback_manager.integrations.langgraph import execution_context_from_config
|
|
253
|
+
|
|
254
|
+
config = {
|
|
255
|
+
"configurable": {"thread_id": "thread-1", "checkpoint_id": "cp-1"},
|
|
256
|
+
"metadata": {"xai_application_id": "support-bot"},
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
context = execution_context_from_config(config, node_id="answer_node")
|
|
260
|
+
print(context.thread_id, context.checkpoint_id, context.node_id)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## HITL example
|
|
264
|
+
|
|
265
|
+
Use native LangGraph interrupts and record the approval request with `HumanInTheLoopBridge`:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
import asyncio
|
|
269
|
+
|
|
270
|
+
from feedback_manager import FeedbackManager, FeedbackTarget, FeedbackTargetType
|
|
271
|
+
from feedback_manager.integrations.langgraph import HumanInTheLoopBridge
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
async def main() -> None:
|
|
275
|
+
manager = FeedbackManager()
|
|
276
|
+
bridge = HumanInTheLoopBridge(manager)
|
|
277
|
+
|
|
278
|
+
feedback = await bridge.request(
|
|
279
|
+
target=FeedbackTarget(type=FeedbackTargetType.GRAPH, id="approval-flow"),
|
|
280
|
+
prompt={"question": "Approve sending this email?"},
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
resolved = await bridge.resolve(feedback.feedback_id, response="approved", approved=True)
|
|
284
|
+
resume = bridge.resume_command("approved")
|
|
285
|
+
print(resolved.status, resume)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
asyncio.run(main())
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This complements LangGraph's runtime instead of replacing it.
|
|
292
|
+
|
|
293
|
+
## Provenance example
|
|
294
|
+
|
|
295
|
+
Attach provenance from `langgraph-xai` by passing the runtime directly --
|
|
296
|
+
`FeedbackManager` wires up the provenance adapter automatically:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
from langgraph_xai import XAIRuntime
|
|
300
|
+
|
|
301
|
+
from feedback_manager import FeedbackManager
|
|
302
|
+
|
|
303
|
+
runtime = XAIRuntime(
|
|
304
|
+
application_id="support-bot",
|
|
305
|
+
tenant_id="acme-corp",
|
|
306
|
+
graph_id="qa-graph",
|
|
307
|
+
)
|
|
308
|
+
manager = FeedbackManager(xai_runtime=runtime)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
When `manager.submit(...)` runs inside an instrumented graph node, the adapter can resolve provenance from `runtime.current_run`.
|
|
312
|
+
|
|
313
|
+
## Extension example
|
|
314
|
+
|
|
315
|
+
### Custom source/category values
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
from feedback_manager import FeedbackCategory, FeedbackSource
|
|
319
|
+
|
|
320
|
+
source = FeedbackSource("mcp_server")
|
|
321
|
+
category = FeedbackCategory("business_policy_violation")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Custom store
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from collections.abc import Sequence
|
|
328
|
+
from uuid import UUID
|
|
329
|
+
|
|
330
|
+
from feedback_manager.contracts import FeedbackQuery, FeedbackStore
|
|
331
|
+
from feedback_manager import FeedbackEvent, FeedbackStatus
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class MyStore(FeedbackStore):
|
|
335
|
+
async def create(self, feedback: FeedbackEvent) -> FeedbackEvent: ...
|
|
336
|
+
async def get(self, feedback_id: UUID) -> FeedbackEvent | None: ...
|
|
337
|
+
async def update(self, feedback: FeedbackEvent) -> FeedbackEvent: ...
|
|
338
|
+
async def transition(self, feedback_id: UUID, status: FeedbackStatus) -> FeedbackEvent: ...
|
|
339
|
+
async def query(self, query: FeedbackQuery) -> Sequence[FeedbackEvent]: ...
|
|
340
|
+
async def list(self) -> Sequence[FeedbackEvent]: ...
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Custom handler
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
from feedback_manager.contracts import FeedbackContext, FeedbackHandler, FeedbackHandlerResult
|
|
347
|
+
from feedback_manager import FeedbackEvent
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class HumanReviewHandler(FeedbackHandler):
|
|
351
|
+
async def handle(
|
|
352
|
+
self, feedback: FeedbackEvent, context: FeedbackContext
|
|
353
|
+
) -> FeedbackHandlerResult:
|
|
354
|
+
return FeedbackHandlerResult(handled=True, detail="queued for review")
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Documentation
|
|
358
|
+
|
|
359
|
+
The full documentation site lives under `docs/` and includes:
|
|
360
|
+
|
|
361
|
+
- architecture guides
|
|
362
|
+
- ADRs
|
|
363
|
+
- getting-started guides
|
|
364
|
+
- concept references
|
|
365
|
+
- integration guides
|
|
366
|
+
- API reference
|
|
367
|
+
- advanced extension guides
|
|
368
|
+
- reliability, security, testing, and FAQ pages
|
|
369
|
+
|
|
370
|
+
Published documentation URL (project metadata): <https://feedback-manager.readthedocs.io>
|
|
371
|
+
|
|
372
|
+
## Contributing
|
|
373
|
+
|
|
374
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for local development setup, running
|
|
375
|
+
the test suite/coverage, linting, type-checking, and building the docs site.
|
|
376
|
+
|
|
377
|
+
## Author and license
|
|
378
|
+
|
|
379
|
+
- Author: **S MUNI HARISH**
|
|
380
|
+
- License: **Apache License 2.0**
|