dsh 플러그인 개발
DeepSeek Harness
(dsh)용 플러그인을 개발합니다. dsh는 Cordis 기반 에이전트 프레임워크입니다.
플러그인은 apply(ctx: Context)를 내보내는 TypeScript 모듈이며,
cordis.yml을 통해 구성됩니다.
빠른 참조
플러그인 구조
import type { Context } from '@deepseek-ai/cordis'
export const name = 'my-plugin'
export function apply(ctx: Context) { /* 기능 등록 */ }
세 가지 형태: 함수 (기본값), 객체 ({ name, inject, apply }), 클래스
(extends Service — 다른 플러그인에 서비스를 제공할 때만 사용).
의존성: export const inject = ['tools', 'llm'] — 프레임워크는
주입된 모든 서비스가 준비될 때까지 플러그인을 PENDING 상태로 유지합니다.
자동 정리: ctx를 통해 등록된 모든 것은 효과(effect)입니다 —
언로드 시 자동으로 정리됩니다. 사용자 정의 리소스(타이머, 연결)는
ctx.effect(() => { ... return () => cleanup })으로 감싸세요.
자식 플러그인: const fiber = ctx.plugin(childPlugin) — 자식은
부모 컨텍스트를 상속받습니다. await fiber.dispose()는 재귀적으로 언로드합니다.
파이버 상태
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
↘ FAILED
PENDING → 서비스 의존성 누락. FAILED → apply에서 오류 발생 또는 설정
검증 실패. 런타임에 서비스가 사라지면 의존하는 플러그인이 자동으로 해제됩니다.
도구(Tools)
import { defineTool } from '@deepseek-ai/dsh-tools'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet', description: '...',
parameters: { name: { type: 'string', required: true } },
output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }] },
async execute(args) { return `Hello, ${args.name}!` },
}))
}
defineTool은 매개변수를 JSON Schema로 변환하고, 인자를 검증하며,
언로드 시 자동으로 등록을 해제합니다.
자세한 내용은 references/basic/tool.md를 참조하세요.
설정(Configuration)
import Schema from '@deepseek-ai/schemastery'
export interface Config { greeting: string; maxRetries: number }
export const Config: Schema<Config> = Schema.object({
greeting: Schema.string().default('Hello'),
maxRetries: Schema.number().default(3),
})
export function apply(ctx: Context, config: Config) { /* 검증된 설정 */ }
interface Config와 const Config: Schema<Config>를 모두 내보내야 합니다.
잘못된 설정 → 명확한 오류와 함께 FAILED 상태가 됩니다. YAML에서 동적 값을 위해
!!js를 사용하세요: config: { apiKey: !!js process.env.API_KEY }.
자세한 내용은 references/basic/config.md를 참조하세요.
서비스(Services)
제공: class extends Service { constructor(ctx) { super(ctx, 'name') } }
declare module '@deepseek-ai/cordis' { interface Context { name: NameService } }
소비: export const inject = ['name'] → ctx.name.method().
선택적: ctx.get('name') → 서비스가 없을 때 undefined 반환.
서비스 격리: group: true + isolate: { shell: true } → 각 그룹에
자체 제공자 인스턴스를 부여합니다. 자세한 내용은 references/framework/service.md를 참조하세요.
이벤트(Events)
| 모드 | 호출 | 용도 |
|---|---|---|
emit | ctx.emit(n, ...args) | 동기 브로드캐스트, 반환값 무시 |
parallel | await ctx.parallel(n, ...args) | 동시 리스너 |
serial | await ctx.serial(n, ...args) | 순차적, 첫 번째 null 아닌 값 승리 |
bail | ctx.bail(n, ...args) | 동기 직렬 |
waterfall | ctx.waterfall(n, ...args, next) | 미들웨어 체인 |
워터폴 리스너는 의도적으로 단락시키지 않는 한 반드시 next()를 호출해야 합니다.
주요 하네스 이벤트: agent/step, tools/result, session/event.
자세한 내용은 references/framework/events.md를 참조하세요.
LLM 어댑터
class MyAdapter extends LlmAdapter {
async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
// 변환 → 제공자 API → StreamChunk 생성
}
}
ctx.llm.registerAdapter(['my-provider'], adapter)
블록별 StreamChunk 순서: block-start → text-delta/tool-call-delta →
block-end → usage → finish. 안정적인 코드와 함께 LlmError를 던지세요.
자세한 내용은 references/practice/llm-adapter.md를 참조하세요.
3계층 기능 설계
정의 (Service 추상 클래스) → 제공자 (구현) → 소비자 (도구)
세 계층 모두 inject를 통해 동일한 서비스 이름을 공유합니다.
역할이 독립적으로 진화해야 할 때만 별도 패키지로 분할하세요.
자세한 내용은 references/practice/index.md를 참조하세요.
cordis.yml / 번들
로컬 개발: --patch ./cordis.patch.yml
- insert:
- id: my-plugin
name: '/absolute/path/to/src/my-plugin.ts'
config: { greeting: 'Hi' }
배포: dsh.bundle 매니페스트 + cordis.patch.yml이 포함된 npm 패키지.
설치: dsh plugin --profile demo add ./hello-plugin.
레이어 순서: 프로필 번들 → 프로필 패치 → 홈 패치 → --patch 오버레이.
이후 레이어가 행 단위로 우선 적용됩니다 (깊은 병합 없음).
자세한 내용은 references/basic/publish.md를 참조하세요.
HMR
@deepseek-ai/cordis-plugin-hmr + @deepseek-ai/cordis-plugin-logger-console
@deepseek-ai/cordis-plugin-timer를 로드하면 파일 저장 시 자동으로 재로드됩니다.
PENDING 진단
import { FiberState, type Context } from '@deepseek-ai/cordis'
for (const fiber of ctx.registry.values().flatMap(r => r.fibers))
if (fiber.state === FiberState.PENDING)
console.log(`${fiber.name} is PENDING`)
참조 문서
references/ 디렉토리의 상세 가이드:
| 경로 | 내용 |
|---|---|
references/basic/ | 첫 플러그인, 도구, 설정, 배포 |
references/framework/ | 생명주기, 서비스, 이벤트 |
references/practice/ | 3계층 설계, LLM 어댑터 |
references/cordis-tutorial/ | Cordis 프레임워크 단계별 튜토리얼 |