Commit Graph

3600 Commits

Author SHA1 Message Date
Junyan Qin
ec2d21fe63 feat(box): add box.enabled toggle and gate consumers on availability
Make the Box sandbox runtime optional. When ``box.enabled`` is false in
config (or when an enabled Box fails to connect), every dependent feature
degrades to the same disabled-state UX rather than crashing or silently
falling back to less safe code paths.

Backend:

- config.yaml: new top-level ``box.enabled: true`` flag (default true)
- BoxService:
  - Read box.enabled on construction
  - initialize() short-circuits when disabled — no remote WS connect, no
    stdio subprocess fork
  - _on_runtime_disconnect is a no-op when disabled (no reconnect loop
    on a deliberately-off service)
  - get_status() now exposes ``enabled`` so the frontend can tell
    "disabled in config" from "configured but failed"
- MCP stdio loader (mcp_stdio.uses_box_stdio): requires box_service to
  be available, not just installed
- MCP _init_stdio_python_server: when ap.box_service exists but is
  unavailable, refuse the stdio server with an actionable error instead
  of silently falling through to host-stdio (which bypasses the sandbox
  the operator asked for). Setups without ap.box_service installed at
  all keep the legacy host-stdio fallback for pre-Box dev mode
- SkillService._require_box_for_write: refuses create/update/install/
  write_skill_file when ap.box_service is installed but unavailable.
  Distinguishes disabled vs failed in the error message so the UI can
  surface the right hint. Legacy setups (no ap.box_service) keep the
  local fallback path — that distinction is what keeps the existing
  local-skills tests valid

Tests:
- Box disabled-state behavior (4 cases)
- Skill write refusal in disabled & failed states (7 cases)
- MCP stdio runtime info policy updated to match new refuse-when-down
  behavior

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:07:53 +08:00
Junyan Qin
99328cf4c0 fix(skill): harden mount/reload paths and HTTP errors against stale skill cache
The Box backends behave inconsistently when extra_mounts reference a
missing host directory (nsjail aborts the entire sandbox start, Docker
silently creates a root-owned empty dir on the host, E2B silently skips
the upload). The cache in skill_mgr.skills is only refreshed on
in-process mutations, so out-of-band changes — container rebuilds,
manual rm in the box volume, anything the LangBot API didn't drive —
leave a stale skill that later produces one of those bad mount paths.

- box/service.py: build_skill_extra_mounts now filters skills whose
  package_root is not isdir on the LangBot-visible filesystem and logs
  a warning, instead of passing the bad mount through to the backend
- skill/manager.py: reload_skills (Box path) drops skills whose
  package_root is missing on the LangBot-side filesystem before they
  reach the in-memory cache, with a summary warning
- api/http/controller/groups/skills.py: file/CRUD handlers now also
  catch BoxError (RuntimeError subclass, previously slipping past
  ``except ValueError`` and surfacing as 500); list/get handlers gain
  a try/except so a transient Box RPC failure becomes a clean 400
  instead of a stack trace

Tests added for build_skill_extra_mounts (skip missing, skip empty,
no skill manager) and SkillManager.reload_skills (drop missing on Box
path). Full unit suite: 279 passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:50:46 +08:00
Junyan Qin
28c00cb8d1 ci(tests): run unit tests on every push to feat/** branches
- Add feat/** to push branches so long-lived feature branches are
  tested on every push (they accumulate large changes before a PR)
- Drop the push path filter entirely: every push to master/develop/
  feat/** now runs the full unit suite (the old 'pkg/**' filter never
  matched the real source path 'src/langbot/pkg/**', so backend-only
  pushes silently skipped tests)
- Fix the same broken path glob on the pull_request trigger
  ('pkg/**' -> 'src/langbot/pkg/**')

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 23:56:17 +08:00
Junyan Qin
18ad51e21e test: repair stale skill/sandbox tests for feat/sandbox
The skill subsystem moved to Tool-Call activation and a Box-managed
skill store; several tests still asserted removed APIs and a sys.modules
stub leaked across the suite. Full unit suite now green (was 23 failing).

- test_skill_tools: drop TestSkillManagerActivation (text-marker API
  removed); rewrite TestSkillActivationHelper around the current
  skill.activation.register_activated_skill; replace the CRUD
  TestSkillAuthoringToolLoader with TestSkillToolLoader covering the
  current activate/register_skill tools and sandbox-availability gating
- test_tool_manager_native: ToolManager attr is skill_tool_loader (not
  skill_authoring_tool_loader); native loader now exposes 6 tools
  (exec/read/write/edit/glob/grep) and requires initialize() with a
  backend-available get_status()
- test_localagent_sandbox_exec: remove obsolete activation-marker
  leakage tests and their helper providers
- test_model_service / pipeline conftest: give the mocks skill_mgr=None
  so PreProcessor's local-agent skill-binding guard short-circuits
- test_n8nsvapi: stop permanently overwriting sys.modules
  ('langbot.pkg.provider.runner' etc.); save and restore around the
  import so other modules get the real LocalAgentRunner base class

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 22:56:25 +08:00
Junyan Qin
5773e8aa27 refactor(box): use unified env-override mechanism for box.local config
The box module hand-rolled its own LANGBOT_BOX_LOCAL_* env parsing in two
places (connector._get_box_config and service._local_config), duplicating
logic that LoadConfigStage._apply_env_overrides_to_config already provides
generically via the SECTION__SUBSECTION__KEY convention.

- Drop the bespoke LANGBOT_BOX_LOCAL_* parsing; read box.local straight
  from instance_config (the unified BOX__LOCAL__* overrides are already
  applied before BoxService initializes)
- Harden _load_allowed_mount_roots to accept a comma-separated string,
  since the generic mechanism stores a freshly-created key as a raw
  string when config.yaml has no box.local.allowed_mount_roots entry
- docker-compose: rename the langbot container env vars to
  BOX__LOCAL__* (the canonical convention); remove them entirely from
  the langbot_box container — the Box runtime never reads box.local from
  env/config.yaml, it is configured via the INIT RPC action

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 22:38:17 +08:00
Junyan Qin
6351730891 docs(review): refresh box architecture review for feat/sandbox
Sync the docs/review/ suite to the current state of the feat/sandbox branch
(both LangBot and langbot-plugin-sdk), ~30 commits ahead of the prior review.

- box-architecture.md: rewrite for the new box.{backend,runtime,local,e2b}
  config schema, add E2B backend, 6 native tools (incl. glob/grep), Skill
  Tool Call activation, shared multi-process MCP container, SkillManager,
  BoxSkillStore (SDK), 25 actions, 9 error types, heartbeat/reconnect
- box-issues.md: move resolved items (reconnect, heartbeat, Windows, nsjail
  image conflict, frontend monitoring card) into a Resolved section; add
  new P0 (INIT/backend ordering), P1 (extra_mounts immutability after
  container creation), P2 (skill_store test gap, integration tests not in CI)
- box-session-scope.md: add §0 Implementation Status — Phase 1 shipped,
  MCP unification landed earlier than originally scoped
- box-test-coverage.md: realign file inventory (4,400 -> 6,500 LOC),
  add 7 new test files including SDK backend_selection/e2b/skill_store
- box-tob-analysis.md: connection recovery now满足基本要求; add E2B and
  backend self-heal to capabilities; tick off Phase 1 reconnect/heartbeat
- box-vs-plugin-runtime.md: heartbeat/reconnect/Windows support now aligned
  with Plugin Runtime; revise remaining gaps (WS auth, shared base class)
2026-05-19 13:31:26 +08:00
Junyan Qin
d80972417e fix(web): improve backend retry and sidebar scrolling 2026-05-19 11:40:20 +08:00
Junyan Qin
257d9d3a65 fix(mcp): stabilize shared box managed processes 2026-05-19 00:45:35 +08:00
Junyan Qin
747ea069aa feat: polish extension import flow 2026-05-18 23:32:56 +08:00
Junyan Qin
9e62227104 feat(web): improve skill import flow 2026-05-18 18:33:39 +08:00
Junyan Qin
971cc3f675 feat: install market extensions from card click 2026-05-18 17:41:43 +08:00
Junyan Qin
651904a5d4 fix: import github skill directories 2026-05-18 17:26:35 +08:00
Junyan Qin
bf8b51569f feat: support github skill installation 2026-05-17 23:09:10 +08:00
Junyan Qin
e814f359cb feat: manage skills through box runtime 2026-05-16 17:14:58 +08:00
Junyan Qin
c1f5ba1927 fix: align add extension marketplace ui 2026-05-15 18:55:25 +08:00
Junyan Qin
e8c7147d34 fix: refine extension ui and backend errors 2026-05-15 15:16:26 +08:00
Junyan Qin
98a106d3b5 feat: persist sidebar list expansion 2026-05-15 14:51:08 +08:00
Junyan Qin
ae11bce8b6 feat: polish extension detail pages 2026-05-15 14:41:23 +08:00
huanghuoguoguo
d5ce3b302e refactor: remove unused imports and clean up code in various files 2026-05-14 09:15:18 +08:00
huanghuoguoguo
656dafb07a feat(toolmgr): enhance tool initialization with backend availability checks 2026-05-14 09:01:20 +08:00
huanghuoguoguo
fd03b202a8 fix(native): update tool descriptions to use register_skill
Replace references to removed import_skill_from_directory with
register_skill in exec/write/edit tool descriptions.
2026-05-13 22:50:21 +08:00
huanghuoguoguo
d786b3475f fix(toolmgr): correct skill_tool_loader attribute name
Rename skill_authoring_tool_loader to skill_tool_loader in execute_func_call
and shutdown methods to match the attribute defined in initialize().

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 22:15:06 +08:00
huanghuoguoguo
17ae6950aa fix(skill): improve file browsing and fix path handling
- Fix nested directory display in skill file tree (preserve root entries)
- Fix file content display when clicking files in skill browser
- Add skill manager and tool manager as proper package modules
- Separate fileContent state to allow editing non-SKILL.md files

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 22:08:58 +08:00
huanghuoguoguo
b9e8827c7f fix(skill): copy builtin skills to data/skills on startup
- Builtin skills (templates/skills/) are now copied to data/skills/
- Users can view and manage builtin skills in the UI
- Rename SkillAuthoringToolLoader to SkillToolLoader

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 21:45:37 +08:00
huanghuoguoguo
77a85c5c23 feat(skill): add skill file browsing capability
- Add API endpoints for listing/reading/writing skill files
- Add FileTree component in SkillForm for directory browsing
- Users can now view scripts/, references/, assets/ directories
- Files can be selected and edited in the instructions textarea
- Add translations for new file browsing features

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 21:26:03 +08:00
huanghuoguoguo
892556da2a feat(tools): add glob and grep native sandbox tools
Add file discovery and content search capabilities to the sandbox:
- glob: Find files by pattern (supports ** recursive matching)
- grep: Search file contents with regex patterns

Both tools respect skill package paths and include safety limits
(max 100 files for glob, max 200 matches for grep).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-13 21:18:12 +08:00
huanghuoguoguo
7145447bcb feat(skill): align skill system with Claude Code's Tool Call design
- Replace text marker activation with `activate` tool (Tool Call mechanism)
- Replace 7 authoring tools with 2: `activate` + `register_skill`
- Add builtin skills loading from templates/skills/
- Add create-skill as first builtin skill
- Remove SKILL_ACTIVATION_MARKER and text detection methods
- Tool Result returns SKILL.md content (protects KV Cache)

This aligns with Claude Code's progressive disclosure pattern:
- Metadata (name+description) always visible in tool description
- SKILL.md body loaded on activate via Tool Call
- Bundled resources accessible through virtual path mapping

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 21:15:39 +08:00
Junyan Qin
4db0f20dc4 fix(skill): remove auto activation setting 2026-05-13 00:51:16 +08:00
Junyan Qin
a565f3e022 fix(box): harden sandbox session isolation 2026-05-13 00:20:07 +08:00
Junyan Qin
e4c674a9f0 fix(box): restore sandbox config and shared mcp runtime 2026-05-12 23:25:43 +08:00
Junyan Qin
afc37958c1 fix: preserve monitoring card borders under sticky filters 2026-05-12 18:30:19 +08:00
Junyan Qin
b73900718a fix: constrain home page content width 2026-05-12 18:23:51 +08:00
WangCham
3f7031b6f0 feat: delete version for mcp and skills 2026-05-12 11:28:43 +08:00
WangCham
3db2ddd2c7 feat: change ui 2026-05-11 22:38:39 +08:00
Junyan Qin
dd809d36f8 feat(extensions): mobile-friendly layout for extensions and add-extension pages
- Stack the extensions page header vertically on small screens, let the
  filter Tabs scroll horizontally if they overflow, hide the debug
  button label below sm and let the install/debug controls wrap.
- Constrain the debug popover and its inputs to the viewport width so
  they no longer overflow on phone-sized screens.
- Drop the card grid from a fixed 30rem column to a min(100%, 22rem)
  column at base / 28rem at sm, and reduce the gap, so cards render
  cleanly at 360px+ widths in both flat and grouped views.
- Make the add-extension header actions wrap on lg- viewports and the
  install dialog responsive instead of a hard 500px box.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 00:15:55 +08:00
Junyan Qin
6f97877a5a feat(sidebar): unify installed-extensions list with plugins, MCP and skills
- Render plugins, MCP servers and skills together under the "Installed
  Extensions" sidebar entry, alphabetically sorted to match the list page.
- Resolve per-item routes by extension type (plugin -> /home/extensions,
  mcp -> /home/mcp, skill -> /home/skills) and gate the plugin-only hover
  context menu on extensionType === 'plugin'.
- Lift the "group by type" toggle into SidebarDataContext (still persisted
  in localStorage) so the sidebar groups items with section headers
  whenever the list page has the toggle enabled.
- Show lucide fallback icons (Server / Sparkles / Puzzle) tinted in the
  LangBot blue for MCP, skill, and missing-icon plugin items, overriding
  the SidebarMenuSubButton svg color rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 00:10:04 +08:00
Junyan Qin
14c2da4d29 feat(extensions): fallback lucide icon when extension icon is missing
Render a tinted lucide icon (Puzzle / Server / Sparkles) on the extension
card when the icon URL is empty or the image fails to load. Picked icons
distinct from EventListener (AudioWaveform) and KnowledgeEngine (Book) to
avoid visual collision with plugin component badges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 23:57:24 +08:00
Junyan Qin
8ff60c5b98 feat(extensions): unify extensions endpoint and refresh extensions page UX
- Rename /home/plugins route to /home/extensions and update all sidebar links.
- Add unified GET /api/v1/extensions returning plugins, MCP servers and skills,
  sorted by name; replace the three separate frontend fetches with this single call.
- Migrate the extensions page to shadcn primitives (Tabs/Card/Alert/Badge/Skeleton/
  Switch/Label) and clean up hardcoded color tokens on the extension card.
- Add a localStorage-persisted "Group by type" switch that, when enabled in the
  All Types tab, renders extensions grouped by type with a compact section header.
- Show a spinner while loading and rename the empty-state copy from
  "No plugins installed" to "No extensions installed".
- Rename the "格式 / Formats" filter label to "类型 / Types" across all 8 locales.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 23:50:17 +08:00
Junyan Qin
46a9ed3da6 chore: rename extension zh translation 2026-05-09 23:04:02 +08:00
WangCham
f3d45eeeab feat: youhua qianduan 2026-05-09 16:47:23 +08:00
WangCham
fffc862fe6 feat: refactor market 2026-05-09 11:49:44 +08:00
WangCham
f306c762c8 feat: translate 2026-05-08 19:23:31 +08:00
Junyan Qin
ad9aa39281 fix: align box runtime launch args 2026-05-08 18:07:55 +08:00
WangCham
e412ed5527 feat: youhua frontend 2026-05-07 18:19:48 +08:00
WangCham
188511a911 feat: delete old filter 2026-05-07 13:34:26 +08:00
WangCham
58f9ff94d3 feat: successfully install 2026-05-07 13:19:02 +08:00
Junyan Qin
80911a3d91 Merge remote-tracking branch 'origin/master' into feat/sandbox
# Conflicts:
#	src/langbot/pkg/api/http/controller/groups/plugins.py
#	src/langbot/pkg/core/app.py
#	src/langbot/pkg/core/stages/build_app.py
#	src/langbot/templates/config.yaml
#	uv.lock
#	web/src/app/home/components/home-sidebar/HomeSidebar.tsx
#	web/src/app/home/components/home-sidebar/SidebarDataContext.tsx
#	web/src/app/home/layout.tsx
#	web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx
#	web/src/i18n/locales/en-US.ts
#	web/src/i18n/locales/es-ES.ts
#	web/src/i18n/locales/ja-JP.ts
#	web/src/i18n/locales/th-TH.ts
#	web/src/i18n/locales/vi-VN.ts
#	web/src/i18n/locales/zh-Hans.ts
#	web/src/i18n/locales/zh-Hant.ts
#	web/src/router.tsx
2026-05-05 14:05:53 +08:00
WangCham
f9347811b1 feat: add download button 2026-05-04 22:20:34 +08:00
Junyan Qin
db135f217f feat(web): add tooltips for truncated fields in system status dialog
Wrap session_id, image, and mount path fields with Tooltip components
so hovering over truncated text shows the full value.
2026-05-04 21:33:45 +08:00
Junyan Qin
fe9aed4ec9 fix(web): widen system status dialog and fix scroll border issue
Use max-w-2xl (matching other dialogs) instead of max-w-lg. Move
overflow-y-auto to an inner container with overflow-hidden on
DialogContent to prevent padding bleed at scroll edges.
2026-05-04 21:33:45 +08:00