스니펫을 사용하는 Code Mode
스니펫은 재사용 가능한 TypeScript 스니펫의 영속 라이브러리로 Code Mode를 확장합니다. LLM이 유용한 코드(예를 들어 NPM 패키지를 가져와 순위를 매기는 함수)를 작성하면 해당 코드를 _스니펫_으로 저장할 수 있습니다. 이후 요청에서는 관련 스니펫이 저장소에서 로드되어, LLM이 로직을 다시 작성하지 않고 호출할 수 있는 일급 도구로 제공됩니다.
에이전트 작성 스킬과는 다릅니다. 이 페이지의 스니펫은 채팅 LLM이 저장하고 재사용하는 런타임 스니펫입니다. 코딩 어시스턴트(Claude Code, Cursor 등)에 TanStack AI 자체의 작동 방식을 가르치려는 경우 Agent Skills (TanStack Intent)를 참고하세요.
개요
스니펫 시스템에는 두 가지 통합 경로가 있습니다.
| 방식 | 진입점 | 스니펫 선택 | 적합한 경우 |
|---|---|---|---|
| High-level | codeModeWithSnippets() | 자동(LLM 기반) | 새 프로젝트, 즉시 사용 가능한 설정 |
| Manual | 개별 함수(snippetsToTools, createSnippetManagementTools 등) | 로드할 스니펫을 직접 결정 | 완전한 제어, 기존 설정 |
두 경로는 동일한 저장, 신뢰, 실행 기본 요소를 공유하며 스니펫을 선택하고 조합하는 방식만 다릅니다.
작동 방식
스니펫을 활성화한 요청은 다음 단계를 거칩니다.
┌─────────────────────────────────────────────────────┐
│ 1. Load snippet index (metadata only, no code) │
├─────────────────────────────────────────────────────┤
│ 2. Select relevant snippets (LLM call — fast model) │
├─────────────────────────────────────────────────────┤
│ 3. Build tool registry │
│ ├── execute_typescript (Code Mode sandbox) │
│ ├── search_snippets / get_snippet / register_snippet │
│ └── snippet tools (one per selected snippet) │
├─────────────────────────────────────────────────────┤
│ 4. Generate system prompt │
│ ├── Code Mode type stubs │
│ └── Snippet library documentation │
├─────────────────────────────────────────────────────┤
│ 5. Main chat() call (strong model) │
│ ├── Can call snippet tools directly │
│ ├── Can write code via execute_typescript │
│ └── Can register new snippets for future use │
└─────────────────────────────────────────────────────┘
LLM 호출
High-level API를 사용하면 요청마다 LLM 상호작용이 두 번 발생합니다.
-
스니펫 선택 (
selectRelevantSnippets) — 제공한 어댑터를 사용하는 단일 채팅 호출입니다. 최근 대화 메시지 5개와 스니펫 이름/설명 카탈로그를 보내고, 관련 스니펫 이름의 JSON 배열을 반환하도록 모델에 요청합니다. 저렴하고 빠른 모델(예:gpt-4o-mini,claude-haiku-4-5)을 사용해야 합니다. -
주요 채팅 — 전체 모델을 사용하는 기본
chat()호출입니다. 여기서 LLM이 추론하고 도구를 호출하며 코드를 작성하고 스니펫을 등록합니다.
선택 호출은 가볍습니다. 전체 코드가 아니라 스니펫 메타데이터(이름, 설명, 사용 힌트)만 확인합니다. 저장소에 스니펫이나 메시지가 없으면 즉시 종료되어 LLM 호출 전체를 건너뜁니다.
고수준 API: codeModeWithSnippets()
설치
pnpm add @tanstack/ai-code-mode-snippets
사용법
import { chat, maxIterations, toServerSentEventsStream } from '@tanstack/ai'
import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
import { codeModeWithSnippets } from '@tanstack/ai-code-mode-snippets'
import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
import { openaiText } from '@tanstack/ai-openai'
import { myTool1, myTool2 } from './tools'
const messages = [{ role: 'user' as const, content: 'Hello' }]
const storage = createFileSnippetStorage({ directory: './.snippets' })
const driver = createNodeIsolateDriver()
const { toolsRegistry, systemPrompt, selectedSnippets } = await codeModeWithSnippets({
config: {
driver,
tools: [myTool1, myTool2],
timeout: 60_000,
memoryLimit: 128,
},
adapter: openaiText('gpt-5-mini'), // cheap model for snippet selection
snippets: {
storage,
maxSnippetsInContext: 5,
},
messages, // current conversation
})
const stream = chat({
adapter: openaiText('gpt-5.5'), // strong model for reasoning
tools: toolsRegistry.getTools(),
messages,
systemPrompts: ['You are a helpful assistant.', systemPrompt],
agentLoopStrategy: maxIterations(15),
})
codeModeWithSnippets는 다음을 반환합니다.
| 속성 | 타입 | 설명 |
|---|---|---|
toolsRegistry | ToolRegistry | 모든 도구를 포함하는 변경 가능한 레지스트리입니다. chat()를 통해 tools: toolsRegistry.getTools()에 전달합니다. |
systemPrompt | string | Code Mode와 스니펫 라이브러리 문서를 결합한 프롬프트입니다. |
selectedSnippets | Array<Snippet> | 선택 모델이 이 대화를 위해 고른 스니펫입니다. |
레지스트리에 포함되는 항목
레지스트리는 다음 항목으로 채워집니다.
execute_typescript— Code Mode 샌드박스 도구입니다. 샌드박스 내부에서는 스니펫도snippet_*함수로 제공됩니다(실행 시 동적으로 로드됨).search_snippets— 쿼리로 스니펫 라이브러리를 검색합니다. 일치하는 스니펫 메타데이터를 반환합니다.get_snippet— 특정 스니펫의 전체 세부 정보(코드 포함)를 가져옵니다.register_snippet— 작동하는 코드를 새 스니펫으로 저장합니다. 새로 등록된 스니펫은 즉시 호출 가능한 도구로 레지스트리에 추가됩니다.- 선택된 스니펫마다 하나의 도구 — 선택된 각 스니펫은 직접 호출할 수 있는 도구가 됩니다(설명에
[SNIPPET]접두사가 붙음). LLM은execute_typescript를 거치지 않고 호출할 수 있습니다.
수동 API
완전히 제어하려면(예를 들어 LLM 기반 선택 대신 모든 스니펫을 로드하려면) 하위 수준 함수를 직접 사용하세요. ts-code-mode-web 예제에서 사용하는 방식입니다.
import { chat, maxIterations } from '@tanstack/ai'
import { createCodeMode } from '@tanstack/ai-code-mode'
import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node'
import {
createAlwaysTrustedStrategy,
createSnippetManagementTools,
createSnippetsSystemPrompt,
snippetsToTools,
} from '@tanstack/ai-code-mode-snippets'
import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
import { openaiText } from '@tanstack/ai-openai'
import { myTool1, myTool2, BASE_PROMPT } from './tools'
const messages = [{ role: 'user' as const, content: 'Hello' }]
const trustStrategy = createAlwaysTrustedStrategy()
const storage = createFileSnippetStorage({
directory: './.snippets',
trustStrategy,
})
const driver = createNodeIsolateDriver()
// 1. Create Code Mode tool + prompt
const { tool: codeModeTool, systemPrompt: codeModePrompt } =
createCodeMode({
driver,
tools: [myTool1, myTool2],
timeout: 60_000,
memoryLimit: 128,
})
// 2. Load all snippets and convert to tools
const allSnippets = await storage.loadAll()
const snippetIndex = await storage.loadIndex()
const snippetTools = allSnippets.length > 0
? snippetsToTools({
snippets: allSnippets,
driver,
tools: [myTool1, myTool2],
storage,
timeout: 60_000,
memoryLimit: 128,
})
: []
// 3. Create management tools
const managementTools = createSnippetManagementTools({
storage,
trustStrategy,
})
// 4. Generate snippet library prompt
const snippetsPrompt = createSnippetsSystemPrompt({
selectedSnippets: allSnippets,
totalSnippetCount: snippetIndex.length,
snippetsAsTools: true,
})
// 5. Assemble and call chat()
const stream = chat({
adapter: openaiText('gpt-5.5'),
tools: [codeModeTool, ...managementTools, ...snippetTools],
messages,
systemPrompts: [BASE_PROMPT, codeModePrompt, snippetsPrompt],
agentLoopStrategy: maxIterations(15),
})
이 방식은 선택 LLM 호출을 완전히 건너뜁니다. 원하는 스니펫을 로드해 직접 전달합니다.
스니펫 저장소
스니펫은 SnippetStorage 인터페이스를 통해 영속화됩니다. 두 가지 구현이 제공됩니다.
파일 저장소(프로덕션)
createFileSnippetStorage는 node:fs / node:path를 가져오는 Node 전용 기능이므로 패키지 루트가 아닌 /storage 하위 경로를 통해 제공됩니다. 이렇게 하면 루트 export를 Cloudflare Workers 및 브라우저 빌드에 안전하게 번들할 수 있으며, Node 런타임에서만 하위 경로를 사용하면 됩니다.
import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage'
import { createDefaultTrustStrategy } from '@tanstack/ai-code-mode-snippets'
const trustStrategy = createDefaultTrustStrategy()
const storage = createFileSnippetStorage({
directory: './.snippets',
trustStrategy, // optional, defaults to createDefaultTrustStrategy()
})
다음 디렉터리 구조를 생성합니다.
.snippets/
_index.json # Lightweight catalog for fast loading
fetch_github_stats/
meta.json # Description, schemas, hints, stats
code.ts # TypeScript source
compare_npm_packages/
meta.json
code.ts
메모리 저장소(테스트 및 엣지 런타임)
import { createMemorySnippetStorage } from '@tanstack/ai-code-mode-snippets'
const storage = createMemorySnippetStorage()
모든 항목을 메모리에 유지합니다. node:fs 의존성이 없으므로 패키지 루트에서 다시 export되며 Workers와 브라우저에서 안전하게 사용할 수 있습니다. 테스트, 데모, 엣지 배포에 유용합니다. (/storage 하위 경로에서도 사용할 수 있습니다.)
저장소 인터페이스
두 구현 모두 이 인터페이스를 만족합니다:
| 메서드 | 설명 |
|---|---|
loadIndex() | 모든 스니펫의 경량 메타데이터를 로드합니다(코드 제외). |
loadAll() | 코드가 포함된 전체 세부 정보와 함께 모든 스니펫을 로드합니다. |
get(name) | 이름으로 단일 스니펫을 가져옵니다. |
save(snippet) | 스니펫을 생성하거나 업데이트합니다. |
delete(name) | 스니펫을 제거합니다. |
search(query, options?) | 텍스트 쿼리로 스니펫을 검색합니다. |
updateStats(name, success) | 신뢰 추적을 위해 실행 결과를 기록합니다. |
신뢰 전략
스니펫은 신뢰되지 않은 상태로 시작하며 성공적인 실행을 통해 신뢰를 얻습니다. 신뢰 수준은 메타데이터일 뿐이며 현재 실행을 제한하지 않습니다. 네 가지 기본 제공 전략을 사용할 수 있습니다.
import {
createDefaultTrustStrategy,
createAlwaysTrustedStrategy,
createRelaxedTrustStrategy,
createCustomTrustStrategy,
} from '@tanstack/ai-code-mode-snippets'
| 전략 | 초기 단계 | 임시 | 신뢰할 수 있음 |
|---|---|---|---|
| Default | untrusted | 10회 이상 실행, 성공률 ≥90% | 100회 이상 실행, 성공률 ≥95% |
| Relaxed | untrusted | 3회 이상 실행, 성공률 ≥80% | 10회 이상 실행, 성공률 ≥90% |
| 항상 신뢰할 수 있음 | trusted | — | — |
| Custom | 구성 가능 | 구성 가능 | 구성 가능 |
const strategy = createCustomTrustStrategy({
initialLevel: 'untrusted',
provisionalThreshold: { executions: 5, successRate: 0.85 },
trustedThreshold: { executions: 50, successRate: 0.95 },
})
스니펫 수명 주기
등록
LLM이 execute_typescript를 통해 유용한 코드를 생성하면 시스템 프롬프트는 다음 항목과 함께 register_snippet을 호출하도록 지시합니다.
name— snake_case 식별자 (도구 이름이 됨)description— 스니펫이 수행하는 작업code—input변수를 받는 TypeScript 소스inputSchema/outputSchema— JSON 스키마 문자열usageHints— 이 스니펫을 언제 사용하는지dependsOn— 이 스니펫이 호출하는 다른 스니펫들
스니펫은 저장소에 저장되며(ToolRegistry가 제공된 경우) 현재 세션에서 호출 가능한 도구로 즉시 추가됩니다.
실행
스니펫 도구가 호출되면 시스템은 다음을 수행합니다.
const input = <serialized input>;로 스니펫 코드를 감쌈- TypeScript 구문을 평범한 JavaScript로 제거
external_*바인딩을 갖춘 새 샌드박스 컨텍스트 생성- 코드를 실행하고 결과를 반환
- 성공/실패 횟수 등 실행 통계를 비동기적으로 업데이트
선택(high-level API 전용)
새 요청마다 selectRelevantSnippets는 다음을 수행합니다.
- 마지막 5 개의 대화 메시지를 컨텍스트로 사용합니다
- 스니펫 인덱스에서 카탈로그를 구축합니다 (이름 + 설명 + 첫 번째 사용 힌트)
- 어댑터가 관련 스니펫 이름의 JSON 배열을 반환하도록 요청합니다 (최대
maxSnippetsInContext) - 선택된 이름에 대한 전체 스니펫 데이터를 로드합니다
파싱에 실패하거나 모델이 유효하지 않은 JSON을 반환하면 빈 선택으로 대체됩니다. 요청은 미리 로드된 스니펫 없이 진행되지만 LLM은 관리 도구를 통해 여전히 스니펫을 검색하고 사용할 수 있습니다.
도구로서의 스니펫과 샌드박스 바인딩 비교
snippetsAsTools 옵션(기본값: true)은 스니펫을 노출하는 방식을 제어합니다.
| 모드 | LLM이 스니펫을 호출하는 방법 | 장점 | 단점 |
|---|---|---|---|
도구로 사용 (true) | 직접 도구 호출: snippet_name({ ... }) | LLM에 더 간단하고 도구 호출 UI에 표시되며 적절한 입력 검증을 제공 | 도구 목록에 스니펫마다 하나의 도구가 추가됨 |
바인딩으로 사용 (false) | execute_typescript 내부: await snippet_fetch_data({ ... }) | 코드에서 스니펫을 조합할 수 있고 최상위 도구 수가 적음 | LLM이 사용을 위한 코드를 작성해야 함 |
snippetsAsTools가 활성화되면 시스템 프롬프트에 각 스니펫의 스키마, 사용 힌트, 호출 예제가 문서화됩니다. 비활성화하면 스니펫이 샌드박스 타입 스텁의 타입이 지정된 snippet_* 함수로 표시됩니다.
사용자 지정 이벤트
스니펫 실행은 TanStack AI 이벤트 시스템을 통해 이벤트를 발생시킵니다.
| 이벤트 | 언제 | 페이로드 |
|---|---|---|
code_mode:snippet_call | 스니펫 도구가 호출됨 | { snippet, input, timestamp } |
code_mode:snippet_result | 스니펫이 성공적으로 완료됨 | { snippet, result, duration, timestamp } |
code_mode:snippet_error | 스니펫 실행에 실패함 | { snippet, error, duration, timestamp } |
snippet:registered | register_snippet을 통해 새 스니펫이 저장됨 | { id, name, description, timestamp } |
React 앱에서 코드 모드 실행 이벤트와 함께 이러한 이벤트를 렌더하려면 UI 에서 코드 모드 표시를 참조하세요.
팁
- 선택에는 저렴한 모델을 사용하세요. 선택 호출은 스니펫 이름과 대화 컨텍스트를 일치시키기만 하면 되므로
gpt-4o-mini또는claude-haiku-4-5가 적합합니다. - 스니펫 없이 시작하세요. 먼저 Code Mode를 작동시킨 다음, 재사용 가능한 패턴을 생성하는 도구가 준비되면
@tanstack/ai-code-mode-snippets를 추가하세요. - 스니펫 수를 모니터링하세요. 라이브러리가 커지면
maxSnippetsInContext를 늘리거나 로드할 스니펫을 직접 제어할 수 있는 Manual API로 전환하세요. - 새로 등록한 스니펫은 현재 턴의 도구 목록이 아니라 다음 메시지에서 사용할 수 있습니다. 단, high-level API에서
ToolRegistry를 사용하면 즉시 추가됩니다. - 스니펫은 다른 스니펫을 호출할 수 있습니다. 샌드박스 내부에서는
external_*및snippet_*함수를 모두 사용할 수 있습니다. 등록할 때dependsOn을 설정해 이러한 관계를 문서화하세요.
다음 단계
- Code Mode — Code Mode 핵심 설정 및 API 참조
- UI 에서 코드 모드 표시 — React 앱에서 실행 진행 상황을 표시합니다.
- Isolate Drivers — 샌드박스 런타임 비교