Compare commits
16 Commits
a525ba4d01
...
d93dbc0533
| Author | SHA1 | Date | |
|---|---|---|---|
| d93dbc0533 | |||
| 9ee77b44ae | |||
| 20cfcfaca3 | |||
| b367abd76a | |||
| 6ab0d64fcb | |||
| 254ecccba2 | |||
| 4d8e022465 | |||
| 50e2754e5e | |||
| 292fc4ea5d | |||
| 230b379979 | |||
| 22598710fd | |||
| 1d6125e57d | |||
| 193c868146 | |||
| 1aa3a409cd | |||
| 159704dc6f | |||
| 6492f10f42 |
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Abstract Workspace Worker runtime spawn operations'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T16:34:39Z'
|
||||
updated_at: '2026-06-24T10:35:01Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T19:25:09Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVTNAY20/resolution.md
Normal file
1
.yoi/tickets/00001KVTNAY20/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -288,4 +288,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Abstract Worker runtime registry and overview reporting'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T09:11:38Z'
|
||||
updated_at: '2026-06-24T11:15:13Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T09:22:55Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVWECEQG/resolution.md
Normal file
1
.yoi/tickets/00001KVWECEQG/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -374,4 +374,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Pod/session storage cleanup CLI を追加する'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T11:39:41Z'
|
||||
updated_at: '2026-06-24T12:36:12Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary']
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVWPVHFJ/resolution.md
Normal file
1
.yoi/tickets/00001KVWPVHFJ/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -213,4 +213,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T11:39:59Z'
|
||||
updated_at: '2026-06-24T12:20:08Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection']
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVWPW3KX/resolution.md
Normal file
1
.yoi/tickets/00001KVWPW3KX/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -208,4 +208,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Backend internal Orchestrator runtime for Kanban operations'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T12:29:58Z'
|
||||
updated_at: '2026-06-24T19:15:42Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T19:04:55Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVWSQM22/resolution.md
Normal file
1
.yoi/tickets/00001KVWSQM22/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -254,4 +254,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Remove legacy raw WASM Plugin runtime'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T20:51:02Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:11:56Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WD3/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WD3/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -270,4 +270,22 @@ Correction:
|
|||
- 正しい merge commit は `bedbb670 merge: 00001KVXK0WD3 legacy wasm removal`。
|
||||
- 実装 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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Reject legacy Plugin runtime in manifest and CLI diagnostics'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T21:20:45Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:11:58Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WDH/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WDH/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -303,4 +303,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Define Plugin Service lifecycle and ingress queue runtime'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T21:51:13Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:00Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WDQ/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WDQ/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -300,4 +300,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Add Plugin service output command model'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T06:20:26Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:02Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WDX/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WDX/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -296,4 +296,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Add host-owned WebSocket driver for Plugin services'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T07:06:30Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:03Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WE4/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WE4/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -285,4 +285,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: 'Update Plugin WIT PDK templates for service event runtime'
|
||||
state: 'done'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T07:57:15Z'
|
||||
updated_at: '2026-06-25T14:13:52Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:05Z'
|
||||
|
|
|
|||
1
.yoi/tickets/00001KVXK0WEA/resolution.md
Normal file
1
.yoi/tickets/00001KVXK0WEA/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
|
|
@ -360,4 +360,22 @@ Evidence:
|
|||
|
||||
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.
|
||||
|
||||
|
||||
---
|
||||
|
|
|
|||
0
.yoi/tickets/00001KVZ9JGK0/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVZ9JGK0/artifacts/.gitkeep
Normal file
13
.yoi/tickets/00001KVZ9JGK0/artifacts/relations.json
Normal file
13
.yoi/tickets/00001KVZ9JGK0/artifacts/relations.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
123
.yoi/tickets/00001KVZ9JGK0/item.md
Normal file
123
.yoi/tickets/00001KVZ9JGK0/item.md
Normal 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` が通る。
|
||||
7
.yoi/tickets/00001KVZ9JGK0/thread.md
Normal file
7
.yoi/tickets/00001KVZ9JGK0/thread.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!-- event: create author: "yoi ticket" at: 2026-06-25T11:45:17Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVZBCQH4/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVZBCQH4/artifacts/.gitkeep
Normal file
21
.yoi/tickets/00001KVZBCQH4/artifacts/relations.json
Normal file
21
.yoi/tickets/00001KVZBCQH4/artifacts/relations.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
147
.yoi/tickets/00001KVZBCQH4/item.md
Normal file
147
.yoi/tickets/00001KVZBCQH4/item.md
Normal 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 が提案されている。
|
||||
246
.yoi/tickets/00001KVZBCQH4/thread.md
Normal file
246
.yoi/tickets/00001KVZBCQH4/thread.md
Normal 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.
|
||||
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVZD10ED/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVZD10ED/artifacts/.gitkeep
Normal 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"}
|
||||
89
.yoi/tickets/00001KVZD10ED/item.md
Normal file
89
.yoi/tickets/00001KVZD10ED/item.md
Normal 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.
|
||||
1
.yoi/tickets/00001KVZD10ED/resolution.md
Normal file
1
.yoi/tickets/00001KVZD10ED/resolution.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Implemented, reviewed, marked done, and merged into develop.
|
||||
335
.yoi/tickets/00001KVZD10ED/thread.md
Normal file
335
.yoi/tickets/00001KVZD10ED/thread.md
Normal 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.
|
||||
|
||||
|
||||
---
|
||||
0
.yoi/tickets/00001KVZG9BMS/artifacts/.gitkeep
Normal file
0
.yoi/tickets/00001KVZG9BMS/artifacts/.gitkeep
Normal file
13
.yoi/tickets/00001KVZG9BMS/artifacts/relations.json
Normal file
13
.yoi/tickets/00001KVZG9BMS/artifacts/relations.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
90
.yoi/tickets/00001KVZG9BMS/item.md
Normal file
90
.yoi/tickets/00001KVZG9BMS/item.md
Normal 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.
|
||||
33
.yoi/tickets/00001KVZG9BMS/thread.md
Normal file
33
.yoi/tickets/00001KVZG9BMS/thread.md
Normal 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
22
Cargo.lock
generated
|
|
@ -2102,7 +2102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
|
||||
|
||||
[[package]]
|
||||
name = "llm-worker"
|
||||
name = "llm-engine"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
|
|
@ -2110,7 +2110,7 @@ dependencies = [
|
|||
"dotenv",
|
||||
"eventsource-stream",
|
||||
"futures",
|
||||
"llm-worker-macros",
|
||||
"llm-engine-macros",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
|
@ -2127,7 +2127,7 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "llm-worker-macros"
|
||||
name = "llm-engine-macros"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
|
|
@ -2242,7 +2242,7 @@ name = "manifest"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"mlua",
|
||||
"protocol",
|
||||
"secrets",
|
||||
|
|
@ -2373,7 +2373,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"libc",
|
||||
"lint-common",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"manifest",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
|
@ -2888,7 +2888,7 @@ dependencies = [
|
|||
"futures-util",
|
||||
"include_dir",
|
||||
"libc",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"manifest",
|
||||
"mcp",
|
||||
"memory",
|
||||
|
|
@ -3045,7 +3045,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"base64",
|
||||
"chrono",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"manifest",
|
||||
"reqwest",
|
||||
"secrets",
|
||||
|
|
@ -3901,7 +3901,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"protocol",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4352,7 +4352,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"chrono",
|
||||
"fs4",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"project-record",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
|
@ -4535,7 +4535,7 @@ dependencies = [
|
|||
"grep-searcher",
|
||||
"html5ever",
|
||||
"ignore",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"manifest",
|
||||
"markup5ever_rcdom",
|
||||
"pdf-extract",
|
||||
|
|
@ -4715,7 +4715,7 @@ dependencies = [
|
|||
"base64",
|
||||
"client",
|
||||
"crossterm 0.28.1",
|
||||
"llm-worker",
|
||||
"llm-engine",
|
||||
"manifest",
|
||||
"minijinja",
|
||||
"pod-registry",
|
||||
|
|
|
|||
12
Cargo.toml
12
Cargo.toml
|
|
@ -2,8 +2,8 @@
|
|||
resolver = "2"
|
||||
members = [
|
||||
"crates/client",
|
||||
"crates/llm-worker",
|
||||
"crates/llm-worker-macros",
|
||||
"crates/llm-engine",
|
||||
"crates/llm-engine-macros",
|
||||
"crates/session-store",
|
||||
"crates/secrets",
|
||||
"crates/manifest",
|
||||
|
|
@ -29,8 +29,8 @@ members = [
|
|||
]
|
||||
default-members = [
|
||||
"crates/client",
|
||||
"crates/llm-worker",
|
||||
"crates/llm-worker-macros",
|
||||
"crates/llm-engine",
|
||||
"crates/llm-engine-macros",
|
||||
"crates/session-store",
|
||||
"crates/secrets",
|
||||
"crates/manifest",
|
||||
|
|
@ -61,8 +61,8 @@ license = "MIT"
|
|||
[workspace.dependencies]
|
||||
# Internal crates
|
||||
client = { path = "crates/client" }
|
||||
llm-worker = { path = "crates/llm-worker", version = "0.2" }
|
||||
llm-worker-macros = { path = "crates/llm-worker-macros", version = "0.2" }
|
||||
llm-engine = { path = "crates/llm-engine", version = "0.2" }
|
||||
llm-engine-macros = { path = "crates/llm-engine-macros", version = "0.2" }
|
||||
manifest = { path = "crates/manifest" }
|
||||
mcp = { path = "crates/mcp" }
|
||||
lint-common = { path = "crates/lint-common" }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Does not own:
|
|||
- product command names (`yoi`)
|
||||
- Pod state authority (`pod`, `pod-store`, `session-store`)
|
||||
- UI rendering (`tui`)
|
||||
- Worker turn semantics (`llm-worker`)
|
||||
- Engine turn semantics (`llm-engine`)
|
||||
|
||||
## Design notes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "llm-worker-macros"
|
||||
description = "llm-worker's proc macros"
|
||||
name = "llm-engine-macros"
|
||||
description = "llm-engine's proc macros"
|
||||
version = "0.2.0"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
# llm-worker-macros
|
||||
# llm-engine-macros
|
||||
|
||||
## 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
|
||||
|
||||
|
|
@ -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
|
||||
//! 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! {
|
||||
match result {
|
||||
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 {
|
||||
|
|
@ -252,7 +252,7 @@ fn generate_tool_impl(self_ty: &Type, method: &syn::ImplItemFn) -> proc_macro2::
|
|||
} else {
|
||||
quote! {
|
||||
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;
|
||||
#result_handling
|
||||
|
|
@ -268,23 +268,23 @@ fn generate_tool_impl(self_ty: &Type, method: &syn::ImplItemFn) -> proc_macro2::
|
|||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ::llm_worker::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> {
|
||||
impl ::llm_engine::tool::Tool for #tool_struct_name {
|
||||
async fn execute(&self, input_json: &str, ctx: ::llm_engine::tool::ToolExecutionContext) -> Result<::llm_engine::tool::ToolOutput, ::llm_engine::tool::ToolError> {
|
||||
let _ = &ctx;
|
||||
#execute_body
|
||||
}
|
||||
}
|
||||
|
||||
impl #self_ty {
|
||||
/// Get ToolDefinition (for registering with Worker)
|
||||
pub fn #definition_name(&self) -> ::llm_worker::tool::ToolDefinition {
|
||||
/// Get ToolDefinition (for registering with Engine)
|
||||
pub fn #definition_name(&self) -> ::llm_engine::tool::ToolDefinition {
|
||||
let ctx = self.clone();
|
||||
::std::sync::Arc::new(move || {
|
||||
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)
|
||||
.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() });
|
||||
(meta, tool)
|
||||
})
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "llm-worker"
|
||||
name = "llm-engine"
|
||||
description = "A library for building autonomous LLM-powered systems"
|
||||
version = "0.2.1"
|
||||
edition.workspace = true
|
||||
|
|
@ -17,7 +17,7 @@ tokio-util = "0.7"
|
|||
reqwest = { version = "0.13", default-features = false, features = ["stream", "json", "native-tls", "http2"] }
|
||||
eventsource-stream = "0.2"
|
||||
zstd = "0.13"
|
||||
llm-worker-macros = { workspace = true }
|
||||
llm-engine-macros = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
clap = { version = "4.5", features = ["derive", "env"] }
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
# llm-worker
|
||||
# llm-engine
|
||||
|
||||
## 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
|
||||
|
||||
Owns:
|
||||
|
||||
- Worker history mutation and append contracts
|
||||
- Engine history mutation and append contracts
|
||||
- tool-call loop semantics
|
||||
- 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
|
||||
|
||||
Does not own:
|
||||
|
|
@ -23,7 +23,7 @@ Does not own:
|
|||
|
||||
## 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
|
||||
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
# llm-worker アーキテクチャ
|
||||
# llm-engine アーキテクチャ
|
||||
|
||||
## 概要
|
||||
|
||||
llm-workerは3層構成でLLMとのインタラクションを管理する。
|
||||
llm-engineは3層構成でLLMとのインタラクションを管理する。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Worker (オーケストレーション) │
|
||||
│ Engine (オーケストレーション) │
|
||||
│ ターンループ / フック / ツール実行 │
|
||||
│ 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 |
|
||||
| `hook` | Hook trait、10フックポイント | R3, R4 |
|
||||
| `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 }
|
||||
→ Scheme.build_request() → プロバイダ固有JSON
|
||||
→ Provider.stream() → HTTP POST
|
||||
|
|
@ -55,7 +55,7 @@ HTTP SSE bytes
|
|||
→ Scheme.parse_event() → Event (統一型)
|
||||
→ Timeline.dispatch() → Handler.on_event()
|
||||
→ TextBlockCollector / ToolCallCollector
|
||||
→ Worker: 履歴に追加、ツール実行判定
|
||||
→ Engine: 履歴に追加、ツール実行判定
|
||||
```
|
||||
|
||||
## 内部型
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# llm-worker 要件
|
||||
# llm-engine 要件
|
||||
|
||||
## 前提
|
||||
|
||||
|
|
@ -12,23 +12,23 @@ c. ツール・フックの基本的なスキーマ自動化を提供する
|
|||
|
||||
メッセージの送信と生成のResume、一時停止/再開。
|
||||
|
||||
- `Worker::run()` でターンを開始
|
||||
- `Engine::run()` でターンを開始
|
||||
- フックから `Pause` を返してターンを一時停止
|
||||
- `Worker::resume()` でユーザーメッセージを追加せず継続
|
||||
- `Engine::resume()` でユーザーメッセージを追加せず継続
|
||||
- AIは中断を認識せず、継続として処理する
|
||||
|
||||
**実装**: `worker.rs` — `resume()`, `get_pending_tool_calls()`, `WorkerResult::Paused`
|
||||
**実装**: `engine.rs` — `resume()`, `get_pending_tool_calls()`, `EngineResult::Paused`
|
||||
|
||||
### R2: 暗黙的KVキャッシュ保証
|
||||
|
||||
キャッシュを破壊しうる操作を明示的にブロックせずとも、いつの間にかキャッシュ破壊してた状態にはしたくない。
|
||||
|
||||
- Type-stateパターン(`Mutable` / `CacheLocked`)でコンパイル時に保証
|
||||
- `Worker::lock()` でCacheLocked状態に遷移
|
||||
- `Engine::lock()` でCacheLocked状態に遷移
|
||||
- CacheLocked状態ではシステムプロンプトや履歴の変更APIが型レベルで利用不可
|
||||
- `locked_prefix_len` でプレフィックスの不変性を追跡
|
||||
|
||||
**実装**: `state.rs` (sealed trait), `worker.rs` (state-specific impl blocks)
|
||||
**実装**: `state.rs` (sealed trait), `engine.rs` (state-specific impl blocks)
|
||||
|
||||
### R3: ツール・フックスキーマ自動化
|
||||
|
||||
|
|
@ -36,13 +36,13 @@ c. ツール・フックの基本的なスキーマ自動化を提供する
|
|||
- `#[tool_registry]` マクロでツールサーバーを自動構成
|
||||
- `Hook` traitで10種のフックポイント
|
||||
|
||||
**実装**: `llm-worker-macros/`, `tool.rs`, `tool_server.rs`, `hook.rs`
|
||||
**実装**: `llm-engine-macros/`, `tool.rs`, `tool_server.rs`, `hook.rs`
|
||||
|
||||
### R4: フックは上層の関心事
|
||||
|
||||
フックはLLMクライアント層ではなく、Worker(オーケストレーション)層に配置する。
|
||||
フックはLLMクライアント層ではなく、Engine(オーケストレーション)層に配置する。
|
||||
|
||||
- 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)
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
//! Worker cancellation demo
|
||||
//! Engine cancellation demo
|
||||
//!
|
||||
//! Example of cancelling from another thread during streaming
|
||||
|
||||
use llm_worker::llm_client::scheme::{Scheme, anthropic::AnthropicScheme};
|
||||
use llm_worker::llm_client::transport::{HttpTransport, ResolvedAuth};
|
||||
use llm_worker::{Worker, WorkerResult};
|
||||
use llm_engine::llm_client::scheme::{Scheme, anthropic::AnthropicScheme};
|
||||
use llm_engine::llm_client::transport::{HttpTransport, ResolvedAuth};
|
||||
use llm_engine::{Engine, EngineResult};
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::main]
|
||||
|
|
@ -28,29 +28,29 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let cap = scheme.default_capability();
|
||||
let base_url = scheme.default_base_url().to_string();
|
||||
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");
|
||||
|
||||
// Get cancel sender before run (Mutable state)
|
||||
let cancel_tx = worker.cancel_sender();
|
||||
let cancel_tx = engine.cancel_sender();
|
||||
|
||||
// Task: Cancel after 2 seconds
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
println!("\n🛑 Cancelling worker...");
|
||||
println!("\n🛑 Cancelling engine...");
|
||||
let _ = cancel_tx.send(()).await;
|
||||
});
|
||||
|
||||
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 {
|
||||
WorkerResult::Finished => println!("✅ Task completed normally"),
|
||||
WorkerResult::Paused => println!("⏸️ Task paused"),
|
||||
WorkerResult::LimitReached => println!("🔒 Turn limit reached"),
|
||||
WorkerResult::Yielded => println!("↩️ Task yielded"),
|
||||
EngineResult::Finished => println!("✅ Task completed normally"),
|
||||
EngineResult::Paused => println!("⏸️ Task paused"),
|
||||
EngineResult::LimitReached => println!("🔒 Turn limit reached"),
|
||||
EngineResult::Yielded => println!("↩️ Task yielded"),
|
||||
},
|
||||
Err(e) => {
|
||||
println!("❌ Task error: {}", e);
|
||||
|
|
@ -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).
|
||||
//! Demonstrates tool registration and execution, and streaming response display.
|
||||
|
|
@ -12,22 +12,22 @@
|
|||
//! echo "OPENAI_API_KEY=your-api-key" >> .env
|
||||
//!
|
||||
//! # Anthropic (default)
|
||||
//! cargo run --example worker_cli
|
||||
//! cargo run --example engine_cli
|
||||
//!
|
||||
//! # Gemini
|
||||
//! cargo run --example worker_cli -- --provider gemini
|
||||
//! cargo run --example engine_cli -- --provider gemini
|
||||
//!
|
||||
//! # OpenAI
|
||||
//! cargo run --example worker_cli -- --provider openai --model gpt-4o
|
||||
//! cargo run --example engine_cli -- --provider openai --model gpt-4o
|
||||
//!
|
||||
//! # Ollama (local)
|
||||
//! cargo run --example worker_cli -- --provider ollama --model llama3.2
|
||||
//! cargo run --example engine_cli -- --provider ollama --model llama3.2
|
||||
//!
|
||||
//! # 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
|
||||
//! cargo run --example worker_cli -- --help
|
||||
//! cargo run --example engine_cli -- --help
|
||||
//! ```
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -39,8 +39,8 @@ use tracing::info;
|
|||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use llm_worker::{
|
||||
Worker,
|
||||
use llm_engine::{
|
||||
Engine,
|
||||
interceptor::{Interceptor, PostToolAction, ToolResultInfo},
|
||||
llm_client::{
|
||||
LlmClient,
|
||||
|
|
@ -52,7 +52,7 @@ use llm_worker::{
|
|||
},
|
||||
timeline::{Handler, TextBlockEvent, TextBlockKind, ToolUseBlockEvent, ToolUseBlockKind},
|
||||
};
|
||||
use llm_worker_macros::tool_registry;
|
||||
use llm_engine_macros::tool_registry;
|
||||
|
||||
// Required imports for macro expansion
|
||||
use schemars;
|
||||
|
|
@ -114,8 +114,8 @@ impl Provider {
|
|||
|
||||
/// Interactive CLI client supporting multiple LLM providers
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "worker-cli")]
|
||||
#[command(about = "Interactive CLI client for multiple LLM providers using Worker")]
|
||||
#[command(name = "engine-cli")]
|
||||
#[command(about = "Interactive CLI client for multiple LLM providers using Engine")]
|
||||
#[command(version)]
|
||||
struct Args {
|
||||
/// Provider to use
|
||||
|
|
@ -393,7 +393,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
dotenv::dotenv().ok();
|
||||
|
||||
// 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
|
||||
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!(
|
||||
provider = ?args.provider,
|
||||
model = ?args.model,
|
||||
"Starting worker CLI"
|
||||
"Starting engine CLI"
|
||||
);
|
||||
|
||||
// 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());
|
||||
|
||||
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;
|
||||
println!("╔{}╗", "═".repeat(border_len));
|
||||
println!("║ {} ║", title);
|
||||
|
|
@ -453,34 +453,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
};
|
||||
|
||||
// Create Worker
|
||||
let mut worker = Worker::new(client);
|
||||
// Create Engine
|
||||
let mut engine = Engine::new(client);
|
||||
|
||||
let tool_call_names = Arc::new(Mutex::new(HashMap::new()));
|
||||
|
||||
// Set system prompt
|
||||
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)
|
||||
if !args.no_tools {
|
||||
let app = AppContext;
|
||||
worker.register_tool(app.get_current_time_definition());
|
||||
worker.register_tool(app.calculate_definition());
|
||||
engine.register_tool(app.get_current_time_definition());
|
||||
engine.register_tool(app.calculate_definition());
|
||||
}
|
||||
|
||||
// Register streaming display handlers
|
||||
worker
|
||||
engine
|
||||
.timeline_mut()
|
||||
.on_text_block(StreamingPrinter::new())
|
||||
.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
|
||||
if let Some(prompt) = args.prompt {
|
||||
match worker.run(&prompt).await {
|
||||
match engine.run(&prompt).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("\n❌ Error: {}", e);
|
||||
|
|
@ -504,8 +504,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let mut locked = match worker.run(first_input).await {
|
||||
Ok(out) => out.worker,
|
||||
let mut locked = match engine.run(first_input).await {
|
||||
Ok(out) => out.engine,
|
||||
Err(e) => {
|
||||
eprintln!("\n❌ Error: {}", e);
|
||||
return Ok(());
|
||||
|
|
@ -20,10 +20,10 @@ mod recorder;
|
|||
mod scenarios;
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use llm_worker::llm_client::scheme::{
|
||||
use llm_engine::llm_client::scheme::{
|
||||
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> {
|
||||
let cap = scheme.default_capability();
|
||||
|
|
@ -225,7 +225,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
|
||||
println!("\n✅ Done!");
|
||||
println!("Run tests with: cargo test -p worker");
|
||||
println!("Run tests with: cargo test -p engine");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ use std::path::Path;
|
|||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use futures::StreamExt;
|
||||
use llm_worker::llm_client::{LlmClient, Request};
|
||||
use llm_engine::llm_client::{LlmClient, Request};
|
||||
|
||||
/// Recorded event
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
|
|
@ -79,7 +79,7 @@ pub async fn record_request<C: LlmClient>(
|
|||
}
|
||||
|
||||
// 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)?;
|
||||
|
||||
let filepath = fixtures_dir.join(format!("{}.jsonl", output_name));
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! 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
|
||||
pub struct TestScenario {
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//! Closure-based event callback API
|
||||
//!
|
||||
//! 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.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -18,13 +18,13 @@ use crate::tool::ToolCall;
|
|||
|
||||
/// 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()`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.on_text_block(|block| {
|
||||
/// engine.on_text_block(|block| {
|
||||
/// block.on_delta(|text| print!("{}", text));
|
||||
/// 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.
|
||||
///
|
||||
/// 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`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.on_tool_use_block(|start, block| {
|
||||
/// engine.on_tool_use_block(|start, block| {
|
||||
/// println!("Tool: {} ({})", start.name, start.id);
|
||||
/// block.on_delta(|json| { /* streaming JSON fragment */ });
|
||||
/// block.on_stop(|call| println!("Done: {}", call.name));
|
||||
|
|
@ -22,19 +22,19 @@ use crate::{
|
|||
ToolDefinition, error::is_retryable, event::Event, retry::RetryPolicy,
|
||||
transport::DEFAULT_FIRST_STREAM_EVENT_TIMEOUT, types::parse_tool_arguments,
|
||||
},
|
||||
state::{Locked, Mutable, WorkerState},
|
||||
state::{EngineState, Locked, Mutable},
|
||||
timeline::event::{ErrorEvent, StatusEvent, UsageEvent},
|
||||
timeline::{TextBlockCollector, ThinkingBlockCollector, Timeline, ToolCallCollector},
|
||||
tool::{
|
||||
ToolCall, ToolDefinition as WorkerToolDefinition, ToolError, ToolExecutionContext,
|
||||
ToolCall, ToolDefinition as EngineToolDefinition, ToolError, ToolExecutionContext,
|
||||
ToolOutputLimits, ToolResult, truncate_content,
|
||||
},
|
||||
tool_server::{ToolServer, ToolServerHandle},
|
||||
};
|
||||
|
||||
/// Worker errors
|
||||
/// Engine errors
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum WorkerError {
|
||||
pub enum EngineError {
|
||||
/// Client error
|
||||
#[error("Client error: {0}")]
|
||||
Client(#[from] ClientError),
|
||||
|
|
@ -60,17 +60,17 @@ pub enum ToolRegistryError {
|
|||
DuplicateName(String),
|
||||
}
|
||||
|
||||
/// Worker configuration
|
||||
/// Engine configuration
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct WorkerConfig {
|
||||
pub struct EngineConfig {
|
||||
// Reserved for future extensions (currently empty)
|
||||
_private: (),
|
||||
}
|
||||
|
||||
/// Worker execution result (status)
|
||||
/// Engine execution result (status)
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkerResult {
|
||||
pub enum EngineResult {
|
||||
/// Completed (waiting for user input)
|
||||
Finished,
|
||||
/// Paused (can be resumed)
|
||||
|
|
@ -85,14 +85,14 @@ pub enum WorkerResult {
|
|||
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.
|
||||
pub struct RunOutput<C: LlmClient> {
|
||||
/// The Worker, now in Locked state.
|
||||
pub worker: Worker<C, Locked>,
|
||||
/// Contains the `Locked` Engine (ready for subsequent runs) and the outcome.
|
||||
pub struct EngineRunOutput<C: LlmClient> {
|
||||
/// The Engine, now in Locked state.
|
||||
pub engine: Engine<C, Locked>,
|
||||
/// Outcome of the turn.
|
||||
pub result: WorkerResult,
|
||||
pub result: EngineResult,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// - [`Locked`]: Cache-protected state. Prefix context is immutable; only `run()` / `resume()` are available.
|
||||
///
|
||||
/// Calling `run()` on a `Mutable` Worker consumes it and returns a
|
||||
/// `Locked` Worker together with the result. This ensures the
|
||||
/// Calling `run()` on a `Mutable` Engine consumes it and returns a
|
||||
/// `Locked` Engine together with the result. This ensures the
|
||||
/// cache prefix is fixed for optimal KV cache hit rate.
|
||||
///
|
||||
/// ```ignore
|
||||
/// let mut worker = Worker::new(client)
|
||||
/// let mut engine = Engine::new(client)
|
||||
/// .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 }
|
||||
/// let out = worker.run("Hello").await?;
|
||||
/// let mut worker = out.worker;
|
||||
/// // Mutable::run() consumes self → EngineRunOutput { engine: Locked, result }
|
||||
/// let out = engine.run("Hello").await?;
|
||||
/// let mut engine = out.engine;
|
||||
///
|
||||
/// // Locked::run() borrows &mut self
|
||||
/// worker.run("Follow-up").await?;
|
||||
/// engine.run("Follow-up").await?;
|
||||
///
|
||||
/// // To edit between turns, unlock back to Mutable
|
||||
/// let mut worker = worker.unlock();
|
||||
/// worker.truncate_history(5);
|
||||
/// let out = worker.run("Continue").await?;
|
||||
/// let mut worker = out.worker;
|
||||
/// let mut engine = engine.unlock();
|
||||
/// engine.truncate_history(5);
|
||||
/// let out = engine.run("Continue").await?;
|
||||
/// let mut engine = out.engine;
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct LlmRetryNotice {
|
||||
|
|
@ -152,7 +152,7 @@ enum StreamCompletion {
|
|||
Interrupted { reason: String },
|
||||
}
|
||||
|
||||
pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
||||
pub struct Engine<C: LlmClient, S: EngineState = Mutable> {
|
||||
/// LLM client
|
||||
client: C,
|
||||
/// Retry policy for opening an LLM response stream.
|
||||
|
|
@ -172,22 +172,22 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
|||
interceptor: Box<dyn Interceptor>,
|
||||
/// System prompt
|
||||
system_prompt: Option<String>,
|
||||
/// Item history (owned by Worker)
|
||||
/// Item history (owned by Engine)
|
||||
history: Vec<Item>,
|
||||
/// History length at lock time (only meaningful in Locked state)
|
||||
locked_prefix_len: usize,
|
||||
/// 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;
|
||||
/// today retry is not implemented so AgentTurn and LlmCall fire 1:1
|
||||
/// and the increment site (the LLM-call loop) is shared.
|
||||
/// `max_turns` is interpreted as a per-`run()` AgentTurn cap.
|
||||
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.
|
||||
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
|
||||
/// resumed pending tool-call set.
|
||||
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
|
||||
/// stream events become visible.
|
||||
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
|
||||
/// can be forwarded to the user — distinct from `tracing::warn!`,
|
||||
/// which is for developer-facing logs.
|
||||
|
|
@ -223,7 +223,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
|||
/// enters history.
|
||||
tool_result_cbs: Vec<Box<dyn Fn(&ToolResult) + Send + Sync>>,
|
||||
/// 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.
|
||||
history_append_cbs: Vec<Box<dyn Fn(&Item) + Send + Sync>>,
|
||||
/// Request configuration (max_tokens, temperature, etc.)
|
||||
|
|
@ -260,7 +260,7 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
|
|||
_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) {
|
||||
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() {}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.on_text_block(|block| {
|
||||
/// engine.on_text_block(|block| {
|
||||
/// block.on_delta(|text| print!("{}", text));
|
||||
/// block.on_stop(|full_text| println!("\n--- {} chars ---", full_text.len()));
|
||||
/// });
|
||||
|
|
@ -335,7 +335,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.on_tool_use_block(|start, block| {
|
||||
/// engine.on_tool_use_block(|start, block| {
|
||||
/// println!("Tool: {} ({})", start.name, start.id);
|
||||
/// block.on_delta(|json| { /* streaming JSON fragment */ });
|
||||
/// 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.
|
||||
///
|
||||
/// 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).
|
||||
/// This channel is separate from `tracing::warn!`, which remains
|
||||
/// 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.
|
||||
pub fn on_history_append(&mut self, callback: impl Fn(&Item) + Send + Sync + 'static) {
|
||||
self.history_append_cbs.push(Box::new(callback));
|
||||
|
|
@ -639,7 +639,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
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).
|
||||
pub fn llm_call_count(&self) -> usize {
|
||||
self.llm_call_count
|
||||
|
|
@ -657,7 +657,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.set_max_tokens(4096);
|
||||
/// engine.set_max_tokens(4096);
|
||||
/// ```
|
||||
pub fn set_max_tokens(&mut self, max_tokens: u32) {
|
||||
self.request_config.max_tokens = Some(max_tokens);
|
||||
|
|
@ -671,7 +671,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.set_temperature(0.7);
|
||||
/// engine.set_temperature(0.7);
|
||||
/// ```
|
||||
pub fn set_temperature(&mut self, temperature: f32) {
|
||||
self.request_config.temperature = Some(temperature);
|
||||
|
|
@ -682,7 +682,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.set_top_p(0.9);
|
||||
/// engine.set_top_p(0.9);
|
||||
/// ```
|
||||
pub fn set_top_p(&mut self, top_p: f32) {
|
||||
self.request_config.top_p = Some(top_p);
|
||||
|
|
@ -695,7 +695,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.set_top_k(40);
|
||||
/// engine.set_top_k(40);
|
||||
/// ```
|
||||
pub fn set_top_k(&mut self, top_k: u32) {
|
||||
self.request_config.top_k = Some(top_k);
|
||||
|
|
@ -706,7 +706,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// worker.add_stop_sequence("\n\n");
|
||||
/// engine.add_stop_sequence("\n\n");
|
||||
/// ```
|
||||
pub fn add_stop_sequence(&mut self, sequence: impl Into<String>) {
|
||||
self.request_config.stop_sequences.push(sequence.into());
|
||||
|
|
@ -730,23 +730,23 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
/// Cancel 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
|
||||
///
|
||||
/// ```ignore
|
||||
/// 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
|
||||
/// let worker_clone = worker.clone();
|
||||
/// let worker_clone = engine.clone();
|
||||
/// tokio::spawn(async move {
|
||||
/// let mut w = worker_clone.lock().unwrap();
|
||||
/// w.run("Long task...").await
|
||||
/// });
|
||||
///
|
||||
/// // Cancel
|
||||
/// worker.lock().unwrap().cancel();
|
||||
/// engine.lock().unwrap().cancel();
|
||||
/// ```
|
||||
pub fn cancel(&self) {
|
||||
let _ = self.cancel_tx.try_send(());
|
||||
|
|
@ -849,15 +849,15 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
///
|
||||
async fn finalize_interruption<T>(
|
||||
&mut self,
|
||||
result: Result<T, WorkerError>,
|
||||
) -> Result<T, WorkerError> {
|
||||
result: Result<T, EngineError>,
|
||||
) -> Result<T, EngineError> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => {
|
||||
self.last_run_interrupted = true;
|
||||
let reason = match &err {
|
||||
WorkerError::Aborted(reason) => reason.clone(),
|
||||
WorkerError::Cancelled => "Cancelled".to_string(),
|
||||
EngineError::Aborted(reason) => reason.clone(),
|
||||
EngineError::Cancelled => "Cancelled".to_string(),
|
||||
_ => err.to_string(),
|
||||
};
|
||||
self.interceptor.on_abort(&reason).await;
|
||||
|
|
@ -913,7 +913,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
async fn execute_tools(
|
||||
&mut self,
|
||||
tool_calls: Vec<ToolCall>,
|
||||
) -> Result<ToolExecutionResult, WorkerError> {
|
||||
) -> Result<ToolExecutionResult, EngineError> {
|
||||
use futures::future::join_all;
|
||||
|
||||
// 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) => {
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Aborted(reason));
|
||||
return Err(EngineError::Aborted(reason));
|
||||
}
|
||||
PreToolAction::Pause => {
|
||||
self.last_run_interrupted = true;
|
||||
|
|
@ -1010,7 +1010,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
}
|
||||
self.timeline.abort_current_block();
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Cancelled);
|
||||
return Err(EngineError::Cancelled);
|
||||
}
|
||||
};
|
||||
results.extend(synthetic_results);
|
||||
|
|
@ -1032,7 +1032,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
PostToolAction::Continue => {}
|
||||
PostToolAction::Abort(reason) => {
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Aborted(reason));
|
||||
return Err(EngineError::Aborted(reason));
|
||||
}
|
||||
}
|
||||
// Reflect interceptor-modified results
|
||||
|
|
@ -1084,14 +1084,14 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
}
|
||||
|
||||
/// 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();
|
||||
let tool_definitions = self.build_tool_definitions();
|
||||
|
||||
info!(
|
||||
item_count = self.history.len(),
|
||||
tool_count = tool_definitions.len(),
|
||||
"Starting worker run"
|
||||
"Starting engine run"
|
||||
);
|
||||
|
||||
// Resume pending tool calls from a previous Pause
|
||||
|
|
@ -1109,7 +1109,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
info!("Execution cancelled");
|
||||
self.timeline.abort_current_block();
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Cancelled);
|
||||
return Err(EngineError::Cancelled);
|
||||
}
|
||||
|
||||
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
|
||||
// estimator are configured, drop ToolResult.content from
|
||||
// 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.
|
||||
if let (Some(config), Some(token_estimator), Some(savings_estimator)) = (
|
||||
&self.prune_config,
|
||||
|
|
@ -1199,7 +1199,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
cb(current_turn);
|
||||
}
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Aborted(reason));
|
||||
return Err(EngineError::Aborted(reason));
|
||||
}
|
||||
PreRequestAction::YieldWith(items) => {
|
||||
self.append_history_items(items.clone());
|
||||
|
|
@ -1209,7 +1209,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
cb(current_turn);
|
||||
}
|
||||
self.last_run_interrupted = true;
|
||||
return Ok(WorkerResult::Yielded);
|
||||
return Ok(EngineResult::Yielded);
|
||||
}
|
||||
PreRequestAction::Yield => {
|
||||
info!("Yielded by interceptor");
|
||||
|
|
@ -1217,7 +1217,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
cb(current_turn);
|
||||
}
|
||||
self.last_run_interrupted = true;
|
||||
return Ok(WorkerResult::Yielded);
|
||||
return Ok(EngineResult::Yielded);
|
||||
}
|
||||
PreRequestAction::ContinueWith(items) => {
|
||||
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
|
||||
// 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.
|
||||
let current_llm_call = self.llm_call_count;
|
||||
for cb in &self.llm_call_start_cbs {
|
||||
|
|
@ -1262,7 +1262,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
stream_continuations += 1;
|
||||
if stream_continuations > MAX_STREAM_CONTINUATIONS {
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Client(ClientError::Api {
|
||||
return Err(EngineError::Client(ClientError::Api {
|
||||
status: None,
|
||||
code: None,
|
||||
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 {
|
||||
TurnEndAction::Finish => {
|
||||
self.last_run_interrupted = false;
|
||||
return Ok(WorkerResult::Finished);
|
||||
return Ok(EngineResult::Finished);
|
||||
}
|
||||
TurnEndAction::ContinueWithMessages(additional) => {
|
||||
self.append_history_items(additional);
|
||||
|
|
@ -1323,7 +1323,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
}
|
||||
TurnEndAction::Pause => {
|
||||
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"
|
||||
);
|
||||
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,
|
||||
turn: usize,
|
||||
llm_call: usize,
|
||||
) -> Result<ResponseStream, WorkerError> {
|
||||
) -> Result<ResponseStream, EngineError> {
|
||||
let policy = self.retry_policy.clone();
|
||||
let started = Instant::now();
|
||||
let mut failed_attempt: u32 = 0;
|
||||
|
|
@ -1385,7 +1385,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
);
|
||||
self.timeline.abort_current_block();
|
||||
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.last_run_interrupted = true;
|
||||
return Err(WorkerError::Cancelled);
|
||||
return Err(EngineError::Cancelled);
|
||||
}
|
||||
};
|
||||
match first_event_result {
|
||||
|
|
@ -1459,7 +1459,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
let next_failed_attempt = failed_attempt + 1;
|
||||
if next_failed_attempt >= policy.max_attempts || !is_retryable(&err) {
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Client(err));
|
||||
return Err(EngineError::Client(err));
|
||||
}
|
||||
|
||||
let wait = err
|
||||
|
|
@ -1468,7 +1468,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
let elapsed = started.elapsed();
|
||||
if elapsed + wait > policy.total_timeout {
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Client(err));
|
||||
return Err(EngineError::Client(err));
|
||||
}
|
||||
|
||||
warn!(
|
||||
|
|
@ -1497,7 +1497,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
}
|
||||
self.timeline.abort_current_block();
|
||||
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,
|
||||
turn: usize,
|
||||
llm_call: usize,
|
||||
) -> Result<StreamCompletion, WorkerError> {
|
||||
) -> Result<StreamCompletion, EngineError> {
|
||||
debug!(
|
||||
item_count = request.items.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.flush_usage();
|
||||
self.last_run_interrupted = true;
|
||||
return Err(WorkerError::Client(ClientError::Api {
|
||||
return Err(EngineError::Client(ClientError::Api {
|
||||
status: None,
|
||||
code: err.code.clone(),
|
||||
message: err.message.clone(),
|
||||
|
|
@ -1579,7 +1579,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
|
|||
self.timeline.abort_current_block();
|
||||
self.timeline.flush_usage();
|
||||
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(
|
||||
&mut self,
|
||||
tool_calls: Vec<ToolCall>,
|
||||
) -> Result<Option<WorkerResult>, WorkerError> {
|
||||
) -> Result<Option<EngineResult>, EngineError> {
|
||||
match self.execute_tools(tool_calls).await {
|
||||
Ok(ToolExecutionResult::Paused) => {
|
||||
self.last_run_interrupted = true;
|
||||
Ok(Some(WorkerResult::Paused))
|
||||
Ok(Some(EngineResult::Paused))
|
||||
}
|
||||
Ok(ToolExecutionResult::Completed(results)) => {
|
||||
// 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> {
|
||||
/// Create a new Worker (in Mutable state)
|
||||
impl<C: LlmClient> Engine<C, Mutable> {
|
||||
/// Create a new Engine (in Mutable state)
|
||||
pub fn new(client: C) -> Self {
|
||||
let text_block_collector = TextBlockCollector::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.
|
||||
/// Duplicate name detection occurs at that point and surfaces as
|
||||
/// [`WorkerError::ToolRegistry`].
|
||||
pub fn register_tool(&mut self, factory: WorkerToolDefinition) {
|
||||
/// [`EngineError::ToolRegistry`].
|
||||
pub fn register_tool(&mut self, factory: EngineToolDefinition) {
|
||||
self.tool_server.register_tool(factory);
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
|
@ -1719,7 +1719,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let worker = Worker::new(client)
|
||||
/// let engine = Engine::new(client)
|
||||
/// .system_prompt("You are a helpful assistant.")
|
||||
/// .max_tokens(4096);
|
||||
/// ```
|
||||
|
|
@ -1733,7 +1733,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let worker = Worker::new(client)
|
||||
/// let engine = Engine::new(client)
|
||||
/// .temperature(0.7);
|
||||
/// ```
|
||||
pub fn temperature(mut self, temperature: f32) -> Self {
|
||||
|
|
@ -1768,7 +1768,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// .with_max_tokens(4096)
|
||||
/// .with_temperature(0.7);
|
||||
///
|
||||
/// let worker = Worker::new(client)
|
||||
/// let engine = Engine::new(client)
|
||||
/// .system_prompt("...")
|
||||
/// .with_config(config);
|
||||
/// ```
|
||||
|
|
@ -1791,7 +1791,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let worker = Worker::new(client)
|
||||
/// let engine = Engine::new(client)
|
||||
/// .temperature(0.7)
|
||||
/// .top_k(40)
|
||||
/// .validate()?; // Error if using OpenAI since top_k is not supported
|
||||
|
|
@ -1799,13 +1799,13 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
///
|
||||
/// # Returns
|
||||
/// * `Ok(Self)` - Validation successful
|
||||
/// * `Err(WorkerError::ConfigWarnings)` - Has unsupported settings
|
||||
pub fn validate(self) -> Result<Self, WorkerError> {
|
||||
/// * `Err(EngineError::ConfigWarnings)` - Has unsupported settings
|
||||
pub fn validate(self) -> Result<Self, EngineError> {
|
||||
let warnings = self.client.validate_config(&self.request_config);
|
||||
if warnings.is_empty() {
|
||||
Ok(self)
|
||||
} 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
|
||||
/// 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.
|
||||
pub fn append_history(&mut self, items: impl IntoIterator<Item = Item>) {
|
||||
self.append_history_items(items);
|
||||
|
|
@ -1855,7 +1855,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
|
||||
/// Apply configuration (reserved for future extensions)
|
||||
#[allow(dead_code)]
|
||||
pub fn config(self, _config: WorkerConfig) -> Self {
|
||||
pub fn config(self, _config: EngineConfig) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -1864,13 +1864,16 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// This is the primary entry point for first use. Equivalent to
|
||||
/// `self.lock()` followed by `locked.run(user_input)`.
|
||||
///
|
||||
/// Subsequent runs can use [`Worker<C, Locked>::run()`] directly.
|
||||
/// To edit state between turns, call [`unlock()`](Worker::unlock) first.
|
||||
pub async fn run(self, user_input: impl Into<String>) -> Result<RunOutput<C>, WorkerError> {
|
||||
/// Subsequent runs can use [`Engine<C, Locked>::run()`] directly.
|
||||
/// To edit state between turns, call [`unlock()`](Engine::unlock) first.
|
||||
pub async fn run(
|
||||
self,
|
||||
user_input: impl Into<String>,
|
||||
) -> Result<EngineRunOutput<C>, EngineError> {
|
||||
let mut locked = self.lock();
|
||||
let result = locked.run(user_input).await?;
|
||||
Ok(RunOutput {
|
||||
worker: locked,
|
||||
Ok(EngineRunOutput {
|
||||
engine: locked,
|
||||
result,
|
||||
})
|
||||
}
|
||||
|
|
@ -1878,11 +1881,11 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
/// Resume from Paused, consuming self and transitioning to Locked.
|
||||
///
|
||||
/// 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 result = locked.resume().await?;
|
||||
Ok(RunOutput {
|
||||
worker: locked,
|
||||
Ok(EngineRunOutput {
|
||||
engine: locked,
|
||||
result,
|
||||
})
|
||||
}
|
||||
|
|
@ -1895,15 +1898,15 @@ impl<C: LlmClient> Worker<C, Mutable> {
|
|||
///
|
||||
/// Most callers should use [`run()`](Self::run) instead, which calls
|
||||
/// 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 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();
|
||||
let locked_prefix_len = self.history.len();
|
||||
Worker {
|
||||
Engine {
|
||||
client: self.client,
|
||||
retry_policy: self.retry_policy,
|
||||
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
|
||||
///
|
||||
/// 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(
|
||||
&mut self,
|
||||
user_input: impl Into<String>,
|
||||
) -> Result<WorkerResult, WorkerError> {
|
||||
) -> Result<EngineResult, EngineError> {
|
||||
self.reset_interruption_state();
|
||||
// Interceptor: on_prompt_submit
|
||||
let mut user_item = Item::user_message(user_input);
|
||||
|
|
@ -1963,7 +1966,7 @@ impl<C: LlmClient> Worker<C, Locked> {
|
|||
PromptAction::Cancel(reason) => {
|
||||
self.last_run_interrupted = true;
|
||||
return self
|
||||
.finalize_interruption(Err(WorkerError::Aborted(reason)))
|
||||
.finalize_interruption(Err(EngineError::Aborted(reason)))
|
||||
.await;
|
||||
}
|
||||
PromptAction::Continue => Vec::new(),
|
||||
|
|
@ -1980,7 +1983,7 @@ impl<C: LlmClient> Worker<C, Locked> {
|
|||
/// Resume execution (from Paused state)
|
||||
///
|
||||
/// 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();
|
||||
let result = self.run_turn_loop().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.
|
||||
/// Use only when you need to edit history.
|
||||
pub fn unlock(self) -> Worker<C, Mutable> {
|
||||
Worker {
|
||||
pub fn unlock(self) -> Engine<C, Mutable> {
|
||||
Engine {
|
||||
client: self.client,
|
||||
retry_policy: self.retry_policy,
|
||||
timeline: self.timeline,
|
||||
|
|
@ -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.
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ pub trait Kind {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// use llm_worker::timeline::{Handler, TextBlockEvent, TextBlockKind};
|
||||
/// use llm_engine::timeline::{Handler, TextBlockEvent, TextBlockKind};
|
||||
///
|
||||
/// struct TextCollector {
|
||||
/// texts: Vec<String>,
|
||||
|
|
@ -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
|
||||
//! 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.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
|
@ -36,13 +36,13 @@ pub enum PromptAction {
|
|||
pub enum PreRequestAction {
|
||||
/// Proceed normally.
|
||||
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
|
||||
/// 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>),
|
||||
/// 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
|
||||
/// usage accounting and compaction checks before the current LLM request is
|
||||
|
|
@ -52,7 +52,7 @@ pub enum PreRequestAction {
|
|||
Cancel(String),
|
||||
/// 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.
|
||||
Yield,
|
||||
}
|
||||
|
|
@ -129,9 +129,9 @@ pub struct ToolResultInfo {
|
|||
// 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
|
||||
/// richer implementations for approval flows, permission checks, etc.
|
||||
#[async_trait]
|
||||
|
|
@ -141,7 +141,7 @@ pub trait Interceptor: Send + Sync {
|
|||
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
|
||||
/// the persistent history (and therefore picked up by the per-turn
|
||||
/// 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
|
||||
/// of `worker.history` (after `pending_history_appends` and the
|
||||
/// Worker's own prune projection have been applied).
|
||||
/// of `engine.history` (after `pending_history_appends` and the
|
||||
/// Engine's own prune projection have been applied).
|
||||
///
|
||||
/// Direct mutations to `context` remain request-local and are not persisted.
|
||||
/// 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.
|
||||
async fn pre_llm_request(&self, _context: &mut Vec<Item>) -> PreRequestAction {
|
||||
PreRequestAction::Continue
|
||||
|
|
@ -194,7 +194,7 @@ pub trait Interceptor: Send + Sync {
|
|||
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.
|
||||
pub(crate) struct DefaultInterceptor;
|
||||
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
//! llm-worker - LLM Worker Library
|
||||
//! llm-engine - LLM Engine Library
|
||||
//!
|
||||
//! Provides components for managing interactions with LLMs.
|
||||
//!
|
||||
//! # 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
|
||||
//! - [`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
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use llm_worker::{Worker, Item};
|
||||
//! use llm_engine::{Engine, Item};
|
||||
//!
|
||||
//! // Create a Worker
|
||||
//! let mut worker = Worker::new(client)
|
||||
//! // Create a Engine
|
||||
//! let mut engine = Engine::new(client)
|
||||
//! .system_prompt("You are a helpful assistant.");
|
||||
//!
|
||||
//! // Register tools (optional)
|
||||
//! // worker.register_tool(my_tool_definition)?;
|
||||
//! // engine.register_tool(my_tool_definition)?;
|
||||
//!
|
||||
//! // Run the interaction
|
||||
//! let history = worker.run("Hello!").await?;
|
||||
//! let history = engine.run("Hello!").await?;
|
||||
//! ```
|
||||
//!
|
||||
//! # Cache Protection
|
||||
|
|
@ -31,15 +31,15 @@
|
|||
//! call `unlock_cache()` first; the next `run()` re-locks automatically.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! worker.run("user input").await?;
|
||||
//! worker.unlock_cache();
|
||||
//! worker.set_system_prompt("new prompt");
|
||||
//! worker.run("next input").await?;
|
||||
//! engine.run("user input").await?;
|
||||
//! engine.unlock_cache();
|
||||
//! engine.set_system_prompt("new prompt");
|
||||
//! engine.run("next input").await?;
|
||||
//! ```
|
||||
|
||||
mod engine;
|
||||
mod handler;
|
||||
mod message;
|
||||
mod worker;
|
||||
|
||||
pub(crate) mod callback;
|
||||
pub mod event;
|
||||
|
|
@ -54,11 +54,12 @@ pub mod tool_server;
|
|||
pub mod usage_record;
|
||||
|
||||
pub use callback::{TextBlockScope, ThinkingBlockScope, ToolUseBlockScope};
|
||||
pub use engine::{
|
||||
Engine, EngineConfig, EngineError, EngineResult, EngineRunOutput, LlmRetryNotice,
|
||||
ToolRegistryError,
|
||||
};
|
||||
pub use handler::ToolUseBlockStart;
|
||||
pub use interceptor::Interceptor;
|
||||
pub use message::{ContentPart, Item, Message, Role};
|
||||
pub use tool::{ToolCall, ToolExecutionContext, ToolOutputLimits, ToolResult};
|
||||
pub use usage_record::UsageRecord;
|
||||
pub use worker::{
|
||||
LlmRetryNotice, RunOutput, ToolRegistryError, Worker, WorkerConfig, WorkerError, WorkerResult,
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
//! `Scheme` 実装と通信層が要求する認証要件、および動的認証プロバイダ。
|
||||
//!
|
||||
//! マニフェスト側の型(`ModelConfig` / `SchemeKind` / `AuthRef`)は
|
||||
//! `crates/manifest` に置き、llm-worker はそれを知らずに済む。
|
||||
//! `crates/manifest` に置き、llm-engine はそれを知らずに済む。
|
||||
//! `AuthRequirement` は scheme が宣言する「この scheme はどんな認証を
|
||||
//! 期待するか」のランタイム記述で、manifest 側の `AuthRef` との
|
||||
//! 照合(`AuthRef → ResolvedAuth` 変換の適否)は `crates/provider`
|
||||
|
|
@ -36,7 +36,7 @@ pub enum AuthRequirement {
|
|||
/// Codex OAuth のように access_token が refresh で更新されたり、
|
||||
/// `ChatGPT-Account-Id` / `X-OpenAI-Fedramp` のような複数ヘッダを
|
||||
/// 同時に注入する必要があるケースで使う。実体は `crates/provider`
|
||||
/// 側に置き、llm-worker は trait を知るだけ。
|
||||
/// 側に置き、llm-engine は trait を知るだけ。
|
||||
///
|
||||
/// 返したヘッダはそのまま `HeaderMap` に挿入される。`Authorization`
|
||||
/// 含む scheme 既定の認証ヘッダは送出されないので、必要なら
|
||||
|
|
@ -81,7 +81,7 @@ impl Clone for Box<dyn LlmClient> {
|
|||
|
||||
/// `Box<dyn LlmClient>` に対する `LlmClient` の実装
|
||||
///
|
||||
/// これにより、動的ディスパッチを使用するクライアントも `Worker` で利用可能になる。
|
||||
/// これにより、動的ディスパッチを使用するクライアントも `Engine` で利用可能になる。
|
||||
#[async_trait]
|
||||
impl LlmClient for Box<dyn LlmClient> {
|
||||
async fn stream(&self, request: Request) -> Result<ResponseStream, ClientError> {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
//! LLM response stream を開く前の transient error 向けリトライポリシー。
|
||||
//!
|
||||
//! Worker が `LlmClient::stream` の open error に対して `is_retryable` を見て
|
||||
//! Engine が `LlmClient::stream` の open error に対して `is_retryable` を見て
|
||||
//! retry / backoff / TUI event / cancellation をまとめて管理する。
|
||||
//! SSE 読み出し開始後の失敗は対象外。
|
||||
|
||||
|
|
@ -8,8 +8,8 @@ use std::time::Duration;
|
|||
|
||||
/// 指数バックオフ + ジッター + 累積タイムアウトを表すポリシー。
|
||||
///
|
||||
/// `Default` は llm-worker 全体の固定値を返す。manifest 経由の上書きが
|
||||
/// 必要になったら拡張する(現状は不要 → `tickets/llm-worker-transient-retry.md`)。
|
||||
/// `Default` は llm-engine 全体の固定値を返す。manifest 経由の上書きが
|
||||
/// 必要になったら拡張する(現状は不要 → `tickets/llm-engine-transient-retry.md`)。
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RetryPolicy {
|
||||
/// 指数の基準値。`base * 2^attempt` を `cap` で頭打ちにした上限から
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user