dev <- main sync#453
Merged
Merged
Conversation
Bridge a developer-built Agno Agent to Band: AgnoAdapter converts room history to Agno messages, runs the agent, and replies with its text output. Agno is model-agnostic, so the agent (model, instructions, tools) is supplied by the developer and reused per room. Includes AgnoHistoryConverter, lazy adapter/converter registration, the `agno` optional-dependency extra, and a basic example with README. Text-only skeleton: Band platform-tool wiring, tool-event conversion, conformance registration, and tests are deferred to follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an agno_agent entry to the repo-root agent_config.yaml.example and repoint the example docstring and README at it, instead of a per-example config file that does not exist. Simplify the example's platform URL handling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use RunOutput.get_content_as_string() instead of assuming response.content is a str, so agents configured with structured output (Pydantic BaseModel) or dict/list output are serialized to JSON rather than crashing on .strip(). Log at debug when non-text content is sent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Declare SUPPORTED_EMIT={Emit.EXECUTION} and, when enabled via
AdapterFeatures(emit={Emit.EXECUTION}), report the Agno agent's own tool
executions to the room as tool_call/tool_result events after each run,
read from RunOutput.tools. Mirrors the event shape used by the other
adapters. Reporting failures are logged, not raised.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
02_tool_reporting.py builds an Agno agent with its own tool and enables
AdapterFeatures(emit={Emit.EXECUTION}) so tool_call/tool_result events are
posted to the room. Listed in the examples README.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Log the message-handling flow at INFO (handling message, reporting tool executions, sending reply) with verbose details (input size, tool args/ results, edge cases) at DEBUG. Verified live against the platform. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Declare SUPPORTED_CAPABILITIES={MEMORY, CONTACTS} and, when those capabilities
are enabled, wire Band's memory/contact tools into the Agno agent as Agno
Functions. Each tool's entrypoint runs the Band tool via execute_tool_call,
binding the per-room tools handle through a ContextVar so a single shared agent
serves concurrent rooms. Base tools (send_message, participants) stay
adapter-driven and are filtered out. Tools are wired once on the first message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deep-copy the provided Agno agent in on_started and wire Band tools onto the copy, so the adapter never mutates the caller's agent object. Guard on_message for the not-yet-started case and handle add_tool's callable-factory rejection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the caller enables Capability.MEMORY (so the adapter exposes Band memory tools to the agent) and the Agno agent also manages its own memory (update_memory_on_run or enable_agentic_memory), raise a UserWarning at construction time (stacklevel points at the caller). Using warnings.warn rather than logging makes the conflict filterable and escalatable to an error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add AgnoOutputAdapter (reads role/content off agno Message objects) and register agno in the converter and adapter config registries: - converter: filters_own_messages=False, skips_tool_events=True (text-only) - adapter: inject a stand-in agent in the factory; no model/prompt or custom tools, so assert adapter-level state (agent=None, _band_tools_wired=False) Resolves the config-drift failure for the new agno modules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Band delivers rehydrated platform history only on session bootstrap; later messages arrive with empty history. The adapter previously rebuilt input from the history arg each call, so it dropped all context after the first turn. Accumulate a per-room transcript (self._message_history) seeded from history on bootstrap and appended with each user message and assistant reply, and feed it to Agno on every run. Restart re-seeds from the rehydrated history; on_cleanup drops the room's transcript. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Register a create_agno_adapter factory (Claude model via ANTHROPIC_API_KEY) and add "agno" to the parametrized adapter_entry fixture so the smoke and tool-execution E2E tests cover it alongside the other adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reply with mentions=[msg.sender_id]; the SDK resolves handles/names/IDs from the string form. Avoids the list[dict] mentions deprecation warning. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-3-haiku-20240307 is retired (Anthropic 404). Default e2e_anthropic_model to claude-haiku-4-5-20251001 so the Anthropic-family adapter E2E tests (anthropic, claude_sdk, agno) authenticate against a current model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The converter now carries tool_call/tool_result events through rehydration: tool calls become an assistant message with batched OpenAI-style tool_calls, and results become tool-role messages paired by tool_call_id. This is Agno's own history shape, so prior tool turns round-trip back through arun(). Dispatch uses match/case with a focused builder per event type. Flips the conformance skips_tool_events flag and extends AgnoOutputAdapter to inspect tool-call names/args. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-method `from agno.models.message import Message` statements with a single `_message_class` cached_property on the converter. Keeps the module importable without agno installed, raises one clear ImportError on use, and lets call sites read as `self._message_class(role=..., ...)`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Converter logs event->message conversion counts. Adapter logs the resolved emit/capability features at startup and the bootstrap history-seed size, so rehydration and feature config are visible at DEBUG. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prefix every on_message/tool-report log with "Room <room_id> msg <msg_id>" and log the sender id on intake and the mentions on reply, so a message can be traced end-to-end across the adapter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
03_tom_and_jerry.py spins up two Agno-backed Band agents (Tom and Jerry) with distinct personalities in one process via asyncio.gather, reusing the shared character prompts. They reply in character when mentioned in a shared room (the Agno adapter is reply-only, so they don't auto-invite like the CrewAI version). Adds tom/jery entries to agent_config.yaml.example and the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Skip band_send_message/band_send_event in _report_tool_executions: their effect is already a visible room message/event, so reporting them would double-record the reply (and duplicate it on rehydration). Adds the constant the filter referenced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split the long on_message into a short orchestrator plus single-concern helpers: _build_run_input (assemble transcript), _run_agent (run + ContextVar bind + error handling), _persist_turn (continuity), and _send_reply (fallback reply). Extract _emit_execution from _report_tool_executions, tighten _make_band_entrypoint's return type, and make room_id/msg_id keyword-only on the reporting/run helpers. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the inline ContextVar set/try/finally-reset in _run_agent with a _bind_room_tools context manager, so the "room's tools are bound for the duration of the run" before/after is named, reusable, and can't drift. Reset still happens on success and error. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add agno_message_class() and agno_function_class() (lru_cached, with a shared _require_agno helper) in band.converters.agno — the single home for the optional-dependency type imports. The converter and the adapter both use them, removing the duplicated per-class _message_class accessors and scattered `from agno...import` statements. Also tidy _build_run_input: collapse the room-history init with setdefault, drop the verbose bootstrap-seed log, and surface bootstrap state on the intake log instead. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build Band tools with a positive walrus guard (if name := fn.get("name")) and
switch the converter's match default from continue to pass. Same behavior,
no continue.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agno 2.6.16 uses any(msg.from_history for msg in input) to decide whether the input already carries history; our converter built rehydrated Band history with the default from_history=False, so an agent with its own db/session history could re-add stored history on top of Band history (duplicate context / repeated tool transcripts on bootstrap). Tag all converter-produced messages from_history=True; the adapter's current-turn message stays False. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A refactor dropped the set_agent_name call, leaving the converter's _agent_name empty so the own-agent check never matched — on restart the agent's own past replies rehydrated as "[Name]: ..." user messages instead of assistant turns. Restore the sync in on_started. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ocators The thoughts scenario reused a persisted room, so accumulated repeats of the same step-by-step question let Claude skip extended thinking, leaving reasoning_content empty -> no thought event -> a flaky failure. Allocate a fresh room instead, matching the database-restart scenario. Also drop the thin agno_multi_room / agno_thoughts_room / agno_database_room fixture wrappers; each scenario calls the allocator directly (mirroring test_context_persistence), keeping the room name and the "why this allocator" rationale at the call site. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When an adapter is configured with emit or capability values it doesn't implement, the base SimpleAdapter now emits a UserWarning in addition to the existing log line, so the misconfiguration surfaces even when logging is not at WARNING level. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(sdk): adapters report boolean activity (working) state to the pl…
Switch release workflow to band-ai/.github/actions/generate-app-token@v1 and remove the promote-dev-to-main workflow that relied on the local GithubToken action.
chore(ci): use shared band-ai app token action
…components--band-sdk chore: release band-sdk 1.1.0
Drop the band-ai/.github composite action (inaccessible from this public repo) and call actions/create-github-app-token@v3 inline. Also fix the broken steps.app_token_generator.outputs.token reference left over from the earlier rename. Requires secrets.APP_PRIVATE_KEY to be stored as raw PEM.
…ction ci: use actions/create-github-app-token@v3 directly
…rted-adapter-feature-flags-INT-880
…-for-unsupported-adapter-feature-flags-INT-880 feat: raise a visible UserWarning for unsupported adapter feature flags
Address PR review feedback:
- Inject the Band-registered identity ("You are {name}, {description}.")
into the agent prompt at startup via render_system_prompt, matching the
other adapters. Previously the fetched agent_name/description were only
used for logging and the converter, so the model never saw its Band
identity. Lock it in with a test assertion.
- Correct the examples README: the adapter does not send a text fallback
(that was dropped earlier); the agent must call band_send_message or it
stays silent. Reword the Overview and Note accordingly.
- Split the combined Tom-and-Jerry example into 03_tom_agent.py and
04_jerry_agent.py (separate processes) to match the other adapters and
demonstrate cross-adapter room communication; renumber memory/db
examples to 05/06 and point agent_config.yaml.example at the shared
tom_agent/jerry_agent entries.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Agno is model-agnostic, but the `agno` optional extra pinned `anthropic`, forcing the Claude SDK onto everyone who installed `band-sdk[agno]` even when using OpenAI/Gemini/Groq. Anthropic was only ever the examples' default. - Drop `anthropic` from the `agno` extra (regen uv.lock); it stays in `dev` so tests/CI are unaffected. - Each example declares its provider (`anthropic`) in its own PEP 723 metadata, so `uv run examples/agno/<file>.py` still pulls it automatically. - examples README: add a Model providers table (import / package / API key for anthropic, openai, google, groq), an Installation section covering both the `uv run` and `uv sync --extra agno` paths, and an OpenAI Quick Start snippet alongside the Claude one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-INT-856 feat: sdk add agno adapter python int 856
…pter-python-INT-856 revert: sdk add agno adapter python int 856"
…for-unsupported-adapter-feature-flags-INT-880
…userwarning-for-unsupported-adapter-feature-flags-INT-880 revert: raise a visible UserWarning for unsupported adapter feature flags"
chore: Dev
…components--band-sdk chore(main): release band-sdk 1.2.0
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.
PR Title Format
Summary
Changes
Related Issues
Testing
uv run pytest tests/ --ignore=tests/integration/)uv run pre-commit run --all-files)Checklist