reflex-agentkit 0.1.0__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.
Files changed (38) hide show
  1. reflex_agentkit/__init__.py +68 -0
  2. reflex_agentkit/adapters/__init__.py +1 -0
  3. reflex_agentkit/adapters/_require.py +27 -0
  4. reflex_agentkit/adapters/langgraph.py +277 -0
  5. reflex_agentkit/adapters/pydantic_ai.py +93 -0
  6. reflex_agentkit/components/__init__.py +21 -0
  7. reflex_agentkit/components/approval.py +123 -0
  8. reflex_agentkit/components/chat.py +42 -0
  9. reflex_agentkit/components/composer.py +44 -0
  10. reflex_agentkit/components/messages.py +104 -0
  11. reflex_agentkit/components/shared_state.py +32 -0
  12. reflex_agentkit/components/status.py +41 -0
  13. reflex_agentkit/components/tools.py +97 -0
  14. reflex_agentkit/core/__init__.py +56 -0
  15. reflex_agentkit/core/_log.py +47 -0
  16. reflex_agentkit/core/_patch.py +46 -0
  17. reflex_agentkit/core/clients/__init__.py +14 -0
  18. reflex_agentkit/core/clients/base.py +71 -0
  19. reflex_agentkit/core/clients/http.py +147 -0
  20. reflex_agentkit/core/clients/in_process.py +67 -0
  21. reflex_agentkit/core/clients/sse.py +75 -0
  22. reflex_agentkit/core/commands.py +589 -0
  23. reflex_agentkit/core/conversation.py +93 -0
  24. reflex_agentkit/core/errors.py +74 -0
  25. reflex_agentkit/core/models.py +243 -0
  26. reflex_agentkit/core/reducer.py +1078 -0
  27. reflex_agentkit/core/run_input.py +122 -0
  28. reflex_agentkit/core/tools.py +204 -0
  29. reflex_agentkit/py.typed +0 -0
  30. reflex_agentkit/state/__init__.py +5 -0
  31. reflex_agentkit/state/_driver.py +520 -0
  32. reflex_agentkit/state/_projection.py +120 -0
  33. reflex_agentkit/state/_registry.py +46 -0
  34. reflex_agentkit/state/agent_state.py +496 -0
  35. reflex_agentkit-0.1.0.dist-info/METADATA +457 -0
  36. reflex_agentkit-0.1.0.dist-info/RECORD +38 -0
  37. reflex_agentkit-0.1.0.dist-info/WHEEL +4 -0
  38. reflex_agentkit-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,74 @@
1
+ """Exception hierarchy and error codes (API §9, DM §6).
2
+
3
+ Exceptions are raised to *developers*. The browser only ever sees an :class:`ErrorCode`
4
+ and a sanitized message in the state vars.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from enum import StrEnum
10
+ from typing import Any, Literal, TypeAlias
11
+
12
+ __all__ = [
13
+ "AdapterNotInstalledError",
14
+ "AgentHTTPError",
15
+ "AgentKitError",
16
+ "AgentStreamError",
17
+ "ConfigurationError",
18
+ "ErrorCode",
19
+ "StreamErrorReason",
20
+ ]
21
+
22
+
23
+ class ErrorCode(StrEnum):
24
+ """Codes surfaced in the ``error_code`` state var (API §9.2). Values equal names."""
25
+
26
+ MESSAGE_TOO_LONG = "MESSAGE_TOO_LONG"
27
+ AGENT_RUN_ERROR = "AGENT_RUN_ERROR"
28
+ AGENT_HTTP_ERROR = "AGENT_HTTP_ERROR"
29
+ AGENT_STREAM_ERROR = "AGENT_STREAM_ERROR"
30
+ AGENT_EXCEPTION = "AGENT_EXCEPTION"
31
+ INVALID_EDITED_ARGS = "INVALID_EDITED_ARGS"
32
+ SHARED_STATE_LOCKED = "SHARED_STATE_LOCKED"
33
+ SHARED_STATE_INVALID = "SHARED_STATE_INVALID"
34
+ SHARED_STATE_PATCH_FAILED = "SHARED_STATE_PATCH_FAILED"
35
+ CLIENT_TOOL_LOOP_LIMIT = "CLIENT_TOOL_LOOP_LIMIT"
36
+
37
+
38
+ StreamErrorReason: TypeAlias = Literal["timeout", "eof", "content_type", "connect", "agent_raised"]
39
+
40
+
41
+ class AgentKitError(Exception):
42
+ """Base class of every reflex-agentkit exception."""
43
+
44
+
45
+ class ConfigurationError(AgentKitError, ValueError):
46
+ """Invalid class configuration, tool schema or adapter setup (raised at startup)."""
47
+
48
+
49
+ class AdapterNotInstalledError(AgentKitError, ImportError):
50
+ """An adapter was imported without its optional extra installed (API §7.7)."""
51
+
52
+
53
+ class AgentHTTPError(AgentKitError):
54
+ """The agent endpoint answered with a non-2xx status."""
55
+
56
+ def __init__(self, status_code: int, message: str | None = None) -> None:
57
+ self.status_code = status_code
58
+ self._message = message
59
+ super().__init__(message or f"agent endpoint returned HTTP {status_code}")
60
+
61
+ def __reduce__(self) -> tuple[Any, ...]:
62
+ return (type(self), (self.status_code, self._message))
63
+
64
+
65
+ class AgentStreamError(AgentKitError):
66
+ """The event stream failed: timeout, EOF, bad content type, connect, or agent raised."""
67
+
68
+ def __init__(self, reason: StreamErrorReason, message: str | None = None) -> None:
69
+ self.reason: StreamErrorReason = reason
70
+ self._message = message
71
+ super().__init__(message or f"agent stream error: {reason}")
72
+
73
+ def __reduce__(self) -> tuple[Any, ...]:
74
+ return (type(self), (self.reason, self._message))
@@ -0,0 +1,243 @@
1
+ """Value types, enums and JSON aliases of the pure core (DM §2, §3, §6, §8; API §5).
2
+
3
+ Every value type is a frozen, slotted dataclass (R-1) whose collections are tuples (R-2)
4
+ and whose enums are ``StrEnum`` (R-3), so the same types serve as Reflex var types (R-5).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import dataclasses
10
+ from collections.abc import Callable
11
+ from enum import StrEnum
12
+ from typing import TYPE_CHECKING, Any, ClassVar, Literal, Self, TypeAlias, Union, cast
13
+
14
+ if TYPE_CHECKING:
15
+ from _typeshed import DataclassInstance
16
+
17
+ __all__ = [
18
+ "ChatMessage",
19
+ "CustomEventRecord",
20
+ "Diagnostic",
21
+ "DiagnosticCode",
22
+ "DiagnosticLevel",
23
+ "InterruptAnswer",
24
+ "JsonObject",
25
+ "JsonValue",
26
+ "MessageRole",
27
+ "OpenInterrupt",
28
+ "PendingInterrupt",
29
+ "ReasoningRecord",
30
+ "ReducerConfig",
31
+ "ResumeStatus",
32
+ "RunStatus",
33
+ "TolerantPickle",
34
+ "ToolCall",
35
+ "ToolCallStatus",
36
+ ]
37
+
38
+ # DM R-4. ``Union`` (not ``|``) because the alias is recursive and must stay a runtime value.
39
+ JsonValue: TypeAlias = Union[ # noqa: UP007
40
+ bool, int, float, str, list["JsonValue"], dict[str, "JsonValue"], None
41
+ ]
42
+ JsonObject: TypeAlias = dict[str, JsonValue]
43
+
44
+ DiagnosticLevel: TypeAlias = Literal["debug", "warning"]
45
+ ResumeStatus: TypeAlias = Literal["resolved", "cancelled"]
46
+
47
+
48
+ class MessageRole(StrEnum):
49
+ """AG-UI message roles (DM §6). Only user/assistant/tool are projected (DM §3.1)."""
50
+
51
+ USER = "user"
52
+ ASSISTANT = "assistant"
53
+ TOOL = "tool"
54
+ SYSTEM = "system"
55
+ DEVELOPER = "developer"
56
+
57
+
58
+ class RunStatus(StrEnum):
59
+ """Run status state machine values (API §4.5)."""
60
+
61
+ IDLE = "idle"
62
+ RUNNING = "running"
63
+ AWAITING_INPUT = "awaiting_input"
64
+ CANCELLED = "cancelled"
65
+ ERROR = "error"
66
+
67
+
68
+ class ToolCallStatus(StrEnum):
69
+ """Tool call status state machine values (API §4.6)."""
70
+
71
+ STREAMING = "streaming"
72
+ PENDING_APPROVAL = "pending_approval"
73
+ RUNNING = "running"
74
+ DONE = "done"
75
+ REJECTED = "rejected"
76
+ ERROR = "error"
77
+
78
+
79
+ class DiagnosticCode(StrEnum):
80
+ """Codes of non-fatal reducer diagnostics (API §11). Values equal names."""
81
+
82
+ UNKNOWN_EVENT_TYPE = "UNKNOWN_EVENT_TYPE"
83
+ INVALID_EVENT = "INVALID_EVENT"
84
+ IMPLICIT_MESSAGE = "IMPLICIT_MESSAGE"
85
+ UNKNOWN_MESSAGE_ID = "UNKNOWN_MESSAGE_ID"
86
+ UNKNOWN_TOOL_CALL_ID = "UNKNOWN_TOOL_CALL_ID"
87
+ DUPLICATE_ID = "DUPLICATE_ID"
88
+ STALE_RUN_EVENT = "STALE_RUN_EVENT"
89
+ PATCH_FAILED = "PATCH_FAILED"
90
+ ARGS_TOO_LARGE = "ARGS_TOO_LARGE"
91
+ IGNORED_EVENT = "IGNORED_EVENT"
92
+
93
+
94
+ def _restore(cls: type[TolerantPickle], state: dict[str, Any]) -> TolerantPickle:
95
+ """Unpickling entry point: rebuild ``cls`` tolerantly from its pickled state."""
96
+ return cls._from_state(state)
97
+
98
+
99
+ class TolerantPickle:
100
+ """Mixin giving dataclasses a version-tolerant pickle format (DM §8 v1.2).
101
+
102
+ The pickled state is ``{"schema_version": n, **fields}``. Restoring fills missing
103
+ fields with their defaults and drops unknown ones, so an older or newer pickle held
104
+ by the state manager (e.g. Redis) still loads after a library upgrade.
105
+
106
+ It hooks ``__reduce__`` because ``@dataclass(frozen=True, slots=True)`` installs its
107
+ own ``__getstate__``/``__setstate__`` on every class, shadowing a mixin's.
108
+ """
109
+
110
+ __slots__ = ()
111
+
112
+ _schema_version: ClassVar[int] = 1
113
+ _derived_fields: ClassVar[frozenset[str]] = frozenset()
114
+
115
+ @classmethod
116
+ def _persisted_fields(cls) -> tuple[dataclasses.Field[Any], ...]:
117
+ fields = dataclasses.fields(cast("type[DataclassInstance]", cls))
118
+ return tuple(f for f in fields if f.init and f.name not in cls._derived_fields)
119
+
120
+ def _to_state(self) -> dict[str, Any]:
121
+ """Return the pickled form: the schema version plus every persisted field."""
122
+ state: dict[str, Any] = {"schema_version": self._schema_version}
123
+ for f in self._persisted_fields():
124
+ state[f.name] = getattr(self, f.name)
125
+ return state
126
+
127
+ @classmethod
128
+ def _from_state(cls, state: dict[str, Any]) -> Self:
129
+ """Build an instance from a pickled state, tolerating missing and unknown fields."""
130
+ kwargs: dict[str, Any] = {}
131
+ for f in cls._persisted_fields():
132
+ if f.name in state:
133
+ kwargs[f.name] = state[f.name]
134
+ elif f.default is dataclasses.MISSING and f.default_factory is dataclasses.MISSING:
135
+ raise TypeError(
136
+ f"cannot restore {cls.__name__}: required field {f.name!r} is missing"
137
+ )
138
+ return cls(**kwargs)
139
+
140
+ def __reduce__(self) -> tuple[Callable[..., Any], tuple[Any, ...]]:
141
+ return (_restore, (type(self), self._to_state()))
142
+
143
+
144
+ @dataclasses.dataclass(frozen=True, slots=True)
145
+ class ChatMessage(TolerantPickle):
146
+ """A conversation message (DM §3.1, API §5.1)."""
147
+
148
+ id: str
149
+ role: MessageRole
150
+ content: str = ""
151
+ streaming: bool = False
152
+ tool_call_ids: tuple[str, ...] = ()
153
+ tool_call_id: str | None = None
154
+ reasoning: str = ""
155
+ is_error: bool = False
156
+
157
+
158
+ @dataclasses.dataclass(frozen=True, slots=True)
159
+ class ToolCall(TolerantPickle):
160
+ """A tool call issued by the agent (DM §3.2, API §5.2)."""
161
+
162
+ id: str
163
+ name: str
164
+ args_text: str = ""
165
+ args: JsonObject | None = None
166
+ status: ToolCallStatus = ToolCallStatus.STREAMING
167
+ result: str | None = None
168
+ parent_message_id: str | None = None
169
+ interrupt_id: str | None = None
170
+ is_client_tool: bool = False
171
+
172
+
173
+ @dataclasses.dataclass(frozen=True, slots=True)
174
+ class PendingInterrupt(TolerantPickle):
175
+ """The generic interrupt shown to the user; computed by ``project()`` (DM §3.3)."""
176
+
177
+ id: str
178
+ reason: str
179
+ message: str
180
+ payload: JsonValue
181
+ response_schema: JsonObject | None
182
+ queue_position: int
183
+ queue_size: int
184
+
185
+
186
+ @dataclasses.dataclass(frozen=True, slots=True)
187
+ class OpenInterrupt(TolerantPickle):
188
+ """An interrupt of the current pause, or a local client-tool approval (DM §3.4)."""
189
+
190
+ id: str
191
+ reason: str
192
+ message: str = ""
193
+ tool_call_id: str | None = None
194
+ payload: JsonValue = None
195
+ response_schema: JsonObject | None = None
196
+ is_local: bool = False
197
+
198
+
199
+ @dataclasses.dataclass(frozen=True, slots=True)
200
+ class InterruptAnswer(TolerantPickle):
201
+ """The user's answer to an open interrupt, mirroring ``ResumeEntry`` (DM §3.5)."""
202
+
203
+ interrupt_id: str
204
+ status: ResumeStatus
205
+ payload: JsonValue = None
206
+
207
+
208
+ @dataclasses.dataclass(frozen=True, slots=True)
209
+ class ReasoningRecord(TolerantPickle):
210
+ """Reasoning of one assistant turn (DM §3.6). ``encrypted_value`` is never projected."""
211
+
212
+ id: str
213
+ assistant_message_id: str | None = None
214
+ content: str = ""
215
+ encrypted_value: str | None = None
216
+
217
+
218
+ @dataclasses.dataclass(frozen=True, slots=True)
219
+ class CustomEventRecord(TolerantPickle):
220
+ """An AG-UI ``CUSTOM`` event kept in a bounded ring (DM §3.7, API §5.4)."""
221
+
222
+ name: str
223
+ value: JsonValue
224
+ run_id: str
225
+
226
+
227
+ @dataclasses.dataclass(frozen=True, slots=True)
228
+ class Diagnostic(TolerantPickle):
229
+ """A transient, non-fatal reducer diagnostic (DM §3.8, API §11)."""
230
+
231
+ level: DiagnosticLevel
232
+ code: DiagnosticCode
233
+ message: str
234
+ event_type: str | None = None
235
+
236
+
237
+ @dataclasses.dataclass(frozen=True, slots=True)
238
+ class ReducerConfig(TolerantPickle):
239
+ """Per-run reducer settings built from the ``AgentState`` ClassVars (DM §3.9)."""
240
+
241
+ client_tool_names: frozenset[str] = frozenset()
242
+ custom_events_limit: int = 100
243
+ max_args_bytes: int = 1_048_576