Commit graph

1061 commits

Author SHA1 Message Date
Zero Liu
47719e63ad
test(agent-mode): drop removed enabled field from backend test fixtures
The `enabled` flag no longer exists on `agentMode`. The Codex/Opencode
backend test fixtures set it on directly-typed `setSettings`/`updateSetting`
literals, which failed the CI `tsc` excess-property check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:42:36 -07:00
Zero Liu
e25dd9861c
refactor(agent-mode): remove "Enable Agent Mode" toggle
Agent Mode is always on now (still desktop-only, since it requires
subprocess support). Drop the persisted `agentMode.enabled` flag and
the master toggle from settings, make `isAgentModeEnabled()`
platform-only, and clean up the now-dead toggle-reactive wiring
(ribbon refresh, settings-driven command re-registration).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:33:44 -07:00
Zero Liu
0a6046ff0a
Merge remote-tracking branch 'origin/v4-preview' into zero/model-settings-redesign
# Conflicts:
#	designdocs/todo/AGENT_MODE_TODOS.md
#	src/agentMode/index.ts
#	src/settings/v2/components/AgentSettings.tsx
2026-05-28 15:22:09 -07:00
Zero Liu
d72e3ee05a
refactor(agent-mode): redesign agent binary configuration UI (#2517)
Replace the per-backend install/settings panels with a shared Configure
dialog layout. Introduces ConfigDialogShell + ConfigSection, InstallCommandRow,
and an installStatus badge/status-line module (with tests), and reworks the
Claude, Codex, and opencode Configure dialogs onto it. The settings page now
shows each backend's icon, an install-status badge, and a Configure button,
dropping the old BinaryInstallContent and SimpleBackendSettingsPanel helpers.
Copy is simplified for non-technical users and dialog spacing/dividers are
made consistent.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:15:52 -07:00
Zero Liu
4ec05a7571
introduce model migration script 2026-05-28 15:14:59 -07:00
Zero Liu
c3ebcddfd6
BYOK model management 2026-05-28 13:41:00 -07:00
Zero Liu
0114cdbd12
docs(agent-mode): migrate pending TODOs to GitHub issues (#2516)
Replaces every pending top-level `- [ ]` in `AGENT_MODE_TODOS.md` with a
link to its corresponding issue in logancyang/obsidian-copilot-preview
(#59-#98). Follows the playbook in `AGENT_TODOS_TO_ISSUES_PLAYBOOK.md`:
sub-bullets folded into issue bodies, and "Integrate copilot plus tool
calls" split into 5 child issues (#80-#84) under a now-plain parent
bullet. 39 issues opened end-to-end via paired author/reviewer subagents.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 11:03:27 -07:00
Zero Liu
3aea987832
docs(agent-mode): add issue-creation skill, migration playbook, refresh TODOs (#2514)
- Add `.claude/skills/create-agent-issue/SKILL.md`: project-level skill that
  codifies the standard for one well-formed GitHub issue (title shape, body
  sections, label palette, draft artifact format, reviewer rubric, three-stage
  workflow: draft / review-and-push / all).
- Add `designdocs/todo/AGENT_TODOS_TO_ISSUES_PLAYBOOK.md`: orchestrator
  playbook for migrating `AGENT_MODE_TODOS.md` into GitHub issues with a
  two-subagent (author + reviewer) flow, autonomous triage, parallelism,
  idempotency, and verbatim subagent prompt templates.
- Revamp `designdocs/todo/AGENT_MODE_TODOS.md`: richer per-item context,
  "design needed" markers, reorganized MCP and Codex auth items, current
  pending count is 33 top-level items (P0=7, P1=17, P2=7, P3=2).
- Drop `designdocs/todo/MCP_EXTERNALLY_MANAGED_SERVERS.md` (stale).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:42:27 -07:00
Zero Liu
e7477385ae
docs(skills): add design doc for project-folder discovery redesign (#2513)
Replaces the rescan/import-consent flow with unified discovery across
canonical and agent project folders, lazy migration with a global
suppress flag, and an overflow-menu lockdown for mirrored duplicates.
2026-05-27 23:50:22 -07:00
Zero Liu
fe93f125f4
Add vault test with test fixture 2026-05-27 11:01:24 -07:00
Zero Liu
12742666c0
Add copilot plus flash support in opencode 2026-05-26 11:20:31 -07:00
Zero Liu
093df5a301
improve agent model enabler settings 2026-05-26 10:50:27 -07:00
Zero Liu
86a9748580
Fix model picker padding 2026-05-26 10:35:02 -07:00
Zero Liu
16f40de70a
Render model descriptions 2026-05-26 10:34:09 -07:00
Zero Liu
60f4d1c8d4
Fix claude extended thinking 2026-05-25 22:36:10 -07:00
Zero Liu
ecf0890b93
Fix opencode enable model UI 2026-05-25 22:33:45 -07:00
Zero Liu
60185fc55a
Add BYOK settings - agent enablement 2026-05-25 22:17:27 -07:00
Zero Liu
d554434020
Fix lint error 2026-05-23 23:37:56 -07:00
Zero Liu
70316d893c
Add BYOK settings modal 2026-05-23 23:30:26 -07:00
Zero Liu
64fc3682e7
Add backend config registry and byok setup api 2026-05-23 12:38:31 -07:00
Zero Liu
21b5244b99
implement verification logic 2026-05-23 01:53:35 -07:00
Zero Liu
aaf72c19a1
Add provider and configured model registry 2026-05-23 01:06:16 -07:00
Zero Liu
05f8abf90a
Add service APIs 2026-05-22 23:17:18 -07:00
Zero Liu
e4f24ec749
introduce catalog download service 2026-05-22 19:58:42 -07:00
Zero Liu
fa70144e60
boostrap new model managmeent 2026-05-22 19:13:42 -07:00
Zero Liu
3d422f4d05
docs(design): add model management redesign spec + data model spec
Replaces the older MODEL_MANAGEMENT_REDESIGN.md with a more focused tech spec,
a data-model spec with review notes, and a portal-container contract doc that
the upcoming reimplementation will follow.
2026-05-22 12:49:55 -07:00
Zero Liu
3e396d1a1d
docs(agent-mode): update TODO checklist (#2509)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:38:55 -07:00
Zero Liu
05434a59df
fix(skills): eliminate Skills Settings UI lag from watcher-driven refreshes (#2508)
* fix(skills): eliminate Skills Settings UI lag from watcher-driven refreshes

Replaces the time-based watcher suppression with path-scoped expectations:
each SkillManager FS write registers predicates (exists/missing/modified/
subtree-*) and the matching vault events are dropped without triggering a
debounced reconcile. A 10s safety timer backstops never-arriving events.
Toggle/delete/rename/saveProperties now publish incremental in-memory updates
instead of re-running full discovery, so the Properties modal save returns
synchronously and the grid reflects the change on the next render.

* fix(skills): heal drift when expectations expire; preserve external reconciles

Two fixes for the watcher-suppression machinery on PR #2508:

- `armSafetyTimer`: when the 10s backstop fires with expectations still
  pending, schedule a debounced reconcile before clearing. Catches the case
  where an external process undid our change (e.g. deleted a link we expected
  to exist) — the matching event was suppressed, predicate never satisfied,
  and previously the state drifted silently until an unrelated watched event
  fired.

- `runInternalMutation`: stop cancelling pre-existing reconcile timers in
  the finally block. Events fired during the mutation are dropped by the
  depth gate, so any debounce timer left armed was scheduled by an external
  event before the mutation started and still needs servicing.

Adds two regression tests and updates the pre-existing "safety timer clears
stale expectations" test which is superseded by the new healing behavior.
2026-05-21 15:07:49 -07:00
Zero Liu
8520b24477
perf(agent-mode): warm-adopt preload probe to skip first-chat spawn (#2507)
* perf(agent-mode): warm-adopt preload probe to skip first-chat spawn

The preloader's probe subprocess is now retained as a "warm" entry and
adopted by the first chat-open on that backend, so the first session
skips both the subprocess spawn and the `newSession` round-trip. Preload
status is also tracked per-backend: the chat gates on the active
backend's status only, and the picker shows per-backend loading rows for
the others.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(agent-mode): defer model+effort seeding to backend confirmation

- Seed only baseModelId (not effort) so descriptor-style backends
  (Claude) don't see a matching seeded effort and skip the real
  setConfigOption inside applyInitialSessionConfig.
- Gate warm-session `ready` on confirmSeededSelection so sendPrompt
  can't race onto the probe's model before setModel resolves.
- Add regression tests covering both paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:48:49 -07:00
Zero Liu
a207694cbf
docs: fix Copilot command ID in CLI testing guide (#2506)
Replace non-existent `copilot:open-copilot-chat` with the registered
`copilot:agent-chat-open-window` ID in both the "Run a command" example
and the smoke-test scaffold so the documented commands actually work.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:00:20 -07:00
Zero Liu
9fe7a3b95e
docs: add Obsidian CLI e2e testing guide (#2505)
Adds OBSIDIAN_CLI_TEST.md with a field guide for driving the plugin
through the Obsidian desktop CLI: multi-vault targeting (the biggest
gotcha — default routes to whichever window was touched last), popout
window limitations, settings round-trips via eval/saveData, real-input
UI driving via dev:cdp, screenshots, console/error capture, performance
metrics, and a smoke-test scaffold. AGENTS.md now points to it and
keeps only the multi-vault warning inline so there is one source of
truth.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:56:44 -07:00
Zero Liu
bf0308dd51
feat(agent-mode): make note links clickable in chat and tool cards (#2503)
* feat(agent-mode): make note links clickable in chat and tool cards

Switches markdown rendering to the modern `MarkdownRenderer.render(app, …)`
API via a shared `renderMarkdown` wrapper, and adds a delegated click
handler so `a.internal-link` inside chat/agent/plan-preview views opens
via `app.workspace.openLinkText` (left-click in current pane, cmd/middle
in a new tab). Tool ActionCards now also expose the collapsed line as
a clickable target once the call has completed.

Threads `app` explicitly through the components and utilities that
previously relied on the global `app` (lexicalTextUtils, notePreviewUtils,
vaultPath, AtMention/Note/Paste/TextInsertion plugins) using the
`useApp()` hook at the leaf, and updates AGENTS.md to discourage new
uses of the global.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(chat): fix ChatSingleMessage mocks for wireInternalLinks

The `renderMarkdown` wrapper now calls `component.register(...)` after
`MarkdownRenderer.render(...)`. The test's `obsidian.Component` mock was
missing `register`, causing the promise to reject and `logError` (which
calls the unmocked `getSettings()`) to crash. Add `register` to the
Component mock and mock `getSettings` as a safety net.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(agent-mode): resolve internal links against active note

Pass the active file path as sourcePath to renderMarkdown so wikilinks
with duplicate basenames or heading-only references resolve to the right
file instead of falling back to vault root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:05:10 -07:00
Zero Liu
4e8c604efb
feat(agent-mode): teach backends about @-mention pill syntax (#2498)
* feat(agent-mode): teach backends about @-mention pill syntax

The chat editor serializes @-mention pills to `[[note]]`, `{folder}`, and
`{activeNote}` tokens, but only `[[note]]` was understood — the others
were literal strings to the agent. Add a shared pill-syntax directive
appended to opencode, codex, and claude SDK spawn-time instructions
(mirroring the existing skill-creation directive plumbing), and resolve
`{activeNote}` to the real `[[Note Title]]` at send time since the active
file is a client-side concept the agent can't query.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(agent-mode): prune narration comments from pill-syntax change

Cut multi-line JSDoc and inline rationale that explained WHAT or referenced
callers, per the project's "one short line max, only WHY" rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(agent-mode): preserve extension when resolving {activeNote}

Non-markdown active files (.pdf, .canvas) lost their extension when
{activeNote} was rewritten via activeFile.basename, leaving the agent
with an ambiguous [[name]] that didn't match the path the pill envelope
carries. Mirror NotePillNode.getTextContent's extension-aware
serialization so the inline token matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:32:49 -07:00
Zero Liu
898c31ac1b
fix(agent-mode): reject invalid env variable names before commit (#2502)
`rowsToRecord` was persisting every non-empty trimmed key, so names
failing `ENV_VAR_NAME_RE` (e.g. `BAD KEY`, `FOO=BAR`) flowed through
`onChange` into settings and were applied verbatim by backend spawn
paths, which read `envOverrides` directly without re-sanitizing.
Filter invalid rows at the commit boundary so the persisted record
and subprocess env only contain valid POSIX identifiers.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:28:13 -07:00
Zero Liu
cdcd9bb601
fix(skills): allow assigning Claude-only skills to any agent (#2501)
Codex (and other non-Claude agents) silently ignore the Claude-only
frontmatter flags (`disable-model-invocation`, `user-invocable`,
`model`), so hard-disabling their toggles on those skills was overly
restrictive. The inline chips on the row already communicate which
flags are Claude-specific.
2026-05-20 23:02:20 -07:00
Zero Liu
c39b9bf44c
feat(agent-mode): per-backend env variable overrides (#2499)
Adds an "Environment variables" editor to each Agent Mode backend
(Claude, Codex, opencode) so users can inject vars like
CLAUDE_CONFIG_DIR, CODEX_HOME, XDG_CONFIG_HOME, or HTTPS_PROXY without
polluting the parent shell. Overrides are merged onto process.env at
spawn (Codex, opencode) or per prompt() (Claude SDK), and persisted
through a shared sanitizer that enforces POSIX-style names, drops
control chars, and caps the record at 64 entries. The editor debounces
commits to avoid rewriting settings on every keystroke.

Also relocates BinaryPathSetting into src/agentMode/backends/shared/
to honor the agent-mode layer boundaries.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 22:58:57 -07:00
Zero Liu
1c0a750b31
fix(agent-mode): apply status-bar clearance padding to agent chat view (#2497) 2026-05-20 22:31:51 -07:00
Zero Liu
c4b92fcb16
feat(agent-mode): inline tool permission cards in chat (#2493)
Replace the modal-based permission prompter with inline ToolPermissionCard
rendered at the tail of the chat scroll, matching how plan proposals already
work. Refactor AgentSession status to be derived from underlying primitives
(resolver maps, abortController, etc.) so it cannot drift from reality, and
add tests covering the awaiting_permission lifecycle and turn-error reset.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
f53672d091
fix(agent-mode): make tool-card verbs status-aware (#2491)
Replaces the brief "Read Read" / "Edited Edit" flash that appeared while
a tool call's input JSON was still streaming. `targetFromTitle` now
returns an ellipsis when the title is just the vendor tool name (the
SDK's documented placeholder state), and a new `verb()` helper picks the
present-participle form for pending/in_progress calls and the past-tense
form for completed/failed ones — so cards read "Reading notes/foo.md" →
"Read notes/foo.md", "Fetching url" → "Fetched url", etc.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
a3c4c583cf
docs(design): refine model management redesign + add Quick Chat follow-up (#2490)
- MODEL_MANAGEMENT_REDESIGN.md: BYOK is now the central, user-bring-only
  registry; drop per-model and per-provider Availability/Capability toggles;
  one global table with provider section rows; Quick Chat added as a 4th
  agent sub-tab; OpenCode/Plus models stay in the Agent panel only.
- QUICK_CHAT_AGENT_INTEGRATION.md (new): follow-up plan for elevating
  LangChain chat into a first-class agent backend (routing service, session
  adapter, v2->v3 settings migration, milestones Q1-Q6).
- AGENT_MODE_TODOS.md: mark shipped items; add notes for opencode/local
  models and subscription-based opencode flows.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
9263f9ae11
Stop persisting agent mode selection (#2487)
* Stop persisting agent mode selection

* Force canonical default mode on every new agent session

Restore `applyPersistedMode` as a small coerce helper and wire it back
into every backend's `applyInitialSessionConfig` with a literal
`"default"` — never reading from settings. Codex-acp's natural starting
native mode is `read-only` (canonical `plan`), so without this the
picker landed on Plan on every fresh chat.

For codex specifically, also pin the spawn-time approval/sandbox config
via `-c approval_policy="on-request"` and `-c sandbox_mode="workspace-write"`
so codex-acp's first `currentModeId` already matches the canonical `auto`
preset. Without these, the picker briefly flashed "Plan" before the
post-spawn coerce switched it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop redundant post-spawn mode coerce

The codex picker briefly flashing "Plan" was fixed at the spawn level
(`-c approval_policy/sandbox_mode` in CodexBackend). Claude's SDK and
opencode's spawn-time `default_agent` already start in canonical
`default`, so the runtime `applyPersistedMode(session, "default")`
calls on all three backends were dead defense-in-depth. Remove them
along with the now-unused helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop stale type-only import comment in settings/model.ts

`import type` is erased at runtime, so there's no actual cycle to
guard against — the keyword itself already signals "type-only" to
any reader.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
122dd4adf5
fix(agent-mode): keep mode picker visible while generating (#2489)
Hoist the agent-mode picker out of the not-generating branch so users
can flip between Auto/Plan/Safe mid-turn instead of having to wait for
the agent to stop. Non-agent chats are unaffected since they don't
pass modePickerOverride.
2026-05-20 19:05:41 -07:00
Zero Liu
0f03c41742
docs(design): add Model Management redesign handoff doc (#2488)
Consolidates the three duplicated model configuration surfaces (basic
settings keys, Models settings table, agent mode curation) into a
single design for product designer handoff. Covers unified Models
panel, agent-first onboarding with three paths, per-backend defaults,
and OpenCode/Copilot Plus as system-managed sections.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
0ebbc73424
fix(agent-mode): disable mode/model picker while session is starting (#2485)
* fix(agent-mode): queue mode/model switch while session is still starting

* fix(agent-mode): disable picker while session is starting instead of queueing

Replace the await-session.ready queueing approach with a UI-level gate:
canSwitchModel/Effort/Mode now return false while status === "starting",
so the picker renders as disabled until the backend session is ready.
The await-during-onChange path made the picker feel buggy because clicks
appeared to do nothing for a beat before applying.

* fix(agent-mode): re-render mode/model picker on session status change

The picker hooks compute a memoization signal that React diffs to decide
when to rebuild the override. Status was not part of the signal, so the
starting → idle transition fired listeners but the snapshot string was
unchanged and the picker stayed disabled forever. Include `getStatus()`
in both signals so the picker re-enables once the session is ready.
2026-05-20 19:05:41 -07:00
Zero Liu
ad4bd759a0
feat(agent-mode): tint chat input border and mode picker by mode (#2486)
* feat(agent-mode): tint chat input border and mode picker by mode

Plan mode shows a blue border and soft glow; auto mode shows red.
The mode picker label picks up a matching faded color that brightens
on hover/focus, making the active agent mode obvious at a glance.

* fix(agent-mode): preserve mode tint on keyboard focus

The ghost2 button variant applies focus-visible:tw-text-normal, which
overrode the focus: tint on keyboard focus. Switch to focus-visible:
so tailwind-merge resolves the conflict in favor of the mode color.
2026-05-20 19:05:41 -07:00
Zero Liu
c9ea0f7e1c
fix(agent-mode): preserve persisted enabled flag on mobile (#2484)
* fix(agent-mode): preserve persisted enabled flag on mobile

Sanitization no longer force-overrides agentMode.enabled on mobile, so
a desktop-synced preference is not silently overwritten the next time
mobile persists settings. Mobile gating now lives at usage sites via a
shared isAgentModeEnabled / useIsAgentModeEnabled helper.

* fix(lint): drop unused Platform import in commands/index.ts

The remaining `Platform.isDesktopApp` site uses a dynamic import that
shadows the top-level binding, so the static import is unused after the
agent-mode gating refactor.
2026-05-20 19:05:41 -07:00
Zero Liu
c722d0d9eb
Support agent image and PDF context (#2483)
* Support agent image and PDF prompt context

* Use agent read for PDF context
2026-05-20 19:05:41 -07:00
Zero Liu
02b9ac31c9
Add agent chat autosave resume support (#2482) 2026-05-20 19:05:41 -07:00
Zero Liu
e0c166ac0f
feat(agent-mode): enable by default on desktop, force off on mobile (#2481)
New installs now start with Agent Mode on. Mobile is locked off at the
sanitizer level so a desktop-synced settings file can't activate the
unsupported subprocess flow.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 19:05:41 -07:00
Zero Liu
1205a34612
fix(agent-mode): make binary auto-detect work under Obsidian's sparse GUI PATH (#2480)
macOS GUI apps launched from Finder/Dock inherit a minimal launchd PATH
(`/usr/bin:/bin:/usr/sbin:/sbin`) that omits Homebrew and user install
prefixes, so `which codex-acp` returned nothing and the Auto-detect button
falsely reported "not found." Augment PATH with the well-known prefixes
(`/opt/homebrew/bin`, `/usr/local/bin`) before invoking `which`, sharing
one source of truth with the existing spawn-time augmentation in
`nodeShebangPath`. For Claude, the Auto-detect button now routes through
the existing `resolveClaudeBinary` resolver (Volta/asdf/NVM/Homebrew/
npm-global/`~/.local/bin`) via a new optional `detect` prop on
`BinaryPathSetting`, matching the candidate list already used by the top
status row.
2026-05-20 19:05:41 -07:00