agentforge-core 0.2.1__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 (58) hide show
  1. agentforge_core/__init__.py +228 -0
  2. agentforge_core/_bm25.py +132 -0
  3. agentforge_core/config/__init__.py +62 -0
  4. agentforge_core/config/loader.py +239 -0
  5. agentforge_core/config/module_schemas.py +208 -0
  6. agentforge_core/config/schema.py +424 -0
  7. agentforge_core/contracts/__init__.py +52 -0
  8. agentforge_core/contracts/auth.py +33 -0
  9. agentforge_core/contracts/chat.py +118 -0
  10. agentforge_core/contracts/embedding.py +71 -0
  11. agentforge_core/contracts/evaluator.py +56 -0
  12. agentforge_core/contracts/finding.py +39 -0
  13. agentforge_core/contracts/graph_store.py +180 -0
  14. agentforge_core/contracts/guardrails.py +129 -0
  15. agentforge_core/contracts/llm.py +152 -0
  16. agentforge_core/contracts/memory.py +113 -0
  17. agentforge_core/contracts/migrator.py +120 -0
  18. agentforge_core/contracts/renderer.py +57 -0
  19. agentforge_core/contracts/reranker.py +91 -0
  20. agentforge_core/contracts/strategy.py +70 -0
  21. agentforge_core/contracts/task.py +73 -0
  22. agentforge_core/contracts/tool.py +71 -0
  23. agentforge_core/contracts/vector_store.py +151 -0
  24. agentforge_core/migrations/__init__.py +14 -0
  25. agentforge_core/migrations/discover.py +77 -0
  26. agentforge_core/migrations/template.py +34 -0
  27. agentforge_core/observability/__init__.py +18 -0
  28. agentforge_core/observability/tracing.py +37 -0
  29. agentforge_core/production/__init__.py +77 -0
  30. agentforge_core/production/budget.py +134 -0
  31. agentforge_core/production/exceptions.py +136 -0
  32. agentforge_core/production/fallback.py +321 -0
  33. agentforge_core/production/log_filter.py +49 -0
  34. agentforge_core/production/log_format.py +117 -0
  35. agentforge_core/production/run_context.py +108 -0
  36. agentforge_core/py.typed +0 -0
  37. agentforge_core/resolver/__init__.py +38 -0
  38. agentforge_core/resolver/discover.py +145 -0
  39. agentforge_core/resolver/resolve.py +168 -0
  40. agentforge_core/testing/__init__.py +45 -0
  41. agentforge_core/testing/conformance.py +1138 -0
  42. agentforge_core/values/__init__.py +103 -0
  43. agentforge_core/values/auth.py +20 -0
  44. agentforge_core/values/chat.py +131 -0
  45. agentforge_core/values/claim.py +30 -0
  46. agentforge_core/values/graph.py +136 -0
  47. agentforge_core/values/guardrails.py +49 -0
  48. agentforge_core/values/manifest.py +129 -0
  49. agentforge_core/values/messages.py +153 -0
  50. agentforge_core/values/module.py +40 -0
  51. agentforge_core/values/pipeline.py +43 -0
  52. agentforge_core/values/retrieval.py +53 -0
  53. agentforge_core/values/state.py +118 -0
  54. agentforge_core/values/vector.py +59 -0
  55. agentforge_core-0.2.1.dist-info/METADATA +66 -0
  56. agentforge_core-0.2.1.dist-info/RECORD +58 -0
  57. agentforge_core-0.2.1.dist-info/WHEEL +4 -0
  58. agentforge_core-0.2.1.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,153 @@
1
+ """Provider-agnostic message and response shapes for the LLM contract.
2
+
3
+ Every `LLMClient` returns `LLMResponse`; every reasoning strategy
4
+ operates on `list[Message]` regardless of which provider backs the
5
+ agent. Streaming clients yield `StreamChunk`s; embedding clients
6
+ return `EmbeddingResponse`.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Literal
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field
14
+
15
+ StreamChunkKind = Literal["text", "tool_call", "stop", "thinking"]
16
+ """Closed enum of stream-chunk kinds. Provider drivers normalise their
17
+ event streams into a sequence of these chunks. Adding a new kind is a
18
+ minor version bump."""
19
+
20
+ MessageRole = Literal["system", "user", "assistant", "tool"]
21
+ """Allowed message roles. Mirrors the Anthropic / OpenAI common set."""
22
+
23
+ StopReason = Literal["end_turn", "tool_use", "max_tokens", "stop_sequence", "other"]
24
+ """Provider-normalised reason the LLM stopped emitting tokens."""
25
+
26
+
27
+ class Message(BaseModel):
28
+ """One turn in the chat-completion exchange."""
29
+
30
+ model_config = ConfigDict(frozen=True, strict=True)
31
+
32
+ role: MessageRole
33
+ content: str
34
+ name: str | None = None
35
+ tool_call_id: str | None = None
36
+
37
+
38
+ class ToolCall(BaseModel):
39
+ """A tool invocation emitted by the LLM."""
40
+
41
+ model_config = ConfigDict(frozen=True, strict=True)
42
+
43
+ id: str
44
+ name: str
45
+ arguments: dict[str, Any] = Field(default_factory=dict)
46
+
47
+
48
+ class ToolSpec(BaseModel):
49
+ """Provider-agnostic tool description sent to the LLM.
50
+
51
+ `schema` is the JSON-schema dict (typically from a Pydantic model's
52
+ `model_json_schema()`). The `Tool` ABC's `to_spec()` produces this.
53
+ """
54
+
55
+ model_config = ConfigDict(frozen=True, strict=True)
56
+
57
+ name: str
58
+ description: str
59
+ schema_: dict[str, Any] = Field(alias="schema")
60
+
61
+
62
+ class TokenUsage(BaseModel):
63
+ """Token accounting from a single LLM call."""
64
+
65
+ model_config = ConfigDict(frozen=True, strict=True)
66
+
67
+ input_tokens: int = Field(ge=0)
68
+ output_tokens: int = Field(ge=0)
69
+ cache_read_tokens: int = Field(default=0, ge=0)
70
+ cache_write_tokens: int = Field(default=0, ge=0)
71
+ thinking_tokens: int = Field(default=0, ge=0)
72
+
73
+ @property
74
+ def total(self) -> int:
75
+ """Sum of input + output tokens (excludes cache and thinking metadata)."""
76
+ return self.input_tokens + self.output_tokens
77
+
78
+
79
+ class LLMResponse(BaseModel):
80
+ """Provider-agnostic response from one LLM call."""
81
+
82
+ model_config = ConfigDict(frozen=True, strict=True)
83
+
84
+ content: str
85
+ tool_calls: tuple[ToolCall, ...] = ()
86
+ stop_reason: StopReason
87
+ usage: TokenUsage
88
+ cost_usd: float = Field(ge=0.0)
89
+ model: str
90
+ provider: str
91
+
92
+
93
+ class StreamChunk(BaseModel):
94
+ """One event in a provider's streaming response.
95
+
96
+ Streaming `LLMClient`s yield an `AsyncIterator[StreamChunk]`. The
97
+ chunks are ordered: text deltas, optional thinking blocks, optional
98
+ tool-call deltas, and exactly one terminal `stop` chunk carrying
99
+ the final usage and cost. Consumers that don't care about
100
+ streaming can accumulate chunks into a single `LLMResponse` via
101
+ a helper.
102
+ """
103
+
104
+ model_config = ConfigDict(frozen=True, strict=True)
105
+
106
+ kind: StreamChunkKind
107
+ delta: str = ""
108
+ """Incremental content for `text` and `thinking` kinds (empty for
109
+ `tool_call` and `stop`)."""
110
+
111
+ tool_call: ToolCall | None = None
112
+ """The fully-assembled `ToolCall` for `kind == "tool_call"` chunks.
113
+ Provider drivers buffer tool-call argument streams internally and
114
+ emit one chunk once the call is complete."""
115
+
116
+ stop_reason: StopReason | None = None
117
+ """Set on the terminal `stop` chunk; `None` otherwise."""
118
+
119
+ usage: TokenUsage | None = None
120
+ """Final token accounting on the terminal `stop` chunk."""
121
+
122
+ cost_usd: float = Field(default=0.0, ge=0.0)
123
+ """Final cost on the terminal `stop` chunk; `0.0` on intermediate
124
+ chunks."""
125
+
126
+
127
+ class EmbeddingResponse(BaseModel):
128
+ """Provider-agnostic response from an embedding call.
129
+
130
+ `vectors` is a list of float lists — one vector per input text in
131
+ the same order the texts were passed. Every vector has the same
132
+ `dimensions` (the model-declared dimensionality).
133
+ """
134
+
135
+ model_config = ConfigDict(frozen=True, strict=True)
136
+
137
+ vectors: tuple[tuple[float, ...], ...]
138
+ """One vector per input text, in input order. Tuples-of-tuples
139
+ keeps the response frozen and hashable while the dimensionality
140
+ stays uniform across vectors."""
141
+
142
+ dimensions: int = Field(ge=1)
143
+ """Length of every vector. The `EmbeddingClient.dimensions()`
144
+ accessor declares this up front for callers that need to size
145
+ storage before the call."""
146
+
147
+ usage: TokenUsage
148
+ """Token accounting (input only — embeddings produce no output
149
+ tokens)."""
150
+
151
+ cost_usd: float = Field(ge=0.0)
152
+ model: str
153
+ provider: str
@@ -0,0 +1,40 @@
1
+ """`ModuleInfo` — descriptor for a registered module (feat-010).
2
+
3
+ Returned by `Resolver.list_installed`. Carries enough metadata for
4
+ the `agentforge list modules` CLI to render a useful table:
5
+ the entry-point category + name, the providing distribution + its
6
+ version, and the class object itself (for introspection — e.g.
7
+ capabilities, docstring).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from pydantic import BaseModel, ConfigDict, Field
13
+
14
+
15
+ class ModuleInfo(BaseModel):
16
+ """Metadata about one registered module.
17
+
18
+ Attributes:
19
+ category: Entry-point group suffix — e.g. `"providers"`,
20
+ `"memory"`, `"tools"`, `"hooks"`, `"renderers"`,
21
+ `"evaluators"`. Matches the second arg to `register`.
22
+ name: Per-category identifier — e.g. `"bedrock"`, `"sqlite"`.
23
+ package: Distribution that provided the class, if known
24
+ (`"agentforge-bedrock"`, `"agentforge"`, etc.). `None`
25
+ for classes registered via `@register` from an unpackaged
26
+ location (typical in tests or single-file agents).
27
+ version: Distribution version (`"0.2.1"`). `None` when
28
+ `package` is `None`.
29
+ cls_qualname: Fully-qualified class name (`"agentforge_bedrock.client.BedrockClient"`)
30
+ — useful for diagnostic output without pulling the class
31
+ object into the renderer.
32
+ """
33
+
34
+ model_config = ConfigDict(frozen=True, strict=True)
35
+
36
+ category: str = Field(min_length=1)
37
+ name: str = Field(min_length=1)
38
+ package: str | None = None
39
+ version: str | None = None
40
+ cls_qualname: str = Field(min_length=1)
@@ -0,0 +1,43 @@
1
+ """`PipelineResult` — the locked output of `Pipeline.run()`.
2
+
3
+ feat-015 ships this as a frozen Pydantic value model. The runtime
4
+ stores it on the agent for the duration of one run (system prompt
5
+ addendum + ``pipeline_findings`` built-in tool) and optionally
6
+ records it as a single ``__pipeline`` claim when ``record_runs`` is
7
+ configured.
8
+
9
+ `findings` is a list of `Finding` Protocol-compatible objects (the
10
+ shipped variants from ``agentforge.findings`` all satisfy it). The
11
+ shape stays tolerant of custom finding subclasses.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+
18
+ from pydantic import BaseModel, ConfigDict, Field
19
+
20
+
21
+ class PipelineResult(BaseModel):
22
+ """Consolidated output of one `Pipeline.run()` call.
23
+
24
+ Fields:
25
+ findings: All findings emitted across every task, in the
26
+ order each task completed. Task-failure entries (when
27
+ ``on_task_error="continue"``) appear here too as
28
+ ``SimpleFinding(category="pipeline.task_failure")``.
29
+ task_durations_ms: Per-task wallclock duration in
30
+ milliseconds.
31
+ task_failures: Map of task name → error message for any
32
+ task that raised. Empty when every task succeeded.
33
+ total_cost_usd: Sum of ``cost_estimate_usd`` across all
34
+ tasks that ran (the engine charges this against the
35
+ agent's budget).
36
+ """
37
+
38
+ model_config = ConfigDict(frozen=True, strict=True)
39
+
40
+ findings: tuple[Any, ...] = ()
41
+ task_durations_ms: dict[str, int] = Field(default_factory=dict)
42
+ task_failures: dict[str, str] = Field(default_factory=dict)
43
+ total_cost_usd: float = Field(default=0.0, ge=0.0)
@@ -0,0 +1,53 @@
1
+ """Retrieval-ergonomics value types (feat-023).
2
+
3
+ `GraphExpansion` bundles the knobs callers pass when wiring a
4
+ `Retriever` with graph-augmented expansion — the GraphStore to
5
+ traverse, the hop budget, edge-type filtering, the node property
6
+ to use as match text, and the per-hop score decay.
7
+
8
+ Kept frozen + strict per the framework's value-type policy. The
9
+ `store` field tolerates an `ABC` instance via
10
+ `arbitrary_types_allowed=True` — `GraphStore` isn't itself a
11
+ Pydantic model.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from pydantic import BaseModel, ConfigDict, Field
17
+
18
+ from agentforge_core.contracts.graph_store import GraphStore
19
+
20
+
21
+ class GraphExpansion(BaseModel):
22
+ """Graph-traversal configuration for :class:`Retriever`
23
+ post-retrieve augmentation (feat-023).
24
+
25
+ Attributes:
26
+ store: The `GraphStore` driver to traverse.
27
+ ``VectorMatch.id`` ↔ ``GraphNode.id`` alignment is a
28
+ caller contract; mismatched ids silently skip
29
+ expansion for that seed.
30
+ max_hops: Maximum traversal depth (>= 1). Each hop
31
+ multiplies the candidate set by the average graph
32
+ fan-out — tune cautiously.
33
+ edge_types: If set, restricts traversal to these edge
34
+ types. ``None`` means all edge types.
35
+ text_property: Graph-node property used to populate the
36
+ synthesised ``VectorMatch.text``. Defaults to
37
+ ``"text"``.
38
+ decay: Per-hop score decay factor in ``(0, 1]``. An
39
+ expansion node at depth `d` gets score
40
+ ``seed.score * decay ** d``. Default 0.5.
41
+ """
42
+
43
+ model_config = ConfigDict(
44
+ frozen=True,
45
+ strict=True,
46
+ arbitrary_types_allowed=True,
47
+ )
48
+
49
+ store: GraphStore
50
+ max_hops: int = Field(default=2, ge=1)
51
+ edge_types: tuple[str, ...] | None = None
52
+ text_property: str = Field(default="text", min_length=1)
53
+ decay: float = Field(default=0.5, gt=0.0, le=1.0)
@@ -0,0 +1,118 @@
1
+ """`AgentState`, `Step`, `RunResult` — the trace shape of an agent run.
2
+
3
+ Per ADR-0008, `state.steps` is uniform across reasoning strategies so
4
+ debugging skills transfer between agents that use different loop
5
+ shapes (ReAct, Plan-Execute, ToT, Multi-Agent).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import UTC, datetime
11
+ from typing import Any, Literal
12
+
13
+ from pydantic import BaseModel, ConfigDict, Field
14
+
15
+ from agentforge_core.contracts.evaluator import EvalResult
16
+ from agentforge_core.values.messages import ToolCall
17
+
18
+ StepKind = Literal[
19
+ "think",
20
+ "act",
21
+ "observe",
22
+ "plan",
23
+ "synthesize",
24
+ "branch",
25
+ "delegate",
26
+ "system",
27
+ ]
28
+ """Closed enum of step kinds. Every reasoning strategy emits steps from
29
+ this set; new kinds require a feature doc + minor version bump."""
30
+
31
+ FinishReason = Literal[
32
+ "completed",
33
+ "iteration_cap",
34
+ "budget_exceeded",
35
+ "guardrail",
36
+ "pipeline",
37
+ "error",
38
+ "cancelled",
39
+ ]
40
+ """How a run terminated. Mirrors the runtime's branching of
41
+ `BudgetExceeded` / `GuardrailViolation` / `PipelineFailure` / clean
42
+ completion."""
43
+
44
+
45
+ class Step(BaseModel):
46
+ """One unit of progress in `AgentState.steps`."""
47
+
48
+ model_config = ConfigDict(frozen=True, strict=True)
49
+
50
+ iteration: int = Field(ge=0)
51
+ kind: StepKind
52
+ content: str | dict[str, Any]
53
+ tool_call: ToolCall | None = None
54
+ tokens_in: int = Field(default=0, ge=0)
55
+ tokens_out: int = Field(default=0, ge=0)
56
+ cost_usd: float = Field(default=0.0, ge=0.0)
57
+ duration_ms: int = Field(default=0, ge=0)
58
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))
59
+ metadata: dict[str, Any] = Field(default_factory=dict)
60
+
61
+
62
+ class AgentState(BaseModel):
63
+ """Mutable per-run state passed through the reasoning loop.
64
+
65
+ Strategies append to `steps`; tools and pipeline tasks may append
66
+ to `findings`. The runtime owns the lifecycle.
67
+
68
+ The per-run execution context (`RuntimeContext` — LLM client,
69
+ tools, memory, budget, system prompt) is stored on
70
+ `state.metadata` under the key `"__agentforge_runtime__"`,
71
+ populated by `Agent.run()` before calling the strategy.
72
+ Strategies access it via the `get_runtime(state)` helper in
73
+ `agentforge.strategies._base`. Storing it on metadata keeps
74
+ `agentforge-core` free of dependencies on runtime modules.
75
+ """
76
+
77
+ model_config = ConfigDict(strict=True, validate_assignment=True)
78
+
79
+ run_id: str
80
+ task: str
81
+ steps: list[Step] = Field(default_factory=list)
82
+ findings: list[Any] = Field(default_factory=list)
83
+ metadata: dict[str, Any] = Field(default_factory=dict)
84
+
85
+
86
+ class RunResult(BaseModel):
87
+ """Final, immutable output of `Agent.run()`.
88
+
89
+ Carries the agent's answer plus full trace, cost accounting, and the
90
+ run's `run_id` for cross-system correlation (ADR-0010).
91
+ """
92
+
93
+ model_config = ConfigDict(frozen=True, strict=True)
94
+
95
+ output: str | dict[str, Any]
96
+ findings: tuple[Any, ...] = ()
97
+ steps: tuple[Step, ...] = ()
98
+ cost_usd: float = Field(ge=0.0)
99
+ tokens_in: int = Field(ge=0)
100
+ tokens_out: int = Field(ge=0)
101
+ run_id: str
102
+ duration_ms: int = Field(ge=0)
103
+ finish_reason: FinishReason = "completed"
104
+ metadata: dict[str, Any] = Field(default_factory=dict)
105
+ guardrail_events: tuple[dict[str, Any], ...] = ()
106
+ """feat-018: one entry per guardrail decision (input / output /
107
+ tool-gate). Each event carries `validator`, `passed`, `violations`,
108
+ `action`, `stage` ("input" / "output" / "tool"), and a hash of the
109
+ content (full content is never persisted here)."""
110
+
111
+ eval_scores: tuple[EvalResult, ...] = ()
112
+ """Per-evaluator `EvalResult` from the post-run evaluator pass.
113
+
114
+ Ordered by the order evaluators were configured on the Agent.
115
+ Empty when no evaluators ran (no `evaluators=` passed) or when
116
+ every evaluator was budget-skipped. See feat-006 §4.3 for the
117
+ cost-gating rule.
118
+ """
@@ -0,0 +1,59 @@
1
+ """Frozen value types for the `VectorStore` contract.
2
+
3
+ `VectorItem` is what callers upsert into a vector store; `VectorMatch`
4
+ is what searches return. Both are immutable Pydantic models so they
5
+ can be freely passed across async boundaries without aliasing bugs.
6
+
7
+ Per ADR-0007 these shapes are part of the framework's locked surface.
8
+ Adding a field is a minor bump; removing or renaming requires a major
9
+ bump.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from typing import Any
15
+
16
+ from pydantic import BaseModel, ConfigDict, Field
17
+
18
+
19
+ class VectorItem(BaseModel):
20
+ """One indexable record in a `VectorStore`.
21
+
22
+ Attributes:
23
+ id: Caller-controlled identifier. Re-upserting an existing id
24
+ replaces the prior record (write-through, not append).
25
+ vector: The embedding. Length must match the store's declared
26
+ `dimensions()`; mismatch raises on `upsert`.
27
+ text: The source text the vector was computed from. Surfaced on
28
+ `VectorMatch` so callers don't have to keep a parallel
29
+ text store. Empty strings are allowed but discouraged.
30
+ metadata: Free-form key-value tags. Used by `search`'s
31
+ `filter_metadata=` argument for AND-style filtering. Kept
32
+ as a plain dict (not frozen) so Pydantic doesn't have to
33
+ recurse into arbitrary user payloads.
34
+ """
35
+
36
+ model_config = ConfigDict(frozen=True, strict=True)
37
+
38
+ id: str = Field(min_length=1)
39
+ vector: tuple[float, ...]
40
+ text: str
41
+ metadata: dict[str, Any] = Field(default_factory=dict)
42
+
43
+
44
+ class VectorMatch(BaseModel):
45
+ """One result from `VectorStore.search`.
46
+
47
+ `score` is normalised cosine similarity in `[0, 1]`:
48
+ - 1.0 means identical direction (highest relevance)
49
+ - 0.0 means orthogonal (effectively unrelated)
50
+ - the contract is store-agnostic; drivers that return raw cosine
51
+ distance or negative inner-product convert at the boundary.
52
+ """
53
+
54
+ model_config = ConfigDict(frozen=True, strict=True)
55
+
56
+ id: str
57
+ text: str
58
+ metadata: dict[str, Any] = Field(default_factory=dict)
59
+ score: float = Field(ge=0.0, le=1.0)
@@ -0,0 +1,66 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentforge-core
3
+ Version: 0.2.1
4
+ Summary: AgentForge core — stable contracts (ABCs, value types) for the agentic framework
5
+ Project-URL: Homepage, https://github.com/Scaffoldic/agentforge-py
6
+ Project-URL: Repository, https://github.com/Scaffoldic/agentforge-py
7
+ Project-URL: Documentation, https://github.com/Scaffoldic/agentforge-py
8
+ Project-URL: Changelog, https://github.com/Scaffoldic/agentforge-py/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/Scaffoldic/agentforge-py/issues
10
+ Author: The AgentForge Authors
11
+ License-Expression: Apache-2.0
12
+ License-File: LICENSE
13
+ Keywords: agent,ai,contracts,framework,llm
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.13
22
+ Requires-Dist: opentelemetry-api>=1.27
23
+ Requires-Dist: pydantic>=2.10
24
+ Requires-Dist: python-ulid>=3.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # agentforge-core
28
+
29
+ The stable contract layer for AgentForge. ABCs, Protocols, and value
30
+ types that every module implements.
31
+
32
+ ## What's in here
33
+
34
+ (Once feat-001 lands.)
35
+
36
+ - `LLMClient`, `EmbeddingClient` — provider abstractions
37
+ - `ReasoningStrategy` — agent loop shape
38
+ - `Tool` — pluggable capabilities
39
+ - `MemoryStore`, `GraphStore` — persistence
40
+ - `Evaluator` — post-run scoring
41
+ - `InputValidator`, `OutputValidator`, `ToolCallGate` — real-time safety
42
+ - `Finding` — output Protocol with shipped variants
43
+ - `BudgetPolicy`, `RunContext`, `RunIdFilter` — production rails
44
+ - Value types: `Claim`, `Step`, `RunResult`, etc.
45
+
46
+ This package is a **locked contract** — adding a method to an ABC is a
47
+ major version bump. See ADR-0007.
48
+
49
+ ## What's NOT in here
50
+
51
+ - Reference implementations (`ReActLoop`, `InMemoryStore`, etc.) — those
52
+ live in `agentforge`
53
+ - Provider clients — those live in `agentforge-anthropic`, etc.
54
+ - Anything that does I/O
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install agentforge-core
60
+ ```
61
+
62
+ Most users install `agentforge` directly, which depends on this package.
63
+
64
+ ## License
65
+
66
+ Apache 2.0.
@@ -0,0 +1,58 @@
1
+ agentforge_core/__init__.py,sha256=McXfkBb7e78HMPMpg415VF_-4Dxu2Fy7rWVfHUj7cvg,5023
2
+ agentforge_core/_bm25.py,sha256=1mjvh7lOBbZPcCYuSFjP6GKJYc7ZpubCeIrpR8Orl04,4632
3
+ agentforge_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ agentforge_core/config/__init__.py,sha256=wTQGgHGmqLuUpjkpmh044xvxULiifUyX6m326_-hyf8,1690
5
+ agentforge_core/config/loader.py,sha256=NJhKjkLWUc-H0H_f-qXgo0B0ONYlB3NtWh95pHO3DgA,8428
6
+ agentforge_core/config/module_schemas.py,sha256=6PsWBK7gtT-96mopXiHUFNktKR5y-Pv0xTUNv3LbWMk,6746
7
+ agentforge_core/config/schema.py,sha256=uW7OfE2eMPW9nkQ_Cnu3MX9BNDoTLuGkTMvRQo17dF8,15430
8
+ agentforge_core/contracts/__init__.py,sha256=XrbuACw7RI99tcQWkIHZJ2zf0wo3x5qCtEmWJFcgHko,1697
9
+ agentforge_core/contracts/auth.py,sha256=zd-JP-POj7TuXg4ymm7wQDAJHECDh90N3Wp9sONE9C4,1195
10
+ agentforge_core/contracts/chat.py,sha256=VRPZM5PfdFO0hBaESIy9VE8VciOQQlur2_8jQNiLd-8,3873
11
+ agentforge_core/contracts/embedding.py,sha256=tOfiml6NQknmrqO5crR1GXmFHwP5r3jrzwkqYju2x4Q,2582
12
+ agentforge_core/contracts/evaluator.py,sha256=gk0nqtKkXdA-wh6LlEqGwJ7DchYBB5a6yUigd6qvbVs,1842
13
+ agentforge_core/contracts/finding.py,sha256=Z3KuEwuk_07f_yuaHC09C5w9v88eXlZspBsHpiUZK4I,1288
14
+ agentforge_core/contracts/graph_store.py,sha256=XGzRFBzCMyPhTDzXQQTBVOerZqMzFuK9jHFc_nkx1oQ,6441
15
+ agentforge_core/contracts/guardrails.py,sha256=pDOolGTZre0R8sl5_wShcqTy48HxjfC3se8NWGyNxhs,3907
16
+ agentforge_core/contracts/llm.py,sha256=HMxdR3iBcU7ANPNaMo6qecP4XzAH064p3PAYpHXuBdc,5384
17
+ agentforge_core/contracts/memory.py,sha256=VE49No2WYubaUemJNvwNP1Cl7MIy0jDTJzfT_7KGd-g,3861
18
+ agentforge_core/contracts/migrator.py,sha256=gyfQkR2NZu5HjMhQhE4mI2Rz8jkbaGHAQps_b72VuDM,4147
19
+ agentforge_core/contracts/renderer.py,sha256=g3zRlADPhK_wwegyt1rJ5HTMfB3TzMpaSTM3uknUa54,2217
20
+ agentforge_core/contracts/reranker.py,sha256=o3bp7tDGaoEAPaAiq7G3KJ7QzLHirEv162YdCHSKtq0,3404
21
+ agentforge_core/contracts/strategy.py,sha256=zukHQ8yQsgaYWf-13e57YExLM81lq56PN4CQeSsuWcg,2801
22
+ agentforge_core/contracts/task.py,sha256=UGFR48u4yltQbsNJbmgR99FP409ldFO6QIAuT1sZbEs,2501
23
+ agentforge_core/contracts/tool.py,sha256=XUxKt8DvBYqZJICyNWMUaNbt_Oq2cC9hQo148pOUCao,2419
24
+ agentforge_core/contracts/vector_store.py,sha256=tn6s1MBMQrDD7g4xCQnLx69dlKKhuI5nt6BATzmi5ZM,5788
25
+ agentforge_core/migrations/__init__.py,sha256=G2lBRpsMpQehBJMvRGiSMjnoKJ54vRhZ2pqMx78F7uA,525
26
+ agentforge_core/migrations/discover.py,sha256=91QNdJ3I0y5ugKtHvm0BM2KxBYm3ulDeCXl0hFuYJQw,2586
27
+ agentforge_core/migrations/template.py,sha256=REROlDA_BPzcFhXHX3-3esgmBecpyqcXzoWLBzgDW1U,1333
28
+ agentforge_core/observability/__init__.py,sha256=6f4XeuJxVHFMCbP4Z9kBANmDQ3PvKdU8G6GyEFOTK6E,593
29
+ agentforge_core/observability/tracing.py,sha256=tyC6KH8C5zJU4t0ZNsQ1b3tTbCWy4i_rlytSIXgaBos,1260
30
+ agentforge_core/production/__init__.py,sha256=ggvR4qPDMUx1hcRnU2puQcfnLlNx-NoCDXbELkJ7lyQ,2179
31
+ agentforge_core/production/budget.py,sha256=odQMsinrIt5a8RfB7ggrgTEujtxkO13XmCpwU68TM3k,5091
32
+ agentforge_core/production/exceptions.py,sha256=sFeEIC6wHds-Pj_nbro4wX0P8gp2Z_O5dbXXUL2K7qs,4222
33
+ agentforge_core/production/fallback.py,sha256=VXTLcxdlZqd0m_u4mYDKddToXzzRdRf5si5u9aPrZKY,12011
34
+ agentforge_core/production/log_filter.py,sha256=c0zX_UOQQAHusu2k62sfv9Nm9lnAAWgS_TSq3ffffUU,1634
35
+ agentforge_core/production/log_format.py,sha256=ZQ5JBatpYFfGQedFMkryiA4l8ZbA6RT0JlldPVt3hKU,3738
36
+ agentforge_core/production/run_context.py,sha256=gQLRxtBRghOuZ_P_qg24sDCHy8TseNJMBtKoevegr8A,3383
37
+ agentforge_core/resolver/__init__.py,sha256=gXpuZ4cVVmxDviblnPSwh0YFNEOVQyQZwcUa389HVog,1096
38
+ agentforge_core/resolver/discover.py,sha256=w8WaWtt2JHv0HGJmB7XFpx-PuN0ubx3HBC5nqh2aw0E,5045
39
+ agentforge_core/resolver/resolve.py,sha256=iOKV5L7qxgqDOP8kkugih6gXzPSHdAB5WmakqTuzUGI,6234
40
+ agentforge_core/testing/__init__.py,sha256=d3ciS5qI6sjezqiRcX5-FYM0azfGRoy498aESBLEqoQ,1425
41
+ agentforge_core/testing/conformance.py,sha256=_SymngwwBu9Sm5CPwaaBCywkeIC7r9NRedyJ0nbupDg,44951
42
+ agentforge_core/values/__init__.py,sha256=gXQ17KLzotM7TmR7N2mwh_xnAwGImmOv4XChqzot5CI,2192
43
+ agentforge_core/values/auth.py,sha256=dErBR6xagq_wZwhU5x3gD0N1-1Mr4Xtnne-L-IIzLgg,569
44
+ agentforge_core/values/chat.py,sha256=HbIPWoQXYSaHCLny01_j53ozTvG0pEwy5uvCDgun0Cs,4293
45
+ agentforge_core/values/claim.py,sha256=yEd1CW9A6pYj3Htq6an9zk3cWiN0IOjWrE-A4vj594M,900
46
+ agentforge_core/values/graph.py,sha256=WeuClLzIiS3Jo5_CZ30dWObLa0I6-RcgLSTj8sgCs9k,5112
47
+ agentforge_core/values/guardrails.py,sha256=9M-Z6eapS6SD8otbXD9bLoR7yHHOcewWRh0NzeuVr5E,1715
48
+ agentforge_core/values/manifest.py,sha256=rcC1yYgXkBUgq-05OuUoU4wwUb6ohqGPZi8MUBsGmpI,4326
49
+ agentforge_core/values/messages.py,sha256=mNnp7VPS-W0T-Xj2xY38T9hMYhkd9ELeV_ziFaf--Pk,4834
50
+ agentforge_core/values/module.py,sha256=whlYMCx-QwUSitHPv_Ybw95bDWsr9DvanefTDb9qj0s,1614
51
+ agentforge_core/values/pipeline.py,sha256=Fa4Fy73O4wsjSt0oJarIyFRNiNv6dXyEq4QjC-vAsLg,1660
52
+ agentforge_core/values/retrieval.py,sha256=gQt94qmzGz2UI7e07ytR9ITV8xEqthIByMemL7qfowc,1942
53
+ agentforge_core/values/state.py,sha256=9GsRmDONQNxgXnkXF9YoHWEbLXq801cTbpmdEExBf-c,3911
54
+ agentforge_core/values/vector.py,sha256=NCgJ7HZ0cMJ9mewfwV7Bygugu7-5LwhzP5LtSKQCfs8,2122
55
+ agentforge_core-0.2.1.dist-info/METADATA,sha256=fCCvY5CPwETd8oMkmzA9VP3KQoF16822Nzmu6imBI3c,2276
56
+ agentforge_core-0.2.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
57
+ agentforge_core-0.2.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
58
+ agentforge_core-0.2.1.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