DeepSeek Harness: プラグイン設定:Config と Schemastery

最終更新:2026-08-31

設定はプラグインの「コントロールノブ」——API キー、タイムアウト、機能トグル、これらの環境依存パラメータはハードコードせず、設定システムを通じて外部化すべきです。Schemastery は Cordis の宣言的設定フレームワーク:一度定義すれば、型安全性、UI フォーム、検証、ドキュメントを自動的に得られます。

💡 ヒント:Schemastery の核心哲学は「宣言即ドキュメント」——Schema で設定構造を定義すると、フレームワークが自動的に Web UI フォームと検証ロジックを生成します。設定変更にコード変更は不要です。

📋 前提知識15-define-tool.md の完了、基本的なツールを書けること

1. 学習内容

設定ホットリロード


2. Schemastery 宣言的設定

(1) 基本概念

Schemastery は Cordis 内蔵の Schema 定義ライブラリで、Zod と JSON Schema にインスパイアされていますが、インタラクティブ設定のために特化設計されています。

TYPESCRIPT
import { Schema } from '@deepseek-ai/cordis'

export const Config = Schema.object({
  apiKey: Schema.string().required().description('API key for the service'),
  maxRetries: Schema.number().default(3).description('Maximum retry attempts'),
  debug: Schema.boolean().default(false).description('Enable debug logging')
})

(2) JSON Schema との比較

次元 Schemastery JSON Schema
構文 チェーン可能 API JSON オブジェクト
型推論 ✅ 自動 ❌ 手動
UI フォーム ✅ 自動生成 ❌ 追加ツールが必要
デフォルト値 .default() default フィールド
説明 .description() description フィールド
検証 チェーン可能バリデータ pattern/min/max

▶ サンプル 3:

TYPESCRIPT
export const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export const name = 'my-plugin'

export function apply(ctx: Context) {
  // ctx.config の型は自動推論される
  ctx.logger.info(`API key: ${ctx.config.apiKey}`)
  ctx.logger.info(`Max retries: ${ctx.config.maxRetries}`)
}

フレームワークはユーザー提供の設定値を検証し、ctx.config に注入します。


3. Schema 型

▶ サンプル 1:

TYPESCRIPT
Schema.string()                           // 任意の文字列
Schema.string().required()                // 必須
Schema.string().default('hello')          // デフォルト値
Schema.string().description('Your name')  // 説明
Schema.string().pattern(/^[a-z]+$/)       // 正規表現検証
Schema.string().min(1).max(100)           // 長さ制限

▶ サンプル 2:

TYPESCRIPT
Schema.number()                    // 任意の数値
Schema.number().default(0)         // デフォルト値
Schema.number().min(0).max(100)    // 範囲制限
Schema.number().step(1)            // ステップ(UI スライダー用)
Schema.integer()                   // 整数

(3) Schema.boolean

TYPESCRIPT
Schema.boolean()                   // 真偽値
Schema.boolean().default(false)    // デフォルト false

(4) Schema.object

TYPESCRIPT
Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  ssl: Schema.boolean().default(false)
})

(5) Schema.array

TYPESCRIPT
Schema.array(Schema.string())                          // 文字列配列
Schema.array(Schema.string()).default([])              // デフォルト空配列
Schema.array(Schema.object({                           // オブジェクト配列
  name: Schema.string().required(),
  url: Schema.string().required()
}))

(6) Schema.union / Schema.const

TYPESCRIPT
// Enum 値
Schema.union(['read', 'write', 'execute'])

// 定数
Schema.const('fixed-value')

// 説明付き Enum
Schema.union([
  Schema.const('read').description('Read-only access'),
  Schema.const('write').description('Read and write access'),
  Schema.const('execute').description('Full access')
])

(7) Schema.dict

TYPESCRIPT
// 辞書型
Schema.dict(
  Schema.string(),           // 値型
  Schema.string()            // キー型(オプション)
)

4. チェーン可能モディファイア

(1) .required()

必須としてマーク。ユーザーが提供しない場合、フレームワークはエラーを報告してロードをブロック。

TYPESCRIPT
apiKey: Schema.string().required()

(2) .default(value)

デフォルト値を設定。ユーザーが提供しない場合、エラーなくデフォルトが使用される。

TYPESCRIPT
maxRetries: Schema.number().default(3)
timeout: Schema.number().default(30000)

(3) .description(text)

設定項目に説明を追加。Web UI でフォームラベルのヒントテキストとして表示。

TYPESCRIPT
apiKey: Schema.string().required()
  .description('サービスダッシュボードから取得した API キー')

(4) .min() / .max()

数値範囲または文字列長の制限:

TYPESCRIPT
port: Schema.number().min(1).max(65535).default(8080)
name: Schema.string().min(1).max(50)

(5) .pattern()

正規表現検証:

TYPESCRIPT
email: Schema.string().pattern(/^[^@]+@[^@]+\.[^@]+$/)
  .description('有効なメールアドレス')

(6) .step()

数値ステップ、UI スライダーの精度に影響:

TYPESCRIPT
timeout: Schema.number().min(1000).max(300000).step(1000).default(30000)

(7) 組み合わせ使用

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string()
    .required()
    .pattern(/^sk-[a-zA-Z0-9]+$/)
    .description('DeepSeek API key (starts with sk-)'),
  
  maxTokens: Schema.number()
    .min(1).max(32768)
    .default(4096)
    .description('Maximum tokens per request'),
  
  model: Schema.union(['deepseek-chat', 'deepseek-reasoner'])
    .default('deepseek-chat')
    .description('Model to use'),
  
  temperature: Schema.number()
    .min(0).max(2).step(0.1)
    .default(0.7)
    .description('Sampling temperature')
})

5. ネスト設定

(1) ネストオブジェクト

TYPESCRIPT
const Config = Schema.object({
  database: Schema.object({
    host: Schema.string().default('localhost'),
    port: Schema.number().default(5432),
    name: Schema.string().required(),
    ssl: Schema.boolean().default(false)
  }).default({ host: 'localhost', port: 5432, ssl: false }),

  cache: Schema.object({
    enabled: Schema.boolean().default(true),
    ttl: Schema.number().default(3600).description('Cache TTL in seconds')
  }).default({ enabled: true, ttl: 3600 })
})

(2) 深いネスト

TYPESCRIPT
const Config = Schema.object({
  llm: Schema.object({
    provider: Schema.union(['deepseek', 'openai']).default('deepseek'),
    deepseek: Schema.object({
      apiKey: Schema.string().required(),
      model: Schema.string().default('deepseek-chat')
    }),
    openai: Schema.object({
      apiKey: Schema.string(),
      endpoint: Schema.string().default('https://api.openai.com/v1')
    })
  })
})

(3) 再利用可能な Schema

TYPESCRIPT
const ConnectionSchema = Schema.object({
  host: Schema.string().default('localhost'),
  port: Schema.number().default(5432),
  timeout: Schema.number().default(5000)
})

const Config = Schema.object({
  primary: ConnectionSchema.description('Primary connection'),
  replica: ConnectionSchema.description('Replica connection')
})

6. Web UI 設定ページでの表示

(1) 自動フォーム生成

Schemastery で定義した Config は Web UI 設定ページに自動的にフォームを生成:

Schema 型 UI コントロール
Schema.string() テキスト入力
Schema.number() 数値入力 / スライダー
Schema.boolean() トグルスイッチ
Schema.union() ドロップダウン選択
Schema.array() リストエディタ
Schema.object() グループパネル
Schema.dict() キー値エディタ

(2) description の表示

各フィールドの .description() は入力欄の下にヒントテキストとして表示:

TEXT 📖 参照専用
┌─────────────────────────────────────────┐
│ API Key                                 │
│ [sk-xxxxxxxxxxxxxxx                   ] │
│ DeepSeek API key (starts with sk-)      │
├─────────────────────────────────────────┤
│ Max Tokens                              │
│ [4096                                 ] │
│ Maximum tokens per request              │
└─────────────────────────────────────────┘

(3) 検証フィードバック

ユーザー入力が Schema に一致しない場合、UI に即座にフィードバックが表示:

TEXT 📖 参照専用
┌─────────────────────────────────────────┐
│ API Key                                 │
│ [invalid-key                          ] │
│ ❌ Must match pattern:/^[a-z]+[a-zA-Z0-9]+$/ │
└─────────────────────────────────────────┘

7. 設定の検証とエラーメッセージ

(1) 起動時検証

プラグインのロード時、フレームワークは設定を自動的に検証:

TYPESCRIPT
const Config = Schema.object({
  port: Schema.number().min(1).max(65535)
})

// ユーザー設定:port:-1
// → Error:Invalid config for plugin my-plugin:
//   port:must be >= 1

検証が失敗すると、プラグインはロードされず、エラーがターミナルに出力されます。

(2) 型安全性

TypeScript は Config 定義から ctx.config の型を自動推論:

TYPESCRIPT
const Config = Schema.object({
  apiKey: Schema.string().required(),
  maxRetries: Schema.number().default(3)
})

export function apply(ctx: Context) {
  ctx.config.apiKey     // string ✅
  ctx.config.maxRetries // number ✅
  ctx.config.unknown    // 型エラー ❌
}

(3) カスタム検証

TYPESCRIPT
const Config = Schema.object({
  startDate: Schema.string().required(),
  endDate: Schema.string().required()
}).validate((value) => {
  if (new Date(value.startDate) > new Date(value.endDate)) {
    throw new Error('startDate must be before endDate')
  }
  return value
})

8. 動的設定更新

(1) 設定変更のリッスン

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (newConfig) => {
    ctx.logger.info('config updated:', newConfig)
    // 新しい設定に基づいて動作を調整
  })
}

(2) ホット更新フロー

100%
graph LR
    UI[ユーザーが設定を変更] --> VALID[Schema 検証]
    VALID --> APPLY[新しい設定を適用]
    APPLY --> EMIT[config/updated を発行]
    EMIT --> RELOAD[プラグインが更新に対応]

(3) 再起動が必要な設定

一部の設定変更(ポート番号や依存性注入など)は再起動が必要:

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.on('config/updated', (config) => {
    if (config.port !== ctx.config.port) {
      ctx.logger.warn('port change requires restart')
    }
  })
}

❓ よくある質問

Q Config は必ず Config という名前でエクスポートする必要がありますか?
A はい、フレームワーク規約は export const Config を探します。他の名前は認識されません。
Q ランタイムで設定項目を動的に追加できますか?
A 非推奨。Config はプラグインロード前に定義すべきです。動的動作が必要な場合は、ctx.on('config/updated') で設定変更に対応してください。
Q 設定項目が多い場合の整理方法は?
A ネスト Schema.object でグループ化し、各グループに明確な description を付ける。Web UI はネストオブジェクトを折りたたみ可能パネルとしてレンダリングします。
Q API キーなどの機密情報を保護するには?
A Schemastery は .hidden() モディファイアをサポートし、UI でパスワードフィールドとして表示します:typescript apiKey:Schema.string().required().hidden()
Q 設定値は関数にできますか?
A いいえ。設定は JSON シリアライズ可能な値(string/number/boolean/object/array)でなければなりません。関数的動作は apply 内で実装してください。
Q 複数プラグインの設定は競合しますか?
A いいえ。各プラグインには独立した設定名前空間 plugins.plugin-name.config があり、互いに分離されています。

📖 まとめ


📝 練習問題

1. ⭐ 基礎:file_count ツールに Config を追加してください。defaultPath(string、デフォルトはカレントディレクトリ)と maxDepth(number、デフォルト 10)。Web UI 設定ページでフォーム生成を確認すること。

2. ⭐⭐ 応用:マルチ接続設定プラグインを書いてください。Config に connections(オブジェクト配列、各オブジェクトに host/port/username/password)を含め、ネスト Schema.object で定義。確認:必須フィールド欠落時にエラー、デフォルト値が正しく埋まること。

3. ⭐⭐⭐ チャレンジ:カスタム検証付きの設定を作成してください:startDateendDate は startDate < endDate を満たす必要あり;maxRetries は正の整数であること。テスト:無効な値を入力し、Web UI で検証エラーメッセージが正しく表示されることを確認。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%