445 Commits
Author SHA1 Message Date
arc53-machine 4b08e94be7 Name every person on agent pages by one rule
people_named_to decides whom the edit page and the share dialog name:
the reader, the holder's owner, anyone sharing a team with the reader and,
for the owner, whoever sponsored something on the holder. A resource's
owner, named as whom to ask or whose credentials a tool uses, also needs
the reader to see that resource. Sponsors, runs_as, contact and account
in resource_states and sponsors in sponsor_details all follow it; anyone
else is left unnamed and the pages say someone else.

A tool's run details (note, credential_mode, account, writes) come from
one function and only for a tool that runs. The share dialog keys each
person's own account on the per_user_account note, as the notice does,
and the unused noteKey helper and its string are gone.
2026-09-29 18:12:54 +01:00
arc53-machine d04f76e97a Say which resources are left out of runs and which can't run until fixed 2026-09-29 17:52:12 +01:00
arc53-machine db9eb2b1c3 Correct what the agent sharing docs say about accounts, sponsors and switches
The table adds tools with saved credentials, says API and widget users
get the owner's account on a tool each person connects, that a sponsored
item runs as the owner again once the owner can use it, and that a
teammate's name shows only to people who share a team with them. The
editor switches are named per resource type, public-link users are said
to be asked only for writes that need approval, the allowlist is said to
cover sponsored and workflow node tools, and the badge names and the new
resource_states fields match the app.
2026-09-29 17:50:42 +01:00
arc53-machine da75845fcf Document sharing agents and whose access what they use runs with
A new "Sharing agents and what they use" section covers viewers and
editors, whose access each tool, source and prompt runs with as the share
dialog labels it, sponsors, stopped resources, what API, widget and
public-link users can't do without the write allowlist, the wiki switch
and research steps. The sharing rules now mention the editor switches and
member-mode tools, the guardrails page no longer says editors can't
change guardrails, the connector guide uses the new tool share labels,
and related pages link to the section.
2026-09-29 17:35:17 +01:00
arc53-machine 9775dd1af9 Document what happens when an agent's resource stops working 2026-09-29 17:17:13 +01:00
arc53-machine 90b385e9ea Document taking over stopped resources and how the agent's audience can grow 2026-09-29 16:55:00 +01:00
arc53-machine 2f6f4edac2 Note that research steps skip actions they would have to ask about 2026-09-29 16:45:55 +01:00
arc53-machine ff10fcca0f Say the wiki switch covers API keys and widgets, not public links
Public-link visitors edit only wikis they can edit themselves and approve
each edit. The docs also note that with authentication off every caller
is the owner's local user, so the switch has no effect there.
2026-09-29 16:37:58 +01:00
arc53-machine c66afd6b30 Document who may sponsor a resource in someone else's agent 2026-09-29 16:34:53 +01:00
arc53-machine d4b30f4838 Document who can edit a wiki from the API, widget and public links 2026-09-29 16:12:42 +01:00
arc53-machine 33a73bc442 Note that older API-key schedules keep the old rules until they run out
Schedules an API or widget chat set before schedules recorded their
origin run as the owner's own until they fire or expire.
2026-09-29 15:55:50 +01:00
arc53-machine 51f88144c5 Run webhooks with the owner's rules again
The owner sets a webhook up and its URL is a secret, and a webhook run
already refuses every action that needs approval, so holding it to the
API write allowlist only broke the owner's own automations. Webhook runs
no longer count as external callers; schedules keep their caller rules.
The allowlist copy no longer names webhooks.
2026-09-29 15:55:36 +01:00
arc53-machine 080b75c81e Gate an API tool action only when it sends the owner's saved values
Every API tool counted as holding the owner's credentials, so outside
callers were refused any write on one even when it sends nothing the
owner stored. Now an action counts only when its headers or query
parameters carry a saved value (sealed or legacy plaintext) or the tool
stores credentials; the allowlist lists just those writes.
2026-09-29 15:54:30 +01:00
arc53-machine daf6af57ae Keep outside callers' write limits in scheduled and webhook runs
A scheduled or webhook run acts as the agent's owner with no one to
approve, so a public-link user or API-key caller could have the agent
schedule a write and have it run on the owner's accounts. Runs now keep
the caller's rules: a schedule set by someone who reaches the agent only
by its public link runs as a public-link caller, one set through the API
(recorded as created_via 'api', migration 0042) and every webhook run as
an external caller, each with the agent's API write allowlist.
2026-09-29 15:44:24 +01:00
arc53-machine 3dc5080058 Refuse public-link writes on the owner's account unless allowlisted
Someone who reaches an agent only through its public link was offered the
approval card for writes on the owner's connected accounts, so a stranger
could approve for the owner. Those writes are now refused with a tool
result, like an API-key caller's, unless the owner allowed the action in
the agent's Access details. Team members keep the card, and a tool on the
caller's own account (member mode) is unaffected. The flag survives a
resume, and workflow nodes now follow the run's caller rules (scheduled,
API-key and public-link) instead of starting from none.
2026-09-29 15:12:46 +01:00
arc53-machine a3484cb567 Use the default connector callback URL in the integration guides 2026-09-29 15:07:14 +01:00
arc53-machine a1789d2ab4 Merge main (roles and access revamp) into connectors
Main's access model (team editors and viewers, edit_credentials, owner-only
OAuth servers, per-user tool preferences, resource sponsors) now applies to
connection-backed tools and sources. Our migrations are renumbered to
0040_connections and 0041_connection_account_name, after main's
0038_resource_access_settings and 0039_resource_sponsors.

Where the two sides met: MCP tools save and load their connections as the
tool owner, editors may add a key (a new connection on the owner's account)
but never rewrite an existing connection's secret, fixed values stay
owner-only, and a member's own connection is used in member mode.
2026-09-29 14:02:26 +01:00
arc53-machine f6f9ae670c Document the Sync into Knowledge choice when connecting 2026-09-29 12:17:33 +01:00
arc53-machine 5d7502631f Document syncing Linear into Knowledge 2026-09-29 11:32:40 +01:00
arc53-machine bcfa8b349b Document GitHub write access and the permissions it needs
Explains the opt-in switch, the full endpoint it uses, how write actions
default to asking first, the admin's Write access switch, and which
fine-grained token or GitHub App permissions changes need.
2026-09-29 11:22:01 +01:00
arc53-machine e0e83b5492 Document account names, fixed values and the Telegram default chat 2026-09-29 10:42:03 +01:00
arc53-machine 84230409c6 Document the GitHub connector
How members connect with a fine-grained token or Sign in with GitHub, how
an admin registers the GitHub App (callback URL, permissions, requesting
authorization during installation, settings), and that
GITHUB_ACCESS_TOKEN now reads public repositories only.
2026-09-29 10:41:03 +01:00
arc53-machine 7b516ade82 Add a built-in GitHub connector for repository sync and read-only tools
One GitHub connection feeds both a Knowledge source and an agent tool.
Users connect with a personal access token, checked against GitHub and
named after the account, or, when an admin registers a GitHub App
(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_APP_SLUG), with Sign in
with GitHub. App tokens expire after eight hours and are refreshed before
each sync or tool call; tokens with no expiry are never treated as expired.

The catalog gains an optional second sign-in method (oauth_settings,
exposed as sign_in_methods) without changing any other connector.

Sync lists the repositories the connection can read (the token's own, or
the App installations') and ingests one with the connection's token. The
tool is GitHub's read-only MCP server (api.githubcopilot.com/mcp/readonly):
setup discovers its actions and creates it bound to the connection, and
the executor sends the connection's token only to that server.
2026-09-29 10:41:03 +01:00
arc53-machine 79fd2ac6cd A connector's page is the one home for its account, knowledge and tools
- Tools from a connection turn on and off on the connector's page (a
  real switch, not a badge), next to their action permissions.
- Knowledge synced from a connection lists its sync state there, with
  Sync now (connector sources and S3/Reddit sources each through their
  own endpoint).
- On the Tools and Knowledge pages, anything from a connection has
  "Manage connection" in its menu, which opens that page; the tool
  editor with its second credentials form is no longer offered for them.
- A link to a part (Jira & Confluence) opens its parent's page.
2026-09-28 22:38:49 +01:00
arc53-machine 3b1288097d One vocabulary: Knowledge, tools, and connectors in plain words
- Sources (the collection) are called Knowledge: the settings page (now
  /settings/knowledge; /settings/sources redirects), the composer and
  agent pickers, Add knowledge, and "syncs into Knowledge" on connectors.
  Citations keep "sources". All seven locales.
- Connector cards describe what they do ("Syncs into Knowledge", "Looks
  things up", "Takes actions") and drop publisher labels ("Built in",
  "Preset"). Filters read "Files & storage" and "Docs & wikis" so
  "knowledge" means one thing.
- Custom tools are tools: "Add custom tool". The agent picker no longer
  splits built-in tools into "Built-in" and "Default".
- Confluence is one card: syncing pages into Knowledge and the Jira &
  Confluence MCP actions (part_of on the preset) share a page. The part
  shows on its own when Confluence sync is not set up.
2026-09-28 22:31:26 +01:00
arc53-machine df70869dc7 Simplify Admin > Connectors
- One control for members' own MCP servers: the custom MCP server row's
  switch (it sets both the policy and the instance switch); the separate
  top-level switch is gone.
- Connectors that only sync content show "No tools" instead of a
  sharing policy, and the policies read "The sharer decides per share",
  "Always the sharer's account", "Always each person's own account".
- A connector that needs server settings can't be switched on until they
  exist; a tooltip says why.
- On phones the table becomes a list ("On · 2 connections · …") and each
  connector's controls open in a sheet.
2026-09-28 21:52:18 +01:00
arc53-machine bfcc4a9773 Sign in to MCP presets from the connect wizard
Notion, Linear, Atlassian, Sentry, Asana and Stripe no longer open the
MCP server form. The wizard shows one "Sign in to Notion" button: the
pop-up opens inside the click (so browsers allow it), follows the
worker's mcp.oauth events to the provider, and the tool is saved on
success with its actions on the done step. Reconnecting a preset uses
the same flow, as do the chat bar and the health toast.

Saving an OAuth MCP server without a new handshake now uses the stored
sign-in instead of failing, and the custom MCP form keeps scopes and
timeout under Show advanced.
2026-09-28 21:42:50 +01:00
arc53-machine a23ace3491 Refuse writes on the owner's accounts from API-key callers unless allowed
An agent called with its API key (widget, API) runs as its owner, and
nobody can approve an action there, so a write set to Always allow ran
on the owner's account for anyone holding the key. A caller is external
when the request carries the key and is not signed in as the owner (an
owner previewing their agent keeps full access).

For external callers, write actions on connection-backed tools are
refused unless listed in the agent config's new api_write_allowlist
(tool_id:action), and a missing connection is refused instead of pausing
on a Connect card the widget cannot show. The flag and list survive a
paused-and-resumed stream. Owners pick the allowed actions under Access
details; a team editor's update keeps the stored list.
2026-09-28 21:33:41 +01:00
arc53-machine a564dea401 Hide connectors that need admin setup; they start turned off
A connector's enabled switch is now optional: unset means on when the
connector has the server settings it needs, so Google Drive, SharePoint
and Confluence start off until their OAuth settings are present, and an
admin's explicit switch always wins. Changing only the sharing mode no
longer switches a connector on.

Members only see connectors they can use. The catalog, Add Source tiles
and Add Tool leave out anything turned off or still needing setup, except
a connector a member already has a connection to, which stays listed as
turned off so it can be managed or removed.
2026-09-28 20:16:40 +01:00
arc53-machine 8f00118afc Document connectors and the upgrade to encrypted connections
- Guides > Connectors: using connections, sharing modes, attribution,
  and admin setup (encryption key and rotation, redirect URIs, Google
  Drive, SharePoint, Confluence, S3, MCP presets).
- Integration pages register CONNECTOR_REDIRECT_BASE_URI as-is; the
  ?provider= suffix never matched what the backend sends.
  VITE_GOOGLE_CLIENT_ID is optional.
- Upgrading: set ENCRYPTION_SECRET_KEY before migrating multi-user installs.
2026-09-28 17:59:36 +01:00
arc53-machine 667d4bbab0 Encrypt connection credentials with an owner-bound AES-GCM envelope
Adds a v2 credential envelope next to the v1 tool-secret helpers:
AES-256-GCM, a master key derived once per process from
ENCRYPTION_SECRET_KEY, and a per-record key from HKDF over the owner's
id, which is also the associated data, so a blob moved onto another
user's row does not decrypt. The envelope names its key, so
ENCRYPTION_SECRET_KEY_PREVIOUS keeps old rows readable during a
rotation.

Log redaction now also covers token_info, tokens and client_info, and
the API warns at startup when the public default key is in use.
2026-09-28 17:03:02 +01:00
arc53-machine c40f06e10b Say that chunks can be exceeded when sources outnumber it
Every attached source gets at least one chunk, so eight sources at
chunks: 6 return eight.
2026-09-28 14:45:06 +01:00
arc53-machine 527880d3b8 Document the 6-chunk default and that chunks is a total
The agent basics page still described the Chunks per query field the form
no longer has.
2026-09-28 14:34:50 +01:00
arc53-machine 9a8653367c Update docs widget to docsgpt-react 0.8.0 2026-09-25 10:47:49 +01:00
arc53-machine 4e1002f5e0 Document execution traces and the GenAI OpenTelemetry export
Covers what is recorded, where it is shown, the TRACES_* settings, the
gen_ai.* spans and metrics, content capture, and the limits of exporting
spans when the request ends.
2026-09-23 17:46:18 +01:00
arc53-machine f6269c483f Add execution-trace settings and declare opentelemetry-api
TRACES_* settings for the per-request trace timeline and its GenAI OTel
export. opentelemetry-api was only transitive; the tracing package
imports it directly.
2026-09-23 17:14:51 +01:00
arc53-machine f693111de1 fix(audit): derive attribution for legacy inserts instead of defaulting it
The DEFAULT 'unknown' added in the last pass stopped a previous-release
process from raising NotNullViolation mid-rollout, but it threw the
attribution away to do it. The highest-volume auth_events writers are OIDC
login and silent renewal, where the actor is simply the user, so a rollout
window would have flattened exactly the rows that were trivially recoverable.

Lifts both derivation rules into SQL functions -- auth_events_derive_actor
and auth_events_derive_target -- so the backfill and a BEFORE INSERT trigger
share one definition rather than two copies of the same CASE drifting apart.

The trigger guards on NEW.actor_id IS NULL, which identifies a legacy insert
exactly because the repository always supplies one. That distinction matters
for target_id: a current writer sets it NULL deliberately for events with no
user target, and deriving there would name the actor as their own target.

Kept rather than scheduled for removal: it is a no-op on the path the
repository takes, and it keeps the column's contract true for any writer that
bypasses it.
2026-09-22 13:22:11 +01:00
arc53-machine 25c82003d7 fix(admin): second review pass
Correctness
- /api/remote never recorded source.created, so URL, GitHub and connector
  sources had a source.deleted with no matching creation. All three creation
  paths now go through one _audit_source_created helper.
- The prompt-cache rate divided cached tokens by a whole bucket's prompt
  tokens. A bucket is a day and mixes calls whose provider reports a cache
  breakdown with calls whose provider does not, so filtering buckets in the
  client could not separate them and the rate was understated by however much
  traffic ran on a non-reporting provider. The denominator is now computed in
  SQL over the reporting rows.
- The outcome pill matched values nothing writes. Guardrails emit triggered /
  not_evaluated and the device feed emits dispatched; the map had blocked /
  denied / allowed, so a guardrail that fired rendered neutral grey -- the one
  signal the merged feed exists to surface. Fixtures were seeding the
  fictional values, so the tests passed on it too.
- Stream duration_ms timed the consumer. stream_token_usage is a generator,
  so start-to-exhaustion includes the agent loop's tool handling and the SSE
  client's pace; a slow browser recorded ~30s for a sub-second call. It now
  accumulates only the time spent inside next().

Safety
- Activity filters failed open: an unknown facet or unparseable timestamp was
  dropped, and no filter means every row, so a typo widened an audit view and
  on the export streamed the full history. Both are now a 400.
- The search term was interpolated into an ILIKE pattern, so "100%" matched
  everything and "q1_report" matched more than it should. Escaped.
- 0034 set actor_id NOT NULL with no default. A previous-release process
  inserting mid-rollout would raise, and in admin/routes.py that insert shares
  the request transaction, so a role grant beside it would roll back too.

Noise and dead code
- The per-user panel is a security panel: data-plane events file under the
  actor, so an active account's routine deletes pushed a denied login out of
  the 20-row window. It now excludes them; the Activity tab shows everything.
- device_audit_log had no created_at-leading index, so the merged feed
  sequentially scanned that branch every page (migration 0036).
- conversation.deleted_all no longer records when nothing was deleted, and
  agent.updated no longer records an empty field list.
- Dropped by_model from /admin/usage (no consumer; an extra aggregate per page
  load), the duplicate filter surface on AuthEventsRepository that nothing
  called, and the unreachable FLOW_LABELS.schedule entry.
- Type hints on record_event's conn and the remaining unannotated helpers.
2026-09-22 12:47:40 +01:00
arc53-machine f6f8af8cef docs: document the activity feed, actor/target and usage spend
Covers what the previous commits changed: the actor_id / target_id split and
the system actors, the data-plane events, the merged Activity feed and its
export, and the new usage and per-user spend endpoints.

Also corrects "there is no UI for these events yet" in the OIDC login
auditing section, which is no longer true.
2026-09-22 10:35:17 +01:00
Alex a25bec6821 Merge remote-tracking branch 'origin/main' into branding-upd
# Conflicts:
#	docsgpt/core/models/anthropic.yaml
#	docsgpt/core/models/openai.yaml
#	frontend/src/admin/AdminUI.tsx
2026-09-21 17:52:53 +01:00
Pavel 2e07390782 logo upd 2026-09-21 19:45:09 +04:00
Alex 1e14605ee7 fix(quotas): keyless agent chat bucket, keep disabled policies disabled, cached rates
- check_usage treats a request through a keyless (draft) agent as agent
  traffic, matching how its usage rows are bucketed and the headless rule
- dashboard edits carry the stored enabled flag instead of re-enabling the
  policy; disabled policies are labelled in the Quotas tab and the editor
- quota 429s send x-should-retry: false so OpenAI SDK clients do not retry
  a refusal that cannot succeed before the reset
- cached-input and cache-write rates for Anthropic, OpenRouter and Groq
  gpt-oss-120b; refresh OpenRouter deepseek-v3.2 list prices
- UsageQuota reuses usagePercent; docs note that a user override needs an
  existing user
2026-09-21 15:26:29 +01:00
Alex 4bd259fc09 fix(quotas): address review: resume claims, agent bucket rule, UI races
- A tool continuation refused for usage now releases the resume claim it
  took; before, retries got a 409 until the stale claim was reverted.
- Agent traffic is any row with an agent key or an agent id, so keyless
  agents and workflow nodes count toward the agent bucket, not direct.
- The user quota modal discards responses for a previously opened user.
- The usage meter shows every limited bucket, not only 'all'.
- Restore the class separator on the analytics stat card that a formatter
  run removed, and align the OpenRouter DeepSeek description with its rates.
2026-09-21 12:44:26 +01:00
Alex 1eacfdd3d0 docs: usage quotas
How the instance default, team allowances and user overrides resolve
(including users in several teams), the quota window, who is charged for
agent traffic, how cost budgets price models and what happens to unpriced
ones, and the admin and user API.
2026-09-21 12:11:38 +01:00
Alex b77561288d feat(pricing): per-million model rates and a cost module
Rename the unused *_cost_per_token capability fields to USD per 1M tokens,
add prompt-cache read/write rates, and ship list prices for the hosted
catalogs. The old per-token keys still load, scaled, with a warning.

docsgpt/pricing.py turns a call's token bins into a USD cost. Models with
no declared rate cost $0 unless QUOTA_UNPRICED_RATE_PER_MILLION is set.
2026-09-21 11:38:22 +01:00
Alex 1c1bc2538f Merge pull request #2812 from arc53-machine/feat/personal-access-tokens
feat: personal access tokens (scoped API tokens for CLI and CI/CD)
2026-09-21 10:55:33 +01:00
arc53-machine 91f2ec2f09 feat(pat): regenerate a token's secret and reset its expiry
POST /api/user/tokens/<id>/regenerate swaps the secret of an existing token
in place: name, scopes and restrictions stay, the old secret stops matching
at once, and the expiry is reset. The lifetime defaults to the one the token
was last issued with (clamped to today's policy) or to expires_in_days when
given. An expired token can be renewed this way; a revoked one cannot. It is
session only like the rest of token management, and writes a pat_regenerated
audit event. regenerated_at records the rotation.
2026-09-21 10:32:17 +01:00
arc53-machine 3e38dc19ec docs: key CI source uploads by commit so a revert is ingested again 2026-09-20 19:47:26 +01:00
arc53-machine 94b5924e36 fix(pat): close restricted-token paths through workflows, chat, schedules and conversations
A resource restriction was checked on ids in the request, not on what the
addressed row pulls in or belongs to. Closed:

- Workflow writes for tokens restricted on sources, tools or prompts (a graph
  names those inside its nodes), and attaching a workflow to an agent unless
  the token is restricted on workflows too.
- Chat for tools-restricted tokens (chat executes tools; rejected at token
  creation as well), and agent-less chat for tokens restricted on prompts or
  workflows.
- conversation_id on chat: it must belong to the agent being run, or to no
  agent for agent-less chat. Otherwise the server continued, appended to, or
  resumed pending tool calls of another agent's conversation.
- Schedules for tokens restricted on anything but agents; schedule-id routes
  for every restricted token.
- Conversations and analytics for every restricted token, not only
  agent-restricted ones.

Also: create, first publish and adopt return the agent API key masked to a
token without agents:keys; token ids must be canonical UUIDs (urn:uuid: gave
a 500); an expired token is reported as expired; token creation takes a
per-user advisory lock so the cap cannot be raced; admin revoke-sessions
writes a pat_revoked event per token. The UI drops a row whose revoke returns
404 and does not offer a tools restriction next to chat:run.
2026-09-20 19:46:43 +01:00
arc53-machine 7ddb5f6400 fix(pat): align replay scopes, keep 404/405, retire expired names, document the PAT_ENABLED switch
The ASGI message events route now accepts the same scopes as its Flask
sibling (conversations:read or chat:run) through a shared constant. A token
request that fails routing gets Flask's 404/405 instead of a 403. Creating a
token retires an expired token that still held the name. allowed_ids uses
is_pat instead of a bare literal. PAT_ENABLED is documented as the master
switch it is: turning it off stops every existing token from authenticating.
The docs explain that sources are matched by name (oldest wins) and point CI
flows at sources upload --replace.
2026-09-20 12:12:42 +01:00