tada-core 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.
- tada_core-0.2.0/.github/workflows/ci.yml +22 -0
- tada_core-0.2.0/.github/workflows/release.yml +28 -0
- tada_core-0.2.0/.gitignore +29 -0
- tada_core-0.2.0/.python-version +1 -0
- tada_core-0.2.0/AGENTS.md +297 -0
- tada_core-0.2.0/CHANGELOG.md +31 -0
- tada_core-0.2.0/LICENSE +21 -0
- tada_core-0.2.0/PKG-INFO +489 -0
- tada_core-0.2.0/README.md +466 -0
- tada_core-0.2.0/agent-apps/agent-studio/README.md +65 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/__init__.py +1 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/__init__.py +3 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/base.py +83 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/coding_agent.py +254 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/registry.py +28 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/shopping_agent.py +129 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/trip_agent.py +139 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/config.py +54 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/environment.py +231 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/model_factory.py +97 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/normalizer.py +370 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/paths.py +12 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/sessions.py +75 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/streaming.py +66 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/app.py +208 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/conftest.py +9 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/tests/__init__.py +0 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_api.py +162 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_normalizer.py +73 -0
- tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_registry.py +13 -0
- tada_core-0.2.0/agent-apps/agent-studio/dev.sh +53 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/AgentSelector.tsx +41 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/AgentStudioShell.tsx +279 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ArtifactPane.tsx +66 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ArtifactRenderer.tsx +79 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ChatPane.tsx +253 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/InspectorPanel.tsx +128 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/MarkdownMessage.tsx +37 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ScenarioLauncher.tsx +201 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/SettingsDrawer.tsx +140 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/StudioSidebar.tsx +139 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/TracePane.tsx +117 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/RuntimeConfigPage.tsx +184 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/SkillsPage.tsx +124 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/ToolsPage.tsx +123 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/WorkspacePage.tsx +154 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/globals.css +2041 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/layout.tsx +17 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/api.ts +222 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/scenarioGroups.ts +50 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/types.ts +118 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/useAgentRun.ts +208 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/useInspectorResize.ts +84 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/app/page.tsx +5 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/next-env.d.ts +6 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/next.config.ts +12 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/package-lock.json +2472 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/package.json +24 -0
- tada_core-0.2.0/agent-apps/agent-studio/frontend/tsconfig.json +41 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/README.md +8 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/main.py +6 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/util.py +3 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/shell_deny/README.md +5 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/shell_deny/tmp.log +2 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/README.md +5 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/app.py +2 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/conftest.py +10 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/tests/__init__.py +1 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/tests/test_api.py +28 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/runtime/.gitkeep +1 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/__init__.py +17 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/hooks.py +273 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/loop_builder.py +94 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/paths.py +11 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/policies.py +54 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/probes.py +248 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/registry.py +61 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/scenarios.py +331 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/__init__.py +5 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/registry.py +46 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/todo_api.py +58 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tools.py +425 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/workspace.py +79 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/conftest.py +24 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_audit_hook.py +63 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_loop_builder.py +47 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_path_jail.py +87 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_safety_hooks.py +69 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_probes.py +63 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_scenarios.py +106 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_tools.py +203 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_shell_deny_hook.py +76 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_steering_hook.py +58 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_task_registry.py +28 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_todo_api_task.py +28 -0
- tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_workspace.py +94 -0
- tada_core-0.2.0/docs/README.md +83 -0
- tada_core-0.2.0/docs/architecture/agent-loop-product-design.md +131 -0
- tada_core-0.2.0/docs/architecture/agent-loop-v2.md +527 -0
- tada_core-0.2.0/docs/architecture/agent-loop.md +514 -0
- tada_core-0.2.0/docs/architecture/context-compression-and-caching-deep-dive.md +1010 -0
- tada_core-0.2.0/docs/architecture/design-principles.md +108 -0
- tada_core-0.2.0/docs/architecture/overview.md +161 -0
- tada_core-0.2.0/docs/architecture/runtime-lifecycle.md +119 -0
- tada_core-0.2.0/docs/architecture/tada-core-analysis.md +400 -0
- tada_core-0.2.0/docs/architecture/tada-core-design-and-optimization.md +490 -0
- tada_core-0.2.0/docs/architecture.md +11 -0
- tada_core-0.2.0/docs/integration/custom-provider.md +166 -0
- tada_core-0.2.0/docs/integration/human-guide.md +201 -0
- tada_core-0.2.0/docs/integration/install.md +55 -0
- tada_core-0.2.0/docs/integration/troubleshooting.md +142 -0
- tada_core-0.2.0/docs/integration-guide.md +11 -0
- tada_core-0.2.0/docs/recipes/async-compaction.md +61 -0
- tada_core-0.2.0/docs/reference/compaction.md +229 -0
- tada_core-0.2.0/docs/reference/events.md +155 -0
- tada_core-0.2.0/docs/reference/mechanisms.md +172 -0
- tada_core-0.2.0/docs/reference/protocols.md +182 -0
- tada_core-0.2.0/docs/reference/providers.md +212 -0
- tada_core-0.2.0/docs/reference/session-state.md +201 -0
- tada_core-0.2.0/docs/reference/tool-concurrency-demo.py +301 -0
- tada_core-0.2.0/docs/source/security-privacy.jpg +0 -0
- tada_core-0.2.0/docs/source/tada-agent-architecture.excalidraw +1067 -0
- tada_core-0.2.0/docs/source/tada-agent-architecture.png +0 -0
- tada_core-0.2.0/pyproject.toml +64 -0
- tada_core-0.2.0/scripts/contract_sdk_install.py +94 -0
- tada_core-0.2.0/scripts/smoke.py +181 -0
- tada_core-0.2.0/tada-core.code-workspace +34 -0
- tada_core-0.2.0/tada_core/__init__.py +57 -0
- tada_core-0.2.0/tada_core/cli/harness.py +36 -0
- tada_core-0.2.0/tada_core/contracts/__init__.py +9 -0
- tada_core-0.2.0/tada_core/contracts/budget.py +43 -0
- tada_core-0.2.0/tada_core/contracts/compaction.py +622 -0
- tada_core-0.2.0/tada_core/contracts/events.py +233 -0
- tada_core-0.2.0/tada_core/contracts/hooks.py +322 -0
- tada_core-0.2.0/tada_core/contracts/messages.py +113 -0
- tada_core-0.2.0/tada_core/contracts/model.py +109 -0
- tada_core-0.2.0/tada_core/contracts/models.py +39 -0
- tada_core-0.2.0/tada_core/contracts/permissions.py +89 -0
- tada_core-0.2.0/tada_core/contracts/session.py +42 -0
- tada_core-0.2.0/tada_core/contracts/tokenization.py +88 -0
- tada_core-0.2.0/tada_core/contracts/tools.py +176 -0
- tada_core-0.2.0/tada_core/extensions/__init__.py +1 -0
- tada_core-0.2.0/tada_core/extensions/mcp_optional.py +18 -0
- tada_core-0.2.0/tada_core/loop/__init__.py +22 -0
- tada_core-0.2.0/tada_core/loop/message_sanitizer.py +232 -0
- tada_core-0.2.0/tada_core/loop/model_client.py +84 -0
- tada_core-0.2.0/tada_core/loop/retry.py +78 -0
- tada_core-0.2.0/tada_core/loop/runner.py +831 -0
- tada_core-0.2.0/tada_core/providers/__init__.py +13 -0
- tada_core-0.2.0/tada_core/providers/anthropic.py +753 -0
- tada_core-0.2.0/tada_core/providers/bedrock.py +454 -0
- tada_core-0.2.0/tada_core/providers/google.py +327 -0
- tada_core-0.2.0/tada_core/providers/openai_completions.py +341 -0
- tada_core-0.2.0/tada_core/providers/openai_responses.py +446 -0
- tada_core-0.2.0/tada_core/providers/openai_utils.py +254 -0
- tada_core-0.2.0/tada_core/providers/registry.py +53 -0
- tada_core-0.2.0/tada_core/utils/__init__.py +2 -0
- tada_core-0.2.0/tada_core/utils/content_normalizer.py +193 -0
- tada_core-0.2.0/tests/__init__.py +1 -0
- tada_core-0.2.0/tests/conformance/README.md +40 -0
- tada_core-0.2.0/tests/conformance/__init__.py +1 -0
- tada_core-0.2.0/tests/conformance/fixtures.py +48 -0
- tada_core-0.2.0/tests/conformance/test_agent_loop.py +714 -0
- tada_core-0.2.0/tests/conformance/test_anthropic_client.py +582 -0
- tada_core-0.2.0/tests/conformance/test_api_request_generate_kwargs.py +95 -0
- tada_core-0.2.0/tests/conformance/test_bedrock_client.py +218 -0
- tada_core-0.2.0/tests/conformance/test_clawcode_model_client.py +71 -0
- tada_core-0.2.0/tests/conformance/test_compaction_cache_reuse.py +139 -0
- tada_core-0.2.0/tests/conformance/test_compaction_structured.py +204 -0
- tada_core-0.2.0/tests/conformance/test_content_normalizer.py +54 -0
- tada_core-0.2.0/tests/conformance/test_contract_semantics.py +271 -0
- tada_core-0.2.0/tests/conformance/test_event_sequences.py +85 -0
- tada_core-0.2.0/tests/conformance/test_google_client.py +156 -0
- tada_core-0.2.0/tests/conformance/test_model_runtime.py +210 -0
- tada_core-0.2.0/tests/conformance/test_openai_adapters.py +228 -0
- tada_core-0.2.0/tests/conformance/test_openai_completions_client.py +223 -0
- tada_core-0.2.0/tests/conformance/test_openai_responses_client.py +163 -0
- tada_core-0.2.0/tests/conformance/test_provider_token_estimation.py +57 -0
- tada_core-0.2.0/tests/conformance/test_retry_model_client.py +67 -0
- tada_core-0.2.0/tests/conformance/test_spec_threshold.py +80 -0
- tada_core-0.2.0/tests/conformance/test_token_source.py +77 -0
- tada_core-0.2.0/tests/conformance/test_tool_middleware.py +37 -0
- tada_core-0.2.0/tests/conformance/test_tool_pair_sanitizer.py +72 -0
- tada_core-0.2.0/tests/conformance/test_tool_result_pruning.py +119 -0
- tada_core-0.2.0/tests/test_public_api.py +101 -0
- tada_core-0.2.0/uv.lock +983 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- run: uv sync
|
|
21
|
+
- run: uv run pytest tests/
|
|
22
|
+
- run: uv run ruff check tada_core tests scripts
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-and-publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.11"
|
|
20
|
+
- run: uv sync
|
|
21
|
+
- run: uv run pytest tests/
|
|
22
|
+
- run: uv run ruff check tada_core tests scripts
|
|
23
|
+
- run: uv run python scripts/contract_sdk_install.py
|
|
24
|
+
- run: uv build
|
|
25
|
+
- name: Publish to PyPI
|
|
26
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
27
|
+
with:
|
|
28
|
+
attestations: true
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.DS_Store
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.worktrees/
|
|
11
|
+
.claude/
|
|
12
|
+
internal-docs/
|
|
13
|
+
docs/superpowers/
|
|
14
|
+
docs/architecture/tada-agent-*
|
|
15
|
+
docs/architecture/claw-code-*
|
|
16
|
+
docs/architecture/hermes-agent-*
|
|
17
|
+
docs/architecture/pi-*
|
|
18
|
+
docs/architecture/claude-code-*
|
|
19
|
+
docs/reference/pi-coding-agent-post.md
|
|
20
|
+
plans/
|
|
21
|
+
agent-apps/.local/
|
|
22
|
+
agent-apps/agent-1/.local/
|
|
23
|
+
agent-apps/agent-1/frontend/node_modules/
|
|
24
|
+
agent-apps/agent-1/frontend/dist/
|
|
25
|
+
agent-apps/agent-studio/backend/.config.json
|
|
26
|
+
agent-apps/agent-studio/frontend/node_modules/
|
|
27
|
+
agent-apps/agent-studio/frontend/.next/
|
|
28
|
+
agent-apps/shared/sandbox/runtime/*
|
|
29
|
+
!agent-apps/shared/sandbox/runtime/.gitkeep
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# tada-core - AGENTS.md
|
|
2
|
+
|
|
3
|
+
AI-readable reference for the `tada-core` Python SDK.
|
|
4
|
+
|
|
5
|
+
## SDK Identity
|
|
6
|
+
|
|
7
|
+
- **Package**: `tada_core` (`pip install tada-core`)
|
|
8
|
+
- **Python**: >=3.10
|
|
9
|
+
- **Core deps**: `httpx>=0.27`, `pydantic>=2.0`, `typing-extensions>=4.8`
|
|
10
|
+
- **Role**: multi-protocol agent runtime SDK: unified Message/Event contracts, adapter registry, streaming events, tool dispatch, hook/permission/compaction/budget extension points, and serializable session state
|
|
11
|
+
- **NOT**: a product shell, a channel router, a long-term memory service, a tool middleware framework, routing/fallback/quota/billing, or OAuth
|
|
12
|
+
- **Model routing**: handled by `token-router`; `tada-core` selects protocol adapters via `ModelSpec.api` (`anthropic-messages`, `openai-responses`, `openai-completions`, `google-generative-ai`, `bedrock-converse-stream`)
|
|
13
|
+
|
|
14
|
+
## Public API
|
|
15
|
+
|
|
16
|
+
The current public surface is exactly the names exported from `tada_core.__all__`:
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from tada_core import (
|
|
20
|
+
AgentLoop,
|
|
21
|
+
AnthropicModelClient,
|
|
22
|
+
BudgetLimits,
|
|
23
|
+
ChainedToolExecutor,
|
|
24
|
+
CharacterTokenEstimator,
|
|
25
|
+
CompactionConfig,
|
|
26
|
+
CompactionMode,
|
|
27
|
+
CompactionStrategy,
|
|
28
|
+
ContentNormalizerConfig,
|
|
29
|
+
ContentBlock,
|
|
30
|
+
ConversationMessage,
|
|
31
|
+
Event,
|
|
32
|
+
MessageRole,
|
|
33
|
+
ModelSpec,
|
|
34
|
+
ModelSummaryCompaction,
|
|
35
|
+
NeverCompact,
|
|
36
|
+
SessionState,
|
|
37
|
+
StopReason,
|
|
38
|
+
StructuredSummaryCompaction,
|
|
39
|
+
TokenEstimator,
|
|
40
|
+
ToolResult,
|
|
41
|
+
ToolResultPruningConfig,
|
|
42
|
+
TruncateCompaction,
|
|
43
|
+
RetryPolicy,
|
|
44
|
+
RetryingModelClient,
|
|
45
|
+
build_model_client,
|
|
46
|
+
normalize_messages,
|
|
47
|
+
__version__,
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Name | Kind | Purpose |
|
|
52
|
+
|------|------|---------|
|
|
53
|
+
| `AgentLoop` | class | Main agent runtime loop; calls model, tools, hooks, permissions, and compaction |
|
|
54
|
+
| `AnthropicModelClient` | class | Anthropic Messages API adapter for direct Anthropic, token-router, LiteLLM Anthropic mode, and similar proxies |
|
|
55
|
+
| `BudgetLimits` | Pydantic model | Provider-neutral runtime limits for tokens, iterations, and tool calls |
|
|
56
|
+
| `CharacterTokenEstimator` | class | Dependency-free fallback token estimator |
|
|
57
|
+
| `ChainedToolExecutor` | class | Wraps a `ToolExecutor` with ordered async middleware |
|
|
58
|
+
| `CompactionConfig` | Pydantic model | Runtime compaction configuration, including thresholds, protected head/tail, and tool result pruning |
|
|
59
|
+
| `CompactionMode` | enum | Built-in compaction modes: `auto`, `disabled`, `hook_only` |
|
|
60
|
+
| `CompactionStrategy` | ABC | Contract for custom conversation compaction |
|
|
61
|
+
| `ContentNormalizerConfig` | Pydantic model | Optional multimodal normalization config |
|
|
62
|
+
| `ContentBlock` | Pydantic model | Text, thinking, tool, tool result, image, and file block inside a message |
|
|
63
|
+
| `ConversationMessage` | Pydantic model | Provider-agnostic transcript message |
|
|
64
|
+
| `Event` | type alias | Discriminated union of runtime events |
|
|
65
|
+
| `MessageRole` | enum | `user`, `assistant`, or `tool` |
|
|
66
|
+
| `ModelSpec` | Pydantic model | Lightweight model/protocol capability descriptor (not a full catalog) |
|
|
67
|
+
| `ModelSummaryCompaction` | class | LLM-backed compaction strategy |
|
|
68
|
+
| `NeverCompact` | class | Default no-op compaction strategy |
|
|
69
|
+
| `SessionState` | Pydantic model | Serializable conversation state and cumulative usage |
|
|
70
|
+
| `StopReason` | enum | Normalized assistant message stop reason |
|
|
71
|
+
| `StructuredSummaryCompaction` | class | Default production compaction strategy with structured summary, tool result pruning, source ids, and token-aware tail selection |
|
|
72
|
+
| `TokenEstimator` | protocol | Provider-neutral token estimation contract |
|
|
73
|
+
| `ToolResult` | dataclass | Structured tool result with optional multimodal blocks |
|
|
74
|
+
| `ToolResultPruningConfig` | Pydantic model | Configures active pruning of oversized old `tool_result` blocks and placeholder/manifest behavior |
|
|
75
|
+
| `TruncateCompaction` | class | Keeps the most recent N messages |
|
|
76
|
+
| `RetryPolicy` | Pydantic model | Retry policy for `RetryingModelClient` |
|
|
77
|
+
| `RetryingModelClient` | class | Model client wrapper that retries pre-stream transient errors |
|
|
78
|
+
| `build_model_client` | function | Build a registered `ModelClient` from `ModelSpec` |
|
|
79
|
+
| `normalize_messages` | function | Optional content normalizer for local paths, URL images, MIME aliases, and image sizing |
|
|
80
|
+
| `__version__` | str | Package version |
|
|
81
|
+
|
|
82
|
+
Adding a new public export requires a minor version bump. Adding optional fields to existing Pydantic models is patch-compatible during 0.x, but persisted `SessionState` JSON is not guaranteed to be readable by older package versions.
|
|
83
|
+
|
|
84
|
+
## Minimal Integration
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import asyncio
|
|
88
|
+
|
|
89
|
+
from tada_core import AgentLoop, AnthropicModelClient, SessionState
|
|
90
|
+
|
|
91
|
+
loop = AgentLoop(
|
|
92
|
+
AnthropicModelClient(
|
|
93
|
+
api_key="token-router-key",
|
|
94
|
+
model="claude-sonnet-4-6",
|
|
95
|
+
base_url="http://localhost:8787",
|
|
96
|
+
cache_retention="short",
|
|
97
|
+
),
|
|
98
|
+
system_prompt=["You are a concise assistant."],
|
|
99
|
+
)
|
|
100
|
+
state = SessionState()
|
|
101
|
+
|
|
102
|
+
async def main() -> None:
|
|
103
|
+
async for event in loop.run_turn(state, "hello"):
|
|
104
|
+
if event.type == "text_delta":
|
|
105
|
+
print(event.text, end="", flush=True)
|
|
106
|
+
elif event.type == "error":
|
|
107
|
+
raise RuntimeError(f"{event.code}: {event.message}")
|
|
108
|
+
|
|
109
|
+
asyncio.run(main())
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`state` is mutated in place. Persist it with `state.model_dump_json()` and restore it with `SessionState.model_validate_json(...)`.
|
|
113
|
+
|
|
114
|
+
## Message Model
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from tada_core import ContentBlock, ConversationMessage, MessageRole, SessionState
|
|
118
|
+
|
|
119
|
+
state = SessionState(
|
|
120
|
+
messages=[
|
|
121
|
+
ConversationMessage(
|
|
122
|
+
role=MessageRole.USER,
|
|
123
|
+
content=[
|
|
124
|
+
ContentBlock(
|
|
125
|
+
type="image",
|
|
126
|
+
source="base64",
|
|
127
|
+
mime_type="image/png",
|
|
128
|
+
data="...",
|
|
129
|
+
),
|
|
130
|
+
ContentBlock(type="text", text="Describe this image."),
|
|
131
|
+
],
|
|
132
|
+
)
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Known `ContentBlock.type` values:
|
|
138
|
+
|
|
139
|
+
| Type | Key fields |
|
|
140
|
+
|------|------------|
|
|
141
|
+
| `text` | `text` |
|
|
142
|
+
| `thinking` | `thinking`, optional `signature` |
|
|
143
|
+
| `tool_use` | `tool_use_id`, `tool_name`, `tool_input` |
|
|
144
|
+
| `tool_result` | `tool_use_id`, `tool_name`, `tool_result`, `is_error` |
|
|
145
|
+
| `image` | `source`, `mime_type`, `data` or `url` |
|
|
146
|
+
| `file` | `source`, `mime_type`, `data` or `url`, optional `name` |
|
|
147
|
+
|
|
148
|
+
`type` remains a free-form string for forward compatibility, but known multimodal block types validate required payload fields.
|
|
149
|
+
|
|
150
|
+
## Event Types
|
|
151
|
+
|
|
152
|
+
Pattern-match on `event.type`.
|
|
153
|
+
|
|
154
|
+
| `.type` | Class | Key fields |
|
|
155
|
+
|---------|-------|------------|
|
|
156
|
+
| `turn_start` | `TurnStartEvent` | `turn_index` |
|
|
157
|
+
| `turn_end` | `TurnEndEvent` | `iterations_used`, `completed` |
|
|
158
|
+
| `text_start` | `TextStart` | no payload |
|
|
159
|
+
| `text_delta` | `TextDelta` | `text` |
|
|
160
|
+
| `text_end` | `TextEnd` | `text` |
|
|
161
|
+
| `thinking_start` | `ThinkingStart` | no payload |
|
|
162
|
+
| `thinking_delta` | `ThinkingDelta` | `text` |
|
|
163
|
+
| `thinking_end` | `ThinkingEnd` | `text` |
|
|
164
|
+
| `tool_input_delta` | `ToolInputDelta` | `tool_use_id`, `tool_name`, `delta` |
|
|
165
|
+
| `tool_use` | `ToolUseRequest` | `tool_use_id`, `tool_name`, `input_json` |
|
|
166
|
+
| `tool_result` | `ToolResultEvent` | `tool_use_id`, `tool_name`, `output`, `is_error` |
|
|
167
|
+
| `tool_progress` | `ToolProgressEvent` | `tool_use_id`, `tool_name`, `update` |
|
|
168
|
+
| `usage` | `UsageEvent` | `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_creation_tokens` |
|
|
169
|
+
| `message_stop` | `MessageStop` | optional `stop_reason` |
|
|
170
|
+
| `permission` | `PermissionEvent` | `tool_name`, `allowed`, `reason` |
|
|
171
|
+
| `hook` | `HookEvent` | `hook_name`, `phase`, `messages` |
|
|
172
|
+
| `compaction` | `CompactionEvent` | `strategy`, `removed_message_count`, `summary`, `compacted_message_ids`, `pruned_tool_results_count`, `fallback_used` |
|
|
173
|
+
| `error` | `ErrorEvent` | `message`, `code` |
|
|
174
|
+
| `unsupported` | `UnsupportedEvent` | `feature`, `detail` |
|
|
175
|
+
| `loop_exit` | `LoopExitEvent` | `tool_name`, `reason` |
|
|
176
|
+
| `steering` | `SteeringEvent` | `tool_name`, `message_count`, `skipped_tools` |
|
|
177
|
+
|
|
178
|
+
Important ordering guarantees:
|
|
179
|
+
|
|
180
|
+
1. `tool_use` is emitted before `permission`, which is emitted before `tool_result` for the same tool call.
|
|
181
|
+
2. `tool_progress` events appear before the final `tool_result` for a tool.
|
|
182
|
+
3. `usage` events update `SessionState.usage` before they are yielded.
|
|
183
|
+
|
|
184
|
+
## AnthropicModelClient
|
|
185
|
+
|
|
186
|
+
`AnthropicModelClient` serializes `ConversationMessage` into Anthropic Messages API wire format and sends `POST /v1/messages`.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
AnthropicModelClient(
|
|
190
|
+
api_key="...",
|
|
191
|
+
model="claude-sonnet-4-6",
|
|
192
|
+
base_url="http://localhost:8787",
|
|
193
|
+
streaming=True,
|
|
194
|
+
max_tokens=8192,
|
|
195
|
+
extra_headers={},
|
|
196
|
+
cache_retention="short", # "none" | "short" | "long"
|
|
197
|
+
)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Cache behavior:
|
|
201
|
+
|
|
202
|
+
- `cache_retention="none"`: no `cache_control` markers.
|
|
203
|
+
- `cache_retention="short"`: block-level `{"type": "ephemeral"}` markers.
|
|
204
|
+
- `cache_retention="long"`: emits `ttl="1h"` only for official `api.anthropic.com`; other base URLs automatically use short retention for proxy compatibility.
|
|
205
|
+
- Markers are always attached to content blocks, never as a top-level SDK parameter.
|
|
206
|
+
- Up to four breakpoints are used: system, tools, previous user turn, current user turn.
|
|
207
|
+
|
|
208
|
+
## Tools
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from tada_core.contracts.tools import InMemoryToolExecutor, ToolDefinition
|
|
212
|
+
|
|
213
|
+
executor = InMemoryToolExecutor()
|
|
214
|
+
executor.register(
|
|
215
|
+
ToolDefinition(
|
|
216
|
+
name="echo",
|
|
217
|
+
description="Return input unchanged",
|
|
218
|
+
parameters_schema={"type": "object"},
|
|
219
|
+
),
|
|
220
|
+
lambda input_json: input_json,
|
|
221
|
+
)
|
|
222
|
+
loop.set_tool_executor(executor)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Tool functions receive and return JSON strings. Tool middleware, platform-specific auth, file upload/download, and channel rendering stay in the host application.
|
|
226
|
+
|
|
227
|
+
## Permissions
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from tada_core.contracts.permissions import DenyListPolicy
|
|
231
|
+
|
|
232
|
+
loop.set_permission_policy(DenyListPolicy(denied={"shell", "rm"}))
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Custom policies implement `PermissionPolicy.authorize(...)`.
|
|
236
|
+
|
|
237
|
+
## Hooks
|
|
238
|
+
|
|
239
|
+
Hooks are the extension point for host-side behavior such as hint injection, tracing, memory retrieval, tool input rewriting, and ask-user style loop exits.
|
|
240
|
+
|
|
241
|
+
Supported phases include:
|
|
242
|
+
|
|
243
|
+
- `OnSessionStart`
|
|
244
|
+
- `OnTurnStart`
|
|
245
|
+
- `PreLlmCall`
|
|
246
|
+
- `PostLlmCall`
|
|
247
|
+
- `PreToolUse`
|
|
248
|
+
- `PostToolUse`
|
|
249
|
+
- `PostToolUseFailure`
|
|
250
|
+
- `OnTurnEnd`
|
|
251
|
+
|
|
252
|
+
Use `FunctionHookRunner` for simple callback composition or implement `HookRunner` directly.
|
|
253
|
+
|
|
254
|
+
## Compaction
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
from tada_core import TruncateCompaction
|
|
258
|
+
|
|
259
|
+
loop.set_compaction_strategy(TruncateCompaction(max_messages=40))
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Built-ins:
|
|
263
|
+
|
|
264
|
+
- `NeverCompact`
|
|
265
|
+
- `TruncateCompaction`
|
|
266
|
+
- `ModelSummaryCompaction`
|
|
267
|
+
- `StructuredSummaryCompaction` (default in `AgentLoop`)
|
|
268
|
+
|
|
269
|
+
`StructuredSummaryCompaction` defaults to:
|
|
270
|
+
|
|
271
|
+
- count `system_prompt`, `tools`, and messages when deciding whether to compact
|
|
272
|
+
- preserve protected head messages and a token-aware recent tail
|
|
273
|
+
- actively prune oversized old `tool_result` blocks in the middle partition before summarization
|
|
274
|
+
- record `compacted_message_ids`, `pruned_tool_results`, `fallback_used`, and a manifest on `CompactionResult`
|
|
275
|
+
- keep `tools` definitions separate from `tool_result` message blocks, so pruning old tool outputs does not mutate the stable `system + tools` cache prefix
|
|
276
|
+
|
|
277
|
+
For `tada-agent` integration, use `ConversationMessage.id` to preserve host message IDs. Map `CompactionResult.summary` to ReMe `_compressed_summary`, `compacted_message_ids` to `COMPRESSED` marks, and `CompactionEvent` fields to Langfuse span metadata.
|
|
278
|
+
|
|
279
|
+
## What tada-core Does Not Own
|
|
280
|
+
|
|
281
|
+
- Multi-provider routing, fallback, and billing: use `token-router`.
|
|
282
|
+
- Product channel protocols: FastAPI, WebSocket, Feishu, DingTalk, Telegram, etc.
|
|
283
|
+
- Business session storage and authentication.
|
|
284
|
+
- Long-term memory or user profile retrieval.
|
|
285
|
+
- Tool middleware, file upload/download, and channel-specific rendering.
|
|
286
|
+
- tada-agent adapter wiring and rollout flags.
|
|
287
|
+
|
|
288
|
+
## Verification
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
uv run pytest tests/
|
|
292
|
+
uv run ruff check tada_core tests
|
|
293
|
+
uv run python scripts/smoke.py
|
|
294
|
+
tada-core-smoke --text "hello"
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`scripts/smoke.py` can call echo, Anthropic-compatible, or OpenAI-compatible endpoints depending on `API_KEY`, `BASE_URL`, `MODEL_ID`, and `PROTOCOL`.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `tada-core` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses semantic versioning during public releases.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-05-25
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Public SDK surface for `AgentLoop`, `AnthropicModelClient`, events, session state, compaction strategies, and message schema models.
|
|
14
|
+
- Anthropic Messages API `cache_control` support with short/long retention handling.
|
|
15
|
+
- Multimodal `ContentBlock` support for image and file blocks.
|
|
16
|
+
- SDK install documentation for local editable, Git URL, and future PyPI consumption.
|
|
17
|
+
- `tada-core-smoke` echo-only CLI harness for manual event-stream checks.
|
|
18
|
+
- Fresh-venv SDK contract verification script.
|
|
19
|
+
- `ToolResultPruningConfig` plus active old `tool_result` pruning with audit manifest metadata.
|
|
20
|
+
- Stable `ConversationMessage.id` propagation through `CompactionResult.compacted_message_ids`.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Clarified that provider routing belongs to `token-router`; `tada-core` owns the client-side Anthropic wire format.
|
|
25
|
+
- Upgraded `StructuredSummaryCompaction` to count system/tools in thresholds, preserve token-budget tails, align tool-use boundaries, and expose richer `CompactionEvent` metadata.
|
|
26
|
+
|
|
27
|
+
## [0.1.0] - 2026-05-21
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- Initial public SDK baseline.
|
tada_core-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tada
|
|
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.
|