90 Commits
Author SHA1 Message Date
HUANG ChengandJubaoliang 16a2602485 fix(chat): refuse to delete a conversation while a reply is in progress (#2222)
* fix(chat): refuse to delete a conversation while a reply is in progress

Deleting the thread mid-turn dropped the row while history was still
being written, and the foreign-key failure showed up as a model-call
error. Return 409 until the turn is idle and leave the confirm dialog open.

* docs: add redacted screenshots for the in-progress delete refusal

The PR images only show the warning and the success toast, without the
session list or account.

---------

Co-authored-by: Jubaoliang <jubaoliang@gmail.com>
2026-10-20 14:19:20 +08:00
Jubaoliang 0982cf54c0 fix(api): localize JWT middleware auth errors via Accept-Language (#2248)
Middleware returned raw English diagnostics because it bypassed the
global OctopError handler. Resolve the request locale and pass it to
to_envelope, matching bridge_proxy and the app handlers (#2187).
2026-10-20 14:12:13 +08:00
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
薄生 8b0793c69a feat(memory): add manual profile context and conflict review (#2103)
* feat(memory): add strong memory editor and surface task failures

* fix(memory): explain session snapshot lifetime in strong memory UI

* feat(memory): add owner profile editor and manual conflict review

* test: verify fault history, turn recovery and memory isolation

* fix: persist terminal failures and release stalled chat turns

* fix(deps): require released memory runtime packages

Require octop-memory 1.0.2, octop-harness 1.0.4 and octop-gateway 1.0.3 for manual document review and terminal stream cleanup. Remove the obsolete harness Git pin and refresh the lockfile so CI installs the matching released APIs.
2026-10-16 20:56:13 +08:00
53fab69f4f feat: add a decision model for skills, tools, and teams (#2098)
* feat: add a decision model for skills, tools, and teams

Let a small model shortlist what the chat model sees, including a local Laya install, and show the result on the turn.

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

* fix: stop Laya through the POSIX-safe kill helper

Windows mypy does not see os.killpg, so process-group shutdown goes through the shared helper.

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

* fix: compare the Laya install command without a POSIX path

Windows quotes the interpreter, so the displayed command is checked against the same argv list.

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

* fix: show Laya readiness and wait for local decisions

Pin the local-CPU timeout fix and distinguish a ready Laya service from the service currently enabled for decisions.

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

* feat: save each decision service and pick the default on the card

Clicking a card selects the default. Endpoint and key stay in the drawer
so Jev, Laya, and custom can be kept at once.

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-16 16:42:26 +08:00
IronMurphy e084e9c68a fix(knowledge): tell the user a restart is what the install needs (#1493)
* fix(knowledge): tell the user a restart is what the install needs

When the local embedding packages land in pip's user site, CPython only puts that
directory on sys.path if it existed at interpreter startup, so a long-running
server can never import them. ensure_local_embedding_deps() already raises with
'Restart the server and try again', but _map_knowledge_error() matched the text on
'embedding'/'component' and replaced it with the generic prerequisites error, so
the user retried a download that could not succeed. Map that case to its own code
and message.

* test(i18n): register the new code in the dashboard locales too

tests/unit/i18n/test_errors.py asserts the dashboard apiErrors keys equal the
backend ErrorCode set, so the new restart-required code has to be listed there
as well.
2026-10-16 11:27:50 +08:00
jubaoliang e65cd6fafe fix(chat): keep steer, approvals, and stream errors consistent (#2037)
Parked steers survive a follow-up approval, session bypass only auto-approves tools that allow it, and a withdrawn steer returns to the composer after the server confirms it is still queued. Stream errors stay in their own bubbles and follow the selected theme color.
2026-10-14 18:52:43 +08:00
Alison 73556e36f4 fix: let in-app browsers download files through a short-lived link (#1991)
Every download in the dashboard fetches the file with the JWT, wraps it
in a `blob:` URL and clicks an `<a download>`. WeChat and similar chat-app
WebViews (WeCom, QQ, DingTalk, Feishu, Weibo, Alipay) refuse to save
`blob:` downloads and only say "可在浏览器打开此网页来下载文件", while the
system browser they point to has no Octop session for the API URL.

In those WebViews `saveBlobAsFile` now hands the bytes it already
fetched to `POST /api/downloads/link`, which keeps them in a temp file
behind a random token for 10 minutes, and shows the link with a copy
button. `GET /api/downloads/link/{token}` serves the file as an
attachment without login; the token is the only credential. Uploads are
capped at `max_upload_mb`, links of disabled users stop working, and
expired files are removed on the next create/get. Normal browsers and
the desktop shell are unchanged.
2026-10-14 12:19:32 +08:00
HUANG Chengandjubaoliang ebcdbf9bbf feat(chat): mid-turn steering for dashboard conversations (#1300) (#1988)
Let users redirect an in-flight agent turn without stopping it.

Backend (`src/octop/infra/gateway/steer/` + WS channel + chat WS router):
- Per-thread steer queue with server-authoritative admission: idle input
  starts a normal turn; busy input queues against the active turn with
  optimistic binding (`expected_turn_id`), depth/byte caps, idempotent
  retries, and structured reject reasons; HITL-paused turns reject new
  steers.
- The queue drains only at provider-safe boundaries: after a completed
  tool batch, the first model output preempts the stream (clean
  checkpoint tail) and the queued steers continue the same logical turn
  as a real persisted user message; a pure-text answer is never
  interrupted and drains at the natural turn end.
- Lifecycle events on the thread socket: turn.started/resumed/ended,
  steer.queued/drained/discarded/removed/rejected and queue snapshots on
  subscribe; Stop and failures discard undrained items; steers parked
  across an HITL approval pause drain after the approval resumes
  (bounded by a 30-minute park TTL).
- Peer bridge relays the new user_turn fields so cross-instance turns
  keep steer semantics.

Dashboard:
- While a turn streams, Enter parks the draft as a numbered chip above
  the composer; the ↵ button on the chip commits it (immediate user row
  in the transcript, settled by server frames), ✎ reclaims the full text
  into the composer, ✕ removes it.
- The chip panel holds only uncommitted drafts; committed steers are
  represented by their transcript row and settle to the canonical
  server bubble at drain.
- Intermediate harness completion frames no longer close the live
  socket or clear the active turn while a steer turn is in flight.

Docs: `docs/api.md` gains a Mid-turn steering section (frames, delivery
fields, drain-boundary rules); CHANGELOG entry under Unreleased.

Tests: unit coverage for admission/drain/discard/park semantics and the
WS channel boundary behavior; integration coverage for rebind and
multi-subscriber streaming with the new protocol frames.

Co-authored-by: jubaoliang <jubaoliang@gmail.com>
2026-10-14 12:05:31 +08:00
seed30 a6db56af98 Merge origin/develop into fix/provider-revoke-api-key
Keep the provider revoke fix in Unreleased and take the 1.0.2b7 notes from develop.
2026-10-13 10:34:25 +08:00
HUANG Cheng 99b3c173e0 Merge pull request #1938 from huangcheng/feature/1345-wps-kb-chat-anydoc
feat(knowledge): support .wps/.doc via firecrawl-anydoc (#1345)
2026-10-13 10:24:22 +08:00
seed30 6f19e9a268 fix(providers): clear the API key when authorization is revoked
Revoke sends api_key null, and the patch treated null as leave unchanged, so the provider stayed authorized. Explicit null now clears only that field.
2026-10-12 20:44:18 +08:00
jubaoliang 815ded9aa0 fix(teams): keep member answers on the room through approval (#1928)
Member speech waits until the host turn is idle, a tool approval pauses that member instead of ending the job, and the live reply stays visible after the user approves. The same change accepts custom role ids and shows long model names in the composer.
2026-10-12 14:14:13 +08:00
e9deb58206 fix: harden Docker bootstrap, Bridge sessions, and desktop/provider UX (#1825)
Avoid silent random admin passwords, keep Bridge links alive under load,
and stop custom providers from sending stream_options that MindIE rejects.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-09 07:04:56 +08:00
lymerin b3b89c045b Merge branch 'develop' into codex/fix-portable-in-app-upgrade 2026-10-07 15:04:28 +08:00
jubaoliang 862f43d626 feat(dashboard): show thread work status in the chat history rail (#1660)
Let the classic and minimal session lists show in-progress and waiting-for-you states in the leading icon slot, and flush the classic rail scrollbar to the divider.
2026-10-06 21:16:50 +08:00
lymerin 956e789643 fix(update): install portable upgrades without re-resolving dependencies
Portable in-app upgrades could stay at 85% and fail: pip --target resolves
dependencies again instead of reusing the ones already installed in the target,
so every upgrade re-downloaded the whole tree (194 packages), timed out on every
mirror, and still reported success while the target held the previous version.

- Ship uv==0.12.22 in the online/offline portable archives and prefer the
  bundled packages/bin updater, which reuses the dependencies already installed
  in the target; start.sh/start.bat declare packages/ as the update target so
  standalone installs use it too.
- For archives built before the bundled updater existed, download only the
  application wheel and check its dependency closure before modifying the target,
  including transitive extras, environment markers and Requires-Python. Install
  the validated local wheel offline with --no-deps. Download and local installation
  each have a 90-second budget. Incompatible dependencies, installation failures or
  failed runtime verification trigger full dependency installation. One 900-second
  fallback window starts at the first full install and is shared across mirrors;
  subsequent installer timeouts are capped by the remaining window. A dependency
  preflight rejection does not overwrite the old application.
- Verify by loading the target's Octop in a fresh interpreter that processes its
  .pth files, then exercise `python -m octop --version`. Parse a marked result
  line so import output cannot obscure the version. Stale dist-info, new
  metadata with old or unloadable code, and a failing CLI entry cannot confirm an
  upgrade; the installed version must be newer and match the requested target.
  Portable and FPK installations share the rule.
- Read the installed target when validating an explicit request, and reject a
  same-or-older version before installing (HTTP 400 before an API task is
  created). Localise results and verification errors through the API and CLI.

The launcher-side version comparison (a reinstalled desktop client kept launching
the previous runtime) is handled in #1561.
2026-10-05 15:59:32 +08:00
e08730cecc fix: restore ask_user_question cards after LangGraph v2 interrupt move (#1595)
Harness projection dropped chunk["interrupts"], so the dashboard left
the tool running and never showed the question card.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 21:01:33 +08:00
b5a27ffc9f fix: adapt S3/Postgres backends and restore admin storage browse (#1565)
* fix: adapt S3/Postgres backends and restore admin storage browse

Published octop-harness 1.0.1 plus Octop-side spec mapping and protocol
wrap stop expert start and Admin tree listing from failing on the older
deepagents_backends surface. Browse now caches the backend session and
can preview or download files.

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

* fix: keep Windows paths valid in storage browse fixtures

f-string JSON turns backslashes into illegal escapes, so row_to_backend_spec
sees an incomplete filesystem config on Windows CI.

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

* fix: write browse fixture bytes without Windows newline translation

Path.write_text() converts LF to CRLF on Windows, so download assertions
saw b'# hello\r\n'.

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-04 10:55:57 +08:00
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
ded7adddfc fix: beta upgrade notes and fnpack download resilience (#1327)
* fix(update): load prerelease changelog from versioned PyPI JSON

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

* ci(fnos): retry and cache fnpack downloads

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 21:13:12 +08:00
e473dd3c4a chore: release 1.0.2b5 (#1321)
* docs: refresh README roadmap, anchors, and product sync (#1211)

Align EN/CN README with shipped features and current install/channel
docs; fix GitHub heading anchors and drop obsolete extras examples.

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

* fix(dashboard): define missing --fn-bg-container theme variable (#1216)

Dark-theme surfaces that use var(--fn-bg-container, #fff) — most
visibly the knowledge-base Markdown preview body, toolbar and outline
panel — resolved to a white background while text stayed light, leaving
preview content invisible. Define the variable as #ffffff (light) and
#141414 (dark), and point the Admin/Users badge tints that borrowed the
name for a translucent fill at --fn-bg-tertiary so their look is
unchanged.

Fixes #1215

* feat(dashboard): let each account customize the sidebar (#1218)

Store group order, item placement, and hidden entries on the user so navigation can be rearranged without showing items the account cannot access.

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

* style(dashboard): apply Prettier to files that drifted from the formatter (#1222)

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

* feat: store role-template id on users.role and harden mobile composer (#1220)

Collapse the dual user_role_id / role model so users.role and invites.role
hold the template public id, block deleting roles still in use, and keep
the chat composer visible under mobile browser visualViewport.

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

* docs: use product names for sibling project links in the README (#1225)

Link labels now match the product names while the repository URLs stay unchanged.

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

* docs(publish): bump version badges in all localized READMEs (#1229)

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

* fix: load plugins that still import harness_agent (#1260)

Marketplace plugins written before the octop_harness rename fail to install
and enable with ModuleNotFoundError. Alias that import onto the installed package.

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

* fix(backup): skip the Octop-owned _builtin_skills prefix on zip import (#1255)

POST /workspace/archive writes archive entries straight into the
workspace; _safe_zip_name only blocks traversal, so a zip could plant
files under _builtin_skills/ and .octop/_builtin_skills/. That prefix is
owned by Octop: DELETE and POST /workspace/move refuse it via
_assert_workspace_mutable and sync_octop_builtin_skills only prunes its
own retired names, so planted skills both load as kind=builtin and stay
irremovable through the API. This restores the #1105 guard (filter plus
warnings reporting) together with its regression test, which a later
"restore prior behaviors" commit had removed along with the filter.

Fixes #1254

Co-authored-by: jubaoliang <jubaoliang@tencent.com>

* fix(dashboard): define the missing --fn-* design tokens (#1240)

About 30 --fn-* custom properties were referenced across dashboard
styles but never defined in theme-vars.css. References without a
fallback resolved to invalid-at-computed-value-time (transparent
surfaces, e.g. the Connectors page sunken wells), and fallbacks were
often light-only literals that broke the dark theme. Define the
missing tokens for both themes, aligned with their nearest existing
design-system values, and fix the misspelled --text-secondary /
--border-color references that could never resolve.

Fixes #1239

* 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>

* feat(skills): let octop-assistant answer product and help questions (#1311)

Give the bundled assistant a product overview plus links to octop.cloud and the docs, and keep CLI setup for changes on the running instance.

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

* fix(ollama): list local models even when Octop service is off (#1316)

* fix(ollama): list local models even when Octop service is off

Windows users often run Ollama themselves. Octop only queried the daemon
when its managed-service toggle was on, so already-pulled models showed
as not downloaded. List from a reachable daemon without starting serve,
and mark IDs from fetch-models as downloaded.

* docs: note Ollama downloaded-model detection when the service toggle is off

* fix(mobile): stop the JPEG stream after a run of failed captures (#1309)

`_stream_frames` (the mobile JPEG fallback) retried forever: on `TimeoutError`
it logged and `continue`d, and on `captured is None` it just `continue`d. A
phone unplugged mid-stream, or a dead adb bridge, makes every capture fail at
once, so the loop spun at the frame interval indefinitely — a warning per
iteration, a log flood, and a canvas frozen on the last frame with nothing ever
sent to explain it.

The desktop sibling `desktop/stream.py::_stream_loop` already counts consecutive
misses, warns once, and after 30 sends an error frame and breaks. This mirrors
that: timeouts and `None` both count as misses, the first one is logged once,
and at `_CAPTURE_MISS_LIMIT` (30) the stream sends the
`{"type": "error", "message": ...}` frame the rest of this router already uses
and returns. A successful frame resets the streak, so an occasional dropped
frame still does not tear the stream down.

Folding the timeout branch into the shared counter also removes the
per-iteration warning flood.

* fix(cli): read and write cli_state.json through the shared JSON helpers (#1307)

`octop.cli.support.state` keeps a private reader/writer for
`~/.octop/cli_state.json` and both halves are looser than the rest of the tree.

`load()` parses with a bare `json.loads(path.read_text(...))`, so an
unparseable file raises a `json.JSONDecodeError` traceback. This file is read by
nearly every CLI command (`config`, `agent`, `db`, `acting`, `ctx`, the REPL),
so one damaged file aborts all of them at once.

`save()` writes with `path.write_text(...)` — truncate, then write. A crash or a
full disk mid-write leaves exactly the truncated file that `load()` then
refuses, with no warning and no `ensure_root()` in between.

`infra/utils/json_file.py` exists for this; its docstring is explicit that a
torn write "creates the same precondition" as a hand-edit slip and that callers
"must not fall back to an empty dict". Four call sites already route through it
(`cli/commands/run.py`, `agents/plugins/manager.py`, `agents/plugins/seed.py`,
`setup/service.py`).

`load()` now reads via `read_json_object` and translates `JsonFileCorruptError`
into `corrupt_config_error(...)` (`CONFIG_FILE_CORRUPT`) — the same policy as
every other `OCTOP_HOME` JSON reader. `save()` writes via `write_json_atomic`
(mkstemp + `os.replace`) so a reader never observes a partial file. A non-object
payload such as `[1, 2]` also raises the typed error now, instead of a stray
`dict.update` `TypeError`.

* fix(gateway): preserve IM attachment metadata in history (#1276)

* fix(docker): ship the langfuse env var the client actually reads (#1258)

OCTOP_LANGFUSE_ENABLED is set by .env.example and forwarded by docker-compose.yml, but nothing reads it: Octop keeps the switch in the settings table (observability_langfuse_enabled) and the langfuse client honours LANGFUSE_TRACING_ENABLED. Add a test that fails while a shipped Langfuse variable has no reader.

* fix(api): sandbox media preview responses (#1243)

media/preview streams user-controlled bytes (chat attachments, tool
outputs) inline on the dashboard origin. image/svg+xml is previewable,
so a navigated preview URL executed as a live document on the app
origin and could run attacker script — the endpoint also accepts the
access_token query parameter for media loads. Serve previews with
Content-Security-Policy: sandbox and X-Content-Type-Options: nosniff;
image/video previews keep working.

Fixes #1242

Co-authored-by: jubaoliang <jubaoliang@gmail.com>

* feat: add Octop↔Octop cloud collab for remote experts (#1281)

* feat: add Octop↔Octop Bridge for remote agent access

Enable admin-managed peer connections with WS tunnel, path allowlist,
hello_ack handshake, SSRF guards, and Chat shadow-agent hydrate so
operators can probe and use remote agents from the local dashboard.

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

* fix: serialize bridge turn chunks and flag remote experts

LangChain HumanMessage objects in peer turn.chunk frames crashed
json.dumps; add a bridge JSON default. Show a 远端/Remote badge on
shadow experts in the picker and sidebar lists.

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

* fix: bridge avatars, named remote badges, and auto-reconnect

Keep bundled / CDN icon URLs for shadow experts and only proxy uploaded
avatars. Show the bridge display name on remote badges. Add a default-on
auto-reconnect switch that backs off on disconnect and disables itself
after repeated failures, recording the reason in last_error.

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

* feat: add card/table views for bridge connections

Match the storage page card layout and add a Segmented toggle so
admins can switch between a card grid and a table of remote links.

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

* fix: render bridge expert icons correctly on the chat page

Encode bridge agent ids in avatar URLs the same way as chat WS paths,
fall back to Lucide when the image fails, size portraits to fill the
sidebar avatar, and refresh AgentContext when icon_url changes.

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

* feat: tunnel peer models and knowledge bases for bridge chat

Allow read-only GET of peer providers/resolved, active-model, and
knowledge-bases (plus capability) through the Bridge tunnel, expose
local bridge connection routes, and point the chat composer at those
sources when talking to a shadow expert. Hide local connectors for
remote sessions. Also allow agent subagents paths on the tunnel.

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

* fix: scope bridge chat expert picker to peer agents

When the active expert is a Bridge shadow, the composer expert picker
and @-mentions only list peers on that connection (not local experts).
Encode bridge agent ids for skills and subagents list/install paths.

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

* fix: hint remote chat pickers to manage settings on the peer

In Bridge sessions, replace local “manage …” footers for models,
skills, knowledge bases, experts, and subagents with a muted
“edit on remote” tip and a toast instead of navigating to local admin.

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

* feat: polish bridge remote UX and tunnel agent status

Allowlist GET …/status so hubs can read real peer harness state (peers need
this build). Keep history-migration hub-local, skip noisy bridge polls in the
UI, move Bridge under Settings, and mark remote experts with cable + name.

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

* feat: tunnel remote expert catalogs and polish bridge connection UX

Hub can edit peer subagents, memory, channels, tools, plugins, and MBTI
through the tunnel; surfaces that cannot hop show an in-drawer hint. Peer
must run this build so the new allowlist takes effect.

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

* feat: group cloud-collab experts and unify header-tunneled composer APIs

Keep the selected remote expert on disconnect, gate peer-only surfaces in the UI, and stop forking composer/task requests through dedicated bridge endpoints.

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

* feat: add search to the Experts toolbar

Filter my experts, teams, and the library from the existing button row so long catalogs stay scannable.

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

* fix: keep inbound cloud-collab cards peer-owned

Inbound links can only edit name/icon/notes; disconnect, delete, and auto-reconnect stay disabled. Peer offline shows as 离线, peer delete removes the card, and the default inbound name is the short connection id.

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

* fix: polish inbound cloud-collab UX and unify 对端 copy

Peer-initiated links can only edit display info and cannot redial;
offline cards may be deleted. Local-only pages hint when a peer
expert is selected.

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

* fix: map peer team speakers onto Bridge shadows

Peer team chats stamped local member ids, so the hub fell back to the host
avatar. Rewrite roster and stream speakers onto bridge:{cid}:{id} shadows,
and keep the local team picker from mixing in peer experts.

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

* fix: stop rewriting team thread ids in the Bridge tunnel

Member job threads are {room}~{agent}. A blanket JSON replace of the peer
agent id turned those into hub shadows, so history 404ed on the peer.

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

* fix: rewrite peer media URLs and keep bridge turn composer fields

Live send_file_to_user frames still pointed at peer-local /api/agents/{id}.
Map every teammate id in tunneled JSON, and copy the full dashboard turn
body so knowledge bases and HITL policy are not dropped on the peer.

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

* fix: rename bridge probe tests to avoid pytest module clash

tests/unit/bridge/test_probe.py collided with tests/unit/mobile/test_probe.py
during collection (same basename).

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

* feat: collapse extra experts on Bridge cards and fill avatars

Show at most four experts on a connection card, with the rest behind
expand. Portraits fill the 40px ring without a tinted background.

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: lulinzhi37-alt <lulinzhi37@gmail.com>

* chore: release 1.0.2b5

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

* chore: bump uv.lock to 1.0.2b5

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

* fix(ollama): sanitize models dir through host path policy

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

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Dang Zitou <dengzitao888@163.com>
Co-authored-by: Frank Zhang <77115469+Master-Frank@users.noreply.github.com>
Co-authored-by: XiaoChen <1326713348@qq.com>
Co-authored-by: locip123 <116343912+locip123@users.noreply.github.com>
Co-authored-by: lihongyuan99 <64824864+lihongyuan99@users.noreply.github.com>
Co-authored-by: lulinzhi37-alt <lulinzhi37@gmail.com>
2026-09-29 17:47:18 +08:00
232030f46c chore: release 1.0.2b4 (#1226)
* docs: refresh README roadmap, anchors, and product sync (#1211)

Align EN/CN README with shipped features and current install/channel
docs; fix GitHub heading anchors and drop obsolete extras examples.

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

* fix(dashboard): define missing --fn-bg-container theme variable (#1216)

Dark-theme surfaces that use var(--fn-bg-container, #fff) — most
visibly the knowledge-base Markdown preview body, toolbar and outline
panel — resolved to a white background while text stayed light, leaving
preview content invisible. Define the variable as #ffffff (light) and
#141414 (dark), and point the Admin/Users badge tints that borrowed the
name for a translucent fill at --fn-bg-tertiary so their look is
unchanged.

Fixes #1215

* feat(dashboard): let each account customize the sidebar (#1218)

Store group order, item placement, and hidden entries on the user so navigation can be rearranged without showing items the account cannot access.

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

* style(dashboard): apply Prettier to files that drifted from the formatter (#1222)

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

* feat: store role-template id on users.role and harden mobile composer (#1220)

Collapse the dual user_role_id / role model so users.role and invites.role
hold the template public id, block deleting roles still in use, and keep
the chat composer visible under mobile browser visualViewport.

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

* docs: use product names for sibling project links in the README (#1225)

Link labels now match the product names while the repository URLs stay unchanged.

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

* chore: release 1.0.2b4

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

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Dang Zitou <dengzitao888@163.com>
2026-09-27 22:05:48 +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
jubaoliangandCursor 1d2b2558fb feat(chat): team artifacts, fan-in tool trail, and host wrap-up context
Persist member file refs and tool history on team walls, open docks by producer agent, and inject truncated member answers into host follow-up so wrap-up can follow their advice.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-25 14:48:45 +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
4e09aeb956 fix(knowledge): map per-base document cap to KNOWLEDGE_DOC_LIMIT (#1013)
`_map_knowledge_error` matched the literal "at most 100" to classify the
document-cap error, but `KnowledgeRepo.create_document` interpolates the
per-base `max_documents`, which has been user-configurable since 90b8ca25.
Any cap other than the default 100 therefore fell through to the base-cap
branch (the repo message also contains "knowledge bases") and the user was
told they had created too many knowledge bases.

Classify both caps by the stable wording of their own messages instead of
a magic number, and drive the mapping from the real repo in a regression
test so the wording coupling cannot silently rot again.

Co-authored-by: sxh <sunxianhong@ncti-gba.cn>
Co-authored-by: sxh313 <sxh313@users.noreply.github.com>
Co-authored-by: jubaoliang <jubaoliang@tencent.com>
2026-09-24 15:11:19 +08:00
theater 2d679cbfb5 fix(update): checkpoint SQLite WAL before desktop process restart (#918)
* fix(update): checkpoint SQLite WAL before desktop process restart

In desktop/portable mode, POST /api/update/restart replaced the process
image with os.execv without flushing the SQLite WAL. Because SqlitePool
uses WAL mode with a large autocheckpoint window, all writes since the
last checkpoint were lost on restart (#800).

Change _restart_desktop_process to accept the OctopServer, and before
execv run PRAGMA wal_checkpoint(TRUNCATE) and close the pool when the
database is SQLite. The restart endpoint now injects the server via
Depends(get_server).

Fixes #800.

* style(tests): format desktop restart regression cases
2026-09-23 15:40:44 +08:00
liukewia 35abf52626 fix(dashboard): honor PWA safe-area insets and widen mobile chat bubbles (#666)
* refactor: update layout styles to support safe area insets

Modified padding and margin properties across various components to utilize environment variables for safe area insets, ensuring better compatibility with devices that have notches or rounded corners. This includes updates to index.html, offline.html, and several layout components to enhance the overall responsiveness and user experience.

* fix: update keyboard offset handling and layout styles

Refactored keyboard offset calculations in the useKeyboardOffset hook to improve handling of soft keyboard visibility. Adjusted layout styles across various components to utilize the largest viewport height (lvh) for better compatibility with devices featuring home indicators. This includes updates to padding, height properties, and background colors to enhance the user experience in chat and main layout components.

* refactor: update chat layout styles for improved responsiveness

Adjusted padding, width, and margin properties across various chat components to utilize environment variables for better responsiveness. This includes updates to the chat input, message list, and welcome components, ensuring consistent spacing and alignment across different screen sizes. Enhanced mobile styles to accommodate varying avatar sizes and maintain layout integrity.

* refactor: enhance chat component styles for consistency and responsiveness

Updated layout styles in chat components to ensure consistent spacing and alignment. Adjusted margin and gap properties to utilize environment variables, improving responsiveness across different screen sizes. Enhanced mobile styles for better alignment of avatars and message bubbles, ensuring a cohesive user experience.

* feat: implement theme management in index.html and update logo assets

Added a script to manage dashboard theme based on user preferences and system settings, ensuring the correct theme is applied before the first paint. Updated CSS to utilize data attributes for theme styling. Replaced existing logo assets with new vertical and horizontal versions for both light and dark themes, and updated references throughout the application. Removed outdated logo files to streamline asset management.

* refactor: update layout styles to improve safe area handling

Enhanced layout components by adjusting padding and margin properties to better utilize environment variables for safe area insets. This includes updates to the PageShell, Sidebar, MainLayout, Login, and Setup components, ensuring improved responsiveness and compatibility with devices featuring notches or rounded corners.
2026-09-22 22:02:18 +08:00
1752bc634d fix(cron,hitl): date timezone + HITL resume expire on error (#890)
* fix(cron,hitl): date triggers use server timezone; expire HITL on resume error

Naive date: ISO times now honor default_timezone like cron:. Dashboard
HITL resume stream failures mark the pending record expired instead of
approved, so reinject safety no longer mislabels a failed resume.

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

* chore: drop unrelated uv.lock change from polish branch

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 12:01:43 +08:00
jubaoliang 06f632ec59 fix(hitl): stop dashboard ask cards from reappearing (#782)
Merged from #877.
2026-09-21 03:02:52 +00:00
c7a095a748 fix(dashboard): AuthGuard 侧栏切页不整页重载;收敛 task_examples 解析 (#841)
* fix(dashboard): stop AuthGuard remount on nav; dedupe task-example resolve

BrowserRouter's navigate identity changes with the path, so AuthGuard must
not re-gate (and tear down MainLayout) on every sidebar click. Keep offline
boot/retry from #744. Share workspace→catalog→name task_examples resolution
between welcome and cron/examples, and drop the unused frontend cron examples client.

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

* style(dashboard): apply leftover prettier formatting

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

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 10:18:35 +08:00
Zara1024andCursor 82263eb0e7 feat(cron): 定时任务空状态提示词按专家区分 (#651) (#747)
* feat(cron): resolve empty-state prompts per expert (#651)

Prefer workspace/catalog/name-based task_examples so cron suggestions differ by agent.

* style: ruff-format cron/chat routers for CI lint

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-19 21:25:55 +08:00
IronMurphy c4685ba54d Treat an uppercase HTTP(S) scheme as already absolute in browser nav (#822)
The stream router's _normalize_nav_url() checked t.startswith(("http://", "https://")) with a raw string, so a user-typed HTTPS://host URL was prefixed again into https://HTTPS://host, which the browser then cannot load. Match octop.infra.utils.url.normalize_nav_url's case-insensitive check, and cover the behaviour with tests.
2026-09-19 20:45:24 +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
Xinmin Zeng f7124f31ac fix(db): ensure knowledge_bases max_documents column in PostgreSQL (#755)
- Add max_documents to 010_thread_message_projection.pg.sql via ADD COLUMN IF NOT EXISTS
- Invoke _ensure_knowledge_bases_schema across dialects at the end of run_migrations
- Distinguish prerequisites errors in _map_knowledge_error instead of masking unclassified errors as 409
- Add PostgreSQL integration test for knowledge_bases max_documents column and CRUD
- Add unit tests verifying _map_knowledge_error behavior on unclassified errors
2026-09-17 20:17:09 +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 b3edf893ab feat(update): default to stable-only checks with optional pre-releases
Keep automatic update reminders on the latest stable release, pin upgrades
to the confirmed version, and require --allow-prerelease for CLI beta installs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 09:40:32 +08:00
jubaoliangandCursor 08814ecffa fix(chat): restore history timestamps and align user bubbles
Refresh dropped message times because live projection never copied
checkpoint_ts. Stamp the current turn, fall back to created_at, keep
the user avatar lined up with the text bubble, and move copy/edit
beside the timestamp. README now matches shipped knowledge, plugin,
and PostgreSQL surfaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 22:45:23 +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
猫猫摸大鱼 3f057e8e15 feat(update): 检查更新错误提示本地化并透出来源,不改探测与缓存逻辑 (#627)
- /update/status 与 /update/check 增加 error_code(pypi_unreachable)与
  source 字段;探测、重试、缓存行为保持不变
- 版本升级界面错误文案按语言展示(errors.pypi_unreachable),镜像来源
  显示提示(mirrorSource)
- octop update 失败提示补充网络/代理排查建议
- PyPIInfo 增加 source 数据字段并标注 pypi.org 来源
- 单测覆盖字段透出,前端类型/文案同步
2026-09-09 20:02:26 +08:00
HUANG Chengandjubaoliang 985c3eb887 feat(knowledge): download originals and rich document preview (#591) (#612)
* feat(knowledge): download originals and rich document preview (#591)

Add file download/inline endpoints with has_original, shared DocumentPreviewCore
for PDF/DOCX/PPTX/XLSX, markdown preview, drag-drop upload, and DOCX layout
sanitization for corrupt spacing metrics.

* feat(dashboard): render PDF previews with PDF.js instead of iframe

Replace Chrome's built-in PDF iframe with react-pdf for consistent
in-app pages, zoom controls, and cross-browser look (#591).

---------

Co-authored-by: jubaoliang <jubaoliang@gmail.com>
2026-09-09 17:46:23 +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
jubaoliang 2fd3a5de7a feat: add Didi connector, improve upgrade progress reliability
- Add Didi (滴滴) MCP connector: catalog entry, remote spec builder,
  credential validation, and dashboard logo asset.
- Report upgrade progress while the upgrade task runs (backend polls
  the task with a timeout loop instead of blocking silently) and
  retry the frontend progress poll a few times before surfacing an
  error, instead of failing on the first transient fetch error.
- Desktop launcher: detect when the bundled portable runtime is newer
  than the installed one and replace it in place (extract to a
  side-by-side dir, swap, keep a previous copy for rollback on
  failure) instead of only extracting on first launch.
- Fix wording in sync-main-to-develop.yml (sync direction was
  described backwards: "develop onto main" -> "main into develop").
2026-09-07 09:04:29 +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 8401f892da feat(knowledge): expand document formats, add optional OCR, and show upload progress
Parse more text and spreadsheet types, add optional local/remote OCR for images and scanned PDFs, and surface upload progress so indexing no longer appears stuck.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 20:03:21 +08:00
jubaoliangandCursor 064f957782 feat(backup): let users choose archive contents and keep omitted data
Default backups skip chat history so archives stay smaller. Restore only
replaces packed config, workspaces, skill packages, plugins, and knowledge
files, and preserves live chats when they were not included.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 17:59:02 +08:00
jubaoliang 7eeeef778c feat: align default experts on home storage and keep chat todos in plan order (#519)
Linux octop run now ensures bubblewrap in the background without blocking boot.
Setup and invite default agents use the same home-scoped local backend as
dashboard-created experts. Chat task progress sorts by original numeric ids
instead of status, so completed steps stay in plan order.
2026-09-01 18:38:52 +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