Repository navigation
release: D1–D8 — durable ACP runtime, dana-code on AgentSession, first-contact DX - #30
Merged
Merged
Conversation
httpx<0.28 blocked dana-agent[langsmith]'s websockets>=15 in a single uv workspace. anthropic==0.30.1 caps httpx<0.28, so the two must move together: anthropic -> >=0.40.0 (first release supporting httpx 0.28.x; the API surface dana uses is stable through 0.116). - requires-python: >=3.12 -> >=3.11,<3.14 - llama-stack gated with python_version>='3.12' marker (needs >=3.12) so [local] resolves on 3.11 (ollama-only) Validated via live provider tests; no new unit-test regressions.
chore(deps): bump httpx>=0.28.1 and anthropic>=0.40.0
@observable dispatches to langsmith.traceable when LANGSMITH_TRACING=true or DANA_LANGSMITH_ENABLED truthy; exclusive with Langfuse (LangSmith wins). No call-site changes — all 30+ @observable sites traced automatically. - observable.py: LANGSMITH>LANGFUSE>noop dispatch, _langsmith_kwargs adapter (as_type->run_type, session_id/user_id folded into metadata), bare-form normalization to avoid double-call, factored _langfuse_wrap preserves byte-equivalent flush behavior on the langfuse path - init_environment.py: _install_langsmith_shim mirrors the langfuse shim so the module imports cleanly without the extra installed - pyproject.toml: langsmith>=0.8,<0.9 added to [observability] extra - tests: 11 cases incl. SC7 langfuse flush regression (sync/bare/async) and async exclusivity - docs: tracing-backends section + silent no-op caveat + changelog entry Enable: pip install dana[observability]; LANGSMITH_TRACING=true LANGSMITH_API_KEY=...
feat(observability): add LangSmith as alternative tracing backend
fix(observability): sanitize LangSmith trace payloads
feat(prompt): add public system prompt template override
Add DanaACPAgent implementing the ACP Agent protocol over stdio JSON-RPC, enabling dana-console to connect to Dana as a Custom ACP Agent. - dana/apps/acp/agent.py: DanaACPAgent translating ACP calls (initialize, session/new, session/load, session/resume, session/prompt, session/cancel) to AgentSession operations, streaming HostEvents back as session_update notifications - dana/apps/acp/translation.py: HostEvent → ACP update chunk translation (ACP types never enter STAR core) - dana/apps/acp/__main__.py: entry point with stderr-only logging - dana/__init__/init_environment.py: redirect structlog to stderr so stdout stays clean for JSON-RPC frames - pyproject.toml: dana-acp console script entry point - tests/integration/test_acp_agent.py: 14 in-process + subprocess tests covering load capability, replay-before-return, chunk streaming, burst ordering, busy, cancel, malformed content, stderr/stdout discipline
Untrack /sprint/, /v2/, CLAUDE.md (local-only working docs, consistent with existing AGENTS.md/.claude/.opencode ignores). CLAUDE.md removed from repo; local copy retained via gitignore.
Per-agent intercept-capable EventBus: first-wins aggregation, sync+async handlers, raise isolation, emit_sync via Misc.safe_asyncio_run. Lazy mount on BaseSTARAgent. Non-dict results warned+skipped. 17 tests.
.agents/, .codegraph/, .codex/, .superpowers/, memories/, tests/unit/core/guard/ — local tool artifacts (consistent with .claude/.opencode).
_build_native_tools_if_supported now returns early if schemas already built. Rebuilding every build_prompt re-ran inspect.signature on every resource method under the tracing chain, exhausting the recursion budget on long sessions (librarian console crash). Structural deps don't change per turn -> build once. Adds 2 tests.
Milestone M3 (longest pole of v2.0 extensibility backbone). Wires the S1
EventBus into both tool-execution paths and adds a deny-only PermissionPolicy.
- ext/operation.py: Operation + ToolIdentity (thin, read-only via MappingProxyType)
- ext/permission.py: PermissionPolicy deny-only (a tool_call subscriber)
- ext/guard.py: reference rm-rf + protected-path policy (S4 discovery target)
- tool_executor.py: emit tool_call/tool_result around dispatch in both single-
call paths; split out _dispatch_single_call[_async] (dispatch NOT merged)
- runtime/{protocols,__init__}.py: remove dead ToolHookProtocol/ApprovalProtocol
scaffold + constructor params hooks/approval (never wired)
Adversarial review fixes: non-dict tool_result modify no longer crashes the
batch (isinstance guard + warn); guard substring rules str()-coerce (defeats
list-arg bypass); strict-bool block (is True); Operation.arguments immutable.
Tests: 27 new (S3.1-S3.15 + 7 adversarial fix-regressions). Regression green:
tests/unit + tests/integration 1614 passed, 37 skipped, 1 xfailed.
Milestone M2. Emits see_end/think_end/act_end/reflect_end around the STAR phases in query()/aquery() so handlers can observe, modify, or block each phase. STAR contract (_see/_think/_act/_reflect) unchanged. - base_star_agent.py: _emit_phase[_async] helpers + per-phase block/modify wiring in _do_query/_do_aquery; reflect_end emit in the reflect wrappers. - Orchestrator-based wiring (not scatter-site): STARAgent._think/_act_async broadcast inline without super(), so base-site wiring would miss them. - Fix latent S1 bug: event_bus property used getattr(self,_event_bus,None) but STARAgent.__getattr__ returns a magic-method stub for any unknown attr, so the bus was never created on the real agent. Now reads self.__dict__. - Adversarial fixes: per-phase exit uses EXIT_FLAG is True (not _do_exit_star_loop, avoiding the empty-dict false-exit quirk); act_end block sets phase_blocked (skips reflect, prevents repeat); non-dict modify ignored + warned. Trade-off: broadcast fires before emit, so legacy broadcast observers see the pre-modify result (accepted for minimal blast radius; modify still changes the result for later phases). Tests: 10 new (T2.1-T2.8 + 2 adversarial). Regression: tests/unit + tests/integration 1624 passed, 37 skipped, 1 xfailed (the 9 done-flag-autonomy tests caught the event_bus bug pre-fix).
Milestone M4 — completes the v2.0 extensibility backbone (M1-M4 all shipped).
Drop-in Python extensions discovered from ~/.dana/extensions/ (global, always)
and .dana/extensions/ (project, trust-gated via DANA_TRUST_PROJECT_EXTENSIONS)
and bound to the agent's EventBus via a setup(agent) factory using agent.on().
- ext/extensions.py: ExtensionManager — discover/load/reload + LoadReport.
* Per-agent, lazy via agent.extensions (__dict__ storage, same __getattr__
lesson as S1/S2).
* Loader bypasses the pyc cache (read_text+compile+exec): SourceFileLoader
keys .pyc on (mtime,size) so a same-byte-size edit within 1s would exec
stale code — fatal for hot-reload correctness.
* Reload: unsub tracked handlers, pop stale sys.modules, re-exec, emit
SESSION_RELOAD. Must run at idle (S1 Finding A).
* Sub tracking via wrapping bus.subscribe during setup (try/finally).
- base_star_agent.py: agent.on alias + extensions property + load_extensions/
reload_extensions delegates. NOT auto-loaded at construction (host calls it;
zero regression risk to agent init).
- Trust gate: global = user's home (trusted); project = explicit flag.
Adversarial fixes: failing setup rolls back partial handler registrations
(transactional; was a reload leak); reload pops stale sys.modules entries.
Tests: 10 new (T4.1-T4.8 + 2 adversarial). Regression: tests/unit +
tests/integration 1634 passed, 37 skipped, 1 xfailed.
…ocumented surface
- README quickstart/usage (6 sites): agent.process/agent.stream_response -> agent.aquery / agent.aquery_text_stream (real documented surface) - docs/code-standards.md: test example + concurrency example off phantom 'process' name - base_star_agent.py: trim stale __getattr__-bypass docstring rationale (workaround __dict__ code kept; harmless defensive style) Suite: 2128 passed, 21 skipped, 1 xfailed (tests/unit); full tests/ 2744 passed. rg sweep clean of magic-dispatch call-site reliance.
ClaudeCodeSkills construction no longer scans skills_dir (default ~/.claude/skills) or probes the Claude CLI unless DANA_CLAUDE_SKILLS=1 is set. Garbage values disable discovery and log a warning. Knob documented in module and class docstrings.
Default STARAgent construction performs no skills scan: the loader is not even constructed unless the opt-in env var is set. Documented in the enable_skills arg docstring.
- default construction: zero discovery/availability calls (resource and agent-level mocked loader) - DANA_CLAUDE_SKILLS=1 restores discovery - garbage knob value -> off + warning - existing discovery tests and integration/live suites updated to opt in
…dir) Approved scope addendum (orchestrator ruling): importing dana used to mkdir ~/.dana/logs via module-level get_debug_logger() in dana/common/llm/llm.py. Resolve log_dir/paths lazily on first use so --help/--version stay side-effect free; logging behavior when actually used is unchanged.
New dana/apps/cli_flags.py: standard_parser(prog, description, setup) builds a stdlib argparse parser with --version (importlib.metadata with pyproject fallback). Called FIRST in every console-script main(): - dana-agent, dana-code, dana-init, dana-acp: parse before any agent/env work - dana-agent-repl: keeps -v/--verbose via setup hook - dana-memory: parser now built via standard_parser; dependency check moved after parse so --help/--version answer even without dana[memory] extras --help/--version exit 0 before constructing agents; unknown flags get the argparse usage error (exit 2), never swallowed into a conversation. Bare invocation path unchanged.
…empty-home All six console scripts: --help exits 0 with usage and no 'Goodbye', --version prints the pyproject version, --bogus-flag exits non-zero with usage on stderr. Plus: --help under an empty HOME creates nothing, bare dana-code still enters the REPL and exits on EOF, bare dana-memory still errors on missing subcommand.
…rnalFact, SessionRecord importable from dana.core.session
…scope+SESSION_CREATED in one call, resume on existing id
…d (relabel agent _session_id in _prepare_agent)
…prompt -> print terminal text, DANA_MOCK_LLM=1 for offline
…tent resume, hello-world flow, identity reconciliation, example runs
…on) as well as =1
- Quick start: STARAgent(model=...) + await agent.aquery(message=...) (executed live, output verified) - CLI table: real [project.scripts] names (dana-agent/-repl, dana-code, dana-memory, dana-init, dana-acp) + --help/--version note (all six verified) - Badges: version 0.2.0, Python 3.11+ (match pyproject) - Remove fictional API surface: tools=/max_tokens=/compression_threshold=/timeout kwargs, agent.state.timeline, WebResearchResource, performance table, llm_providers config key (real: llm.providers) - DANA_MOCK_LLM reframed as make-target/example-script detail, not library feature; drop DANA_DEBUG claim (zero refs in dana/) - Link AgentSession hello world at docs/examples/host_hello.py (executed with DANA_MOCK_LLM=1) - API reference: real STARAgent kwargs (max_context_tokens, enable_*), get_state()/get_timeline_summary() - Dev section: only real make targets
Copyright (c) 2026 Dana Contributors. Makes the README MIT badge/link resolve.
PyPI 'dana' is taken by the unrelated Dana DSL, so the distribution is renamed to dana-agent while the import package stays dana. Consequences: - cli_flags.py + acp/agent.py: importlib.metadata version lookups now read dana-agent (code_app already did) - [project.optional-dependencies] full extra self-reference and pip-install hint comments updated to dana-agent (old string resolved against the foreign PyPI 'dana' and broke uv lock) - uv.lock: project entry renamed (2-line mechanical diff) Addendum 1 (pre-approved): cli_flags dist-name string. Addendum 2 (supervisor ruling): acp/agent.py:73 same one-string fix. Addendum 3 (mechanical, flagged): full-extra self-reference + uv.lock.
PEP 639 SPDX license expression ('license = "MIT"') requires
setuptools>=77; >=42 only worked via isolated builds that pulled latest.
Folds in the Minor flagged in formal code review.
publish.yml fires on the v* tags that release-on-merge-to-master.yml already pushes. Verifies tag == pyproject version, builds sdist+wheel, twine-checks metadata, uploads via pypa/gh-action-pypi-publish with OIDC (no stored tokens). Manual dry-run via workflow_dispatch (default) and test.pypi.org target included. One-time maintainer step documented in the header: configure the dana-agent Trusted Publisher on pypi.org.
Append-only: adds the PyPI install path alongside git clone, honestly marked pending-first-release until the maintainer completes the Trusted Publisher setup (dist renamed to dana-agent; import package stays dana).
…n diagram, dead magic guards, gitignore .worktree
…x python
The [postgres] parametrizations of test_session_journal_contract.py fail
(not skip) when CI=true and DANA_TEST_POSTGRES_DSN is unset — by design
('the real-database contract must be exercised in CI') — but the workflow
never provided a database, so every PR run died at setup with 10 errors
(Event loop is closed masking the intended pytest.fail). Verified locally:
32/32 pass against postgres:16.
Also pins setup-uv to the matrix python — the '(3.12)' job was actually
running CPython 3.13.15.
Fast lane (develop PRs + dispatch): no postgres service, [postgres] parametrizations deselected via -k "not postgres" (verified: 16 passed, 16 deselected locally). Full lane (PRs to master): postgres:16 service + DSN, complete suite.
feat: D1 Durable Dana Conversation — restart-resumable ACP agent
chore: bump version to 0.2.1 (release train)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's in this release train
105 commits · 195 files · +35,380 / −2,900 — the full D1–D8 delivery from
feat/acp-agent-session-kernel.D1 — Durable Conversation
Session Journal (SQLite + PostgreSQL) as the sole durable authority; restart-resumable ACP agent; input facts durable before model output; session replay.
D2–D6 — ACP phases
/modelD7 — dana-code on AgentSession
CLI rewired onto the host-neutral
AgentSessioncore in-process (Option B) — durable conversations, tool catalog, permission prompts, model switching, MCP, multimodal in the terminal; dana-code ↔ dana-acp parity.D8 — First-Contact DX (from an external engineer's hands-on review)
--help/--version; zero import-time side effects (lazy log dir, skills scan opt-in viaDANA_CLAUDE_SKILLS=1)make testgreen (env guard; 2728+ passing); two-lane CI with real-postgres journal contract on master PRsSTARAgent.__getattr__magic removed (unknown attrs raiseAttributeError)AgentSession.create()+ flat imports + session-id reconciliation; 16-line hello-world host (docs/examples/host_hello.py)Verification
uv sync && make test: 2728 passed / 221 skipped / 1 xfailed (independently reproduced twice)dana-agent --version→dana-agent 0.2.0;twine checkPASSEDThe
bump-versionbot will bump develop to 0.2.1 on PR open. On merge, the release train tagsv0.2.1andpublish.ymluploads to PyPI — configure thedana-agentTrusted Publisher on pypi.org first (repo aitomatic/dana-runtime, workflow publish.yml, environment pypi) or the publish job will fail (re-runnable after config).