Commit Graph

4294 Commits

Author SHA1 Message Date
Hyu e14e277424 fix(api): scope TOTP oversight to the caller's workspace
The second-factor listing was instance-wide and the three mutating endpoints never checked that the target Account belongs to the caller's Workspace, so an owner or admin could see and reset another tenant's account. The listing now resolves the Workspace members and the mutations answer 404 for a foreign account, which does not disclose that it exists.

Also fixes the TOTP write path on Postgres: six write points passed timezone-aware datetimes into timestamp-without-time-zone columns, which asyncpg rejects, so every enroll, confirm, revoke and recovery-code consumption raised a 500 there. SQLite tolerated the same values.

The panel derives its oversight view from the API authorization instead of the length of the account list, which would have hidden it in a single-member Workspace.
2026-09-28 22:38:30 +08:00
Hyu 06ca7a93a9 feat(web): consolidate operation log settings into a collection dialog
Rename the traceability surface to "operation log", move its entry from the sidebar into the settings dialog, and collect the capture level and the retention policy in one dialog. The retention fields are shown inline instead of behind a disclosure; edits stay a draft until Save, and Reset restores the persisted policy. Copy updated across the eight locales.
2026-09-28 22:38:24 +08:00
Hyu c18db122e1 fix(web): keep the beta banner clear of the app shell
- render the banner through the Alert API so its grid keeps one full-width text column instead of wrapping inside the empty icon column

- point the cloud link at space.langbot.app/cloud?environment=dedicated and the self-hosted link at the GitHub repository

- keep the last known state and retry the probe (1/2/4/8s plus a re-check on window focus) so a restarting backend cannot hide the banner for the session

- publish --beta-banner-height so the fixed sidebar container, the sidebar wrapper and the wizard shell start below the banner
2026-09-28 19:38:09 +08:00
RockChinQ 36661442ad build(core): pin SDK 0.7.4 wheel while PyPI index catches up 2026-09-28 10:57:20 +00:00
RockChinQ 299a6df74a build(core): pin plugin SDK 0.7.4 for legacy runner compatibility 2026-09-28 10:53:25 +00:00
RockChinQ c384e4715a test(plugin): include stateless certificate model in shared fixtures 2026-09-28 09:14:54 +00:00
RockChinQ 621f2f0a4a fix(cloud): pin SDK 0.7.3 dedicated binding fix 2026-09-28 08:40:59 +00:00
RockChinQ ebe5bd9d86 fix(cloud): pin SDK dedicated worker initialization fix 2026-09-28 08:06:46 +00:00
RockChinQ b51a448b1e feat: stateless certified shared worker
Implements stateless singleton component model for certified shared Workers, integrating with SDK 0.7.0.
2026-09-28 13:25:40 +08:00
RockChinQ e778445982 feat: add beta environment banner
Add beta environment warning banner for Cloud beta deployments with i18n support (zh/en/ja)
2026-09-28 13:17:03 +08:00
Type_rBody a75e57ade3 Merge pull request #2579 from langbot-app/feat/workspace-operation-traceability
Feat/workspace operation traceability
2026-09-28 02:27:56 +08:00
TyperBody 280be0d7a4 fix(operation-trace): audit every route for misclassified mutations
Systematically cross-checked all 263 route/method pairs against the classifier
and fixed every case where a real change could be mislabelled:

- POST /skills and PUT /skills/<name> were classified as skill_view (read
  bucket), so creating or editing a skill was silently unlogged at the mutation
  level. They now record skill_update.
- The public webhook ingress (/bots/<uuid>) and the embedded chat widget
  (/embed/*) are unauthenticated visitor traffic, not Workspace changes; they
  are dropped instead of logged as create/resource.
- Uploading files and indexing documents (data flowing into a resource) are
  offered as observations so they never fill the log; deleting a knowledge-base
  file is destructive and now records file_delete.
- A plugin's own config-file edit/delete is a plugin change, not an opaque
  resource delete; ordered before the /config rule that also matched it.
- The bucket now comes from the action table (plus 'a read verb is always a
  read'), so a write action can no longer be forced into the read bucket.
- Added agents and files resource families; localized every new action/resource
  type in all nine locales.
2026-09-28 02:17:50 +08:00
TyperBody 67ff4d3054 fix(operation-trace): record uninstalls and deletes, drop assistant chatter
- Split the route rules on the HTTP method so a DELETE is classified as a
  destructive action instead of falling into the read/write bucket. Uninstalling
  a plugin or skill and deleting a knowledge base or MCP server were recorded as
  a view/update and left no readable trace.
- Add plugin_uninstall, skill_uninstall, knowledge_base_delete and mcp_delete.
- Skip the assistant's own conversation traffic: a chat session produced opaque
  create/resource rows that answered nothing.
- Localize the new actions and the assistant_conversation resource type in all locales.
- Sync the assistant tool action list and apply ruff formatting.
2026-09-28 02:06:57 +08:00
TyperBody b0fab2386e Merge remote-tracking branch 'origin/master' into feat/workspace-operation-traceability 2026-09-28 01:56:03 +08:00
TyperBody 7eeb0393a6 feat(operation-trace): collapsible retention policy and assistant trace tool
- Collapse the retention policy section by default, showing a one-line summary when collapsed.
- Add the owner/admin-only list_operation_logs assistant tool backed by audit.view.
- Enforce per-tool permissions on both tool listing and invocation.
- Add a substring search filter (search) to query_logs and the tool so callers can
  ask narrow questions (plugin name, account, verb) instead of dumping the full history.
- Project records to a compact shape so a page stays under the assistant result budget.
- Localize the new assistant tool label and retention summary across all locales.
2026-09-28 01:56:00 +08:00
TyperBody 9ecb469d13 feat(operation-trace): lead with the change, fix pipeline extension tracing
The panel answered "who, when, what" poorly: the actual before → after diff
was hidden behind a click, the actor was a muted line, and a whole row went to
the route while duration and hash sat in a permanent right column. The data
already arrives with the page, so the panel now reads top-down in the order an
operator actually looks:

* who and when first, then the action and resource, then the diff spelled out
  inline (long values collapse to their size so a pipeline config does not
  render as two near-identical blobs), with route / method / status / duration
  / evidence hash moved into the expanded diagnostics line;
* the whole card is the expand toggle with a rotating chevron, which removes
  the ambiguity of a small text link whose expanded state looked identical;
* records are bucketed into today / yesterday / dated groups so a long history
  reads as a timeline;
* a "changes only" toggle (reusing the level filter) answers "who changed
  something" in one click -- in the live log 489 of 499 rows are pure views,
  so this is the difference between a haystack and the ten rows that matter.

Tracing fixes found while reading the live log:

* PUT /pipelines/<uuid>/extensions was classified as a plugin config change
  because the generic ('/extensions') rule ran first; it now maps to a
  pipeline-specific action;
* that handler recorded no diff at all, so "modified extension config" could
  never say what changed. It now captures the previous bindings and reports the
  before → after.

Cache: the integrity result is now keyed by (Workspace, listing filters) so
each view reuses its own verification, and a delete invalidates all views for
the Workspace. Fourteen tests cover the projection, the verifier, the cache
lifecycle and the failure modes.
2026-09-28 01:03:02 +08:00
TyperBody ed93e7f1ac perf(operation-trace): project hash columns and make the integrity cache safe
The integrity scan selected whole rows, so a cold pass paged in the
changes/detail payloads and the client fingerprint for up to
MAX_INTEGRITY_SCAN_ROWS rows the verifier never reads. Project only the hash
columns, and add a lightweight verifier so the scan no longer builds a full
display dict per row.

Repair the read cache so it is a latency shield, not a correctness shortcut:
a result computed within INTEGRITY_CACHE_TTL_SECONDS is served from the
per-Workspace cache (opening, refreshing and paging all land inside that
window and pay nothing), while a cache miss re-verifies the whole window. An
incremental scan that skips previously verified ids can never see an edit to
an already-cached row -- exactly the tampering this feature exists to expose.
Verified against a live 414-row log: 50 content edits and 7 re-signed links
are all detected, including an edit to a row verified on a previous pass.

Also fix two correctness gaps and one maintenance bug:
- age-based prune deleted rows without invalidating the cached prefix;
- the boundary baseline is now read only when the history exceeds the scan
  window, which a bounded scan makes the rare case;
- the operation-log retention block had drifted outside the per-binding loop
  in the maintenance task, so only the last discovered Workspace was ever
  pruned while the others grew unbounded.

Tests: scan projection, verifier parity, TTL cache reuse, cache-miss
re-verification, edit to an already-verified row, hash mismatch, chain break
and prune invalidation.
2026-09-27 23:43:51 +08:00
TyperBody 7e8daa1c14 perf(operation-trace): cache and incrementally verify the integrity scan
Reading the panel re-hashed up to MAX_INTEGRITY_SCAN_ROWS (20000) rows on
every open, refresh and page turn -- measured ~280ms for 385 rows, growing
linearly with history -- which is what made the log feel slow. The chain is
append-only, so a verified prefix stays valid: keep a per-Workspace cache and,
once warm, verify only the rows appended since (bounded window), reusing the
prior result across reads. Deletions (prune / row budget) invalidate it.

Also fix the cache-hit path (it referenced a field that was never stored) and
the "scanned" count (it double-counted reused rows).

Measured on 385 rows: cold ~280ms -> warm ~0.7ms -> incremental ~15ms.
2026-09-27 23:00:56 +08:00
huanghuoguoguo 4f00878a83 Merge pull request #2601 from langbot-app/feat/cli-core-integrated
feat(api): support CLI diagnostics and Pipeline runs
2026-09-27 18:04:12 +08:00
huanghuoguoguo 4f95016998 test(api): align CLI diagnostics with integration gates 2026-09-27 17:46:19 +08:00
huanghuoguoguo 07f3283abf feat(api): enable CLI diagnostics on current master 2026-09-27 17:31:06 +08:00
RockChinQ ac366193bc Merge pull request #2600 from langbot-app/fix/pin-sdk-0.6.20
chore(plugin): pin SDK 0.6.20
2026-09-27 17:08:39 +08:00
RockChinQ 3b94b7e4cc chore(plugin): pin SDK 0.6.20 2026-09-27 09:00:36 +00:00
RockChinQ 10bd175944 Merge pull request #2599 from langbot-app/fix/pin-sdk-0.6.19
chore(plugin): pin SDK 0.6.19
2026-09-27 15:50:14 +08:00
RockChinQ 0b78617b82 chore(plugin): pin SDK 0.6.19 2026-09-27 07:42:02 +00:00
RockChinQ d7ccb71dab Merge pull request #2598 from langbot-app/fix/pin-sdk-0.6.18
chore(plugin): pin SDK 0.6.18
2026-09-27 14:44:57 +08:00
RockChinQ cbc8ef2324 chore(plugin): pin SDK 0.6.18 2026-09-27 06:36:21 +00:00
RockChinQ 58c1b8ee4f Merge pull request #2597 from langbot-app/fix/pin-sdk-0.6.17
chore(plugin): pin SDK 0.6.17
2026-09-27 13:48:23 +08:00
RockChinQ b06083d9b6 chore(plugin): pin SDK 0.6.17 2026-09-27 05:36:56 +00:00
RockChinQ 30e7d9409e Merge pull request #2596 from langbot-app/dev/shared-worker-local-e2e
chore(plugin): pin SDK 0.6.16
2026-09-27 12:53:21 +08:00
RockChinQ c7306dc8b2 chore(plugin): pin SDK 0.6.16 2026-09-27 04:38:11 +00:00
RockChinQ 16d3ac58b8 Merge pull request #2595 from langbot-app/fix/pin-sdk-0.6.15
fix(plugin): pin SDK 0.6.15
2026-09-27 11:07:49 +08:00
RockChinQ 6da0aea901 fix(plugin): pin SDK 0.6.15 2026-09-27 02:59:40 +00:00
huanghuoguoguo 6a1cc49c54 docs(agent): document standalone LangBot CLI (#2571) 2026-09-27 10:27:48 +08:00
RockChinQ 718fa771e4 Merge pull request #2594 from langbot-app/fix/shared-install-readiness-final
fix(plugin): bound shared install readiness
2026-09-27 09:03:26 +08:00
RockChinQ d1a0ae9b26 fix(plugin): bound shared install readiness 2026-09-27 00:55:58 +00:00
RockChinQ e77f66d22c Merge pull request #2593 from langbot-app/fix/pin-sdk-0.6.14
fix(plugin): pin SDK 0.6.14 and bound shared readiness
2026-09-27 08:25:38 +08:00
RockChinQ 765dac74ea fix(plugin): pin SDK 0.6.14 and bound shared readiness 2026-09-27 00:11:57 +00:00
RockChinQ bd8eaf3123 Merge pull request #2591 from langbot-app/fix/pin-sdk-0.6.13
chore(runtime): pin plugin SDK 0.6.13
2026-09-27 05:38:07 +08:00
RockChinQ 3d6a203724 chore(runtime): pin plugin SDK 0.6.13 2026-09-26 21:28:52 +00:00
RockChinQ a0cab74ea7 Merge pull request #2590 from langbot-app/fix/pin-sdk-0.6.12
chore(runtime): pin plugin SDK 0.6.12
2026-09-27 04:50:46 +08:00
RockChinQ e63fcb36e4 chore(runtime): pin plugin SDK 0.6.12 2026-09-26 20:42:15 +00:00
TyperBody 1488dd3924 chore(operation-trace): rebase migration onto master head, drop unused import
The pull request merge produced two Alembic heads: this branch's
0032_operation_traceability and master's 0032_cert_artifact_digest both
descended from 0031_merge_totp_assistant, so the integration and migration
jobs failed with "Multiple head revisions". Renumber the traceability
migration to 0033 and point it at master's head (0032_cert_artifact_digest),
restoring a single linear head.

Also replace the noqa'd unused import of the traceability routes with an
importlib bootstrap (addresses the CodeQL unused-import finding) and merge
origin/master to pick up the certification digest backfill.
2026-09-27 02:50:28 +08:00
TyperBody 7eac330f33 Merge remote-tracking branch 'origin/master' into feat/workspace-operation-traceability 2026-09-27 02:46:00 +08:00
TyperBody a8daa99884 fix(operation-trace): repair pageOf key placement, numbered pager, right column
- pageOf was inserted under the wrong namespace (the locale files already had a
  hideDetails in toolCalls), so the UI rendered the raw key. Removed it and
  replaced the dropdown with a numbered pager (first/last always visible, a
  one-page window around the current page, gaps as an ellipsis).
- Restore the right-hand column (duration + record hash) that the previous
  declutter removed; the digest is still opt-in, but the hash stays visible.
- Hide the status code on success: a 200 is the default, so only >=400 shows.
2026-09-27 02:39:09 +08:00
TyperBody 67bc80e3bc feat(operation-trace): declutter the log list and add page navigation
The list was noisy and hard to read: a constant "verified" badge and the
"L1/L2" level badge on every row carried no information, the same "view X"
line repeated until it buried real changes, and each row rendered its full
payload diff inline.

- Drop the per-row level badge and the "verified" badge; keep only an
  exception badge, so a healthy row shows nothing extra.
- Collapse consecutive identical rows into one line with an "xN" count.
- Make the change digest opt-in per row (one expanded at a time) and show a
  "<n> changes" toggle instead of dumping the diff.
- Show the registered route under each row so "Resource / System" is no
  longer ambiguous about what actually happened.
- Replace the arrows-only pager with a page selector ("Page x / y") plus the
  arrows, for logs with hundreds of records.

Verified: tsc, eslint, prettier and check-i18n all pass.
2026-09-27 02:32:12 +08:00
RockChinQ 7c282964c8 Merge pull request #2589 from langbot-app/fix/pin-sdk-0.6.11
chore(runtime): pin plugin SDK 0.6.11
2026-09-27 02:29:52 +08:00
RockChinQ 755149ab0a chore(runtime): pin plugin SDK 0.6.11 2026-09-26 18:16:39 +00:00
TyperBody 884beea4b6 perf(operation-trace): move all trace persistence off the request path
Tracing ran inline with the request: every traced call did several database
round trips (dedupe probe, actor-name lookup, newest-hash read) and a
serialized insert. With tracing on, the WebUI's burst of parallel requests
(login alone touches a dozen endpoints) saturated the write path and stalled
the whole service.

Now the request path only builds a bounded dict and pushes it onto a queue
(measured ~0.005ms per trace, zero database work). A single background writer
coroutine drains the queue and persists sequentially, which also removes the
read-newest-hash race that used to produce false "chain broken" reports; the
previous asyncio lock is gone. The actor display-name lookup and the dedupe
key hash move into the writer as well. The queue is bounded: when traffic
outruns the writer the oldest pending trace is dropped instead of slowing the
request down.

Verified: migration tests pass, ruff clean, a focused writer test shows
enqueue is non-blocking, rows link with zero chain breaks and no internal
key leaks into the stored row.
2026-09-27 02:16:26 +08:00
RockChinQ 8a55781f02 Merge pull request #2588 from langbot-app/fix/pin-sdk-0.6.10
chore(runtime): pin plugin SDK 0.6.10
2026-09-27 01:23:02 +08:00