Documentation
¶
Index ¶
- Constants
- Variables
- func ErrNeedBookLanguageMessage(bookDir string) error
- func LoadBundleFor(cfg bootstrap.Config, outDir, lang string) assets.Bundle
- func LogEvent(ev Event)
- func MaskAPIKey(value string) string
- func StreamToolHeader(tool string) string
- type APIKeyAction
- type AgentCacheStat
- type AgentContextSnapshot
- type AgentSnapshot
- type AgentUsage
- type Book
- type BudgetSentinel
- type ChapterAdvanceGate
- type ChapterText
- type CoCreateMessage
- type CoCreateReply
- type ConfiguredModel
- type DeleteBookResult
- type Event
- type Host
- func (h *Host) Abort() bool
- func (h *Host) AdvanceOneChapter() error
- func (h *Host) AskStoryPartner(ctx context.Context, req sp.Request) (sp.Result, error)
- func (h *Host) AvailableThinking(role string) []agentcore.ThinkingLevel
- func (h *Host) BookLanguage() (string, error)
- func (h *Host) Books() ([]Book, error)
- func (h *Host) CancelCoCreate()
- func (h *Host) CancelStoryPartner()
- func (h *Host) CheckChapterRevisions() ([]int, error)
- func (h *Host) Close()
- func (h *Host) CoCreateStream(ctx context.Context, history []CoCreateMessage, ...) (CoCreateReply, error)
- func (h *Host) CompletedChapters() ([]int, error)
- func (h *Host) ConfigureModels(draft ModelConfigurationDraft) error
- func (h *Host) ConfiguredModelOptions(provider string) []ConfiguredModel
- func (h *Host) ConfiguredModels(provider string) []string
- func (h *Host) ConfiguredProviders() []string
- func (h *Host) Continue(text string) error
- func (h *Host) CurrentModelSelection(role string) (string, string, bool)
- func (h *Host) CurrentThinking(role string) string
- func (h *Host) DeleteBook(dir string) error
- func (h *Host) Dir() string
- func (h *Host) Done() <-chan struct{}
- func (h *Host) Events() <-chan Event
- func (h *Host) Export(ctx context.Context, opts exp.Options) (*exp.Result, error)
- func (h *Host) FileLogError() error
- func (h *Host) ImportFrom(ctx context.Context, opts imp.Options) (<-chan imp.Event, error)
- func (h *Host) ImportResumeHint() string
- func (h *Host) ImportSimulationProfile(ctx context.Context, path string) (<-chan sim.Event, error)
- func (h *Host) InspectBook(dir string) (DeleteBookResult, error)
- func (h *Host) ModelConfiguration() ModelConfigurationSnapshot
- func (h *Host) NewBookDir(name string) (string, error)
- func (h *Host) PauseForCoCreate() bool
- func (h *Host) PrepareUserRules(rawPrompt string) error
- func (h *Host) ReadChapter(chapter int) (ChapterText, error)
- func (h *Host) ReadableChapters() ([]int, error)
- func (h *Host) Reopen(direction string) error
- func (h *Host) ReplayQueue(afterSeq int64) ([]domain.RuntimeQueueItem, error)
- func (h *Host) Resume() (Msg, error)
- func (h *Host) ResumeFromCoCreate(draft string) error
- func (h *Host) SetAdvanceMode(mode domain.ChapterAdvanceMode) error
- func (h *Host) SetBookLanguage(lang string) error
- func (h *Host) SetRoleThinking(role, level string) error
- func (h *Host) Simulate(ctx context.Context) (<-chan sim.Event, error)
- func (h *Host) Snapshot() UISnapshot
- func (h *Host) StageCoCreateStream(ctx context.Context, history []CoCreateMessage, ...) (CoCreateReply, error)
- func (h *Host) StartPrepared(rawRequirement string) error
- func (h *Host) Steer(text string) error
- func (h *Host) Stream() <-chan string
- func (h *Host) SwitchModel(role, provider, model string) error
- func (h *Host) SyncChapterRevisions(ctx context.Context) (*revision.Result, error)
- func (h *Host) TestModelConnection(ctx context.Context, draft ModelConfigurationDraft, modelName string) error
- type ModelConfigurationDraft
- type ModelConfigurationSnapshot
- type ModelRename
- type Msg
- type NewOption
- type OutlineSnapshot
- type ProviderSnapshot
- type UISnapshot
- type UsageTracker
- func (t *UsageTracker) LoadFromStore() (bool, error)
- func (t *UsageTracker) MissingAssistantUsage() int
- func (t *UsageTracker) OverallCacheBreaks() int
- func (t *UsageTracker) OverallCacheCapable() bool
- func (t *UsageTracker) OverallRecent() (cacheRead, input, samples int)
- func (t *UsageTracker) PerAgent() []AgentUsage
- func (t *UsageTracker) PerModel() []AgentUsage
- func (t *UsageTracker) Record(agentName, task string, msg agentcore.AgentMessage)
- func (t *UsageTracker) RecordSidecar(agentName, task string, u agentcore.Usage, provider, modelName string)
- func (t *UsageTracker) ReplaySessions(rootDir string) (int, error)
- func (t *UsageTracker) SaveNow() error
- func (t *UsageTracker) SavedUSD() float64
- func (t *UsageTracker) SetOnCost(cb func(total float64))
- func (t *UsageTracker) SetOnMissingUsage(cb func())
- func (t *UsageTracker) Snapshot() domain.UsageState
- func (t *UsageTracker) StartAutoSave(ctx context.Context)
- func (t *UsageTracker) Totals() (cost float64, input, output, cacheRead, cacheWrite int)
- func (t *UsageTracker) WaitAutoSave()
Constants ¶
const ( CoCreateProgressThinking = "thinking" CoCreateProgressReply = "reply" )
CoCreateProgressKind identifies the content type of a streaming callback.
const StreamClearSentinel = "\x00\x00CLEAR\x00\x00"
StreamClearSentinel gửi một mục qua streamCh để báo hiệu "xoá round đang stream". Không dùng clearCh riêng nữa — hai kênh không có thứ tự khiến header ✻ hay rơi xuống cuối round trước.
Variables ¶
var ErrBookExists = errors.New("truyện đã tồn tại")
ErrBookExists báo thư mục truyện đã tồn tại. Tách riêng để phía gọi (đặt tên ngẫu nhiên) phân biệt "trùng tên, thử tên khác" với lỗi thật bằng errors.Is thay vì so chuỗi thông báo.
var ErrBookInUse = errors.New("Thư mục truyện đã bị một instance " + buildversion.AppName + " khác chiếm")
ErrBookInUse nghĩa là cùng thư mục truyện đã bị một tiến trình khác chiếm. Nêu đúng tên chương trình từ AppName, vì đây là thông báo người dùng đọc được và phải khớp với tên binary họ sẽ chạy.
var ErrNeedBookLanguage = errors.New("book language not set")
ErrNeedBookLanguage báo truyện chưa khoá ngôn ngữ sáng tác và không thể hỏi (headless). Tách riêng để lớp trên biết đây là "cần người dùng chỉ định", không phải lỗi hệ thống — nên thông báo phải khác, và phải nêu cách chỉ định.
Functions ¶
func ErrNeedBookLanguageMessage ¶ added in v1.5.3
ErrNeedBookLanguageMessage là câu chữ cho trường hợp headless gặp truyện chưa khoá ngôn ngữ. Thân câu chữ nằm ở bootstrap vì main.go cần gọi trước khi dựng Host, không import host được.
func LoadBundleFor ¶ added in v1.5.3
LoadBundleFor dựng bộ tài nguyên theo ngôn ngữ đã quyết.
Tách hàm để dùng chung cho lúc khởi động và lúc chuyển truyện: nếu hai chỗ tự dựng khác nhau thì một chỗ sẽ quên ApplyLanguage — đúng loại lỗi từng xảy ra với Arbiter. Truyền LANG ĐÃ QUYẾT vào, không tự suy ra, để người gọi là nơi duy nhất quyết định (khoá theo truyện hay mặc định cấu hình).
func LogEvent ¶
func LogEvent(ev Event)
LogEvent records one UI / runtime event through the process logger. Summary is the display text; Detail is the full diagnostic payload and is used as the log body whenever it is present.
func MaskAPIKey ¶
MaskAPIKey chỉ giữ đầu-cuối vừa đủ nhận diện chứng thực; key ngắn che hết. TUI chỉ nhận kết quả này, không bao giờ giữ API Key đầy đủ trong cấu hình.
func StreamToolHeader ¶ added in v1.5.2
StreamToolHeader trả tiêu đề khối mà TUI dựng cho một tool ("✻ …"), hoặc rỗng nếu tool không có tiêu đề riêng (ví dụ draft_chapter chỉ hiện nội dung). Dùng để TUI biết trước chuỗi nào sẽ tới, phục vụ test; vòng đời thật vẫn do extractor ghi.
Types ¶
type APIKeyAction ¶
type APIKeyAction string
const ( APIKeyKeep APIKeyAction = "keep" APIKeyReplace APIKeyAction = "replace" APIKeyClear APIKeyAction = "clear" )
type AgentCacheStat ¶
type AgentCacheStat struct {
Role string
Model string
Input int
Output int
CacheRead int
CacheWrite int
Cost float64
Saved float64
CacheCapable bool
RecentCacheRead int
RecentInput int
RecentSamples int
}
AgentCacheStat is a single agent's cumulative cache hits (projected into the left column). HitRate = CacheRead / Input; Input already carries the "includes CacheRead" semantics at the litellm layer.
CacheCapable distinguishes the two kinds of 0% hit rate:
- true -> the model supports prompt cache, 0% means a badly designed prompt or an unstable prefix, and needs optimizing
- false -> the model/provider does not support prompt cache, 0% is expected and needs no investigation
Recent* is the hit data of the sliding window (the last N calls); comparing it with the cumulative total identifies "an early-drag problem" vs "a steady low hit rate".
type AgentContextSnapshot ¶
type AgentContextSnapshot struct {
Tokens int
ContextWindow int
Percent float64
Scope string
Strategy string
ActiveMessages int
SummaryMessages int
CompactedCount int
KeptCount int
}
AgentContextSnapshot is the Agent context usage.
type AgentSnapshot ¶
type AgentSnapshot struct {
Name string
State string
TaskID string
TaskKind string
Summary string
Tool string
Turn int
Context AgentContextSnapshot
UpdatedAt time.Time
}
AgentSnapshot is the display projection of an Agent's state.
type AgentUsage ¶
type AgentUsage struct {
Role string
Model string
Input int
Output int
CacheRead int
CacheWrite int
Cost float64
Saved float64
CacheCapable bool
RecentCacheRead int
RecentInput int
RecentSamples int
}
AgentUsage is a snapshot of one agent's cumulative usage (exposed to the UI).
type Book ¶ added in v1.5.2
type Book struct {
// Dir là đường dẫn tuyệt đối tới thư mục truyện.
Dir string
// Name là tên lấy từ meta/book.json, rơi về tên thư mục khi chưa có sách.
Name string
// Chapters là số chương đã chốt.
Chapters int
// Words là tổng số chữ đã viết.
Words int
// HasOutline cho biết đã có tiền đề/dàn ý chưa.
HasOutline bool
}
Book là một thư mục truyện trong cây đầu ra.
type BudgetSentinel ¶
type BudgetSentinel struct {
// contains filtered or unexported fields
}
BudgetSentinel theo dõi chi phí tích luỹ và thực thi chính sách ngân sách của người dùng (khối budget trong cấu hình).
Định vị hợp lý (architecture.md §8.3/§10): không đánh giá hành vi model — dừng khi vượt hạn tương đương Abort thủ công của người dùng vào đúng thời điểm đó, Host chỉ thay họ thực thi một chỉ lệnh đã ký trước. Nó ảnh hưởng dòng điều khiển nên không phải quan sát viên, mà là thành phần chính sách của Host ngang hàng với flow.Dispatcher; tầng Route/công cụ không biết tới.
Thời điểm dừng: mặc định ở ranh giới tác vụ con (Host gọi đồng bộ HandleBoundary), không phí chương đang chạy dở; hardStop=true thì dừng ngay khi vượt. Xử lý ranh giới diễn ra trước khi flow.Dispatcher phát việc kế tiếp; tầng Route/công cụ không biết tới ngân sách.
func NewBudgetSentinel ¶
func NewBudgetSentinel(cfg bootstrap.BudgetConfig, costNow func() float64, abort func(reason string), report func(level, summary string)) *BudgetSentinel
NewBudgetSentinel tạo cảnh báo ngân sách; trả nil khi chính sách không bật (mọi method đều nil-safe).
func (*BudgetSentinel) HandleBoundary ¶
func (s *BudgetSentinel) HandleBoundary() bool
func (*BudgetSentinel) HandleEvent ¶
func (s *BudgetSentinel) HandleEvent(ev agentcore.Event)
HandleEvent thực hiện lệnh dừng đang chờ ở ranh giới tác vụ con. Phải đăng ký trước Dispatcher. Không bỏ qua IsError — trả về lỗi cũng là một ranh giới, việc dừng không nên bị hoãn vì tác vụ con thất bại.
func (*BudgetSentinel) Limit ¶
func (s *BudgetSentinel) Limit() float64
Limit trả về trần ngân sách (để TUI hiển thị); trả 0 khi không bật.
func (*BudgetSentinel) OnCost ¶
func (s *BudgetSentinel) OnCost(total float64)
OnCost do UsageTracker gọi sau mỗi lần ghi sổ, mang theo chi phí tích luỹ mới nhất (ngoài khoá). Một lần callback có thể nhảy qua hai cấp (normal→warned→stopPending), mỗi tác dụng phụ kích hoạt đúng một lần.
func (*BudgetSentinel) Refuse ¶
func (s *BudgetSentinel) Refuse() error
Refuse là kiểm tra trước khi chạy: trả lỗi từ chối nếu đã vượt ngân sách (được gọi ở các đường Start/Resume/Continue). Người dùng tăng ngân sách = cấp quyền lại, với cấu hình mới thì Refuse tự nhiên cho qua.
type ChapterAdvanceGate ¶
type ChapterAdvanceGate struct {
// contains filtered or unexported fields
}
ChapterAdvanceGate là thành phần chính sách tiến viết duy nhất của Host:
- AdvanceHold: thực hiện lần tạm dừng một lần mà can thiệp này đã ký;
- review permit: chặn chương mới tiến về phía trước khi chưa được cấp quyền.
Nó không tham gia Route, không diễn giải Task/Reason, cũng không đưa ra phán đoán văn chương.
func NewChapterAdvanceGate ¶
func NewChapterAdvanceGate(s *store.Store, pause func(reason string), report func(level, summary string)) *ChapterAdvanceGate
func (*ChapterAdvanceGate) Allow ¶
func (g *ChapterAdvanceGate) Allow(inst *flow.Instruction) (bool, error)
Allow thực hiện kiểm tra giấy phép cuối cùng trước khi phát việc cho Worker.
func (*ChapterAdvanceGate) HandleBoundary ¶
func (g *ChapterAdvanceGate) HandleBoundary() bool
HandleBoundary tiêu thụ hold trúng và đối soát giấy phép chương. Trả true nghĩa là Engine phải dừng. Khi ở auto và không có hold thì chỉ đọc RunMeta một lần, không đụng Progress/PendingCommit/checkpoint.
type ChapterText ¶ added in v1.5.2
type ChapterText struct {
Chapter int
Title string
Body string
WordCount int
// Exists phân biệt "chương chưa viết" với "chương viết rỗng". Cả hai đều cho
// Body rỗng, nhưng người đọc cần biết để không tưởng sách bị hỏng.
Exists bool
// Committed phân biệt đã chốt với còn là bản nháp. Người đọc cần biết để
// không tưởng bản nháp là bản cuối.
Committed bool
}
ChapterText là nội dung một chương đã chốt, kèm tiêu đề lấy từ dàn ý.
type CoCreateMessage ¶
CoCreateMessage is a message of the co-create conversation.
type CoCreateReply ¶
type CoCreateReply struct {
Message string
Prompt string
Ready bool
Suggestions []string
Raw string
}
CoCreateReply is the LLM reply of the co-create conversation. Raw keeps the model's complete four-part original text, which is written back into history so the next round sees its own previous [DRAFT], and therefore really accumulates updates on top of the existing draft (with only Message, the model would re-summarise from the conversation every round). Suggestions is the AI's proactive "here is what you might want to say next"; when the user is stuck, a number key fills it into the input box in one keystroke.
type ConfiguredModel ¶
type ConfiguredModel struct {
Name string
ContextWindow int
ContextSource bootstrap.ContextWindowSource
}
type DeleteBookResult ¶ added in v1.5.2
DeleteBookResult báo kết quả xoá, đủ để hiển thị xác nhận trước khi xoá.
type Event ¶
type Event struct {
ID string // shared by the start and the end of one call; empty for non-call events
Time time.Time // when it was first emitted (the start moment)
FinishedAt time.Time // zero value = in progress; non-zero = finished
Failed bool // finished but failed (only meaningful in the finished state)
Category string // DISPATCH / MODEL / TOOL / DECISION / SYSTEM / REVIEW / CHECK / ERROR / CONTEXT
Agent string // the agent that produced the event
Summary string
// SummaryMsg là bản CHƯA dịch của Summary, dùng khi Summary là thông điệp hiển thị
// có tham số: TUI dịch Key rồi mới điền Args, nên hiện đúng ở cả vi/en/zh.
// Summary vẫn được giữ (đã điền sẵn) cho log và cho code đọc trực tiếp.
// Nil nghĩa là Summary là dữ liệu thô, không dịch — ví dụ tên tool, thông điệp provider.
SummaryMsg *Msg
Detail string // full text, written to the log untruncated for troubleshooting; falls back to Summary when empty. The UI only reads Summary
Kind string // error classification (e.g. stream_idle), emitted with the log for filtering/alerting; not emitted when empty
Level string // info / warn / error / success
Depth int // 0 = Engine layer, 1 = Worker layer
Duration time.Duration // how long the execution took, once finished
RetryAt time.Time // retry events: the deadline of the next retry; the UI counts down second by second from it and clears at zero (the request is already in flight)
}
Event is a structured event consumed by the TUI.
For call events (MODEL / TOOL / DISPATCH / DECISION) the start and the end of one call share a single ID: at the start an event with a zero FinishedAt is emitted first (the TUI renders it in the "in progress" style); at the end another event with the same ID is emitted, filling in FinishedAt + Duration (+ Failed), and the TUI locates the original row by ID and updates it in place, avoiding the redundancy of
"a row for the start and another row for the finish". Non-call events (SYSTEM / ERROR / CONTEXT) have an
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host là vỏ runtime: vòng đời / cửa vào can thiệp / chiếu sự kiện / quản lý model. Lập lịch và thực thi nằm ở engine (vòng lặp tất định); định đoạn ngữ nghĩa nằm ở arbiter (LLM-as-function).
func (*Host) AdvanceOneChapter ¶
AdvanceOneChapter cấp quyền cho đúng một chương ở chế độ duyệt từng chương rồi khởi động Engine.
func (*Host) AskStoryPartner ¶ added in v1.5.3
AskStoryPartner chạy một lượt hỏi advisor trên runtime thật.
Luồng: resolve advisor model (failover) → sp.Service → accounting sidecar → audit logs/sp. Không pause Engine, không interMu, không exclusive slot, không chạm lifecycle — Engine đang viết thì /sp vẫn chạy song song.
Single-flight: mỗi thời điểm một request advisor. Request mới hủy request cũ qua context riêng của sidecar; ctx của caller vẫn được tôn trọng (cancel từ phía nào cũng về context.Canceled).
func (*Host) AvailableThinking ¶
func (h *Host) AvailableThinking(role string) []agentcore.ThinkingLevel
func (*Host) BookLanguage ¶ added in v1.5.3
BookLanguage trả ngôn ngữ sáng tác đang khoá cho truyện này. Trả ("", nil) khi truyện chưa khoá: đó là trường hợp bình thường với truyện tạo trước tính năng này, không phải lỗi.
func (*Host) Books ¶ added in v1.5.2
Books liệt kê các truyện đang tồn tại trong cây đầu ra. base là thư mục gốc (thường là nơi kietnovel chạy, hoặc thư mục cha của cây output).
func (*Host) CancelCoCreate ¶
func (h *Host) CancelCoCreate()
CancelCoCreate bỏ dở đồng sáng tác: xóa cờ chiếm, giữ trạng thái tạm dừng (người dùng có thể nhập tiếp ở ô nhập hoặc khởi động lại để Resume).
func (*Host) CancelStoryPartner ¶ added in v1.5.3
func (h *Host) CancelStoryPartner()
CancelStoryPartner hủy advisor request đang chạy, nếu có. Không có request thì không làm gì. Không bao giờ động vào Engine.
func (*Host) CheckChapterRevisions ¶
func (*Host) Close ¶
func (h *Host) Close()
Close dừng Engine và đóng kênh sự kiện.
Ngữ nghĩa lưu bền của Usage: trước hết hủy autoSaveLoop (nó tự flush lần trạng thái dirty cuối), rồi gọi thêm một SaveNow đồng bộ để chốt. Sau khi dừng, vài trăm token cuối của lệnh gọi LLM đang dở có thể mất, nhưng sẽ được bù tự động bằng replay session jsonl ở lần khởi động sau.
func (*Host) CoCreateStream ¶
func (h *Host) CoCreateStream(ctx context.Context, history []CoCreateMessage, onProgress func(kind, text string)) (CoCreateReply, error)
CoCreateStream đồng sáng tác khởi đầu từ số 0: làm rõ yêu cầu và sinh chỉ đạo sáng tác cho cả cuốn.
func (*Host) CompletedChapters ¶ added in v1.5.2
CompletedChapters liệt kê số chương đã chốt, tăng dần. Trả rỗng khi chưa có sách.
func (*Host) ConfigureModels ¶
func (h *Host) ConfigureModels(draft ModelConfigurationDraft) error
ConfigureModels kiểm tra, lưu và áp nóng kho model của một provider.
func (*Host) ConfiguredModelOptions ¶
func (h *Host) ConfiguredModelOptions(provider string) []ConfiguredModel
func (*Host) ConfiguredModels ¶
func (*Host) ConfiguredProviders ¶
func (*Host) Continue ¶
Continue is called when the user types in the input box after pausing: it locks in the intervention and makes sure the Engine runs again.
func (*Host) CurrentModelSelection ¶
func (*Host) CurrentThinking ¶
CurrentThinking trả về chuỗi mức suy luận đang có hiệu lực của một vai trò (để /model đồng bộ giá trị hiện tại).
func (*Host) DeleteBook ¶ added in v1.5.2
DeleteBook xoá vĩnh viễn thư mục truyện. Không có tham số "đổi ý" — vì vậy phía TUI bắt buộc phải gọi InspectBook trước để lấy thông tin xác nhận, rồi mới gọi hàm này.
Chặn xoá thư mục đang mở: người dùng đang viết truyện đó, xoá đi thì Engine đang chạy giữa chừng sẽ ghi vào thư mục biến mất.
func (*Host) Export ¶
Export xuất các chương đã hoàn thành ra file ngoài (hiện chỉ hỗ trợ TXT).
Khác với ImportFrom: xuất là thao tác chỉ đọc (không đụng Progress / Checkpoint), nên **không yêu cầu Engine dừng** — kể cả khi đang viết cũng xuất được "thành phẩm tại thời điểm này". Chỉ đọc một snapshot nhất quán gồm Progress.CompletedChapters + bản chính thức chương + dàn ý + premise.
func (*Host) FileLogError ¶
FileLogError trả về lỗi khởi tạo log file lúc dựng; không đổi trong suốt vòng đời của Host.
func (*Host) ImportFrom ¶
ImportFrom chạy một lần nhập biên dịch ngữ nghĩa truyện ngoài: ingest → segment → analyze → synthesize → publish. Model chỉ định đoạn phần ngữ nghĩa mở (biên/độ kiện/tổng hợp), Go phụ trách toạ độ/ghi đè/idempotent; loại trừ với Engine đang chạy, sau khi nhập xong thì AdvanceHold quyết định có viết tiếp hay không. Kênh sự kiện trả về do imp.Run đóng; bên gọi chịu trách nhiệm tiêu thụ (đầy thì bỏ để không chặn goroutine pipeline).
func (*Host) ImportResumeHint ¶
ImportResumeHint trả về một dòng nhắc về lần nhập chưa xong (rỗng nếu không có), để TUI chủ động báo lúc khởi động (RFC §18.2). Chỉ gọi một lần lúc khởi động: bên trong tính lại InputDigest của từng artifact trong workspace, không hợp đặt vào vòng poll snapshot.
func (*Host) ImportSimulationProfile ¶
ImportSimulationProfile nhập hồ sơ văn phong đã sinh từ trước.
func (*Host) InspectBook ¶ added in v1.5.2
func (h *Host) InspectBook(dir string) (DeleteBookResult, error)
InspectBook dựng thông tin thư mục sẽ bị xoá, KHÔNG xoá gì. Dùng cho bước xác nhận: người dùng phải thấy rõ đang xoá cái gì, bao nhiêu chương, trước khi đồng ý.
func (*Host) ModelConfiguration ¶
func (h *Host) ModelConfiguration() ModelConfigurationSnapshot
ModelConfiguration trả về cấu hình đã che, đích ghi và tham chiếu model, không bao giờ lộ API Key hiện có.
func (*Host) NewBookDir ¶ added in v1.5.2
NewBookDir tạo thư mục truyện mới trong <base>/output/<name> và trả về đường dẫn. Không tạo sẵn meta/: store sẽ khởi tạo đúng cấu trúc khi mở.
func (*Host) PauseForCoCreate ¶
PauseForCoCreate vào đồng sáng tác giai đoạn: đặt cờ chiếm đồng sáng tác, nếu đang chạy thì tạm dừng Engine luôn. Trả false nghĩa là không vào được (đã xong sách hoặc đang trong đồng sáng tác), bên gọi có thể bỏ qua. Cờ chiếm trong cửa sổ đồng sáng tác chặn can thiệp chồng nhau từ import/simulate/start/resume/continue — khi tạm dừng lúc đang chạy thì lifecycle=paused, ràng buộc loại trừ ==running mất hiệu lực, nên phải có cờ này bù; đã dừng (idle/paused) vẫn cho vào, xong phần quy hoạch sẽ chạy tiếp qua Continue.
func (*Host) PrepareUserRules ¶
PrepareUserRules sinh snapshot quy tắc người dùng cho cuốn sách này ở chế độ tạo mới (tất định phía khởi động, không đi vào Run sáng tác chính).
Đầu vào là yêu cầu sáng tác **gốc** của người dùng (chưa bọc qua BuildStartPrompt) — thứ cần chuẩn hóa là chính quy tắc của người dùng, không phải khung khởi động. Cửa vào phải được gọi một lần trước StartPrepared (cả hai đường tạo mới quick/cocreate đều đi qua đây).
Chuẩn hóa hỏng chỉ hạ cấp, không báo lỗi (đường tăng cường); chỉ khi không ghi được snapshot mới trả error để dừng việc tạo truyện — nếu không thì các lần chạy sau sẽ không có nguồn dữ kiện ổn định (xem thiết kế §thất bại và hạ cấp).
func (*Host) ReadChapter ¶ added in v1.5.2
func (h *Host) ReadChapter(chapter int) (ChapterText, error)
ReadChapter đọc một chương: ưu tiên bản đã chốt (chapters/), không có thì lấy bản nháp (drafts/).
Vì sao phải đọc được cả nháp: bản nháp là thứ người viết CẦN đọc để quyết định có chốt hay không. Chỉ đọc được bản chốt thì tạo ra vòng luẩn quẩn — không đọc được nháp thì không biết có nên chốt, mà chưa chốt thì đọc đâu.
Chương chưa viết trả Exists=false, Body rỗng, KHÔNG phải lỗi. Chỉ lỗi đĩa và dàn ý hỏng mới thành error.
Tiêu đề lấy từ dàn ý, không lấy từ tiêu đề markdown trong file chương: tên file chỉ là %02d.md, còn dàn ý là nơi duy nhất giữ tên chương sau khi engine commit.
func (*Host) ReadableChapters ¶ added in v1.5.2
ReadableChapters liệt kê chương nào đọc được: đã chốt thì chắc chắn có; đang làm dở thì lấy theo danh sách bản nháp. Tăng dần, không trùng.
func (*Host) Reopen ¶
Reopen mở lại cuốn đã hoàn thành thành trạng thái đang viết. Xong sách và mở lại đều là quyết định nặng: xong sách có thể do kiến trúc sư định đoạn, còn mở lại chỉ người dùng chủ động yêu cầu (/reopen), không qua định đoạn của model. direction khác rỗng được ghi là can thiệp chờ xử lý; khi khôi phục, Arbiter sẽ định đoạn rồi chèn (cùng kênh với can thiệp lúc dừng), sau đó Engine chạy tiếp (định tuyến cuối tập sẽ phát ra tập tiếp theo).
func (*Host) ReplayQueue ¶
func (h *Host) ReplayQueue(afterSeq int64) ([]domain.RuntimeQueueItem, error)
func (*Host) Resume ¶
Resume chế độ khôi phục: sinh resume prompt từ checkpoint + progress rồi khởi động. Resume khôi phục phiên viết từ store. Trả về Msg (chưa dịch) để TUI hiển thị đúng ngôn ngữ; dùng resumeLabel.String() nếu cần chuỗi thô cho log.
func (*Host) ResumeFromCoCreate ¶
ResumeFromCoCreate kết thúc đồng sáng tác: chèn hướng đi tiếp do đồng sáng tác sinh ra thành can thiệp rồi khôi phục việc viết. Sau khi xóa cờ chiếm, tái dùng đường chèn của Continue khi đã dừng (vẫn chịu ràng buộc ngân sách trước). Lưu ý: draft rỗng thì trả về sớm mà không xóa cờ là cố ý (đồng sáng tác chưa kết thúc); phía TUI dùng cùng một tiêu chí "không rỗng" ở canStart(), nên đường này không tới được và cocreating không bị rò.
func (*Host) SetAdvanceMode ¶
func (h *Host) SetAdvanceMode(mode domain.ChapterAdvanceMode) error
SetAdvanceMode chuyển chế độ đẩy chương theo cách tất định. Nó chỉ ghi ý định chạy của người dùng, không gọi Arbiter và không tự khởi động Engine đang tạm dừng.
func (*Host) SetBookLanguage ¶ added in v1.5.3
SetBookLanguage khoá ngôn ngữ sáng tác cho truyện này.
func (*Host) SetRoleThinking ¶
SetRoleThinking đặt mức suy luận cho một vai trò (hoặc default): kiểm tra → lưu bền → liên kết agent đang chạy → sự kiện. Cấu trúc đối xứng với SwitchModel; độc lập với việc chọn model nên chỉnh riêng được. level rỗng = không ghi đè (kế thừa).
func (*Host) Snapshot ¶
func (h *Host) Snapshot() UISnapshot
func (*Host) StageCoCreateStream ¶
func (h *Host) StageCoCreateStream(ctx context.Context, history []CoCreateMessage, onProgress func(kind, text string)) (CoCreateReply, error)
StageCoCreateStream đồng sáng tác theo giai đoạn: quy hoạch hướng đi tiếp dựa trên phần đã viết. Prompt hệ thống = prompt giai đoạn + tóm tắt trạng thái câu chuyện hiện tại, để trợ lý biết "đã viết đến đâu".
func (*Host) StartPrepared ¶
StartPrepared bắt đầu viết từ yêu cầu sáng tác **gốc** của người dùng: định đoạn plan_start chọn kiến trúc sư và mở rộng yêu cầu, kết quả định đoạn được cố thành dữ kiện trước (PlanStartRecord) rồi mới khởi động Engine — mọi lần khôi phục luôn dựa trên dữ kiện đã ghi đĩa, không làm lại định đoạn đã có. Dữ kiện đầu vào (StartPrompt) được ghi đĩa trước khi định đoạn: nếu định đoạn hỏng thì đây là căn cứ để Engine bù định đoạn, nên khởi động hỏng vẫn tự lành từ mọi cửa khôi phục (Resume/tiếp tục), không phải ngõ cụt.
func (*Host) Steer ¶
Steer submits a user intervention (allowed at any point while running; once paused, whether the Engine is pulled back up afterwards depends on the action). The TUI waits on the result through a tea.Cmd, so it sees the real lock-in/persist error without blocking the interface.
func (*Host) SwitchModel ¶
func (*Host) SyncChapterRevisions ¶
func (*Host) TestModelConnection ¶
func (h *Host) TestModelConnection(ctx context.Context, draft ModelConfigurationDraft, modelName string) error
TestModelConnection dùng bản nháp hiện tại dựng một client model thật và gửi request tối thiểu. Không lưu cấu hình, không chuyển model runtime, thất bại cũng không rớt sang Provider khác.
type ModelConfigurationDraft ¶
type ModelConfigurationDraft struct {
Provider string
Type string
API string
BaseURL string
Models []bootstrap.ModelConfig
Renames []ModelRename
APIKeyAction APIKeyAction
APIKey string
}
ModelConfigurationDraft là bản nháp một provider mà /config gửi cho Host. Chỉ mô tả định nghĩa provider (giao thức/chứng thực/kho model), không gồm "đang dùng cái nào" — chuyển model là việc của /model.
type ModelConfigurationSnapshot ¶
type ModelConfigurationSnapshot struct {
Providers []ProviderSnapshot
DefaultProvider string
DefaultModel string
ConfigPath string
References map[string][]string
}
func (ModelConfigurationSnapshot) ReferencesFor ¶
func (s ModelConfigurationSnapshot) ReferencesFor(provider, model string) []string
type ModelRename ¶
ModelRename mô tả việc đổi ID của cùng một cấu hình model. Nó không phải phỏng đoán "xóa cũ thêm mới" — Host chỉ chuyển default, vai trò và tham chiếu fallback khi TUI gửi tường minh quan hệ này.
type Msg ¶ added in v1.5.2
Msg là thông điệp hiển thị CHƯA dịch, đi kèm qua ranh giới host → TUI.
Key là nguồn tiếng Việt theo đúng quy ước của internal/i18n (chuỗi tiếng Việt là nguồn sự thật), thường ở dạng format string. Args là tham số sẽ điền vào lúc hiển thị.
Vì sao không dựng sẵn ở host rồi gửi chuỗi đã điền: "Khôi phục: chương %d" và "Khôi phục: chương 3" là hai chuỗi khác nhau, mà bảng dịch chỉ có thể chứa mẫu chứa %d. Điền số ở host thì TUI không còn gì để dịch, và mọi ngôn ngữ đều hiện tiếng Việt — đúng cái lỗi "vá triệu chứng" mà Msg này loại bỏ.
TUI dịch Key trước rồi mới điền Args (i18n.Tf), y hệt cách TUI vẫn làm với chuỗi của riêng nó, nên một thông điệp hiện đúng ở cả vi/en/zh.
func Ptr ¶ added in v1.5.2
Ptr trả con trỏ tới bản sao, để gán vào Event.SummaryMsg (*Msg). Dùng khi thông điệp được tính tại chỗ gọi: cần địa chỉ ổn định chứ không phải con trỏ tới biến cục bộ.
type NewOption ¶
type NewOption func(*newOptions)
NewOption configures the Host construction process; the runtime resources are still owned by Host.
func WithFileLog ¶
WithFileLog gives Host a runtime log session. The log is opened only after the novel-directory lease is taken, and closed once Host has closed all logs. If opening fails the current process logger keeps being used, and the caller must handle that error explicitly through FileLogError.
type OutlineSnapshot ¶
OutlineSnapshot is the display summary of an outline entry.
type ProviderSnapshot ¶
type ProviderSnapshot struct {
Name string
Type string
API string
BaseURL string
Models []bootstrap.ModelConfig
HasAPIKey bool
APIKeyHint string
RequiresAPIKey bool
}
ProviderSnapshot là cấu hình provider đã che API key, để TUI hiển thị.
type UISnapshot ¶
type UISnapshot struct {
Provider string
BookTitle string
ModelName string
ModelContextWindow int // context window of the current default model (resolved live on /model switch)
ThinkingLevel string
Style string
RuntimeState string // idle / running / pausing / paused / completed
StatusLabel string
Phase string
Flow string
CurrentChapter int
TotalChapters int
CompletedCount int
TotalWordCount int
InProgressChapter int
PendingRewrites []int
RewriteReason string
PendingSteer string
AdvanceMode string
AdvancePermitChapter int
HasAdvanceHold bool
AdvanceHoldReason string
RecoveryLabel Msg // chưa dịch; TUI gọi i18n.Tf(RecoveryLabel.Key, RecoveryLabel.Args...)
IsRunning bool
Agents []AgentSnapshot
// cumulative usage (whole session, across all agents and model switches)
TotalInputTokens int
TotalOutputTokens int
TotalCacheReadTokens int
TotalCacheWriteTokens int
TotalCostUSD float64
TotalSavedUSD float64 // USD saved thanks to CacheRead hits (relative to billing every input at the non-cached input price)
BudgetLimitUSD float64 // budget cap (config budget.book_usd); 0 = not enabled
// cache diagnostics
OverallCacheCapable bool // at least one role has run a model that supports prompt cache (distinguishes "not enabled" from "0% hit rate")
OverallRecentCacheRead int // sum of cacheRead over the most recent N samples in the sliding window
OverallRecentInput int // sum of input over the most recent N samples in the sliding window
OverallRecentSamples int // number of samples in the sliding window (<= recentSampleCap)
TotalCacheBreaks int // number of cache-chain breaks detected live (the prefix did not shorten while the hit rate dropped), see noteCacheBreak in usage.go
// MissingAssistantUsage > 0 usually means the upstream streaming did not send the final usage
// chunk per the OpenAI stream_options.include_usage protocol (common with self-hosted proxies),
// so the UsageTracker receives no cumulative data at all. The UI tells the user to inspect the backend,
// rather than letting them think the cache module itself is broken.
MissingAssistantUsage int
// cache per-role dimension, sorted by CacheRead descending, with roles that never consumed tokens filtered out
CachePerAgent []AgentCacheStat
CachePerModel []AgentCacheStat
// base settings
Synopsis string
Premise string
Outline []OutlineSnapshot
Characters []string
SupportingCount int // total number of supporting characters recorded for the chapter
RecentSupporting []string // most recently active supporting characters (at most 5, sorted by LastSeenChapter descending)
Layered bool
CurrentVolumeArc string
NextVolumeTitle string
CompassDirection string
CompassScale string
// details
LastCommitSummary string
LastReviewSummary string
LastCheckpointName string
RecentSummaries []string
}
UISnapshot is the aggregate state snapshot the TUI needs for rendering.
type UsageTracker ¶
type UsageTracker struct {
// contains filtered or unexported fields
}
UsageTracker accumulates the LLM input/output tokens and dollar cost of every agent for the whole session.
How it works:
- Record(agentName, msg) is called on every agent OnMessage callback
- agentName maps to a role (architect_* is normalized to architect), then the model currently bound to that role is looked up in ModelSet
- models.DefaultRegistry supplies the model price, multiplied across four items: non-cached input / output / cache read / cache write
- when the model is not in the registry, fall back to msg.Usage.Cost.Total (whatever the provider reported, possibly 0)
- after a hot model switch (/model) later messages are priced with the new model while old messages keep their old cost
It also maintains a per-role dimension (writer/editor/architect):
- cumulative hit data -> the overall optimization effect
- the sliding window of the last N calls -> tells early drag apart from a steady low hit rate
- the CacheCapable flag -> tells "not enabled" apart from "really a 0% hit rate"
Thread-safe.
func NewUsageTracker ¶
func NewUsageTracker(set *bootstrap.ModelSet, store *storepkg.Store) *UsageTracker
func (*UsageTracker) LoadFromStore ¶
func (t *UsageTracker) LoadFromStore() (bool, error)
LoadFromStore reads the persisted snapshot from store.Usage and back-fills it into memory. true means a non-empty (schema matching) state was loaded successfully; false means there is no file or it is unusable, and the caller should keep going with a one-off back-fill from the session replay.
func (*UsageTracker) MissingAssistantUsage ¶
func (t *UsageTracker) MissingAssistantUsage() int
MissingAssistantUsage returns the cumulative count of "an assistant message was received but Usage is nil". Greater than 0 usually means the upstream streaming did not send OpenAI's final usage chunk, and the UI shows a hint instead of letting the user think the cache module itself is broken.
func (*UsageTracker) OverallCacheBreaks ¶
func (t *UsageTracker) OverallCacheBreaks() int
OverallCacheBreaks returns the total number of cache-chain breaks detected live.
func (*UsageTracker) OverallCacheCapable ¶
func (t *UsageTracker) OverallCacheCapable() bool
OverallCacheCapable reports whether the whole run has been through a model known to support cache at least once.
func (*UsageTracker) OverallRecent ¶
func (t *UsageTracker) OverallRecent() (cacheRead, input, samples int)
OverallRecent returns the cacheRead total, the input total and the sample count inside the sliding window (at most recentSampleCap calls).
func (*UsageTracker) PerAgent ¶
func (t *UsageTracker) PerAgent() []AgentUsage
PerAgent returns the cumulative usage per role, sorted by CacheRead descending, skipping roles that never consumed tokens.
func (*UsageTracker) PerModel ¶
func (t *UsageTracker) PerModel() []AgentUsage
PerModel returns the cumulative usage per model, sorted by cost descending and then by input volume descending.
func (*UsageTracker) Record ¶
func (t *UsageTracker) Record(agentName, task string, msg agentcore.AgentMessage)
Record dispatches one agent message onto two paths: accumulation and diagnostics.
Accumulation only looks at whether Usage exists - "which messages carry Usage" is an agentcore/litellm adapter assembly detail (the upstream protocol puts usage at the top level of the response), so if the assembly rules ever change, nothing here has to change. Diagnostics require Role=Assistant and non-empty Content so that AbortMsg / abnormal recovery / tool / user messages do not pollute the missingAssistantUsage counter.
func (*UsageTracker) RecordSidecar ¶ added in v1.5.3
func (t *UsageTracker) RecordSidecar(agentName, task string, u agentcore.Usage, provider, modelName string)
RecordSidecar ghi accounting cho tác vụ phụ (sidecar) như /sp hỏi.
Khác Record ở đúng một điểm: KHÔNG cộng vào overall và KHÔNG gọi onCost. overall là số BudgetSentinel dùng để quyết định abort Engine; một câu hỏi phụ mà đẩy tổng vượt trần rồi dừng cả máy đang viết là sai nguyên tắc "sidecar không can thiệp Engine".
Nhưng vẫn cộng vào perAgent["advisor"] + perModel và vẫn notifyDirty để persist: tiền thật đã đốt thì phải còn dấu vết, chỉ là không được dùng để giết Engine.
task là lineage của cache detector: mỗi /sp request là một prompt lineage mới (snapshot/question khác nhau, model có thể đổi), nên mỗi request phải có task riêng. Dùng chung một task cho mọi request thì detector so B với baseline của A và báo "đứt cache" oan cho một lineage hoàn toàn mới.
func (*UsageTracker) ReplaySessions ¶
func (t *UsageTracker) ReplaySessions(rootDir string) (int, error)
ReplaySessions scans meta/sessions/agents/*.jsonl, re-accumulates the usage of every assistant message into the tracker, and returns the number of back-filled records.
Call constraint: called exactly once for back-filling, only when meta/usage.json is missing. Regular persistence goes through SaveNow / autoSaveLoop.
The accuracy relies on the three-level fallback described in the sessionRecord comment - the third level (both Usage and _meta missing) only triggers on older logs or upstream anomalies.
func (*UsageTracker) SaveNow ¶
func (t *UsageTracker) SaveNow() error
SaveNow writes the current snapshot to disk immediately. The autoSaveLoop / Close paths both write through it.
func (*UsageTracker) SavedUSD ¶
func (t *UsageTracker) SavedUSD() float64
SavedUSD returns the cumulative dollars saved by cache hits.
func (*UsageTracker) SetOnCost ¶
func (t *UsageTracker) SetOnCost(cb func(total float64))
SetOnCost registers the accounting callback (carrying the latest cumulative cost, called outside the lock). It must be called once during Host construction, before concurrent Record calls start.
func (*UsageTracker) SetOnMissingUsage ¶
func (t *UsageTracker) SetOnMissingUsage(cb func())
SetOnMissingUsage registers the one-shot callback for the first time usage is found missing. It must be called once during Host construction, before concurrent Record calls start.
func (*UsageTracker) Snapshot ¶
func (t *UsageTracker) Snapshot() domain.UsageState
Snapshot copies the current cumulative state into a serializable domain.UsageState. The sliding-window samples do not go into the snapshot - it is a short-term diagnostic window and little of it carries across processes.
func (*UsageTracker) StartAutoSave ¶
func (t *UsageTracker) StartAutoSave(ctx context.Context)
StartAutoSave starts a goroutine that listens on saveCh and writes to disk with a debounce. Before ctx is done it flushes the last unsaved state. Close triggers that flush and the exit by cancelling ctx.
func (*UsageTracker) Totals ¶
func (t *UsageTracker) Totals() (cost float64, input, output, cacheRead, cacheWrite int)
Totals returns a snapshot of the cumulative totals.
func (*UsageTracker) WaitAutoSave ¶
func (t *UsageTracker) WaitAutoSave()
WaitAutoSave waits for the final flush after cancellation. Host.Close calls cancel first and then waits here, so autoSaveLoop does not race the pre-exit SaveNow over the same snapshot.
Source Files
¶
- advance_gate.go
- arbiter_model.go
- book_language.go
- book_lock.go
- books.go
- budget.go
- cocreate.go
- cocreate_stage.go
- decision_observer.go
- engine.go
- event_log.go
- events.go
- host.go
- model_config.go
- msg.go
- observer.go
- observer_events.go
- observer_model.go
- observer_stream.go
- observer_tools.go
- options.go
- read.go
- resume.go
- story_partner.go
- stream_extract.go
- usage.go
- usage_replay.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package exp implements the export of completed chapters.
|
Package exp implements the export of completed chapters. |
|
Package imp implements the staged semantic import pipeline for external novels (docs/import-pipeline.md).
|
Package imp implements the staged semantic import pipeline for external novels (docs/import-pipeline.md). |