promptkit

package
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 4, 2026 License: None detected not legal advice Imports: 0 Imported by: 0

Documentation

Overview

Package promptkit defines the three-layer prompt assembly framework for Flyto Agent. Mirrors the public mechanism Claude Code uses internally: static base + conditional sections + runtime reminders.

promptkit 包定义 Flyto Agent 的三层 prompt 装配框架. mirror Claude Code 内部公开机制: 静态基座 + 条件块 + 运行时 reminder.

Three layers

Layer 1 - BaseSections: always-on sections forming the cache-stable
          prefix. The engine places a cache_control marker after the
          last base section so prompt cache hits ~90% on subsequent
          turns. Examples: role identity, doing-tasks guidance, tone.
          始终在的 cache 稳定前缀, engine 在末尾打 cache_control marker
          让后续轮次 cache 命中率 ~90%. 例: 角色定位 / 任务流程 / 语气.

Layer 2 - ConditionalSections: evaluated once at session setup (NOT
          per-turn). Caller-defined predicates decide which sections
          fire. Examples: git status snapshot only when in git repo,
          MCP server instructions only when configured.
          会话启动时判定一次 (不每轮跑). 调用方定义条件谓词决定哪些段
          触发. 例: 检测到 git 仓库才加 git status, 配 MCP 才加 instructions.

Layer 3 - ReminderTriggers: runtime hooks that fire on engine-emitted
          events (tool result, file read, mtime drift, permission
          wait, token budget low, custom). Rendered text injects into
          the messages array (NOT system prompt) preserving cache
          stability. Wrapped in <system-reminder> XML tags by
          convention.
          运行时 hook, 在 engine 发出事件时触发 (tool 返回 / 文件读 /
          mtime 漂 / 权限等待 / token budget 紧张 / 自定义). 渲染文本注入
          messages 数组 (不进 system prompt) 保持 cache 稳定. 按惯例用
          <system-reminder> XML 标签包.

Why three layers

Pre-ADR-0005 Flyto's engine baked Claude Code's coding-assistant content into the engine itself: 8-section system prompt unconditionally injected (~16KB), reminders re-injected per-turn even when SystemPrompt override claimed to bypass them, no prompt cache. This package abstracts the cc mechanism — caller fills content; framework owns assembly + cache boundary placement. First implementation: core/extra/preset-coding/ (Claude Code preset). Second implementation (planned): preset-extraction for logistics quote extraction.

ADR-0005 之前 Flyto 引擎硬塞 Claude Code 内容: 8 段无条件注入 (~16KB) / SystemPrompt 名义 override 仍每轮塞 reminder / 没接 prompt cache. 本包 抽象 cc 机制 — 调用方填内容, framework 负责装配 + cache 边界. 首个实现: core/extra/preset-coding/ (Claude Code preset). 计划第二实现: preset-extraction 给物流报价表抽取场景.

Escape hatch

Callers who find this interface too rigid can bypass entirely via engine.Config.SystemPrompt (literal string sent to LLM, no decoration, no three-layer assembly). Mutually exclusive with cfg.PromptBundle. See ADR-0005 § 2.3 for the design rationale.

嫌接口僵硬的调用方可走 engine.Config.SystemPrompt 字符串路径绕过 (字面 字符串发给 LLM, 零装饰, 不走三层). 与 cfg.PromptBundle 互斥. 设计依据 见 ADR-0005 § 2.3.

See also

Index

Constants

This section is empty.

Variables

View Source
var ErrNilBundle = errors.New("promptkit: nil PromptBundle")

ErrNilBundle is returned by Build when given a nil PromptBundle.

ErrNilBundle 在 Build 收到 nil PromptBundle 时返回.

Functions

func Build

func Build(b PromptBundle, ctx BuildContext) (string, int, error)

Build assembles a final system prompt string from a PromptBundle.

Build 装配 PromptBundle 成 system prompt 字符串.

Returns: (assembled prompt, cache boundary byte offset, error). cache boundary is the byte offset after Layer-1 (BaseSections) ends — callers pass this to providers that support cache_control marker placement (e.g. Anthropic API ephemeral cache).

返回: (装配后 prompt, cache 边界字节偏移量, error). cache 边界是 Layer-1 (BaseSections) 结束后的字节偏移 — 调用方将其传给支持 cache_control marker 的 provider (例如 Anthropic API ephemeral cache).

Sections separated by "\n\n" (cc convention). If a Section.Render returns empty string the section is skipped (no spacing emitted).

段间用 "\n\n" 分隔 (cc 惯例). Section.Render 返回空串则跳过该段 (不输出空白).

CLEVER: cache boundary tracked by sb.Len() snapshot after last base section. This requires Build to NOT trim trailing whitespace before the snapshot — providers expect the marker at the byte boundary they see in the wire payload, not the visual string boundary.

CLEVER: cache 边界用 sb.Len() snapshot 在最后一个 base section 后捕获. 这要求 Build 在 snapshot 前不修剪尾部空白 — provider 期望 marker 落在 它在 wire payload 中看到的字节边界, 不是视觉字符串边界.

Types

type BuildContext

type BuildContext struct {
	// Cwd is the engine's working directory.
	// 引擎工作目录.
	Cwd string

	// ModelFamily is a coarse model classifier (e.g. "claude", "openai",
	// "qwen"). Used by sections that adjust phrasing per model family.
	// 模型粗分类 (e.g. "claude" / "openai" / "qwen"). 给按模型家族调整措辞的段用.
	ModelFamily string

	// Language is an optional language hint (e.g. "zh-CN", "en-US").
	// Empty = caller didn't specify; section may default.
	// 可选语言提示. 空 = 调用方未指定, 段可默认.
	Language string

	// HasGitRepo: a git repository was detected at or above Cwd.
	// 在 Cwd 或祖先目录检测到 git 仓库.
	HasGitRepo bool

	// HasMCPServer: at least one MCP server is configured.
	// 至少配了一个 MCP server.
	HasMCPServer bool

	// HasFLYTOMD: a FLYTO.md file was found in any of the standard
	// search locations (project root, cwd, ~/.flyto/).
	// 在标准搜索位置 (项目根 / cwd / ~/.flyto/) 找到 FLYTO.md.
	HasFLYTOMD bool

	// Custom is for caller-defined predicates. Section implementations
	// type-assert keys they recognize.
	// 调用方自定义谓词. Section 实现按识别的 key 做类型断言.
	Custom map[string]any
}

BuildContext carries session-level invariants supplied to ConditionalSections at session setup.

BuildContext 是 ConditionalSections 会话启动时收到的会话级不变量.

Implementations should treat these as read-only.

实现者应视为只读.

type Context

type Context = BuildContext

Context is supplied to Section.Render at render time. Currently aliased to BuildContext; kept as a separate type so render-time vs setup-time invariants can diverge later without breaking implementations.

Context 是 Section.Render 时收到的不变量. 当前别名 BuildContext, 单独 命名让 render 时 vs 启动时不变量未来可独立演进而不破坏实现.

type Event

type Event struct {
	// Type identifies which TriggerEvent fired.
	// 触发的事件类型.
	Type TriggerEvent

	// ToolName is set for EventToolResult / EventFileRead.
	// 给 EventToolResult / EventFileRead 用.
	ToolName string

	// FilePath is set for EventFileRead / EventFileMTimeDrift.
	// 给 EventFileRead / EventFileMTimeDrift 用.
	FilePath string

	// Payload carries event-specific data. Trigger implementations
	// type-assert keys they recognize.
	// 事件特定数据. Trigger 实现按识别的 key 做类型断言.
	Payload map[string]any

	// Custom is the discriminator for EventCustom sub-types.
	// EventCustom 子类型的区分字符串.
	Custom string
}

Event carries trigger-time payload supplied to Trigger.Inject.

Event 是 Trigger.Inject 时收到的 payload.

type PromptBundle

type PromptBundle interface {
	// BaseSections returns the cache-stable always-on prefix.
	// Engine places cache_control marker after the last base section.
	//
	// 始终在的 cache 稳定前缀. engine 在末尾打 cache_control marker.
	BaseSections() []Section

	// ConditionalSections evaluates trigger predicates once at session
	// setup (NOT per-turn) and returns sections whose condition matched.
	//
	// 会话启动时判定一次 (不每轮跑), 返回触发段.
	ConditionalSections(ctx BuildContext) []Section

	// ReminderTriggers returns runtime reminder hooks. Engine fires them
	// on matching events and injects rendered content into messages array.
	//
	// 运行时 reminder hook. engine 在匹配事件触发, 注入 messages 数组.
	ReminderTriggers() []Trigger
}

PromptBundle assembles a system prompt in the three-layer pattern: static base + conditional sections + runtime reminders.

PromptBundle 按三层模式装配 system prompt: 静态基座 + 条件块 + 运行时 reminder.

All three methods are caller-defined. promptkit owns assembly + cache boundary placement; content ownership stays with the implementor.

三个方法都由调用方实现. promptkit 只管装配 + cache 边界, 内容由实现者负责.

See ADR-0005 § 2.3 for the design rationale (mirror cc, no new concepts).

设计依据见 ADR-0005 § 2.3 (mirror cc, 不发明新概念).

type Section

type Section interface {
	// Name returns a stable identifier for debugging and cache-key derivation.
	// Implementations should return the same value across the process lifetime.
	//
	// 稳定标识符, 用于调试和 cache key 派生. 实现者应返回进程生命期不变的值.
	Name() string

	// Render produces the text content. Context carries cwd, model family,
	// language, etc. — engine-provided invariants, NOT domain content.
	// Empty string return is legal (signals "section produces nothing this time").
	//
	// 产出文本. Context 带 cwd / model family / language 等 engine 提供的不变量,
	// 不带 domain 内容. 返回空串合法 (表示"本次此段不产出").
	Render(ctx Context) (string, error)
}

Section is a renderable prompt fragment.

Section 是可渲染的提示词片段.

type SectionRenderError

type SectionRenderError struct {
	Layer   string
	Section string
	Cause   error
}

SectionRenderError wraps an error from a Section.Render call. Layer is "base" or "conditional"; Section is the offending section's Name().

SectionRenderError 包装 Section.Render 调用的错误. Layer 是 "base" 或 "conditional"; Section 是出错段的 Name().

func (*SectionRenderError) Error

func (e *SectionRenderError) Error() string

func (*SectionRenderError) Unwrap

func (e *SectionRenderError) Unwrap() error

type Trigger

type Trigger interface {
	// On returns the event type this trigger listens for.
	//
	// 监听的事件类型.
	On() TriggerEvent

	// Inject decides whether to fire on this specific event instance and
	// returns the reminder text if firing. Empty string = skip.
	// Returned text is wrapped by the engine in <system-reminder> tags.
	//
	// 决定是否在此具体事件触发, 返回 reminder 文本; 空串 = 跳过.
	// 返回文本由 engine 包 <system-reminder> 标签.
	Inject(evt Event) string
}

Trigger declares a runtime event handler that injects a system reminder.

Trigger 是运行时事件处理器, 命中时注入 system reminder.

type TriggerEvent

type TriggerEvent int

TriggerEvent enumerates engine-emitted event types Layer-3 triggers can listen for. EventCustom is reserved for caller-defined extensions.

TriggerEvent 列举 engine 发出的事件类型. EventCustom 给调用方扩展.

const (
	// EventToolResult fires after any tool returns.
	// 任一工具返回后触发.
	EventToolResult TriggerEvent = iota

	// EventFileRead fires when a Read-style tool reads a file.
	// Read 类工具读完文件触发.
	EventFileRead

	// EventFileMTimeDrift fires when a previously-read file's mtime
	// has drifted since last cache snapshot.
	// 之前读过的文件 mtime 自上次缓存以来漂移时触发.
	EventFileMTimeDrift

	// EventPermissionWait fires while a permission request is pending.
	// 权限请求挂起时触发.
	EventPermissionWait

	// EventTokenBudgetLow fires when remaining token budget < 20% of cap.
	// 剩余 token budget < 上限 20% 时触发.
	EventTokenBudgetLow

	// EventTurnStart fires at the start of every turn (use sparingly —
	// per-turn injection inflates messages array fast).
	// 每轮开始触发 (慎用, 每轮注入让 messages 快速膨胀).
	EventTurnStart

	// EventCustom is reserved for caller-defined events. Use Event.Custom
	// field to discriminate sub-types.
	// 给调用方自定义, 用 Event.Custom 字段区分子类型.
	EventCustom
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL