Jarvis tool switches and gating

Task 5136 · Done · Coder · created · updated

## Original request (verbatim, epic) Jarvis improvements: - When referencing documentation, Jarvis should show clickable links - When referencing specific sections of the Jaah Console, Jarvis should give deep links to those sections, so that user can instantly to to a Directory/Tab/Subtab or to the specific task artifact - Enable Jarvis to use certain tools: - Initially Read-only, heavily guarded to what user can see - Initially only list/read Tasks, Projects, Nodes. List Credentials: name, type, only non-secret content - Tools are enabled/disabled in System Settings. Initial: off. Can be overriden by operator per tenant. Settled inputs: the BA PRD (Task 5126, artifact `prd`) and the architecture (Task 5127, artifact `architecture`) — read them with `task_read` / `task_read_artifact` for full context. Jarvis = the support agent: `apps/api/app/support_agent/` (prompt.py, tools.py, turn.py). ## This child: C4 — the 9 switches and tool-list gating (ask A6) Ask A6 (verbatim): "Tools are enabled/disabled in System Settings. Initial: off. Can be overriden by operator per tenant." Operator decision D2: "one master switch, plus two switches per entity — read and write. Entities: Tasks, Projects, Nodes, Credentials. Write switches are fully active settings (visible, saveable, overridable like the others) but no write tool exists for Jarvis, so turning one on grants nothing yet." Assumption AS1: all switches default off and each is overridable per tenant by the operator only; effective read access for entity E = master ON AND E.read ON, both resolved for the caller's org. AS2: existing tools and the link features are NOT governed by the switches. Owns: AC6.1, AC6.2, AC6.3 (server side), AC6.4, AC6.5. Acceptance criteria (verbatim from PRD): - AC6.1 System Settings (operator) has a Jarvis tools section with: one master switch, and for each of Tasks, Projects, Nodes, Credentials a Read and a Write switch. Labels are short nouns per the UI copy standard. → Verify: dev as operator open Settings, observe the section and 9 switches. - AC6.2 Defaults: every switch off. With nothing set, Jarvis has none of the new tools (not even offered to the model). → Verify: fresh dev setting state; API test that the tool list sent to the model contains only the 4 existing tools. - AC6.3 Per-tenant override by the operator: each switch can be overridden for a specific org; that org's users get the override, other orgs the system value. A tenant Org Admin cannot see or change these switches. → Verify: dev as operator set Tasks read ON for org X only; as a member of X ask about a task → answered; as a member of org Y → "can't look that up". Test: tenant Org Admin PUT on the key is refused. - AC6.4 Effective rule: a tool for entity E is offered only when master AND E.read are ON for the caller's org; turning master OFF disables all regardless of per-entity values. A tool that is off is not offered to the model and is refused server-side if called anyway. → Verify: API test over the truth table (master × read) for one entity; test that dispatching a disabled tool name is refused. - AC6.5 Write switches are fully working settings (saved, overridable per tenant, shown with their value) but grant nothing: no write tool exists, and turning every Write ON changes the tool list by zero tools. → Verify: API test with all Write ON, all Read OFF → tool list = existing 4 only. Approach (architecture D7, D8, §6, pinned): - 9 org-tier bool knobs in `apps/api/app/operator_settings.py` `CATALOG`, `group="Support"`, `section="Jarvis tools"`, `default=False`, `env=None`, NO `tenant_editable`. Keys (pinned — other children import them): `support_tools_enabled`, `support_tools_tasks_read`, `support_tools_tasks_write`, `support_tools_projects_read`, `support_tools_projects_write`, `support_tools_nodes_read`, `support_tools_nodes_write`, `support_tools_credentials_read`, `support_tools_credentials_write`. Labels: "Enabled", "Tasks read", "Tasks write", … (UI copy standard: short). Help on write knobs states they grant nothing yet. - NEW `Knob` field `tenant_visible: bool = True`, set `False` on all nine; `apps/api/app/routes/settings.py::_settings_out` drops `tenant_visible=False` knobs for a non-operator (fail closed, beside its existing `tier == "org"` filter). Check every other non-operator read path of org knobs (e.g. org settings routes) applies the same drop. - `apps/api/app/support_agent/tools.py`: `available(principal) -> tuple[SupportTool, ...]` = the 4 existing tools + each entity's tools when `get_bool(support_tools_enabled, org=principal.org_id) and get_bool(support_tools_<entity>_read, org=…)`. Entity → tool names mapping is pinned here (the tools themselves are built by a later child): Tasks → `list_tasks`, `read_task`, `read_task_artifact`; Projects → `list_projects`, `read_project`; Nodes → `list_nodes`, `read_node`; Credentials → `list_credentials`. Provide a registration seam so the later child adds the tool objects without editing the gating logic (e.g. `ENTITY_TOOLS: dict[entity, tuple[SupportTool, ...]]` starting empty). Write knobs are read by nothing. (The reader child later adds a `has_session` keyword to `available` — keep the signature easy to extend.) - `apps/api/app/support_agent/turn.py`: the tool list sent to the model = `available(principal)`, resolved once per turn; `dispatch` refuses a tool name not in `available` (same refusal shape as an unknown tool). - No web change: generic Settings rendering + `OrgSettingsTab` (per-org operator override via `PUT /api/orgs/{org_id}/settings`). Confirm the operator per-org override UI shows and saves these knobs. Quality bar: labels and help text must read cleanly in the console (short nouns, no key names as labels); a section an operator cannot find or read FAILS this child. Out of scope: Do NOT add `tenant_editable` to these knobs; do NOT build any entity tool, console reader, or prompt change (later children); do NOT gate `search_docs`/`report_docs_gap`/`list_my_tickets`/`create_ticket`; do NOT change the Settings page UI code beyond what a new knob needs (expect none). Epic fences (PRD §5): no write tools; no reads beyond Tasks/Projects/Nodes/Credentials; no secret values anywhere; do not widen visibility or change authz clauses; do not gate existing Jarvis tools or links behind the new switches; no links to operator docs/console help, no repo paths, no GitHub links; no `tenant_editable` on the switches; no full markdown renderer; do not change the docs portal URL scheme/hosting; do not change any other console URL scheme beyond the single-artifact address; do not change support chat storage/rate limits/model settings/ticket flow beyond what links need. Deferred, NOT built: write tools, operator-doc links, more read entities. Done means: - AC6.1 — test that `CATALOG` has exactly these 9 keys in group "Support" / section "Jarvis tools", bool, default False; operator `GET /api/settings` returns all 9. - AC6.2 — API test: with nothing set, the tool list a turn sends to the model is exactly the 4 existing tools. - AC6.3 (server side) — tests: (a) a per-org override for org X makes `available` include the entity's tools for an X principal and not for an org-Y principal; (b) a tenant Org Admin PUT on any of the 9 keys is refused; (c) a tenant Org Admin `GET /api/settings` (and org settings read) does NOT contain the 9 keys. - AC6.4 — truth-table test (master × read) for one entity; test that dispatching a tool name not in `available` is refused. - AC6.5 — test: all Write ON, all Read OFF → tool list = existing 4 only; Write keys save and override per org like the others. - Gate: `./dc check full` green before the PR; the PR auto-merges into develop.

Outcome

Added 9 operator-only Jarvis tools switches (default off, per-org override, hidden from tenants); support agent offers/dispatches entity tools only when master+read are on. Full gate green; PR #4524 merged. Entity tools & result rendering deferred to later children.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)