bytedance / bytedance/deer-flow
Shared composer skill feed: agent-scoped catalog + a reserved-name source for the /context compact alias
- Dominant language
- Python
- Stars
- 82.4k
- Forks
- 11.4k
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 295
Description
**Context**: surfaced during the #5102 review (skill picker entry). Two catalog/collision gaps live in the *shared* composer surfaces, pre-date that PR, and deliberately do not belong in it — both fixes change behavior for every composer path (slash suggestions and the picker alike), so they need their own change.
## 1. The skill feed is not agent-scoped
`useSkills()` (`frontend/src/components/workspace/input-box.tsx:363`) returns the unfiltered `GET /api/skills` catalog. On a custom-agent chat whose `agent.skills` is an explicit allowlist — especially `[]` — the slash suggestions and the picker both offer skills that agent cannot use. Verified today on both surfaces (they share the one feed; a picker-only filter would diverge the two surfaces for the same name).
**Proposed shape**: scope the catalog at the shared feed — e.g. a `useSkills({ agentId })`-style parameter or a selector that intersects with the active agent's allowlist when one is set — so every consumer (slash suggestions at input-box.tsx:1300, the picker's `getSelectableSkills`, anything future) derives from one source.
## 2. A skill named `context` collides with the `/context compact` alias
`parseCompactCommand` accepts `/^(?:compact|context\s+compact)\s*$/i` (`frontend/src/components/workspace/input-box-helpers.ts:265`), but `context` is in neither `RESERVED_SLASH_SKILL_NAMES` nor `COMPOSER_BUILTIN_COMMAND_NAMES` (`frontend/src/core/skills/slash.ts`). Verified today, entirely on the pre-existing slash path:
- `getMatchingSkillSuggestions([skill("context")], "context", [])` → offers it (`kind: "skill"`);
- `getInputSubmitAction({ text: "/context compact", fileCount: 0, status: "idle" })` → `{ kind: "compact" }` — picking the skill and typing `compact` as the task silently runs context compaction instead of the skill.
**Proposed shape**: fix it at the parse/reserved-name contract, not at either suggestion surface — e.g. teach the shared exclusion source (or `parseCompactCommand` itself) that `context` is unreachable when followed by `compact`, mirroring how `compact` is already owned by `COMPOSER_BUILTIN_COMMAND_NAMES`. `core/skills/slash.ts` is already the contract-pinned module mirrored by the backend via `contracts/slash_skill_contract.json`, so the reserved-name change should consider whether the fixture needs to move too.
Happy to take either or both as a follow-up PR once the picker lands.
Contributor guide
Research direction
Start with useSkills() in frontend/src/components/workspace/input-box.tsx and its shared consumers, including the slash suggestions and getSelectableSkills, then trace how the active agent allowlist reaches the feed. Read parseCompactCommand in frontend/src/components/workspace/input-box-helpers.ts and the reserved-name contract in frontend/src/core/skills/slash.ts, checking contracts/slash_skill_contract.json. Done means both surfaces show only allowed skills and a context skill cannot conflict with /context compact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100