実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。
- 変更後の製品動作を実地で検証したいとき
- 画面キャプチャなどの証拠を集めたいとき
- 検証計画とレポートを作成したいとき
エージェント実行中の各段階をフックで監視し、ツール呼び出しの模擬・制御や人の承認、圧縮、サブエージェント処理に介入する仕組みを扱います。
Use for agent lifecycle hooks, tool mocks, intervention, sub-agent calls and context compression.
実行スコア 未検証
インストール方法を見るエージェントの実行ライフサイクルにフックを登録し、各段階のイベントを扱う方法を説明します。ステップ開始・完了、ツール実行前後やエラー、人による承認、コンテキスト圧縮、サブエージェントの呼び出し、最終状態などを対象にできます。ローカルハンドラーではツール結果を模擬し、Webhookではイベント通知や設定に応じた許可・拒否の判断を扱います。イベントに含まれる実行ID、ツール情報、結果などのコンテキストや、Webhookのペイロードと配信エラーの挙動も示します。
エージェント実行の観測や運用時の介入を組み込みたい開発者、ツールの結果を検証用に差し替えたい場合に向いています。承認やサブエージェントを含む処理の流れを追う用途にも使えます。
Webhookの設定や動作には配信先URLが必要です。ヘッダーに環境変数を使う場合は許可リストを指定し、秘密情報は保存時に展開しません。Webhookのみで登録したフックはプロセス再起動後に関数ハンドラーを復元できません。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
SKILL.md の記述から、注意が要る操作と導入の前提を AI が確認しました。点数は実際に動かした結果(実行検証)だけで付けています。
点数には入れていません。 2026年10月26日 時点で AI(OpenAI Codex)が判定しました。目安なので、入れる前に原文も確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Register lifecycle hooks through execAgent({ hooks }). HookDispatcher stores them per operation and dispatches them in registration order.
16 hook types across 5 categories:
execAgent({ hooks })
│
├─ beforeStep ──────────── Before each step executes
│ │
│ ├─ [call_llm] LLM inference
│ │
│ ├─ [call_tool]
│ │ ├─ beforeToolCall ── Before tool executes (supports mocking)
│ │ ├─ (tool execution)
│ │ ├─ afterToolCall ─── After tool completes (optional result control)
│ │ └─ onToolCallError ─ Tool threw an exception
│ │
│ ├─ [request_human_approve]
│ │ ├─ beforeHumanIntervention ── Before agent pauses
│ │ ├─ afterHumanIntervention ─── After approve/reject + resume
│ │ └─ onStopByHumanIntervention ── User rejected, agent halted
│ │
│ ├─ [compress_context]
│ │ ├─ beforeCompact ──── Before compression starts
│ │ ├─ afterCompact ───── After compression completes
│ │ └─ onCompactError ─── Compression failed
│ │
│ ├─ [callAgent] (via execSubAgentTask)
│ │ ├─ beforeCallAgent ── Before sub-agent starts
│ │ ├─ afterCallAgent ─── After creation/start returns
│ │ └─ onCallAgentError ── Sub-agent failed
│ │
│ └─ afterStep ──────────── After step completes
│
├─ (next step...)
│
├─ onComplete ───────────── Operation reaches terminal state
└─ onError ──────────────── Error during execution
| File | Role |
|---|---|
packages/agent-runtime/src/types/hooks.ts | Event types and required/optional fields |
apps/server/src/services/agentRuntime/hooks/types.ts | Registration and webhook types |
apps/server/src/services/agentRuntime/hooks/HookDispatcher.ts | Registration, dispatch, local mocks, HTTP/QStash delivery |
apps/server/src/services/agentRuntime/hooks/webhookPayload.ts | Event projection and email enrichment |
apps/server/src/modules/AgentRuntime/adapters/toolCallHookContext.ts | Shared tool-event context builder |
apps/server/src/modules/AgentRuntime/adapters/ServerToolTransport.ts | Tool notifications and execution results |
apps/server/src/modules/AgentRuntime/RuntimeExecutors.ts | Tool, compression and human-intervention execution |
apps/server/src/services/agentRuntime/AgentRuntimeService/ (executeStep/, intervention.ts) | Step events and human-intervention continuation |
apps/server/src/services/agentRuntime/CompletionLifecycle/index.ts | Terminal events |
apps/server/src/services/aiAgent/subAgentRuns.ts | Sub-agent events |
const hooks: AgentHook[] = [
{
id: 'observe-step',
type: 'afterStep',
handler: async (event) => {
console.log(event.operationId, event.stepIndex);
},
},
];
await aiAgentService.execAgent({ agentId, prompt, hooks });
Completion cleans up registrations through hookDispatcher.unregister(operationId).
Webhook-only hooks deliver in both local and queue modes. For hooks with both handler and webhook, local dispatch calls the handler; queue dispatch uses the serialized webhook. Only webhook configuration is persisted, so functions are unavailable after a process restart.
const hook: AgentHook = {
id: 'tool-notification',
type: 'afterToolCall',
matcher: '^fs/readFile$',
webhook: {
url: 'https://example.com/hooks',
delivery: 'fetch',
timeout: 5, // seconds; default 30
headers: { Authorization: 'Bearer ${HOOK_TOKEN}' },
allowedEnvVars: ['HOOK_TOKEN'],
},
};
matcher is a regex against ${identifier}/${apiName}, supported only on tool events. Omitted, empty, or * matches all tools.allowedEnvVars; persist templates, never resolved secrets.beforeToolCall with responseHandling: 'toolCall' awaits an optional HTTP decision before tool execution. Return HTTP 2xx JSON with { "decision": "allow" } or { "decision": "deny", "reason": "禁止执行该操作" } to intervene. The type is { decision: 'allow' } | { decision: 'deny'; reason?: string }; a deny with an omitted or empty reason uses Blocked by beforeToolCall hook.. Denials preserve the reason in the tool result/card with classification hook_denied.afterToolCall also accepts responseHandling: 'toolCall'. It synchronously checks the full request/result before archival and model consumption; deny replaces the original result with the receiver's optional reason in both content and blocked state. A deny with an omitted or empty reason uses Blocked by afterToolCall hook., following the same Blocked by ${type} hook. rule as beforeToolCall. The reason enters model context and the tool card, as with beforeToolCall. It does not undo tool side effects, retries, or charges. See the result-control contract for deferred completions and runtime boundaries.ignore (default notifications) and toolCall (optional decisions for both before and after). Only subscribed events are enabled. Replace removed toolResult/toolCallAndResult values with toolCall; use the events list to select after-only checking. Existing after responses with a valid decision now control results.hookSpecificOutput) are notification responses, even with onError: 'block'. Continue checking subsequent hooks; do not treat a notification as permission to skip later policies. Explicit invalid decisions, non-2xx status, oversized bodies, invalid UTF-8, network failures, and timeouts follow onError: 'continue' | 'block' (default continue); blocking uses hook_control_error as the tool-result content and reason for both before and after hooks. Cancellation never grants permission.decision and a deny's optional string reason are consumed; updatedInput/additionalContext do not change tool arguments or conversation context.packages/types/src/agentHook.ts; response parsing: packages/types/src/agentHookResponse.ts; HTTP delivery: apps/server/src/services/agentRuntime/hooks/httpWebhook.ts.AGENT_HOOK_WEBHOOK_*) always come from the executing worker's current environment, including after human approval and deferred completion. Never persist their configuration or restore a previous environment's hooks.execAgent({ hooks })) retain the existing per-operation serialization and persistence. Recover these caller hooks from the runtime snapshot or durable operation record; preserve environment-variable templates without expanding secrets into storage.onError.toolResultControl pending/allowed/blocked metadata or hide raw output through history projections.MessageModel.resolveHumanApproval defaults to claim-only; only the runtime calls it with publishResult: true after result control. Stop/rejection receipts can publish directly because they contain no executed tool output.type: 'blocked' is not a hook verdict.| Event | Timing and payload |
|---|---|
beforeStep | Before a step; AgentHookEvent |
afterStep | After a step; content, tool calls/results and usage totals |
onComplete | Terminal state; reason such as done, error, interrupted, max_steps or cost_limit |
onError | Operation error; errorMessage, errorDetail and available error metadata |
beforeToolCall | Before tool execution; shared tool context and local mock() callback |
afterToolCall | After tool execution; structured result and mocked |
onToolCallError | Tool execution throws; shared tool context and error |
beforeHumanIntervention | Before approval; pendingTools, operationId, stepIndex |
afterHumanIntervention | Approval decision and continuation; action, optional toolCallId and rejectionReason |
onStopByHumanIntervention | Human rejection stops the run; optional toolCallId and rejectionReason |
beforeCompact | Before compression; messageCount, tokenCount, stepIndex |
afterCompact | After compression; groupId, messagesBefore, messagesAfter, summary |
onCompactError | Compression error; error, tokenCount, stepIndex |
beforeCallAgent | Before sub-agent creation; agentId, instruction |
afterCallAgent | Creation/start returns; agentId, subOperationId, success, optional threadId |
onCallAgentError | Sub-agent call fails; agentId, error |
CallAgent events dispatch on the parent operation identified by parentOperationId. An isolated child supplies threadId; shared group members use the shared conversation. Child completion is reported by the child's onComplete event.
Use buildToolCallHookContext() for the three tool events.
toolCallId, assistantMessageId, identifier, apiName, effective args, callIndex, stepIndex, operationId and executor.userId uses runtime.userId ?? origin.userId.toolSource identifies the tool's origin; executor identifies the server/client dispatch route. executionTarget and activeDeviceId describe the run's execution plan and device selection.afterToolCall.result carries content, success, optional executionTime and error/state data such as state.type: 'blocked'. mocked marks results supplied by a local hook.Sandbox and MCP tools use the same event path. Filter with identifier, apiName or toolSource.
dispatchBeforeToolCall() exposes event.mock(result). The first accepted mock wins and short-circuits the remaining mock handlers. The method returns { isMocked: true, result } for a mock, or null to continue execution.
event.mock({ content: '{"items":[]}', success: true });
Tool observation payloads use BeforeToolCallObservationEvent; the callback belongs to the in-memory handler event. dispatchBeforeToolCall() does not deliver webhooks.
createWebhookPayloadBuilder() selects eventFields, adds hookId/hookType, then merges webhook.body. The body determines the final value of overlapping fields. Tool-result notification payloads use redactResultForEvents() to trim raw skill Work data; controls receive the full result. Work registration retains the full in-process result. finalState is available to local handlers; serialized payloads carry the event's data fields.
When email is selected, the builder resolves userEmail from the final effective userId, replacing supplied email values. Email-only projections use the event ID. An explicit invalid ID, missing email or lookup error leaves email omitted.
Email queries share a per-dispatcher cache of up to 1,000 users for five minutes. Query timeouts belong to the database layer. The builder's optional fourth { signal } argument lets a waiter cancel independently; cancellation returns undefined so the caller can stop delivery. Fetch and QStash use the enriched payload.
Dispatch awaits each handler or webhook. Ordinary errors are logged and dispatch continues. Webhooks with fallback: 'none' accumulate a CriticalHookDeliveryError, which is thrown after sibling hooks have run. QStash delivery defaults to a fetch fallback; use fallback: 'none' for QStash-signed endpoints.
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。
LobeHubにAIモデルプロバイダーを追加し、実行時連携からモデル表示、設定、ブランド表記、文書化、動作確認まで進めるスキルです。
ユーザー設定の初期値をサーバー側の環境変数で切り替えるため、型定義や設定の組み立て、ユーザーストアへの反映、環境変数の例と説明書きを追加する手順です。
イベントを起点にエージェントのバックグラウンド処理を組み立て、ソース・シグナル・アクション・ポリシーの役割分担や非同期連携を実装するためのスキルです。
DiscordやSlackなどの実際のチャットアプリでボットにメッセージを送り、応答を画面で確認する受け入れテストを行うスキルです。
エージェントの実行記録を操作IDから調べ、失敗したツール呼び出し、入出力、LLMに渡した文脈を確認して原因を追えるようにします。