プログラミング
Jevの実践:型付けされた決定、スコープ化された権限
Jev in practice: typed decisions, scoped authority (tenuo.ai)
要約
この記事では、Tenuoが開発したJev、LangGraph、Tenuoを組み合わせた安全なエージェント委任システム「safe-upgrade」について解説しています。Jevはリポジトリの証拠を型付けされた確率的決定に変換し、LangGraphがその決定をワークフローで実行、Tenuoが各アクションにタスクスコープの権限(ワラント)を付与します。この設計により、判断、制御フロー、権限を分離し、依存関係のアップグレードのような複雑なタスクを安全かつ効率的に実行します。
全文翻訳
← Engineering Blog Tenuo Engineering ·2026年9月21日
Jevの実践:型付けされた決定、スコープ化された権限
Jev、LangGraph、Tenuoで安全なエージェント委任を構築
TL;DR: safe-upgradeは、Jev、LangGraph、Tenuoを基盤とした依存関係アップグレードエージェントです。Jevはリポジトリの証拠を型付けされた確率的決定に変換します。LangGraphはそれらの決定を耐久性のあるワークフローで運びます。Tenuoは結果として生じる各アクションにタスクスコープの権限(ワラント)を付与します。設計原則:判断、制御フロー、権限を分離する。
私たちは、Jev、LangGraph、Tenuoがシステムの異なる部分をそれぞれ担当する場合、有用なワークフローはどのようなものになるか、というビルダーの問いから始めました。依存関係のアップグレードは、それを実証する実用的な方法を提供しました。なぜなら、リポジトリメンテナーがすぐに学ぶように、一見機械的なプロセスでも、互換性に関する難しい問題を隠している可能性があるからです。バージョンを変更し、パッケージをインストールし、テストを実行し、プルリクエストを開いても、リリースによってAPIが削除されたり、モジュール形式が変更されたり、既存のスイートで実行されない動作が変更されたりすることがあります。インストールとCIは成功しても、アプリケーションは壊れたままになる可能性があります。有用なアップグレードエージェントは、リリース証拠を解釈し、それを馴染みのないリポジトリに関連付け、必要な作業を決定し、コードを変更し、結果が健全であることを確立する必要があります。また、ソースファイル、パッケージインストール、テストコマンド、Git、そして時にはリモートリポジトリへのアクセスも受け取ります。この組み合わせにより、エージェント開発の両側面、すなわち、乱雑なコンテキストから有用な決定を下すことと、それに続くアクションを制御することの両方を研究することができました。
決定から始めよう、プログラムが使用できるもの
Jevは、依存関係のアップグレードには、通常のルールではうまく扱えない意味論的な質問が含まれるため、私たちの出発点となりました。このリリースノートは、このリポジトリがパッケージを使用する方法に影響しますか?既存のテストは報告された問題を検出しますか?現在適格なステップのうち、最もリスクを軽減できるのはどれですか?最終的なパッチは、各移行の発見事項に対処していますか?
Jevは、開発者が状態と型付けされた質問を提供するソフトウェア内の決定のためのSystem One Modelです。Choiceの場合、開発者は利用可能なオプションを定義し、Jevは選択されたオプション、確率分布、およびプログラムがルーティングに使用できる信頼度を返します。safe-upgradeでは、決定論的なコードが最初に適格なアクションとその理由を計算します。次に、プロダクションアダプターがこのTypeSafe SDK呼び出しを行います。
const client = new TypeSafeClient();
const criteria = Object.fromEntries(
input.eligibleActions.map(({ action, reason }) => [action, reason]),
);
const result = await client.systemOne({
state: JSON.parse(JSON.stringify(input)),
questions: {
next: choice(
"Choose the eligible action that most directly reduces the unresolved " +
"risk in this upgrade. Every option is already permitted; pick the " +
"most useful one.",
criteria,
),
},
});
const answer = result.answers.next;
実際のChoice応答は、この型付けされた形状を持ちます。以下の値は、回帰テストの追加が最も強力な次のステップであった実行例を示しています。
{
"type": "choice",
"choice": "author_tests",
"confidence": 0.82,
"probabilities": {
"author_tests": 0.74,
"assess_verification": 0.18,
"implement": 0.08
}
}
ルーターは、選択されたラベルを元の候補と比較して検証し、通常のTypeScriptで信頼度を使用します。
const choice = validateRouteChoice(
{
action: answer.choice,
confidence: answer.confidence,
probabilities: answer.probabilities,
},
eligibleActions.map(({ action }) => action),
);
const selected = choice.confidence >= confidenceThreshold ? choice : deterministicFallback(input);
const worker = ACTION_WORKER[selected.action];
Jevは、リッチなリポジトリ状態がリッチなままであり、結果が小さな型付けされた決定としてグラフに入力されるため、ここで特に役立ちます。低い信頼度、不正な形式の応答、またはトランスポートの失敗は、ワークフローを決定論的なルートに送ります。候補セットはリクエストの前に確立され、実行時に返された選択を再度検証します。
Jevの決定からTenuoのワラントへ
Jevの応答は、選択されたアクションと信頼度で終了します。実行は、信頼されたルーティングコードがそのアクションを既知のワーカーにマッピングするときに開始されます。これにより、次のアーキテクチャ上の質問が生じます:この呼び出しに対して、そのワーカーはどのような権限を受け取るべきか? author-testsの場合、答えはリポジトリ読み取りツール、テストファイル書き込み、およびテスト実行です。本番環境では、Tenuoは明示的に信頼された発行者の公開鍵で初期化され、次に外部発行の実行ワラントとその所有者キーをインポートします。抜粋は、そのインポートステップから始まります。ローカルデモは開発ルートを使用し、コマンド出力でそのモードを示します。ワーカーは、実行の親ワラントから狭められた短命のターミナルセッションを受け取ります。
const parentSession = tenuo.sessionFromWire({
warrant: process.env.TENUO_RUN_WARRANT!,
holderKey: createTenuo.holderKeyFromEnv(
"TENUO_RUN_HOLDER_SECRET",
),
});
const testAuthor = tighten(
pick(ceilings, [
...READ_ONLY,
"write_test_file",
"run_check",
]),
"run_check",
"kind",
oneOf(["test"]),
);
const childSession = tenuo.narrow(parentSession, testAuthor, { terminal: true, ttlSeconds: 600 });
親ワラントは、実行の最大権限を設定します。狭めると、ツールのセットが小さくなり、run-checkがテストに絞り込まれ、有効期間が短縮され、子ターミナルになるため、再委任できなくなります。実装者は、ソースコードの変更と正確な依存関係の更新のための個別の子セッションを受け取りますが、write_test_fileはそのプロファイルから除外されます。実装コードが回帰テストを弱めようとすると、書き込みツールよりも前に承認が実行されます。
await broker.withWorker("implementer", "implement", (handle) =>
handle.tools.write_test_file({
path: "src/sneaky.test.ts",
expectedBeforeHash: "absent",
content: "test.skip('regression', () => {});",
}),
);
テストされた拒否記録が始まります。
TENUO_TOOL_NOT_AUTHORIZED
worker: implementer
capability: write_test_file
承認テストは、基盤となる書き込み関数が実行されないことも確認します。拒否記録には、ワーカー、機能、引数ハッシュ、およびセッション識別子が含まれ、試行されたファイルの内容は省略されます。これにより、グラフ内のロールが強制的な実行境界になります。テスト作成者はテストを書き、実装者はソースを書き、検証者は読み取り専用の候補ファイルを読み取り、チェックを実行します。
LangGraphが結果をワークフローで運ぶ
LangGraphは、実行中のリポジトリの事実、発見事項、決定、試行、および証拠を保持します。各ノードは明示的な状態を受け取り、更新を返し、チェックポイントは意味のある境界で進捗を保存します。
リポジトリ証拠 | v
信頼されたコードが適格な遷移を計算 | v
Jevがその型セット内で選択 | v
信頼されたコードがアクションをワーカーにマッピング | v
Tenuoがワーカーのワラントを狭める | v
保護されたツールがLangGraphに証拠を返す
評価は読み取り専用のワーカーのみを使用し、影響を受けるファイル、移行の発見事項、現在のチェック、および検証ギャップを記録します。評価の適用は、焦点を絞ったテストの追加、ソースの移行、正確な依存関係の更新、および一時的なGitワークツリーでの候補の検証を行うことができます。評価は、それが検査したコミット、マニフェスト、ロックファイル、および作業ツリーの状態にバインドされます。
CIでこれが重要な理由
エージェントがGitHub Actionsで無人で実行される場合、同じ境界がより重要になります。CIジョブには、リポジトリのチェックアウト、パッケージマネージャーのキャッシュ、GitHubトークン、およびプルリクエストへのコメントまたは開設権限が含まれる場合があります。ジョブレベルの権限は、ワークフローIDが何に到達できるかを確立します。これらは、この特定の実行が特定のパッケージ、ブランチ、またはファイルを変更する理由についての詳細を限定的に提供します。safe-upgradeは、イベントからDependabotプルリクエストを評価するか、検証済みのアップグレードをドラフトとして開くことができます。本番環境では、CIプロセスは信頼されたルートによって発行された実行ワラントをインポートします。そのワラントは、実行を要求されたパッケージと正確なバージョンにバインドできます。