Skip to content

feat: support toolRestrictions on POST /api/chat (AI-3600) - #46

Draft
claude[bot] wants to merge 2 commits into
mainfrom
feat/ai-3600-tool-restrictions
Draft

feat: support toolRestrictions on POST /api/chat (AI-3600)#46
claude[bot] wants to merge 2 commits into
mainfrom
feat/ai-3600-tool-restrictions

Conversation

@claude

@claude claude Bot commented Jul 20, 2026

Copy link
Copy Markdown

Requested by Jordan Burger · Slack thread

Before / After

Before: KaiClient.send_message(...) had no way to constrain which tools the assistant could use. Every chat ran with the full tool set — you couldn't ask for a read-only session, an allowlist of safe tools, or block specific write tools from the client.

After: Callers can pass an optional tool_restrictions argument to send_message(...) to scope tool usage for a chat:

from kai_client import KaiClient, ToolRestrictions

async with KaiClient(...) as client:
    chat_id = client.new_chat_id()
    async for event in client.send_message(
        chat_id,
        "Show me my tables, but don't change anything",
        tool_restrictions=ToolRestrictions(
            allowed_tools=["list_tables", "get_table_detail"],
            disallowed_tools=["run_job"],
            read_only_mode=True,
        ),
    ):
        ...

How

  • A new public ToolRestrictions Pydantic model with three optional fields — allowed_tools, disallowed_tools, read_only_mode — that serialize to the exact JSON keys the backend expects: allowedTools, disallowedTools, readOnlyMode.
  • An optional tool_restrictions field on ChatRequest (src/kai_client/models.py), serializing to toolRestrictions.
  • An optional tool_restrictions: ToolRestrictions | None = None parameter on send_message (src/kai_client/client.py), plumbed into the ChatRequest.
  • Serialization uses model_dump(by_alias=True, exclude_none=True), so when tool_restrictions is None the toolRestrictions key is omitted entirely, and any unset sub-fields are dropped from the payload.
  • ToolRestrictions is exported from the package's public API (kai_client.__init__).

Behavioral note (documented, not enforced client-side): restrictions are first-message-wins — the backend persists them from the first message of a chat and silently ignores toolRestrictions on follow-up messages of the same chat.

Pairs with the already-merged backend PR keboola/ui#6267 and Linear AI-3600.


Generated by Claude Code

Callers frequently need to constrain which tools the assistant may use for
a given chat — for example running a read-only session, restricting to an
allowlist of safe tools, or blocking specific write tools. The backend
already accepts a `toolRestrictions` field on `POST /api/chat` (merged in
keboola/ui#6267), but the Python SDK had no way to send it.

This adds a `ToolRestrictions` model (allowed_tools / disallowed_tools /
read_only_mode, serializing to allowedTools / disallowedTools / readOnlyMode)
and an optional `tool_restrictions` parameter on `KaiClient.send_message`,
plumbed through `ChatRequest`. When omitted, no `toolRestrictions` key is
sent; unset sub-fields are omitted via exclude_none.

Restrictions are first-message-wins: the backend persists them from the
first message of a chat and ignores the field on follow-up messages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnbZpLRgq9gmFSWX8bvERm
@linear-code

linear-code Bot commented Jul 20, 2026

Copy link
Copy Markdown

AI-3600

Document the new tool_restrictions parameter on send_message so users
can discover and use tool allowlists, denylists, and read-only mode
without reading the source. Covers the three optional ToolRestrictions
fields, the toolRestrictions serialization on POST /api/chat, and the
first-message-wins persistence behavior.

Updates the README usage examples, the kai-cli api-details reference,
and the kai-js data-app skill (which builds the /api/chat payload
directly). Pairs with backend PR keboola/ui#6267 (AI-3600).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MnbZpLRgq9gmFSWX8bvERm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant