Skip to content

feat!: add capabilities & replace legacy message filters - #28

Merged
elfominty merged 2 commits into
devfrom
eng-996-introduce-the-core-capabilities-model-with-backward
Oct 16, 2026
Merged

elfominty merged 2 commits into
devfrom
eng-996-introduce-the-core-capabilities-model-with-backward

Conversation

@elfominty

@elfominty elfominty commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds capabilities to chat.start and chat.send, including a memory capability, and
removes the legacy message filters and the memory_namespace argument they replace.

The keyword name tells you the scope:

  • thread_capabilities (start only): overrides some of the agent's capabilities for
    this thread, frozen for its lifetime. This is also where the memory bag is set.
  • message_scope (start and send): turns a capability on or off, or narrows its
    allowlist, for one message. Sent as message.scope.

Every capability is an explicit object with a required activation, and every scope is an
explicit object with a required enabled. There are no shortcuts such as web=True or
web="on_request".

run = await client.chat.start(
    agent_id=AGENT_ID,
    message="Summarize every board deck",
    thread_capabilities=AgentCapabilities(
        web=WebCapability(activation="never"),
        # document_ids omitted: defaults to ALL
        indexed_documents=IndexedDocumentsCapability(activation="always", source_ids=[101]),
        # explicit ALL, same as omitting connections
        mcp=McpCapability(activation="on_request", connections=ALL),
        skills=SkillsCapability(activation="always"),
        image_generation=ImageGenerationCapability(activation="on_request"),
        memory=MemoryCapability(activation="always", namespace="support-bot"),
    ),
    message_scope=MessageScope(image_generation=ImageGenerationScope(enabled=True)),
)

await client.chat.send(
    run.thread.id,
    agent_id=AGENT_ID,
    message="Only deck 2024",
    message_scope=MessageScope(
        indexed_documents=IndexedDocumentsScope(enabled=True, source_ids=[101]),
        mcp=McpScope(enabled=True, connections=["linear"]),
        web=WebScope(enabled=False),
    ),
)

Design

  • Thread level classes: WebCapability, IndexedDocumentsCapability, McpCapability,
    SkillsCapability, ImageGenerationCapability, VideoGenerationCapability,
    MusicGenerationCapability, MemoryCapability. Message level classes: WebScope,
    IndexedDocumentsScope, McpScope, ImageGenerationScope, VideoGenerationScope,
    MusicGenerationScope. They are distinct classes, so pyright rejects
    web=ImageGenerationCapability(...).
  • activation and enabled are always required. Skills accept "always" or "never"
    only. MessageScope has no skills and no memory, like the API.
  • Filters (source_ids, document_ids, connections, include) default to ALL (the
    string "*", no restriction) on capabilities and on scopes. Passing ALL explicitly is
    equivalent to omitting the filter. None, [] and a "*" inside a list raise
    InvalidParams before any request is sent, and so does a filter combined with
    activation="never" or enabled=False.
  • "never" sends only {"activation": "never"}, a disabled scope only
    {"enabled": false}. This is done with mode="wrap" serializers that edit the default
    output.
  • Memory is a capability like the others. MemoryCapability(activation="always", namespace=...) sets the thread's memory bag (1 to 128 characters),
    MemoryCapability(activation="never") runs the thread without memory. always requires
    a namespace and never refuses one. Without a memory entry, the thread uses the
    agent's namespace, or runs without memory if the agent has none. The bag is frozen at
    start: a follow-up cannot change it.
  • The scope is sent as message.scope. Under the key message.capabilities the API
    silently ignores it, so this matters.
  • thread_capabilities does not exist on chat.send, so the API's 422 for a follow-up
    override cannot be triggered.
  • Policy checks that depend on thread state (widening an allowlist, a capability the
    thread does not have, switching off what is already off) stay server side and surface as
    a 422 APIError.
  • The ValidationError to InvalidParams conversion is a mode="wrap" model validator
    on a private _StrictModel base, so pyright keeps the per-field __init__ signature.
  • AgentCapabilities is reusable as is by a future client.agents. /agents is not
    covered here: it returns 403 with an API key.

Breaking changes

This is a major release (1.0.0). Removed from chat.start / chat.send and
HumanMessage: source_ids, document_ids, disabled_tools, and DisablableTool. The
API refuses to mix them with capabilities. Removed from chat.start and
StartChatOptions: memory_namespace, now a capability.

Before After
disabled_tools=["web"] message_scope=MessageScope(web=WebScope(enabled=False))
disabled_tools=["company_documents"] MessageScope(indexed_documents=IndexedDocumentsScope(enabled=False))
disabled_tools=["mcp:*"] MessageScope(mcp=McpScope(enabled=False))
disabled_tools=["mcp:notion"] MessageScope(mcp=McpScope(enabled=True, connections=[<connections to keep>]))
source_ids=[101] MessageScope(indexed_documents=IndexedDocumentsScope(enabled=True, source_ids=[101]))
document_ids=[...] IndexedDocumentsScope(enabled=True, document_ids=[...])
memory_namespace="support-bot" thread_capabilities=AgentCapabilities(memory=MemoryCapability(activation="always", namespace="support-bot"))

Also in this PR

  • Examples 07 and 08 migrated, new examples/11_capabilities.py (it follows
    10_max_steps.py).
  • README section, CHANGELOG [1.0.0] section with the migration table. The version bump
    is left to uv run invoke release --major.

Test plan

  • uv run invoke code.all (ruff, pyright strict, pytest, 100% coverage)
  • Unit tests on Python 3.9 as well
  • Unit tests: exact wire shape ("*" kept, never and enabled=False send only the
    switch, no None keys), local validation errors, memory namespace rules, request
    bodies for start and send (message.scope), memory_namespace no longer
    accepted
  • Playground scenarios against the local API (playground/test_scenario, not part of
    the PR): every capability and scope observed through the agent's own scopes block and
    tool list, follow-up scopes lasting one message, the server's 422 policy errors,
    saved agents combined with thread overrides, and memory routing checked with real
    writes through client.memory

@elfominty
elfominty requested a review from mous222 October 2, 2026 19:45
@elfominty elfominty self-assigned this Oct 2, 2026
@elfominty elfominty added the enhancement New feature or request label Oct 2, 2026
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3974236d-f288-4160-9d57-9cde258f3a3e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@elfominty
elfominty force-pushed the eng-996-introduce-the-core-capabilities-model-with-backward branch 2 times, most recently from 67c1426 to 756db56 Compare October 7, 2026 11:49
@elfominty elfominty changed the title feat!: add capabilities and max_steps, replace legacy message filters feat!: add capabilities & replace legacy message filters Oct 7, 2026
@elfominty
elfominty force-pushed the eng-996-introduce-the-core-capabilities-model-with-backward branch 2 times, most recently from e681878 to 6a8dab6 Compare October 15, 2026 16:20
ref ENG-996

- Added `thread_capabilities` to `chat.start` for overriding agent capabilities for the thread's lifetime.
- Introduced `message_scope` in `chat.start` and `chat.send` to enable/disable capabilities or narrow their allowlist for individual messages.
- Removed deprecated parameters: `source_ids`, `document_ids`, and `disabled_tools` in favor of the new capabilities structure.
- Updated documentation and examples to reflect these changes, including new usage patterns for capabilities.
@elfominty
elfominty force-pushed the eng-996-introduce-the-core-capabilities-model-with-backward branch from 6a8dab6 to 368b7e6 Compare October 16, 2026 09:11
@elfominty

Copy link
Copy Markdown
Collaborator Author

/merge

@elfominty
elfominty merged commit ff9d4c9 into dev Oct 16, 2026
12 checks passed
@elfominty

Copy link
Copy Markdown
Collaborator Author

Success! Fast forwarded dev to eng-996-introduce-the-core-capabilities-model-with-backward! git checkout dev && git merge eng-996-introduce-the-core-capabilities-model-with-backward --ff-only

@elfominty
elfominty deleted the eng-996-introduce-the-core-capabilities-model-with-backward branch October 16, 2026 10:17

This branch was successfully deployed

1 active deployment
pypi — ff9d4c93 Deployed Oct 16, 2026 by elfominty via Publish to PyPI #8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants