basant307/AI_Governance_Project
045
1# Skill Required Capabilities Design2 3Status: design note; this PR proceeds with Option B and leaves4`required-capabilities` as a future proposal.5 6## Context7 8Web Shell can render custom fenced code blocks through its markdown renderer. The9chart renderer proposal uses an `echarts-fulldata` fenced code block so the model10can return a complete ECharts option and dataset payload that Web Shell renders11as an interactive chart.12 13That output contract is only useful in clients that can render it. In the CLI,14ACP clients, or any other surface without a matching renderer, the same response15would appear as a large code block instead of a chart.16 17The initial bundled chart skill proposal relied on wording to tell the model18that the format is for Web Shell. This is a soft guard. If the skill is exposed19in a non-Web-Shell session, the model can still choose an output format that the20client cannot render.21 22For the current PR, Qwen Code keeps the renderer extension point in Web Shell23but does not bundle `qwencode-viz` in core. The Web Shell package includes a24copyable, non-auto-loaded skill template, and hosts should install or inject25that skill only when they also register an `echarts-fulldata` renderer.26 27## Problem28 29Qwen Code needs a clear way to decide whether a host-specific skill should be30shown to the model and to users.31 32For `qwencode-viz`, the concrete question is:33 34- Should core support a generic `required-capabilities` skill metadata field?35- Or should `qwencode-viz` not be a core bundled skill at all, and instead be36 supplied only by Web Shell clients that install or inject it?37 38## Goals39 40- Prevent renderer-specific skills from being exposed when the current client41 cannot satisfy their output contract.42- Keep startup skill reminders, explicit skill activation, slash-command43 discovery, and skill validation consistent.44- Avoid hardcoding `qwencode-viz` as a special case.45- Preserve existing skill behavior when no capability requirement is declared.46- Keep the design extensible for future host capabilities, not only ECharts.47 48## Non-goals49 50- Implementing the ECharts renderer itself.51- Redesigning all client/server capability negotiation.52- Changing the semantics of existing skill frontmatter.53- Solving multi-client shared-session capability changes in the first version.54 55## Current Related Mechanisms56 57The codebase already has several visibility controls, but none represent client58rendering capabilities:59 60- `disable-model-invocation`: prevents a skill from being auto-invoked by the61 model.62- `user-invocable`: controls whether a bundled skill is available as a command.63- `paths`: scopes skill availability to matching workspace paths.64- `skills.disabled`: disables configured skills.65- `allowedTools`: currently used by bundled skill loading to hide cron-oriented66 skills when cron tools are unavailable.67- Slash command `supportedModes`: filters commands by execution mode.68- Daemon and ACP capability objects: describe protocol or client support, but69 are not currently connected to skill exposure.70 71There is no existing `required-capabilities` or equivalent skill frontmatter.72Adding it would be a new skill contract.73 74## Option A: Add `required-capabilities`75 76Add a generic skill frontmatter field:77 78```yaml79---80name: qwencode-viz81description: Render analytical charts in Web Shell using echarts-fulldata fenced code blocks.82required-capabilities:83 - markdown.codeBlock.echarts-fulldata84---85```86 87When the current client/session does not advertise all listed capabilities, the88skill is treated as unavailable.89 90### Capability Naming91 92Use namespaced string capabilities:93 94```text95markdown.codeBlock.echarts-fulldata96```97 98This keeps the field generic while making the contract precise:99 100- `markdown`: the capability belongs to rendered markdown.101- `codeBlock`: the capability applies to fenced code block rendering.102- `echarts-fulldata`: the specific language/info string supported by the103 renderer.104 105Future examples could be:106 107- `markdown.codeBlock.vega-lite`108- `markdown.codeBlock.mermaid-interactive`109- `artifact.openUrl`110 111### Skill Metadata112 113Add `requiredCapabilities?: string[]` to skill configuration after parsing the114frontmatter key `required-capabilities`.115 116Both skill parsing paths should understand the field:117 118- `packages/core/src/skills/skill-load.ts`119- `packages/core/src/skills/skill-manager.ts`120 121The field should be optional. Missing or empty means the skill has no client122capability requirement.123 124### Runtime Capability Source125 126Add client/session capabilities to the runtime config:127 128```ts129interface ConfigParameters {130 clientCapabilitiesProvider?: () => ReadonlySet<string>;131}132```133 134Expose a helper on `Config`, for example:135 136```ts137config.getClientCapabilities(): ReadonlySet<string>138```139 140Then centralize the check:141 142```ts143function skillMeetsRequiredCapabilities(skill: Skill, config: Config): boolean {144 return skill.config.requiredCapabilities.every((capability) =>145 config.getClientCapabilities().has(capability),146 );147}148```149 150### Filtering Points151 152The capability filter should be applied before skills are exposed to either the153model or the user:154 155- `collectAvailableSkillEntries` in `packages/core/src/tools/skill-utils.ts`156 should skip skills whose required capabilities are missing. This keeps startup157 skill reminders, delta reminders, `SkillTool` validation, and model-invocable158 activation aligned.159- `BundledSkillLoader` should skip unavailable bundled skills when creating160 user-facing commands.161- `SkillCommandLoader` should skip unavailable file-system skills when creating162 user-facing commands.163 164The important invariant is that a skill hidden from the model should not still165appear as an invocable command unless the project intentionally supports a166manual override.167 168### Web Shell Registration169 170Web Shell should advertise renderer support explicitly rather than relying on171the presence of an opaque `renderCodeBlock` callback.172 173For example:174 175```tsx176<WebShell177 customization={{178 markdown: {179 renderableCodeBlockLanguages: ['echarts-fulldata'],180 renderCodeBlock(info) {181 // render custom blocks182 },183 },184 }}185/>186```187 188The Web Shell client can map that to:189 190```text191markdown.codeBlock.echarts-fulldata192```193 194This makes the capability declaration stable even if the renderer callback195contains custom logic, fallbacks, or multiple supported languages.196 197### Daemon and ACP Propagation198 199For hosted or daemon-based sessions, the client capability set needs to reach200core before skills are loaded or listed. A minimal version can pass capabilities201when creating a session:202 203```ts204interface CreateSessionRequest {205 clientCapabilities?: string[];206}207```208 209The daemon bridge, SDK, and ACP session creation flow can store this as210session-scoped config.211 212For the first version, capabilities can be session-scoped. If multiple clients213attach to the same session, the behavior should be documented as using the214capabilities from session creation time.215 216### Pros217 218- Keeps `qwencode-viz` as one canonical bundled skill.219- Prevents host-specific output contracts from leaking into unsupported220 clients.221- Creates a reusable mechanism for future renderer-specific or host-specific222 skills.223- Makes the dependency explicit and testable.224 225### Cons226 227- Adds a new cross-cutting skill metadata field.228- Requires client/session capability plumbing across Web Shell, daemon, SDK, and229 ACP surfaces.230- Needs careful documentation for shared-session behavior.231- May be more machinery than needed if `qwencode-viz` is the only expected232 capability-gated skill.233 234## Option B: Client-Supplied Skill235 236Do not add a generic `required-capabilities` field. Instead, avoid bundling237`qwencode-viz` in core. The Web Shell client, or any client that supports the238renderer, supplies the skill itself.239 240Possible distribution models:241 242- The Web Shell host installs `.qwen/skills/qwencode-viz/SKILL.md`.243- The Web Shell package ships an optional non-auto-loaded skill template that a244 host can copy or install when chart rendering is enabled.245- The Web Shell integration ships an extension skill package.246- The Web Shell integration injects equivalent model instructions only when its247 chart renderer is enabled.248 249In this model, the skill is available only because the rendering client chose to250provide it.251 252### Web Shell Host Integration253 254A Web Shell host that wants chart output should opt in to both halves of the255contract:256 2571. Register an `echarts-fulldata` Markdown code block renderer.2582. Provide the matching chart skill from259 `packages/web-shell/docs/examples/qwencode-viz/SKILL.md`.260 261For example:262 263```tsx264import * as echarts from 'echarts';265import {266 WebShellWithProviders,267 createEchartsFullDataRenderer,268} from '@qwen-code/web-shell';269 270<WebShellWithProviders271 baseUrl="http://127.0.0.1:4170"272 token={token}273 sessionId={sessionId}274 markdown={{275 renderCodeBlock: createEchartsFullDataRenderer({276 loadEcharts: () => echarts,277 resolveDataRef: async (ref, meta) =>278 loadControlledChartDataset(ref, meta),279 }),280 }}281/>;282```283 284In this renderer configuration, `loadEcharts` lets the host provide the285approved ECharts runtime, either as a static import or a lazy-loaded module.286`resolveDataRef` is only used for `data.kind="ref"` chart blocks; it is the287host-owned bridge from a model-visible data reference to a trusted dataset.288The model-facing envelope format is described by the optional skill template in289`packages/web-shell/docs/examples/qwencode-viz/SKILL.md`; the renderer-side290validation lives in291`packages/web-shell/client/components/messages/EchartsFullDataBlock.tsx`.292 293The skill file should be installed or injected only by hosts that perform this294registration. A simple file-based integration can copy:295 296```text297packages/web-shell/docs/examples/qwencode-viz/SKILL.md298```299 300to the workspace or user skill directory, for example:301 302```text303.qwen/skills/qwencode-viz/SKILL.md304```305 306An integration with its own skill distribution layer can instead load the same307file as the canonical source content and expose it through that layer. In both308cases, core does not auto-load the skill; the host owns enabling it because the309host owns the renderer.310 311For `data.kind="ref"` envelopes, the built-in renderer validates that `data.ref`312uses a normalized `artifact://` or `session-file://` reference before it calls313the host-controlled `resolveDataRef(ref, meta)` implementation. The renderer314also parses the block as JSON and sanitizes the ECharts option before rendering;315it does not evaluate model-provided JavaScript, fetch arbitrary URLs, or read316local files by itself. A custom renderer should preserve the same split:317renderer-level JSON/ref/option validation first, host-owned artifact resolution318second.319 320A daemon-backed host can treat the workspace file API as one artifact backend.321For example, the host can persist chart artifacts under a controlled workspace322directory such as `.qwen/artifacts/`, expose model-facing references like323`artifact://chart-data/orders.csv`, and resolve them through daemon324`GET /file?path=.qwen/artifacts/chart-data/orders.csv`. This keeps325`artifact://` as the public chart contract while allowing the first326implementation to reuse daemon workspace files.327 328The resolver must still enforce the artifact root before calling the daemon:329 330```tsx331const ARTIFACT_ROOT = '.qwen/artifacts/';332const MAX_CHART_DATA_BYTES = 256 * 1024;333 334async function resolveDataRef(335 ref: string,336 meta: { format?: string; dimensions?: string[] },337) {338 const artifactPrefix = 'artifact://';339 if (!ref.startsWith(artifactPrefix)) {340 throw new Error(`Unsupported chart data ref: ${ref}`);341 }342 343 const artifactPath = ref.slice(artifactPrefix.length);344 if (345 artifactPath.length === 0 ||346 artifactPath.startsWith('/') ||347 artifactPath.includes('\\') ||348 artifactPath.split('/').includes('..')349 ) {350 throw new Error(`Invalid chart data ref: ${ref}`);351 }352 353 const url = new URL('/file', daemonBaseUrl);354 url.searchParams.set('path', `${ARTIFACT_ROOT}${artifactPath}`);355 url.searchParams.set('maxBytes', String(MAX_CHART_DATA_BYTES));356 357 const response = await fetch(url, {358 headers: token ? { Authorization: `Bearer ${token}` } : undefined,359 });360 if (!response.ok) {361 throw new Error(`Failed to read chart data: ${response.status}`);362 }363 364 const file = (await response.json()) as { content: string };365 return meta.format === 'csv'366 ? parseCsvAsArrayRows(file.content, meta.dimensions)367 : JSON.parse(file.content);368}369```370 371This example intentionally maps only normalized `artifact://` paths under372`.qwen/artifacts/`. If a host later moves artifacts to object storage or a373session-scoped artifact service, only `resolveDataRef` needs to change; the374model-facing `echarts-fulldata` block can keep using the same ref shape.375 376### Pros377 378- Minimal core change.379- No new global skill metadata contract.380- Capability availability is naturally owned by the client that implements the381 renderer.382- Avoids daemon or ACP plumbing unless the client already has a skill injection383 mechanism.384 385### Cons386 387- No canonical bundled skill unless all clients copy the same content.388- More burden on each Web Shell integrator.389- Users moving between clients may see inconsistent skill availability.390- Does not create a general safeguard for future host-specific skills.391- Harder to test in core because availability depends on external installation392 or injection.393 394## Recommendation395 396For this PR, use Option B.397 398That keeps the core skill system unchanged and avoids exposing399`echarts-fulldata` instructions in unsupported clients. The Web Shell renderer400hook remains useful for any host-owned block renderer, while chart-specific401model instructions become an explicit host opt-in.402 403Longer term, discuss this as a product/API boundary decision.404 405Choose Option A if maintainers expect Qwen Code to support more client-rendered406output contracts over time. In that case, `required-capabilities` is a small407general contract that keeps skill exposure honest across CLI, Web Shell, ACP,408and future clients.409 410Choose Option B if `qwencode-viz` is expected to remain a Web-Shell-only411extension and maintainers do not want core skills to depend on client rendering412features. In that case, the current bundled skill should be removed from core413and supplied by Web Shell clients that support `echarts-fulldata`.414 415The recommended future default is Option A only if maintainers are comfortable416making client/session capabilities part of the skill system. Otherwise, keep417host-renderer skills client-owned.418 419## Open Questions420 421- Should capabilities be session-scoped, request-scoped, or client-scoped?422- Should missing capabilities hide user-invocable commands, or only hide423 model-invocable skill activation?424- Should capability names be free-form strings or validated against a known425 registry?426- Should unavailable skills be hidden entirely from `/skills`, or shown as427 disabled with a reason?428- Should there be a manual override for users who intentionally want to emit raw429 `echarts-fulldata` blocks in unsupported clients?430- Should the field name be `required-capabilities`, `requires-capabilities`, or431 `client-capabilities`?432 433## Validation Plan434 435If Option A is implemented, add tests for:436 437- Frontmatter parsing in both skill parsing paths.438- `collectAvailableSkillEntries` hiding a skill when capabilities are missing.439- The same skill appearing when capabilities are present.440- Interaction with `paths`, `skills.disabled`, and `disable-model-invocation`.441- `BundledSkillLoader` and `SkillCommandLoader` command visibility.442- Web Shell mapping from supported code block languages to client capabilities.443- Daemon or ACP session creation preserving the capability set.444- Existing bundled skill integration tests, to ensure skills without445 `required-capabilities` are unchanged.446 447## Migration448 449Existing skills require no migration because the new field is optional.450 451For the current Option B path, remove the chart skill from core bundled skills.452The Web Shell package template must not be loaded by core automatically; hosts453opt in by installing or injecting it.454 455If Option A is accepted, add:456 457```yaml458required-capabilities:459 - markdown.codeBlock.echarts-fulldata460```461 462to a future bundled `qwencode-viz`.463 464If Option B is accepted, remove the chart skill from core bundled skills and465document how Web Shell clients can install or inject it when they register an466`echarts-fulldata` renderer.467 