アプリを作る
Agent を組み込む
Agent の定義の書き方、アプリから AgentRun を始めて結果を受け取る方法、外への操作の承認の扱い方を説明します。
このページでは、アプリに Agent を組み込む方法を説明します。Agent は定義に書いた目的・入力・ツール・出力の範囲で動き、外への操作は承認を通してから Hane が行います。考え方は Agent にあります。
Agent を定義する
Section titled “Agent を定義する”apiVersion: agents/v1alpha1kind: Agentmetadata: name: vehicle-checkspec: purpose: 登録番号から、車両の車種・車検の満了日・走行距離を車両台帳で調べて答える examples: - 架空 300 あ 10-02 の車検はいつまで? input: type: object required: [vehicle] properties: vehicle: { type: string, title: 登録番号 } driver: llm instructions: |- 1. data.find_record を type Vehicle、key に入力の vehicle で呼ぶ。 2. 見つかったら values の model・inspection_expiry・odometer_km を submit_result に入れ、status は answered にする。 3. 見つからなければ request_human_help で担当に引き継ぎ、status を handed_over にする。 台帳にない値を作らない。 tools: [data.find_record, request_human_help] handover: assignment: fleet-desk limits: maxToolCalls: 4 maxSeconds: 60 output: type: object required: [status, vehicle] properties: status: title: 結果 oneOf: - { const: answered, title: 回答した } - { const: handed_over, title: 担当に引き継いだ } vehicle: { title: 登録番号, type: string } model: { title: 車種, type: [string, "null"] } inspection_expiry: { title: 車検の満了日, type: [string, "null"] } odometer_km: { title: 走行距離(km), type: [integer, "null"] }| 項目 | 中身 |
|---|---|
purpose・examples |
何をする Agent か、どう頼むか。受付とチャットの Agent が、頼む Agent を選ぶときに使う |
input |
入力の JSON Schema。チャットで頼める Agent は入力を持つ |
driver |
動かし方。下の表 |
tools |
呼んでよいツール。Tool Gateway が呼ぶたびに確かめる |
limits |
ツールの呼出しの数(50 まで)、秒数(600 まで)、モデルのトークン |
output |
結果の JSON Schema。submit_result の値をこれで確かめる。title は画面の項目名になる |
approval |
外への操作の承認を回す割り当ての規則と、DeciderPolicy |
handover |
request_human_help で作る Task の割り当ての規則 |
| driver | 動き方 | 提供状況 |
|---|---|---|
scripted |
script に書いた手順どおりにツールを呼ぶ |
使える |
llm |
モデルがツールを選ぶ。instructions が要る |
使える |
opencode |
CLI をサンドボックスで動かし、モデルは Model Gateway を通す | プレビュー |
codex・claude |
Codex CLI・Claude Code をサンドボックスで動かし、MCP の Tool Gateway でツールを呼ぶ | プレビュー 手元の開発環境だけ |
業務の判断(計算や照合)は Agent にさせず、計算の定義や Workflow に書きます。Agent は calculations.run などのツールでそれを呼び、値と値の状態はサーバーが決めます。
AgentRun を始める
Section titled “AgentRun を始める”const run = await unwrap( hane.POST("/v1/agents/runs", { body: { agent: "vehicle-check", input: { vehicle: "架空 300 あ 10-02" } } }),);// run.status は queued。run.run_id で状態を読む実行は非同期です。状態は queued → running → succeeded・failed・cancelled・limit_exceeded と進みます。終わったら、result に出力の Schema で確かめた結果が入ります。
async function waitRun(id: string) { for (;;) { const r = await unwrap(hane.GET("/v1/agents/runs/{id}", { params: { path: { id } } })); if (r.status !== "queued" && r.status !== "running") return r; await new Promise((ok) => setTimeout(ok, 2000)); }}const done = await waitRun(run.run_id);console.log(done.status, done.result, done.trace.map((t) => `${t.kind} ${t.tool ?? ""} ${t.summary}`));- 画面に経過を出したいときは、組み込みチャット の会話を使うと、ツールの開始と終了・承認待ちを SSE で受け取れます。1 回の AgentRun だけを始める API には、経過を流す口はありません。
- 自分のシステムで終わりを知りたいときは、webhook で
agents.run.succeeded・agents.run.failedなどを購読します(webhook)。 shadow: trueを付けると、外への操作と人への引き継ぎをせず、記録だけを残します。定義を変える前の確かめに使えます。- 止めるときは
POST /v1/agents/runs/{id}/cancel(本文は{})です。次のツールの呼出しから拒否されます。
自由な文から頼む(受付)
Section titled “自由な文から頼む(受付)”頼む Agent が決まっていないときは、受付に自由な文を渡します。受付は有効な Agent の目的と頼み方の例から Agent を選び、入力の Schema に沿って文から値を拾います。
const r = await unwrap(hane.POST("/v1/agents/requests", { body: { messages: ["C-1001 の満了日を教えて"] } }));if (r.outcome === "started") console.log(r.run?.run_id);if (r.outcome === "needs_input") console.log(r.missing.map((m) => m.title)); // 聞き返すif (r.outcome === "unmatched") console.log(r.candidates);聞き返して答えをもらったら、messages の後ろに足して送り直します。
外への操作と承認
Section titled “外への操作と承認”Agent がメール・SMS・電話・顧客の API への書込み・人が行う操作のツールを呼ぶと、Hane は宛先と内容を固定した ActionRequest を作り、digest を付けて、approval.assignment のグループに承認の Task を作ります。Agent は承認を待たずに結果を返し、送るのは承認の後に Hane が行います。
spec: tools: [data.find_record, communication.send_email, request_human_help] sender: fleet-desk # 送信の名義。管理者が承認するまで使えない approval: assignment: fleet-approval decider: lease-application # 任意。金額などで決定者や段を決める DeciderPolicyアプリでは、実行に結び付く ActionRequest を読んで状態を見せます。
const actions = await unwrap(hane.GET("/v1/agents/action-requests", { params: { query: { run_id: run.run_id } } }));for (const a of actions.items) console.log(a.tool, a.state, a.parameters.contact?.masked, a.approval_task_id);承認は、頼んだ人とは別の人が Task として決めます。決め方は データと Workflow を使う にあります。承認の前なら POST /v1/agents/action-requests/{id}/cancel で取り消せます。
人が行う操作
Section titled “人が行う操作”郵送や窓口のように Hane の外で人が行う操作(human.perform)は、承認の後に実行の Task が担当に上がります。担当は承認された内容のとおりに行い、結果を POST /v1/agents/action-requests/{id}/perform で記録します。承認と違う内容は「受け付けられた」とは記録できず、逸脱として記録すると承認を取り直す Task になります。