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.
Files changed (186) hide show
  1. tada_core-0.2.0/.github/workflows/ci.yml +22 -0
  2. tada_core-0.2.0/.github/workflows/release.yml +28 -0
  3. tada_core-0.2.0/.gitignore +29 -0
  4. tada_core-0.2.0/.python-version +1 -0
  5. tada_core-0.2.0/AGENTS.md +297 -0
  6. tada_core-0.2.0/CHANGELOG.md +31 -0
  7. tada_core-0.2.0/LICENSE +21 -0
  8. tada_core-0.2.0/PKG-INFO +489 -0
  9. tada_core-0.2.0/README.md +466 -0
  10. tada_core-0.2.0/agent-apps/agent-studio/README.md +65 -0
  11. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/__init__.py +1 -0
  12. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/__init__.py +3 -0
  13. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/base.py +83 -0
  14. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/coding_agent.py +254 -0
  15. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/registry.py +28 -0
  16. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/shopping_agent.py +129 -0
  17. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/agents/trip_agent.py +139 -0
  18. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/config.py +54 -0
  19. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/environment.py +231 -0
  20. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/model_factory.py +97 -0
  21. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/normalizer.py +370 -0
  22. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/paths.py +12 -0
  23. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/sessions.py +75 -0
  24. tada_core-0.2.0/agent-apps/agent-studio/backend/agent_studio/streaming.py +66 -0
  25. tada_core-0.2.0/agent-apps/agent-studio/backend/app.py +208 -0
  26. tada_core-0.2.0/agent-apps/agent-studio/backend/conftest.py +9 -0
  27. tada_core-0.2.0/agent-apps/agent-studio/backend/tests/__init__.py +0 -0
  28. tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_api.py +162 -0
  29. tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_normalizer.py +73 -0
  30. tada_core-0.2.0/agent-apps/agent-studio/backend/tests/test_registry.py +13 -0
  31. tada_core-0.2.0/agent-apps/agent-studio/dev.sh +53 -0
  32. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/AgentSelector.tsx +41 -0
  33. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/AgentStudioShell.tsx +279 -0
  34. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ArtifactPane.tsx +66 -0
  35. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ArtifactRenderer.tsx +79 -0
  36. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ChatPane.tsx +253 -0
  37. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/InspectorPanel.tsx +128 -0
  38. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/MarkdownMessage.tsx +37 -0
  39. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/ScenarioLauncher.tsx +201 -0
  40. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/SettingsDrawer.tsx +140 -0
  41. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/StudioSidebar.tsx +139 -0
  42. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/TracePane.tsx +117 -0
  43. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/RuntimeConfigPage.tsx +184 -0
  44. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/SkillsPage.tsx +124 -0
  45. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/ToolsPage.tsx +123 -0
  46. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/components/environment/WorkspacePage.tsx +154 -0
  47. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/globals.css +2041 -0
  48. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/layout.tsx +17 -0
  49. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/api.ts +222 -0
  50. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/scenarioGroups.ts +50 -0
  51. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/types.ts +118 -0
  52. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/useAgentRun.ts +208 -0
  53. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/lib/useInspectorResize.ts +84 -0
  54. tada_core-0.2.0/agent-apps/agent-studio/frontend/app/page.tsx +5 -0
  55. tada_core-0.2.0/agent-apps/agent-studio/frontend/next-env.d.ts +6 -0
  56. tada_core-0.2.0/agent-apps/agent-studio/frontend/next.config.ts +12 -0
  57. tada_core-0.2.0/agent-apps/agent-studio/frontend/package-lock.json +2472 -0
  58. tada_core-0.2.0/agent-apps/agent-studio/frontend/package.json +24 -0
  59. tada_core-0.2.0/agent-apps/agent-studio/frontend/tsconfig.json +41 -0
  60. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/README.md +8 -0
  61. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/main.py +6 -0
  62. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/path_jail/util.py +3 -0
  63. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/shell_deny/README.md +5 -0
  64. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/sandbox/shell_deny/tmp.log +2 -0
  65. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/README.md +5 -0
  66. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/app.py +2 -0
  67. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/conftest.py +10 -0
  68. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/tests/__init__.py +1 -0
  69. tada_core-0.2.0/agent-apps/shared/sandbox/fixtures/tasks/todo_api/tests/test_api.py +28 -0
  70. tada_core-0.2.0/agent-apps/shared/sandbox/runtime/.gitkeep +1 -0
  71. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/__init__.py +17 -0
  72. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/hooks.py +273 -0
  73. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/loop_builder.py +94 -0
  74. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/paths.py +11 -0
  75. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/policies.py +54 -0
  76. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/probes.py +248 -0
  77. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/registry.py +61 -0
  78. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/scenarios.py +331 -0
  79. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/__init__.py +5 -0
  80. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/registry.py +46 -0
  81. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tasks/todo_api.py +58 -0
  82. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/tools.py +425 -0
  83. tada_core-0.2.0/agent-apps/shared/sandbox/sandbox/workspace.py +79 -0
  84. tada_core-0.2.0/agent-apps/shared/sandbox/tests/conftest.py +24 -0
  85. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_audit_hook.py +63 -0
  86. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_loop_builder.py +47 -0
  87. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_path_jail.py +87 -0
  88. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_safety_hooks.py +69 -0
  89. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_probes.py +63 -0
  90. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_scenarios.py +106 -0
  91. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_sandbox_tools.py +203 -0
  92. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_shell_deny_hook.py +76 -0
  93. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_steering_hook.py +58 -0
  94. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_task_registry.py +28 -0
  95. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_todo_api_task.py +28 -0
  96. tada_core-0.2.0/agent-apps/shared/sandbox/tests/test_workspace.py +94 -0
  97. tada_core-0.2.0/docs/README.md +83 -0
  98. tada_core-0.2.0/docs/architecture/agent-loop-product-design.md +131 -0
  99. tada_core-0.2.0/docs/architecture/agent-loop-v2.md +527 -0
  100. tada_core-0.2.0/docs/architecture/agent-loop.md +514 -0
  101. tada_core-0.2.0/docs/architecture/context-compression-and-caching-deep-dive.md +1010 -0
  102. tada_core-0.2.0/docs/architecture/design-principles.md +108 -0
  103. tada_core-0.2.0/docs/architecture/overview.md +161 -0
  104. tada_core-0.2.0/docs/architecture/runtime-lifecycle.md +119 -0
  105. tada_core-0.2.0/docs/architecture/tada-core-analysis.md +400 -0
  106. tada_core-0.2.0/docs/architecture/tada-core-design-and-optimization.md +490 -0
  107. tada_core-0.2.0/docs/architecture.md +11 -0
  108. tada_core-0.2.0/docs/integration/custom-provider.md +166 -0
  109. tada_core-0.2.0/docs/integration/human-guide.md +201 -0
  110. tada_core-0.2.0/docs/integration/install.md +55 -0
  111. tada_core-0.2.0/docs/integration/troubleshooting.md +142 -0
  112. tada_core-0.2.0/docs/integration-guide.md +11 -0
  113. tada_core-0.2.0/docs/recipes/async-compaction.md +61 -0
  114. tada_core-0.2.0/docs/reference/compaction.md +229 -0
  115. tada_core-0.2.0/docs/reference/events.md +155 -0
  116. tada_core-0.2.0/docs/reference/mechanisms.md +172 -0
  117. tada_core-0.2.0/docs/reference/protocols.md +182 -0
  118. tada_core-0.2.0/docs/reference/providers.md +212 -0
  119. tada_core-0.2.0/docs/reference/session-state.md +201 -0
  120. tada_core-0.2.0/docs/reference/tool-concurrency-demo.py +301 -0
  121. tada_core-0.2.0/docs/source/security-privacy.jpg +0 -0
  122. tada_core-0.2.0/docs/source/tada-agent-architecture.excalidraw +1067 -0
  123. tada_core-0.2.0/docs/source/tada-agent-architecture.png +0 -0
  124. tada_core-0.2.0/pyproject.toml +64 -0
  125. tada_core-0.2.0/scripts/contract_sdk_install.py +94 -0
  126. tada_core-0.2.0/scripts/smoke.py +181 -0
  127. tada_core-0.2.0/tada-core.code-workspace +34 -0
  128. tada_core-0.2.0/tada_core/__init__.py +57 -0
  129. tada_core-0.2.0/tada_core/cli/harness.py +36 -0
  130. tada_core-0.2.0/tada_core/contracts/__init__.py +9 -0
  131. tada_core-0.2.0/tada_core/contracts/budget.py +43 -0
  132. tada_core-0.2.0/tada_core/contracts/compaction.py +622 -0
  133. tada_core-0.2.0/tada_core/contracts/events.py +233 -0
  134. tada_core-0.2.0/tada_core/contracts/hooks.py +322 -0
  135. tada_core-0.2.0/tada_core/contracts/messages.py +113 -0
  136. tada_core-0.2.0/tada_core/contracts/model.py +109 -0
  137. tada_core-0.2.0/tada_core/contracts/models.py +39 -0
  138. tada_core-0.2.0/tada_core/contracts/permissions.py +89 -0
  139. tada_core-0.2.0/tada_core/contracts/session.py +42 -0
  140. tada_core-0.2.0/tada_core/contracts/tokenization.py +88 -0
  141. tada_core-0.2.0/tada_core/contracts/tools.py +176 -0
  142. tada_core-0.2.0/tada_core/extensions/__init__.py +1 -0
  143. tada_core-0.2.0/tada_core/extensions/mcp_optional.py +18 -0
  144. tada_core-0.2.0/tada_core/loop/__init__.py +22 -0
  145. tada_core-0.2.0/tada_core/loop/message_sanitizer.py +232 -0
  146. tada_core-0.2.0/tada_core/loop/model_client.py +84 -0
  147. tada_core-0.2.0/tada_core/loop/retry.py +78 -0
  148. tada_core-0.2.0/tada_core/loop/runner.py +831 -0
  149. tada_core-0.2.0/tada_core/providers/__init__.py +13 -0
  150. tada_core-0.2.0/tada_core/providers/anthropic.py +753 -0
  151. tada_core-0.2.0/tada_core/providers/bedrock.py +454 -0
  152. tada_core-0.2.0/tada_core/providers/google.py +327 -0
  153. tada_core-0.2.0/tada_core/providers/openai_completions.py +341 -0
  154. tada_core-0.2.0/tada_core/providers/openai_responses.py +446 -0
  155. tada_core-0.2.0/tada_core/providers/openai_utils.py +254 -0
  156. tada_core-0.2.0/tada_core/providers/registry.py +53 -0
  157. tada_core-0.2.0/tada_core/utils/__init__.py +2 -0
  158. tada_core-0.2.0/tada_core/utils/content_normalizer.py +193 -0
  159. tada_core-0.2.0/tests/__init__.py +1 -0
  160. tada_core-0.2.0/tests/conformance/README.md +40 -0
  161. tada_core-0.2.0/tests/conformance/__init__.py +1 -0
  162. tada_core-0.2.0/tests/conformance/fixtures.py +48 -0
  163. tada_core-0.2.0/tests/conformance/test_agent_loop.py +714 -0
  164. tada_core-0.2.0/tests/conformance/test_anthropic_client.py +582 -0
  165. tada_core-0.2.0/tests/conformance/test_api_request_generate_kwargs.py +95 -0
  166. tada_core-0.2.0/tests/conformance/test_bedrock_client.py +218 -0
  167. tada_core-0.2.0/tests/conformance/test_clawcode_model_client.py +71 -0
  168. tada_core-0.2.0/tests/conformance/test_compaction_cache_reuse.py +139 -0
  169. tada_core-0.2.0/tests/conformance/test_compaction_structured.py +204 -0
  170. tada_core-0.2.0/tests/conformance/test_content_normalizer.py +54 -0
  171. tada_core-0.2.0/tests/conformance/test_contract_semantics.py +271 -0
  172. tada_core-0.2.0/tests/conformance/test_event_sequences.py +85 -0
  173. tada_core-0.2.0/tests/conformance/test_google_client.py +156 -0
  174. tada_core-0.2.0/tests/conformance/test_model_runtime.py +210 -0
  175. tada_core-0.2.0/tests/conformance/test_openai_adapters.py +228 -0
  176. tada_core-0.2.0/tests/conformance/test_openai_completions_client.py +223 -0
  177. tada_core-0.2.0/tests/conformance/test_openai_responses_client.py +163 -0
  178. tada_core-0.2.0/tests/conformance/test_provider_token_estimation.py +57 -0
  179. tada_core-0.2.0/tests/conformance/test_retry_model_client.py +67 -0
  180. tada_core-0.2.0/tests/conformance/test_spec_threshold.py +80 -0
  181. tada_core-0.2.0/tests/conformance/test_token_source.py +77 -0
  182. tada_core-0.2.0/tests/conformance/test_tool_middleware.py +37 -0
  183. tada_core-0.2.0/tests/conformance/test_tool_pair_sanitizer.py +72 -0
  184. tada_core-0.2.0/tests/conformance/test_tool_result_pruning.py +119 -0
  185. tada_core-0.2.0/tests/test_public_api.py +101 -0
  186. 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.
@@ -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.