| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(agent): add Claude Code CLI backend Adds a claude-code agent backend so the built-in Agent can run on a Claude subscription through the official claude CLI, with no Anthropic API key — parallel to the existing OpenAI Codex CLI backend. Design differs from Codex in one important way. Claude Code's tool calling is MCP-native, so a turn spawns claude -p pointed at OpenChatCut's own external MCP server (--mcp-config + --strict-mcp-config + --allowedTools mcp__openchatcut-builtin__* + --permission-mode bypassPermissions) and lets Claude's own MCP client execute the tools. OpenChatCut never bridges or settles tool calls the way server/codex/turn-manager.ts does — it only parses the stream-json output for display. Auth stays entirely CLI-owned: status comes from claude auth status --json, and the user runs claude auth login or claude setup-token themselves. No OAuth is reimplemented and no token reaches the browser. ModelBackend grows a third member ('api' | 'codex' | 'claude-code'), which forces every exhaustive switch over it to handle the new backend. Notable details, each verified against the real CLI rather than assumed: - The system prompt is written to a temp file and passed with --append-system-prompt-file. Inline, a real OpenChatCut system prompt overflows the ~32KB Windows command-line cap and spawn fails with ENAMETOOLONG. - tool-start deliberately does not emit a tool-request run event. That event asks the browser to execute a tool and settle it back; since Claude Code already ran the call, the client's /tool-claim 404s and store-recovery then retries the unresolved request on every reload. - Curated models use canonical ids (claude-sonnet-5), not the CLI's short aliases, because the capability catalog is keyed by canonical id — aliases miss every entry and fall through to the estimator. - A built-in capability override caps maxOutputTokens at 64000; the catalog records the API's 128000, but the CLI reports 64000 in modelUsage. - The spawned MCP server is named openchatcut-builtin, never plain openchatcut. Claude Code caches MCP auth failures by server *name* in ~/.claude/mcp-needs-auth-cache.json, and users routinely have their own openchatcut entry — this repo's .mcp.json defines one, deliberately without an Authorization header since the token is generated per server start. Sharing the name let a single unrelated auth failure route this turn's private, correctly bearer-authenticated config into the OAuth path, exposing only authenticate/complete_authentication and hiding all editor tools. --strict-mcp-config does not help: the collision is on the name, not the config source. Known limitation: because tool calls run in Claude Code's own MCP session, they bypass this run's ToolActivation and proposal bookkeeping, so manual approval mode does not gate them the way it gates a Codex turn. Verify scripts cover version parsing, Windows command escaping, the full stream-json event pipeline against a fake CLI, an oversized system prompt, and the model-choice gating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1kuTz49j5Gtf2dbEzQ8mq | 1 个月前 | |
fix(agent): normalize load_skill arguments before schema validation The previous commit normalized load_skill's merged selectors inside the tool executor, but the shared invocation boundary validates against the tool schema first. That schema declares files.minItems=1, file: string and offset: integer, so exactly the filler the normalization exists to absorb — files: [], file: null, offset: "0" — was rejected by Ajv before any tool code ran. The normalization could only ever see calls that were already legal. Move it ahead of validation. execution-policy owns a per-tool normalizer map so every adapter that validates an invocation gets the same cleanup, and validateAgentToolInvocation now returns the normalized arguments rather than a bare ok flag, so callers execute and record what actually passed the schema. Extracted to tools/skill-args.ts and widened while it moved: a bare string on files becomes a one-file batch, a one-element array on file becomes one file, integer-looking strings become integers, and paths are trimmed. When both selectors survive, only a non-zero offset keeps the paged file — offset: 0 on SKILL.md repeats what the initial load already returned, so the batch wins. Wrong-typed values still survive normalization so validation reports them. Shared paths touched, and why unrelated callers are unaffected: - validateAgentToolInvocation (execution-policy.ts) — every tool invocation flows through it. Tools with no registered normalizer take the identity path and validate the exact object they passed in; the returned args are then the same reference. Only load_skill has an entry. - effectiveToolInvocationArgs / the codex tool boundary (codex/runtime.ts) — now records validation.args instead of the raw args, so the run ledger and the executed call agree. For every tool but load_skill these are identical. - validateExternalInvocation (external-tool-schemas.ts) — returns the validated form for the same reason; external tools register no normalizer. Verification: - npx tsc -b --force clean (bare tsc --noEmit is a no-op on the solution tsconfig and reported nothing). - npm run lint 0 warnings; npm run verify:affected 178 passed. - New boundary coverage in harness-runtime.verify.ts asserts the executor receives normalized arguments, the tool event carries them, and a genuine violation (files: 123) never reaches the executor. - Real agent link test, dev server on 5199, deepseek-v4-flash-vision-exp: "Load the talking-head-guide skill and quote its first two steps verbatim." Observed chain: manage_skill list, then load_skill · talking-head-guide returning the skill body; the agent quoted it verbatim and left the timeline untouched (context ~18k to ~36k). A wrong slug returned the domain error no such skill "clean-talking-head-edit" from the executor rather than an argument rejection, and the agent recovered by suggesting the right skill. The organic merged-selector shape is not reproducible on demand; it stays covered by the unit assertions above. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 1 个月前 | |
fix: integrate Copilot runtime with isolated startup and streamed tools Merge current main and repair bundled CLI resolution, SDK streaming, Auto model discovery, and optional-backend startup. Remove unrelated persistence changes so existing API and Codex save paths retain their behavior. Validation: tsc -b, lint, verify:server-runs, appShell startup isolation regression, production build, and desktop main bundle passed. Real CLI 1.0.82 authenticated through gh-cli and streamed READY. Chrome selected Copilot Auto and executed set_aspect_ratio plus read_timeline through browser tool claims and results, returning the portrait canvas response. | 1 个月前 | |
feat(media): support project files and DeepSeek vision Add DeepSeek vision capability metadata and preserve documents and generic files as project assets. Shared path impact: media import now accepts project-only files, while explicit timeline guards keep existing audio, video, and image editing behavior unchanged. Persistence normalization preserves both legacy and new asset kinds. Verification: live DeepSeek model listing plus text and image requests; browser import, reload, AI document attachment, and model discovery; npx tsc -b --force; npm run lint; npm run verify:affected; TEST_CONCURRENCY=4 npm test; npm run build. | 2 个月前 | |
feat: add autonomous agent acceptance loop Keep the feature disabled by default and expose a bounded verification loop with inspector status.\n\nVerified with affected checks, type checking, lint, build, full tests, and six real-model Browser4 scenarios. | 2 个月前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 9 天前 | |
feat(import): start every URL in a download batch download_media and push_asset stopped starting URLs 75 seconds into a batch, and the tool description asked the model for at most three URLs per call. The window (b6667db6) only kept a batch inside the AI SDK chunk watchdog, which used to keep counting while a tool ran. Since ai 7.0.136 the watchdog stops when the model response ends and tool time only counts against the run's step and tool timeouts, so the window did nothing but turn work away. Each URL stays bounded on its own by the connect and response-header limits of /api/import-url. serialBatch now runs every URL in order, one at a time, with one row per URL. The tool description and the generated server tool catalog drop the window and the three-URL advice, and stock-tools.verify checks the order, the one-at-a-time execution and that a failed row does not stop the URLs after it. Verification: npx tsc -b, npm run lint, npm test (197 segments) and npm run build pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 | |
docs: translate code comments to English | 3 个月前 | |
docs: translate code comments to English | 3 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
fix: make local VAD silence removal reachable and warm installed local models Three capabilities existed in the tree but could never run. The VAD-backed silence removal was gated only by the build-time VITE_ENABLE_VAD_SILENCE_REMOVAL flag, so released builds carried the tracked Silero model (public/models/silero-vad, ~13MB) as unreachable bytes and remove_silence always refused to cut. The three desktop native warm-up entry points and ensureSileroVad had zero call sites, so those workers always cold-started on first use. runAgent had no production and no test caller. - Add src/audio/vadPreference.ts: a device-local tri-state preference (cc.vadSilenceRemoval). An unchosen preference still defers to the build flag, so builds that shipped the flag keep their behaviour and every other build stays disabled until the user opts in. - Move the single gate vadSilenceRemovalEnabled(storage?, buildFlag?) out of vad.ts so both inputs are injectable and truthiness is normalized in exactly one place; vad.ts keeps runner registration and evidence logic only. - Expose the toggle in Settings > Local models > Local transcription with zh/en/it/ru copy, and point the disabled remove_silence note at that location so the agent can guide the user. - Warm only model packs already reported installed. Pack status is checked first because a load request for a missing pack fails pack verification, and the rhythm and CLAP adapters treat a failed load as "native unavailable for this session", which would disable the native path until reload. Preloading never downloads a model. - Warm the bundled Silero model on idle only when the preference is on. - Remove runAgent together with the helpers it exclusively owned (runPreparedAgent, runCodexBackend, createContextRepreparer, contextRecord, toCodexToolSpec) and the orphaned imports. The comment claiming three verifies keep it alive was wrong: those verifies exercise runCodexAgent and runApiAgent directly. runtime.ts drops from 427 to 179 lines and the runtime chunk from 231.63 kB to 194.60 kB (gzip 71.01 -> 59.56). Shared paths touched, and the evidence they stay intact: - Silence gate (src/audio/vad.ts, src/audio/silence.ts): with no stored preference the gate is false and analyzeClipSilence short-circuits before fetching the source; a real browser session issues zero silero/ort requests when the editor opens. - src/agent/runtime.ts, which hosts the live executeCodexTool used by every server-run tool call: a real DeepSeek turn executed read_project in the browser and answered "Canvas width x height: 1080 x 1920. No modifications made (read-only)." - src/hooks/useInferenceWarmup.ts: the existing ASR warm-up path is unchanged; native warm-up runs only for installed packs and the VAD warm-up only for opted-in users. - src/components/settings/LocalAsrPane.tsx: the toggle renders, reflects the stored value, persists '0'/'1', and keeps its state across a panel reopen. Enabled-path proof: on a 5.18s Chinese speech sample Silero returned confidence 0.942 with speech spans 160-480 ms and 576-5152 ms in 773 ms, and the conservative intersection correctly removed nothing because the clip is speech throughout. Verification: tsc -b clean, oxlint clean, npm run build clean, npm test 178/179 segments pass. The single failure is pre-existing on main and untouched here: verify-gate-coverage flags server/keystore.ts at 502 lines. The new verify src/audio/vadPreference.verify.ts is registered in verify:captions. | 1 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
perf(asr): default to base tier and extend transcribe tool timeout Measured in-browser: wasm small runs at RTF ~0.9 (a 10-min clip takes ~9 min) while base is ~2.5x faster, so the automatic tier selection now stays on base for everyone (small/medium remain explicit choices). The transcribe_track AI SDK timeout rises from 5 to 15 minutes: the old 5-min window was shorter than a long clip's wasm inference, so long local transcriptions were always killed mid-run; 15 min covers base on a 15-min clip (~5 min) and small on the same clip (~13 min) while still bounding a stuck worker. | 2 个月前 | |
feat(agent): add model-aware context compaction Use provider-reported usage when available and fall back to model-aware estimates. Compact older turns before limits while preserving recent context across API and Codex backends. | 2 个月前 | |
fix(agent): keep model reply on tool failure, drop injected failure template The api runtime (completeRound/completeAborted/failRound) and the codex runtime (unresolvedFailureCompletion) no longer discard the model's own text nor inject the 'I couldn't complete the requested operation...' template when a turn ends with unresolved tool failures. The model saw the failed tool result in its own context and replies freely, so the final assistant message is its own reply in the interface language. Removed ApiRoundOutput.failureCompletion and its now-unused tracker field; the unresolved-failure tracker still records/clears for retry context but no longer drives a terminal message. report() stays as a tested tracker accessor. Shared paths touched: in-app agent run loop (api + codex runtimes), tool-failure tracker. Verified: tsc -b --force, oxlint, ai-sdk / codex-runtime / useAgentHistoryActions verifies. | 2 个月前 | |
feat(agent): remove the cost guard approval gate entirely Users picked this product for speed; a confirmation card before paid or persistent tools added friction. The whole cost-guard layer is deleted: - skills/costGuard.ts (paid-tool registry, remember authorization, proposal auto-apply interception) and runtime-guard.ts (guard card construction) are removed; the paid-surface registry in agentSettings is gone too. - codex/runtime.ts executes every validated tool directly: the request-approval chain, deny results, and the skill-guard callback are deleted. The browser and server-run pendingGuard plumbing (executor, state, protocol, controller actions, UI card) is removed end to end. - The proposal auto-apply gate now follows the user toggle directly; the high-cost badge on proposal cards and the guard i18n copy are removed. - Paid tools keep their recovery classification: the execution policy still marks generation/export/transcription/web/sandbox as non-idempotent (outcome_unknown) so failed invocations are never replayed automatically, and offline authorization still rejects them. Preserved: parameter validation, edit-proposal approval, the auto-apply preference, external-agent real-project approval, and the approval ledger for the run inspector. Shared-path impact: tool execution boundary (codex/runtime.ts, execution-policy.ts) and both pendingGuard UI chains. Every mutating tool now runs without a card, which is the requested product behavior; proposal application and external-bridge approval are unchanged. Validation: tsc -b --force clean, lint 0 warnings, all touched verifies pass (execution policy, harness runtime, hydration recovery, executor, recovery, settings, job registry), full suite shows only the two pre-existing environmental failures, production build passes, and a real edit task ran punch animation straight through with no card. | 2 个月前 | |
chore(release): prepare v0.2.0 Harden project storage, upload finalization, export recovery, watched-folder ownership, and native inference lifecycle boundaries. Add cross-platform desktop update packaging and checksum-gated GitHub Release publication while preserving the public v3 project schema, existing media URL semantics, and opt-in defaults. Verified with TypeScript project builds, zero-warning lint, the full test suite, production build, and a browser create/import/edit/reload/close-reopen smoke. | 2 个月前 | |
fix(agent): align execution modes and verification Align Ask and YOLO UI, prompt, documentation, and comments with direct built-in tool execution while preserving proposal application behavior and the external MCP approval boundary. Fix the proposal durability test fixture and split oversized runtime verification and external global-read code without changing execution order. Shared paths: agent prompt and composer mode registry, proposal verification, external global reads, and server-run/Codex verification. Validation: npx tsc -b --force; npm run lint; npm test (97/97); npm run build; browser read_timeline E2E. | 2 个月前 | |
fix(agent): align execution modes and verification Align Ask and YOLO UI, prompt, documentation, and comments with direct built-in tool execution while preserving proposal application behavior and the external MCP approval boundary. Fix the proposal durability test fixture and split oversized runtime verification and external global-read code without changing execution order. Shared paths: agent prompt and composer mode registry, proposal verification, external global reads, and server-run/Codex verification. Validation: npx tsc -b --force; npm run lint; npm test (97/97); npm run build; browser read_timeline E2E. | 2 个月前 | |
fix(agent): align sync_images_to_music with sync_cuts_to_music on the external gate Both music-driven sync tools apply batched timeline edits from the global music analysis store, but sync_images_to_music was draft-whitelisted while its twin ran as an approval-gated real-project edit for external MCP/Codex agents. Removing the draft entry makes both real; approval-policy.verify now pins the pair to the same classification. | 2 个月前 | |
feat(agent): reduce context token usage | 2 个月前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 9 天前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 9 天前 | |
feat(agent): land pool imports as each tool finishes instead of when the run ends A downloaded file sat invisible until the whole run ended: addAsset actions were recorded as "persistent" during the run but committed to the live project only at terminal time, behind a check that the project had not changed since the run began. The user watched download_media succeed and saw nothing in the media pool. Pool imports now land right after the tool that produced them. Assets are additive, so they are replayed onto whatever the project is at that moment: a user edit made while the agent was downloading neither blocks the import nor gets overwritten — the save is the fence, and if the project moved during it the live document is put back and the import replayed on top (covered by a race test). One change-log row per run collects every landing and rolls all of them back together. The draft-invalidation check now compares the live project against the proposal base, which already carries the run's own landings; comparing against the original base read those landings as a foreign edit and refused the run's timeline edits, which would have broken every "download it, then place it" request. Verified end to end with deepseek-v4-flash: flower.mp4 appeared in the pool with its own "素材已加入媒体池" change-log row while the run went on to place the clip on V1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): land pool imports as each tool finishes instead of when the run ends A downloaded file sat invisible until the whole run ended: addAsset actions were recorded as "persistent" during the run but committed to the live project only at terminal time, behind a check that the project had not changed since the run began. The user watched download_media succeed and saw nothing in the media pool. Pool imports now land right after the tool that produced them. Assets are additive, so they are replayed onto whatever the project is at that moment: a user edit made while the agent was downloading neither blocks the import nor gets overwritten — the save is the fence, and if the project moved during it the live document is put back and the import replayed on top (covered by a race test). One change-log row per run collects every landing and rolls all of them back together. The draft-invalidation check now compares the live project against the proposal base, which already carries the run's own landings; comparing against the original base read those landings as a foreign edit and refused the run's timeline edits, which would have broken every "download it, then place it" request. Verified end to end with deepseek-v4-flash: flower.mp4 appeared in the pool with its own "素材已加入媒体池" change-log row while the run went on to place the clip on V1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix: preserve offline edits and optimize editor workflows Recover conflicting offline project documents into verified, retry-safe copies without replacing the original project. Harden skill installation and media stream handling, deduplicate loudness work, reuse transcript projections, and load sequence options only when needed. Split oversized source modules while preserving their public exports. Expand affected verification coverage, add a macOS frame-sync CI job, and update vulnerable media dependency overrides. Shared-path impact: - Persistence recovery runs only for pending conflicting documents. Normal saves keep their existing format, media URLs, and ownership rules. Recovery confirms document and index writes before clearing pending state. - Agent and UI loudness paths retain existing volume limits and undo behavior; repeated sources share bounded analysis and stale sources are rejected. - Transcript, caption, preview, export, server, and desktop module moves keep existing call contracts. Differential checks cover projections and stored job reports; media transport checks cover ranges, empty files, and aborts. Validation: - Full TypeScript project build, zero-warning lint, and production build passed. - npm test preflight passed; all 172 test segments passed after registering the new verification files (TEST_CONCURRENCY=2 npm run test --ignore-scripts). - Final persistence changes passed project-store transport and recovery checks, lint, build, and the 561-verification gate coverage check. - npm audit --omit=dev reported zero vulnerabilities. - Real DeepSeek Agent invoked add_audio and normalize_loudness successfully. Browser checks covered import, save/reopen, undo/redo, and offline recovery with the original project and recovered media preserved. - Native macOS frame-sync checks and real FFmpeg media checks passed. The new remote macOS CI job has not yet run. | 1 个月前 | |
fix(agent): gate history shaking, localize overflow guidance, route missing-pack button Three follow-ups to the overflow-recovery work: - prepareContext no longer shakes stale tool results below the compaction trigger. Shaking is a compaction strategy; the previous version rewrote the model-visible history on every happy-path run. Under pressure the mechanical trim still runs first and recovers the budget without an LLM summary. - contextOverflowGuidance is locale-aware: the guidance now renders through t() (en users get the English entry that was previously dead dictionary data), and extractOverflowOriginal round-trips both spellings. - The chat missing-model-pack button now passes the tool result's settingsRoute to onOpenSettings, and SettingsDialog accepts initialVendor so the dialog opens on the model-pack page instead of the default pane. Shared paths: prepareContext (happy path restored to pre-shake behavior), chat onOpenSettings signature (route is optional; CapabilityGapBanner and other callers pass none), SettingsDialog (initialVendor is optional and defaults to the previous first-page selection). Verification: context-compaction and context-overflow-guidance verifies pass (shake gating and en-localization assertions added); 108 affected verifies pass; tsc -b clean; oxlint 0 warnings. | 1 个月前 | |
feat(agent): add GitHub Copilot as an agent backend Drive Copilot in-app through @github/copilot-sdk, alongside the existing api and codex backends, rather than only exposing OpenChatCut over MCP. The SDK is a direct analogue of the codex app-server integration, so this mirrors server/codex/ closely: - server/copilot/installation.ts discovers the CLI (bundled platform package, PATH, common install roots, OPENCHATCUT_COPILOT_PATH) - server/copilot/client.ts owns one runtime with an isolated COPILOT_HOME (~/.openchatcut/copilot) so in-app runs never disturb the user's own ~/.copilot, and caches the model catalog - server/copilot/turn-manager.ts registers OpenChatCut's tool catalog as SDK tools with in-process handlers and maps session events onto the same stream-event union the codex backend emits Host tools are the whole tool surface: availableTools is restricted to custom tools, so the agent has no shell, filesystem, web or MCP access, and any permission request is rejected as a filter escape. Copilot reports exact per-model limits, so capabilities come from resolveCopilotModelCapabilities rather than the bundled models.dev catalog, and models are attributed to their upstream provider (claude-* -> anthropic, grok-* -> xai) so capability overrides and vision selection keep working. Models without tool support are hidden. Two details worth recording: - tool failures return a typed ToolResultObject; throwing collapses to a generic "Tool execution failed" and strips the diagnostic the agent needs to recover - __images results are handed over as binary attachments, matching the codex backend's inputImage handling, so frame contact sheets remain viewable instead of being stringified into the prompt The turn uses an idle timeout rather than a wall-clock cap: a long edit streams continuously for many minutes and must not be killed for total elapsed time. It is suspended while a host tool is in flight, bounded by the broker's own maximum so a never-settled call cannot hang the turn. Auth stays with the CLI (copilot login); OpenChatCut never sees the credential and the settings pane is read-only status plus model choice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> | 1 个月前 | |
fix: preserve offline edits and optimize editor workflows Recover conflicting offline project documents into verified, retry-safe copies without replacing the original project. Harden skill installation and media stream handling, deduplicate loudness work, reuse transcript projections, and load sequence options only when needed. Split oversized source modules while preserving their public exports. Expand affected verification coverage, add a macOS frame-sync CI job, and update vulnerable media dependency overrides. Shared-path impact: - Persistence recovery runs only for pending conflicting documents. Normal saves keep their existing format, media URLs, and ownership rules. Recovery confirms document and index writes before clearing pending state. - Agent and UI loudness paths retain existing volume limits and undo behavior; repeated sources share bounded analysis and stale sources are rejected. - Transcript, caption, preview, export, server, and desktop module moves keep existing call contracts. Differential checks cover projections and stored job reports; media transport checks cover ranges, empty files, and aborts. Validation: - Full TypeScript project build, zero-warning lint, and production build passed. - npm test preflight passed; all 172 test segments passed after registering the new verification files (TEST_CONCURRENCY=2 npm run test --ignore-scripts). - Final persistence changes passed project-store transport and recovery checks, lint, build, and the 561-verification gate coverage check. - npm audit --omit=dev reported zero vulnerabilities. - Real DeepSeek Agent invoked add_audio and normalize_loudness successfully. Browser checks covered import, save/reopen, undo/redo, and offline recovery with the original project and recovered media preserved. - Native macOS frame-sync checks and real FFmpeg media checks passed. The new remote macOS CI job has not yet run. | 1 个月前 | |
fix(agent): gate history shaking, localize overflow guidance, route missing-pack button Three follow-ups to the overflow-recovery work: - prepareContext no longer shakes stale tool results below the compaction trigger. Shaking is a compaction strategy; the previous version rewrote the model-visible history on every happy-path run. Under pressure the mechanical trim still runs first and recovers the budget without an LLM summary. - contextOverflowGuidance is locale-aware: the guidance now renders through t() (en users get the English entry that was previously dead dictionary data), and extractOverflowOriginal round-trips both spellings. - The chat missing-model-pack button now passes the tool result's settingsRoute to onOpenSettings, and SettingsDialog accepts initialVendor so the dialog opens on the model-pack page instead of the default pane. Shared paths: prepareContext (happy path restored to pre-shake behavior), chat onOpenSettings signature (route is optional; CapabilityGapBanner and other callers pass none), SettingsDialog (initialVendor is optional and defaults to the previous first-page selection). Verification: context-compaction and context-overflow-guidance verifies pass (shake gating and en-localization assertions added); 108 affected verifies pass; tsc -b clean; oxlint 0 warnings. | 1 个月前 | |
fix(agent): gate history shaking, localize overflow guidance, route missing-pack button Three follow-ups to the overflow-recovery work: - prepareContext no longer shakes stale tool results below the compaction trigger. Shaking is a compaction strategy; the previous version rewrote the model-visible history on every happy-path run. Under pressure the mechanical trim still runs first and recovers the budget without an LLM summary. - contextOverflowGuidance is locale-aware: the guidance now renders through t() (en users get the English entry that was previously dead dictionary data), and extractOverflowOriginal round-trips both spellings. - The chat missing-model-pack button now passes the tool result's settingsRoute to onOpenSettings, and SettingsDialog accepts initialVendor so the dialog opens on the model-pack page instead of the default pane. Shared paths: prepareContext (happy path restored to pre-shake behavior), chat onOpenSettings signature (route is optional; CapabilityGapBanner and other callers pass none), SettingsDialog (initialVendor is optional and defaults to the previous first-page selection). Verification: context-compaction and context-overflow-guidance verifies pass (shake gating and en-localization assertions added); 108 affected verifies pass; tsc -b clean; oxlint 0 warnings. | 1 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add GitHub Copilot as an agent backend Drive Copilot in-app through @github/copilot-sdk, alongside the existing api and codex backends, rather than only exposing OpenChatCut over MCP. The SDK is a direct analogue of the codex app-server integration, so this mirrors server/codex/ closely: - server/copilot/installation.ts discovers the CLI (bundled platform package, PATH, common install roots, OPENCHATCUT_COPILOT_PATH) - server/copilot/client.ts owns one runtime with an isolated COPILOT_HOME (~/.openchatcut/copilot) so in-app runs never disturb the user's own ~/.copilot, and caches the model catalog - server/copilot/turn-manager.ts registers OpenChatCut's tool catalog as SDK tools with in-process handlers and maps session events onto the same stream-event union the codex backend emits Host tools are the whole tool surface: availableTools is restricted to custom tools, so the agent has no shell, filesystem, web or MCP access, and any permission request is rejected as a filter escape. Copilot reports exact per-model limits, so capabilities come from resolveCopilotModelCapabilities rather than the bundled models.dev catalog, and models are attributed to their upstream provider (claude-* -> anthropic, grok-* -> xai) so capability overrides and vision selection keep working. Models without tool support are hidden. Two details worth recording: - tool failures return a typed ToolResultObject; throwing collapses to a generic "Tool execution failed" and strips the diagnostic the agent needs to recover - __images results are handed over as binary attachments, matching the codex backend's inputImage handling, so frame contact sheets remain viewable instead of being stringified into the prompt The turn uses an idle timeout rather than a wall-clock cap: a long edit streams continuously for many minutes and must not be killed for total elapsed time. It is suspended while a host tool is in flight, bounded by the broker's own maximum so a never-settled call cannot hang the turn. Auth stays with the CLI (copilot login); OpenChatCut never sees the credential and the settings pane is read-only status plus model choice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> | 1 个月前 | |
fix(agent): surface long tool progress and fix execution label The chat run status showed 'writing arguments…' for the whole execution phase (the server never streams tool-input deltas, so the label only ever appeared while a tool was actually running), and long tools like local ASR gave zero feedback while the whisper model loaded. Tools can now report progress through AgentContext.onToolProgress, wired to the live-tool line (transcribe_track reports model load/download notes). Empty progress shows 'running…' instead of 'writing arguments…'. Shared paths: AgentContext gains an optional callback (degraded safely when absent); chat i18n gains one string. No schema change, server tool catalog unaffected. Verified: serverRunToolExecutor.verify, transcript-tools.verify, verify:i18n, tsc -b, oxlint. | 2 个月前 | |
refactor(auth): drop launch-token and editor-credential handshakes Local trust now rests on the request shape alone: loopback binding + Host check + matching Origin + browser-enforced Sec-Fetch-Site for the project store writes; loopback host + Origin for editor endpoints (uploads, model packs, ASR, external-agent bridge). Removed: /session exchange endpoint, launch token persistence, process-local sessions, the no-auth escape hatch env var, and every credential header on the browser side; editor bootstrap now exposes only the MCP token (external-agent Bearer mechanism unchanged). Shared paths touched: server/project-store-http-auth.ts (write gate), server/editor-auth.ts, server/plugins/project-store-plugin.ts, src/persist/projectStoreTransport.ts, src/agent/editor-credential.ts and the external-agent bridge registration helpers. Existing behavior is preserved for non-loopback callers (rejected) and the desktop shell. Verification: tsc -b --force clean, oxlint 0 warnings, full npm test (89 verifies) green, production build passes, and a real-browser smoke on localhost:5199 renders the editor and performs project-store reads and writes from a bare URL without any token. | 2 个月前 | |
fix(captions,export): template fallback, translation staleness, FCPXML retime - CAPTION_STYLE_BY_ID was indexed raw in six places, so a template id this build does not know (a project saved by a NEWER build) yielded undefined and the first preset.fontFamily access threw — taking down preview AND export instead of degrading. New captionStyleFor() resolves to the 'plain' preset for unknown/absent/non-string ids; all six sites use it. Persisted template ids are untrusted input. - Translation cues store ABSOLUTE timeline ms, and nothing invalidated them: deleting words or moving the source clip left the translated line pinned to old positions, silently under the wrong phrases. buildTranslation now also returns a timing fingerprint stored as captions.translationFingerprint; isTranslationStale compares it against live timing and the captions panel shows a re-translate hint. Older translations without a fingerprint are never reported stale. - FCPXML dropped playbackRate entirely: a 2x clip imported at 1x and showed only the first half of its span. Rate-stretched clips now emit a <timeMap> mapping the clip's timeline duration to the source span it consumes (duration x rate), plus an XML comment recording the intended rate. - FCPXML collectAssets let the FIRST item referencing a src fix its kind, so a file used as audio and also as video exported audio-only and the video clip imported black. The visual kind now wins. Shared paths touched: caption style resolution (preview, export, manual captions, agent caption tools), translation generation (panel, style menu, agent bilingual tool), FCPXML export. Known templates and rate-1 clips are byte-identical to before. NOT verified: the emitted <timeMap> has not been round-tripped through Final Cut Pro or Resolve — only the mapping arithmetic is asserted. The intended rate is written as an XML comment so an integrator can check. Verification: tsc -b --force clean; oxlint 0 warnings (also fixed two constant-comparison warnings in the execution-modes verify added in the previous commit); new captionFallback.verify covers unknown/undefined/ non-string template fallback, effectivePreset no longer throwing, the staleness three-way (fresh / retimed / legacy-without-fingerprint), and the FCPXML timeMap + mixed-kind asset; existing fcpxml.verify and fcpxml-background-fill.verify pass; 105 verifies across captions/export/ agent-tools run with 2 failures (effect-tools, library-edit-item) that reproduce on a clean tree (ERR_UNKNOWN_FILE_EXTENSION, pre-existing). Browser smoke on localhost:5199: editor and Captions panel render with no application console errors. | 1 个月前 | |
fix(agent): name offending fields in tool schema validation errors Root-level extra properties on strict schemas (edit_item's additionalProperties:false, issue #135) were reported as bare "/ must NOT have additional properties" — ajv keeps the field name in params.additionalProperty, which issueText dropped. The model got an unactionable error, retried the same shape, and every call died before the handler's friendly unknown-field path could run. issueText now appends the offending property for additionalProperties and unevaluatedProperties keywords, so the error reads "/ must NOT have additional properties: \"itemId\"" and models can self-correct. This also improves what the Codex backend sees in its validation_failed summary. Shared paths: validateAgentToolInvocation error formatting for every tool. Valid calls are unaffected; rejection behavior is unchanged — only the error text gained the field name. No verify asserted the old bare message (only the "Invalid arguments for tool" prefix, which is preserved). Verification: execution-policy-args.verify.ts extended with edit_item rejection/acceptance cases; end-to-end probe prints both offending field names; 47 affected verifies pass; tsc -b clean; oxlint 0 warnings. Real agent chain (dev server 5199 + deepseek-v4-flash-vision-exp, isolated dev profile, dedicated throwaway project deleted afterwards): sent "add a red solid clip (3s at 1s), then move it right 24 frames" and observed edit_item {"adds":[{"type":"solid","color":"#ff0000", "fromFrame":30,"durationInFrames":90,"track":"V1"}]} validate and execute, then move_item {itemId item_6735ba00-…, track V1, startFrame 54}; the final reply reported the clip at frame 54 / 90 frames and the inspector showed the selected solid clip at 00:03.00 — canonical calls pass the shared validation path unchanged. The improved error text was exercised by the unit probe because a real model cannot be forced to emit invalid args deterministically. Screenshot: output/playwright/agent-e2e-edit-item.png | 1 个月前 | |
feat(publish): publish finished renders to social platforms via Upload-Post Adds publish_to_social / track_social_publish so the agent can post a completed render (the /media/uploads/ downloadUrl from track_export) to TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest and Bluesky through Upload-Post. - Two steps by contract: without confirm the server only previews (file, profile, connected/missing platforms, title, privacy); confirm:true uploads. - request_id is derived from the file and the publish fields and doubles as the Idempotency-Key: re-sending an approved publish resumes it, a dropped connection never re-uploads. - File-backed multipart via openAsBlob and the shared outbound proxy, as sonilo-media does; YouTube defaults to private. - Settings → Enhanced tools → Social publishing (key + profile), key probe, en/it/ru strings, routing, execution policy (irreversible_external). - server/plugins/upload-post.verify.ts and src/agent/tools/publish-tools.verify.ts run against a local fake API and a mocked fetch; no network in the suite. | 30 天前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix(agent): swallow transient bridge 409 instead of flashing a blocking alert A poll/registration/cancellation HTTP 409 in the external editor bridge is a recoverable condition: runBridge re-registers within ~1s, so the previous behavior of surfacing '工程正在其他窗口编辑,连接已中断。请关闭其他窗口后重试。' produced an alarming flash on every transient lease/registration mismatch even for single-window users. Swallow any 409 in handleExternalBridgeAttemptError so the retry loop recovers silently; genuine non-409 errors still surface. Shared-path impact: - external-bridge-attempt-error: a 409 (any operation) returns without calling onError (silent retry). 401 credential handling and generic-error surfacing are unchanged. - external-bridge-attempt-error.verify: updated to assert 409 is retried silently (no message, no reload) while a non-409 error still surfaces. Verification: npx tsc -b exit 0; npm run lint 0 warnings; external-bridge-attempt-error.verify passes. | 2 个月前 | |
fix(agent): swallow transient bridge 409 instead of flashing a blocking alert A poll/registration/cancellation HTTP 409 in the external editor bridge is a recoverable condition: runBridge re-registers within ~1s, so the previous behavior of surfacing '工程正在其他窗口编辑,连接已中断。请关闭其他窗口后重试。' produced an alarming flash on every transient lease/registration mismatch even for single-window users. Swallow any 409 in handleExternalBridgeAttemptError so the retry loop recovers silently; genuine non-409 errors still surface. Shared-path impact: - external-bridge-attempt-error: a 409 (any operation) returns without calling onError (silent retry). 401 credential handling and generic-error surfacing are unchanged. - external-bridge-attempt-error.verify: updated to assert 409 is retried silently (no message, no reload) while a non-409 error still surfaces. Verification: npx tsc -b exit 0; npm run lint 0 warnings; external-bridge-attempt-error.verify passes. | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix(mcp): harden recovery and result transport Reserve orphaned edit sessions before dispatch so concurrent transports cannot overwrite recovery ownership, and release reservations after failed or cancelled calls. Keep browser-only recovery tools out of the offline catalog. Carry bounded multimodal editor results through a dedicated 16 MiB result route with a byte-accurate 12 MiB image budget, while retaining the 2 MiB control-request limit. Split shared broker, MCP, and bridge responsibilities below the source-file limit and add the missing English UI labels. Shared path impact: external MCP broker ownership, MCP tool exposure, and the editor bridge result endpoint. Built-in Agent and non-result bridge requests retain their previous behavior; the larger request budget is isolated to authenticated POST /result traffic. Validation: TypeScript build, zero-warning lint, verify:affected, targeted broker/offline/projection/MCP checks, i18n verification, full test suite, and production build. | 1 个月前 | |
fix(agent): gate external bridge on transport Direct browser editor sessions use IndexedDB and may not have a project-store launch token. Avoid starting the optional external MCP bridge when no remote transport is available. | 2 个月前 | |
fix(agent): close external MCP durability and security gaps found by full-tool e2e Shared paths touched: request-shape gate (all non-GET writes), external-agent broker/registry/binding (MCP + editor bridge), bridge routes, browser bridge registration/poll/result plumbing, and two verifies. Fixes, each reproduced and re-verified against a real browser editor + real MCP client sweeping all 118 tools: - upload handoff: the global request-shape gate 403'd legitimate MCP-client uploads (no Origin header). The /upload?handoff= token is single-use, scope-bound and verified by the upload endpoint itself, so the gate now lets handoff uploads through to that check. Verified: import_media -> HTTP upload -> finalize_uploaded_asset succeeds end-to-end (previously http 403). - registry revision sync: a tool settle reported the browser doc revision, but autosave could land after the settle, leaving the registry (and the store ownership) one revision behind and poisoning the next MCP session as stale. The settle route now syncs the registry to the post-tool revision, the registry touch adopts the store's authoritative revision (renewed claim), and the browser flushes pending project saves before reporting a tool result. Verified: consecutive MCP sessions bind to a consistent revision. - orphaned edit sessions: a closed/crashed MCP transport left its drafting session wedged ("An edit session is already active") with no owner able to discard it. cancelEditorCallsForOwner now emits an owner-gone signal through the cancellation queue, and the browser poll discards those sessions. Verified: sweep sessions no longer wedge begin_edit_session. - stale-tab false positives: a same-editor revision advance between bind and invoke (autosave landing) was treated as a stale takeover and permanently poisoned the MCP session. Sessionless calls (begin_edit_session, reads) now adopt the registry's current binding when the editor identity matches; control tools and edit-session-carrying calls stay strict so the stale-tab guard is unchanged. Verified: broker/mcp verifies still enforce stale semantics for mutations and control reads. - verifies updated: external-agent.verify mock gains editorCallBinding/ touchEditor and the capability-less browser re-claim assertion (claim gate re-issues ownership by design since 48ae9a1); broker.verify asserts the adopted-call behavior instead of a stale throw. Validation: tsc -b --force clean, oxlint 0 warnings, verify:affected 4/4 (request-shape-gate, external-agent, mcp, broker), real MCP client sweep 95/100 tool calls against a live editor (import, draft edits, review apply, export session A), remaining failures are test-harness session-timing noise, not tool failures. Known follow-up (pre-existing, not introduced here): a committed write can still leave the store ownership record one revision behind the project document; renew then refuses and the editor reloads to recover. Needs a dedicated ownership-sync pass. | 2 个月前 | |
fix(mcp): preserve ownership when reusing active drafts | 26 天前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat: land professional timeline, durable jobs, and safe media flows Add slip/rate-stretch, nested sequences, multicam sync, durable generation/export recovery, media intelligence, and hardened MCP/media boundaries while keeping the implementation local-first and cross-platform. | 2 个月前 | |
Update src/agent/external-draft-persistence.verify.ts for MCP recovery | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix(mcp): preserve unlocked recovery semantics Keep browser takeover lock-free while preserving offline writer fencing, retain begin-session error compatibility, and document orphan recovery in the distributed skill. Shared paths: browser registration ownership, external session startup, MCP instructions, and skill recovery guidance. Verified with focused recovery checks, MCP transport integration, TypeScript, oxlint, and diff-check. | 1 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
fix(mcp): close refresh and orphan recovery gaps | 2 个月前 | |
fix(mcp): support reuseExisting in begin_edit_session to adopt active draft sessions When an external MCP agent reconnects or executes consecutive turns while an edit session is in drafting status, calling begin_edit_session rejected with a conflict error ("An edit session is already active"). Because transport ownership was locked to ephemeral HTTP connection UUIDs, external agents encountered recovery deadlocks and timeouts. This adds an optional reuseExisting boolean parameter to begin_edit_session in both connected and offline runtimes. When set to true, the active drafting session is adopted and returned directly, allowing the broker to bind the caller as the active owner and continue editing seamlessly without breaking existing single-session conflict rejection tests. | 26 天前 | |
fix(agent): align execution modes and verification Align Ask and YOLO UI, prompt, documentation, and comments with direct built-in tool execution while preserving proposal application behavior and the external MCP approval boundary. Fix the proposal durability test fixture and split oversized runtime verification and external global-read code without changing execution order. Shared paths: agent prompt and composer mode registry, proposal verification, external global reads, and server-run/Codex verification. Validation: npx tsc -b --force; npm run lint; npm test (97/97); npm run build; browser read_timeline E2E. | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
fix(agent): align execution modes and verification Align Ask and YOLO UI, prompt, documentation, and comments with direct built-in tool execution while preserving proposal application behavior and the external MCP approval boundary. Fix the proposal durability test fixture and split oversized runtime verification and external global-read code without changing execution order. Shared paths: agent prompt and composer mode registry, proposal verification, external global reads, and server-run/Codex verification. Validation: npx tsc -b --force; npm run lint; npm test (97/97); npm run build; browser read_timeline E2E. | 2 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
fix(mcp): harden recovery and result transport Reserve orphaned edit sessions before dispatch so concurrent transports cannot overwrite recovery ownership, and release reservations after failed or cancelled calls. Keep browser-only recovery tools out of the offline catalog. Carry bounded multimodal editor results through a dedicated 16 MiB result route with a byte-accurate 12 MiB image budget, while retaining the 2 MiB control-request limit. Split shared broker, MCP, and bridge responsibilities below the source-file limit and add the missing English UI labels. Shared path impact: external MCP broker ownership, MCP tool exposure, and the editor bridge result endpoint. Built-in Agent and non-result bridge requests retain their previous behavior; the larger request budget is isolated to authenticated POST /result traffic. Validation: TypeScript build, zero-warning lint, verify:affected, targeted broker/offline/projection/MCP checks, i18n verification, full test suite, and production build. | 1 个月前 | |
fix(mcp): close refresh and orphan recovery gaps | 2 个月前 | |
fix(mcp): harden recovery and result transport Reserve orphaned edit sessions before dispatch so concurrent transports cannot overwrite recovery ownership, and release reservations after failed or cancelled calls. Keep browser-only recovery tools out of the offline catalog. Carry bounded multimodal editor results through a dedicated 16 MiB result route with a byte-accurate 12 MiB image budget, while retaining the 2 MiB control-request limit. Split shared broker, MCP, and bridge responsibilities below the source-file limit and add the missing English UI labels. Shared path impact: external MCP broker ownership, MCP tool exposure, and the editor bridge result endpoint. Built-in Agent and non-result bridge requests retain their previous behavior; the larger request budget is isolated to authenticated POST /result traffic. Validation: TypeScript build, zero-warning lint, verify:affected, targeted broker/offline/projection/MCP checks, i18n verification, full test suite, and production build. | 1 个月前 | |
fix(mcp): harden recovery and result transport Reserve orphaned edit sessions before dispatch so concurrent transports cannot overwrite recovery ownership, and release reservations after failed or cancelled calls. Keep browser-only recovery tools out of the offline catalog. Carry bounded multimodal editor results through a dedicated 16 MiB result route with a byte-accurate 12 MiB image budget, while retaining the 2 MiB control-request limit. Split shared broker, MCP, and bridge responsibilities below the source-file limit and add the missing English UI labels. Shared path impact: external MCP broker ownership, MCP tool exposure, and the editor bridge result endpoint. Built-in Agent and non-result bridge requests retain their previous behavior; the larger request budget is isolated to authenticated POST /result traffic. Validation: TypeScript build, zero-warning lint, verify:affected, targeted broker/offline/projection/MCP checks, i18n verification, full test suite, and production build. | 1 个月前 | |
feat(cli): browse local media and export a jianying draft headlessly Both halves of the last two gaps, plus one product bug found while proving them. - browse_local_media: the desktop app's browse core moved from desktop/ to server/ (it was already pure Node) and the tool gained a shared entry point (browseLocalMediaResult) — the desktop keeps shipping it over IPC while a headless host calls it in-process. It joins the server-direct read set, gated by AGENT_IMPORT_ROOTS like the import tools. - export_jianying_draft: request building and response shaping moved out of the browser fetch body into jianyingExportBody() / jianyingExportOutcome(), and a headless host calls exportJianyingDraft in-process instead of POSTing to /api/external-agent/jianying-export. New CLI: occ export jianying [--draft-name] [--out-dir]. A draft export stages nothing in the project, so the CLI reports that no-op honestly and still prints the exporter result. - Bug found by the new end-to-end check: resolveMediaPath() looked only for a real file under the upload roots, but path imports store a pointer under .references/ when the master stays on disk — so every clip imported by path exported as "media files not found locally". It now follows the reference (resolveMediaReference), exactly as resolveUploadFile already did. Shared paths touched: the jianying exporter's media resolution (an app behavior fix), the tool module's seams, the whitelist and the executor, and one module moved desktop → server. Everything else is CLI and verification. Verification: cli/cli.verify.ts also browses the import directory and drives the full draft path (ffmpeg-generated PNG → import_assets → edit_item adds an image clip → occ export jianying with a stub capcut-cli → asserts the reported draft path and that nothing was staged); jianying-export.verify pins the reference resolution with a fixture manifest (plus the copied and missing cases); offline-runtime, offline-mcp, verify:mcp and agent-local-media pass; tsc -b clean; lint 0 warnings; registration and gate coverage pass; npm run build, npm run desktop:build:main and npm run build:cli pass; npm test 181/181 green. | 1 个月前 | |
feat: harden media captions and offline editing | 2 个月前 | |
fix(agent): normalize load_skill arguments before schema validation The previous commit normalized load_skill's merged selectors inside the tool executor, but the shared invocation boundary validates against the tool schema first. That schema declares files.minItems=1, file: string and offset: integer, so exactly the filler the normalization exists to absorb — files: [], file: null, offset: "0" — was rejected by Ajv before any tool code ran. The normalization could only ever see calls that were already legal. Move it ahead of validation. execution-policy owns a per-tool normalizer map so every adapter that validates an invocation gets the same cleanup, and validateAgentToolInvocation now returns the normalized arguments rather than a bare ok flag, so callers execute and record what actually passed the schema. Extracted to tools/skill-args.ts and widened while it moved: a bare string on files becomes a one-file batch, a one-element array on file becomes one file, integer-looking strings become integers, and paths are trimmed. When both selectors survive, only a non-zero offset keeps the paged file — offset: 0 on SKILL.md repeats what the initial load already returned, so the batch wins. Wrong-typed values still survive normalization so validation reports them. Shared paths touched, and why unrelated callers are unaffected: - validateAgentToolInvocation (execution-policy.ts) — every tool invocation flows through it. Tools with no registered normalizer take the identity path and validate the exact object they passed in; the returned args are then the same reference. Only load_skill has an entry. - effectiveToolInvocationArgs / the codex tool boundary (codex/runtime.ts) — now records validation.args instead of the raw args, so the run ledger and the executed call agree. For every tool but load_skill these are identical. - validateExternalInvocation (external-tool-schemas.ts) — returns the validated form for the same reason; external tools register no normalizer. Verification: - npx tsc -b --force clean (bare tsc --noEmit is a no-op on the solution tsconfig and reported nothing). - npm run lint 0 warnings; npm run verify:affected 178 passed. - New boundary coverage in harness-runtime.verify.ts asserts the executor receives normalized arguments, the tool event carries them, and a genuine violation (files: 123) never reaches the executor. - Real agent link test, dev server on 5199, deepseek-v4-flash-vision-exp: "Load the talking-head-guide skill and quote its first two steps verbatim." Observed chain: manage_skill list, then load_skill · talking-head-guide returning the skill body; the agent quoted it verbatim and left the timeline untouched (context ~18k to ~36k). A wrong slug returned the domain error no such skill "clean-talking-head-edit" from the executor rather than an argument rejection, and the agent recovered by suggesting the right skill. The organic merged-selector shape is not reproducible on demand; it stays covered by the unit assertions above. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 1 个月前 | |
fix(mcp): preserve ownership when reusing active drafts | 26 天前 | |
fix(agent): close external MCP durability and security gaps found by full-tool e2e Shared paths touched: request-shape gate (all non-GET writes), external-agent broker/registry/binding (MCP + editor bridge), bridge routes, browser bridge registration/poll/result plumbing, and two verifies. Fixes, each reproduced and re-verified against a real browser editor + real MCP client sweeping all 118 tools: - upload handoff: the global request-shape gate 403'd legitimate MCP-client uploads (no Origin header). The /upload?handoff= token is single-use, scope-bound and verified by the upload endpoint itself, so the gate now lets handoff uploads through to that check. Verified: import_media -> HTTP upload -> finalize_uploaded_asset succeeds end-to-end (previously http 403). - registry revision sync: a tool settle reported the browser doc revision, but autosave could land after the settle, leaving the registry (and the store ownership) one revision behind and poisoning the next MCP session as stale. The settle route now syncs the registry to the post-tool revision, the registry touch adopts the store's authoritative revision (renewed claim), and the browser flushes pending project saves before reporting a tool result. Verified: consecutive MCP sessions bind to a consistent revision. - orphaned edit sessions: a closed/crashed MCP transport left its drafting session wedged ("An edit session is already active") with no owner able to discard it. cancelEditorCallsForOwner now emits an owner-gone signal through the cancellation queue, and the browser poll discards those sessions. Verified: sweep sessions no longer wedge begin_edit_session. - stale-tab false positives: a same-editor revision advance between bind and invoke (autosave landing) was treated as a stale takeover and permanently poisoned the MCP session. Sessionless calls (begin_edit_session, reads) now adopt the registry's current binding when the editor identity matches; control tools and edit-session-carrying calls stay strict so the stale-tab guard is unchanged. Verified: broker/mcp verifies still enforce stale semantics for mutations and control reads. - verifies updated: external-agent.verify mock gains editorCallBinding/ touchEditor and the capability-less browser re-claim assertion (claim gate re-issues ownership by design since 48ae9a1); broker.verify asserts the adopted-call behavior instead of a stale throw. Validation: tsc -b --force clean, oxlint 0 warnings, verify:affected 4/4 (request-shape-gate, external-agent, mcp, broker), real MCP client sweep 95/100 tool calls against a live editor (import, draft edits, review apply, export session A), remaining failures are test-harness session-timing noise, not tool failures. Known follow-up (pre-existing, not introduced here): a committed write can still leave the store ownership record one revision behind the project document; renew then refuses and the editor reloads to recover. Needs a dedicated ownership-sync pass. | 2 个月前 | |
feat(voice): support configured Doubao speaker IDs Add a default 音色 ID setting and pass user-supplied Volcengine speaker IDs verbatim as references[].speaker. Use the saved speaker in the connection probe and expose it to the agent prompt; keep curated aliases working. | 9 天前 | |
test: repair stale verify assertions blocking the full suite Four pre-existing verify failures repaired so the full suite can gate again: - agent-runtime-persistence.verify: the mock shared-kv backend lacked writeAgentRuntime (crashing the same-process chain after injection) and asserted a compare-and-swap API that has no server implementation; the backend now implements the write method, cleans up its module-global injection, and the dead CAS assertions are replaced with retained-sidecar and merge-monotonicity checks. - harness-context-checkpoint.verify-helper: checkpoint key set now includes the model/window provenance added by pressure-driven compaction. - nativeSemanticWorkerAdapter.verify / nativeBeatThisWorkerAdapter.verify: "must default off" assertions contradicted the auto-enable contract with a desktop bridge (matching desktop-native-asr.verify); aligned to auto-on-with-bridge. No production behavior changed; all edits are verify-side. The remaining suite failures are environmental (hf-proxy real download with no network route to hf-mirror.com) and a dead-code mock stream rejection print in token-efficiency.verify whose assertions pass. Validation: tsc -b --force clean, lint clean, verify:harness chain passes. | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat(agent): remove the cost guard approval gate entirely Users picked this product for speed; a confirmation card before paid or persistent tools added friction. The whole cost-guard layer is deleted: - skills/costGuard.ts (paid-tool registry, remember authorization, proposal auto-apply interception) and runtime-guard.ts (guard card construction) are removed; the paid-surface registry in agentSettings is gone too. - codex/runtime.ts executes every validated tool directly: the request-approval chain, deny results, and the skill-guard callback are deleted. The browser and server-run pendingGuard plumbing (executor, state, protocol, controller actions, UI card) is removed end to end. - The proposal auto-apply gate now follows the user toggle directly; the high-cost badge on proposal cards and the guard i18n copy are removed. - Paid tools keep their recovery classification: the execution policy still marks generation/export/transcription/web/sandbox as non-idempotent (outcome_unknown) so failed invocations are never replayed automatically, and offline authorization still rejects them. Preserved: parameter validation, edit-proposal approval, the auto-apply preference, external-agent real-project approval, and the approval ledger for the run inspector. Shared-path impact: tool execution boundary (codex/runtime.ts, execution-policy.ts) and both pendingGuard UI chains. Every mutating tool now runs without a card, which is the requested product behavior; proposal application and external-bridge approval are unchanged. Validation: tsc -b --force clean, lint 0 warnings, all touched verifies pass (execution policy, harness runtime, hydration recovery, executor, recovery, settings, job registry), full suite shows only the two pre-existing environmental failures, production build passes, and a real edit task ran punch animation straight through with no card. | 2 个月前 | |
fix(agent): normalize load_skill arguments before schema validation The previous commit normalized load_skill's merged selectors inside the tool executor, but the shared invocation boundary validates against the tool schema first. That schema declares files.minItems=1, file: string and offset: integer, so exactly the filler the normalization exists to absorb — files: [], file: null, offset: "0" — was rejected by Ajv before any tool code ran. The normalization could only ever see calls that were already legal. Move it ahead of validation. execution-policy owns a per-tool normalizer map so every adapter that validates an invocation gets the same cleanup, and validateAgentToolInvocation now returns the normalized arguments rather than a bare ok flag, so callers execute and record what actually passed the schema. Extracted to tools/skill-args.ts and widened while it moved: a bare string on files becomes a one-file batch, a one-element array on file becomes one file, integer-looking strings become integers, and paths are trimmed. When both selectors survive, only a non-zero offset keeps the paged file — offset: 0 on SKILL.md repeats what the initial load already returned, so the batch wins. Wrong-typed values still survive normalization so validation reports them. Shared paths touched, and why unrelated callers are unaffected: - validateAgentToolInvocation (execution-policy.ts) — every tool invocation flows through it. Tools with no registered normalizer take the identity path and validate the exact object they passed in; the returned args are then the same reference. Only load_skill has an entry. - effectiveToolInvocationArgs / the codex tool boundary (codex/runtime.ts) — now records validation.args instead of the raw args, so the run ledger and the executed call agree. For every tool but load_skill these are identical. - validateExternalInvocation (external-tool-schemas.ts) — returns the validated form for the same reason; external tools register no normalizer. Verification: - npx tsc -b --force clean (bare tsc --noEmit is a no-op on the solution tsconfig and reported nothing). - npm run lint 0 warnings; npm run verify:affected 178 passed. - New boundary coverage in harness-runtime.verify.ts asserts the executor receives normalized arguments, the tool event carries them, and a genuine violation (files: 123) never reaches the executor. - Real agent link test, dev server on 5199, deepseek-v4-flash-vision-exp: "Load the talking-head-guide skill and quote its first two steps verbatim." Observed chain: manage_skill list, then load_skill · talking-head-guide returning the skill body; the agent quoted it verbatim and left the timeline untouched (context ~18k to ~36k). A wrong slug returned the domain error no such skill "clean-talking-head-edit" from the executor rather than an argument rejection, and the agent recovered by suggesting the right skill. The organic merged-selector shape is not reproducible on demand; it stays covered by the unit assertions above. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): add per-model capabilities | 2 个月前 | |
feat(agent): reduce context token usage | 2 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
feat(agent): add Claude Code CLI backend Adds a claude-code agent backend so the built-in Agent can run on a Claude subscription through the official claude CLI, with no Anthropic API key — parallel to the existing OpenAI Codex CLI backend. Design differs from Codex in one important way. Claude Code's tool calling is MCP-native, so a turn spawns claude -p pointed at OpenChatCut's own external MCP server (--mcp-config + --strict-mcp-config + --allowedTools mcp__openchatcut-builtin__* + --permission-mode bypassPermissions) and lets Claude's own MCP client execute the tools. OpenChatCut never bridges or settles tool calls the way server/codex/turn-manager.ts does — it only parses the stream-json output for display. Auth stays entirely CLI-owned: status comes from claude auth status --json, and the user runs claude auth login or claude setup-token themselves. No OAuth is reimplemented and no token reaches the browser. ModelBackend grows a third member ('api' | 'codex' | 'claude-code'), which forces every exhaustive switch over it to handle the new backend. Notable details, each verified against the real CLI rather than assumed: - The system prompt is written to a temp file and passed with --append-system-prompt-file. Inline, a real OpenChatCut system prompt overflows the ~32KB Windows command-line cap and spawn fails with ENAMETOOLONG. - tool-start deliberately does not emit a tool-request run event. That event asks the browser to execute a tool and settle it back; since Claude Code already ran the call, the client's /tool-claim 404s and store-recovery then retries the unresolved request on every reload. - Curated models use canonical ids (claude-sonnet-5), not the CLI's short aliases, because the capability catalog is keyed by canonical id — aliases miss every entry and fall through to the estimator. - A built-in capability override caps maxOutputTokens at 64000; the catalog records the API's 128000, but the CLI reports 64000 in modelUsage. - The spawned MCP server is named openchatcut-builtin, never plain openchatcut. Claude Code caches MCP auth failures by server *name* in ~/.claude/mcp-needs-auth-cache.json, and users routinely have their own openchatcut entry — this repo's .mcp.json defines one, deliberately without an Authorization header since the token is generated per server start. Sharing the name let a single unrelated auth failure route this turn's private, correctly bearer-authenticated config into the OAuth path, exposing only authenticate/complete_authentication and hiding all editor tools. --strict-mcp-config does not help: the collision is on the name, not the config source. Known limitation: because tool calls run in Claude Code's own MCP session, they bypass this run's ToolActivation and proposal bookkeeping, so manual approval mode does not gate them the way it gates a Codex turn. Verify scripts cover version parsing, Windows command escaping, the full stream-json event pipeline against a fake CLI, an oversized system prompt, and the model-choice gating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1kuTz49j5Gtf2dbEzQ8mq | 1 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
perf: reduce hot-path overhead in editor, transcript, and agent streaming - editor/store: memoize activeEditorState so unrelated renders keep downstream [state] memos and effects stable - editor/sequenceGraph: skip graph traversal when the project has no sequence items (runs on every per-timeline action); duplicate timeline id detection is preserved in the fast path - agent/proposal: cache projectDocsDiffer per (baseDoc, currentDoc) identity pair (docs are immutable) so pending-proposal renders stop re-migrating and stringifying two full docs - transcript/TranscriptViews: memoize buildScriptRows and WordRow so drag-over/gap-adjust state changes no longer rebuild rows and re-render every word span on long transcripts - agent/serverRun: batch streaming text/thinking persistence into 200ms flushes via new serverRunStreamDeltaBuffer instead of rewriting the full localStorage record per SSE delta (O(text^2)); cursor+text always land in one atomic patch, non-delta commits fold pending text into their own write, stale cross-run flushes are discarded, and flush failures follow the existing persistenceError abandon path Shared paths touched: useEditor state identity (all editor consumers), per-timeline action validation, proposal staleness checks (browser and external bridge), transcript script view, serverRun durable stream persistence. All changes are memoization/short-circuit/batching only; no action semantics, storage schema, or recovery contract changed. Verification: tsc -b --force clean; oxlint 0 warnings; verify:affected (sequenceGraph, proposal) and serverRunSessionStorage.verify pass; 6-scenario standalone logic test for the delta buffer (batch merge, fold, cross-run discard, failure reporting, drop) passed; browser e2e on localhost:5199 (isolated dev profile): new project -> add solid -> undo -> redo -> dashboard reload with 0 console errors. Pre-existing issue confirmed on a clean tree: useServerRun.verify and serverRunToolRecovery.verify crash under run-check (dynamic require in @vercel/oidc via the ai package), unrelated to this change. | 1 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
perf: bound editor runtime and storage costs Virtualize large timeline and resource surfaces, defer Agent and media work, and bound rebuildable caches without evicting source media. | 2 个月前 | |
fix: reduce agent generation and persistence latency | 2 个月前 | |
fix(import): bound imports through the proxy, keep batches inside the run watchdog, make retry rewind the turn The previous fix bounded the TCP connect phase, which holds for a direct dial but not for the everyday case behind Clash: a blocked host behind the proxy still took ~80s per URL, and two of them in one download_media batch outlived the AI SDK's 120s chunk watchdog — which keeps counting while a tool runs — so the whole run died with "Chunk timeout of 120000ms exceeded" instead of returning per-URL failures. safePublicFetch now settles its own promise from two timers instead of relying on the request's 'error' event (Node defers that until the agent has produced a socket, i.e. until the proxy gives up): the connect bound waits for the TLS handshake on https (getCipher(), since getProtocol() reports the offered version before any byte comes back), and a 30s response-header bound covers a proxy that accepts CONNECT lazily and a host that connects and never answers. The unreachable message now says which of the two things the user can change matters: PROXY_URL without a proxy, the proxy's rules with one. download_media / push_asset batches stop starting new URLs after 75s and report the rest as failed rows, so a batch cannot outlive the watchdog; the tool description tells the model to pass at most three URLs per call. An origin that answers 4xx/5xx is now a failed row too — it used to be registered as a "remote src" success that could never play or export, and the model had to discover that itself. Retry used to append the same message again under the error, so the failed attempt (error, half-finished tool call, duplicate user turn) stayed in the model's context and steered the second try. It now rewinds both the chat and the model history to just before the turn — matched by user-turn ordinal and confirmed by text, falling back to the plain re-send when the histories cannot be matched — and re-sends it. Only the latest turn offers retry; rewinding an earlier one would discard every turn after it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
fix(import): bound imports through the proxy, keep batches inside the run watchdog, make retry rewind the turn The previous fix bounded the TCP connect phase, which holds for a direct dial but not for the everyday case behind Clash: a blocked host behind the proxy still took ~80s per URL, and two of them in one download_media batch outlived the AI SDK's 120s chunk watchdog — which keeps counting while a tool runs — so the whole run died with "Chunk timeout of 120000ms exceeded" instead of returning per-URL failures. safePublicFetch now settles its own promise from two timers instead of relying on the request's 'error' event (Node defers that until the agent has produced a socket, i.e. until the proxy gives up): the connect bound waits for the TLS handshake on https (getCipher(), since getProtocol() reports the offered version before any byte comes back), and a 30s response-header bound covers a proxy that accepts CONNECT lazily and a host that connects and never answers. The unreachable message now says which of the two things the user can change matters: PROXY_URL without a proxy, the proxy's rules with one. download_media / push_asset batches stop starting new URLs after 75s and report the rest as failed rows, so a batch cannot outlive the watchdog; the tool description tells the model to pass at most three URLs per call. An origin that answers 4xx/5xx is now a failed row too — it used to be registered as a "remote src" success that could never play or export, and the model had to discover that itself. Retry used to append the same message again under the error, so the failed attempt (error, half-finished tool call, duplicate user turn) stayed in the model's context and steered the second try. It now rewinds both the chat and the model history to just before the turn — matched by user-turn ordinal and confirmed by text, falling back to the plain re-send when the histories cannot be matched — and re-sends it. Only the latest turn offers retry; rewinding an earlier one would discard every turn after it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat: reduce agent token usage | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
fix: make local VAD silence removal reachable and warm installed local models Three capabilities existed in the tree but could never run. The VAD-backed silence removal was gated only by the build-time VITE_ENABLE_VAD_SILENCE_REMOVAL flag, so released builds carried the tracked Silero model (public/models/silero-vad, ~13MB) as unreachable bytes and remove_silence always refused to cut. The three desktop native warm-up entry points and ensureSileroVad had zero call sites, so those workers always cold-started on first use. runAgent had no production and no test caller. - Add src/audio/vadPreference.ts: a device-local tri-state preference (cc.vadSilenceRemoval). An unchosen preference still defers to the build flag, so builds that shipped the flag keep their behaviour and every other build stays disabled until the user opts in. - Move the single gate vadSilenceRemovalEnabled(storage?, buildFlag?) out of vad.ts so both inputs are injectable and truthiness is normalized in exactly one place; vad.ts keeps runner registration and evidence logic only. - Expose the toggle in Settings > Local models > Local transcription with zh/en/it/ru copy, and point the disabled remove_silence note at that location so the agent can guide the user. - Warm only model packs already reported installed. Pack status is checked first because a load request for a missing pack fails pack verification, and the rhythm and CLAP adapters treat a failed load as "native unavailable for this session", which would disable the native path until reload. Preloading never downloads a model. - Warm the bundled Silero model on idle only when the preference is on. - Remove runAgent together with the helpers it exclusively owned (runPreparedAgent, runCodexBackend, createContextRepreparer, contextRecord, toCodexToolSpec) and the orphaned imports. The comment claiming three verifies keep it alive was wrong: those verifies exercise runCodexAgent and runApiAgent directly. runtime.ts drops from 427 to 179 lines and the runtime chunk from 231.63 kB to 194.60 kB (gzip 71.01 -> 59.56). Shared paths touched, and the evidence they stay intact: - Silence gate (src/audio/vad.ts, src/audio/silence.ts): with no stored preference the gate is false and analyzeClipSilence short-circuits before fetching the source; a real browser session issues zero silero/ort requests when the editor opens. - src/agent/runtime.ts, which hosts the live executeCodexTool used by every server-run tool call: a real DeepSeek turn executed read_project in the browser and answered "Canvas width x height: 1080 x 1920. No modifications made (read-only)." - src/hooks/useInferenceWarmup.ts: the existing ASR warm-up path is unchanged; native warm-up runs only for installed packs and the VAD warm-up only for opted-in users. - src/components/settings/LocalAsrPane.tsx: the toggle renders, reflects the stored value, persists '0'/'1', and keeps its state across a panel reopen. Enabled-path proof: on a 5.18s Chinese speech sample Silero returned confidence 0.942 with speech spans 160-480 ms and 576-5152 ms in 773 ms, and the conservative intersection correctly removed nothing because the clip is speech throughout. Verification: tsc -b clean, oxlint clean, npm run build clean, npm test 178/179 segments pass. The single failure is pre-existing on main and untouched here: verify-gate-coverage flags server/keystore.ts at 502 lines. The new verify src/audio/vadPreference.verify.ts is registered in verify:captions. | 1 个月前 | |
feat: land professional timeline, durable jobs, and safe media flows Add slip/rate-stretch, nested sequences, multicam sync, durable generation/export recovery, media intelligence, and hardened MCP/media boundaries while keeping the implementation local-first and cross-platform. | 2 个月前 | |
feat: land professional timeline, durable jobs, and safe media flows Add slip/rate-stretch, nested sequences, multicam sync, durable generation/export recovery, media intelligence, and hardened MCP/media boundaries while keeping the implementation local-first and cross-platform. | 2 个月前 | |
feat(media): support project files and DeepSeek vision Add DeepSeek vision capability metadata and preserve documents and generic files as project assets. Shared path impact: media import now accepts project-only files, while explicit timeline guards keep existing audio, video, and image editing behavior unchanged. Persistence normalization preserves both legacy and new asset kinds. Verification: live DeepSeek model listing plus text and image requests; browser import, reload, AI document attachment, and model discovery; npx tsc -b --force; npm run lint; npm run verify:affected; TEST_CONCURRENCY=4 npm test; npm run build. | 2 个月前 | |
fix(quality): revive watchdogs, fix orphan checks, and unify skill count Resurrect two silent quality gateways and wire them into the test suite, catch up CHANGELOG and skill-count docs, and convert every orphaned verify/check file into a tracked, npm-wired regression. Quality watchdogs (now in pretest): - verify:shortcuts: catalog count 54->56, keymap scope, native-copy - verify:i18n: check-i18n.mjs now exempts test files; 4 real UI files wrapped in t(); 62 missing en keys added across 9 dict slices - Fixed stableOverrideKeys merging distinct legacy caption overrides when wordRef is empty (3 overrides collapsed to one key) - Fixed buildFollowupWidget silently dropping option-less choice fields (now degrades to a prompt line) - Fixed apply_script repack being silently rejected by the same-track overlap guard: reorderTrackItems now accepts explicit starts and apply_script rebuys atomically per track Docs: - CHANGELOG [Unreleased]: SQLite migration, session-recovery, chat-load-perf, Geist fonts, platform inference routing; fixed link refs - Skill count unified to 26 (README/README_ZH/AGENTS.md/tools.ts) Verify/check cleanup: - Promoted 81 .check.ts to tracked .verify.ts and deleted the originals - Fixed 20+ stale assertions (PROJECT_VERSION 3->7, sourceRevision, caption-track structure, legacy index selectors, shader hash re-pins, abort wiring refactor, stock orientation enum) - 8 new verify groups (editor/captions/agent-tools/components/ media-persist/export-gl/server-extra/sqlite-migration) wired into pretest - Orphan verify count: 158 -> 0 Full npm test, tsc -b --force, and npm run lint all pass. | 2 个月前 | |
feat(mcp): external agent connect UI + Codex model defaults - McpGuide: redesigned dialog with official client logos and one-click 'connect' buttons (Claude Code / Codex / Cursor / Antigravity) - server: POST /api/external-agent/connect-client writes client MCP configs (idempotent, atomic, token validation), with verification script - codex: seed system auth credentials into the isolated CODEX_HOME so the Codex CLI talks to OpenAI without 401 - model-selection: Codex official models expand into the composer picker; persisted preference wins over snapshot default; composer defaults to Codex (MCP backend) when no model was pinned; BytePlus/API models are hidden from the picker while Codex is available - composer: drop the Q&A (ask) mode option; show Codex logo in the corner model button - 404 handling: server run abandon/protocol/stream lifecycle no longer warn on stale runs after server restart - mcp.verify: await editor registration and raise notify timeout to 30s | 2 个月前 | |
feat(agent): remove the cost guard approval gate entirely Users picked this product for speed; a confirmation card before paid or persistent tools added friction. The whole cost-guard layer is deleted: - skills/costGuard.ts (paid-tool registry, remember authorization, proposal auto-apply interception) and runtime-guard.ts (guard card construction) are removed; the paid-surface registry in agentSettings is gone too. - codex/runtime.ts executes every validated tool directly: the request-approval chain, deny results, and the skill-guard callback are deleted. The browser and server-run pendingGuard plumbing (executor, state, protocol, controller actions, UI card) is removed end to end. - The proposal auto-apply gate now follows the user toggle directly; the high-cost badge on proposal cards and the guard i18n copy are removed. - Paid tools keep their recovery classification: the execution policy still marks generation/export/transcription/web/sandbox as non-idempotent (outcome_unknown) so failed invocations are never replayed automatically, and offline authorization still rejects them. Preserved: parameter validation, edit-proposal approval, the auto-apply preference, external-agent real-project approval, and the approval ledger for the run inspector. Shared-path impact: tool execution boundary (codex/runtime.ts, execution-policy.ts) and both pendingGuard UI chains. Every mutating tool now runs without a card, which is the requested product behavior; proposal application and external-bridge approval are unchanged. Validation: tsc -b --force clean, lint 0 warnings, all touched verifies pass (execution policy, harness runtime, hydration recovery, executor, recovery, settings, job registry), full suite shows only the two pre-existing environmental failures, production build passes, and a real edit task ran punch animation straight through with no card. | 2 个月前 | |
fix(agent): clear a run recovery draft while its capability is still stored A terminal that arrives with no in-memory turn — server restart, browser reload, detached tab — was settled by the finishRecoveredRun fallback, which dropped the stored run and with it the run capability. The only code left to clean up the run recovery draft is the abandon hook the stream lifecycle calls afterwards, so its POST /draft/clear went out with no capability header and the route rejected it as 403: every completed turn logged one, and in that path the draft artifact was never deleted at all. The fallback now clears the draft itself, before it drops the stored run, and clearServerRunDraft skips a request it cannot authenticate instead of sending one that can only be refused. The verify records what reaches the endpoint, so the capability header and the absence of the second request are both asserted. | 1 个月前 | |
feat(agent): land timeline edits per tool call in auto-apply mode In auto-apply mode the run's edits were still collected into a proposal and applied in one go when the run ended, so the user watched tool rows tick by while the timeline stayed still. Auto-apply already meant "apply whatever the run proposes"; landing each tool's edits as they happen only removes the wait. After every tool call the recorded operations are replayed onto the live project and saved (the same move-safe fence pool imports use), the draft is rebased onto the landed document so the next tool sees what the user sees — including anything they changed meanwhile — and the run's single change-log row grows with each landing and takes the model's own summary when the run ends. Landed calls are flagged in the run draft so a resumed run continues from the live project instead of applying them twice. Manual approval mode is unchanged: edits still become a proposal. Verified end to end with deepseek-v4-flash in YOLO mode: a three-step request (download, place on V1, duplicate after it) landed step by step with one change-log row and no proposal card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): note failed tool calls in a completed server run Since the failure banner no longer overrides the model's reply, nothing told the user when a run completed with a failed call the model glossed over. The executor now pushes a tool-failures event (the tracker's snapshot) right before finish; the browser appends a muted note message under the reply and the run inspector lists the calls. The note is built in the interface language on the client. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
test(agent): repoint server-run verify shims at localStorage The capability store moved from sessionStorage to localStorage; the tool-executor, model-history, and tool-recovery verifies still shimmed sessionStorage and failed the release gate. | 2 个月前 | |
fix(agent): harden server-run terminal recovery Retain terminal proposal handoffs until model history and proposal exposure both settle. Cancel unexposed proposals during project switches, terminate browser awaiting-user ledger records, and serialize same-page ownership handoff across projects. Shared paths: only the opt-in server-run recovery lifecycle changes; the default browser Agent path, ProjectDoc schema, media paths, preview, and export remain unchanged. Verification: npx tsc -b --force; focused oxlint; npm run verify:server-runs. | 2 个月前 | |
fix(agent): harden server-run terminal recovery Retain terminal proposal handoffs until model history and proposal exposure both settle. Cancel unexposed proposals during project switches, terminate browser awaiting-user ledger records, and serialize same-page ownership handoff across projects. Shared paths: only the opt-in server-run recovery lifecycle changes; the default browser Agent path, ProjectDoc schema, media paths, preview, and export remain unchanged. Verification: npx tsc -b --force; focused oxlint; npm run verify:server-runs. | 2 个月前 | |
fix(agent): honor auto-apply mode on the Claude Code backend With auto-apply (YOLO) enabled, a Claude Code run still raised a confirmation card for every real-project tool call and for the final proposal. Both gates read session.approvalMode (external-bridge-runtime.ts, the per-tool gate and the review gate), and that value has exactly one source: the argument the model passes to begin_edit_session. An omitted argument normalizes to 'manual'. Nothing connected the composer's toggle to it — the backend's RUNTIME_RULES tell the model to call begin_edit_session without ever mentioning approvalMode. This is specific to claude-code. The API and Codex paths execute tools in-process and read the auto-apply registry directly; Claude Code's tools run inside the CLI's own MCP client and arrive here as an ordinary external MCP session, so the toggle never reached them. The YOLO system-prompt paragraph ("Tools execute directly in every built-in mode. Do not invent or wait for runtime approval cards") was therefore false for this one backend. The mode is now enforced rather than requested. The turn's private --mcp-config carries x-openchatcut-approval-mode beside the existing x-openchatcut-mcp-client: claude-code-builtin, and the MCP server overrides begin_edit_session's argument with it. Enforcing beats instructing here: a turn cannot forget to pass it, and the mode stays a fact about the run. Both headers are required for an override, so no third-party MCP client (Claude Desktop, Cursor, a hand-rolled driver) can have its approvalMode changed by this path even if it guesses the approval header. Kept deliberately narrow to avoid disturbing the other backends: - The payload field is sent only when the active choice is claude-code, so every other backend's request body is byte-identical to before. - runRequestDigests widens only for claude-code, mirroring how it already widens for copilot, so stored request-shape hashes for existing API, Codex and Copilot runs are unchanged and still resume. - An absent approvalMode sends no header at all and leaves the choice to the model — the exact pre-change behaviour, which is what the HTTP /turn route and any older client still get. Verified: builtin-approval-mode.verify.ts covers the override, third-party isolation, malformed/absent headers, and round-trips the config the CLI actually receives back through the server's reader. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtfLU7dYnQoWZQQhEvEPN6 | 1 个月前 | |
fix(agent): restore thinking visibility, retry transient timeouts, and admit remembered tools in server runs Server runs dropped model reasoning on the floor: collectServerText consumed result.textStream, which carries only visible text — native reasoning arrives as reasoning-delta parts on fullStream, and inline <think>/<thinking> content was stripped but never forwarded. Forward both as thinking-delta run events (codex-turn forwards thinking-delta too), accumulate them into the streaming assistant message, persist assistantThinking for reload recovery, and render the existing ThinkingBlock. Also fix two server-run reliability gaps: - AI SDK chunk/step timers abort with a TimeoutError DOMException, which classifyLlmFailure did not recognise, so a transient provider stall failed the whole run with no retry. Classify it as TIMEOUT (retryable). - A model can call a tool it used earlier in the conversation while the new request's activation set has expired it, failing the run with 'Tool is not active for this request'. Activation is a token optimization, not a security boundary: canonical-catalog membership still gates the call, and canonical but inactive tools are now admitted at execution time on both server and browser sides. Shared paths: run event stream (thinking-delta events are rollable like text-delta), StoredServerRun session shape (assistantThinking is optional and degrades safely), ToolActivation (admit is additive and never registers non-canonical names). ask-mode and unknown-tool rejection are unchanged. Verified: verify:server-runs (18 suites), ai-sdk.verify, tool-activation.verify (admit assertions), useServerRun.verify, serverRunSessionStorage.verify, llm-retry.verify (TimeoutError/AbortError classification), tsc -b, oxlint, and a real browser smoke showing the Thinking Process block renders model reasoning. | 2 个月前 | |
fix(import): bound imports through the proxy, keep batches inside the run watchdog, make retry rewind the turn The previous fix bounded the TCP connect phase, which holds for a direct dial but not for the everyday case behind Clash: a blocked host behind the proxy still took ~80s per URL, and two of them in one download_media batch outlived the AI SDK's 120s chunk watchdog — which keeps counting while a tool runs — so the whole run died with "Chunk timeout of 120000ms exceeded" instead of returning per-URL failures. safePublicFetch now settles its own promise from two timers instead of relying on the request's 'error' event (Node defers that until the agent has produced a socket, i.e. until the proxy gives up): the connect bound waits for the TLS handshake on https (getCipher(), since getProtocol() reports the offered version before any byte comes back), and a 30s response-header bound covers a proxy that accepts CONNECT lazily and a host that connects and never answers. The unreachable message now says which of the two things the user can change matters: PROXY_URL without a proxy, the proxy's rules with one. download_media / push_asset batches stop starting new URLs after 75s and report the rest as failed rows, so a batch cannot outlive the watchdog; the tool description tells the model to pass at most three URLs per call. An origin that answers 4xx/5xx is now a failed row too — it used to be registered as a "remote src" success that could never play or export, and the model had to discover that itself. Retry used to append the same message again under the error, so the failed attempt (error, half-finished tool call, duplicate user turn) stayed in the model's context and steered the second try. It now rewinds both the chat and the model history to just before the turn — matched by user-turn ordinal and confirmed by text, falling back to the plain re-send when the histories cannot be matched — and re-sends it. Only the latest turn offers retry; rewinding an earlier one would discard every turn after it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): land timeline edits per tool call in auto-apply mode In auto-apply mode the run's edits were still collected into a proposal and applied in one go when the run ended, so the user watched tool rows tick by while the timeline stayed still. Auto-apply already meant "apply whatever the run proposes"; landing each tool's edits as they happen only removes the wait. After every tool call the recorded operations are replayed onto the live project and saved (the same move-safe fence pool imports use), the draft is rebased onto the landed document so the next tool sees what the user sees — including anything they changed meanwhile — and the run's single change-log row grows with each landing and takes the model's own summary when the run ends. Landed calls are flagged in the run draft so a resumed run continues from the live project instead of applying them twice. Manual approval mode is unchanged: edits still become a proposal. Verified end to end with deepseek-v4-flash in YOLO mode: a three-step request (download, place on V1, duplicate after it) landed step by step with one change-log row and no proposal card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
fix(agent): honor auto-apply mode on the Claude Code backend With auto-apply (YOLO) enabled, a Claude Code run still raised a confirmation card for every real-project tool call and for the final proposal. Both gates read session.approvalMode (external-bridge-runtime.ts, the per-tool gate and the review gate), and that value has exactly one source: the argument the model passes to begin_edit_session. An omitted argument normalizes to 'manual'. Nothing connected the composer's toggle to it — the backend's RUNTIME_RULES tell the model to call begin_edit_session without ever mentioning approvalMode. This is specific to claude-code. The API and Codex paths execute tools in-process and read the auto-apply registry directly; Claude Code's tools run inside the CLI's own MCP client and arrive here as an ordinary external MCP session, so the toggle never reached them. The YOLO system-prompt paragraph ("Tools execute directly in every built-in mode. Do not invent or wait for runtime approval cards") was therefore false for this one backend. The mode is now enforced rather than requested. The turn's private --mcp-config carries x-openchatcut-approval-mode beside the existing x-openchatcut-mcp-client: claude-code-builtin, and the MCP server overrides begin_edit_session's argument with it. Enforcing beats instructing here: a turn cannot forget to pass it, and the mode stays a fact about the run. Both headers are required for an override, so no third-party MCP client (Claude Desktop, Cursor, a hand-rolled driver) can have its approvalMode changed by this path even if it guesses the approval header. Kept deliberately narrow to avoid disturbing the other backends: - The payload field is sent only when the active choice is claude-code, so every other backend's request body is byte-identical to before. - runRequestDigests widens only for claude-code, mirroring how it already widens for copilot, so stored request-shape hashes for existing API, Codex and Copilot runs are unchanged and still resume. - An absent approvalMode sends no header at all and leaves the choice to the model — the exact pre-change behaviour, which is what the HTTP /turn route and any older client still get. Verified: builtin-approval-mode.verify.ts covers the override, third-party isolation, malformed/absent headers, and round-trips the config the CLI actually receives back through the server's reader. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtfLU7dYnQoWZQQhEvEPN6 | 1 个月前 | |
feat(agent): run Codex turns on the server side Server-side execution (serverRun) is now the only Agent path for every backend: the executor routes Codex model runs through a new server-side turn bridge (server/agent-runs/codex-turn.ts) that reuses the Codex turn manager, the browser tool claim/result chain, and the run event store. Changes: - serverRun payload/protocol carries backend ('api' | 'codex'); routes admit Codex runs without LLM-key config; ServerRun records backend and persists provider/backend separately (legacy records where backend held the provider name restore as api). - executor plans Codex runs without a LanguageModel and routes them to executeServerCodexTurn: prepareContext with a Codex summary turn, prompt via serializeMessagesForPrompt, CodexTurnStreamEvent bridge (text-delta into run events, tool-start into executeBrowserTool + settleToolResult, context-usage into run metrics), assistant text + merged tool history rebuilt per turn. - serverRunSend admits codex choices and only runs describeImagesForTextModel when the active main model lacks image input (a vision-capable main model keeps raw image parts). - projectedHistory: whole-image budget admission (no mid-base64 truncation) and window-first budgeting so sliced-off history cannot starve the tail. - New codex-turn.verify (text/tool/error/missing-terminal cases) and extended serverRunProtocol.verify (whole-image skip, window ordering). Shared-path impact: server-run send/protocol/executor/store only. The browser-side runAgent loop and its api/codex backends are now verify-only regression assets (annotated); executeCodexTool, runCodexSummary, and the serverRun tool chain are unchanged. Verified: tsc -b --force, oxlint (0 warnings), verify:server-runs (17 suites incl. new codex-turn), verify:harness, verify:project-store-transport. Real-codex smoke: runServerCodexTurn reaches the local Codex CLI and normalizes the usage-limit failure into the friendly server message (successful turns are covered by the verify suite). | 2 个月前 | |
fix(agent): clear a run recovery draft while its capability is still stored A terminal that arrives with no in-memory turn — server restart, browser reload, detached tab — was settled by the finishRecoveredRun fallback, which dropped the stored run and with it the run capability. The only code left to clean up the run recovery draft is the abandon hook the stream lifecycle calls afterwards, so its POST /draft/clear went out with no capability header and the route rejected it as 403: every completed turn logged one, and in that path the draft artifact was never deleted at all. The fallback now clears the draft itself, before it drops the stored run, and clearServerRunDraft skips a request it cannot authenticate instead of sending one that can only be refused. The verify records what reaches the endpoint, so the capability header and the absence of the second request are both asserted. | 1 个月前 | |
fix(agent): restore thinking visibility, retry transient timeouts, and admit remembered tools in server runs Server runs dropped model reasoning on the floor: collectServerText consumed result.textStream, which carries only visible text — native reasoning arrives as reasoning-delta parts on fullStream, and inline <think>/<thinking> content was stripped but never forwarded. Forward both as thinking-delta run events (codex-turn forwards thinking-delta too), accumulate them into the streaming assistant message, persist assistantThinking for reload recovery, and render the existing ThinkingBlock. Also fix two server-run reliability gaps: - AI SDK chunk/step timers abort with a TimeoutError DOMException, which classifyLlmFailure did not recognise, so a transient provider stall failed the whole run with no retry. Classify it as TIMEOUT (retryable). - A model can call a tool it used earlier in the conversation while the new request's activation set has expired it, failing the run with 'Tool is not active for this request'. Activation is a token optimization, not a security boundary: canonical-catalog membership still gates the call, and canonical but inactive tools are now admitted at execution time on both server and browser sides. Shared paths: run event stream (thinking-delta events are rollable like text-delta), StoredServerRun session shape (assistantThinking is optional and degrades safely), ToolActivation (admit is additive and never registers non-canonical names). ask-mode and unknown-tool rejection are unchanged. Verified: verify:server-runs (18 suites), ai-sdk.verify, tool-activation.verify (admit assertions), useServerRun.verify, serverRunSessionStorage.verify, llm-retry.verify (TimeoutError/AbortError classification), tsc -b, oxlint, and a real browser smoke showing the Thinking Process block renders model reasoning. | 2 个月前 | |
refactor(agent): remove every browser-side agent-run ledger write The browser recorder (AgentRunRecorder) is retired from the serverRun flow: run startup no longer resumes a recorder or stores lease tokens, proposal settlement/recovery calls the server settle endpoint, tool checkpoint/context records are dropped because the server executor already records them, and hydration no longer claims run ownership (server-side settle is idempotent across windows). All affected verifies were updated to the single-writer semantics (settle endpoint stubbed with a local patch so the full settlement path stays covered). | 2 个月前 | |
feat(agent): add Claude Code CLI backend Adds a claude-code agent backend so the built-in Agent can run on a Claude subscription through the official claude CLI, with no Anthropic API key — parallel to the existing OpenAI Codex CLI backend. Design differs from Codex in one important way. Claude Code's tool calling is MCP-native, so a turn spawns claude -p pointed at OpenChatCut's own external MCP server (--mcp-config + --strict-mcp-config + --allowedTools mcp__openchatcut-builtin__* + --permission-mode bypassPermissions) and lets Claude's own MCP client execute the tools. OpenChatCut never bridges or settles tool calls the way server/codex/turn-manager.ts does — it only parses the stream-json output for display. Auth stays entirely CLI-owned: status comes from claude auth status --json, and the user runs claude auth login or claude setup-token themselves. No OAuth is reimplemented and no token reaches the browser. ModelBackend grows a third member ('api' | 'codex' | 'claude-code'), which forces every exhaustive switch over it to handle the new backend. Notable details, each verified against the real CLI rather than assumed: - The system prompt is written to a temp file and passed with --append-system-prompt-file. Inline, a real OpenChatCut system prompt overflows the ~32KB Windows command-line cap and spawn fails with ENAMETOOLONG. - tool-start deliberately does not emit a tool-request run event. That event asks the browser to execute a tool and settle it back; since Claude Code already ran the call, the client's /tool-claim 404s and store-recovery then retries the unresolved request on every reload. - Curated models use canonical ids (claude-sonnet-5), not the CLI's short aliases, because the capability catalog is keyed by canonical id — aliases miss every entry and fall through to the estimator. - A built-in capability override caps maxOutputTokens at 64000; the catalog records the API's 128000, but the CLI reports 64000 in modelUsage. - The spawned MCP server is named openchatcut-builtin, never plain openchatcut. Claude Code caches MCP auth failures by server *name* in ~/.claude/mcp-needs-auth-cache.json, and users routinely have their own openchatcut entry — this repo's .mcp.json defines one, deliberately without an Authorization header since the token is generated per server start. Sharing the name let a single unrelated auth failure route this turn's private, correctly bearer-authenticated config into the OAuth path, exposing only authenticate/complete_authentication and hiding all editor tools. --strict-mcp-config does not help: the collision is on the name, not the config source. Known limitation: because tool calls run in Claude Code's own MCP session, they bypass this run's ToolActivation and proposal bookkeeping, so manual approval mode does not gate them the way it gates a Codex turn. Verify scripts cover version parsing, Windows command escaping, the full stream-json event pipeline against a fake CLI, an oversized system prompt, and the model-choice gating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W1kuTz49j5Gtf2dbEzQ8mq | 1 个月前 | |
fix(agent): persist server-run capability in localStorage so drafts survive tabs 'Server run draft could not be persisted' reproduced as a 403: the run capability header lives only in sessionStorage, which is isolated per tab and wiped on close — a reload/new tab/restart loses the capability and every draft POST fails with 'invalid run capability'. The capability now persists in localStorage (same-origin trust level, project-scoped key), and the draft error message carries the HTTP status and the actual reason (403 capability lost / 404 run gone) so users get an actionable hint instead of a bare failure. | 2 个月前 | |
fix(agent): clear a run recovery draft while its capability is still stored A terminal that arrives with no in-memory turn — server restart, browser reload, detached tab — was settled by the finishRecoveredRun fallback, which dropped the stored run and with it the run capability. The only code left to clean up the run recovery draft is the abandon hook the stream lifecycle calls afterwards, so its POST /draft/clear went out with no capability header and the route rejected it as 403: every completed turn logged one, and in that path the draft artifact was never deleted at all. The fallback now clears the draft itself, before it drops the stored run, and clearServerRunDraft skips a request it cannot authenticate instead of sending one that can only be refused. The verify records what reaches the endpoint, so the capability header and the absence of the second request are both asserted. | 1 个月前 | |
fix: second-scan findings and complete CAS removal Behavior: - The request-shape gate now mounts at '/' so every write mount (not only /api) rejects cross-site requests (LLM proxy, e2b sandbox, generation, render, export endpoints were CSRF-able via safelisted text/plain posts). - fetchRemoteEntry never overwrites a locally-pending (offline-written) value with the server's older copy. - Hydration fast path also runs recovery when a preserved external run needs its pending approvals cancelled (stale external records no longer leave ghost waiting_approval runs). - Settle no longer requires the run-capability handshake (idempotent terminal writes; the same-origin gate fences it), and a waiting_approval settle no longer cancels a live executor or deferred admission. - Settle client type drops the never-sent awaiting_user status. CAS removal completion: renamed all remaining CAS symbols and wire operations (writeAgentRuntime/writeProjectDocument, -write operations, agent-runtime/write and project-document/write routes, handler names, error strings); the two ownership claim/renew revision gates are kept as intentional business-level stale detection — deleting them would let a stale tab clobber newer content. | 2 个月前 | |
fix(agent): restore thinking visibility, retry transient timeouts, and admit remembered tools in server runs Server runs dropped model reasoning on the floor: collectServerText consumed result.textStream, which carries only visible text — native reasoning arrives as reasoning-delta parts on fullStream, and inline <think>/<thinking> content was stripped but never forwarded. Forward both as thinking-delta run events (codex-turn forwards thinking-delta too), accumulate them into the streaming assistant message, persist assistantThinking for reload recovery, and render the existing ThinkingBlock. Also fix two server-run reliability gaps: - AI SDK chunk/step timers abort with a TimeoutError DOMException, which classifyLlmFailure did not recognise, so a transient provider stall failed the whole run with no retry. Classify it as TIMEOUT (retryable). - A model can call a tool it used earlier in the conversation while the new request's activation set has expired it, failing the run with 'Tool is not active for this request'. Activation is a token optimization, not a security boundary: canonical-catalog membership still gates the call, and canonical but inactive tools are now admitted at execution time on both server and browser sides. Shared paths: run event stream (thinking-delta events are rollable like text-delta), StoredServerRun session shape (assistantThinking is optional and degrades safely), ToolActivation (admit is additive and never registers non-canonical names). ask-mode and unknown-tool rejection are unchanged. Verified: verify:server-runs (18 suites), ai-sdk.verify, tool-activation.verify (admit assertions), useServerRun.verify, serverRunSessionStorage.verify, llm-retry.verify (TimeoutError/AbortError classification), tsc -b, oxlint, and a real browser smoke showing the Thinking Process block renders model reasoning. | 2 个月前 | |
perf: reduce hot-path overhead in editor, transcript, and agent streaming - editor/store: memoize activeEditorState so unrelated renders keep downstream [state] memos and effects stable - editor/sequenceGraph: skip graph traversal when the project has no sequence items (runs on every per-timeline action); duplicate timeline id detection is preserved in the fast path - agent/proposal: cache projectDocsDiffer per (baseDoc, currentDoc) identity pair (docs are immutable) so pending-proposal renders stop re-migrating and stringifying two full docs - transcript/TranscriptViews: memoize buildScriptRows and WordRow so drag-over/gap-adjust state changes no longer rebuild rows and re-render every word span on long transcripts - agent/serverRun: batch streaming text/thinking persistence into 200ms flushes via new serverRunStreamDeltaBuffer instead of rewriting the full localStorage record per SSE delta (O(text^2)); cursor+text always land in one atomic patch, non-delta commits fold pending text into their own write, stale cross-run flushes are discarded, and flush failures follow the existing persistenceError abandon path Shared paths touched: useEditor state identity (all editor consumers), per-timeline action validation, proposal staleness checks (browser and external bridge), transcript script view, serverRun durable stream persistence. All changes are memoization/short-circuit/batching only; no action semantics, storage schema, or recovery contract changed. Verification: tsc -b --force clean; oxlint 0 warnings; verify:affected (sequenceGraph, proposal) and serverRunSessionStorage.verify pass; 6-scenario standalone logic test for the delta buffer (batch merge, fold, cross-run discard, failure reporting, drop) passed; browser e2e on localhost:5199 (isolated dev profile): new project -> add solid -> undo -> redo -> dashboard reload with 0 console errors. Pre-existing issue confirmed on a clean tree: useServerRun.verify and serverRunToolRecovery.verify crash under run-check (dynamic require in @vercel/oidc via the ai package), unrelated to this change. | 1 个月前 | |
fix(agent): per-run session identity; stale lifecycle callbacks are fenced Issue #125: stopping a run mid-tool and immediately sending the next task let the old tool's late completion read executor state the new run had overwritten. ServerRunToolExecutor kept runId, capability, claimId and abort as mutable fields on one long-lived instance; a continuation resuming after start() posted /tool-result under the NEW run's capability, the server answered 403, and that stray permanent failure then tore the new run down: abandonStaleRecovery closed the current event stream and stopped the current executor without checking whose failure it was handling. The second run completed server-side, but its answer never reached the chat. Two changes, no locks — identity comparison only, per the project's no-locks constraint: - The executor snapshots an immutable RunSession at start(); every claim, post, retry and execution continuation carries it. After each await the session is compared with the current one: a stale continuation either settles with its OWN authority (an in-flight result keeps the old capability) or is dropped before touching the draft, activation, recovered map, chat, or network. handle() also rejects requests whose runId does not match the session, so a superseded stream cannot execute under the new run's authority. - lifecycleRunFence guards abandonStaleRecovery and finishRun: a callback for a foreign run is ignored while another run is active. With no active run (pre-adoption recovery failure) cleanup still proceeds, so stored runs are settled rather than retried forever. serverRunToolExecutor.race.verify.ts pins both directions: the stale-claim, in-flight-result, stale-runId and fence cases, plus the undisturbed single-run path to guard against over-fencing. | 1 个月前 | |
fix(agent): harden server-run terminal recovery Retain terminal proposal handoffs until model history and proposal exposure both settle. Cancel unexposed proposals during project switches, terminate browser awaiting-user ledger records, and serialize same-page ownership handoff across projects. Shared paths: only the opt-in server-run recovery lifecycle changes; the default browser Agent path, ProjectDoc schema, media paths, preview, and export remain unchanged. Verification: npx tsc -b --force; focused oxlint; npm run verify:server-runs. | 2 个月前 | |
fix: close agent and desktop regression gaps Keep Codex tool activation and business-failure settlement consistent, preserve media identity across agent edits, and expose complete timeline projections. Harden transcript recovery, capability fallbacks, media ingest, and Jianying export while adding a shared model-cache path plus Windows fresh-process persistence CI. | 2 个月前 | |
fix: harden imports and provider runtimes Serialize xAI OAuth lifecycle operations, reject stale sessions, and align Grok request contracts. Fix directory imports and Silero VAD state, bound imported document context, complete Russian Agent surfaces, and split oversized shared modules without changing their contracts. Shared paths: Agent prompts and execution errors, generation routes, media import, settings, and composer UI. Validation: npx tsc -b --force; npm run lint; npm run verify:affected (33); TEST_CONCURRENCY=4 npm test; npm run build; real DeepSeek Agent read_project/read_timeline calls in Chinese and Russian; Browser4 composer smoke with zero console warnings. | 2 个月前 | |
fix(agent): per-run session identity; stale lifecycle callbacks are fenced Issue #125: stopping a run mid-tool and immediately sending the next task let the old tool's late completion read executor state the new run had overwritten. ServerRunToolExecutor kept runId, capability, claimId and abort as mutable fields on one long-lived instance; a continuation resuming after start() posted /tool-result under the NEW run's capability, the server answered 403, and that stray permanent failure then tore the new run down: abandonStaleRecovery closed the current event stream and stopped the current executor without checking whose failure it was handling. The second run completed server-side, but its answer never reached the chat. Two changes, no locks — identity comparison only, per the project's no-locks constraint: - The executor snapshots an immutable RunSession at start(); every claim, post, retry and execution continuation carries it. After each await the session is compared with the current one: a stale continuation either settles with its OWN authority (an in-flight result keeps the old capability) or is dropped before touching the draft, activation, recovered map, chat, or network. handle() also rejects requests whose runId does not match the session, so a superseded stream cannot execute under the new run's authority. - lifecycleRunFence guards abandonStaleRecovery and finishRun: a callback for a foreign run is ignored while another run is active. With no active run (pre-adoption recovery failure) cleanup still proceeds, so stored runs are settled rather than retried forever. serverRunToolExecutor.race.verify.ts pins both directions: the stale-claim, in-flight-result, stale-runId and fence cases, plus the undisturbed single-run path to guard against over-fencing. | 1 个月前 | |
fix: preserve offline edits and optimize editor workflows Recover conflicting offline project documents into verified, retry-safe copies without replacing the original project. Harden skill installation and media stream handling, deduplicate loudness work, reuse transcript projections, and load sequence options only when needed. Split oversized source modules while preserving their public exports. Expand affected verification coverage, add a macOS frame-sync CI job, and update vulnerable media dependency overrides. Shared-path impact: - Persistence recovery runs only for pending conflicting documents. Normal saves keep their existing format, media URLs, and ownership rules. Recovery confirms document and index writes before clearing pending state. - Agent and UI loudness paths retain existing volume limits and undo behavior; repeated sources share bounded analysis and stale sources are rejected. - Transcript, caption, preview, export, server, and desktop module moves keep existing call contracts. Differential checks cover projections and stored job reports; media transport checks cover ranges, empty files, and aborts. Validation: - Full TypeScript project build, zero-warning lint, and production build passed. - npm test preflight passed; all 172 test segments passed after registering the new verification files (TEST_CONCURRENCY=2 npm run test --ignore-scripts). - Final persistence changes passed project-store transport and recovery checks, lint, build, and the 561-verification gate coverage check. - npm audit --omit=dev reported zero vulnerabilities. - Real DeepSeek Agent invoked add_audio and normalize_loudness successfully. Browser checks covered import, save/reopen, undo/redo, and offline recovery with the original project and recovered media preserved. - Native macOS frame-sync checks and real FFmpeg media checks passed. The new remote macOS CI job has not yet run. | 1 个月前 | |
fix(agent): align execution modes and verification Align Ask and YOLO UI, prompt, documentation, and comments with direct built-in tool execution while preserving proposal application behavior and the external MCP approval boundary. Fix the proposal durability test fixture and split oversized runtime verification and external global-read code without changing execution order. Shared paths: agent prompt and composer mode registry, proposal verification, external global reads, and server-run/Codex verification. Validation: npx tsc -b --force; npm run lint; npm test (97/97); npm run build; browser read_timeline E2E. | 2 个月前 | |
test(agent): repoint server-run verify shims at localStorage The capability store moved from sessionStorage to localStorage; the tool-executor, model-history, and tool-recovery verifies still shimmed sessionStorage and failed the release gate. | 2 个月前 | |
fix: preserve offline edits and optimize editor workflows Recover conflicting offline project documents into verified, retry-safe copies without replacing the original project. Harden skill installation and media stream handling, deduplicate loudness work, reuse transcript projections, and load sequence options only when needed. Split oversized source modules while preserving their public exports. Expand affected verification coverage, add a macOS frame-sync CI job, and update vulnerable media dependency overrides. Shared-path impact: - Persistence recovery runs only for pending conflicting documents. Normal saves keep their existing format, media URLs, and ownership rules. Recovery confirms document and index writes before clearing pending state. - Agent and UI loudness paths retain existing volume limits and undo behavior; repeated sources share bounded analysis and stale sources are rejected. - Transcript, caption, preview, export, server, and desktop module moves keep existing call contracts. Differential checks cover projections and stored job reports; media transport checks cover ranges, empty files, and aborts. Validation: - Full TypeScript project build, zero-warning lint, and production build passed. - npm test preflight passed; all 172 test segments passed after registering the new verification files (TEST_CONCURRENCY=2 npm run test --ignore-scripts). - Final persistence changes passed project-store transport and recovery checks, lint, build, and the 561-verification gate coverage check. - npm audit --omit=dev reported zero vulnerabilities. - Real DeepSeek Agent invoked add_audio and normalize_loudness successfully. Browser checks covered import, save/reopen, undo/redo, and offline recovery with the original project and recovered media preserved. - Native macOS frame-sync checks and real FFmpeg media checks passed. The new remote macOS CI job has not yet run. | 1 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
test(agent): repoint server-run verify shims at localStorage The capability store moved from sessionStorage to localStorage; the tool-executor, model-history, and tool-recovery verifies still shimmed sessionStorage and failed the release gate. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
fix: harden imports and provider runtimes Serialize xAI OAuth lifecycle operations, reject stale sessions, and align Grok request contracts. Fix directory imports and Silero VAD state, bound imported document context, complete Russian Agent surfaces, and split oversized shared modules without changing their contracts. Shared paths: Agent prompts and execution errors, generation routes, media import, settings, and composer UI. Validation: npx tsc -b --force; npm run lint; npm run verify:affected (33); TEST_CONCURRENCY=4 npm test; npm run build; real DeepSeek Agent read_project/read_timeline calls in Chinese and Russian; Browser4 composer smoke with zero console warnings. | 2 个月前 | |
Merge pull request #117 from drbelt27/feat/italian-locale-settings # Conflicts: # package.json # server/mobile-upload-service.ts # server/mobile-upload-service.verify.ts # server/plugins/mobile-upload.ts # server/plugins/mobile-upload.verify.ts # src/agent/agent-session.ts # src/agent/systemPrompt.ts # src/agent/systemPromptOrder.verify.ts # src/components/TopBar.tsx # src/components/chat/ChatComposer.tsx # src/components/chat/WorkflowPickerContent.tsx # src/i18n/locale.ts # src/library/SkillsTabPanel.tsx # src/media/mobileUploadApi.ts # src/shortcuts/ShortcutsDialog.tsx | 2 个月前 | |
Merge PR #123 (FlexCrop) — crop feature only, agent governor excluded Trial merge of J160KU's FlexCrop onto v0.2.12 for CI validation. Two things had to be resolved beyond ordinary conflicts. The PR does not build. npm run build runs tsc -b, and on the PR branch alone that fails four ways: two unused imports in systemPrompt.ts and a cast in read-project-tools-check.verify.ts that omits selectedIds/selectedId and then reads them. npx tsc --noEmit passes, which is presumably what was run. Fixed here by completing the cast; the systemPrompt errors disappear with the revert below. The PR also carries 192 lines of agent-behaviour change that its title and summary do not mention, so those are left out of this merge: - src/agent/inspect-loop.ts hooks guardFlexCropToolLoop into tools.ts, the central dispatcher, where it can short-circuit ANY tool call. It caps frame inspection at 6 looks for every agent run — its own comment notes caption/MG verification needs more — and injects "stop", "do not recheck frames", "do not call run_code" into the result stream. - src/agent/sandbox-unavailable.ts turns run_code/probe_media into {ok: true, skipped: true} when E2B is unconfigured. Reporting an unavailable capability as success is the shape of open issue #114, which is fixed on main. - frames-tool.ts raises the frame-sampling cap from 8 back to 16, undoing the hardening in aafac5dc. tools.ts, systemPrompt.ts, probe-tools.ts, run-code-tools.ts, known-errors/SKILL.md and frames-tool.ts are therefore taken from main, and the two new modules plus their verifies are dropped along with their entries in the verify:agent-tools script. tools.ts contained nothing else, so FlexCrop loses nothing by this. FlexCrop itself is sound: storage stays a 0-1 canvas fraction so no migration is needed, pixel conversion is isolated in src/editor/flexCrop.ts with its own verify, edit_item previously rejected transform.crop as an unknown field so no existing agent call changes meaning, and every new verify was registered in test:serial by the author. CHANGELOG keeps the released 0.2.12 section and files FlexCrop under [Unreleased]; the tool catalog was regenerated rather than hand-merged. Local: tsc -b, lint (0 warnings), npm test (162 segments) all pass. | 1 个月前 | |
feat: land professional timeline, durable jobs, and safe media flows Add slip/rate-stretch, nested sequences, multicam sync, durable generation/export recovery, media intelligence, and hardened MCP/media boundaries while keeping the implementation local-first and cross-platform. | 2 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat(agent): add durable token-aware harness | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(agent): add durable server-side execution Add an opt-in authenticated server-run lifecycle with streamed events, browser-delegated tools, approvals, recovery, bounded persistence, and run inspection. Keep the browser Agent path as the default, preserve EditorCommands as the editing authority, leave the ProjectDoc schema unchanged, and serialize only the existing Agent runtime sidecar. Shared paths: Agent settings and chat orchestration branch only when server execution is enabled; Project Store reads and writes remain on the existing ownership-bound transport; client mode remains unchanged when disabled. Release: bump the application to 0.3.0 and document the server-side continuation workflow in English and Chinese. Verification: npx tsc -b --force; npm run lint; npm test; npm run build; real browser smoke on localhost:5204 covering server mode on/off, a real model read_project tool call, persisted project reload, service restart, Project Store read/write, and MCP bootstrap token recovery. | 2 个月前 | |
feat(publish): publish finished renders to social platforms via Upload-Post Adds publish_to_social / track_social_publish so the agent can post a completed render (the /media/uploads/ downloadUrl from track_export) to TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest and Bluesky through Upload-Post. - Two steps by contract: without confirm the server only previews (file, profile, connected/missing platforms, title, privacy); confirm:true uploads. - request_id is derived from the file and the publish fields and doubles as the Idempotency-Key: re-sending an approved publish resumes it, a dropped connection never re-uploads. - File-backed multipart via openAsBlob and the shared outbound proxy, as sonilo-media does; YouTube defaults to private. - Settings → Enhanced tools → Social publishing (key + profile), key probe, en/it/ru strings, routing, execution policy (irreversible_external). - server/plugins/upload-post.verify.ts and src/agent/tools/publish-tools.verify.ts run against a local fake API and a mocked fetch; no network in the suite. | 30 天前 | |
feat: add configurable AI model providers | 3 个月前 | |
fix: harden imports and provider runtimes Serialize xAI OAuth lifecycle operations, reject stale sessions, and align Grok request contracts. Fix directory imports and Silero VAD state, bound imported document context, complete Russian Agent surfaces, and split oversized shared modules without changing their contracts. Shared paths: Agent prompts and execution errors, generation routes, media import, settings, and composer UI. Validation: npx tsc -b --force; npm run lint; npm run verify:affected (33); TEST_CONCURRENCY=4 npm test; npm run build; real DeepSeek Agent read_project/read_timeline calls in Chinese and Russian; Browser4 composer smoke with zero console warnings. | 2 个月前 | |
feat(agent): note failed tool calls in a completed server run Since the failure banner no longer overrides the model's reply, nothing told the user when a run completed with a failed call the model glossed over. The executor now pushes a tool-failures event (the tracker's snapshot) right before finish; the browser appends a muted note message under the reply and the run inspector lists the calls. The note is built in the interface language on the client. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): note failed tool calls in a completed server run Since the failure banner no longer overrides the model's reply, nothing told the user when a run completed with a failed call the model glossed over. The executor now pushes a tool-failures event (the tracker's snapshot) right before finish; the browser appends a muted note message under the reply and the run inspector lists the calls. The note is built in the interface language on the client. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(publish): publish finished renders to social platforms via Upload-Post Adds publish_to_social / track_social_publish so the agent can post a completed render (the /media/uploads/ downloadUrl from track_export) to TikTok, Instagram, YouTube, LinkedIn, Facebook, X, Threads, Pinterest and Bluesky through Upload-Post. - Two steps by contract: without confirm the server only previews (file, profile, connected/missing platforms, title, privacy); confirm:true uploads. - request_id is derived from the file and the publish fields and doubles as the Idempotency-Key: re-sending an approved publish resumes it, a dropped connection never re-uploads. - File-backed multipart via openAsBlob and the shared outbound proxy, as sonilo-media does; YouTube defaults to private. - Settings → Enhanced tools → Social publishing (key + profile), key probe, en/it/ru strings, routing, execution policy (irreversible_external). - server/plugins/upload-post.verify.ts and src/agent/tools/publish-tools.verify.ts run against a local fake API and a mocked fetch; no network in the suite. | 30 天前 | |
fix(import): bound imports through the proxy, keep batches inside the run watchdog, make retry rewind the turn The previous fix bounded the TCP connect phase, which holds for a direct dial but not for the everyday case behind Clash: a blocked host behind the proxy still took ~80s per URL, and two of them in one download_media batch outlived the AI SDK's 120s chunk watchdog — which keeps counting while a tool runs — so the whole run died with "Chunk timeout of 120000ms exceeded" instead of returning per-URL failures. safePublicFetch now settles its own promise from two timers instead of relying on the request's 'error' event (Node defers that until the agent has produced a socket, i.e. until the proxy gives up): the connect bound waits for the TLS handshake on https (getCipher(), since getProtocol() reports the offered version before any byte comes back), and a 30s response-header bound covers a proxy that accepts CONNECT lazily and a host that connects and never answers. The unreachable message now says which of the two things the user can change matters: PROXY_URL without a proxy, the proxy's rules with one. download_media / push_asset batches stop starting new URLs after 75s and report the rest as failed rows, so a batch cannot outlive the watchdog; the tool description tells the model to pass at most three URLs per call. An origin that answers 4xx/5xx is now a failed row too — it used to be registered as a "remote src" success that could never play or export, and the model had to discover that itself. Retry used to append the same message again under the error, so the failed attempt (error, half-finished tool call, duplicate user turn) stayed in the model's context and steered the second try. It now rewinds both the chat and the model history to just before the turn — matched by user-turn ordinal and confirmed by text, falling back to the plain re-send when the histories cannot be matched — and re-sends it. Only the latest turn offers retry; rewinding an earlier one would discard every turn after it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
fix(import): bound imports through the proxy, keep batches inside the run watchdog, make retry rewind the turn The previous fix bounded the TCP connect phase, which holds for a direct dial but not for the everyday case behind Clash: a blocked host behind the proxy still took ~80s per URL, and two of them in one download_media batch outlived the AI SDK's 120s chunk watchdog — which keeps counting while a tool runs — so the whole run died with "Chunk timeout of 120000ms exceeded" instead of returning per-URL failures. safePublicFetch now settles its own promise from two timers instead of relying on the request's 'error' event (Node defers that until the agent has produced a socket, i.e. until the proxy gives up): the connect bound waits for the TLS handshake on https (getCipher(), since getProtocol() reports the offered version before any byte comes back), and a 30s response-header bound covers a proxy that accepts CONNECT lazily and a host that connects and never answers. The unreachable message now says which of the two things the user can change matters: PROXY_URL without a proxy, the proxy's rules with one. download_media / push_asset batches stop starting new URLs after 75s and report the rest as failed rows, so a batch cannot outlive the watchdog; the tool description tells the model to pass at most three URLs per call. An origin that answers 4xx/5xx is now a failed row too — it used to be registered as a "remote src" success that could never play or export, and the model had to discover that itself. Retry used to append the same message again under the error, so the failed attempt (error, half-finished tool call, duplicate user turn) stayed in the model's context and steered the second try. It now rewinds both the chat and the model history to just before the turn — matched by user-turn ordinal and confirmed by text, falling back to the plain re-send when the histories cannot be matched — and re-sends it. Only the latest turn offers retry; rewinding an earlier one would discard every turn after it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
fix: harden imports and provider runtimes Serialize xAI OAuth lifecycle operations, reject stale sessions, and align Grok request contracts. Fix directory imports and Silero VAD state, bound imported document context, complete Russian Agent surfaces, and split oversized shared modules without changing their contracts. Shared paths: Agent prompts and execution errors, generation routes, media import, settings, and composer UI. Validation: npx tsc -b --force; npm run lint; npm run verify:affected (33); TEST_CONCURRENCY=4 npm test; npm run build; real DeepSeek Agent read_project/read_timeline calls in Chinese and Russian; Browser4 composer smoke with zero console warnings. | 2 个月前 | |
fix(server,agent): scrub host paths from client errors, surface chat save failures - Upload, project-store and resource-preview failures returned the raw error message to the browser. The text itself is worth keeping (the editor shows it to the user), but fs errors embed absolute paths that leak the account name and install location. New scrubInternalPaths collapses POSIX/Windows absolute paths and the home directory to placeholders while preserving the sentence and the final path segment; full detail still goes to the server log. - Chat persistence failures were console.error only, so a user could talk for an hour, refresh, and find the conversation gone with no prior warning. They now raise an app toast once per failing streak (reset on the next success), matching how project-save failures are already reported in useEditorProjectPersistence. Shared paths touched: three server error responses and the agent chat write path. Successful requests and writes are unaffected; messages without paths pass through byte-identical. Verification: tsc -b --force clean; oxlint 0 warnings; new error-scrub.verify covers home-dir, POSIX and Windows path collapsing, survival of the error code and file name, and untouched path-free messages; 120 verifies across server/ and src/agent pass with 0 failures. Not changed: mobile-upload still binds 0.0.0.0. Narrowing it to one address would break machines reachable on several interfaces (the QR flow lists every LAN address), so the exposure stays documented in docs/TODO.md rather than papered over with a change that breaks the feature. | 1 个月前 | |
refactor: unify model policy, proposal commits, and export jobs Share browser and server request policy, preserve proposal concurrency recovery, and centralize render job validation and structured failures. Validated pretest, 193 main test segments, provider parity, typecheck, lint, and production build. | 26 天前 | |
feat(agent): land timeline edits per tool call in auto-apply mode In auto-apply mode the run's edits were still collected into a proposal and applied in one go when the run ended, so the user watched tool rows tick by while the timeline stayed still. Auto-apply already meant "apply whatever the run proposes"; landing each tool's edits as they happen only removes the wait. After every tool call the recorded operations are replayed onto the live project and saved (the same move-safe fence pool imports use), the draft is rebased onto the landed document so the next tool sees what the user sees — including anything they changed meanwhile — and the run's single change-log row grows with each landing and takes the model's own summary when the run ends. Landed calls are flagged in the run draft so a resumed run continues from the live project instead of applying them twice. Manual approval mode is unchanged: edits still become a proposal. Verified end to end with deepseek-v4-flash in YOLO mode: a three-step request (download, place on V1, duplicate after it) landed step by step with one change-log row and no proposal card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 | |
feat(agent): remove the cost guard approval gate entirely Users picked this product for speed; a confirmation card before paid or persistent tools added friction. The whole cost-guard layer is deleted: - skills/costGuard.ts (paid-tool registry, remember authorization, proposal auto-apply interception) and runtime-guard.ts (guard card construction) are removed; the paid-surface registry in agentSettings is gone too. - codex/runtime.ts executes every validated tool directly: the request-approval chain, deny results, and the skill-guard callback are deleted. The browser and server-run pendingGuard plumbing (executor, state, protocol, controller actions, UI card) is removed end to end. - The proposal auto-apply gate now follows the user toggle directly; the high-cost badge on proposal cards and the guard i18n copy are removed. - Paid tools keep their recovery classification: the execution policy still marks generation/export/transcription/web/sandbox as non-idempotent (outcome_unknown) so failed invocations are never replayed automatically, and offline authorization still rejects them. Preserved: parameter validation, edit-proposal approval, the auto-apply preference, external-agent real-project approval, and the approval ledger for the run inspector. Shared-path impact: tool execution boundary (codex/runtime.ts, execution-policy.ts) and both pendingGuard UI chains. Every mutating tool now runs without a card, which is the requested product behavior; proposal application and external-bridge approval are unchanged. Validation: tsc -b --force clean, lint 0 warnings, all touched verifies pass (execution policy, harness runtime, hydration recovery, executor, recovery, settings, job registry), full suite shows only the two pre-existing environmental failures, production build passes, and a real edit task ran punch animation straight through with no card. | 2 个月前 | |
fix(mcp): preserve unlocked recovery semantics Keep browser takeover lock-free while preserving offline writer fencing, retain begin-session error compatibility, and document orphan recovery in the distributed skill. Shared paths: browser registration ownership, external session startup, MCP instructions, and skill recovery guidance. Verified with focused recovery checks, MCP transport integration, TypeScript, oxlint, and diff-check. | 1 个月前 | |
Fix verified persistence, editor, and agent bugs | 2 个月前 | |
feat: add autonomous agent acceptance loop Keep the feature disabled by default and expose a bounded verification loop with inspector status.\n\nVerified with affected checks, type checking, lint, build, full tests, and six real-model Browser4 scenarios. | 2 个月前 | |
fix(agent): use file part for vision input (AI SDK deprecated image part) | 2 个月前 | |
feat(agent): vision bypass — describe images with a separate vision model DeepSeek-family main models are text-only; before this change every image (user attachments, view_timeline_frames, export QA evidence) was stripped to a one-line note, leaving the agent blind. Adds an optional vision-model bypass modeled on omp's inspect_image / describeForTextModels: - visionConfig: cc.visionModel.v1 (follow/custom/disabled) + resolveVisionModel - vision.ts: describeImageWithVision (bounded call via existing /llm proxy), describeImagesForTextModel (message-layer: image parts replaced by text descriptions in place, concurrency-bounded, failure degrades to strip), maybeDescribeFramesResult (tool-layer: __images -> visualSummary) - api-runtime + codex/runtime: message/tool-result bypass wired in - frames-tool + export-qa-tools: frame results described for text-only mains - Settings -> Agent 模型 -> 视觉理解 pane (VisionModelPane): pick any configured vision-capable model; localStorage, no server key changes - vision.verify.ts covers resolution + short-circuit contracts No server changes: vision calls reuse the /llm provider proxy. | 2 个月前 | |
feat(agent): vision bypass — describe images with a separate vision model DeepSeek-family main models are text-only; before this change every image (user attachments, view_timeline_frames, export QA evidence) was stripped to a one-line note, leaving the agent blind. Adds an optional vision-model bypass modeled on omp's inspect_image / describeForTextModels: - visionConfig: cc.visionModel.v1 (follow/custom/disabled) + resolveVisionModel - vision.ts: describeImageWithVision (bounded call via existing /llm proxy), describeImagesForTextModel (message-layer: image parts replaced by text descriptions in place, concurrency-bounded, failure degrades to strip), maybeDescribeFramesResult (tool-layer: __images -> visualSummary) - api-runtime + codex/runtime: message/tool-result bypass wired in - frames-tool + export-qa-tools: frame results described for text-only mains - Settings -> Agent 模型 -> 视觉理解 pane (VisionModelPane): pick any configured vision-capable model; localStorage, no server key changes - vision.verify.ts covers resolution + short-circuit contracts No server changes: vision calls reuse the /llm provider proxy. | 2 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 9 天前 | ||
| 9 天前 | ||
| 3 个月前 | ||
| 3 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 9 天前 | ||
| 9 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 30 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 26 天前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 9 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 26 天前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 30 天前 | ||
| 3 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 30 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 26 天前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 1 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 |