0.5.1: MCPの設定読み込みの削除

This commit is contained in:
2025-10-30 04:16:04 +09:00
parent cc6bbe2a43
commit 90edd3828b
11 changed files with 345 additions and 428 deletions
+41 -42
View File
@@ -31,7 +31,7 @@ pub struct HookManager {
pub enum HookEvent {
OnMessageSend,
PreToolUse,
PostToolUse,
PostToolUse,
OnTurnCompleted,
}
```
@@ -181,10 +181,10 @@ impl HookContext {
impl HookContext {
// ストリーミング中にメッセージを送信
pub fn stream_message(&self, content: String, role: Role);
// ストリーミング中にシステム通知を送信
pub fn stream_system_message(&self, content: String);
// ストリーミング中にデバッグ情報を送信
pub fn stream_debug(&self, title: String, data: serde_json::Value);
}
@@ -198,22 +198,22 @@ Hook関数は以下のいずれかの結果を返す必要があります:
pub enum HookResult {
// 処理を続行
Continue,
// コンテンツを変更して続行
ModifyContent(String),
// システムメッセージを追加して続行
AddMessage(String, Role),
// 複数のメッセージを追加して続行
AddMessages(Vec<Message>),
// ターンを強制完了
Complete,
// エラーでターンを終了
Error(String),
// Hook処理をスキップ(デバッグ用)
Skip,
}
@@ -282,7 +282,7 @@ pub async fn dangerous_command_hook(context: HookContext) -> HookResult {
if let Some(args) = &context.tool_args {
if let Some(command) = args.get("command").and_then(|v| v.as_str()) {
let dangerous_commands = ["rm -rf", "format", "dd if="];
for dangerous in &dangerous_commands {
if command.contains(dangerous) {
return HookResult::Error(format!(
@@ -293,7 +293,7 @@ pub async fn dangerous_command_hook(context: HookContext) -> HookResult {
}
}
}
HookResult::Continue
}
```
@@ -326,7 +326,7 @@ pub async fn auto_read_hook(mut context: HookContext) -> HookResult {
}
}
}
HookResult::Continue
}
```
@@ -361,7 +361,7 @@ worker.register_hooks(tui_hooks);
```rust
// 実行順序の例
worker.register_hook(Box::new(TimestampHook)); // 1番目
worker.register_hook(Box::new(ValidationHook)); // 2番目
worker.register_hook(Box::new(ValidationHook)); // 2番目
worker.register_hook(Box::new(LoggingHook)); // 3番目
```
@@ -375,13 +375,13 @@ worker.register_hook(Box::new(LoggingHook)); // 3番目
impl Worker {
// Hook一覧を取得
pub fn list_hooks(&self) -> Vec<(&str, &str)>; // (name, hook_type)
// 特定のHookを削除
pub fn remove_hook(&mut self, hook_name: &str) -> bool;
// フェーズ別Hookを削除
pub fn remove_hooks_by_phase(&mut self, hook_type: &str);
// すべてのHookをクリア
pub fn clear_hooks(&mut self);
}
@@ -395,16 +395,16 @@ impl Worker {
// worker/src/lib.rs の process_with_shared_state より
stream! {
// ... LLM応答処理中 ...
// ツール呼び出し検出時
if let Some(tool_calls) = &response.tool_calls {
for tool_call in tool_calls {
// PreToolUse hooks 実行
let (context, hook_result) = execute_hooks(
HookEvent::PreToolUse,
HookEvent::PreToolUse,
tool_call.name.clone()
).await;
match hook_result {
HookResult::Error(msg) => {
yield Ok(StreamEvent::Error(msg));
@@ -413,16 +413,16 @@ stream! {
HookResult::Complete => break,
_ => {}
}
// ツール実行
let result = execute_tool(tool_call).await;
// PostToolUse hooks 実行(ストリーミング中)
let (context, hook_result) = execute_hooks(
HookEvent::PostToolUse,
tool_call.name.clone()
).await;
// Hook結果を即座にストリーミング
if let HookResult::AddMessage(msg, role) = hook_result {
yield Ok(StreamEvent::HookMessage {
@@ -468,13 +468,13 @@ pub async fn performance_aware_hook(context: HookContext) -> HookResult {
// 大きなコンテンツの場合はスキップ
return HookResult::Skip;
}
// 非同期処理は適切にawaitする
let result = tokio::time::timeout(
Duration::from_secs(5),
expensive_operation(&context)
).await;
match result {
Ok(output) => HookResult::AddMessage(output, Role::System),
Err(_) => {
@@ -495,20 +495,20 @@ pub async fn configurable_hook(mut context: HookContext) -> HookResult {
.unwrap_or_default()
.parse::<bool>()
.unwrap_or(false);
if !enabled {
return HookResult::Skip;
}
// 設定ファイルからオプション読み込み
let config_path = format!("{}/.nia/hook_config.json", context.workspace_path);
let config_path = format!("{}/hook_config.json", context.workspace_path);
if let Ok(config_content) = tokio::fs::read_to_string(&config_path).await {
if let Ok(config) = serde_json::from_str::<HookConfig>(&config_content) {
// 設定に基づく処理
return process_with_config(&mut context, &config).await;
}
}
HookResult::Continue
}
```
@@ -523,7 +523,7 @@ pub async fn conditional_hook(context: HookContext) -> HookResult {
let is_rust_project = tokio::fs::metadata(
format!("{}/Cargo.toml", context.workspace_path)
).await.is_ok();
match (is_git_repo, is_rust_project) {
(true, true) => {
// Rustプロジェクト + Git
@@ -548,7 +548,7 @@ pub async fn conditional_hook(context: HookContext) -> HookResult {
mod tests {
use super::*;
use worker::types::*;
#[tokio::test]
async fn test_timestamp_hook() {
let mut context = HookContext {
@@ -561,9 +561,9 @@ mod tests {
tool_args: None,
tool_result: None,
};
let result = add_timestamp_hook(context).await;
match result {
HookResult::ModifyContent(content) => {
assert!(content.contains("Hello, world!"));
@@ -587,7 +587,7 @@ pub async fn debug_hook(context: HookContext) -> HookResult {
context.tools.len(),
context.message_history.len()
);
// デバッグ情報をストリーミング
context.stream_debug(
"Hook Debug Info".to_string(),
@@ -598,7 +598,7 @@ pub async fn debug_hook(context: HookContext) -> HookResult {
"workspace": context.workspace_path
})
);
HookResult::Continue
}
```
@@ -625,13 +625,13 @@ impl WorkerHook for StatefulHook {
fn name(&self) -> &str { "stateful_hook" }
fn hook_type(&self) -> &str { "OnTurnCompleted" }
fn matcher(&self) -> &str { "" }
async fn execute(&self, mut context: HookContext) -> (HookContext, HookResult) {
let mut count = self.counter.lock().unwrap();
*count += 1;
context.set_variable("turn_count".to_string(), count.to_string());
if *count % 10 == 0 {
(
context,
@@ -658,7 +658,7 @@ impl HookChain {
pub fn new() -> Self {
Self { hooks: Vec::new() }
}
pub fn add_hook(mut self, hook: Box<dyn WorkerHook>) -> Self {
self.hooks.push(hook);
self
@@ -670,18 +670,18 @@ impl WorkerHook for HookChain {
fn name(&self) -> &str { "hook_chain" }
fn hook_type(&self) -> &str { "OnMessageSend" }
fn matcher(&self) -> &str { "" }
async fn execute(&self, mut context: HookContext) -> (HookContext, HookResult) {
for hook in &self.hooks {
let (new_context, result) = hook.execute(context).await;
context = new_context;
match result {
HookResult::Continue | HookResult::Skip => continue,
other => return (context, other),
}
}
(context, HookResult::Continue)
}
}
@@ -715,4 +715,3 @@ A: `HookResult::Error`を返すと、そのターンは中断されます。継
- [worker-macro.md](worker-macro.md) - マクロシステム
- `worker/src/lib.rs` - Hook実装コード
- `worker-types/src/lib.rs` - Hook型定義
- `nia-cli/src/tui/hooks/` - TUI用Hook実装例
+1 -2
View File
@@ -6,7 +6,7 @@ v0.3.0 はプロンプトリソースの解決責務を利用側へ完全に移
## Breaking Changes
- `ConfigParser::resolve_path` を削除し、`#nia/` `#workspace/` 等のプレフィックス解決をライブラリ利用者実装の `ResourceLoader` に委譲しました。
- `ConfigParser::resolve_path` を削除し、`#user/` `#workspace/` 等のプレフィックス解決をライブラリ利用者実装の `ResourceLoader` に委譲しました。
- `WorkerBuilder::build()``resource_loader(...)` が未指定の場合エラーを返すようになりました。ワーカー構築前に必ずローダーを提供してください。
## 新機能 / 仕様変更
@@ -19,7 +19,6 @@ v0.3.0 はプロンプトリソースの解決責務を利用側へ完全に移
## 不具合修正
- `include_file` ヘルパーがカスタムローダーを利用せずにファイルアクセスしていた問題を修正。
- `ConfigParser` が存在しない `#nia/` プレフィックスを静的に解決しようとしていた挙動を除去し、誤ったパスが静かに通ることを防止。
## 移行ガイド
+1 -1
View File
@@ -16,7 +16,7 @@ v0.4.0 は Worker が `Role` や YAML 設定を扱わず、システムプロン
## 不具合修正
- Worker から NIA 固有の設定コードを除去し、環境依存の副作用を縮小。
- Worker から旧プロジェクト固有の設定コードを除去し、環境依存の副作用を縮小。
## 移行ガイド
+4 -3
View File
@@ -2,7 +2,7 @@
**Release Date**: 2025-10-25
v0.5.0 introduces the Worker Blueprint API and removes the old type-state builder. Configuration now lives on the blueprint, while instantiated workers keep only the materialised system prompt and runtime state.
v0.5.0 introduces the Worker Blueprint API and removes the old type-state builder. Configuration now lives on the blueprint, while instantiated workers keep only the materialised system prompt, model metadata, and runtime state.
## Breaking Changes
@@ -12,9 +12,10 @@ v0.5.0 introduces the Worker Blueprint API and removes the old type-state builde
## New Features / Behaviour
- `WorkerBlueprint` stores provider/model/api keys, tools, hooks, and optional precomputed system prompt strings. `instantiate()` evaluates the prompt (if not already cached) and hands the final string to the `Worker`.
- Instantiated workers retain only the composed system prompt string; the generator function lives solely on the blueprint and is dropped after instantiation.
- `WorkerBlueprint` stores provider/model/api keys, tools, hooks, optional precomputed system prompt messages, and optional model feature flags. `instantiate()` evaluates the prompt (if not already cached) and hands the final string to the `Worker`.
- Instantiated workers retain the composed system prompt, the original generator closure, and a `Model` struct describing provider/model/features; the generator only runs again if a new session requires it.
- System prompts are no longer recomputed per turn. Tool metadata is appended dynamically as plain text when native tool support is unavailable.
- Worker now exposes a `Model` struct (`provider`, `name`, `features`) in place of the previous loose strings and `supports_native_tools` helper. Capability heuristics remain for built-in providers but applications can override them via `WorkerBlueprint::model_features`.
## Migration Guide