Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/fabioc-aloha/ChessCoach --skill chat-participant-patterns명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| type | skill |
| lifecycle | stable |
| inheritance | inheritable |
| name | chat-participant-patterns |
| description | VS Code Chat API patterns. |
| tier | standard |
| user-invokable | false |
| applyTo | **/*participant*,**/*chat*,**/*copilot*,**/lm/** |
| currency | 2026-04-22T00:00:00.000Z |
VS Code Chat API patterns.
Chat APIs evolve with VS Code releases. Last validated: March 2026 (VS Code 1.111+)
Check: Chat API, LM API, Tools API, AI Extensibility Overview, EXTERNAL-API-REGISTRY.md
| Approach | Use When | VS Code API |
|---|---|---|
| Chat Participant | Need full control of prompt + response, domain-specific @-mention | vscode.chat.createChatParticipant |
| LM Tool | Domain capability invoked automatically in agent sessions | vscode.lm.registerTool |
| Agent Skill (SKILL.md) | Domain knowledge embedded into any agent session (no code) | chat.useAgentSkills + SKILL.md file |
| MCP Server | Cross-platform tool providing data/actions to any MCP client | MCP SDK |
→ Prefer Skills for domain knowledge. Reserve participants for full prompt orchestration.
// package.json contribution
"contributes": {
"chatParticipants": [{
"id": "my-ext.participant",
"name": "myparticipant",
"fullName": "My Participant",
"description": "What can I help with?",
"isSticky": true,
: [{ : , : }]
}]
}
participant = vscode..(, handler);
participant. = vscode..(context., );
const handler: vscode.ChatRequestHandler = async (
request: vscode.ChatRequest,
context: vscode.ChatContext,
stream: vscode.ChatResponseStream,
token: vscode.CancellationToken
): Promise<IChatResult> => {
// Handle request
};
| Operation | Method |
|---|---|
| Stream text | stream.markdown() |
| Show progress | stream.progress() |
| Add button | stream.button() |
| File tree | stream.filetree() |
| Reference | stream.reference() |
| Inline anchor | stream.anchor() |
| Access history | context.history |
| Get references | request.references |
| Get model | request.model |
| Check command | request.command |
| Chat location | request.location |
// Markdown (supports CommonMark)
stream.markdown('# Title\n**bold** and _italic_');
// Code block with IntelliSense
stream.markdown('```typescript\nconst x = 1;\n```');
// Progress message
stream.progress('Processing...');
// Button (invokes VS Code command)
stream.button({ command: 'my.command', title: 'Run' });
// Command link in markdown
const md = new vscode.MarkdownString('[Run](command:my.command)');
md.isTrusted = { enabledCommands: ['my.command'] };
stream.markdown(md);
// File tree
stream.filetree([{ name: 'src', children: [{ name: 'app.ts' }] }], baseUri);
// Reference
stream.reference(vscode.Uri.file('/path/to/file.ts'));
stream.reference(new vscode.Location(uri, range));
const models = await vscode.lm.selectChatModels({ vendor: 'copilot' });
const response = await models[0].sendRequest(messages, {}, token);
for await (const chunk of response.text) {
stream.markdown(chunk);
}
// Using @vscode/chat-extension-utils library (recommended)
import * as chatUtils from '@vscode/chat-extension-utils';
const tools = vscode.lm.tools.filter(t => t.tags.includes('my-tag'));
const result = chatUtils.sendChatParticipantRequest(request, context, {
prompt: 'System instructions here',
responseStreamOptions: { stream, references: true, responseText: true },
tools
}, token);
return await result.result;
vscode.lm.registerTool('tool_name', {
async invoke(options, token) {
return new vscode.LanguageModelToolResult([
new vscode.LanguageModelTextPart('result text')
]);
}
});
"chatParticipants": [{
"id": "my-ext.participant",
"disambiguation": [{
"category": "my-domain",
"description": "Questions about X domain",
"examples": ["How do I do X?", "Explain Y concept"]
}]
}]
participant.followupProvider = {
provideFollowups(result, context, token) {
return [{ prompt: 'Tell me more', label: 'More details' }];
}
};
// Get previous requests to this participant
const previousRequests = context.history.filter(
h => h instanceof vscode.ChatRequestTurn
);
| Do | Don't |
|---|---|
| Stream responses incrementally | Block until complete |
| Handle cancellation via token | Ignore cancellation token |
| Catch and handle errors | Let exceptions crash |
| Use progress for long operations | Leave user waiting silently |
| Limit to one participant per extension | Create multiple participants |
| Ask consent for costly operations | Auto-execute destructive actions |
When a chat participant routes user intent to an action (muscle execution, file modification, or LLM judgment), evaluate the routing decision against this table. The goal: never silently auto-decide between a mechanical action and a semantic follow-up.
| # | Check | Pass | Fail | Action on Fail |
|---|---|---|---|---|
| 1 | Mechanical vs semantic classification — handler knows whether the request needs script execution, LLM judgment, or both | Request classified as M (muscle), S (LLM-only), or H (hybrid with handoff) | Handler treats all requests the same way | Classify intent; route M to muscle, S to LLM, H to muscle-then-prompt |
| 2 | Hybrid handoff signal — when a muscle runs and produces artifacts, the chat response references the decision table for Phase 2 | Response includes skill reference + table rows the LLM should evaluate | Muscle result returned as plain text with no follow-up guidance | Use skillPrompt() helper from muscleRunner.ts to generate Phase 2 prompt |
| 3 | No silent auto-decision — when multiple valid actions exist, participant surfaces the choice to the user | QuickPick, follow-up buttons, or explicit question before acting | Handler picks one action without user input | Add follow-up provider or QuickPick for ambiguous intents |
| 4 | Cancellation respected — long-running operations check CancellationToken | Token checked before each phase; early exit on cancellation | Operation runs to completion ignoring cancel | Add token.isCancellationRequested checks between phases |
| 5 | Error context preserved — when an operation fails, the error includes enough context for the user to retry or escalate | Error message includes: what was attempted, what failed, suggested next step | Generic "something went wrong" or raw exception text | Wrap errors with action context; suggest concrete recovery steps |
| 6 | Decision table reference in response — when the LLM makes a judgment, the response cites which decision table row matched | "Based on row N of [table name]: [rationale]" | LLM responds with freeform judgment and no table reference | Reference the specific skill + decision table in the system prompt |
Current state of handler.ts: Minimal stub — delegates entirely to Copilot via workspace context. This is architecturally correct (Cardinal Rule I6: architecture doesn't depend on extension). The decision table applies when/if the handler gains intent-routing logic in the future.