機能エージェント

プロファイルを選ぶ

セッションがどのモデル・ツール・権限モードで動くかを決めるプロファイル

プロファイル (profile) は、セッションの動作方式を決める。runtime とそのバージョン、モデル、ツール一覧、権限モード、モデル provider、リポジトリを使うかどうかである。運用担当者のプロファイル は、そのインストールのすべてのワークスペースが使える最も広い範囲を決める。インストールのデータベースにあり、ユーザーは id を指定して選ぶ。プロファイルごとに動作できるリポジトリの一覧もその行にある。新しいインストールにプロファイルはない。インストールのオーナーがコンソールの設定 > エージェント接続 > モデル接続で接続を追加し、プロファイルを作るときにその接続を選ぶ。プロファイル画面では接続を作ったり変更したりせず、選ぶだけである。接続もインストールのデータベースにある。接続の追加ダイアログは、選んだ種類の公式エンドポイント (anthropic は https://api.anthropic.com) を入力済みにする。プロキシや互換サーバーを使うときだけ変更すればよく、空のまま送っても同じアドレスで保存される。公式アドレスのない種類 (litellm) は、エンドポイントを自分で入力する。エンドポイントは作成後に変更できない。接続を使用停止すると、その接続だけでモデルを呼ぶプロファイルとエージェントは、再び有効にするまで動かない。確認ダイアログは、取得できた影響の数 (プロファイル、有効なリリースのエージェント、未終了のセッション) を示す。使用停止した接続は、同じ画面の再び有効にするで戻せる。ただし、保存したキーがない場合や、同じ定義の別の接続が使用中の場合は戻せない。プロファイルが使っていた接続が利用できなくなったときは、フォームが先頭の接続に置き換えず、接続を選び直させる。

一覧を見る

SDK の例は SDK のインストールで作った werft クライアントを、HTTP API の例はサーバーのアドレス API とキー KEY のシェル変数を使う。

const profiles = await werft.profiles.list();
for (const profile of profiles.items) {
  console.log(profile.id, profile.model, profile.repository_mode);
}
claude-coding-auto claude-sonnet-5 required
claude-coding-local claude-sonnet-5 required
general claude-sonnet-5 none
フィールド意味
modelデフォルトのモデル
toolsセッションで使えるツール。これ以外のツールは実行されない (権限)
denyこのプロファイルがブロックする組み込みツール。このインストールがその runtime バージョンでサポートする組み込みツールのうち、tools にないもの。サポート一覧がないバージョンなら null (ツールのブロックリスト)
billingmetered ならコストをセッションの上限に計上する。none なら計上しない
repository_moderequired (リポジトリ必須)、optional、none (リポジトリなし)

provider のアドレスと認証情報は一覧に表示されない。その値は worker にも渡されない。

セッションで選ぶ

セッションを作成するとき、profile_id で選ぶ。プロファイルが複数のモデルを許可している場合は model でその中の 1 つを選び、省略するとデフォルトのモデルで動く。

実行中のセッションのモデルが許可リストから外れると、モデルへのリクエストはまもなく切断される。セッションのイベントに error イベント(code: MODEL_NOT_ALLOWED、model)が 1 回残り、セッション詳細のタイムラインに「… がプロファイルの許可リストから外れたため、このセッションのモデルリクエストがブロックされました」と表示される。許可リストを元に戻すか、別のモデルで新しいセッションを開始する。

モデルが許可リストから外れたためにブロックされる経路は、どれもそのモデル名を伝える。

  • 実行中のターンは上の error イベントである。プロファイルやモデル接続ごとなくなってブロックされるときも同じイベントが残り、cause は profile_removed(モデルだけが外れた場合は model_removed)、model にはセッションが使っていたモデルが入る。
  • 次のメッセージで新しい worker を起動しようとして止まると、セッションは failed になる。同じ error イベント(cause: model_removed)と「モデル … がプロファイル … の許可リストから外れた」という理由が、セッションのイベントと入力 receipt に残る。セッション詳細の attention(CATALOG_MISMATCH)も外れたモデル名を伝える。
  • 許可リストにないモデルで新しいセッションを作ると、422 UNSUPPORTED_CAPABILITY がモデル名を伝える。リクエストがモデルを指定せず、リリースのモデルで動く場合も同じである。
  • 許可リストから外れたモデルのリリースを有効化したり、そのリリースでセッションを作ったりすると、PROFILE_DIGEST_MISMATCH がリリースのモデルが許可リストから外れたことをモデル名とともに伝える。

プロファイル詳細は「このプロファイルを使うエージェント」の上に、エージェントの概要は準備状況の上に、どのモデルが外れたかと対処(モデルをリストに戻すか、エージェントの詳細設定でモデルを許可されたものに変更して保存する)を警告として表示する。

同じシリーズの新しいモデルへ切り替える

運用担当者のプロファイル(設定ドキュメントの profiles)に model_families を書いておくと、リストから外れたモデルのセッションは、止まる代わりに同じシリーズの新しいモデルへ切り替わる。モデル名から推測はせず、書かれた値だけを使う。

"model_families": {
  "claude-sonnet-5-0": { "family": "sonnet", "rank": 0 },
  "claude-sonnet-5-1": { "family": "sonnet", "rank": 1 }
}
  • family が同じモデルは 1 つのシリーズで、rank が大きいほど新しい。同じ family で rank が重なると設定は拒否される。
  • リストから外れたモデルのエントリも消さない。ないと、そのモデルがどのシリーズか分からず、これまでどおり止まる。
  • 候補は、許可リストにある同じ family で rank が高いモデル。複数あれば最も近い(最も低い)1 つ。低い rank へ下がることも、別の family へ移ることもない。候補がなければ上で説明したとおり止まる。
  • model_families はセッションの固定値(フィンガープリント)に入らない。書いたり変えたりしても、作成済みのセッションとリリースはそのまま。

切り替えは、セッションが次のターンを始める claim で行う。ターンを待っているセッションだけが切り替わり、実行中のターンには触れない。そのターンは上で説明したとおりモデルリクエストが切られる。切り替えるとセッションイベントに system イベント(subtype: model_migrated、from、to)が残り、タイムラインに「…から…に切り替えました」と表示される。前のモデルで作ったチェックポイントは、切り替え後もそのまま復元できる。

リリースのモデルが外れても候補があれば、そのリリースでセッションを作れる。セッションは候補のモデルで始まり、セッションを作ってもリリースは変わらない。リクエストが model を直接指定した場合は、許可リストにあるモデルでなければならない。プロファイルの要約(GET /v1/profiles)の model_successors が、外れたモデルと切り替え先を示し、このときエージェントの概要はブロックの警告ではなくお知らせを表示する。

エージェントのアクティブなリリースも候補に切り替わる。サーバーが理由 model_migration の新しいリリースを作って有効化し、監査 receipt に前後のモデルと automatic: true が残る。人が操作したものではないため、実行者はそのリリースを最後に有効化した人(owner か admin が必要) になる。その人が無効化されている、または owner・admin でなくなっている場合は切り替えず、エージェントはブロックされたままで、管理者に失敗の DM が届く。切り替えた後はエージェントの管理者に DM が届く。エージェントの auto_model_migration(PATCH /v1/agents/{id}、既定は true)を false にすると、リリースの書き換え・セッションの切り替え・新しいセッションでの候補の利用がすべて止まり、このエージェントはブロックされる。エージェント概要の警告からも切り替えられる。

この仕組みは、運用担当者のプロファイルのモデルリストが変わる場合を扱う。ワークスペースのプロファイルのバージョンは、作成後にモデルリストが変わらない。

最初にブロックされたとき、Slack の DM も 1 回届く。DM にも外れたモデル名が入る。宛先はセッションを作成した人とエージェントの管理者(直接指定した管理者、管理者チームのメンバー、担当チームの lead)で、それぞれこのエージェントの Slack アプリがインストールされたチームに Slack アカウントを連携している場合だけ届く。1 つのセッションにつき 1 人 1 回なので、同じセッションの次の試行がブロックされても再送されない。ほかの理由で終了したセッションには送らない。

const created = await werft.sessions.create({
  profile_id: "claude-coding-local",
  model: "claude-sonnet-5",
  repository_id: "sample-app",
  message: 'GATE-SPEC {"id":"profile","steps":[],"final":"ok"}',
});
const sessionId = created.session_id;
console.log((await werft.sessions.get(sessionId)).runtime);
{
  kind: 'claude_agent_sdk',
  version: '0.3.319',
  profile_id: 'claude-coding-local',
  model: 'claude-sonnet-5',
  permission_mode: 'default'
}

カタログにないプロファイル、そのリポジトリで動作できないプロファイル、プロファイルが許可していないモデルは 422 になる。

エージェントのリリースを作成するときは、runtime_profile_id で選ぶ。カードの model がそのプロファイルで実行できるモデルのひとつで、カードのツールがすべてプロファイルにある必要がある (作成)。

ツールのブロックリスト

プロファイルのバージョンは、使うツールを並べる代わりに、ブロックする組み込みツールだけを deny に書ける。運用担当者のプロファイルなら、サーバーはバージョンを保存するとき、このインストールがその runtime バージョンでサポートする組み込みツールのうち deny にないものを tools として保存する。ワークスペースのプロファイルは、下のとおりベースのツールの中で計算する。セッションとリリースは保存された tools だけを見る。

  • 制限なしはサポート一覧の中での話である。 運用担当者のプロファイルの deny: [] はサポート一覧の組み込みツールをすべて開く。エンジンに入っていても、このインストールがサポートしないツールは開かない。サポート一覧とツールごとの実行場所 (boundary) は、オーナーが GET /v1/installation-profiles/options の tool_catalogs で見る。
  • 実行場所。 local は worker の中で、egress はプラットフォームの外部接続プロキシを通って外へ、provider はモデル provider 側で動く。provider 側のツール (WebSearch) は外部接続プロキシでは止められず、プロファイルのブロックだけが止める。そのため、新しい名前の最初のバージョンは provider 側のツールを deny に入れて始めることを勧める。API は deny に書いたものだけをブロックするので、deny: [] は WebSearch も開く。コンソールは最初のバージョンで provider 側のツールを既定でブロックしておく。
  • あとから増えたツールはブロックされたまま引き継がれる。 バージョンは保存したときのサポート一覧で tools を固定し、既存のバージョン・リリース・セッションは新しいツールを得ない。エンジンを上げると runtime バージョンが変わるので、新しいプロファイルのバージョンを作ることになる。このとき、前のバージョン (運用担当者のプロファイルは previous_id、ワークスペースのプロファイルは同じ名前の最新バージョン) が検討していないツールは、accept_added_tools に書いたときだけ新しい tools に入る。そのようなツールが deny にも accept_added_tools にもなければ 400 (reason_code: added_tool_not_accepted) になる。前のバージョンを tools で作っていれば、その一覧の外のツールがすべてこれにあたる。
  • deny は組み込みツールの名前と mcp__<server>__<tool> の名前を受け付ける。 MCP の名前は、ツール一つを指す mcp__<server>__<tool> の形でなければならない。サーバー全体やパターンではブロックできない。形が違えば 400 (mcp_tool_name)、組み込みの GitHub サーバーのツールなら 400 (github_server) になる。このインストールの一覧にないサーバーなら 400 (unknown_mcp_server) になる。前のバージョンがすでにブロックしていた名前は、そのサーバーが一覧から外れていても改めて判定しない。レスポンスでは MCP の名前は deny ではなく mcp_deny に並べ替えて出て、deny には組み込みツールだけが残る。
  • accept_added_tools は組み込みツールの名前だけを受け付ける。 そこに MCP の名前を書くと 400 (mcp_tool) になる。deny と accept_added_tools のどちらでも、Bash(rm:*) のようなパターンは 400 (tool_pattern)、一覧にない名前は 400 (unknown_tool) になる。許可リスト (tools) で保存しても、前のバージョンがブロックした mcp__ の名前は引き継がれる。有効なリリースのプロファイルがブロックした MCP ツールは、エージェントの MCP 設定でも新たに許可できない (mcp_tool_denied)。
  • MCP のブロックは次のバージョンに引き継がれ、unblock_mcp_tools でだけ解除できる。 新しいバージョンは、前のバージョンがブロックした mcp__ の名前をすべて引き継ぐ。解除するには、その名前を unblock_mcp_tools に書く。前のバージョンがブロックしていない名前は 400 (mcp_unblock_unknown)、同じ名前を deny にも書くと 400 (mcp_unblock_conflict)、前のバージョンがなければ 400 (mcp_unblock_no_previous) になる。ワークスペースのプロファイル (POST /v1/workspace-profiles) の新バージョンは、前のバージョンを previous_id で指す。その間に同じ名前でより新しいバージョンができていれば 409 (stale_previous) になる。
  • ベースのプロファイルの上に作るバージョンは、ベースがブロックした MCP の名前を deny に自分で書く。 書き漏らしたり unblock_mcp_tools で解除しようとしたりすると 400 (base_mcp_deny_dropped) になる。
  • tools と deny のどちらか一方。 リクエストはどちらか一方だけを送る。両方送る、またはどちらも送らないと 400 になる。accept_added_tools は deny と一緒にだけ送る。tools で送ると、これまでどおりその一覧のまま保存される。サポート一覧がない runtime バージョンは tools だけを受け付け、deny は 400 (no_tool_catalog) になる。
  • ワークスペースのプロファイルはベースを超えない。 tools は、ベースのプロファイルの tools のうちサポート一覧にあるツールから deny を除いたものである。そのため deny: [] でも、ベースが使わないツールは開かない。ベースが deny で作ったバージョンでサポート一覧が同じなら、ベースがブロックしたツールを deny から外すリクエストは 400 (base_denies) になる。
  • 既存のバージョンはそのままである。 tools で作ったバージョンも、一覧の deny にはサポート一覧から tools を除いたものが出る。広げるには deny で新しいバージョンを作る。

下の例は、オーナーが 作成 の WEB ヘッダーで呼ぶ。まず、サポート一覧のうち worker の外へ出るツールを見る。

curl -sS "$API/v1/installation-profiles/options" "${WEB[@]}" \
  | jq -c '.tool_catalogs[0].tools | map(select(.boundary != "local"))'
[{"name":"WebFetch","boundary":"egress"},{"name":"WebSearch","boundary":"provider"}]

ローカルプロファイルの次のバージョンを、WebSearch だけをブロックして作る。ローカルプロファイルは tools で作ったバージョンなので、NotebookEdit・WebFetch は検討したことのないツールである。

next=$(jq -nc '{name: "coding-local", previous_id: "claude-coding-local",
  connection_id: "fake-messages", runtime_kind: "claude_agent_sdk", runtime_version: "0.3.319",
  model: "claude-sonnet-5", models: ["claude-sonnet-5"], permission_mode: "default",
  repository_ids: ["sample-app"], deny: ["WebSearch"]}')
curl -sS "$API/v1/installation-profiles" "${WEB[@]}" -d "$next" | jq -c '.error.details'
curl -sS "$API/v1/installation-profiles" "${WEB[@]}" \
  -d "$(echo "$next" | jq -c '.accept_added_tools = ["NotebookEdit", "WebFetch"]')" \
  | jq -c '.profile | {id, tools, deny}'
{"reason_code":"added_tool_not_accepted","field":"accept_added_tools"}
{"id":"op_coding-local_v1","tools":["Read","Edit","Write","Glob","Grep","NotebookEdit","Bash","AskUserQuestion","WebFetch"],"deny":["WebSearch"]}

リファレンス: POST /v1/installation-profiles

進行中のセッションのプロファイルを変更する

sessions.changeProfile(POST /v1/sessions/{id}/profile)で変更する。実行中のターンは開始時のプロファイルで終わり、その次の入力から新しいプロファイルで動く。会話と作業ツリーは最後の checkpoint から引き継がれる。同じプロファイルに変更しても何も変わらず、receipt だけが残る。

import { waitForTurn } from "@werft-ai/sdk";

await waitForTurn(werft, sessionId, created.turn_id);
const { revision } = await werft.sessions.get(sessionId);
const changed = await werft.sessions.changeProfile(sessionId, {
  expected_revision: revision,
  profile_id: "claude-coding-local",
});
console.log(changed.receipt_status);
succeeded

新しいプロファイルの runtime の種類・バージョンや課金方式が異なる場合、またはそのリポジトリと組み合わせられない場合は 422 UNSUPPORTED_CAPABILITY になる。エージェントのリリースで作成したセッションは、リリースがプロファイルを決めるため 409 RELEASE_PROFILE_MISMATCH になる。scope は sessions:control である。

ワークスペースのプロファイルを作る

ワークスペースのオーナーと管理者は、運用担当者のプロファイルを 1 つもとにして、このワークスペースだけで使うプロファイルを作れます。コンソールの ワークスペース > プロファイル で プロファイルを作成 を押します。

  • 減らすことだけができます。モデルとツールはベースプロファイルにあるものから選び、権限モードはベースプロファイルと同じか、人がより多く確認するモードだけを選べます。ベースプロファイルが auto を許可する場合(もとが auto か bypassPermissions)、新しいプロファイルは auto から始まり、プロファイルを作成 はそのようなベースプロファイルを先に選びます。もとが許可しない auto・bypassPermissions は選べない選択肢として表示されます。bypassPermissions のベースプロファイルは運用担当者がインストール設定を有効にしたインストールにだけあります。bypassPermissions を選ぶと危険の案内が表示されます。runtime、provider、認証情報、リポジトリとの組み合わせはベースプロファイルのものをそのまま使います。
  • 保存したバージョンは変わりません。編集 して保存するたびに新しいバージョンの id ws_<ワークスペースの slug>_<名前>_v<n> ができ、画面は保存前にその id を表示します。前のバージョンを使う release は、新しいバージョンで release を作り直すまで変わりません。一覧は名前ごとに最新のバージョンを 1 行で表示し、前のバージョンは 前のバージョン N 件 を押して開きます。
  • 行を押すと詳細画面(/profiles/<id>)が開きます。モデル・ツール・権限モード・ベースプロファイル、同じ名前のバージョン履歴、有効なリリースがそのバージョンを使うエージェントが表示されます。エージェント一覧はエージェントを管理できる人だけに表示されます。オーナー・管理者は 使用可能 なバージョンの詳細で 編集 を押すと現在の値が入った編集画面を開きます(ベースプロファイル変更済み なら 作り直す、使用停止したバージョンやもとがないバージョンにはボタンがありません)。運用担当者のプロファイルの詳細では ワークスペースのプロファイルを作成 で新しいワークスペースのプロファイルを始めます。
  • 一覧(GET /v1/profiles)には運用担当者のプロファイル(source: "operator")とこのワークスペースのバージョン(source: "workspace")が一緒に出ます。コンソールは運用担当者のプロファイルを変更できません。運用担当者のカタログは ws_ で始まる id を使えないため、両者は重なりません。
  • 運用担当者がベースプロファイルを変更するとバージョンは ベースプロファイル変更済み、削除すると ベースプロファイルなし、オーナーがブロックすると ベースプロファイルブロック中 になります。そのバージョンでは新しいリリースとセッションを作れません。もとが変わったバージョンは 作り直す で新しいバージョンを作ります。
  • 使用停止 したバージョンは新しいリリースとセッションが選べません。すでにそのバージョンを使う release とセッションは動き続けます。使用停止は元に戻せません。
  • リリースのプロファイル一覧は運用担当者のプロファイルとワークスペースのプロファイルを分けて表示し、新しいリリースを受けないバージョンは選べません。
  • メンバーは一覧を見るだけです。作成・編集・使用停止はコンソールにログインしたオーナー・管理者だけができ(POST /v1/workspace-profiles、POST /v1/workspace-profiles/{profile_id}/retire)、API key では 403 です。

auto ルールとスクリプト上限は画面に場所だけがあり、まだ変更できません。

運用担当者のプロファイルをブロックする

オーナーは運用担当者のプロファイルを 1 つ、いま動いているセッションまで含めて止められる。使用停止 (retire) は新しいリリースとセッションだけを止めるが、ブロックはそのプロファイルで動くものをすべて止める。Web ログインの cookie で、オーナーだけが行う。管理者・メンバーと API key は 403 になる。コンソールでは運用担当者のプロファイル詳細の ブロック・ブロック解除 から行い、確認ダイアログを通す。下の例は 作成 の WEB ヘッダーを使う。

curl -sS -X POST "$API/v1/installation-profiles/claude-coding-local/block" "${WEB[@]}" \
  | jq -c '{state: .profile.installation.state, receipt_id}'
{"state":"blocked","receipt_id":"…"}
  • プロファイルは ブロック中 (blocked) になり、その上のワークスペースのプロファイルは ベースプロファイルブロック中 (base_blocked) になる。
  • 新しいリリース、リリースの有効化、セッションは 409 PROFILE_BLOCKED で拒否される。error.details.reason_code は blocked(選んだプロファイルがブロック中)か base_blocked(そのベースがブロック中)で、error.details.profile_id は選んだプロファイルである。そのプロファイルの既存セッションは新しいメッセージを 409 PROFILE_BLOCKED で拒否し(ブロック前に受け付けたメッセージを同じ Idempotency-Key で再送すると元の応答が返る)、GET /v1/sessions/{id} の attention が PROFILE_BLOCKED になる。ブロック前に積まれたターンは始まるときに catalog_mismatch で終わり、いま動いているターンは 1 秒ほどでモデルとリポジトリへのリクエストが切れる。
  • POST /v1/installation-profiles/{profile_id}/unblock で解除すると元の状態に戻る。終わったセッションとターンは自動では動き直さないので、必要な入力をもう一度送る。
  • すでにその状態なら何も変わらず、receipt_id は null になる。

次のステップ

  • 権限: ツール一覧と権限モードの役割
  • 開始: セッション作成リクエスト

このページ