Even after the previous owner check, the agent could still patch/edit
a UI-uploaded skill (source=upload) it happened to own. Uploaded skills
represent human-reviewed content; letting the agent rewrite them risks
silent drift from what the user approved.
Add _assert_skill_is_agent_authored which reads usage.json and refuses
unless source==agent. Wired into all five write actions
(create/edit/patch/delete/write_file/remove_file). Skills with no usage
entry default to source=upload, so legacy and adopted-orphan skills are
also refused — only skills the agent created via mark_agent_created in
the create flow stay editable.
Note: this check is independent of skill_store availability (it reads
the usage file, not the DB), so it runs even when skill_store is None.
Tests that exercise non-create paths against pre-existing skills will
need to call mark_agent_created first or mock get_entry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The review agent was creating too many low-value skills. Three changes
tighten the funnel:
- review_worker prompt: rewritten in "保守模式". Default decision is
do-nothing. To create, all five AND conditions must hold (>=5 tool
calls with step dependencies, an explicit fail->fix->success episode,
cross-scenario reusability, no >=70% overlap with skill_list, can
produce >=300 chars of substance). Adds 7 explicit NO categories
(single-tool loops, one-off queries, LLM common knowledge, etc.)
and a 4-question self-check before any create. Hard cap of 1 new
skill per review, with patch preferred over create.
- min_tool_calls: 3 -> 5. Matches the prompt's ">=5 steps" hard
condition so trivial turns never reach the LLM reviewer.
- Updated config.yaml, the default-value assertion in
test_skill_review_worker, and the middleware docstring's "(default
3)" annotation to keep all three references in sync.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Only delete had a DB owner check via _assert_agent_may_delete. The other
four write actions only called ensure_custom_skill_is_editable, which
just verifies the directory exists under skills/custom/ — it does not
check owner_user_id. Any agent that knew a skill's name could overwrite
or strip support files from another user's UI-uploaded skill.
Generalise the helper to _assert_agent_may_modify (same three rules:
no DB row / built-in owner=None / owner mismatch) and call it from
edit, patch, delete, write_file, and remove_file. Hoist user_id +
skill_store to the top of the lock block so the four newly-guarded
branches stay one-liners and create/delete reuse the same handles.
Behaviour preserved when skill_store is None (no DB) — matches the
existing delete fallback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- workspace-nav-studio: return null while isLoading so the "工作室" group
no longer briefly mounts and then unmounts when getTokenByEmail returns
"用户不存在" (404). Skeleton branch became dead code, removed.
- studio/hooks: switch all three token queries from retry: 1 to false —
account-not-found is a permanent error; retry just doubled isError latency.
- env: drop VITE_STUDIO_ENABLED everywhere (env.ts + 7 env files +
workspace-nav-chat-list). Sidebar availability is now decided at runtime
by token success instead of a build-time flag.
- env: add VITE_AIPI_PRESENT_URL + VITE_AIPI_KNOWES_URL for the document
upload popup's A-system jump + B-system knowledge iframe; reuse the
existing VITE_AIPI_KNOWLEDGE_URL for the Y-system iframe.
- document-upload-popup: replace 8 hardcoded URLs (6 present, 1 knowes,
1 knowlibrary) with the corresponding env vars.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>