Commit Graph
4294 Commits
Author SHA1 Message Date
RockChinQ 3493660f5e chore(runtime): pin plugin SDK 0.6.10 2026-09-26 17:08:51 +00:00
TyperBody a4f89cf28f fix(operation-trace): stop false tamper reports and sharpen resource classification
- Chain integrity: the "read newest hash, then insert" pair in record() could be
  interleaved by concurrent traces (the panel opens a dozen parallel GETs), so two
  rows linked to the same predecessor and one looked like a broken chain even
  though nobody edited anything. Serialize the pair with a per-service lock.
- Resource classification: generic verbs fell back to resource_type='resource', so
  almost every read showed up as "View resource / Resource" (pipelines, bots,
  providers, users, monitoring...). Derive the family from the registered route
  identity (pipeline, bot, model_provider, llm_model, monitoring, user, workspace,
  webhook, api_key, system).
- Frontend: render the resource family for the new types (8 locales) and keep the
  resource_id badge added earlier.

Verified: backend integration 358 passed, ruff check/format clean; frontend tsc,
eslint, prettier and check-i18n all pass.
2026-09-27 00:45:55 +08:00
TyperBody 9964f284e1 refactor(operation-trace): isolate subsystem, fix install identity, merge migrations
- Move the operation-traceability service and its HTTP routes into a standalone
  pkg/operation_trace package; the Core controller package no longer depends on it
  (routes stay auto-discovered by the controller package scan).
- Gate the hot path on one module-level boolean exposed as ap.operation_trace_active:
  while no Workspace has tracing enabled the route wrapper performs zero trace work
  and zero database round trips. The gate opens when a Workspace enables tracing and
  is primed once at startup for already-enabled Workspaces.
- Record the installed extension identity for GitHub / marketplace / local / upload
  installs (owner/repo, author/name, filename) so the trace no longer shows a
  nameless "a plugin was installed" event and the card names the extension.
- Merge migrations 0032 + 0033 into a single 0032_operation_traceability revision
  carrying the full table shape and an index set that matches the ORM.

Tests: unit 5165 passed / integration 358 passed; ruff check + format clean.
2026-09-27 00:11:57 +08:00
RockChinQ 5e21d02ce4 Merge pull request #2587 from langbot-app/fix/pin-sdk-0.6.9
chore(runtime): pin plugin SDK 0.6.9
2026-09-26 22:46:54 +08:00
RockChinQ 64dc04d848 chore(runtime): pin plugin SDK 0.6.9 2026-09-26 14:33:35 +00:00
RockChinQ 81c38be0af Merge pull request #2586 from langbot-app/fix/pin-sdk-0.6.8
chore(runtime): pin plugin SDK 0.6.8
2026-09-26 21:11:34 +08:00
RockChinQ ccbf7c226e chore(runtime): pin plugin SDK 0.6.8 2026-09-26 13:02:43 +00:00
RockChinQ 2356086550 Merge pull request #2585 from langbot-app/fix/pin-sdk-0.6.7
fix(plugin): pin runtime SDK 0.6.7
2026-09-26 14:26:42 +08:00
RockChinQ 92669ef584 fix(plugin): pin runtime SDK 0.6.7 2026-09-26 06:19:15 +00:00
RockChinQ aad78767cd Merge pull request #2584 from langbot-app/fix/pin-sdk-0.6.6
fix(plugin): pin runtime SDK 0.6.6
2026-09-26 13:29:25 +08:00
RockChinQ 37e80e510f fix(plugin): pin runtime SDK 0.6.6 2026-09-26 05:21:50 +00:00
RockChinQ f34814270c Merge pull request #2583 from langbot-app/fix/pin-sdk-0.6.5
fix(plugin): pin runtime SDK 0.6.5
2026-09-26 12:36:55 +08:00
RockChinQ 9690f0bc6c fix(plugin): pin runtime SDK 0.6.5 2026-09-26 04:29:05 +00:00
RockChinQ dd88a54118 Merge pull request #2581 from langbot-app/fix/pin-sdk-0.6.4
fix(plugin): pin runtime SDK 0.6.4
2026-09-26 10:10:07 +08:00
RockChinQ ede433f0b1 fix(plugin): pin runtime SDK 0.6.4 2026-09-25 22:34:08 +00:00
RockChinQ 19634d3f54 Merge pull request #2580 from langbot-app/fix/certification-artifact-digest-backfill
fix(plugin): backfill certified artifact digest
2026-09-26 05:23:05 +08:00
RockChinQ a5e5ee5fb8 fix(plugin): backfill certified artifact digest 2026-09-25 21:03:47 +00:00
TyperBody becb6c78b4 fix(operation-trace): satisfy ruff/codeql and drop a dead summary channel
- Remove the unused request_summary local: the stored summary is derived by the
  service from changes + the classified action, so handlers publishing
  quart.g.operation_log_summary was a dead channel that never reached the row.
- Drop the unused datetime import in the operation log model.
- Apply ruff format to the touched files so `ruff format --check` passes.
2026-09-26 03:51:36 +08:00
TyperBody 475420956c feat(operation-trace): record which resource was touched and what changed
Granularity follow-up: a record used to say only "installed an extension".

- Add resolve_resource_identity(): derive the acted-on resource from trusted route
  params or the install-style payload (plugin_author/plugin_name), so every
  resource family names its target. Unknown keys are ignored and sensitive keys
  are skipped, keeping the audit trail bounded and secret-free.
- The route wrapper applies it to every traced request; the identity only fills
  in when a handler did not publish a more precise one.
- Publish field-level before/after diffs for plugin config, skill, knowledge
  base, MCP server, pipeline, provider and model updates, reusing
  changed_fields()/build_summary() so secret-looking keys stay redacted and a
  masked round-trip never shows up as a phantom change.
2026-09-26 03:46:20 +08:00
TyperBody 6981b6643f feat(operation-trace): workspace-wide integrity counters, drill-down and resource identity
- Count hash mismatches / broken links over the whole filtered history instead
  of only the returned page, so the badges no longer reset to zero on page 2.
- Classify failing record ids during the same scan and expose them through an
  integrity=all|issues|hash_mismatch|chain_broken listing filter.
- Report scanned_count / scan_truncated so an approximate (row-capped) summary
  is never mistaken for a clean one.
- Resolve the acted-on resource identity from route params or the request body,
  giving every resource family a "which plugin/skill/knowledge base" trace.
- Render resource types and the two counters through i18n, keeping all eight
  locale files key- and line-aligned.
2026-09-26 03:23:24 +08:00
RockChinQ 3dee5f5cf8 Merge pull request #2578 from langbot-app/feat/certified-cross-tenant-worker-pool
feat(plugin): route certified installs to shared workers
2026-09-26 03:17:25 +08:00
RockChinQ deca26a666 chore(plugin): pin SDK 0.6.3 2026-09-25 19:09:16 +00:00
TyperBody abca2e7bff fix(operation-trace): repair export URL, drop dead action, prune unused keys
- Export download failed because the URL builder appended the path to a
  "/" base, producing a protocol-relative "//api/..." URL that the browser
  read as host "api"; the request never reached the backend. Resolve the
  base to the current origin, mirroring the other URL builders.
- Remove the orphan ``clear_prune`` action: the branch has no prune/clear
  route and no route rule maps to it, so it could never be produced. Its
  i18n key is removed too.
- Remove ``tamperedCount``, now unreferenced after the verification badge
  was split into integrity/chain counters. The operationTrace catalogue is
  now free of unproduced keys.
- Correct the settings controller docstring: only governance, operation
  logs, filters and export routes exist; there is no on-demand delete.

Verified: no producer for clear_prune, classify() can no longer emit it,
operationTrace orphan scan returns none, tsc/check-i18n/prettier/py_compile
all pass.
2026-09-26 02:43:48 +08:00
TyperBody cf28b5694d fix(operation-trace): default tracing to off
Tracing is now opt-in: a Workspace records nothing until an owner or admin
explicitly turns it on, so auditing stays off the hot path by default.

View and configure remain limited to owners and admins: the audit.view
permission is granted to those roles only, non-owner/admin callers receive a
403 from the governance write route, and the panel already gates both on the
owner/admin membership role.
2026-09-26 02:33:45 +08:00
TyperBody a5ff69f024 fix(operation-trace): polish panel toolbar and record-header layout
- Group the toolbar actions into a single right-aligned cluster so
  "Download logs" and "Refresh" sit together instead of being spread apart
  by the toolbar's space-between layout.
- Align the record header's filter row with the rest of the panel: replace
  the ``ml-auto`` push (which left the filters misaligned once they wrapped
  onto a second line) with ``justify-between``.
2026-09-26 02:32:36 +08:00
TyperBody 48d92ad612 fix(operation-trace): correct capture scope, broaden coverage, polish panel
- Capture scope: treat the ``audit`` bucket (viewing the log / tracing
  settings) as a read-level observation instead of recording it from the
  mutation level. At "mutations only" the log no longer fills with GET page
  views; views are recorded only at the read level.
- Coverage: classify plugin lifecycle (install / upgrade / config / page),
  skills, knowledge bases and MCP servers, with dedicated actions and
  resource types, so those operations are traced instead of falling into the
  generic resource bucket. Route rules now support multi-fragment AND
  matching and per-verb read/write actions.
- Panel: move "Download logs" next to "Refresh" in the toolbar.
- Verification: count hash mismatches and broken links separately instead of
  collapsing both into one "tampered" signal.
- i18n: add the new action labels plus the split verification labels in all
  eight locales.
2026-09-26 02:26:48 +08:00
TyperBody 78baabde96 fix(operation-trace): speed up audit reads and align i18n locales
Performance of the operation traceability surface:

- Cache the retention / row-budget / dedupe policy per Workspace and
  invalidate it on governance change, so the hot write path no longer
  issues three metadata round trips per recorded operation.
- Resolve the governance payload with one metadata query instead of four.
- Turn the dedupe probe into an existence check (LIMIT 1) instead of a
  full COUNT over the dedupe window.
- Defer the row-budget COUNT to every N inserts; prune still enforces the
  exact budget, and the maintenance loop keeps it bounded.
- Panel: fetch only the records page when paging or filtering instead of
  re-requesting governance and the filter catalogue every time.
- Export: include the effective filters (and limit) in the artifact so a
  downloaded CSV is self-describing.

Fixes and cleanup:

- Drop the unused OperationLogPruneReport import that broke `tsc`.
- i18n: remove the 9 redundant blank lines unique to en-US and format the
  six non-compliant locale files with the project Prettier config; all
  eight locales keep identical key sets, key order and placeholders.
2026-09-26 02:11:42 +08:00
RockChinQ f488087cc4 Merge remote-tracking branch 'origin/master' into feat/certified-cross-tenant-worker-pool 2026-09-25 13:33:22 +00:00
RockChinQ 300f5825bb fix(plugin): fail closed on incomplete certification records 2026-09-25 13:13:35 +00:00
Type_rBody 840214da23 Merge pull request #2577 from langbot-app/fix/certified-plugin-oss-force-install
fix(plugin): keep certified marketplace packages installable on OSS
2026-09-25 20:51:36 +08:00
RockChinQ 9f296bd57e feat(plugin): route certified installs to shared workers 2026-09-25 12:48:55 +00:00
TyperBody 4b9a1590df style(plugin): apply ruff formatting to certification.py 2026-09-25 20:37:57 +08:00
TyperBody c76fd2d7c5 fix(migration): treat an unselected runner id as not_legacy
A saved pipeline may carry the post-migration shape
{'ai': {'runner': {'id': ''}, 'runner_config': {}}} while no runner has been
selected yet. The planner matched the empty id against the certified
'plugin:author/name/component' form, failed, and returned a malformed-id
blocker, so the whole 'migrate all' batch stopped with both pipelines reported
as blocked even though there was no legacy section and nothing to convert.

A blank id with no legacy runner section now reports not_legacy: no work is
needed and no target is synthesized. A blank id that still coexists with a
legacy section remains an explicit invalid_runner_id blocker, because that
ambiguous state must be resolved by the operator rather than guessed.
2026-09-25 20:02:17 +08:00
TyperBody afe700f1d8 fix(plugin): keep certified marketplace packages installable on OSS
The certified-archive admission gate treated any declared certificate it could
not resolve as an untrusted archive and rejected the install with
CERTIFIED_PLUGIN_OSS_FORCE_REQUIRED. OSS ships an empty
plugin.certification.trusted_public_keys ring and the marketplace signs every
package with its own issuer key, so all certified marketplace packages (for
example langbot-team/RunnerDemo and langbot-team/LocalAgent) failed at the
'validating plugin package' step before artifact storage.

Admission now distinguishes an unresolvable declaration from a configured trust
decision that fails:

- record certificate_id only when the key_id is actually present in the
  configured ring, so an empty ring yields an unresolvable declaration;
- OSS degrades an unresolvable declaration to the existing oss_dev dedicated
  profile with CERTIFIED_PLUGIN_OSS_UNTRUSTED_DEDICATED instead of blocking;
- a resolvable declaration that still fails keeps requiring the explicit
  administrator force (CERTIFIED_PLUGIN_OSS_FORCE_REQUIRED);
- Cloud stays fail-closed and rejects before storage.

No shared-runtime privilege is granted when the issuer is not trusted, so this
withholds isolation rather than escalating it.
2026-09-25 19:32:54 +08:00
Type_rBody 9631eccaaf Merge pull request #2576 from langbot-app/fix/i18n-locale-sync
fix(web): align i18n locale keys and ordering with en-US
2026-09-25 18:33:27 +08:00
TyperBody 262980d612 fix(web): add missing common.next/previous pagination keys
The bot session monitor paging controls use `common.next` and
`common.previous`, but those keys never existed in any locale. They were
only rendered because of the hardcoded `defaultValue: 'Next'`/`'Previous'`.
Removing those fallbacks (previous commit) made i18next render the raw key
name, so the Playwright smoke tests could no longer find the "Next" button.

Add `common.previous` and `common.next` to all 8 locales (reusing each
language's existing `guidedTour.previous`/`next` wording) and re-align the
locale key order with the `en-US` reference.

Verified locally:
- scripts/check-i18n.mjs passes for all locales
- every t('...') key referenced by BotSessionMonitor.tsx now exists in en-US
- tests/e2e/bot-session-tool-timeline.spec.ts: 13/13 passed (including the
  two request-recovery cases that failed in CI)
- prettier / tsc / eslint clean
2026-09-25 18:07:11 +08:00
TyperBody f17b148b1a fix(web): align i18n locale keys and ordering with en-US
The bot session monitor referenced several translation keys that did not
exist in any locale file. Because i18next `fallbackLng` is `zh-Hans`, the
missing keys fell back to the hardcoded English `defaultValue`, leaking
untranslated strings (e.g. "0 sessions", "User ID or name", "Search") into
every non-English UI.

- Add the missing keys to all 8 locales with proper translations:
  `common.search`, `bots.sessionMonitor.{totalSessions,userSearch,startDate,endDate}`
  and `monitoring.toolCalls.{showDetails,hideDetails}`.
- Remove the hardcoded `defaultValue` fallbacks in `BotSessionMonitor.tsx`
  so translations are always driven by the locale files.
- Reorder nested keys in every locale file to match the `en-US.ts` reference
  order, keeping values untouched. This removes all structural drift between
  locale files (previously `guidedTour.*`, `plugins.*`, etc. were ordered
  differently).

Verified: `scripts/check-i18n.mjs` reports matching keys for all locales,
every key/value pair is preserved, Prettier passes, and `tsc --noEmit` is clean.
2026-09-25 17:05:02 +08:00
Type_rBody 043b1a2ee7 Merge pull request #2565 from langbot-app/feat/totp-two-factor-auth
feat(auth): add TOTP two-factor authentication
2026-09-25 16:18:10 +08:00
TyperBody 7543340f39 fix(web): stabilize invitation error assertions
The invitation error copy also renders as a transient sonner toast, so the
plain text locator resolved to two elements and tripped Playwright strict
mode while the toast was on screen.

Tag the inline error region with data-testid="invitation-error" and assert
against it, keeping the check deterministic under CI parallelism.
2026-09-25 15:19:34 +08:00
TyperBody 97c1addba7 Merge remote-tracking branch 'origin/master' into feat/totp-two-factor-auth
# Conflicts:
#	uv.lock
2026-09-25 14:31:03 +08:00
Type_rBody 5435b3bbfc Merge pull request #2575 from langbot-app/fix/assistant-i18n-locales
fix(web): add the assistant namespace to remaining locales
2026-09-25 14:20:03 +08:00
TyperBody 85da438d21 fix(web): add the assistant namespace to remaining locales
The workspace assistant added 39 keys under `assistant.*` to en-US,
zh-Hans and ja-JP, but es-ES, ru-RU, th-TH, vi-VN and zh-Hant were never
updated. The i18n key consistency check fails on all five, blocking the
release PR.

Add the full assistant namespace with translated copy so every locale
matches the en-US reference. No source changes; keys and placeholders
(`{{count}}`) mirror en-US exactly.
2026-09-25 14:07:50 +08:00
Type_rBody f09c8a8bed Merge pull request #2549 from langbot-app/experiment/in-process-assistant
feat(web): add an in-process workspace assistant
2026-09-25 13:56:30 +08:00
RockChinQ edd3369582 Merge pull request #2573 from langbot-app/fix/migration-certified-runner-versions
fix(migration): pin certified runner packages
2026-09-25 13:50:57 +08:00
RockChinQ eb9261fae1 fix(migration): pin certified runner packages 2026-09-25 05:42:34 +00:00
TyperBody 03f50d1afc style(web): apply prettier formatting and drop an unused import
Run prettier over the assistant files and the new dock unit test so the
web lint job passes, and remove the unused ASSISTANT_BUTTON_SIZE import
flagged by code quality review.
2026-09-25 13:38:23 +08:00
TyperBody 6283d21311 fix(web): scroll assistant to newest turn and settle the rail on release
Opening the panel left the user at the oldest message because the scroll
effect did not depend on `open`. Add it and defer the scroll to the next
frame so the popover has laid out before the sentinel is measured.

A click or an aborted swipe never arms the long press, so no drop handler
ran and a hover-expanded button stayed expanded after the pointer left.
Track real pointer presence and re-sync the rail on release.
2026-09-25 13:32:29 +08:00
TyperBody e6e1958fc5 fix(web): let the docked assistant button collapse again
`shouldCollapseRail` was keyed on `!railExpanded`, mirroring the expand
helper instead of negating it. Once a hover revealed the button it could
never collapse back into the rail, so the collapse looked broken after the
first restore.

Key the predicate on `railExpanded` being true, restore the mirror
relationship with `shouldExpandRail`, and add regression coverage for the
expand -> leave -> collapse round trip. Also lengthen the rail strip.
2026-09-25 13:22:18 +08:00
TyperBody 88257fe0e2 Merge origin/master into experiment/in-process-assistant
Resolve conflicts in the workspace assistant integration:

- DynamicFormItemComponent: keep HEAD's compact model selector and
  `disabled` field support while adopting master's `sortModelsByCatalog`
  ordering and `MODEL_SELECT_TRIGGER_CLASS`.
- i18n (en-US, ja-JP, zh-Hans): keep both the `assistant` namespace from
  HEAD and master's `sidebarGuide` / `pipelineMigration` additions.

Add 0030_merge_assistant to join the assistant conversations branch with
the released chain so the migration graph converges on a single head.
Rename it from 0030_merge_assistant_conversations to stay within the 32
character revision limit enforced by test_migrations.

Also add assistant button docking (long-press drag, edge collapse to a
short blue rail, hover restore) with pure helpers in assistant-dock.ts
and unit coverage, plus auto-collapse for finished tool result cards.
2026-09-25 13:17:44 +08:00
TyperBody f316958619 Merge remote-tracking branch 'origin/master' into experiment/in-process-assistant 2026-09-25 12:46:34 +08:00