19 Commits
Author SHA1 Message Date
42e41ed33e feat: add one-shot tasks and split personalization permissions (#2157)
Scheduled jobs can run once and then stop, personalization tabs can be granted separately, and rotated logs use a date-before-extension name.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 07:11:24 +08:00
Bosheng0422 e9d01401e7 fix: bound local knowledge indexing memory and service restarts 2026-10-13 16:03:03 +08:00
Grapette.L f2d0baeb4e fix(config): bound OCTOP_PORT and --port to a bindable range (#1150)
* fix(config): 绑定端口越界时告警回落,--port 越界直接报错

OCTOP_PORT 只按 int() 解析、octop run --port 也只有 type=int,70000/-1
这类根本无法绑定的取值会盖掉 config.json 里本来可用的端口,进程死在
socket.bind 抛出的 OverflowError 里,报错既不含变量名也看不出端口来源;
--port 更是在启动之前就把该值写进 config.json,之后每次 octop run 都继续继承。

现按 resolve_bind 已经支持的「0 表示由系统随机分配端口」把取值收口到
0-65535:环境变量越界沿用「告警 + 不覆盖」的既有契约回落配置文件端口,
命令行 --port 越界交给 click.IntRange 在使用期错误里拦下、不落盘。

* docs: 补上绑定端口的取值范围说明

`octop run --port` 现在会渲染成 `INTEGER RANGE … [0<=x<=65535]`,环境变量表也顺手写明
`OCTOP_PORT` 接受 0–65535(0 = 由系统随机分配),与 `OCTOP_LOG_LEVEL` 那行「One of …」的写法一致。
2026-09-26 20:14:30 +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 5e34c8a001 fix: connectors empty layout and restore prior control-plane behaviors
Apply the remaining working-tree changes: connectors empty-state layout,
plus the knowledge, HITL, captcha, workspace, user-cache, and SSRF
adjustments with matching tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 22:40:47 +08:00
5bb827f37b fix(auth): OCTOP_CAPTCHA_V3_MIN_SCORE 只接受 [0, 1] 内的有限值 (#1087) (#1088)
nan / -inf / 负数会被 float() 成功解析并原样透传给 recaptcha-v3 的判定式
`float(score) < min_score`,而该式对 NaN 恒为 False,等于静默关闭分数门槛;
inf / >1 则反向锁死所有登录。现在沿用同一解析点已有的"值不可用即回落
0.5"规则,只放行 [0, 1] 内的有限值。

Co-authored-by: sxh313 <250161920+sxh313@users.noreply.github.com>
Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 15:08:22 +08:00
HUANG Cheng 297326734f feat(auth): GeeTest v4 login captcha provider (#870) (#900)
Adds 极验行为验 v4 to the login captcha layer, following the provider
plug-in seam (one dataclass + register call backend-side, one widget
adapter frontend-side; the settings UI is data-driven so only locale
keys were needed):

- providers.py: _GeetestV4Provider — login token carries the frontend
  getValidate() result as JSON (lot_number / captcha_output /
  pass_token / gen_time); siteverify posts form-urlencoded to
  gcaptcha4.geetest.com/validate?captcha_id=<id> with
  sign_token = HMAC-SHA256(captcha_key, lot_number); only
  result == "success" passes (fail / status:error both reject).
  Aliases: geetest, geetest4, gt4. Fail-closed on transport errors,
  consistent with the other providers.
- CaptchaField: geetest-v4 popup via gt4.js bind mode — initGeetest4,
  showCaptcha on ready, getValidate() serialized as the captcha_token;
  error/close resolve undefined so login re-prompts.
- Settings UI: captcha_id / captcha_key fields via locale keys.

Tests: provider unit tests (URL + form fields + HMAC against an
independent computation, malformed/missing-field rejection, interpret
matrix), ensure_captcha flow through a local siteverify double (form
body + signature asserted; fail result rejects), popup adapter tests
(validate payload JSON, error path), builtin-order + integration list
assertions updated. Locale parity green.
2026-09-21 14:26:14 +08:00
theater 812006597a docs(configuration): add password and url to database schema example (#896)
The config.json example in docs/configuration.md omitted the password
and url fields from DatabaseConfig, even though both are documented
in the surrounding text and present in src/octop/config.py. Add them so
the snippet matches the actual schema.
2026-09-21 14:26:06 +08:00
Momoru19 4ed6caf463 docs: translate stray Chinese text in configuration.md to English (#794)
docs/configuration.md is an English-only reference doc, but two chunks
were left untranslated: the database.password bullet note, and the
entire 'Optional segmented history archive' subsection. Translated
both to English so the doc reads consistently for English readers.
2026-09-19 20:45:11 +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
薄生andjubaoliang 2439d93ddb Checkpoint slim (#606)
* chore: bump harness-memory to 0.9.9

* proactive care timezone bug fix

* ruff format

* sqlite checkpointer slim

* update harness-memory

* polish windows uni test

---------

Co-authored-by: jubaoliang <jubaoliang@gmail.com>
2026-09-08 15:37:08 +08:00
HUANG Cheng 745eba618a fix(logging): cap log size and delaycompress like logrotate
Prevent multi-GB daily octop.log growth with size-based rotation, suppress noisy memory maintenance INFO, and gzip prior rotated files on the next cycle (Python gzip works on Windows).
2026-09-02 14:27: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
jubaoliangandjubaoliang 18ab9f6ba9 feat: workspace backend sandboxing, execute-env injection, and ephemeral image refs (#376)
* feat: workspace backend sandboxing, execute-env injection, and ephemeral image refs

Workspace file-I/O hardening across backend and dashboard:
- Host directory sandboxing via root_dir allow-list and denied prefixes
- Execute-environment defaults injected into harness backend specs
- Ephemeral workspace image rematerialization for model calls
- Attachment hint expansion and inbound store improvements
- Portable memory backend and skill workspace catalog updates
- Dashboard UI for agent backend fields and root-dir selection
- Bump harness-agent 0.9.23 / harness-memory 0.9.7; docs + install notes

* feat: add user invitation codes with admin management and redeem flow

- Add user_invites table (migration 009) plus SQLite/Postgres reconcile paths
- Add InviteRepo and InviteService for create/revoke/list/redeem
- Expose public validate/redeem endpoints and admin create/revoke/list routers
- Extract default-agent bootstrap into octop.infra.agents.default_agent
- Add invite error codes and en/zh i18n strings
- Dashboard: invite drawer, login redeem UI, users list, and locales

* fix: add Windows cross-platform guards for pre-existing sandbox/rootfs tests

- Guard POSIX/container-only tests (rootfs-absolute /.octop/... workspace
  paths) with posix_only in test_thread_artifacts.py and test_agent_manager.py
- Normalize the rendered workspace path assertion in test_octop_builtin_skills.py
  (forward slashes on Windows, not str(tmp_path) backslashes)
- Canonicalize ws_dir before the prefix check in attachment hint/path tests
  (tempfile may yield an 8.3 short path on Windows while the resolved
  attachment path uses the long form)

These failures predate the user-invites commit and are unrelated to it; the
product path logic is correct.

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
2026-08-21 22:32:48 +08:00
0dce85cc85 fix: inject Admin env into running agents and sum turn token usage (#345)
Running shells and Docker sandboxes now pick up ~/.octop/env (and workspace .env) without a full reload; MCP stdio no longer inherits the entire host environment. Usage accounting adds every model call in the turn, and workspace I/O survives the harness rebuild window.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 21:53:03 +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
薄生 dca16ccc21 Feat/postgresql dual backend (#60)
* feat: PostgreSQL dual-backend for control plane

Add SqlitePool|PostgresPool behind DatabasePool, parallel PG migrations,
setup wizard defer/bind, pg_dump backups with cross-engine refusal, and
memory defaulting to the control-plane DSN when using PostgreSQL.

* fix(chat): delete checkpoint data when a conversation thread is deleted

Deleting a thread only removed Octop's own metadata row; the actual
message history stayed in the agent's LangGraph checkpointer forever,
making "delete conversation" cosmetic. Also confirm before deleting a
session in the UI, since the action is now genuinely destructive.

Checkpoint deletion runs before the metadata row is removed: if it
fails outright (not just "nothing to delete"), the thread stays
visible/retryable instead of orphaning data with no remaining handle.

* fix(memory): stop suggesting pg_dump for portable export of postgres memory

The 501 hint told users to "use pg_dump on the memory schema instead".
That advice predates the shared-table layout: memory for ALL agents now
lives in one harness_memory schema isolated by a namespace column, so a
schema-level pg_dump would export every agent's memory, not just the
requester's — a cross-agent data exposure if followed on a multi-user
install.

Document the two migration models where the refusal is implemented:
sqlite memory is per-agent files moved via pack/adopt; postgres memory
is shared, and the supported way to use it from another host (e.g.
OpenClaw's harness-memory bridge with --backend postgres) is pointing
that host at the same DSN and namespace — shared, not migrated.

* fix(test): update test_slash_compact to renamed SqlitePool

The /compact test module still imported the pre-rename DBPool, which
broke collection (ImportError) on this branch after develop's compact
feature was merged in — DBPool was renamed to SqlitePool (the concrete
class) with DatabasePool now the Protocol.

DBPool -> SqlitePool at all three sites: the import, the _agent_manager
type hint, and the fixture's DBPool(path) instantiation. SqlitePool is
the byte-for-byte successor of DBPool and matches how every other test
constructs a pool; DatabasePool cannot be used at the instantiation
site (a Protocol is not instantiable).

pytest -m live now collects cleanly (31 selected, 0 errors);
test_slash_compact 3 tests pass.

* fix(test): make memory_backend db_path assertion separator-agnostic

test_explicit_sqlite_overrides_postgresql_control_plane compared the
resolved db_path against the literal "/tmp/ws/memory.sqlite", which the
code never produces on Windows: it builds the path with pathlib, so the
Windows CI job got "\tmp\ws\memory.sqlite" and the string equality failed.

Compare as Path objects so the assertion holds on every OS separator,
matching the .as_posix() discipline already used in test_config.py.
2026-07-24 14:45:53 +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
jubaoliang 748d998cf2 first commit 2026-07-09 14:32:36 +00:00