feature/api-wrappers #2

Merged
niels merged 10 commits from feature/api-wrappers into develop 2026-09-17 20:01:18 +00:00
Owner

Should allow to wrap an api to set permissions and monitor endpoint calls

Should allow to wrap an api to set permissions and monitor endpoint calls
A new agent tool kind, api_wrapper, lets an agent call a third-party
HTTP API through the OpenSteward API instead of directly. The container
receives a per-execution wrapper token and the proxy URL; the upstream
credential stays server-side. Every call is checked against the tool's
method/path rules (deny wins, default deny, per-execution rule groups),
forwarded when allowed, blocked with 403 otherwise, and recorded with
the session and execution that made it. Includes the rule engine in
shared/, migration 0042, admin call-log routes, the tool editor panel,
tool and session call-log views, preflight, and docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Exported standalone agents get the same wrapper behaviour as managed
OpenSteward: the standalone backend proxies whitelisted calls with the
upstream secret from its secret store, mints per-execution wrapper
tokens, records calls per session and serves them to the shared session
UI. The transport half of the proxy moves to shared/api-wrapper-proxy.js
so both runtimes use one implementation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The proxy now takes rules and upstream settings from the tool only and
lifts just rule_groups from the execution link, so editing a tool's
rules takes effect immediately; links save rule_groups under
link_tool_config. Wrapper env var names fall back to API_WRAPPER_TOKEN
and API_WRAPPER_URL everywhere, an oversized body gets a readable 413,
HEAD responses are not refused for their advertised length, a wrapper
tool imports into a fresh agent without its local upstream (preflight
reports upstream_not_configured), the credential lookup no longer scans
the credentials table, path_contains escapes LIKE wildcards, call
summaries count the whole scope, and the session call table refreshes
while a session runs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The container's runtime-tools.json still carried upstream_base_url and the
auth settings of api_wrapper tools. Agents only need the rules and the env
var names, so both runtimes now strip the upstream side before writing
the manifest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An exported agent definition described every tool many times over. Each row in
links/execution-tools.json embedded the whole tool, its config and the merged
view, and every execution file embedded the same links again, so one tool change
rewrote thousands of lines across unrelated files. For the Twin Grant and
Knowledge Base Editor that was 67 KB of links and 37 KB per execution file for
two links.

A tool link now records what only the link knows: the execution, the tool id,
its own link_tool_config and the sort order. Artifact links keep their four
fields. Execution files no longer repeat either kind. The tool travels once, in
tools/index.json, and the runtime still merges it with link_tool_config when a
session starts. A tool preflight result is a local health check at one moment in
one environment, so it no longer travels either.

Import reads both shapes: it resolves agent_tool_id against the exported tools,
falls back to a legacy link's merged tool_config when there is no
link_tool_config, and still reads links embedded in execution files when the
link files hold none. A lean import produces the same execution_tool_links rows
and the same runtime tool view as the older embedded copies, which the new test
asserts by importing a fat definition, re-exporting it lean and importing that
into a second agent.

Standalone export is unaffected: it builds its manifest from the database, and
its runtime already resolves a link's tool by id.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`agent.json` carried a second copy of the conversation instructions in
`metadata.instructions`, which the session runtime prefers, so a drifted
copy silently won. It also repeated the agent identity scalars, and
`executions/index.json` repeated the role, engine, model, order, status,
trigger, manual label and loop flag of every execution file.

The folder export now writes `metadata.instructions` nowhere, keeps the
metadata scalars only when they differ from the top-level agent fields,
and reduces each index entry to `id`, `name`, `config_file` and
`instructions_file`. Import reads `instructions/agent/conversation.md`
into both `conversation_instructions` and `metadata.instructions`, so an
older fat folder converges on the markdown file, and it restores the
metadata scalars from the top-level fields, so the imported snapshot
still hashes like the API's own export.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An agent stored its conversation instructions twice: in
`agents.conversation_instructions` and in a `metadata.instructions` copy
that the session runtime preferred. The agent editor re-sent the stored
metadata object on save while the general agent PATCH only wrote the
column, so the stale copy silently won at runtime.

The column is now the single source. Migration 0043 rescues the copy for
any agent whose column is still empty and then removes the key
everywhere. Runtime resolution, version restore, definition import,
standalone export and the standalone bundle read the column and treat a
legacy copy in an old row, snapshot or folder as fallback input only; no
write path stores it again, and every write that receives a metadata
object strips the key, so an old client cannot resurrect it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The API calls pane was the only workspace pane without its own scrollport:
`.os-workspace-panel--api-calls .os-panel-scroll` was missing from the rule
that gives a pane `overflow-y: auto`, so it inherited `overflow: hidden` from
`.os-workspace-panel .os-panel-scroll`. Its rows were clipped instead of
scrollable, and the pane's full content height (2931px for a 60-row log at
1440x900) still counted as the flex base size of `.os-session-layout`. Because
`.os-session-shell` is a column flex box and `.os-session-topbar` only set
`height: 42px`, the shell resolved that overflow by shrinking the topbar to its
35px min-content height: selecting the tab moved the whole header up 7px.

Pin the topbar with `flex: 0 0 auto` so no pane can compress it, and add the
pane to the scrollport rule (desktop and the small-screen touch-scroll block)
so the call log scrolls while staying pinned to the top as before.

Measured in headless Chromium over the real primitives.css: before the fix the
topbar rendered 42px on the files tab and 35px on the API calls tab; after it,
every element in the shell chrome keeps identical geometry across tabs at both
1440x900 and 390x780, and the pane scroll container reports scrollHeight 2947
over clientHeight 789.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad1WypQXTnZz7nHHMwVDAv
The API calls tab showed every session member the proxied request and
response bodies, and the endpoint behind it was open to anyone who could
open the session. The tab, its pane and the fetch now need an admin, and
the session call-log route is mounted behind requireAdminUser like the
tool-scoped one already was.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ad1WypQXTnZz7nHHMwVDAv
niels merged commit 9f11a7aafa into develop 2026-09-17 20:01:18 +00:00
niels deleted branch feature/api-wrappers 2026-09-17 20:01:28 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
opensteward/OpenSteward!2
No description provided.