agentstate-lib 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.
agentstate/__init__.py ADDED
@@ -0,0 +1,63 @@
1
+ from __future__ import annotations
2
+
3
+ from agentstate.core.events import (
4
+ AgentErrored,
5
+ BaseStateEvent,
6
+ CheckpointSaved,
7
+ ConflictDetected,
8
+ PatchApplied,
9
+ StateEvent,
10
+ WorkflowCompleted,
11
+ WorkflowStarted,
12
+ event_adapter,
13
+ )
14
+ from agentstate.core.patch import (
15
+ StatePatch,
16
+ apply_patch,
17
+ get_nested,
18
+ set_nested,
19
+ )
20
+ from agentstate.core.state import (
21
+ Artifact,
22
+ Decision,
23
+ Goal,
24
+ SharedState,
25
+ Task,
26
+ WorkflowStatus,
27
+ )
28
+ from agentstate.memory.store import InMemoryStore, SQLiteStore, StateStore
29
+ from agentstate.router.context import slice_state
30
+ from agentstate.router.graph import AgentGraph
31
+ from agentstate.router.types import AgentFn, EdgeCondition
32
+
33
+ __version__ = "0.1.0"
34
+
35
+ __all__ = [
36
+ "SharedState",
37
+ "Task",
38
+ "Goal",
39
+ "Artifact",
40
+ "Decision",
41
+ "WorkflowStatus",
42
+ "StatePatch",
43
+ "apply_patch",
44
+ "set_nested",
45
+ "get_nested",
46
+ "StateEvent",
47
+ "BaseStateEvent",
48
+ "WorkflowStarted",
49
+ "WorkflowCompleted",
50
+ "PatchApplied",
51
+ "ConflictDetected",
52
+ "CheckpointSaved",
53
+ "AgentErrored",
54
+ "event_adapter",
55
+ "AgentGraph",
56
+ "AgentFn",
57
+ "EdgeCondition",
58
+ "slice_state",
59
+ "StateStore",
60
+ "InMemoryStore",
61
+ "SQLiteStore",
62
+ "__version__",
63
+ ]
File without changes
agentstate/api/app.py ADDED
File without changes
agentstate/api/auth.py ADDED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,30 @@
1
+ from .events import (
2
+ AgentErrored,
3
+ BaseStateEvent,
4
+ CheckpointSaved,
5
+ ConflictDetected,
6
+ PatchApplied,
7
+ StateEvent,
8
+ WorkflowCompleted,
9
+ WorkflowStarted,
10
+ event_adapter,
11
+ )
12
+ from .state import Artifact, Decision, Goal, SharedState, Task, WorkflowStatus
13
+
14
+ __all__ = [
15
+ "SharedState",
16
+ "Task",
17
+ "Goal",
18
+ "Artifact",
19
+ "Decision",
20
+ "WorkflowStatus",
21
+ "StateEvent",
22
+ "BaseStateEvent",
23
+ "WorkflowStarted",
24
+ "WorkflowCompleted",
25
+ "PatchApplied",
26
+ "ConflictDetected",
27
+ "CheckpointSaved",
28
+ "AgentErrored",
29
+ "event_adapter",
30
+ ]
@@ -0,0 +1,74 @@
1
+ import time
2
+ import uuid
3
+ from typing import Annotated, Any, Literal
4
+
5
+ from pydantic import BaseModel, Field, TypeAdapter
6
+
7
+
8
+ # This is the parent all events share
9
+ class BaseStateEvent(BaseModel):
10
+ event_id : str = Field(default_factory=lambda: str(uuid.uuid4()))
11
+ workflow_id : str
12
+ agent_id : str
13
+ timestamp : float = Field(default_factory=time.time)
14
+
15
+
16
+ # six subclasses inherting from BaseStateEvent,
17
+ # with each one, having a 'type' field typed as a literal with
18
+ # a single string value, and set its default to that string.
19
+
20
+ class WorkflowStarted(BaseStateEvent):
21
+ type : Literal["workflow_started"]
22
+ workflow_type : str
23
+ goal : str
24
+
25
+
26
+ class WorkflowCompleted(BaseStateEvent):
27
+ type : Literal["workflow_completed"]
28
+ final_status : Any
29
+
30
+
31
+ class PatchApplied(BaseStateEvent):
32
+ type : Literal["patch_applied"]
33
+ patch_id : str
34
+ target : str
35
+ old_value : Any
36
+ new_value : Any
37
+ reason : str
38
+
39
+
40
+ class ConflictDetected(BaseStateEvent):
41
+ type : Literal["conflict_detected"]
42
+ conflict_id : str
43
+ path : str
44
+ winner_agent_id : str
45
+ loser_agent_id : str
46
+ resolution_strategy : str
47
+
48
+
49
+ class CheckpointSaved(BaseStateEvent):
50
+ type : Literal["checkpoint_saved"]
51
+ checkpoint_id : str
52
+ event_count : int
53
+
54
+ class AgentErrored(BaseStateEvent):
55
+ type : Literal["agent_errored"]
56
+ error_type : str
57
+ error_message : str
58
+ retry_count : int
59
+
60
+ # Pydantic will use the type field to decide which model to instantiate
61
+ # when deserializing
62
+ StateEvent = Annotated[
63
+ WorkflowStarted
64
+ | WorkflowCompleted
65
+ | PatchApplied
66
+ | ConflictDetected
67
+ | CheckpointSaved
68
+ | AgentErrored,
69
+ Field(discriminator="type")
70
+ ]
71
+
72
+ # at module level, writing a typeadapter for statevent
73
+ # this is how you deserialize a JSON string into the correct event subtype
74
+ event_adapter: TypeAdapter[StateEvent] = TypeAdapter(StateEvent)
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import uuid
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+ from agentstate.core.state import SharedState
10
+
11
+
12
+ # represents "one change an agent wants to make" to the shared state
13
+ class StatePatch(BaseModel):
14
+ patch_id:str = Field(default_factory=lambda: str(uuid.uuid4()))
15
+ agent_id: str
16
+ target : str # dotted path, eg: tasks.task_1.status
17
+ value : Any
18
+ reason : str
19
+ timestamp : float = Field(default_factory=time.time)
20
+ priority : int = 0
21
+
22
+ def set_nested(obj: dict[str, Any], path: str, value : Any) -> dict[str, Any]:
23
+ """
24
+ Set value at a dotted path inside a nested dict, creating dicts as needed.
25
+ """
26
+ parts = path.split(".") # turns "a.b.c" into ["a","b","c"]
27
+ current : dict[str, Any] = obj
28
+
29
+ for key in parts[:-1]:
30
+ if key not in current or not isinstance(current[key], dict):
31
+ current[key] = {}
32
+ current = current[key]
33
+
34
+ current[parts[-1]] = value
35
+ return obj
36
+
37
+ def get_nested(obj: dict[str, Any], path: str) -> Any:
38
+ """
39
+ Get value at a dotted path from a nested dict, or None if missing.
40
+ """
41
+
42
+ parts = path.split(".")
43
+ current : Any = obj
44
+
45
+ for key in parts:
46
+ if not isinstance(current, dict):
47
+ return None
48
+ if key not in current:
49
+ return None
50
+ current = current[key]
51
+
52
+ return current
53
+
54
+ # creates a dict view of SharedState with model_dump()
55
+ def apply_patch(state: SharedState, patch: StatePatch) -> SharedState:
56
+ """Return a new SharedState with the patch applied at patch.target"""
57
+ state_dict = state.model_dump()
58
+ set_nested(state_dict, patch.target, patch.value)
59
+ return SharedState.model_validate(state_dict)
@@ -0,0 +1,49 @@
1
+ import time
2
+ import uuid
3
+ from typing import Any, Literal
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ WorkflowStatus = Literal["running", "complete", "failed", "paused"]
8
+
9
+ class Task(BaseModel):
10
+ id : str = Field(default_factory=lambda: str(uuid.uuid4()))
11
+ description : str
12
+ status : Literal["pending", "running", "done", "failed"] = 'pending'
13
+ result : Any | None = None
14
+ created_at : float = Field(default_factory=time.time)
15
+ updated_as: float = Field(default_factory=time.time)
16
+
17
+
18
+ class Goal(BaseModel):
19
+ id: str = Field(default_factory=lambda: str(uuid.uuid4()))
20
+ description : str
21
+ status : Literal["pending", "active", "complete", "failed"] = 'pending'
22
+ created_at : float = Field(default_factory=time.time)
23
+
24
+ class Artifact(BaseModel):
25
+ id : str = Field(default_factory=lambda : str(uuid.uuid4()))
26
+ produced_by : str
27
+ artifact_type : str
28
+ content : Any
29
+ created_at : float = Field(default_factory=time.time)
30
+
31
+ class Decision(BaseModel):
32
+ id : str = Field(default_factory=lambda : str(uuid.uuid4()))
33
+ made_by : str
34
+ description : str
35
+ rationale : str
36
+ timestamp : float = Field(default_factory=time.time)
37
+
38
+ class SharedState(BaseModel):
39
+ workflow_id : str = Field(default_factory=lambda: str(uuid.uuid4()))
40
+ workflow_type : str = "general"
41
+ goal : str
42
+ goals : dict[str, Goal] = Field(default_factory=dict)
43
+ tasks : dict[str, Task] = Field(default_factory=dict)
44
+ artifacts : dict[str, Artifact] = Field(default_factory=dict)
45
+ decisions : list[Decision] = Field(default_factory=list)
46
+ facts : dict[str, Any] = Field(default_factory=dict)
47
+ status : WorkflowStatus = 'running'
48
+ created_at : float = Field(default_factory=time.time)
49
+ updated_at : float = Field(default_factory=time.time)
@@ -0,0 +1,11 @@
1
+ from .store import (
2
+ InMemoryStore,
3
+ SQLiteStore,
4
+ StateStore,
5
+ )
6
+
7
+ __all__ = [
8
+ "StateStore",
9
+ "InMemoryStore",
10
+ "SQLiteStore",
11
+ ]
File without changes
File without changes
@@ -0,0 +1,134 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ import aiosqlite
4
+
5
+ from agentstate.core.events import StateEvent, event_adapter
6
+
7
+
8
+ # Protocol : a rule sheet for what a store must be able to do
9
+ @runtime_checkable
10
+ class StateStore(Protocol):
11
+ async def append(self, event: StateEvent) -> None:
12
+ ...
13
+
14
+ async def get_workflow(self, workflow_id: str) -> list[StateEvent]:
15
+ ...
16
+
17
+ async def since(self, workflow_id: str, index: int) -> list[StateEvent]:
18
+ ...
19
+
20
+ async def count(self, workflow_id: str) -> int:
21
+ ...
22
+
23
+ class InMemoryStore:
24
+ def __init__(self) -> None:
25
+ self._events: dict[str, list[StateEvent]] = {}
26
+
27
+ async def append(self, event: StateEvent) -> None:
28
+ if event.workflow_id not in self._events:
29
+ self._events[event.workflow_id] = []
30
+ self._events[event.workflow_id].append(event)
31
+
32
+ async def get_workflow(self, workflow_id: str) -> list[StateEvent]:
33
+ return list(self._events.get(workflow_id, []))
34
+
35
+ async def since(self, workflow_id : str, index: int) -> list[StateEvent]:
36
+ return list(self._events.get(workflow_id, [])[index:])
37
+
38
+ async def count(self, workflow_id: str) -> int:
39
+ return len(self._events.get(workflow_id, []))
40
+
41
+ # this method should create the events table if it does not already exists
42
+ # create an index on workflow_id
43
+ # commit the changes
44
+ class SQLiteStore:
45
+ def __init__(self, path: str) -> None:
46
+ self.path = path
47
+
48
+ async def _init_db(self, db:aiosqlite.Connection) -> None:
49
+ await db.execute(
50
+ """
51
+ CREATE TABLE IF NOT EXISTS events(
52
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
53
+ event_id TEXT NOT NULL,
54
+ workflow_id TEXT NOT NULL,
55
+ type TEXT NOT NULL,
56
+ data TEXT NOT NULL,
57
+ timestamp REAL NOT NULL
58
+ )
59
+ """
60
+ )
61
+
62
+ await db.execute(
63
+ """
64
+ CREATE INDEX IF NOT EXISTS idx_wf_id
65
+ ON events(workflow_id)
66
+ """
67
+ )
68
+
69
+ await db.commit()
70
+
71
+ async def append(self, event: StateEvent) -> None:
72
+ async with aiosqlite.connect(self.path) as db:
73
+ await self._init_db(db)
74
+ await db.execute(
75
+ """
76
+ INSERT INTO events(event_id, workflow_id, type, data, timestamp)
77
+ VALUES (?, ?, ?, ?, ?)
78
+ """,
79
+ (
80
+ event.event_id,
81
+ event.workflow_id,
82
+ event.type,
83
+ event.model_dump_json(),
84
+ event.timestamp,
85
+ ),
86
+ )
87
+ await db.commit()
88
+
89
+ async def get_workflow(self, workflow_id : str) -> list[StateEvent]:
90
+ async with aiosqlite.connect(self.path) as db:
91
+ await self._init_db(db)
92
+ cursor = await db.execute(
93
+ """
94
+ SELECT data
95
+ FROM events
96
+ WHERE workflow_id=?
97
+ ORDER BY id ASC
98
+ """,
99
+ (workflow_id,),
100
+ )
101
+ rows = await cursor.fetchall()
102
+ return [event_adapter.validate_json(row[0]) for row in rows]
103
+
104
+ async def since(self, workflow_id: str, index: int) -> list[StateEvent]:
105
+ async with aiosqlite.connect(self.path) as db:
106
+ await self._init_db(db)
107
+ cursor = await db.execute(
108
+ """
109
+ SELECT data
110
+ FROM events
111
+ WHERE workflow_id=?
112
+ ORDER BY id ASC
113
+ LIMIT -1 OFFSET ?
114
+ """,
115
+ (workflow_id, index),
116
+ )
117
+ rows = await cursor.fetchall()
118
+ return [event_adapter.validate_json(row[0]) for row in rows]
119
+
120
+
121
+ async def count(self, workflow_id: str) -> int:
122
+ async with aiosqlite.connect(self.path) as db:
123
+ await self._init_db(db)
124
+ cursor = await db.execute(
125
+ """
126
+ SELECT COUNT(*)
127
+ FROM events
128
+ WHERE workflow_id=?
129
+ """,
130
+ (workflow_id,),
131
+ )
132
+ row = await cursor.fetchone()
133
+ return int(row[0]) if row else 0
134
+
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from agentstate.router.context import slice_state
4
+ from agentstate.router.graph import AgentGraph
5
+ from agentstate.router.types import AgentFn, EdgeCondition
6
+
7
+ __all__ = [
8
+ "AgentGraph",
9
+ "AgentFn",
10
+ "EdgeCondition",
11
+ "slice_state",
12
+ ]
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from agentstate.core.patch import get_nested, set_nested
6
+ from agentstate.core.state import SharedState
7
+
8
+
9
+ def slice_state(state: SharedState, include_paths: list[str]) -> dict[str, Any]:
10
+ """
11
+ Returns a dict view of just the requested paths from SharedState.
12
+ if include_paths is empty, return the full state dict
13
+ """
14
+ full_dict = state.model_dump()
15
+ # no slice requested mean "full context"
16
+ if not include_paths:
17
+ return full_dict
18
+
19
+ result : dict[str, Any] = {}
20
+ for path in include_paths:
21
+ value = get_nested(full_dict, path)
22
+ if value is not None:
23
+ set_nested(result, path, value)
24
+ return result
@@ -0,0 +1,162 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import Callable
5
+ from dataclasses import dataclass
6
+
7
+ from agentstate.core.events import (
8
+ PatchApplied,
9
+ WorkflowCompleted,
10
+ WorkflowStarted,
11
+ )
12
+ from agentstate.core.patch import apply_patch
13
+ from agentstate.core.state import SharedState
14
+ from agentstate.memory.store import InMemoryStore, StateStore
15
+ from agentstate.router.context import slice_state
16
+ from agentstate.router.types import AgentFn, EdgeCondition
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class _Node:
21
+ agent_id: str
22
+ fn : AgentFn
23
+ context_keys : list[str]
24
+
25
+ @dataclass(frozen=True)
26
+ class _Edge:
27
+ from_agent : str
28
+ to_agent: str
29
+ condition: EdgeCondition
30
+
31
+ class AgentGraph:
32
+ """A simple directed graph of agents with conditional edges."""
33
+
34
+ def __init__(
35
+ self,
36
+ store: StateStore | None = None,
37
+ max_concurrent: int = 3,
38
+ ) ->None:
39
+ self._store: StateStore = store or InMemoryStore()
40
+ self._nodes: dict[str, _Node] = {}
41
+ self._edges: list[_Edge] = []
42
+ self._sem = asyncio.Semaphore(max_concurrent)
43
+
44
+ def node(
45
+ self,
46
+ agent_id: str,
47
+ context: list[str] | None = None,
48
+ ) -> Callable[[AgentFn], AgentFn]:
49
+ """Decorator to register an agent function under a given agent_id"""
50
+
51
+ def decorator(fn:AgentFn) -> AgentFn:
52
+ node = _Node(
53
+ agent_id=agent_id,
54
+ fn=fn,
55
+ context_keys=context or [],
56
+ )
57
+ self._nodes[agent_id] = node
58
+ return fn
59
+ return decorator
60
+
61
+ def edge(
62
+ self,
63
+ from_agent: str,
64
+ to_agent: str,
65
+ condition: EdgeCondition | None = None,
66
+ ) -> None:
67
+ """Add a directed edge between two agents."""
68
+ cond = condition or (lambda s: True)
69
+ self._edges.append(
70
+ _Edge(
71
+ from_agent=from_agent,
72
+ to_agent=to_agent,
73
+ condition=cond,
74
+ ),
75
+ )
76
+
77
+ def _next_agent(self, current_id:str, state:SharedState) -> str | None:
78
+ """Return the next agent_id to run current_id, or None if done."""
79
+ state_dict = state.model_dump()
80
+
81
+ for edge in self._edges:
82
+ if edge.from_agent != current_id:
83
+ continue
84
+ if edge.condition(state_dict):
85
+ return edge.to_agent
86
+
87
+ return None
88
+
89
+ async def run(
90
+ self,
91
+ state: SharedState,
92
+ start: str,
93
+ event_queue: asyncio.Queue[PatchApplied | WorkflowStarted
94
+ | WorkflowCompleted] | None = None,
95
+ ) -> SharedState:
96
+ """Run the agent graph starting from the given agent_id"""
97
+ if start not in self._nodes:
98
+ msg = f"Start agent '{start}' is not registered in this AgentGraph."
99
+ raise ValueError(msg)
100
+
101
+ # for now, use the state's workflow_id as the workflow identifier
102
+ workflow_id = state.workflow_id
103
+
104
+ # Record workflow start
105
+ workflow_started = WorkflowStarted(
106
+ workflow_id=workflow_id,
107
+ agent_id="system",
108
+ workflow_type=state.workflow_type,
109
+ goal=state.goal,
110
+ type="workflow_started",
111
+ )
112
+ await self._store.append(workflow_started)
113
+ if event_queue is not None:
114
+ event_queue.put_nowait(workflow_started)
115
+
116
+ current_id: str | None = start
117
+ current_state = state
118
+
119
+ while current_id is not None:
120
+ if current_id not in self._nodes:
121
+ msg = f"Agent '{current_id}' is not registered in this AgentGraph."
122
+ raise ValueError(msg)
123
+
124
+ node = self._nodes[current_id]
125
+ context = slice_state(current_state, node.context_keys)
126
+
127
+ async with self._sem:
128
+ patch = await node.fn(context)
129
+
130
+ old_value = current_state.model_dump()
131
+ current_state = apply_patch(current_state, patch)
132
+ new_value = current_state.model_dump()
133
+
134
+ patch_event = PatchApplied(
135
+ workflow_id=workflow_id,
136
+ agent_id=patch.agent_id,
137
+ type="patch_applied",
138
+ patch_id=patch.patch_id,
139
+ target=patch.target,
140
+ old_value=old_value,
141
+ new_value=new_value,
142
+ reason=patch.reason,
143
+ timestamp=patch.timestamp,
144
+ )
145
+ await self._store.append(patch_event)
146
+ if event_queue is not None:
147
+ event_queue.put_nowait(patch_event)
148
+
149
+ current_id = self._next_agent(node.agent_id, current_state)
150
+
151
+ workflow_completed = WorkflowCompleted(
152
+ workflow_id=workflow_id,
153
+ agent_id="system",
154
+ type="workflow_completed",
155
+ final_status=current_state.status,
156
+ )
157
+ await self._store.append(workflow_completed)
158
+ if event_queue is not None:
159
+ event_queue.put_nowait(workflow_completed)
160
+
161
+ return current_state
162
+
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Awaitable, Callable
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from agentstate.core.patch import StatePatch
8
+
9
+ # Any async function that takes a context dict and returns a StatePatch
10
+ # is a valid agent. No inheritance required.
11
+ AgentFn = Callable[[dict[str,Any]], Awaitable["StatePatch"]]
12
+
13
+ # A function that takes the current state as a dict and returns True
14
+ # if this edge should be followed.
15
+ EdgeCondition = Callable[[dict[str, Any]], bool]
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentstate_lib
3
+ Version: 0.1.0
4
+ Summary: Stateful coordination layer for multi-agent AI systems
5
+ Author-email: Tanveer Kaur <tanveerkaur1292@outlook.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: agents,llm,multi-agent,orchestration,state
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: aiosqlite>=0.19
11
+ Requires-Dist: pydantic>=2.0
12
+ Provides-Extra: api
13
+ Requires-Dist: fastapi>=0.100; extra == 'api'
14
+ Requires-Dist: uvicorn[standard]>=0.20; extra == 'api'
15
+ Provides-Extra: contrib
16
+ Provides-Extra: dashboard
17
+ Requires-Dist: rich>=13.0; extra == 'dashboard'
18
+ Provides-Extra: dev
19
+ Requires-Dist: httpx>=0.24; extra == 'dev'
20
+ Requires-Dist: hypothesis>=6.0; extra == 'dev'
21
+ Requires-Dist: mypy>=1.0; extra == 'dev'
22
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
23
+ Requires-Dist: pytest>=7.0; extra == 'dev'
24
+ Requires-Dist: ruff>=0.1; extra == 'dev'
25
+ Provides-Extra: otel
26
+ Requires-Dist: opentelemetry-api; extra == 'otel'
27
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc; extra == 'otel'
28
+ Requires-Dist: opentelemetry-sdk; extra == 'otel'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # agentstate
32
+ Building a stateful coordination layer for multi-agent AI systems.
33
+
@@ -0,0 +1,32 @@
1
+ agentstate/__init__.py,sha256=3YZ6uWZUa7E1L8xC4OrBUFJ2ndiRfGDUSEqIPra3D9c,1325
2
+ agentstate/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ agentstate/api/app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ agentstate/api/auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ agentstate/api/cache.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ agentstate/api/routes.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ agentstate/api/streaming.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ agentstate/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ agentstate/contrib/base_agent.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ agentstate/coordination/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ agentstate/coordination/conflicts.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ agentstate/coordination/invariants.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ agentstate/core/__init__.py,sha256=MzflZdUoctDKhZzpJbyZbjM9JLhQmQKpBFuXE8p2Mm4,617
14
+ agentstate/core/events.py,sha256=5dKXoS5CYd_PXWrZ65pwZfbPBg-VbtiGJQEsMJEkWHQ,1960
15
+ agentstate/core/patch.py,sha256=4d27aIdnekcmSY7MpMgVTMbqLpC_JK4A7qO5xT866Yw,1799
16
+ agentstate/core/state.py,sha256=FkafgxnVDJ2P2XtkUNjAPKkE9BZwM1pOn7ukTCY1VVs,1821
17
+ agentstate/memory/__init__.py,sha256=21GRbnmwoNmV--n9LJxti-weTo1mrBhuAwgR0qJBF6g,159
18
+ agentstate/memory/checkpoint.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ agentstate/memory/replay.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ agentstate/memory/store.py,sha256=omOIWwdccotsqFQTbMY1crfOBJQJX-ijY6MdE2EIZHo,4425
21
+ agentstate/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ agentstate/observability/analysis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ agentstate/observability/dashboard.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ agentstate/observability/tracing.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ agentstate/router/__init__.py,sha256=qROHk83A6XTM88J6EEWiSPwr6czaWGNuVMXOC0Mc-zo,290
26
+ agentstate/router/context.py,sha256=7XSPOPqpZgytyBIhsbLPHYLvYSaxzd2eHJUDoAAob7Y,751
27
+ agentstate/router/graph.py,sha256=S_m96lUwwuw2H30v8mH7Ja4CPYUkHpJL7ZkYboqk8fE,5342
28
+ agentstate/router/types.py,sha256=SkuV6l1kpjSn4QpdVD5gH1Ojp-Hsn7NKysF3Asp7ljM,536
29
+ agentstate_lib-0.1.0.dist-info/METADATA,sha256=qKTj7tG29p5A15FOnzz90AD1om02LeqqmiLN7aQESbs,1171
30
+ agentstate_lib-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
31
+ agentstate_lib-0.1.0.dist-info/licenses/LICENSE,sha256=zUb9KlZdCdZd8E5fO4a-ySskntrRYVApJRiDhk9J54w,1090
32
+ agentstate_lib-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tanveer kaur
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.