Compare commits

...

16 Commits

253 changed files with 2594 additions and 1159 deletions

View File

@ -1,8 +1,8 @@
--- ---
title: 'Abstract Workspace Worker runtime spawn operations' title: 'Abstract Workspace Worker runtime spawn operations'
state: 'done' state: 'closed'
created_at: '2026-06-23T16:34:39Z' created_at: '2026-06-23T16:34:39Z'
updated_at: '2026-06-24T10:35:01Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-23T19:25:09Z' queued_at: '2026-06-23T19:25:09Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -288,4 +288,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Abstract Worker runtime registry and overview reporting' title: 'Abstract Worker runtime registry and overview reporting'
state: 'done' state: 'closed'
created_at: '2026-06-24T09:11:38Z' created_at: '2026-06-24T09:11:38Z'
updated_at: '2026-06-24T11:15:13Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T09:22:55Z' queued_at: '2026-06-24T09:22:55Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -374,4 +374,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Pod/session storage cleanup CLI を追加する' title: 'Pod/session storage cleanup CLI を追加する'
state: 'done' state: 'closed'
created_at: '2026-06-24T11:39:41Z' created_at: '2026-06-24T11:39:41Z'
updated_at: '2026-06-24T12:36:12Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary'] risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary']

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -213,4 +213,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる' title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる'
state: 'done' state: 'closed'
created_at: '2026-06-24T11:39:59Z' created_at: '2026-06-24T11:39:59Z'
updated_at: '2026-06-24T12:20:08Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection'] risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection']

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -208,4 +208,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Backend internal Orchestrator runtime for Kanban operations' title: 'Backend internal Orchestrator runtime for Kanban operations'
state: 'done' state: 'closed'
created_at: '2026-06-24T12:29:58Z' created_at: '2026-06-24T12:29:58Z'
updated_at: '2026-06-24T19:15:42Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T19:04:55Z' queued_at: '2026-06-24T19:04:55Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -254,4 +254,22 @@ Evidence:
Closure is not performed here; this state records implementation/design completion after merge/validation. Closure is not performed here; this state records implementation/design completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Remove legacy raw WASM Plugin runtime' title: 'Remove legacy raw WASM Plugin runtime'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-24T20:51:02Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:11:56Z' queued_at: '2026-06-24T20:11:56Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -270,4 +270,22 @@ Correction:
- 正しい merge commit は `bedbb670 merge: 00001KVXK0WD3 legacy wasm removal` - 正しい merge commit は `bedbb670 merge: 00001KVXK0WD3 legacy wasm removal`
- 実装 commit `741d7132`、review approve、validation results、Ticket done 判断には変更なし。 - 実装 commit `741d7132`、review approve、validation results、Ticket done 判断には変更なし。
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Reject legacy Plugin runtime in manifest and CLI diagnostics' title: 'Reject legacy Plugin runtime in manifest and CLI diagnostics'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-24T21:20:45Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:11:58Z' queued_at: '2026-06-24T20:11:58Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -303,4 +303,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Define Plugin Service lifecycle and ingress queue runtime' title: 'Define Plugin Service lifecycle and ingress queue runtime'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-24T21:51:13Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:12:00Z' queued_at: '2026-06-24T20:12:00Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -300,4 +300,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/review/focused validation. Closure is not performed here; this state records implementation completion after merge/review/focused validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Add Plugin service output command model' title: 'Add Plugin service output command model'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-25T06:20:26Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:12:02Z' queued_at: '2026-06-24T20:12:02Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -296,4 +296,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/review/focused validation. Closure is not performed here; this state records implementation completion after merge/review/focused validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Add host-owned WebSocket driver for Plugin services' title: 'Add host-owned WebSocket driver for Plugin services'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-25T07:06:30Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:12:03Z' queued_at: '2026-06-24T20:12:03Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -285,4 +285,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/review/focused validation. Closure is not performed here; this state records implementation completion after merge/review/focused validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Update Plugin WIT PDK templates for service event runtime' title: 'Update Plugin WIT PDK templates for service event runtime'
state: 'done' state: 'closed'
created_at: '2026-06-24T19:51:56Z' created_at: '2026-06-24T19:51:56Z'
updated_at: '2026-06-25T07:57:15Z' updated_at: '2026-06-25T14:13:52Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-06-24T20:12:05Z' queued_at: '2026-06-24T20:12:05Z'

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -360,4 +360,22 @@ Evidence:
Closure is not performed here; this state records implementation completion after merge/validation. Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
--- ---

View File

@ -0,0 +1,13 @@
{
"version": 1,
"relations": [
{
"ticket_id": "00001KVZ9JGK0",
"kind": "depends_on",
"target": "00001KVZBCQH4",
"note": "Backend internal Companion should run on the embeddable Runtime API.",
"author": "yoi ticket",
"at": "2026-06-25T13:25:34Z"
}
]
}

View File

@ -0,0 +1,123 @@
---
title: 'Backend内蔵Companion RuntimeとWeb Console MVP'
state: 'planning'
created_at: '2026-06-25T11:45:17Z'
updated_at: '2026-06-25T13:25:34Z'
assignee: null
---
## 背景
Workspace backend は Worker runtime registry / Backend internal runtime を control plane として扱う方向に進んでいる。Orchestrator については Backend internal runtime 上の Worker として Kanban / Ticket event を routing する設計が固まりつつある。同じ考え方で、Companion も local Pod / TUI 専用ではなく、Backend internal runtime 上の lightweight Worker として起動し、Web frontend から接続できるようにしたい。
この Ticket では、TUI Console の Web 移植版に向けた MVP として、Backend internal Companion Worker にメッセージを送り、LLM 応答を Web frontend で受け取るところまでを実装する。Companion は v0 では filesystem / shell / ticket mutation / runtime operation tools を持たなくてよい。まずは tools なしの conversational Worker として、Backend internal runtime、Web API、Web console UI、stream / transcript projection の最小経路を作る。
## 目的
- Backend internal runtime 上で Companion Worker を起動・保持できる。
- Workspace web frontend から Companion に接続できる。
- Web console UI から message を送信し、Companion の応答を表示できる。
- TUI Console の基本体験を Web に移植するための最小 transcript / run status / input path を作る。
- v0 では tool authority を持たせず、Backend internal conversational Worker として安全に始める。
## 要件
### Backend internal Companion runtime
- Backend internal runtime 上に Companion Worker を表現する。
- Companion は local Pod process / Unix socket / `.yoi/pods` metadata に依存しない。
- Worker identity は runtime scoped に扱う。
- `runtime_id`
- `worker_id`
- `display_name`
- `display_ref` 例: `companion@backend-internal`
- Runtime registry / Worker list/detail から Backend internal Companion が見える。
- v0 Companion は tools なし、または明示的に empty tool registry / minimal safe tool registry とする。
- Workspace filesystem、shell、git、Ticket mutation、raw session path、raw socket path を Companion authority にしない。
### Conversation / transcript model
- Backend internal Companion に user message を送れる API を追加する。
- Assistant response を Web frontend が受け取れるようにする。
- v0 は以下のどちらかの方式でよい。
- request / response 完了後に transcript を返す。
- SSE / streaming endpoint で delta / final response を返す。
- 実装方式は実装時に選んでよいが、UI が「送る -> 返る」を確認できること。
- Backend は raw provider trace を durable authority にしない。
- Web console 用 transcript は bounded projection とし、将来 prune / overview 化できる形にする。
- usage aggregate / run status は取れる範囲で残す。v0 で詳細 dashboard は不要。
### Web API
- Workspace server に Companion connection / message API を追加する。
- API は browser から raw runtime path / socket path / session path を受け取らない。
- API は current workspace の Backend internal Companion を解決する。
- 最低限以下を扱う。
- Companion status / detail 取得。
- Transcript / conversation projection 取得。
- User message 送信。
- Assistant response 取得または stream。
- Error は typed response として扱う。
- companion unavailable
- already running / busy
- invalid input
- provider error
- response timeout / cancelled
### Web Console UI
- Workspace web に Companion Console 画面または panel を追加する。
- TUI Console の基本 UI を Web 向けに移植する。
- transcript 表示。
- user message composer。
- sending / generating / idle / error 状態表示。
- assistant response の表示。
- v0 は message round-trip が主目的であり、TUI Console の全機能移植は不要。
- tool call UI、file viewer、diff viewer、thinking block grouping、multi Pod attach は scope 外でよい。
- Web UI は Backend API response / stream を authority とし、local session file / Pod socket を直接読まない。
### Runtime / LLM integration
- Backend internal Companion は existing LLM worker / provider config / profile selection のどれを使うか実装時に決める。
- v0 では project/default Companion profile の完全継承は必須ではないが、model / provider / language / prompt selection の最小方針を明確にする。
- Companion prompt は Rust 直書きではなく prompt resource boundary を使う。
- tools なし Companion でも system prompt / conversation history / current workspace identity は最小限渡せるようにする。
- Long-running provider request 中に複数 message を送った場合の扱いを決める。
- v0 は single-flight / busy reject でよい。
### Safety / authority
- Browser は raw provider credential、socket path、session path、runtime file path を知らない。
- Backend internal Companion は workspace filesystem / shell / git / Ticket mutation authority を持たない。
- 将来 tool を追加する場合も、domain-specific backend operation / explicit grant 経由にする。
- User message / assistant response は normal conversation history として扱い、hidden context injection にしない。
- Provider error / cancellation / timeout は Web UI に明示する。
## Non-goals
- Full TUI Console parity。
- Tool call execution UI。
- Filesystem / shell / git / Ticket mutation tools を Companion に渡すこと。
- Local Pod Companion の廃止。
- Remote runtime implementation。
- Multi-user auth / permission model の完成。
- Persistent raw session DB ingest。
- Usage dashboard の完成。
- Orchestrator routing / Kanban integration。
## 受け入れ条件
- Backend internal runtime 上に Companion Worker が存在し、runtime / worker API から確認できる。
- Web frontend から Backend internal Companion の status / transcript projection を取得できる。
- Web frontend の Console UI から user message を送信できる。
- Companion が LLM response を生成し、Web UI に表示される。
- v0 Companion は filesystem / shell / git / Ticket mutation tools を持たない。
- Browser が raw socket path / session path / runtime path / provider credential を扱わない。
- Provider request 中の busy / error / timeout が typed error または UI state として扱われる。
- Prompt prose は resource boundary に置かれている。
- Focused backend / frontend tests が追加されている、または E2E 不足の場合はテスト可能範囲と手動確認手順が記録されている。
- `cargo test -p yoi-workspace-server` が通る。
- `cargo check -p yoi` が通る。
- `cd web/workspace && deno task check && deno task build` が通る。
- `git diff --check` が通る。
- `nix build .#yoi --no-link` が通る。

View File

@ -0,0 +1,7 @@
<!-- event: create author: "yoi ticket" at: 2026-06-25T11:45:17Z -->
## 作成
LocalTicketBackend によって作成されました。
---

View File

@ -0,0 +1,21 @@
{
"version": 1,
"relations": [
{
"ticket_id": "00001KVZBCQH4",
"kind": "depends_on",
"target": "00001KVZD10ED",
"note": "Runtime crate API should use llm-engine naming for the turn engine before defining Worker types.",
"author": "yoi ticket",
"at": "2026-06-25T13:25:34Z"
},
{
"ticket_id": "00001KVZBCQH4",
"kind": "depends_on",
"target": "00001KVZG9BMS",
"note": "Worker Runtime should be created after the former pod crate is renamed to worker as the single Worker host.",
"author": "yoi ticket",
"at": "2026-06-25T13:43:31Z"
}
]
}

View File

@ -0,0 +1,147 @@
---
title: '組み込み/ネットワーク対応Worker Runtime crateを作る'
state: 'planning'
created_at: '2026-06-25T12:17:05Z'
updated_at: '2026-06-25T13:43:31Z'
assignee: null
---
## 背景
Yoi は現在、Worker 的な実行単位を主に `yoi pod` process / Unix socket / pod metadata / session jsonl として扱っている。一方で今後は、Companion や routing-only Orchestrator を Backend process 内に組み込んだ Runtime 上の Worker として動かし、Coder / Reviewer などは local / remote host 上の Runtime process で動かしたい。
このため、Backend が持つ `RuntimeRegistry` や Workspace API の都合ではなく、**Worker を動かす環境そのものとしての Runtime** を独立した crate / library API として定義する必要がある。`RuntimeRegistry` は Backend が embedded Runtime と remote Runtime をまとめて同じようにアクセスするための集約境界であり、Runtime 自体の実装主体ではない。
この Ticket では、まず要件だけを整理する。実装前に、現在の `pod`、`llm-worker`、Panel / Workspace backend における Pod / Worker 扱いを調査し、既存構造から Runtime crate へ移すべき責務と adapter として残すべき責務を把握する。
## 要件
### Runtime crate の位置付け
- `crates/worker-runtime` を Worker を動かす実行環境の正体として設計する。
- `worker-runtime/lib.rs` は Backend などに組み込める embeddable Runtime API を公開する。
- `worker-runtime/main.rs` は同じ Runtime を network API で公開する Runtime process を起動する。
- Runtime process と embedded Runtime は Worker semantics を二重実装しない。
- Worker lifecycle / input / output / event / transcript projection は lib 側を正とする。
- main binary は config / API server / transport / shutdown wrapper に留める。
### Runtime / Worker model
- Runtime は Worker を動かす環境であり、trait object ではなく domain entity / concrete runtime implementation として扱う。
- Runtime は複数 Worker を保持・起動・停止・操作できる。
- Worker identity は Runtime scoped とする。
- `runtime_id`
- `worker_id`
- UI 用 `display_name` / `display_ref`
- Browser / API / Backend は `runtime_id + worker_id` を authority とし、`pod_name` / socket path / session path を authority にしない。
- Runtime は capability / status / diagnostics を返す。
- backend internal
- local process capable
- future remote host capable
- filesystem / shell / git / worktree capability
- tools availability
### Embeddable Runtime API
- Backend は `Runtime` を process 内に直接組み込める。
- Embedded Runtime は tools なし Companion のような Worker を local process / socket なしで動かせる。
- API は少なくとも以下の操作を表現できる。
- runtime summary / status
- worker list / detail
- create worker
- send input
- stop / cancel worker
- bounded transcript projection
- event subscription または event cursor
- usage / overview projection
- v0 は single-flight / busy reject でよい。
- raw provider trace / raw session full log を Backend durable authority にしない。
### Networked Runtime process API
- `worker-runtime/main.rs` は Runtime を network API として公開する。
- 将来、別ホストの Runtime process に Backend が接続し、remote Worker を local / internal Worker と同じ概念で扱えるようにする。
- Network API は command と observation を分ける。
- command: create / input / stop / cancel
- observation: worker status / transcript projection / events
- v0 transport は実装時に選ぶが、HTTP command + SSE/WebSocket event stream を想定可能な shape にする。
- Browser が remote Runtime へ直接 authority-bearing request を送るのではなく、Backend registry / policy 経由にする。
### Backend RuntimeRegistry との関係
- Workspace backend の `RuntimeRegistry` は、embedded Runtime と remote Runtime client をまとめる集約境界とする。
- Registry は Worker を実行しない。
- Registry は runtime lookup / policy / visibility / API projection / current workspace filtering を担う。
- Backend internal Companion は embedded Runtime に載る Worker として扱う。
- Existing local Pod / process-based Worker は Runtime の adapter または移行対象として扱う。
### Existing Worker / LLM engine migration boundary
- `llm-worker` は先に `llm-engine` へ改名し、LLM turn engine と実行単位としての Worker を名前上分離する。
- 既存 `pod` crate は先に `worker` crate へ rename し、single Worker host として扱う。
- 既存 `yoi pod` process は当面 compatibility / process-backed Worker adapter として扱えるようにする。
- 最終的には process boundary を Worker ではなく Runtime に寄せる。
- Runtime process が複数 Worker を保持できる。
- Worker ごとに subprocess を持つかどうかは Runtime implementation detail とする。
- `llm-engine` の provider streaming / tool execution / history integration のうち、Runtime crate に移すべきものと Worker-specific に残すものを調査して整理する。
- `worker` crate の Unix socket protocol / metadata / session persistence / TUI attach semantics は、Runtime API との対応を調査してから移行方針を決める。
### Pod-named store / registry migration boundary
- `pod-store` / `pod-registry` は standalone crate として rename せず、`worker-runtime` 作成時に Runtime 内部 module へ直接統合する。
- `pod-store` 相当は Runtime 内部の Worker metadata / transcript projection / config snapshot persistence module とする。
- `pod-registry` 相当は Backend RuntimeRegistry ではなく、Runtime 内部の live Worker allocation / scope conflict / stale reclaim module とする。
- Backend `RuntimeRegistry` は embedded / remote Runtime を束ねる集約境界であり、Worker store / live allocation authority を直接持たない。
- 後方互換 alias / standalone `worker-store` / standalone `worker-registry` / old crate compatibility / old on-disk migration は設けない。
### Safety / authority
- Runtime API は raw socket path / session path / local metadata path を公開 API authority にしない。
- Worker tool authority は Runtime / Worker config / explicit grant で決める。
- Backend internal Companion v0 は filesystem / shell / git / Ticket mutation tools を持たない。
- Remote Runtime との接続では将来 auth / permission / network safety を挟める境界を残す。
## 調査事項
実装前に以下を調査する。
- `crates/pod` が現在担っている責務。
- process entrypoint
- socket protocol
- session persistence
- metadata / runtime dir
- in-flight snapshot / attach behavior
- tool registry / workflow / profile integration
- `crates/llm-worker` が現在担っている責務。
- provider request / streaming
- history / callback / tool-call loop
- reasoning / usage / continuation / retry
- Worker として再利用できる boundary
- Panel / TUI / Workspace backend が現在 Pod をどう扱っているか。
- Companion send path
- Worker/host list API
- Pod metadata reader
- spawn / stop / attach / event handling
- Existing `client` crate の process spawn / PodClient / socket protocol を Runtime adapter でどう扱うか。
## Non-goals
- Backend internal Companion Web Console の完成。
- Remote Runtime protocol の完成。
- Existing Pod process model の即時削除。
- Full session storage migration。
- Full tool authority redesign。
- Multi-user auth / permission model の完成。
## 受け入れ条件
この Ticket は要件整理と現状把握から開始する。ready に進める前に以下を満たす。
- `worker-runtime/lib.rs``worker-runtime/main.rs` の責務境界が整理されている。
- Runtime / Worker / RuntimeRegistry / Backend service の責務境界が整理されている。
- Runtime は Worker を動かす環境、Registry は Backend の集約境界であることが明確になっている。
- Embedded Runtime と networked Runtime process が同じ Runtime API に基づく方針が整理されている。
- Existing `worker` / `llm-engine` / Panel / Workspace backend の Worker 扱いの調査結果が記録されている。
- `pod-store` / `pod-registry` は standalone rename を挟まず、`worker-runtime` 内部 module へ直接統合する方針が整理されている。
- Backend `RuntimeRegistry` と Runtime internal store / allocation registry の責務境界が整理されている。
- 既存 Worker process model から Runtime model へ移行するための初期 implementation split が提案されている。

View File

@ -0,0 +1,246 @@
<!-- event: create author: "yoi ticket" at: 2026-06-25T12:17:05Z -->
## 作成
LocalTicketBackend によって作成されました。
---
<!-- event: comment author: hare at: 2026-06-25T12:21:06Z -->
## Comment
## 現状調査メモ: Pod / llm-worker / Panel / Workspace backend の Worker 扱い
### crates/pod
`pod` crate は現在、Worker 実行環境というより `yoi pod` process そのものの runtime を担っている。
主な責務:
- `entrypoint.rs`
- `yoi pod` CLI entrypoint。
- workspace / profile / manifest / project / store / pod name / session resume / hidden ticket-role marker を解決する。
- Profile launch policy、ticket role policy、workflow selection、resource prompt loading、tool feature install の起点を持つ。
- `pod.rs`
- `Pod` 構造体が session store、metadata、current state、scope、tool registry、workflow registry、in-flight events、LLM Worker を束ねる。
- `Method::Run` を受けて history に user input を commit し、`llm_worker::Worker::run_with_callbacks` を起動する。
- assistant/tool/reasoning/usage/error/turn_end を session log と event broadcast に反映する。
- session persistence / snapshots / compaction / workflow invocation / pod metadata 更新が同居している。
- `controller.rs` / `ipc/server.rs`
- Unix socket server。
- connect 時に `Event::Snapshot` を送る。
- JSON line method を読み、Pod controller に渡す。
- broadcaster 経由で append / status / alert / snapshot events を client に流す。
- `in_flight.rs`
- attach mid-stream 用の transient text / thinking / tool-call block accumulator。
- session log authority ではなく socket snapshot/event 用の live projection。
Runtime crate へ移す候補:
- Worker lifecycle state / busy handling / input dispatch / event projection。
- in-flight / transcript projection の汎用概念。
- Worker event / method / status の domain model。
Pod-specific に残す候補:
- `yoi pod` CLI entrypoint。
- Unix socket protocol compatibility。
- pod metadata / runtime dir / stderr ready handshake。
- session jsonl layout compatibility。
- Profile / manifest discovery の既存 startup path。
### crates/llm-worker
`llm-worker` は Pod process とは独立した LLM turn executor に近い。
主な責務:
- `Worker` が model/provider config、history、tool registry、workflow registry、memory config、prompt config、retry/continuation policy を保持する。
- `run_with_callbacks` が 1 user turn を LLM provider に投げ、stream events を callbacks に渡す。
- tool-call loop、tool execution、reasoning / usage / continuation / retry / compaction safety など、実際の LLM turn semantics を持つ。
- `CallbackHandler` / `RunCallbacks` により、Pod 側が session persistence / event broadcast / in-flight tracking を差し込む。
Runtime crate へ移す候補:
- 「Worker に input を送り response/events を得る」上位 lifecycle。
- usage / overview projection。
そのまま再利用する候補:
- provider transport / request serialization / streaming event parsing。
- tool-call loop / history-aware retry / continuation。
- callbacks abstraction。
注意点:
- `llm-worker::Worker` は既に比較的 embeddable だが、現在は `pod::Pod` が session store・event・metadata・scope と強く結合して使っている。
- Backend internal Runtime は、Pod を経由せず `llm-worker::Worker` を直接持てる可能性がある。
### crates/client
`client` crate は既存 Pod process / socket client の adapter 部分を持つ。
主な責務:
- `spawn.rs`
- `PodProcessLaunchConfig` / `PodProcessLaunchOptions`
- `yoi pod` process を起動し、stderr の `YOI-READY` と socket connectability を acceptance evidence とする。
- `pod_client.rs`
- Unix socket に接続し、connect-time snapshot / alert を drain してから method を送る。
- one-shot Pod client。
Runtime model 上の位置付け:
- `LocalProcess` / legacy Pod adapter が使う process-backed compatibility layer。
- `worker-runtime` lib の core semantics ではなく、process transport adapter 側。
### Panel / TUI
Panel / TUI は現在 Pod を socket / metadata ベースで扱う。
例:
- dashboard companion send path は Companion Pod の socket path に `UnixStream::connect` し、connect-time Snapshot/Alert を読んでから `Method::Run` を送る。
- `UserMessage` event を acceptance evidence とする。
- Panel の role/session claim や ticket row 操作は既存 Pod / role launch helper に寄っている。
Runtime model への移行方向:
- TUI/Panel は直接 socket path を authority とせず、Backend / Runtime API 経由で `runtime_id + worker_id` に input を送る方向へ移す。
- 既存 local Pod attach は compatibility path として残す。
### Workspace backend
Workspace backend は現在 `WorkerRuntimeRegistry` / `LocalPodRuntime` 相当を持つが、実行 Runtime ではなく local Pod metadata projection が中心。
主な現状:
- `crates/workspace-server/src/hosts.rs`
- `WorkspaceWorkerRuntime` trait、`WorkerRuntimeRegistry`、`LocalPodRuntime` が存在する。
- `LocalRuntimeBridge = LocalPodRuntime` alias が残る。
- `/api/hosts`, `/api/workers`, `/api/hosts/{host_id}/workers` は registry 経由で worker summaries を返す。
- LocalPodRuntime は `.yoi/pods/*/metadata.json` を読み、runtime/worker projection を作る。
- `spawn_worker` 等の typed shape はあるが、実 operation は unsupported / pending に近い。
- Backend internal LLM Worker runtime はまだ存在しない。
Runtime model への移行方向:
- Workspace backend の Registry は `worker-runtime::Runtime` または network Runtime client を束ねる集約境界にする。
- `LocalPodRuntime` は本来の Runtime ではなく、既存 Pod metadata/socket を Worker projection に見せる compatibility adapter として扱う。
- Backend internal Companion は `worker-runtime::Runtime` を embedded に持ち、その Runtime 内の Worker として作る。
### 初期 implementation split 案
1. `worker-runtime` crate skeleton。
- `RuntimeId` / `WorkerId` / `WorkerRef` / status / summary / input / event / transcript projection / error 型。
- `Runtime` concrete struct の最小 shell。
- worker list/detail/send_input の mock or no-op capable core。
2. Backend に embedded Runtime を組み込む。
- Workspace backend の Registry に embedded Runtime handle を登録。
- まだ LLM は mock でもよい。
3. `llm-worker` を使った tools なし in-process Worker。
- single-flight。
- transcript projection。
- usage/error projection。
4. Existing LocalPodRuntime を compatibility adapter として明示化。
- metadata reader / socket send は adapter 側。
- PodProcessLaunchConfig は process-backed path に閉じる。
5. `worker-runtime` binary / network API。
- 同じ Runtime lib を起動して HTTP command + event observation API を公開する。
6. Web Companion Console MVP。
- Backend embedded Runtime 上の companion Worker に message round-trip。
---
<!-- event: decision author: hare at: 2026-06-25T13:14:10Z -->
## Decision
## 追加調査メモ: pod-store / pod-registry の役割と移行方針
### pod-store
`pod-store``{data_dir}/pods/{pod_name}/metadata.json` を扱う name-keyed metadata store である。主な内容は active session/segment pointer、workspace_root、spawned/reclaimed children、peers、resolved_manifest_snapshot。
これは正規 Worker Runtime の永続化層としては粒度と authority が古い。
- identity が `pod_name` 中心。
- socket/process/session restore を前提にした metadata が混ざる。
- child/peer relation は Runtime/Worker records と orchestration records に分解すべき。
- session pointer は Runtime-local transcript/run projection として扱うべき。
短期対応として `worker-store` に rename するが、最終的には `worker-runtime` 内部の persistence module に統合する。
### pod-registry
`pod-registry``<runtime_dir>/pods.json` の flock-protected live allocation table である。主な内容は pod_name、pid、socket path、scope allow/deny、delegated_from、segment_id。
これは Backend の RuntimeRegistry とは別物で、旧 local Pod process 群の machine-wide scope lock / delegation / stale reclaim である。Runtime model では、Worker allocation は Runtime 内部の責務になる。
- 同一 Runtime 内 Worker の scope conflict は Runtime の allocation manager が扱う。
- remote Runtime の allocation は remote Runtime 側の authority。
- host-level conflict が必要な場合も Pod registry ではなく Runtime/host allocation model として設計する。
短期対応として `worker-registry` に rename するが、最終的には `worker-runtime` 内部の allocation / scope_registry module に統合する。
### 決定
- `pod-store` / `pod-registry` は正規 architecture では役目を終える。
- ただし即削除ではなく、まず `worker-store` / `worker-registry` へ rename し、Pod terminology を active API から外す。
- 後続 Ticket で standalone crates を削除し、`worker-runtime` 内部 module に統合する。
- 後方互換 alias / old path migration は設けない。
---
<!-- event: decision author: hare at: 2026-06-25T13:25:49Z -->
## Decision
Implementation order is now recorded with depends_on relations:
1. 00001KVZD10ED llm-worker crateをllm-engineへ改名する
2. 00001KVZEHJG1 pod-store/pod-registry crateをWorker用語へ改名する
3. 00001KVZBCQH4 組み込み/ネットワーク対応Worker Runtime crateを作る
4. 00001KVZEHJGT worker store/registryをworker-runtimeへ統合する
5. 00001KVZ9JGK0 Backend内蔵Companion RuntimeとWeb Console MVP
The key boundary is that Backend RuntimeRegistry aggregates Runtime instances, while worker store/allocation belongs inside worker-runtime after the transitional rename step.
---
<!-- event: decision author: hare at: 2026-06-25T13:30:09Z -->
## Decision
Decision update: skip the standalone worker-store / worker-registry rename step.
The implementation order is now:
1. 00001KVZD10ED llm-worker crateをllm-engineへ改名する
2. 00001KVZBCQH4 組み込み/ネットワーク対応Worker Runtime crateを作る
3. 00001KVZ9JGK0 Backend内蔵Companion RuntimeとWeb Console MVP
`pod-store` and `pod-registry` should be handled during the worker-runtime implementation itself: do not create standalone `worker-store` / `worker-registry` transitional crates. Move their relevant responsibilities directly into worker-runtime internal persistence/allocation modules, and leave Pod-specific compatibility as adapter detail only where still needed.
---
<!-- event: decision author: hare at: 2026-06-25T13:43:31Z -->
## Decision
Implementation order update:
1. 00001KVZD10ED llm-worker crateをllm-engineへ改名する
2. 00001KVZG9BMS pod crateをworker crateへ改名する
3. 00001KVZBCQH4 組み込み/ネットワーク対応Worker Runtime crateを作る
4. 00001KVZ9JGK0 Backend内蔵Companion RuntimeとWeb Console MVP
The pod -> worker step is a rename, not a rewrite. Runtime creation absorbs the former pod-store / pod-registry responsibilities directly into worker-runtime internal persistence/allocation modules; do not create standalone worker-store / worker-registry crates.
---

View File

@ -0,0 +1 @@
{"id":"orch-plan-20260625-132518-1","ticket_id":"00001KVZD10ED","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVZD10ED` は implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVZD10ED-llm-engine-rename` と branch `work/00001KVZD10ED-llm-engine-rename` で、`llm-worker` / `llm-worker-macros` を `llm-engine` / `llm-engine-macros` に rename し、主要 public turn-engine 型を `Worker` から `Engine` 系へ rename する。責務移動や worker-runtime 実装、互換 alias は non-goal。","branch":"work/00001KVZD10ED-llm-engine-rename","worktree":"/home/hare/Projects/yoi/.worktree/00001KVZD10ED-llm-engine-rename","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: repository-wide crate/type rename in dedicated child worktree. Reviewer: read-only review focusing on mechanical rename completeness, no compatibility alias, no behavior/authority movement, and validation evidence."},"author":"yoi-orchestrator","at":"2026-06-25T13:25:18Z"}

View File

@ -0,0 +1,89 @@
---
title: 'llm-worker crateをllm-engineへ改名する'
state: 'closed'
created_at: '2026-06-25T12:45:38Z'
updated_at: '2026-06-25T14:13:52Z'
assignee: null
queued_by: 'workspace-panel'
queued_at: '2026-06-25T13:24:26Z'
---
## 背景
今後は旧 `Pod` 相当の実行単位を `Worker` として扱い、`Runtime` が複数 Worker を保持・操作する構造へ移行したい。一方、現在の `crates/llm-worker` は実行単位としての Worker ではなく、LLM provider request / stream parsing / tool-call loop / reasoning / usage / retry / continuation / low-level history を進める turn engine である。
このまま `llm-worker::Worker` という名前を残すと、今後導入する `worker-runtime::Worker` / Runtime scoped Worker identity と衝突し、Pod から Worker への概念移行が分かりにくくなる。責務分離自体は現在の `llm-worker` のままで概ね良いが、名前は実体に合わせて `llm-engine` へ変更する。
この Ticket では crate rename、Rust module path rename、主要型 rename、関連 procedural macro crate rename を一括で行う。中途半端に crate 名だけ変えると check が通りにくく、移行中の混乱も残るため、`llm-worker -> llm-engine`、`llm-worker-macros -> llm-engine-macros`、`Worker -> Engine` を同じ実装単位で完了させる。
## 要件
### Crate / package rename
- `crates/llm-worker``crates/llm-engine` に rename する。
- `crates/llm-worker-macros``crates/llm-engine-macros` に rename する。
- Cargo package name を `llm-worker` から `llm-engine` に変更する。
- Cargo package name を `llm-worker-macros` から `llm-engine-macros` に変更する。
- Workspace `Cargo.toml`、crate dependencies、imports、tests、docs、Nix packaging references を新しい crate 名に更新する。
- Rust import path は `llm_worker` から `llm_engine` に変更する。
- Macro crate import path は `llm_worker_macros` から `llm_engine_macros` に変更する。
- 旧 crate 名 compatibility alias は作らない。
### Type / API rename
- `llm_worker::Worker``llm_engine::Engine` に rename する。
- `WorkerConfig``EngineConfig` に rename する。
- `WorkerResult``EngineRunResult` または同等に rename する。
- `WorkerError``EngineError` に rename する。
- `RunOutput``EngineRunOutput` または `RunOutput` のままでもよいが、public API 上で `Worker` という語が turn engine の主体名として残らないよう整理する。
- `ToolDefinition as WorkerToolDefinition` のような import alias は、意味が残るなら `EngineToolDefinition` 等に更新する。
- 内部 doc comment / examples / tests の「Worker」は、実行単位としての Worker と混同しないよう `Engine` / `LLM engine` / `turn engine` に更新する。
### Responsibility boundary
- `llm-engine` は Runtime / Worker identity / process lifecycle / socket protocol / session file authority を持たない。
- `llm-engine` は LLM turn engine として以下を担う。
- provider request / stream handling
- normalized LLM events
- tool-call loop
- text / reasoning / tool / usage handling
- retry / continuation
- low-level history management
- callback hooks
- `pod` crate や将来の `worker-runtime` crate が、実行単位としての Worker lifecycle / Runtime scoped identity / transcript projection / API exposure を担う。
- この Ticket では責務移動は最小限にし、主に naming / package boundary を整理する。
### Migration scope
- Repository-wide references to `llm-worker`, `llm-worker-macros`, `llm_worker`, and `llm_worker::Worker` are updated.
- Repository-wide references to `llm_worker_macros` are updated to `llm_engine_macros`.
- `pod` crate uses `llm_engine::Engine` internally.
- Tests / fixtures / generated docs that mention the old crate/type names are updated.
- If generated lock/package files change, they are updated consistently.
- Obsolete paths are removed; no duplicate `crates/llm-worker` or `crates/llm-worker-macros` directory remains.
## Non-goals
- New `worker-runtime` crate implementation.
- Pod -> Worker runtime migration.
- Backend internal Companion implementation.
- Runtime network API implementation.
- Moving session persistence / socket protocol / metadata authority into `llm-engine`.
- Changing provider request semantics, tool-call loop behavior, retry/continuation behavior, or history semantics beyond rename fallout.
- Backward compatibility alias for the unreleased `llm-worker` crate name.
## 受け入れ条件
- `crates/llm-engine` and `crates/llm-engine-macros` exist; `crates/llm-worker` and `crates/llm-worker-macros` are gone.
- Cargo package names and crate import paths are `llm-engine` / `llm_engine` and `llm-engine-macros` / `llm_engine_macros`.
- Public turn-engine type is `llm_engine::Engine`, not `llm_engine::Worker`.
- Public config/result/error names no longer use `Worker` for the LLM turn engine concept.
- Repository-wide references to `llm-worker` / `llm-worker-macros` / `llm_worker` / `llm_worker_macros` are gone except migration notes or changelog-like context where intentionally retained.
- `pod` and dependent crates compile against `llm_engine::Engine`.
- Existing behavior of provider streaming, tool-call loop, history append callbacks, retry/continuation, and usage events is unchanged except for names.
- Docs / comments that define the new WorkerRuntime direction no longer conflict with the LLM engine naming.
- `cargo test -p llm-engine` passes.
- `cargo test -p pod` passes.
- `cargo check -p yoi` passes.
- `git diff --check` passes.
- `nix build .#yoi --no-link` passes.

View File

@ -0,0 +1 @@
Implemented, reviewed, marked done, and merged into develop.

View File

@ -0,0 +1,335 @@
<!-- event: create author: "yoi ticket" at: 2026-06-25T12:45:38Z -->
## 作成
LocalTicketBackend によって作成されました。
---
<!-- event: intake_summary author: hare at: 2026-06-25T13:23:50Z -->
## Intake summary
Marked ready by `yoi ticket state`.
---
<!-- event: state_changed author: "yoi ticket" at: 2026-06-25T13:23:50Z from: planning to: ready reason: cli_state field: state -->
## State changed
Marked ready by `yoi ticket state`.
---
<!-- event: state_changed author: workspace-panel at: 2026-06-25T13:24:26Z from: ready to: queued reason: queued field: state -->
## State changed
Ticket を `workspace-panel` が queued にしました。
---
<!-- event: decision author: yoi-orchestrator at: 2026-06-25T13:26:00Z -->
## Decision
Routing decision: implementation_ready
Reason:
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
- Ticket body は `llm-worker` / `llm-worker-macros` crate rename、Rust import path rename、major public type rename (`Worker` -> `Engine`, config/result/error names)、repo-wide references、validation を具体的に列挙している。
- `TicketRelationQuery` は blocking relation 0 件、`TicketOrchestrationPlanQuery` は routing 前 plan 0 件だった。
- bounded context check で repository-wide `llm-worker` / `llm_worker` references を確認し、主な変更 surface は `crates/llm-worker`, `crates/llm-worker-macros`, workspace/dependency metadata, `pod`/`manifest` imports, docs/tests/examples/Nix/Cargo.lock である。これは大きめだが mechanical rename task として明確で、責務移動や WorkerRuntime 実装は non-goal として分離されている。
- risk は API/naming churn だが、受け入れ条件と validation が明確で、Coder の bounded implementation latitude に収まる。planning return が必要な未決定事項は見つからない。
Evidence checked:
- Ticket body / thread: `item.md`, `thread.md`。thread は create、planning->ready、ready->queued のみで未解決 blocker は記録されていない。
- Relations / orchestration plan: relation 0 件、routing 前 plan 0 件。accepted plan `orch-plan-20260625-132518-1` を記録済み。
- Code context: `git grep``crates/llm-worker`, `crates/llm-worker-macros`, `llm_worker`, `llm_worker_macros`, `Worker` imports/examples/tests/docs references を確認。
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。queued Ticket はこの 1 件、inprogress Ticket は 0 件。
IntentPacket:
Intent:
- LLM turn-processing crate を `llm-worker` から `llm-engine` へ rename し、public turn-engine主体型を `Worker` から `Engine` 系へ rename することで、今後の Runtime-scoped Worker concept と衝突しない package/API naming に整理する。
Binding decisions / invariants:
- `llm-engine` は LLM turn engine。Runtime / Worker identity / process lifecycle / socket protocol / session file authority は持たない。
- 責務移動は最小限。provider request/stream handling、tool-call loop、reasoning/usage/retry/continuation/history/callback semantics は変えない。
- `crates/llm-worker` / `crates/llm-worker-macros` は残さない。
- `llm-worker` / `llm_worker` / `llm_worker_macros` compatibility alias は作らない。
- `pod` crate and dependents should compile against `llm_engine::Engine` and renamed config/result/error types.
- New `worker-runtime` crate or Pod->Worker migration is non-goal.
Requirements / acceptance criteria:
- `crates/llm-engine` and `crates/llm-engine-macros` exist; old directories gone.
- Cargo package/dependency names and Rust import paths use `llm-engine` / `llm_engine` and `llm-engine-macros` / `llm_engine_macros`.
- Public turn-engine type is `llm_engine::Engine`, not `Worker`; config/result/error names no longer use `Worker` for the turn engine concept.
- Repository-wide old references are gone except intentional historical/migration notes if any.
- `pod`, `manifest`, `yoi`, examples/tests/docs/Nix/Cargo.lock update consistently.
- Existing runtime behavior is unchanged except names.
- Validation target includes `cargo test -p llm-engine`, `cargo test -p pod`, `cargo check -p yoi`, `git diff --check`, `nix build .#yoi --no-link`.
Implementation latitude:
- Result/output type exact names may follow Ticket guidance (`EngineRunResult`, `EngineRunOutput`, etc.) as long as public API no longer presents LLM turn engine as Worker.
- Internal file names may be renamed for clarity (`worker.rs` -> `engine.rs`) if practical; otherwise public module/API must be clean.
- Historical ticket ids or changelog-like references may remain only if clearly intentional and not active API/docs guidance.
Escalate if:
- Rename requires behavior changes to provider streaming/tool-loop/history semantics.
- A compatibility alias appears necessary to make internal crates compile.
- Existing macro/test generated names cannot be renamed without broader procedural macro redesign.
- `cargo test -p pod` failure is not the known prompt guidance snapshot caveat but a rename regression.
Validation:
- `cargo test -p llm-engine`
- `cargo test -p pod`
- `cargo check -p yoi`
- `git diff --check`
- `nix build .#yoi --no-link`
- Add focused grep evidence for old names.
Current code map:
- Primary: `crates/llm-worker`, `crates/llm-worker-macros`, workspace `Cargo.toml`, `Cargo.lock`, `package.nix`
- Secondary: dependent imports in `crates/pod`, `crates/manifest`, examples/tests/docs/resources as found by grep。
- Avoid: worker-runtime implementation, Pod runtime migration, session/socket authority changes, provider/tool-loop behavior changes。
Critical risks / reviewer focus:
- stale old crate/import/type references。
- hidden compatibility alias left behind。
- behavior changes mixed into mechanical rename。
- `Worker` remaining as public turn-engine主体名 where it conflicts with Runtime Worker concept。
- Nix/Cargo lock/hash updates missed。
Next action:
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVZD10ED-llm-engine-rename` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
---
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T13:26:35Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
## State changed
Orchestrator acceptance: queued -> inprogress
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan `orch-plan-20260625-132518-1` を確認した。
- routing decision と IntentPacket は Ticket thread に記録済み。
- orchestration worktree は clean。この Ticket 用 worktree/branch はまだ作成していない。
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVZD10ED-llm-engine-rename` を作成し、multi-agent-workflow に接続する。
---
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T13:28:20Z -->
## Implementation report
Implementation orchestration update:
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVZD10ED-llm-engine-rename` と branch `work/00001KVZD10ED-llm-engine-rename` を作成した。
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
- Coder Pod `yoi-coder-00001KVZD10ED-llm-engine` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
---
<!-- event: implementation_report author: yoi-coder-00001KVZD10ED-llm-engine at: 2026-06-25T13:47:26Z -->
## Implementation report
Implementation report:
対象 Ticket:
- `00001KVZD10ED``llm-worker crateをllm-engineへ改名する`
実装概要:
- `crates/llm-worker``crates/llm-engine`
- `crates/llm-worker-macros``crates/llm-engine-macros`
- Cargo package / workspace dependency 名を `llm-engine` / `llm-engine-macros` へ更新。
- Rust import path を `llm_engine` / `llm_engine_macros` へ更新。
- turn-engine API を rename。
- `Worker``Engine`
- `WorkerConfig``EngineConfig`
- `WorkerError``EngineError`
- `WorkerResult``EngineResult`
- `WorkerState``EngineState`
- `RunOutput``EngineRunOutput`
- `pod` 側の engine 保持 API / error / alert source 等も rename fallout として更新。
- docs / tests / examples / Nix / `Cargo.lock` / `package.nix` hash を更新。
- 旧 crate directory は削除済みで、互換 alias は追加していない。
Commit:
- `292fc4ea refactor: rename llm worker crate to engine`
Validation:
- `cargo test -p llm-engine`: success
- `cargo test -p pod`: success
- 既知 caveat の prompt guidance snapshot failure は今回発生しなかった。
- `cargo check -p yoi`: success
- `git diff --check`: success
- `nix build .#yoi --no-link`: success
Grep evidence:
- `.yoi/tickets/**``docs/report/**` を除外した active tree で以下の旧 active references は 0 件。
- `llm-worker`
- `llm_worker`
- `llm-worker-macros`
- `llm_worker_macros`
- `crates/llm-engine` / `crates/llm-engine-macros` 内の旧 public Worker API 名も 0 件。
- `\bWorker\b`
- `WorkerConfig`
- `WorkerError`
- `WorkerResult`
- `WorkerState`
- historical `.yoi/tickets` / `docs/report` 内には旧語が残る。count: 786。これは Ticket 本文・過去 report 類の履歴文脈として意図的に残している。
Residual risks / notes:
- 互換 alias は入れていないため、外部未追跡コードが `llm-worker` / `llm_worker::Worker` を直接参照している場合は破壊的変更になる。ただし Ticket の binding invariant 通り。
- merge / Ticket close / worktree cleanup は未実施。
---
<!-- event: review author: yoi-reviewer-00001KVZD10ED-llm-engine at: 2026-06-25T13:54:15Z status: approve -->
## Review: approve
Review result: approve
確認結果、Ticket `00001KVZD10ED` の IntentPacket / acceptance criteria に対してブロッカーは見つかりませんでした。
Read-only 確認:
- 対象 worktree / branch / commit:
- `work/00001KVZD10ED-llm-engine-rename`
- HEAD `292fc4ea`
- base `22598710` は ancestor。
- Ticket 記録:
- `thread.md` の IntentPacket / acceptance criteria / reviewer focus を確認。
- 要件は `llm-worker``llm-engine`、public turn-engine API を `Worker` 系から `Engine` 系へ rename、互換 alias なし、責務移動なし。
- crate / directory:
- `crates/llm-engine`, `crates/llm-engine-macros` が存在。
- `crates/llm-worker`, `crates/llm-worker-macros` は存在しない。
- Cargo / Nix:
- root `Cargo.toml` の members/default-members/workspace deps が `llm-engine` / `llm-engine-macros`
- `crates/pod/Cargo.toml` 等の依存も `llm-engine`
- `Cargo.lock` は旧 package 名から新 package 名へ置換済み。
- `package.nix``cargoHash` 更新を確認。
- public API:
- `crates/llm-engine/src/lib.rs``Engine`, `EngineConfig`, `EngineError`, `EngineResult`, `EngineRunOutput` を export。
- `WorkerConfig` / `WorkerError` / `WorkerResult` / `WorkerState` / bare `RunOutput` は active tree で検出されず。
- `llm-engine` / `llm-engine-macros` 内に `pub type Worker` 等の互換 alias は見つからず。
- stale reference:
- `.yoi/tickets/**``docs/report/**` を除いた tracked active tree で `llm-worker`, `llm_worker`, `llm-worker-macros`, `llm_worker_macros` は検出されず。
- behavior / responsibility risk:
- `crates/llm-worker/src/worker.rs``crates/llm-engine/src/engine.rs` は正規化比較で import order / formatting 程度の差分に収まっていることを確認。
- `crates/llm-engine/README.md` に Pod names / sockets / process lifecycle / scope delegation / durable Pod state を持たない境界が明記されており、Runtime/Worker identity や socket/session authority の責務移動は見当たらない。
- whitespace:
- `git diff --check 22598710..HEAD`: success。
未再実行:
- `cargo test -p llm-engine`
- `cargo test -p pod`
- `cargo check -p yoi`
- `nix build .#yoi --no-link`
上記は reviewer の read-only/no-write 条件を優先して再実行していない。coder 報告では成功済み。
Non-blocking note:
- `pod` 側には local variable や既存 runtime/manifest 文脈としての `worker` 語が残っているが、今回の acceptance 対象である old crate/import/API 名や `llm_engine::Worker` 互換 alias ではないため問題なし。
---
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T13:57:16Z -->
## Implementation report
Integration outcome:
- Coder `yoi-coder-00001KVZD10ED-llm-engine` が implementation branch `work/00001KVZD10ED-llm-engine-rename` に実装を commit した。
- implementation commit: `292fc4ea refactor: rename llm worker crate to engine`
- Reviewer `yoi-reviewer-00001KVZD10ED-llm-engine` は read-only review で `approve`。old crate directories removal、Cargo/Nix consistency、public Engine API、old active references なし、compatibility alias なし、behavior/responsibility movement なしを確認した。
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVZD10ED-llm-engine-rename` を merge 済み。
- merge commit: `254ecccb merge: 00001KVZD10ED llm engine rename`
Implemented behavior:
- `crates/llm-worker` -> `crates/llm-engine`
- `crates/llm-worker-macros` -> `crates/llm-engine-macros`
- Cargo package/dependency/import path を `llm-engine` / `llm_engine`, `llm-engine-macros` / `llm_engine_macros` に更新。
- Public turn-engine API を Engine 系へ rename。
- `Worker` -> `Engine`
- `WorkerConfig` -> `EngineConfig`
- `WorkerError` -> `EngineError`
- `WorkerResult` -> `EngineResult`
- `WorkerState` -> `EngineState`
- `RunOutput` -> `EngineRunOutput`
- `pod`, `manifest`, docs, examples, tests, Nix, `Cargo.lock`, `package.nix` hash を更新。
- old crate directories は削除済み。compatibility alias は追加していない。
Validation in Orchestrator worktree:
- `cargo test -p llm-engine`: success
- `cargo test -p pod`: success
- `cargo check -p yoi`: success
- active old reference grep excluding `.yoi/tickets/**` and `docs/report/**`: success, none found for:
- `llm-worker`
- `llm_worker`
- `llm-worker-macros`
- `llm_worker_macros`
- `crates/llm-engine` / `crates/llm-engine-macros` old public Worker API grep: success, none found for:
- `\bWorker\b`
- `WorkerConfig`
- `WorkerError`
- `WorkerResult`
- `WorkerState`
- `git diff --check`: success
- `nix build .#yoi --no-link`: success
Notes:
- Historical `.yoi/tickets/**` and `docs/report/**` references to old names remain as durable history/report context and are not active API/docs guidance.
- Unlike recent Plugin full `cargo test -p pod` runs, this validation passed `cargo test -p pod` fully.
Next action:
- Mark Ticket done after this integration/validation evidence.
- Then stop related child Pods and remove only the child implementation worktree/branch.
---
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T13:57:29Z from: inprogress to: done reason: merged_validated field: state -->
## State changed
Implementation is merged into the orchestration branch and validated.
Evidence:
- merge commit: `254ecccb merge: 00001KVZD10ED llm engine rename`
- reviewer result: approve
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
- `cargo test -p llm-engine`
- `cargo test -p pod`
- `cargo check -p yoi`
- active old reference grep excluding `.yoi/tickets/**` and `docs/report/**`
- old public Worker API grep in `crates/llm-engine` / `crates/llm-engine-macros`
- `git diff --check`
- `nix build .#yoi --no-link`
Closure is not performed here; this state records implementation completion after merge/validation.
---
<!-- event: state_changed author: hare at: 2026-06-25T14:13:52Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-25T14:13:52Z status: closed -->
## 完了
Implemented, reviewed, marked done, and merged into develop.
---

View File

@ -0,0 +1,13 @@
{
"version": 1,
"relations": [
{
"ticket_id": "00001KVZG9BMS",
"kind": "depends_on",
"target": "00001KVZD10ED",
"note": "Rename llm-worker to llm-engine first so Worker naming is available for the former pod crate.",
"author": "yoi ticket",
"at": "2026-06-25T13:43:31Z"
}
]
}

View File

@ -0,0 +1,90 @@
---
title: 'pod crateをworker crateへ改名する'
state: 'queued'
created_at: '2026-06-25T13:42:37Z'
updated_at: '2026-06-25T14:13:35Z'
assignee: null
queued_by: 'workspace-panel'
queued_at: '2026-06-25T14:13:35Z'
---
## 背景
Yoi は旧 `Pod` 相当の実行単位を今後 `Worker` として扱い、`Runtime` が複数 Worker を保持・操作する構造へ移行する。既存の `crates/pod` は、現在の `yoi pod` process / Unix socket / session persistence / tool registry / workflow / `llm-engine` turn execution host を束ねる実行単位の本体であり、実質的には「single Worker host」である。
`llm-worker``llm-engine` に改名して LLM turn engine から `Worker` 名を空ける。その後、`pod` crate を rewrite ではなく rename として `worker` crate に寄せる。大規模な責務移動はこの Ticket では行わず、名前と公開 API を今後の Runtime/Worker model に合わせる。`pod-store` / `pod-registry` 相当の責務は、この rename Ticket では直接扱わず、後続の `worker-runtime` 作成時に Runtime 内部 persistence / allocation module として吸収する。
## 目的
- 旧 `Pod` 実行単位を `Worker` として命名し直す。
- `worker-runtime` 導入前に、`Worker` が実行単位、`llm-engine` が turn engine、`Runtime` が Worker を動かす環境、という命名を揃える。
- 既存 `pod` crate の実装は基本 rewrite せず、rename / import path / type name / docs / tests を整理する。
- 後続の `worker-runtime` crate が `worker` crate を single Worker host として扱える状態にする。
## 要件
### Crate / package rename
- `crates/pod``crates/worker` に rename する。
- Cargo package name を `pod` から `worker` に変更する。
- Rust import path を `pod` から `worker` に変更する。
- Workspace `Cargo.toml`、crate dependencies、tests、docs、Nix packaging references を更新する。
- 旧 crate name / import path の compatibility alias は作らない。
### Type / module rename
- Public type / module / doc comment の `Pod` terminology を Worker terminology に更新する。
- `Pod` -> `Worker`
- `PodConfig` / `PodController` / `PodState` / `PodEvent` 相当があれば Worker terminology に寄せる。
- `pod_name``worker_name` または `worker_id` 相当へ寄せる。
- ただし、既存 socket protocol / session file / on-disk compatibility の詳細に残る `pod` 文字列については、後続 Runtime 移行で消すべき legacy detail として明示的に扱う。
- `llm-engine` 内部の `Engine` と、実行単位としての `worker::Worker` が名前上衝突しないようにする。
### CLI / process surface
- 現在の `yoi pod` CLI surface をどう rename するかを実装時に決める。
- 後方互換は設けなくてよいが、dogfooding runtime / spawn path / scripts / tests への影響を明示的に処理する。
- Low-level process launch path は、後続の `worker-runtime` では compatibility / process-backed Worker host として扱えるようにする。
### Responsibility boundary
- この Ticket は rename が主目的であり、大規模な responsibility rewrite はしない。
- `worker` crate は当面 single Worker host として以下を保持する。
- input handling
- `llm-engine` integration
- event emission
- session / transcript compatibility
- tool registry / workflow integration
- legacy socket compatibility
- Runtime に属する責務は後続 Ticket へ残す。
- 複数 Worker 管理
- embedded / networked Runtime API
- worker store / allocation integration
- remote runtime support
- `pod-store` / `pod-registry` の standalone rename は行わず、後続 `worker-runtime` 作成時に直接内部 module へ吸収する。
## Non-goals
- `worker-runtime` crate の実装。
- Backend internal Companion Web Console の実装。
- `pod-store` / `pod-registry``worker-store` / `worker-registry` への中間 rename。
- Runtime 内部 persistence / allocation module の完成。
- Existing process/socket/session model の完全削除。
- `llm-engine` rename の実装。
- Provider request / tool-call loop / history semantics の変更。
## 受け入れ条件
- `crates/worker` が存在し、`crates/pod` は残っていない。
- Cargo package name and Rust import path are `worker`.
- Public execution-unit type is `worker::Worker`, not `pod::Pod`.
- Repository-wide active references to `pod` crate / `pod::` import / `crates/pod` are gone except intentionally documented legacy context.
- Dependent crates compile against `worker` crate.
- `llm-engine::Engine``worker::Worker` の責務境界が code/docs/comments 上で明確になっている。
- Existing process/socket/session compatibility path still works or is explicitly updated without old-name alias.
- `pod-store` / `pod-registry` are not renamed to standalone `worker-store` / `worker-registry` in this Ticket.
- `cargo test -p worker` passes.
- `cargo test -p yoi` or relevant CLI tests covering process launch pass.
- `cargo check -p yoi` passes.
- `git diff --check` passes.
- `nix build .#yoi --no-link` passes.

View File

@ -0,0 +1,33 @@
<!-- event: create author: "yoi ticket" at: 2026-06-25T13:42:37Z -->
## 作成
LocalTicketBackend によって作成されました。
---
<!-- event: intake_summary author: hare at: 2026-06-25T14:08:22Z -->
## Intake summary
Marked ready by `yoi ticket state`.
---
<!-- event: state_changed author: "yoi ticket" at: 2026-06-25T14:08:22Z from: planning to: ready reason: cli_state field: state -->
## State changed
Marked ready by `yoi ticket state`.
---
<!-- event: state_changed author: workspace-panel at: 2026-06-25T14:13:35Z from: ready to: queued reason: queued field: state -->
## State changed
Ticket を `workspace-panel` が queued にしました。
---

22
Cargo.lock generated
View File

@ -2102,7 +2102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]] [[package]]
name = "llm-worker" name = "llm-engine"
version = "0.2.1" version = "0.2.1"
dependencies = [ dependencies = [
"async-trait", "async-trait",
@ -2110,7 +2110,7 @@ dependencies = [
"dotenv", "dotenv",
"eventsource-stream", "eventsource-stream",
"futures", "futures",
"llm-worker-macros", "llm-engine-macros",
"reqwest", "reqwest",
"schemars", "schemars",
"serde", "serde",
@ -2127,7 +2127,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "llm-worker-macros" name = "llm-engine-macros"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
@ -2242,7 +2242,7 @@ name = "manifest"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"llm-worker", "llm-engine",
"mlua", "mlua",
"protocol", "protocol",
"secrets", "secrets",
@ -2373,7 +2373,7 @@ dependencies = [
"chrono", "chrono",
"libc", "libc",
"lint-common", "lint-common",
"llm-worker", "llm-engine",
"manifest", "manifest",
"schemars", "schemars",
"serde", "serde",
@ -2888,7 +2888,7 @@ dependencies = [
"futures-util", "futures-util",
"include_dir", "include_dir",
"libc", "libc",
"llm-worker", "llm-engine",
"manifest", "manifest",
"mcp", "mcp",
"memory", "memory",
@ -3045,7 +3045,7 @@ dependencies = [
"async-trait", "async-trait",
"base64", "base64",
"chrono", "chrono",
"llm-worker", "llm-engine",
"manifest", "manifest",
"reqwest", "reqwest",
"secrets", "secrets",
@ -3901,7 +3901,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"futures", "futures",
"llm-worker", "llm-engine",
"protocol", "protocol",
"serde", "serde",
"serde_json", "serde_json",
@ -4352,7 +4352,7 @@ dependencies = [
"async-trait", "async-trait",
"chrono", "chrono",
"fs4", "fs4",
"llm-worker", "llm-engine",
"project-record", "project-record",
"schemars", "schemars",
"serde", "serde",
@ -4535,7 +4535,7 @@ dependencies = [
"grep-searcher", "grep-searcher",
"html5ever", "html5ever",
"ignore", "ignore",
"llm-worker", "llm-engine",
"manifest", "manifest",
"markup5ever_rcdom", "markup5ever_rcdom",
"pdf-extract", "pdf-extract",
@ -4715,7 +4715,7 @@ dependencies = [
"base64", "base64",
"client", "client",
"crossterm 0.28.1", "crossterm 0.28.1",
"llm-worker", "llm-engine",
"manifest", "manifest",
"minijinja", "minijinja",
"pod-registry", "pod-registry",

View File

@ -2,8 +2,8 @@
resolver = "2" resolver = "2"
members = [ members = [
"crates/client", "crates/client",
"crates/llm-worker", "crates/llm-engine",
"crates/llm-worker-macros", "crates/llm-engine-macros",
"crates/session-store", "crates/session-store",
"crates/secrets", "crates/secrets",
"crates/manifest", "crates/manifest",
@ -29,8 +29,8 @@ members = [
] ]
default-members = [ default-members = [
"crates/client", "crates/client",
"crates/llm-worker", "crates/llm-engine",
"crates/llm-worker-macros", "crates/llm-engine-macros",
"crates/session-store", "crates/session-store",
"crates/secrets", "crates/secrets",
"crates/manifest", "crates/manifest",
@ -61,8 +61,8 @@ license = "MIT"
[workspace.dependencies] [workspace.dependencies]
# Internal crates # Internal crates
client = { path = "crates/client" } client = { path = "crates/client" }
llm-worker = { path = "crates/llm-worker", version = "0.2" } llm-engine = { path = "crates/llm-engine", version = "0.2" }
llm-worker-macros = { path = "crates/llm-worker-macros", version = "0.2" } llm-engine-macros = { path = "crates/llm-engine-macros", version = "0.2" }
manifest = { path = "crates/manifest" } manifest = { path = "crates/manifest" }
mcp = { path = "crates/mcp" } mcp = { path = "crates/mcp" }
lint-common = { path = "crates/lint-common" } lint-common = { path = "crates/lint-common" }

View File

@ -18,7 +18,7 @@ Does not own:
- product command names (`yoi`) - product command names (`yoi`)
- Pod state authority (`pod`, `pod-store`, `session-store`) - Pod state authority (`pod`, `pod-store`, `session-store`)
- UI rendering (`tui`) - UI rendering (`tui`)
- Worker turn semantics (`llm-worker`) - Engine turn semantics (`llm-engine`)
## Design notes ## Design notes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "llm-worker-macros" name = "llm-engine-macros"
description = "llm-worker's proc macros" description = "llm-engine's proc macros"
version = "0.2.0" version = "0.2.0"
edition.workspace = true edition.workspace = true
license.workspace = true license.workspace = true

View File

@ -1,8 +1,8 @@
# llm-worker-macros # llm-engine-macros
## Role ## Role
`llm-worker-macros` provides procedural macros for declaring Rust methods as LLM-callable tools. `llm-engine-macros` provides procedural macros for declaring Rust methods as LLM-callable tools.
## Boundaries ## Boundaries

View File

@ -1,4 +1,4 @@
//! llm-worker-macros - Procedural macros for Tool generation //! llm-engine-macros - Procedural macros for Tool generation
//! //!
//! Provides `#[tool_registry]` and `#[tool]` macros to //! Provides `#[tool_registry]` and `#[tool]` macros to
//! automatically generate `Tool` trait implementations from user-defined methods. //! automatically generate `Tool` trait implementations from user-defined methods.
@ -215,7 +215,7 @@ fn generate_tool_impl(self_ty: &Type, method: &syn::ImplItemFn) -> proc_macro2::
quote! { quote! {
match result { match result {
Ok(val) => Ok(format!("{:?}", val).into()), Ok(val) => Ok(format!("{:?}", val).into()),
Err(e) => Err(::llm_worker::tool::ToolError::ExecutionFailed(format!("{}", e))), Err(e) => Err(::llm_engine::tool::ToolError::ExecutionFailed(format!("{}", e))),
} }
} }
} else { } else {
@ -252,7 +252,7 @@ fn generate_tool_impl(self_ty: &Type, method: &syn::ImplItemFn) -> proc_macro2::
} else { } else {
quote! { quote! {
let args: #args_struct_name = serde_json::from_str(input_json) let args: #args_struct_name = serde_json::from_str(input_json)
.map_err(|e| ::llm_worker::tool::ToolError::InvalidArgument(e.to_string()))?; .map_err(|e| ::llm_engine::tool::ToolError::InvalidArgument(e.to_string()))?;
let result = #method_call #awaiter; let result = #method_call #awaiter;
#result_handling #result_handling
@ -268,23 +268,23 @@ fn generate_tool_impl(self_ty: &Type, method: &syn::ImplItemFn) -> proc_macro2::
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ::llm_worker::tool::Tool for #tool_struct_name { impl ::llm_engine::tool::Tool for #tool_struct_name {
async fn execute(&self, input_json: &str, ctx: ::llm_worker::tool::ToolExecutionContext) -> Result<::llm_worker::tool::ToolOutput, ::llm_worker::tool::ToolError> { async fn execute(&self, input_json: &str, ctx: ::llm_engine::tool::ToolExecutionContext) -> Result<::llm_engine::tool::ToolOutput, ::llm_engine::tool::ToolError> {
let _ = &ctx; let _ = &ctx;
#execute_body #execute_body
} }
} }
impl #self_ty { impl #self_ty {
/// Get ToolDefinition (for registering with Worker) /// Get ToolDefinition (for registering with Engine)
pub fn #definition_name(&self) -> ::llm_worker::tool::ToolDefinition { pub fn #definition_name(&self) -> ::llm_engine::tool::ToolDefinition {
let ctx = self.clone(); let ctx = self.clone();
::std::sync::Arc::new(move || { ::std::sync::Arc::new(move || {
let schema = schemars::schema_for!(#args_struct_name); let schema = schemars::schema_for!(#args_struct_name);
let meta = ::llm_worker::tool::ToolMeta::new(#tool_name) let meta = ::llm_engine::tool::ToolMeta::new(#tool_name)
.description(#description) .description(#description)
.input_schema(serde_json::to_value(schema).unwrap_or(serde_json::json!({}))); .input_schema(serde_json::to_value(schema).unwrap_or(serde_json::json!({})));
let tool: ::std::sync::Arc<dyn ::llm_worker::tool::Tool> = let tool: ::std::sync::Arc<dyn ::llm_engine::tool::Tool> =
::std::sync::Arc::new(#tool_struct_name { ctx: ctx.clone() }); ::std::sync::Arc::new(#tool_struct_name { ctx: ctx.clone() });
(meta, tool) (meta, tool)
}) })

View File

@ -1,5 +1,5 @@
[package] [package]
name = "llm-worker" name = "llm-engine"
description = "A library for building autonomous LLM-powered systems" description = "A library for building autonomous LLM-powered systems"
version = "0.2.1" version = "0.2.1"
edition.workspace = true edition.workspace = true
@ -17,7 +17,7 @@ tokio-util = "0.7"
reqwest = { version = "0.13", default-features = false, features = ["stream", "json", "native-tls", "http2"] } reqwest = { version = "0.13", default-features = false, features = ["stream", "json", "native-tls", "http2"] }
eventsource-stream = "0.2" eventsource-stream = "0.2"
zstd = "0.13" zstd = "0.13"
llm-worker-macros = { workspace = true } llm-engine-macros = { workspace = true }
[dev-dependencies] [dev-dependencies]
clap = { version = "4.5", features = ["derive", "env"] } clap = { version = "4.5", features = ["derive", "env"] }

View File

@ -1,17 +1,17 @@
# llm-worker # llm-engine
## Role ## Role
`llm-worker` owns provider-independent model turn orchestration over committed history, tools, callbacks, retries, continuation, pruning, and compaction boundaries. `llm-engine` owns provider-independent model turn orchestration over committed history, tools, callbacks, retries, continuation, pruning, and compaction boundaries.
## Boundaries ## Boundaries
Owns: Owns:
- Worker history mutation and append contracts - Engine history mutation and append contracts
- tool-call loop semantics - tool-call loop semantics
- pre-stream retry and stream-started continuation policy - pre-stream retry and stream-started continuation policy
- pruning/compaction coordination from the Worker perspective - pruning/compaction coordination from the Engine perspective
- provider-neutral events/callbacks/interceptors - provider-neutral events/callbacks/interceptors
Does not own: Does not own:
@ -23,7 +23,7 @@ Does not own:
## Design notes ## Design notes
The Worker is where turn lifecycle belongs because it sees history, in-flight usage, partial output, and tool-call state. It should not receive context-only volatile facts; model-affecting inputs must first be appended to history. The Engine is where turn lifecycle belongs because it sees history, in-flight usage, partial output, and tool-call state. It should not receive context-only volatile facts; model-affecting inputs must first be appended to history.
## See also ## See also

View File

@ -1,12 +1,12 @@
# llm-worker アーキテクチャ # llm-engine アーキテクチャ
## 概要 ## 概要
llm-workerは3層構成でLLMとのインタラクションを管理する。 llm-engineは3層構成でLLMとのインタラクションを管理する。
``` ```
┌─────────────────────────────────────────┐ ┌─────────────────────────────────────────┐
Worker (オーケストレーション) │ Engine (オーケストレーション) │
│ ターンループ / フック / ツール実行 │ │ ターンループ / フック / ツール実行 │
│ Type-state: Mutable ↔ CacheLocked │ │ Type-state: Mutable ↔ CacheLocked │
└───────────┬─────────────────────────────┘ └───────────┬─────────────────────────────┘
@ -27,7 +27,7 @@ llm-workerは3層構成でLLMとのインタラクションを管理する。
| モジュール | 責務 | 要件 | | モジュール | 責務 | 要件 |
|---|---|---| |---|---|---|
| `worker` | ターンループ、フック統合、ツール実行、Pause/Resume | R1, R4 | | `engine` | ターンループ、フック統合、ツール実行、Pause/Resume | R1, R4 |
| `state` | Type-state (Mutable/CacheLocked) | R2 | | `state` | Type-state (Mutable/CacheLocked) | R2 |
| `hook` | Hook trait、10フックポイント | R3, R4 | | `hook` | Hook trait、10フックポイント | R3, R4 |
| `tool` / `tool_server` | ツール定義・登録・実行 | R3 | | `tool` / `tool_server` | ツール定義・登録・実行 | R3 |
@ -42,7 +42,7 @@ llm-workerは3層構成でLLMとのインタラクションを管理する。
### リクエスト(送信) ### リクエスト(送信)
``` ```
Worker.history (Vec<Item>) Engine.history (Vec<Item>)
→ build_request() → Request { items, tools, config } → build_request() → Request { items, tools, config }
→ Scheme.build_request() → プロバイダ固有JSON → Scheme.build_request() → プロバイダ固有JSON
→ Provider.stream() → HTTP POST → Provider.stream() → HTTP POST
@ -55,7 +55,7 @@ HTTP SSE bytes
→ Scheme.parse_event() → Event (統一型) → Scheme.parse_event() → Event (統一型)
→ Timeline.dispatch() → Handler.on_event() → Timeline.dispatch() → Handler.on_event()
→ TextBlockCollector / ToolCallCollector → TextBlockCollector / ToolCallCollector
Worker: 履歴に追加、ツール実行判定 Engine: 履歴に追加、ツール実行判定
``` ```
## 内部型 ## 内部型

View File

@ -1,4 +1,4 @@
# llm-worker 要件 # llm-engine 要件
## 前提 ## 前提
@ -12,23 +12,23 @@ c. ツール・フックの基本的なスキーマ自動化を提供する
メッセージの送信と生成のResume、一時停止/再開。 メッセージの送信と生成のResume、一時停止/再開。
- `Worker::run()` でターンを開始 - `Engine::run()` でターンを開始
- フックから `Pause` を返してターンを一時停止 - フックから `Pause` を返してターンを一時停止
- `Worker::resume()` でユーザーメッセージを追加せず継続 - `Engine::resume()` でユーザーメッセージを追加せず継続
- AIは中断を認識せず、継続として処理する - AIは中断を認識せず、継続として処理する
**実装**: `worker.rs` — `resume()`, `get_pending_tool_calls()`, `WorkerResult::Paused` **実装**: `engine.rs` — `resume()`, `get_pending_tool_calls()`, `EngineResult::Paused`
### R2: 暗黙的KVキャッシュ保証 ### R2: 暗黙的KVキャッシュ保証
キャッシュを破壊しうる操作を明示的にブロックせずとも、いつの間にかキャッシュ破壊してた状態にはしたくない。 キャッシュを破壊しうる操作を明示的にブロックせずとも、いつの間にかキャッシュ破壊してた状態にはしたくない。
- Type-stateパターン`Mutable` / `CacheLocked`)でコンパイル時に保証 - Type-stateパターン`Mutable` / `CacheLocked`)でコンパイル時に保証
- `Worker::lock()` でCacheLocked状態に遷移 - `Engine::lock()` でCacheLocked状態に遷移
- CacheLocked状態ではシステムプロンプトや履歴の変更APIが型レベルで利用不可 - CacheLocked状態ではシステムプロンプトや履歴の変更APIが型レベルで利用不可
- `locked_prefix_len` でプレフィックスの不変性を追跡 - `locked_prefix_len` でプレフィックスの不変性を追跡
**実装**: `state.rs` (sealed trait), `worker.rs` (state-specific impl blocks) **実装**: `state.rs` (sealed trait), `engine.rs` (state-specific impl blocks)
### R3: ツール・フックスキーマ自動化 ### R3: ツール・フックスキーマ自動化
@ -36,13 +36,13 @@ c. ツール・フックの基本的なスキーマ自動化を提供する
- `#[tool_registry]` マクロでツールサーバーを自動構成 - `#[tool_registry]` マクロでツールサーバーを自動構成
- `Hook` traitで10種のフックポイント - `Hook` traitで10種のフックポイント
**実装**: `llm-worker-macros/`, `tool.rs`, `tool_server.rs`, `hook.rs` **実装**: `llm-engine-macros/`, `tool.rs`, `tool_server.rs`, `hook.rs`
### R4: フックは上層の関心事 ### R4: フックは上層の関心事
フックはLLMクライアント層ではなく、Worker(オーケストレーション)層に配置する。 フックはLLMクライアント層ではなく、Engine(オーケストレーション)層に配置する。
- LLMクライアント (`llm_client/`) はストリーミングとプロトコルのみ - LLMクライアント (`llm_client/`) はストリーミングとプロトコルのみ
- Worker層でフック実行、ツール統合、Pause/Resume制御 - Engine層でフック実行、ツール統合、Pause/Resume制御
**実装**: `worker.rs` (hook integration), `hook.rs` (trait definitions) **実装**: `engine.rs` (hook integration), `hook.rs` (trait definitions)

View File

@ -1,10 +1,10 @@
//! Worker cancellation demo //! Engine cancellation demo
//! //!
//! Example of cancelling from another thread during streaming //! Example of cancelling from another thread during streaming
use llm_worker::llm_client::scheme::{Scheme, anthropic::AnthropicScheme}; use llm_engine::llm_client::scheme::{Scheme, anthropic::AnthropicScheme};
use llm_worker::llm_client::transport::{HttpTransport, ResolvedAuth}; use llm_engine::llm_client::transport::{HttpTransport, ResolvedAuth};
use llm_worker::{Worker, WorkerResult}; use llm_engine::{Engine, EngineResult};
use std::time::Duration; use std::time::Duration;
#[tokio::main] #[tokio::main]
@ -28,29 +28,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cap = scheme.default_capability(); let cap = scheme.default_capability();
let base_url = scheme.default_base_url().to_string(); let base_url = scheme.default_base_url().to_string();
let client = HttpTransport::new(scheme, model, base_url, ResolvedAuth::ApiKey(api_key), cap); let client = HttpTransport::new(scheme, model, base_url, ResolvedAuth::ApiKey(api_key), cap);
let worker = Worker::new(client); let engine = Engine::new(client);
println!("🚀 Starting Worker..."); println!("🚀 Starting Engine...");
println!("💡 Will cancel after 2 seconds\n"); println!("💡 Will cancel after 2 seconds\n");
// Get cancel sender before run (Mutable state) // Get cancel sender before run (Mutable state)
let cancel_tx = worker.cancel_sender(); let cancel_tx = engine.cancel_sender();
// Task: Cancel after 2 seconds // Task: Cancel after 2 seconds
tokio::spawn(async move { tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(2)).await; tokio::time::sleep(Duration::from_secs(2)).await;
println!("\n🛑 Cancelling worker..."); println!("\n🛑 Cancelling engine...");
let _ = cancel_tx.send(()).await; let _ = cancel_tx.send(()).await;
}); });
println!("📡 Sending request to LLM..."); println!("📡 Sending request to LLM...");
match worker.run("Tell me a very long story about a brave knight. Make it as detailed as possible with many paragraphs.").await { match engine.run("Tell me a very long story about a brave knight. Make it as detailed as possible with many paragraphs.").await {
Ok(out) => match out.result { Ok(out) => match out.result {
WorkerResult::Finished => println!("✅ Task completed normally"), EngineResult::Finished => println!("✅ Task completed normally"),
WorkerResult::Paused => println!("⏸️ Task paused"), EngineResult::Paused => println!("⏸️ Task paused"),
WorkerResult::LimitReached => println!("🔒 Turn limit reached"), EngineResult::LimitReached => println!("🔒 Turn limit reached"),
WorkerResult::Yielded => println!("↩️ Task yielded"), EngineResult::Yielded => println!("↩️ Task yielded"),
}, },
Err(e) => { Err(e) => {
println!("❌ Task error: {}", e); println!("❌ Task error: {}", e);

View File

@ -1,4 +1,4 @@
//! Interactive CLI client using Worker //! Interactive CLI client using Engine
//! //!
//! A CLI application for interacting with multiple LLM providers (Anthropic, Gemini, OpenAI, Ollama). //! A CLI application for interacting with multiple LLM providers (Anthropic, Gemini, OpenAI, Ollama).
//! Demonstrates tool registration and execution, and streaming response display. //! Demonstrates tool registration and execution, and streaming response display.
@ -12,22 +12,22 @@
//! echo "OPENAI_API_KEY=your-api-key" >> .env //! echo "OPENAI_API_KEY=your-api-key" >> .env
//! //!
//! # Anthropic (default) //! # Anthropic (default)
//! cargo run --example worker_cli //! cargo run --example engine_cli
//! //!
//! # Gemini //! # Gemini
//! cargo run --example worker_cli -- --provider gemini //! cargo run --example engine_cli -- --provider gemini
//! //!
//! # OpenAI //! # OpenAI
//! cargo run --example worker_cli -- --provider openai --model gpt-4o //! cargo run --example engine_cli -- --provider openai --model gpt-4o
//! //!
//! # Ollama (local) //! # Ollama (local)
//! cargo run --example worker_cli -- --provider ollama --model llama3.2 //! cargo run --example engine_cli -- --provider ollama --model llama3.2
//! //!
//! # With options //! # With options
//! cargo run --example worker_cli -- --provider anthropic --model claude-3-haiku-20240307 --system "You are a helpful assistant." //! cargo run --example engine_cli -- --provider anthropic --model claude-3-haiku-20240307 --system "You are a helpful assistant."
//! //!
//! # Show help //! # Show help
//! cargo run --example worker_cli -- --help //! cargo run --example engine_cli -- --help
//! ``` //! ```
use std::collections::HashMap; use std::collections::HashMap;
@ -39,8 +39,8 @@ use tracing::info;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use llm_worker::{ use llm_engine::{
Worker, Engine,
interceptor::{Interceptor, PostToolAction, ToolResultInfo}, interceptor::{Interceptor, PostToolAction, ToolResultInfo},
llm_client::{ llm_client::{
LlmClient, LlmClient,
@ -52,7 +52,7 @@ use llm_worker::{
}, },
timeline::{Handler, TextBlockEvent, TextBlockKind, ToolUseBlockEvent, ToolUseBlockKind}, timeline::{Handler, TextBlockEvent, TextBlockKind, ToolUseBlockEvent, ToolUseBlockKind},
}; };
use llm_worker_macros::tool_registry; use llm_engine_macros::tool_registry;
// Required imports for macro expansion // Required imports for macro expansion
use schemars; use schemars;
@ -114,8 +114,8 @@ impl Provider {
/// Interactive CLI client supporting multiple LLM providers /// Interactive CLI client supporting multiple LLM providers
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(name = "worker-cli")] #[command(name = "engine-cli")]
#[command(about = "Interactive CLI client for multiple LLM providers using Worker")] #[command(about = "Interactive CLI client for multiple LLM providers using Engine")]
#[command(version)] #[command(version)]
struct Args { struct Args {
/// Provider to use /// Provider to use
@ -393,7 +393,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
// Initialize logging // Initialize logging
// Use RUST_LOG=debug cargo run --example worker_cli ... for detailed logs // Use RUST_LOG=debug cargo run --example engine_cli ... for detailed logs
// Default is warn level, can be overridden with RUST_LOG environment variable // Default is warn level, can be overridden with RUST_LOG environment variable
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn")); let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));
@ -408,7 +408,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
info!( info!(
provider = ?args.provider, provider = ?args.provider,
model = ?args.model, model = ?args.model,
"Starting worker CLI" "Starting engine CLI"
); );
// Interactive mode or one-shot mode // Interactive mode or one-shot mode
@ -421,7 +421,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.unwrap_or_else(|| args.provider.default_model().to_string()); .unwrap_or_else(|| args.provider.default_model().to_string());
if is_interactive { if is_interactive {
let title = format!("Worker CLI - {}", args.provider.display_name()); let title = format!("Engine CLI - {}", args.provider.display_name());
let border_len = title.len() + 6; let border_len = title.len() + 6;
println!("{}", "".repeat(border_len)); println!("{}", "".repeat(border_len));
println!("{}", title); println!("{}", title);
@ -453,34 +453,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
}; };
// Create Worker // Create Engine
let mut worker = Worker::new(client); let mut engine = Engine::new(client);
let tool_call_names = Arc::new(Mutex::new(HashMap::new())); let tool_call_names = Arc::new(Mutex::new(HashMap::new()));
// Set system prompt // Set system prompt
if let Some(ref system_prompt) = args.system { if let Some(ref system_prompt) = args.system {
worker.set_system_prompt(system_prompt); engine.set_system_prompt(system_prompt);
} }
// Register tools (unless --no-tools) // Register tools (unless --no-tools)
if !args.no_tools { if !args.no_tools {
let app = AppContext; let app = AppContext;
worker.register_tool(app.get_current_time_definition()); engine.register_tool(app.get_current_time_definition());
worker.register_tool(app.calculate_definition()); engine.register_tool(app.calculate_definition());
} }
// Register streaming display handlers // Register streaming display handlers
worker engine
.timeline_mut() .timeline_mut()
.on_text_block(StreamingPrinter::new()) .on_text_block(StreamingPrinter::new())
.on_tool_use_block(ToolCallPrinter::new(tool_call_names.clone())); .on_tool_use_block(ToolCallPrinter::new(tool_call_names.clone()));
worker.set_interceptor(ToolResultPrinterPolicy::new(tool_call_names)); engine.set_interceptor(ToolResultPrinterPolicy::new(tool_call_names));
// One-shot mode // One-shot mode
if let Some(prompt) = args.prompt { if let Some(prompt) = args.prompt {
match worker.run(&prompt).await { match engine.run(&prompt).await {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
eprintln!("\n❌ Error: {}", e); eprintln!("\n❌ Error: {}", e);
@ -504,8 +504,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
return Ok(()); return Ok(());
} }
let mut locked = match worker.run(first_input).await { let mut locked = match engine.run(first_input).await {
Ok(out) => out.worker, Ok(out) => out.engine,
Err(e) => { Err(e) => {
eprintln!("\n❌ Error: {}", e); eprintln!("\n❌ Error: {}", e);
return Ok(()); return Ok(());

View File

@ -20,10 +20,10 @@ mod recorder;
mod scenarios; mod scenarios;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use llm_worker::llm_client::scheme::{ use llm_engine::llm_client::scheme::{
Scheme, anthropic::AnthropicScheme, gemini::GeminiScheme, openai_chat::OpenAIScheme, Scheme, anthropic::AnthropicScheme, gemini::GeminiScheme, openai_chat::OpenAIScheme,
}; };
use llm_worker::llm_client::transport::{HttpTransport, ResolvedAuth}; use llm_engine::llm_client::transport::{HttpTransport, ResolvedAuth};
fn make_transport<S: Scheme>(scheme: S, model: &str, auth: ResolvedAuth) -> HttpTransport<S> { fn make_transport<S: Scheme>(scheme: S, model: &str, auth: ResolvedAuth) -> HttpTransport<S> {
let cap = scheme.default_capability(); let cap = scheme.default_capability();
@ -225,7 +225,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
println!("\n✅ Done!"); println!("\n✅ Done!");
println!("Run tests with: cargo test -p worker"); println!("Run tests with: cargo test -p engine");
Ok(()) Ok(())
} }

View File

@ -8,7 +8,7 @@ use std::path::Path;
use std::time::{Instant, SystemTime, UNIX_EPOCH}; use std::time::{Instant, SystemTime, UNIX_EPOCH};
use futures::StreamExt; use futures::StreamExt;
use llm_worker::llm_client::{LlmClient, Request}; use llm_engine::llm_client::{LlmClient, Request};
/// Recorded event /// Recorded event
#[derive(Debug, serde::Serialize, serde::Deserialize)] #[derive(Debug, serde::Serialize, serde::Deserialize)]
@ -79,7 +79,7 @@ pub async fn record_request<C: LlmClient>(
} }
// Save // Save
let fixtures_dir = Path::new("worker/tests/fixtures").join(subdir); let fixtures_dir = Path::new("engine/tests/fixtures").join(subdir);
fs::create_dir_all(&fixtures_dir)?; fs::create_dir_all(&fixtures_dir)?;
let filepath = fixtures_dir.join(format!("{}.jsonl", output_name)); let filepath = fixtures_dir.join(format!("{}.jsonl", output_name));

View File

@ -2,7 +2,7 @@
//! //!
//! Defines requests and output file names for each scenario //! Defines requests and output file names for each scenario
use llm_worker::llm_client::{Request, ToolDefinition}; use llm_engine::llm_client::{Request, ToolDefinition};
/// Test scenario /// Test scenario
pub struct TestScenario { pub struct TestScenario {

View File

@ -1,7 +1,7 @@
//! Closure-based event callback API //! Closure-based event callback API
//! //!
//! Provides a closure-based alternative to implementing `Handler<K>` directly. //! Provides a closure-based alternative to implementing `Handler<K>` directly.
//! Register callbacks on `Worker` via `on_text_block()`, `on_tool_use_block()`, //! Register callbacks on `Engine` via `on_text_block()`, `on_tool_use_block()`,
//! `on_usage()`, etc. //! `on_usage()`, etc.
use std::marker::PhantomData; use std::marker::PhantomData;
@ -18,13 +18,13 @@ use crate::tool::ToolCall;
/// Callback scope for a text block. /// Callback scope for a text block.
/// ///
/// Passed to the setup closure registered with `Worker::on_text_block()`. /// Passed to the setup closure registered with `Engine::on_text_block()`.
/// Register per-block callbacks via `on_delta()` and `on_stop()`. /// Register per-block callbacks via `on_delta()` and `on_stop()`.
/// ///
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.on_text_block(|block| { /// engine.on_text_block(|block| {
/// block.on_delta(|text| print!("{}", text)); /// block.on_delta(|text| print!("{}", text));
/// block.on_stop(|full_text| println!("\n--- {} chars ---", full_text.len())); /// block.on_stop(|full_text| println!("\n--- {} chars ---", full_text.len()));
/// }); /// });
@ -176,13 +176,13 @@ impl Handler<ThinkingBlockKind> for ClosureThinkingBlockHandler {
/// Callback scope for a tool use block. /// Callback scope for a tool use block.
/// ///
/// Passed to the setup closure registered with `Worker::on_tool_use_block()`. /// Passed to the setup closure registered with `Engine::on_tool_use_block()`.
/// The setup closure also receives `&ToolUseBlockStart` with `id` and `name`. /// The setup closure also receives `&ToolUseBlockStart` with `id` and `name`.
/// ///
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.on_tool_use_block(|start, block| { /// engine.on_tool_use_block(|start, block| {
/// println!("Tool: {} ({})", start.name, start.id); /// println!("Tool: {} ({})", start.name, start.id);
/// block.on_delta(|json| { /* streaming JSON fragment */ }); /// block.on_delta(|json| { /* streaming JSON fragment */ });
/// block.on_stop(|call| println!("Done: {}", call.name)); /// block.on_stop(|call| println!("Done: {}", call.name));

View File

@ -22,19 +22,19 @@ use crate::{
ToolDefinition, error::is_retryable, event::Event, retry::RetryPolicy, ToolDefinition, error::is_retryable, event::Event, retry::RetryPolicy,
transport::DEFAULT_FIRST_STREAM_EVENT_TIMEOUT, types::parse_tool_arguments, transport::DEFAULT_FIRST_STREAM_EVENT_TIMEOUT, types::parse_tool_arguments,
}, },
state::{Locked, Mutable, WorkerState}, state::{EngineState, Locked, Mutable},
timeline::event::{ErrorEvent, StatusEvent, UsageEvent}, timeline::event::{ErrorEvent, StatusEvent, UsageEvent},
timeline::{TextBlockCollector, ThinkingBlockCollector, Timeline, ToolCallCollector}, timeline::{TextBlockCollector, ThinkingBlockCollector, Timeline, ToolCallCollector},
tool::{ tool::{
ToolCall, ToolDefinition as WorkerToolDefinition, ToolError, ToolExecutionContext, ToolCall, ToolDefinition as EngineToolDefinition, ToolError, ToolExecutionContext,
ToolOutputLimits, ToolResult, truncate_content, ToolOutputLimits, ToolResult, truncate_content,
}, },
tool_server::{ToolServer, ToolServerHandle}, tool_server::{ToolServer, ToolServerHandle},
}; };
/// Worker errors /// Engine errors
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum WorkerError { pub enum EngineError {
/// Client error /// Client error
#[error("Client error: {0}")] #[error("Client error: {0}")]
Client(#[from] ClientError), Client(#[from] ClientError),
@ -60,17 +60,17 @@ pub enum ToolRegistryError {
DuplicateName(String), DuplicateName(String),
} }
/// Worker configuration /// Engine configuration
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct WorkerConfig { pub struct EngineConfig {
// Reserved for future extensions (currently empty) // Reserved for future extensions (currently empty)
_private: (), _private: (),
} }
/// Worker execution result (status) /// Engine execution result (status)
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum WorkerResult { pub enum EngineResult {
/// Completed (waiting for user input) /// Completed (waiting for user input)
Finished, Finished,
/// Paused (can be resumed) /// Paused (can be resumed)
@ -85,14 +85,14 @@ pub enum WorkerResult {
Yielded, Yielded,
} }
/// Result of [`Worker<C, Mutable>::run()`] / [`Worker<C, Mutable>::resume()`]. /// Result of [`Engine<C, Mutable>::run()`] / [`Engine<C, Mutable>::resume()`].
/// ///
/// Contains the `Locked` Worker (ready for subsequent runs) and the outcome. /// Contains the `Locked` Engine (ready for subsequent runs) and the outcome.
pub struct RunOutput<C: LlmClient> { pub struct EngineRunOutput<C: LlmClient> {
/// The Worker, now in Locked state. /// The Engine, now in Locked state.
pub worker: Worker<C, Locked>, pub engine: Engine<C, Locked>,
/// Outcome of the turn. /// Outcome of the turn.
pub result: WorkerResult, pub result: EngineResult,
} }
/// Internal: tool execution result /// Internal: tool execution result
@ -113,27 +113,27 @@ const MAX_STREAM_CONTINUATIONS: u32 = 3;
/// - [`Mutable`]: Initial state. System prompt, history, and tools can be freely edited. /// - [`Mutable`]: Initial state. System prompt, history, and tools can be freely edited.
/// - [`Locked`]: Cache-protected state. Prefix context is immutable; only `run()` / `resume()` are available. /// - [`Locked`]: Cache-protected state. Prefix context is immutable; only `run()` / `resume()` are available.
/// ///
/// Calling `run()` on a `Mutable` Worker consumes it and returns a /// Calling `run()` on a `Mutable` Engine consumes it and returns a
/// `Locked` Worker together with the result. This ensures the /// `Locked` Engine together with the result. This ensures the
/// cache prefix is fixed for optimal KV cache hit rate. /// cache prefix is fixed for optimal KV cache hit rate.
/// ///
/// ```ignore /// ```ignore
/// let mut worker = Worker::new(client) /// let mut engine = Engine::new(client)
/// .system_prompt("You are a helpful assistant."); /// .system_prompt("You are a helpful assistant.");
/// worker.register_tool(my_tool); /// engine.register_tool(my_tool);
/// ///
/// // Mutable::run() consumes self → RunOutput { worker: Locked, result } /// // Mutable::run() consumes self → EngineRunOutput { engine: Locked, result }
/// let out = worker.run("Hello").await?; /// let out = engine.run("Hello").await?;
/// let mut worker = out.worker; /// let mut engine = out.engine;
/// ///
/// // Locked::run() borrows &mut self /// // Locked::run() borrows &mut self
/// worker.run("Follow-up").await?; /// engine.run("Follow-up").await?;
/// ///
/// // To edit between turns, unlock back to Mutable /// // To edit between turns, unlock back to Mutable
/// let mut worker = worker.unlock(); /// let mut engine = engine.unlock();
/// worker.truncate_history(5); /// engine.truncate_history(5);
/// let out = worker.run("Continue").await?; /// let out = engine.run("Continue").await?;
/// let mut worker = out.worker; /// let mut engine = out.engine;
/// ``` /// ```
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct LlmRetryNotice { pub struct LlmRetryNotice {
@ -152,7 +152,7 @@ enum StreamCompletion {
Interrupted { reason: String }, Interrupted { reason: String },
} }
pub struct Worker<C: LlmClient, S: WorkerState = Mutable> { pub struct Engine<C: LlmClient, S: EngineState = Mutable> {
/// LLM client /// LLM client
client: C, client: C,
/// Retry policy for opening an LLM response stream. /// Retry policy for opening an LLM response stream.
@ -172,22 +172,22 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
interceptor: Box<dyn Interceptor>, interceptor: Box<dyn Interceptor>,
/// System prompt /// System prompt
system_prompt: Option<String>, system_prompt: Option<String>,
/// Item history (owned by Worker) /// Item history (owned by Engine)
history: Vec<Item>, history: Vec<Item>,
/// History length at lock time (only meaningful in Locked state) /// History length at lock time (only meaningful in Locked state)
locked_prefix_len: usize, locked_prefix_len: usize,
/// AgentTurn count. /// AgentTurn count.
/// ///
/// Once retry (`llm-worker-stream-continuation`) is implemented, an /// Once retry (`llm-engine-stream-continuation`) is implemented, an
/// AgentTurn collapses N retried `LlmCall`s with identical input; /// AgentTurn collapses N retried `LlmCall`s with identical input;
/// today retry is not implemented so AgentTurn and LlmCall fire 1:1 /// today retry is not implemented so AgentTurn and LlmCall fire 1:1
/// and the increment site (the LLM-call loop) is shared. /// and the increment site (the LLM-call loop) is shared.
/// `max_turns` is interpreted as a per-`run()` AgentTurn cap. /// `max_turns` is interpreted as a per-`run()` AgentTurn cap.
turn_count: usize, turn_count: usize,
/// LlmCall count (per-Worker running counter, monotonic). Unlike /// LlmCall count (per-Engine running counter, monotonic). Unlike
/// `turn_count` this never collapses retries. /// `turn_count` this never collapses retries.
llm_call_count: usize, llm_call_count: usize,
/// Tool execution batch count (per-Worker running counter, monotonic). /// Tool execution batch count (per-Engine running counter, monotonic).
/// Each batch corresponds to one collected assistant tool-call set or one /// Each batch corresponds to one collected assistant tool-call set or one
/// resumed pending tool-call set. /// resumed pending tool-call set.
tool_execution_batch_count: usize, tool_execution_batch_count: usize,
@ -212,7 +212,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
/// Pre-stream lifecycle callbacks for debugging stalls before provider /// Pre-stream lifecycle callbacks for debugging stalls before provider
/// stream events become visible. /// stream events become visible.
lifecycle_trace_cbs: Vec<Arc<dyn Fn(usize, usize, &str, &Value) + Send + Sync>>, lifecycle_trace_cbs: Vec<Arc<dyn Fn(usize, usize, &str, &Value) + Send + Sync>>,
/// Non-fatal warning callbacks. Invoked when the Worker wants to /// Non-fatal warning callbacks. Invoked when the Engine wants to
/// surface an advisory message to the upper layer (e.g. Pod) so it /// surface an advisory message to the upper layer (e.g. Pod) so it
/// can be forwarded to the user — distinct from `tracing::warn!`, /// can be forwarded to the user — distinct from `tracing::warn!`,
/// which is for developer-facing logs. /// which is for developer-facing logs.
@ -223,7 +223,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
/// enters history. /// enters history.
tool_result_cbs: Vec<Box<dyn Fn(&ToolResult) + Send + Sync>>, tool_result_cbs: Vec<Box<dyn Fn(&ToolResult) + Send + Sync>>,
/// History-append callbacks. Invoked for non-streamed items when they /// History-append callbacks. Invoked for non-streamed items when they
/// are appended to persistent worker history, so upper layers can /// are appended to persistent engine history, so upper layers can
/// broadcast those items using history itself as the source of truth. /// broadcast those items using history itself as the source of truth.
history_append_cbs: Vec<Box<dyn Fn(&Item) + Send + Sync>>, history_append_cbs: Vec<Box<dyn Fn(&Item) + Send + Sync>>,
/// Request configuration (max_tokens, temperature, etc.) /// Request configuration (max_tokens, temperature, etc.)
@ -260,7 +260,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
_state: PhantomData<S>, _state: PhantomData<S>,
} }
impl<C: LlmClient, S: WorkerState> Worker<C, S> { impl<C: LlmClient, S: EngineState> Engine<C, S> {
fn reset_interruption_state(&mut self) { fn reset_interruption_state(&mut self) {
self.last_run_interrupted = false; self.last_run_interrupted = false;
} }
@ -269,7 +269,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
while self.cancel_rx.try_recv().is_ok() {} while self.cancel_rx.try_recv().is_ok() {}
} }
/// Discard pending cancellation notifications while the worker is idle. /// Discard pending cancellation notifications while the engine is idle.
/// ///
/// Cancellation is a running-turn control signal. Callers that own a higher /// Cancellation is a running-turn control signal. Callers that own a higher
/// level run state can use this before starting a new turn so an old idle /// level run state can use this before starting a new turn so an old idle
@ -296,7 +296,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.on_text_block(|block| { /// engine.on_text_block(|block| {
/// block.on_delta(|text| print!("{}", text)); /// block.on_delta(|text| print!("{}", text));
/// block.on_stop(|full_text| println!("\n--- {} chars ---", full_text.len())); /// block.on_stop(|full_text| println!("\n--- {} chars ---", full_text.len()));
/// }); /// });
@ -335,7 +335,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.on_tool_use_block(|start, block| { /// engine.on_tool_use_block(|start, block| {
/// println!("Tool: {} ({})", start.name, start.id); /// println!("Tool: {} ({})", start.name, start.id);
/// block.on_delta(|json| { /* streaming JSON fragment */ }); /// block.on_delta(|json| { /* streaming JSON fragment */ });
/// block.on_stop(|call| println!("Done: {}", call.name)); /// block.on_stop(|call| println!("Done: {}", call.name));
@ -468,7 +468,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// Register a non-fatal warning callback. /// Register a non-fatal warning callback.
/// ///
/// The callback is invoked with a short human-readable message /// The callback is invoked with a short human-readable message
/// whenever the Worker encounters a condition that should be /// whenever the Engine encounters a condition that should be
/// surfaced to a human (e.g. tool output byte-cap truncation). /// surfaced to a human (e.g. tool output byte-cap truncation).
/// This channel is separate from `tracing::warn!`, which remains /// This channel is separate from `tracing::warn!`, which remains
/// in place for developer logs. /// in place for developer logs.
@ -498,7 +498,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
} }
/// Register a callback invoked for items appended directly to worker /// Register a callback invoked for items appended directly to engine
/// history outside streaming timeline callbacks. /// history outside streaming timeline callbacks.
pub fn on_history_append(&mut self, callback: impl Fn(&Item) + Send + Sync + 'static) { pub fn on_history_append(&mut self, callback: impl Fn(&Item) + Send + Sync + 'static) {
self.history_append_cbs.push(Box::new(callback)); self.history_append_cbs.push(Box::new(callback));
@ -639,7 +639,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
self.turn_count self.turn_count
} }
/// Get the current LlmCall count (per-Worker running counter, never /// Get the current LlmCall count (per-Engine running counter, never
/// collapsed by retry). /// collapsed by retry).
pub fn llm_call_count(&self) -> usize { pub fn llm_call_count(&self) -> usize {
self.llm_call_count self.llm_call_count
@ -657,7 +657,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.set_max_tokens(4096); /// engine.set_max_tokens(4096);
/// ``` /// ```
pub fn set_max_tokens(&mut self, max_tokens: u32) { pub fn set_max_tokens(&mut self, max_tokens: u32) {
self.request_config.max_tokens = Some(max_tokens); self.request_config.max_tokens = Some(max_tokens);
@ -671,7 +671,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.set_temperature(0.7); /// engine.set_temperature(0.7);
/// ``` /// ```
pub fn set_temperature(&mut self, temperature: f32) { pub fn set_temperature(&mut self, temperature: f32) {
self.request_config.temperature = Some(temperature); self.request_config.temperature = Some(temperature);
@ -682,7 +682,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.set_top_p(0.9); /// engine.set_top_p(0.9);
/// ``` /// ```
pub fn set_top_p(&mut self, top_p: f32) { pub fn set_top_p(&mut self, top_p: f32) {
self.request_config.top_p = Some(top_p); self.request_config.top_p = Some(top_p);
@ -695,7 +695,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.set_top_k(40); /// engine.set_top_k(40);
/// ``` /// ```
pub fn set_top_k(&mut self, top_k: u32) { pub fn set_top_k(&mut self, top_k: u32) {
self.request_config.top_k = Some(top_k); self.request_config.top_k = Some(top_k);
@ -706,7 +706,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// worker.add_stop_sequence("\n\n"); /// engine.add_stop_sequence("\n\n");
/// ``` /// ```
pub fn add_stop_sequence(&mut self, sequence: impl Into<String>) { pub fn add_stop_sequence(&mut self, sequence: impl Into<String>) {
self.request_config.stop_sequences.push(sequence.into()); self.request_config.stop_sequences.push(sequence.into());
@ -730,23 +730,23 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// Cancel execution /// Cancel execution
/// ///
/// Interrupts currently running streaming or tool execution. /// Interrupts currently running streaming or tool execution.
/// WorkerError::Cancelled is returned at the next event loop checkpoint. /// EngineError::Cancelled is returned at the next event loop checkpoint.
/// ///
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// use std::sync::Arc; /// use std::sync::Arc;
/// let worker = Arc::new(Mutex::new(Worker::new(client))); /// let engine = Arc::new(Mutex::new(Engine::new(client)));
/// ///
/// // Run in another thread /// // Run in another thread
/// let worker_clone = worker.clone(); /// let worker_clone = engine.clone();
/// tokio::spawn(async move { /// tokio::spawn(async move {
/// let mut w = worker_clone.lock().unwrap(); /// let mut w = worker_clone.lock().unwrap();
/// w.run("Long task...").await /// w.run("Long task...").await
/// }); /// });
/// ///
/// // Cancel /// // Cancel
/// worker.lock().unwrap().cancel(); /// engine.lock().unwrap().cancel();
/// ``` /// ```
pub fn cancel(&self) { pub fn cancel(&self) {
let _ = self.cancel_tx.try_send(()); let _ = self.cancel_tx.try_send(());
@ -849,15 +849,15 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
/// ///
async fn finalize_interruption<T>( async fn finalize_interruption<T>(
&mut self, &mut self,
result: Result<T, WorkerError>, result: Result<T, EngineError>,
) -> Result<T, WorkerError> { ) -> Result<T, EngineError> {
match result { match result {
Ok(value) => Ok(value), Ok(value) => Ok(value),
Err(err) => { Err(err) => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
let reason = match &err { let reason = match &err {
WorkerError::Aborted(reason) => reason.clone(), EngineError::Aborted(reason) => reason.clone(),
WorkerError::Cancelled => "Cancelled".to_string(), EngineError::Cancelled => "Cancelled".to_string(),
_ => err.to_string(), _ => err.to_string(),
}; };
self.interceptor.on_abort(&reason).await; self.interceptor.on_abort(&reason).await;
@ -913,7 +913,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
async fn execute_tools( async fn execute_tools(
&mut self, &mut self,
tool_calls: Vec<ToolCall>, tool_calls: Vec<ToolCall>,
) -> Result<ToolExecutionResult, WorkerError> { ) -> Result<ToolExecutionResult, EngineError> {
use futures::future::join_all; use futures::future::join_all;
// Map from tool call ID to (ToolCall, Meta, Tool, Context) // Map from tool call ID to (ToolCall, Meta, Tool, Context)
@ -953,7 +953,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
PreToolAction::Abort(reason) => { PreToolAction::Abort(reason) => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Aborted(reason)); return Err(EngineError::Aborted(reason));
} }
PreToolAction::Pause => { PreToolAction::Pause => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
@ -1010,7 +1010,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
}; };
results.extend(synthetic_results); results.extend(synthetic_results);
@ -1032,7 +1032,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
PostToolAction::Continue => {} PostToolAction::Continue => {}
PostToolAction::Abort(reason) => { PostToolAction::Abort(reason) => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Aborted(reason)); return Err(EngineError::Aborted(reason));
} }
} }
// Reflect interceptor-modified results // Reflect interceptor-modified results
@ -1084,14 +1084,14 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
/// Internal turn execution logic /// Internal turn execution logic
async fn run_turn_loop(&mut self) -> Result<WorkerResult, WorkerError> { async fn run_turn_loop(&mut self) -> Result<EngineResult, EngineError> {
self.reset_interruption_state(); self.reset_interruption_state();
let tool_definitions = self.build_tool_definitions(); let tool_definitions = self.build_tool_definitions();
info!( info!(
item_count = self.history.len(), item_count = self.history.len(),
tool_count = tool_definitions.len(), tool_count = tool_definitions.len(),
"Starting worker run" "Starting engine run"
); );
// Resume pending tool calls from a previous Pause // Resume pending tool calls from a previous Pause
@ -1109,7 +1109,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
info!("Execution cancelled"); info!("Execution cancelled");
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
let current_turn = self.turn_count; let current_turn = self.turn_count;
@ -1138,7 +1138,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
// Prune projection: if both the config and the savings // Prune projection: if both the config and the savings
// estimator are configured, drop ToolResult.content from // estimator are configured, drop ToolResult.content from
// prunable candidates whose estimated savings meet the // prunable candidates whose estimated savings meet the
// threshold. Worker does not own usage history itself; the // threshold. Engine does not own usage history itself; the
// estimator is injected by the layer that does. // estimator is injected by the layer that does.
if let (Some(config), Some(token_estimator), Some(savings_estimator)) = ( if let (Some(config), Some(token_estimator), Some(savings_estimator)) = (
&self.prune_config, &self.prune_config,
@ -1199,7 +1199,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
cb(current_turn); cb(current_turn);
} }
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Aborted(reason)); return Err(EngineError::Aborted(reason));
} }
PreRequestAction::YieldWith(items) => { PreRequestAction::YieldWith(items) => {
self.append_history_items(items.clone()); self.append_history_items(items.clone());
@ -1209,7 +1209,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
cb(current_turn); cb(current_turn);
} }
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Ok(WorkerResult::Yielded); return Ok(EngineResult::Yielded);
} }
PreRequestAction::Yield => { PreRequestAction::Yield => {
info!("Yielded by interceptor"); info!("Yielded by interceptor");
@ -1217,7 +1217,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
cb(current_turn); cb(current_turn);
} }
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Ok(WorkerResult::Yielded); return Ok(EngineResult::Yielded);
} }
PreRequestAction::ContinueWith(items) => { PreRequestAction::ContinueWith(items) => {
self.append_history_items(items.clone()); self.append_history_items(items.clone());
@ -1227,7 +1227,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
// LlmCall boundary fires per LLM generation request — today // LlmCall boundary fires per LLM generation request — today
// 1:1 with AgentTurn, but retry (`llm-worker-stream-continuation`) // 1:1 with AgentTurn, but retry (`llm-engine-stream-continuation`)
// will multiply this within a single AgentTurn. // will multiply this within a single AgentTurn.
let current_llm_call = self.llm_call_count; let current_llm_call = self.llm_call_count;
for cb in &self.llm_call_start_cbs { for cb in &self.llm_call_start_cbs {
@ -1262,7 +1262,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
stream_continuations += 1; stream_continuations += 1;
if stream_continuations > MAX_STREAM_CONTINUATIONS { if stream_continuations > MAX_STREAM_CONTINUATIONS {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Client(ClientError::Api { return Err(EngineError::Client(ClientError::Api {
status: None, status: None,
code: None, code: None,
message: format!("LLM stream interrupted too many times: {reason}"), message: format!("LLM stream interrupted too many times: {reason}"),
@ -1315,7 +1315,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
match self.interceptor.on_turn_end(&self.history).await { match self.interceptor.on_turn_end(&self.history).await {
TurnEndAction::Finish => { TurnEndAction::Finish => {
self.last_run_interrupted = false; self.last_run_interrupted = false;
return Ok(WorkerResult::Finished); return Ok(EngineResult::Finished);
} }
TurnEndAction::ContinueWithMessages(additional) => { TurnEndAction::ContinueWithMessages(additional) => {
self.append_history_items(additional); self.append_history_items(additional);
@ -1323,7 +1323,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
TurnEndAction::Pause => { TurnEndAction::Pause => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Ok(WorkerResult::Paused); return Ok(EngineResult::Paused);
} }
} }
} }
@ -1340,7 +1340,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
"Turn limit reached" "Turn limit reached"
); );
self.last_run_interrupted = false; self.last_run_interrupted = false;
return Ok(WorkerResult::LimitReached); return Ok(EngineResult::LimitReached);
} }
} }
} }
@ -1351,7 +1351,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
request: Request, request: Request,
turn: usize, turn: usize,
llm_call: usize, llm_call: usize,
) -> Result<ResponseStream, WorkerError> { ) -> Result<ResponseStream, EngineError> {
let policy = self.retry_policy.clone(); let policy = self.retry_policy.clone();
let started = Instant::now(); let started = Instant::now();
let mut failed_attempt: u32 = 0; let mut failed_attempt: u32 = 0;
@ -1385,7 +1385,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
); );
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
}; };
@ -1417,7 +1417,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
); );
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
}; };
match first_event_result { match first_event_result {
@ -1459,7 +1459,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
let next_failed_attempt = failed_attempt + 1; let next_failed_attempt = failed_attempt + 1;
if next_failed_attempt >= policy.max_attempts || !is_retryable(&err) { if next_failed_attempt >= policy.max_attempts || !is_retryable(&err) {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Client(err)); return Err(EngineError::Client(err));
} }
let wait = err let wait = err
@ -1468,7 +1468,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
let elapsed = started.elapsed(); let elapsed = started.elapsed();
if elapsed + wait > policy.total_timeout { if elapsed + wait > policy.total_timeout {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Client(err)); return Err(EngineError::Client(err));
} }
warn!( warn!(
@ -1497,7 +1497,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
} }
@ -1511,7 +1511,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
request: Request, request: Request,
turn: usize, turn: usize,
llm_call: usize, llm_call: usize,
) -> Result<StreamCompletion, WorkerError> { ) -> Result<StreamCompletion, EngineError> {
debug!( debug!(
item_count = request.items.len(), item_count = request.items.len(),
tool_count = request.tools.len(), tool_count = request.tools.len(),
@ -1561,7 +1561,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.timeline.flush_usage(); self.timeline.flush_usage();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Client(ClientError::Api { return Err(EngineError::Client(ClientError::Api {
status: None, status: None,
code: err.code.clone(), code: err.code.clone(),
message: err.message.clone(), message: err.message.clone(),
@ -1579,7 +1579,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
self.timeline.abort_current_block(); self.timeline.abort_current_block();
self.timeline.flush_usage(); self.timeline.flush_usage();
self.last_run_interrupted = true; self.last_run_interrupted = true;
return Err(WorkerError::Cancelled); return Err(EngineError::Cancelled);
} }
} }
} }
@ -1595,11 +1595,11 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
async fn execute_and_commit_tools( async fn execute_and_commit_tools(
&mut self, &mut self,
tool_calls: Vec<ToolCall>, tool_calls: Vec<ToolCall>,
) -> Result<Option<WorkerResult>, WorkerError> { ) -> Result<Option<EngineResult>, EngineError> {
match self.execute_tools(tool_calls).await { match self.execute_tools(tool_calls).await {
Ok(ToolExecutionResult::Paused) => { Ok(ToolExecutionResult::Paused) => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
Ok(Some(WorkerResult::Paused)) Ok(Some(EngineResult::Paused))
} }
Ok(ToolExecutionResult::Completed(results)) => { Ok(ToolExecutionResult::Completed(results)) => {
// Route per-result pushes through the callback path so // Route per-result pushes through the callback path so
@ -1624,8 +1624,8 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
} }
} }
impl<C: LlmClient> Worker<C, Mutable> { impl<C: LlmClient> Engine<C, Mutable> {
/// Create a new Worker (in Mutable state) /// Create a new Engine (in Mutable state)
pub fn new(client: C) -> Self { pub fn new(client: C) -> Self {
let text_block_collector = TextBlockCollector::new(); let text_block_collector = TextBlockCollector::new();
let tool_call_collector = ToolCallCollector::new(); let tool_call_collector = ToolCallCollector::new();
@ -1684,13 +1684,13 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// ///
/// The factory is queued and executed at the next `run()` or `resume()` call. /// The factory is queued and executed at the next `run()` or `resume()` call.
/// Duplicate name detection occurs at that point and surfaces as /// Duplicate name detection occurs at that point and surfaces as
/// [`WorkerError::ToolRegistry`]. /// [`EngineError::ToolRegistry`].
pub fn register_tool(&mut self, factory: WorkerToolDefinition) { pub fn register_tool(&mut self, factory: EngineToolDefinition) {
self.tool_server.register_tool(factory); self.tool_server.register_tool(factory);
} }
/// Register multiple tool factories for deferred initialization. /// Register multiple tool factories for deferred initialization.
pub fn register_tools(&mut self, factories: impl IntoIterator<Item = WorkerToolDefinition>) { pub fn register_tools(&mut self, factories: impl IntoIterator<Item = EngineToolDefinition>) {
self.tool_server.register_tools(factories); self.tool_server.register_tools(factories);
} }
@ -1719,7 +1719,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// let worker = Worker::new(client) /// let engine = Engine::new(client)
/// .system_prompt("You are a helpful assistant.") /// .system_prompt("You are a helpful assistant.")
/// .max_tokens(4096); /// .max_tokens(4096);
/// ``` /// ```
@ -1733,7 +1733,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// let worker = Worker::new(client) /// let engine = Engine::new(client)
/// .temperature(0.7); /// .temperature(0.7);
/// ``` /// ```
pub fn temperature(mut self, temperature: f32) -> Self { pub fn temperature(mut self, temperature: f32) -> Self {
@ -1768,7 +1768,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// .with_max_tokens(4096) /// .with_max_tokens(4096)
/// .with_temperature(0.7); /// .with_temperature(0.7);
/// ///
/// let worker = Worker::new(client) /// let engine = Engine::new(client)
/// .system_prompt("...") /// .system_prompt("...")
/// .with_config(config); /// .with_config(config);
/// ``` /// ```
@ -1791,7 +1791,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// let worker = Worker::new(client) /// let engine = Engine::new(client)
/// .temperature(0.7) /// .temperature(0.7)
/// .top_k(40) /// .top_k(40)
/// .validate()?; // Error if using OpenAI since top_k is not supported /// .validate()?; // Error if using OpenAI since top_k is not supported
@ -1799,13 +1799,13 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// ///
/// # Returns /// # Returns
/// * `Ok(Self)` - Validation successful /// * `Ok(Self)` - Validation successful
/// * `Err(WorkerError::ConfigWarnings)` - Has unsupported settings /// * `Err(EngineError::ConfigWarnings)` - Has unsupported settings
pub fn validate(self) -> Result<Self, WorkerError> { pub fn validate(self) -> Result<Self, EngineError> {
let warnings = self.client.validate_config(&self.request_config); let warnings = self.client.validate_config(&self.request_config);
if warnings.is_empty() { if warnings.is_empty() {
Ok(self) Ok(self)
} else { } else {
Err(WorkerError::ConfigWarnings(warnings)) Err(EngineError::ConfigWarnings(warnings))
} }
} }
@ -1820,7 +1820,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// Append items to history and notify history-append observers for each /// Append items to history and notify history-append observers for each
/// item before it lands. This is the only public Mutable-state API for /// item before it lands. This is the only public Mutable-state API for
/// growing worker history; callers that need session-log persistence must /// growing engine history; callers that need session-log persistence must
/// install [`on_history_append`](Self::on_history_append) before calling it. /// install [`on_history_append`](Self::on_history_append) before calling it.
pub fn append_history(&mut self, items: impl IntoIterator<Item = Item>) { pub fn append_history(&mut self, items: impl IntoIterator<Item = Item>) {
self.append_history_items(items); self.append_history_items(items);
@ -1855,7 +1855,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// Apply configuration (reserved for future extensions) /// Apply configuration (reserved for future extensions)
#[allow(dead_code)] #[allow(dead_code)]
pub fn config(self, _config: WorkerConfig) -> Self { pub fn config(self, _config: EngineConfig) -> Self {
self self
} }
@ -1864,13 +1864,16 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// This is the primary entry point for first use. Equivalent to /// This is the primary entry point for first use. Equivalent to
/// `self.lock()` followed by `locked.run(user_input)`. /// `self.lock()` followed by `locked.run(user_input)`.
/// ///
/// Subsequent runs can use [`Worker<C, Locked>::run()`] directly. /// Subsequent runs can use [`Engine<C, Locked>::run()`] directly.
/// To edit state between turns, call [`unlock()`](Worker::unlock) first. /// To edit state between turns, call [`unlock()`](Engine::unlock) first.
pub async fn run(self, user_input: impl Into<String>) -> Result<RunOutput<C>, WorkerError> { pub async fn run(
self,
user_input: impl Into<String>,
) -> Result<EngineRunOutput<C>, EngineError> {
let mut locked = self.lock(); let mut locked = self.lock();
let result = locked.run(user_input).await?; let result = locked.run(user_input).await?;
Ok(RunOutput { Ok(EngineRunOutput {
worker: locked, engine: locked,
result, result,
}) })
} }
@ -1878,11 +1881,11 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// Resume from Paused, consuming self and transitioning to Locked. /// Resume from Paused, consuming self and transitioning to Locked.
/// ///
/// Used after `unlock()` → edit → resume. /// Used after `unlock()` → edit → resume.
pub async fn resume(self) -> Result<RunOutput<C>, WorkerError> { pub async fn resume(self) -> Result<EngineRunOutput<C>, EngineError> {
let mut locked = self.lock(); let mut locked = self.lock();
let result = locked.resume().await?; let result = locked.resume().await?;
Ok(RunOutput { Ok(EngineRunOutput {
worker: locked, engine: locked,
result, result,
}) })
} }
@ -1895,15 +1898,15 @@ impl<C: LlmClient> Worker<C, Mutable> {
/// ///
/// Most callers should use [`run()`](Self::run) instead, which calls /// Most callers should use [`run()`](Self::run) instead, which calls
/// this internally. Use `lock()` directly only when you need the /// this internally. Use `lock()` directly only when you need the
/// `Locked` worker back on error (e.g. in a persistence layer). /// `Locked` engine back on error (e.g. in a persistence layer).
/// ///
/// # Panics /// # Panics
/// ///
/// Panics if a pending tool factory produces a duplicate name. /// Panics if a pending tool factory produces a duplicate name.
pub fn lock(self) -> Worker<C, Locked> { pub fn lock(self) -> Engine<C, Locked> {
self.tool_server.flush_pending(); self.tool_server.flush_pending();
let locked_prefix_len = self.history.len(); let locked_prefix_len = self.history.len();
Worker { Engine {
client: self.client, client: self.client,
retry_policy: self.retry_policy, retry_policy: self.retry_policy,
timeline: self.timeline, timeline: self.timeline,
@ -1947,7 +1950,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
} }
} }
impl<C: LlmClient> Worker<C, Locked> { impl<C: LlmClient> Engine<C, Locked> {
/// Execute a turn /// Execute a turn
/// ///
/// Adds a new user message to history and sends a request to the LLM. /// Adds a new user message to history and sends a request to the LLM.
@ -1955,7 +1958,7 @@ impl<C: LlmClient> Worker<C, Locked> {
pub async fn run( pub async fn run(
&mut self, &mut self,
user_input: impl Into<String>, user_input: impl Into<String>,
) -> Result<WorkerResult, WorkerError> { ) -> Result<EngineResult, EngineError> {
self.reset_interruption_state(); self.reset_interruption_state();
// Interceptor: on_prompt_submit // Interceptor: on_prompt_submit
let mut user_item = Item::user_message(user_input); let mut user_item = Item::user_message(user_input);
@ -1963,7 +1966,7 @@ impl<C: LlmClient> Worker<C, Locked> {
PromptAction::Cancel(reason) => { PromptAction::Cancel(reason) => {
self.last_run_interrupted = true; self.last_run_interrupted = true;
return self return self
.finalize_interruption(Err(WorkerError::Aborted(reason))) .finalize_interruption(Err(EngineError::Aborted(reason)))
.await; .await;
} }
PromptAction::Continue => Vec::new(), PromptAction::Continue => Vec::new(),
@ -1980,7 +1983,7 @@ impl<C: LlmClient> Worker<C, Locked> {
/// Resume execution (from Paused state) /// Resume execution (from Paused state)
/// ///
/// Resumes turn processing from current state without adding a new user message. /// Resumes turn processing from current state without adding a new user message.
pub async fn resume(&mut self) -> Result<WorkerResult, WorkerError> { pub async fn resume(&mut self) -> Result<EngineResult, EngineError> {
self.reset_interruption_state(); self.reset_interruption_state();
let result = self.run_turn_loop().await; let result = self.run_turn_loop().await;
self.finalize_interruption(result).await self.finalize_interruption(result).await
@ -1995,8 +1998,8 @@ impl<C: LlmClient> Worker<C, Locked> {
/// ///
/// Note: After this operation, subsequent requests may not hit the cache. /// Note: After this operation, subsequent requests may not hit the cache.
/// Use only when you need to edit history. /// Use only when you need to edit history.
pub fn unlock(self) -> Worker<C, Mutable> { pub fn unlock(self) -> Engine<C, Mutable> {
Worker { Engine {
client: self.client, client: self.client,
retry_policy: self.retry_policy, retry_policy: self.retry_policy,
timeline: self.timeline, timeline: self.timeline,

View File

@ -1,4 +1,4 @@
//! Public event types for Worker layer //! Public event types for Engine layer
//! //!
//! Re-exports from the canonical event definitions in llm_client. //! Re-exports from the canonical event definitions in llm_client.

View File

@ -32,7 +32,7 @@ pub trait Kind {
/// # Examples /// # Examples
/// ///
/// ```ignore /// ```ignore
/// use llm_worker::timeline::{Handler, TextBlockEvent, TextBlockKind}; /// use llm_engine::timeline::{Handler, TextBlockEvent, TextBlockKind};
/// ///
/// struct TextCollector { /// struct TextCollector {
/// texts: Vec<String>, /// texts: Vec<String>,

View File

@ -1,8 +1,8 @@
//! Interceptor - control flow delegation for the Worker execution loop //! Interceptor - control flow delegation for the Engine execution loop
//! //!
//! Defines the [`Interceptor`] trait that upper layers (e.g. Pod) implement //! Defines the [`Interceptor`] trait that upper layers (e.g. Pod) implement
//! to inject orchestration decisions (approval, skip, pause, abort) //! to inject orchestration decisions (approval, skip, pause, abort)
//! into the Worker's turn loop without the Worker knowing about //! into the Engine's turn loop without the Engine knowing about
//! higher-level concepts. //! higher-level concepts.
use std::sync::Arc; use std::sync::Arc;
@ -36,13 +36,13 @@ pub enum PromptAction {
pub enum PreRequestAction { pub enum PreRequestAction {
/// Proceed normally. /// Proceed normally.
Continue, Continue,
/// Proceed after appending these items to durable worker history. /// Proceed after appending these items to durable engine history.
/// ///
/// This is for upper-layer budget/status nudges that the model may react /// This is for upper-layer budget/status nudges that the model may react
/// to: the items are committed before the request so later turns can see /// to: the items are committed before the request so later turns can see
/// why the worker changed course. /// why the engine changed course.
ContinueWith(Vec<Item>), ContinueWith(Vec<Item>),
/// Yield after appending these items to durable worker history. /// Yield after appending these items to durable engine history.
/// ///
/// This is for host-mediated pre-request appends that must be visible to /// This is for host-mediated pre-request appends that must be visible to
/// usage accounting and compaction checks before the current LLM request is /// usage accounting and compaction checks before the current LLM request is
@ -52,7 +52,7 @@ pub enum PreRequestAction {
Cancel(String), Cancel(String),
/// Yield control to the caller for external processing. /// Yield control to the caller for external processing.
/// ///
/// The Worker exits the turn loop cleanly with `WorkerResult::Yielded`. /// The Engine exits the turn loop cleanly with `EngineResult::Yielded`.
/// The caller is expected to resume execution later. /// The caller is expected to resume execution later.
Yield, Yield,
} }
@ -129,9 +129,9 @@ pub struct ToolResultInfo {
// Interceptor Trait // Interceptor Trait
// ============================================================================= // =============================================================================
/// Intercepts the Worker execution loop at key decision points. /// Intercepts the Engine execution loop at key decision points.
/// ///
/// All methods have default implementations that let the Worker /// All methods have default implementations that let the Engine
/// proceed without intervention. Upper layers (e.g. Pod) provide /// proceed without intervention. Upper layers (e.g. Pod) provide
/// richer implementations for approval flows, permission checks, etc. /// richer implementations for approval flows, permission checks, etc.
#[async_trait] #[async_trait]
@ -141,7 +141,7 @@ pub trait Interceptor: Send + Sync {
PromptAction::Continue PromptAction::Continue
} }
/// Items that should be **committed to `worker.history`** just /// Items that should be **committed to `engine.history`** just
/// before the next LLM request. Returned items are `extend`ed into /// before the next LLM request. Returned items are `extend`ed into
/// the persistent history (and therefore picked up by the per-turn /// the persistent history (and therefore picked up by the per-turn
/// clone that backs the LLM request, plus the usual /// clone that backs the LLM request, plus the usual
@ -164,12 +164,12 @@ pub trait Interceptor: Send + Sync {
} }
/// Called before each LLM request. The context starts as a clone /// Called before each LLM request. The context starts as a clone
/// of `worker.history` (after `pending_history_appends` and the /// of `engine.history` (after `pending_history_appends` and the
/// Worker's own prune projection have been applied). /// Engine's own prune projection have been applied).
/// ///
/// Direct mutations to `context` remain request-local and are not persisted. /// Direct mutations to `context` remain request-local and are not persisted.
/// If an interceptor derives a human/model-visible nudge from the current /// If an interceptor derives a human/model-visible nudge from the current
/// request context, return [`PreRequestAction::ContinueWith`] so the Worker /// request context, return [`PreRequestAction::ContinueWith`] so the Engine
/// commits it to history before the request is sent. /// commits it to history before the request is sent.
async fn pre_llm_request(&self, _context: &mut Vec<Item>) -> PreRequestAction { async fn pre_llm_request(&self, _context: &mut Vec<Item>) -> PreRequestAction {
PreRequestAction::Continue PreRequestAction::Continue
@ -194,7 +194,7 @@ pub trait Interceptor: Send + Sync {
async fn on_abort(&self, _reason: &str) {} async fn on_abort(&self, _reason: &str) {}
} }
/// Default interceptor: no intervention. Worker proceeds through the loop /// Default interceptor: no intervention. Engine proceeds through the loop
/// without any external control flow decisions. /// without any external control flow decisions.
pub(crate) struct DefaultInterceptor; pub(crate) struct DefaultInterceptor;

View File

@ -1,28 +1,28 @@
//! llm-worker - LLM Worker Library //! llm-engine - LLM Engine Library
//! //!
//! Provides components for managing interactions with LLMs. //! Provides components for managing interactions with LLMs.
//! //!
//! # Main Components //! # Main Components
//! //!
//! - [`Worker`] - Central component for managing LLM interactions //! - [`Engine`] - Central component for managing LLM interactions
//! - [`tool::Tool`] - Tools that can be invoked by the LLM //! - [`tool::Tool`] - Tools that can be invoked by the LLM
//! - [`interceptor::Interceptor`] - Control-flow delegation for the execution loop //! - [`interceptor::Interceptor`] - Control-flow delegation for the execution loop
//! - Closure-based event callbacks via `Worker::on_text_block()`, `on_tool_use_block()`, etc. //! - Closure-based event callbacks via `Engine::on_text_block()`, `on_tool_use_block()`, etc.
//! //!
//! # Quick Start //! # Quick Start
//! //!
//! ```ignore //! ```ignore
//! use llm_worker::{Worker, Item}; //! use llm_engine::{Engine, Item};
//! //!
//! // Create a Worker //! // Create a Engine
//! let mut worker = Worker::new(client) //! let mut engine = Engine::new(client)
//! .system_prompt("You are a helpful assistant."); //! .system_prompt("You are a helpful assistant.");
//! //!
//! // Register tools (optional) //! // Register tools (optional)
//! // worker.register_tool(my_tool_definition)?; //! // engine.register_tool(my_tool_definition)?;
//! //!
//! // Run the interaction //! // Run the interaction
//! let history = worker.run("Hello!").await?; //! let history = engine.run("Hello!").await?;
//! ``` //! ```
//! //!
//! # Cache Protection //! # Cache Protection
@ -31,15 +31,15 @@
//! call `unlock_cache()` first; the next `run()` re-locks automatically. //! call `unlock_cache()` first; the next `run()` re-locks automatically.
//! //!
//! ```ignore //! ```ignore
//! worker.run("user input").await?; //! engine.run("user input").await?;
//! worker.unlock_cache(); //! engine.unlock_cache();
//! worker.set_system_prompt("new prompt"); //! engine.set_system_prompt("new prompt");
//! worker.run("next input").await?; //! engine.run("next input").await?;
//! ``` //! ```
mod engine;
mod handler; mod handler;
mod message; mod message;
mod worker;
pub(crate) mod callback; pub(crate) mod callback;
pub mod event; pub mod event;
@ -54,11 +54,12 @@ pub mod tool_server;
pub mod usage_record; pub mod usage_record;
pub use callback::{TextBlockScope, ThinkingBlockScope, ToolUseBlockScope}; pub use callback::{TextBlockScope, ThinkingBlockScope, ToolUseBlockScope};
pub use engine::{
Engine, EngineConfig, EngineError, EngineResult, EngineRunOutput, LlmRetryNotice,
ToolRegistryError,
};
pub use handler::ToolUseBlockStart; pub use handler::ToolUseBlockStart;
pub use interceptor::Interceptor; pub use interceptor::Interceptor;
pub use message::{ContentPart, Item, Message, Role}; pub use message::{ContentPart, Item, Message, Role};
pub use tool::{ToolCall, ToolExecutionContext, ToolOutputLimits, ToolResult}; pub use tool::{ToolCall, ToolExecutionContext, ToolOutputLimits, ToolResult};
pub use usage_record::UsageRecord; pub use usage_record::UsageRecord;
pub use worker::{
LlmRetryNotice, RunOutput, ToolRegistryError, Worker, WorkerConfig, WorkerError, WorkerResult,
};

View File

@ -1,7 +1,7 @@
//! `Scheme` 実装と通信層が要求する認証要件、および動的認証プロバイダ。 //! `Scheme` 実装と通信層が要求する認証要件、および動的認証プロバイダ。
//! //!
//! マニフェスト側の型(`ModelConfig` / `SchemeKind` / `AuthRef`)は //! マニフェスト側の型(`ModelConfig` / `SchemeKind` / `AuthRef`)は
//! `crates/manifest` に置き、llm-worker はそれを知らずに済む。 //! `crates/manifest` に置き、llm-engine はそれを知らずに済む。
//! `AuthRequirement` は scheme が宣言する「この scheme はどんな認証を //! `AuthRequirement` は scheme が宣言する「この scheme はどんな認証を
//! 期待するか」のランタイム記述で、manifest 側の `AuthRef` との //! 期待するか」のランタイム記述で、manifest 側の `AuthRef` との
//! 照合(`AuthRef → ResolvedAuth` 変換の適否)は `crates/provider` //! 照合(`AuthRef → ResolvedAuth` 変換の適否)は `crates/provider`
@ -36,7 +36,7 @@ pub enum AuthRequirement {
/// Codex OAuth のように access_token が refresh で更新されたり、 /// Codex OAuth のように access_token が refresh で更新されたり、
/// `ChatGPT-Account-Id` / `X-OpenAI-Fedramp` のような複数ヘッダを /// `ChatGPT-Account-Id` / `X-OpenAI-Fedramp` のような複数ヘッダを
/// 同時に注入する必要があるケースで使う。実体は `crates/provider` /// 同時に注入する必要があるケースで使う。実体は `crates/provider`
/// 側に置き、llm-worker は trait を知るだけ。 /// 側に置き、llm-engine は trait を知るだけ。
/// ///
/// 返したヘッダはそのまま `HeaderMap` に挿入される。`Authorization` /// 返したヘッダはそのまま `HeaderMap` に挿入される。`Authorization`
/// 含む scheme 既定の認証ヘッダは送出されないので、必要なら /// 含む scheme 既定の認証ヘッダは送出されないので、必要なら

View File

@ -81,7 +81,7 @@ impl Clone for Box<dyn LlmClient> {
/// `Box<dyn LlmClient>` に対する `LlmClient` の実装 /// `Box<dyn LlmClient>` に対する `LlmClient` の実装
/// ///
/// これにより、動的ディスパッチを使用するクライアントも `Worker` で利用可能になる。 /// これにより、動的ディスパッチを使用するクライアントも `Engine` で利用可能になる。
#[async_trait] #[async_trait]
impl LlmClient for Box<dyn LlmClient> { impl LlmClient for Box<dyn LlmClient> {
async fn stream(&self, request: Request) -> Result<ResponseStream, ClientError> { async fn stream(&self, request: Request) -> Result<ResponseStream, ClientError> {

View File

@ -1,6 +1,6 @@
//! LLM response stream を開く前の transient error 向けリトライポリシー。 //! LLM response stream を開く前の transient error 向けリトライポリシー。
//! //!
//! Worker が `LlmClient::stream` の open error に対して `is_retryable` を見て //! Engine が `LlmClient::stream` の open error に対して `is_retryable` を見て
//! retry / backoff / TUI event / cancellation をまとめて管理する。 //! retry / backoff / TUI event / cancellation をまとめて管理する。
//! SSE 読み出し開始後の失敗は対象外。 //! SSE 読み出し開始後の失敗は対象外。
@ -8,8 +8,8 @@ use std::time::Duration;
/// 指数バックオフ + ジッター + 累積タイムアウトを表すポリシー。 /// 指数バックオフ + ジッター + 累積タイムアウトを表すポリシー。
/// ///
/// `Default` は llm-worker 全体の固定値を返す。manifest 経由の上書きが /// `Default` は llm-engine 全体の固定値を返す。manifest 経由の上書きが
/// 必要になったら拡張する(現状は不要 → `tickets/llm-worker-transient-retry.md`)。 /// 必要になったら拡張する(現状は不要 → `tickets/llm-engine-transient-retry.md`)。
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RetryPolicy { pub struct RetryPolicy {
/// 指数の基準値。`base * 2^attempt` を `cap` で頭打ちにした上限から /// 指数の基準値。`base * 2^attempt` を `cap` で頭打ちにした上限から

Some files were not shown because too many files have changed in this diff Show More