30 Commits
Author SHA1 Message Date
Suroyandjubaoliang 83b2ae2e73 feat(auth): add LDAP directory login (#1123)
Let users sign in with their directory (Active Directory / OpenLDAP)
credentials through the existing login form. Reuses sso_providers
(kind='ldap') and user_sso_identities, so no schema change is needed.

Authentication is search-then-bind: a service account resolves the user and
only the returned DN is bound with the submitted password, so user input is
never used as a bind identity. Roles come from a role template at first
provisioning only; changing a directory group later never re-templates an
existing account. Directory outages and wrong passwords stay distinguishable
(502 LDAP_UNAVAILABLE vs 401 AUTH_FAILED).

Hardening from review:

- An account holding its own password stops at the local check, so a local
  secret is never forwarded to the directory nor counted against that
  directory's own lockout policy.
- A lookup without a unique exact identifier match is refused instead of
  being bound against the first hit.
- A failure during the user bind surfaces as LDAP_UNAVAILABLE rather than a
  401 credential verdict.
- Binds are throttled before they reach the directory, keyed per identifier
  and client address, with the address resolved from a trusted peer so a
  spoofed X-Forwarded-For cannot reset the budget.
- Enabling a plain ldap:// URL without StartTLS is rejected; a disabled
  certificate check is surfaced as a warning.
- auto_provision defaults to off, with an optional allowed_groups allow-list
  and a group-search mode (member / uniqueMember / memberUid) for directories
  that do not expose memberOf. Nested groups are not resolved.
- The identity key is configurable (entryUUID / objectGUID) and blank by
  default; a connectivity probe reports which attribute the directory
  exposes.
- Config changes are audited against the acting admin, and referrals are no
  longer followed during binds.

Tests cover the above without a live directory (ldap3.Connection is the only
thing replaced); a live test exercises a real directory when configured.

Co-authored-by: jubaoliang <jubaoliang@gmail.com>
2026-10-02 22:39:13 +08:00
Frank ZhangandCursor a8d42fd663 feat(ollama): allow configuring local model download directory (#1279)
* feat(ollama): allow configuring local model download directory

Users who move Ollama models off the default path could list custom models
but Octop treated them as not downloaded. Persist an OLLAMA_MODELS directory,
scan manifests for downloaded names, and pass the path when starting serve.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ollama): keep service running when saving models dir

Saving the download directory no longer sends enabled=false, so a running
Ollama daemon is not stopped. Disk-scanned models report size 0 so the UI
does not show the manifest file size as the model size.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 11:55:11 +08:00
HUANG Chengandjubaoliang bd73bb60aa fix(plugins): offload oversized octop_ui payloads to ToolMessage.artifact (#1032) (#1116)
Plugin tools returning large octop_ui payloads (e.g. a bangumi season
with 1200+ episodes, ~228KB JSON) blew up the LLM context because the
same tool-result string served both the model and the UI.

Add OctopUiOffloadMiddleware at the innermost agent middleware layer:
when a ToolMessage content is a >=4000-char string carrying a non-empty
octop_ui renderer and data (and no file:// media refs), the payload is
moved in-place to ToolMessage.artifact and the model-visible content is
replaced by a compact result that keeps title/summary. Tool id,
tool_call_id, name and status are preserved.

Frontend restores rendering from artifact: ToolCallData.artifact,
closeToolCall extraction, history replay path, and resolvePluginUiData
prefers explicit data over data_ref. serialize.py surfaces artifact on
tool_result blocks; history recorder backfills artifact as fallback.

Spec: docs/octop-ui-payload-offload.md

Co-authored-by: jubaoliang <jubaoliang@gmail.com>
2026-09-25 23:06:19 +08:00
347dee56f4 refactor(infra): group agents modules and clarify package ownership (#1164)
* refactor(agents): group thin modules into domain subpackages

Move plugin helpers, memory, settings stores, persona/MBTI, and avatar
bootstrap code under plugins/, memory/, settings/, persona/, and experts/
while keeping top-level import shims so existing call sites stay stable.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(agents): drop compatibility shims after subpackage move

Call sites already import the new package paths; remove the top-level
re-export stubs so the agents tree only shows real modules.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(agents): move thread helpers into threads/

Group artifact shaping, fork, and context breakdown under
agents/threads so top-level only keeps lifecycle/config adapters.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(agents): fold profile/runtime/tool catalog into settings/

Move the remaining config-surface helpers under settings/ and drop the
skill_package id-list aliases in favor of dump/parse_id_list.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(agents): group workspace_dir and execute_env under workspace/

Keep path resolution and harness execute-env injection together as one
workspace package; leave only manager and conversation_mode at top level.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(infra): fix history/SkillHub ownership and drop thin providers/

Move history_projection under history/, share SkillHub host/limits and
route expert skill downloads through skills.skillhub_market, and fold
Codex OAuth helpers into agents.providers to remove the tiny providers/
package.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: sync AGENTS.md and guides with infra/agents layout

Reflect subpackages (settings/workspace/threads/persona, history/, skills/)
and drop stale runtime.py / mbti_profiles paths after the agents reorg.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 22:32:41 +08:00
2209cdc90f chore(deps): switch runtime packages to octop-* 1.0.0 (#1136)
Replace orcakit-harness-agent / harness-* with octop-harness, octop-gateway, octop-memory, and octop-browser, and align docs, UI copy, and generated paths.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 06:44:24 +08:00
jubaoliangandCursor 69f31656c3 feat(chat): add per-thread HITL allow policy
Keep tool-approval bypass on the conversation (allow this tool / allow all)
without changing global security settings. Also let expert create carry
welcome quick prompts, and replace the login forgot-password tip with a
platform-specific CLI dialog.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 17:14:28 +08:00
薄生 e512f05bf5 Feature/memory slim tool (#865)
* harness agent upgrade for cache polish

* format

* feat(memory): add coordinated memory slim commands and progress UI

* build(deps): require harness-memory 0.9.11

* fix(deps): restore harness-memory 0.9.11 floor after merge

* fix(agents): await async shutdown to drain SQLite workers

Use HarnessAgentManager.aclose() during shutdown so SQLite cleanup
finishes before the event loop closes, preventing background threads
from raising "Event loop is closed".

Add a real SQLite regression test and preserve the existing ordering
that waits for memory slimming to finish before closing agents.

Validation: make all — 3582 passed, 17 skipped.
2026-09-21 15:44:19 +08:00
jubaoliangandCursor ae62ec3088 fix: LAN MCP HTTP、TLS 公网 IP 预检与 Models 侧栏抽屉
允许本机/局域网 MCP 使用 HTTP 并返回结构化错误码;TLS 预检优先走云元数据与国内可达 IP 探测;send_file 工具错误不再误判为模型故障;模型配置弹窗改为右侧抽屉。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 20:00:39 +08:00
24c00b0297 feat(auth): multi-provider OAuth SSO (Feishu, DingTalk, WeCom) (#687)
* feat(auth): add pluggable Feishu OAuth and multi-identity SSO binds

Introduce App OAuth (Feishu) alongside OIDC, persist multiple SSO
identities per user, and simplify the admin provider UI for coexistence.

* fix(dashboard): restore OIDC SSO checklist and login preview

Keep the OIDC admin card unchanged; only App OAuth cards use the
callback-only aside.

* feat(auth): add DingTalk and WeCom App OAuth SSO adapters

Enable dashboard login/bind for DingTalk and WeCom alongside Feishu, with
WeCom CorpApp wwlogin (CorpID + Agent ID) and DingTalk authCode callback support.

* feat(dashboard): redesign account SSO bind list and default names

Use an icon + status + action row list in personal settings for App OAuth
binds, and prefill empty provider display names in the admin SSO cards.

* feat(dashboard): split admin SSO settings into per-provider tabs

* fix(auth): log SSO callback failures and silence httpx URL leaks

* docs: changelog for multi-provider OAuth SSO

* style: ruff format users/manager.py after SSO conflict merge

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 11:55:26 +08:00
HUANG Cheng dcb680b421 feat(auth): optional login captcha (slider + tencent/turnstile/hcaptcha/recaptcha) (#679)
* feat(auth): add optional login captcha (slider, turnstile/hcaptcha/recaptcha, tencent)

Password login can now be guarded by a captcha. Default slider stays
client-only; strong providers are verified server-side with the vendor
(Cloudflare Turnstile, hCaptcha, reCAPTCHA v2/v3, Tencent Cloud Captcha).

- infra/auth/captcha: env snapshot + settings blob resolution, provider
  registry with per-vendor verify calls, siteverify with 10s timeout
- GET /api/auth/captcha (public widget config); POST /api/auth/login
  accepts captcha_token; tencent token carries ticket:randstr and is
  checked via GET with the client IP
- admin GET/PUT /api/settings/captcha behind the new captcha permission;
  OCTOP_CAPTCHA_SECRET redacted in envs API; boot validation for strong
  env providers
- dashboard: CaptchaField with slider/checkbox/invisible/popup modes,
  login page wiring, advanced-settings captcha panel
- docs + i18n (en/zh) + unit/integration/frontend tests

* fix(captcha): verify Tencent tickets via DescribeCaptchaResult (TC3)

The legacy ssl.captcha.qq.com/ticket/verify endpoint rejects current
tickets with response=15 "decrypt fail" even for correct
CaptchaAppId/AppSecretKey pairs. Switch to the official ticket-check API:

- POST captcha.tencentcloudapi.com DescribeCaptchaResult (2019-07-22),
  TC3-HMAC-SHA256 signed with CAM API keys; AppSecretKey stays in the body
- captcha settings gain cam_secret_id/cam_secret (encrypted at rest,
  env fallback OCTOP_CAPTCHA_CAM_SECRET_ID/KEY); settings view exposes
  cam_secret_id + has_cam_secret; dashboard shows the two fields for the
  tencent provider only
- interpret maps CaptchaCode (1 OK; 7/8/9/15/16/21/100 fail) and
  EvilLevel=100 (malicious) instead of the legacy response=="1"
- TC3 signer moved voice/tencent_sign.py -> utils/tencent_sign.py (shared)
- drop the redundant Host header from signed requests: httpx sets Host
  from the URL (same value the signature covers), and an explicit Host
  let host-routing system proxies intercept localhost mock calls
- secrets no longer appear in httpx URL logs (payload is in the body)
- move the Login Captcha settings tab next to HTTPS

* polish(dashboard): show reCAPTCHA v3 min score only when that provider is active

* fix(dashboard): captcha widgets follow the site locale, not the browser

- tencent popup: userLanguage from i18n.language (was navigator.language)
- turnstile: pass language render option
- hcaptcha/recaptcha/recaptcha-v3: hl script param from UI locale
- slider already renders site-provided labels

* feat(captcha): unlist reCAPTCHA v2 from the settings catalog

No verified deployment key for v2; keep the provider registered so
existing configs still verify, but stop offering it in the dropdown
(list_providers now filters on a per-provider listed flag).

* feat(cli): octop captcha reset — offline lockout escape hatch

Clears the stored captcha settings blob so login falls back to the
built-in slider when a misconfigured provider blocks all logins
(settings UI requires login, so it cannot fix itself). Boot-env
captcha is untouched; a running server needs a restart.
CHANGELOG: cover reset command, TC3 switch, widget language, v2 unlist.

* feat(cli): register octop captcha reset command and add changelog

Without the registry entry the command module from c5a7649d was
unreachable; CHANGELOG covers the login captcha feature, the TC3
ticket-check switch, widget locale, v2 unlisting, and captcha reset.

* fix(captcha): close pre-merge gaps + document the provider architecture

- envs API: redact OCTOP_CAPTCHA_CAM_SECRET_KEY like OCTOP_CAPTCHA_SECRET
  (was exposed in plaintext by GET /api/envs)
- validate_boot: env-only tencent provider now requires the CAM keys,
  failing fast at boot instead of at first login
- docs/configuration.md: document the two CAM env vars; note recaptcha
  v2 is unlisted but resolvable
- providers.py: architecture docstring (four layers + settled design
  decisions + adding-a-vendor recipe); rename _SuccessProvider to
  _FormPostProvider; drop the register() cast, which exposed a real
  structural bug: frozen-dataclass providers never satisfied the
  Protocol's mutable metadata members — declare them read-only
  properties so the structural check is real
- verify.py: docstring naming it the execution layer
2026-09-16 21:23:32 +08:00
jubaoliangandCursor 0bdf7f4d14 feat: persist failed chat turns and add expert task examples
Keep partial tokens and stream errors in thread history after a stop or
provider failure, and drive cron empty-state cards from manifest
task_examples. Backup skips stale workspace paths instead of creating them.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 19:05:32 +08:00
jubaoliangandCursor fcf23bdca4 feat: apply resource policy on user create and require cron job names
Admins can set storage-root and token quota when creating a user, and
cronjob_create now requires a display name with prompt-prefix fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-11 10:26:17 +08:00
Pandaandleoxyang 74f15b6548 feat(skills): add skill package copy workflows (#621)
Co-authored-by: leoxyang <leoxyang@tencent.com>
2026-09-09 17:45:06 +08:00
jubaoliang fa2f6a7f56 feat(browser): isolate harness-browser profiles per Octop user
Replace the legacy shared/default Playwright session router with
per-user harness-browser profiles (`user-<id>`) so concurrent users no
longer share one Chrome session, cookie jar, or recording. The backend
now always derives the profile from the authenticated user (or the IM
thread's agent owner) instead of trusting client-supplied profile/session
ids, and a BrowserProfileMiddleware pins tool-selected profiles to the
same boundary. Also dedupes ThreadRegistry's session-refresh logic.
2026-09-05 08:35:26 +08:00
jubaoliangandCursor 515f601838 perf(trajectory): bound live stream persistence overhead
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 12:59:13 +00:00
liukewia c305010e86 feat(cron): add name field to cron jobs and update related interfaces (#525)
* feat(cron): add name field to cron jobs and update related interfaces

- Introduced a `name` field to the `OctopCronRow`, `OctopCronCreateBody`, and `OctopCronPatchBody` interfaces.
- Updated localization files to include validation messages for the new `name` field.
- Added a constant for maximum name length.
- Enhanced the UI to display the job name in the cron jobs table and detail views.
- Updated API documentation to reflect the new optional `name` parameter in cron job creation and updates.
- Implemented database schema changes to support the new `name` field in cron jobs.

This change improves the user experience by allowing users to assign descriptive names to their cron jobs, making them easier to identify.

* feat(cron): restrict cron job management to owners only

- Updated the cron job management logic to ensure that only the owner of a cron job can create, view, update, or delete it.
- Modified the API endpoints to return empty lists for non-owners attempting to access cron jobs.
- Enhanced the frontend logic to reflect these changes, ensuring a consistent user experience across the application.
- Updated related tests to verify that cron jobs are correctly scoped to their owners, preventing unauthorized access.

This change improves security and clarity in the management of cron jobs within shared agents.

* refactor(cron): improve code readability in cron management functions

- Reformatted the `_assert_cron_manage` function for better readability by adjusting the parameter layout.
- Simplified the invocation of the `create` function in the test case for clarity.

These changes enhance the maintainability of the code and improve the overall structure of the cron management logic.
2026-09-03 11:13:10 +08:00
jubaoliang 9a7db4e44f feat: idle-reap local Chrome and add an explicit shutdown API (#520)
Stop Octop-managed Chromium after real CDP inactivity, and let the
workbench close the process without wiping on-disk login state.
2026-09-01 18:38:34 +08:00
jubaoliang 17effe4306 fix(connectors): mark custom MCP OAuth reauth when refresh fails (#474)
Expired tokens that cannot be refreshed now prompt the dashboard to re-authorize. Cache OAuth discovery for an hour, and localize callback and start-error copy.
2026-08-29 16:46:25 +08:00
jubaoliangandCursor 8b2f1ecdd7 feat: 内置插件随包分发、可配置上传上限,并补齐 Dashboard 推送与聊天音视频
把 bundled 插件打进 wheel 并在启动时按需种植;上传大小走 config/env;聊天支持音视频预览,定时任务通过 WS toast 推到 Dashboard。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 14:06:02 +08:00
Pandaandleoxyang 1d92570fca feat(media): add Volcengine Ark image and video generation (#428)
* feat(media): add generation model management and feedback

* chore: document media generation and restore quality gates

* test(browser): support missing getuid on Windows

---------

Co-authored-by: leoxyang <leoxyang@tencent.com>
2026-08-26 11:41:39 +08:00
liukewia 2f33954689 fix(chat): accept OS MIME aliases and expand inbound attachment types (#409)
* refactor: replace hardcoded media type mappings with INBOUND_EXTENSION_MEDIA_TYPES

- Removed the _EXTENSION_MEDIA_TYPES dictionary from uploads.py and replaced it with INBOUND_EXTENSION_MEDIA_TYPES imported from inbound_store.py.
- Updated the _resolve_media_type and validate_inbound_media_type functions to utilize the new mapping for determining media types based on file extensions.
- Added unit tests to ensure that unknown MIME types correctly fall back to their respective extensions and that unsupported types raise appropriate errors.

* fix(api): improve error handling for upload requests

- Refactored error rejection in requestUpload to provide clearer error messages, including response text when available.
- Updated error handling in WorkspaceDrawer and useChatAttachments to utilize a new utility function for consistent API error messaging.

* feat: add error handling for unsupported and oversized attachments

- Introduced new error codes for unsupported file types and oversized attachments in the API.
- Updated localization files for English and Chinese to include messages for these new error codes.
- Enhanced the inbound media validation logic to raise appropriate errors when attachments exceed size limits or are of unsupported types.
- Added unit tests to verify the new error handling for attachment validation.

* feat: expand allowed inbound media types and improve validation logic

- Added a comprehensive list of allowed inbound media types and their corresponding file extensions to enhance file type validation.
- Introduced new test cases to ensure that various file extensions and MIME types are correctly validated, including support for additional programming and document formats.
- Updated the existing validation logic to accommodate new media types and ensure proper fallback mechanisms for unknown MIME types.
2026-08-25 15:02:38 +08:00
22bf41be14 feat(plugins): per-agent tool toggles, plugin reload, UI assets, and tool catalog (#387)
- Add server-wide plugin enable/disable (PATCH /plugins/{id}) and a
  reload endpoint to pick up CLI installs without a full restart.
- Serve read-only plugin UI assets with traversal checks.
- Persist per-agent plugin tool enable flags and hot-sync the harness
  denylist so disables take effect on the next turn (no full reload).
- Add a tool catalog and plugin market UI plus a tool settings API.
- Ship demo plugins: ui-card, server-status, bilibili-anime.
- Update i18n bundles and API docs.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: CodeBuddy <noreply@codebuddy.ai>
2026-08-23 21:07:14 +08:00
0ce9cf46d3 feat(dashboard): layout refactor, email invites, KB text editor, remote desktop (#380)
* feat: minimal layout, user email, KB text docs, and remote desktop hub

Add classic/minimal chrome with a unified chat records host, optional user
email (invite/login), in-app markdown/txt knowledge editing, and a combined
remote desktop/phone control surface—plus host path and mobile setup hardening.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(host_dirs): don't jail host-root browse to home drive on Windows

The restrict_to_home=False case allows any absolute host path (no home
jail). On POSIX everything sits under '/'; on Windows the denylist is
empty and windows_neutralize_host_root rewrites root_dir '/' at runtime,
so a drive-relative '/' must stay allowed. The new _path_within_base
containment incorrectly rejected root_dir '/' on Windows when the checkout
drive differed from the home drive, breaking from-expert/local_shell agent
creation.

Also mark test_install_published_expert_accepts_create_options posix_only:
it relies on local_shell workspace file writes unsupported on Windows.

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-22 22:04:09 +08:00
jubaoliangandCursor 1af14b8031 chore: wire shared agents, SSO, experts, ONNX, and knowledge into the app
Register routers/repos/migrations, OpenAPI tags, i18n/error codes, sidebar routes, and docs for the new platform capabilities.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 18:56:23 +08:00
jubaoliang f2495bf411 feat(dashboard): chat stream resume via turn_active (#168) 2026-08-05 20:04:43 +08:00
jubaoliang c8132dbdfb feat: scoped root_dir bubblewrap jail and workspace path I/O (#167) 2026-08-05 20:04:04 +08:00
jubaoliang ecad9ec3da feat: chat stream resume, shared terminal dock, and thread title repair (#157)
Keep dashboard chat turns attachable after reconnect, reuse one terminal
session store across Workbench and the chat dock, and migrate legacy
hard-cut thread titles to clipped titles with ellipsis.
2026-08-04 15:40:58 +08:00
d990ca1afa feat: backup restore rehydrate, server timezone API, and scoped provider reload (#34)
Restore syncs providers and reloads agents in-process; rename cron_timezone to
default_timezone with GET /api/settings/timezone; reload only impacted agents
after provider changes; align dashboard timestamps to the server timezone.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 14:09:45 +08:00
jubaoliangandCursor 07ea4d128e Add host root_dir browser and permission probe for agent backends.
Expose /api/filesystem for lazy directory listing and write probes, wire
RootDirSelect into expert/agent forms, and validate non-/ paths before save.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 03:45:33 +00:00
jubaoliang 748d998cf2 first commit 2026-07-09 14:32:36 +00:00