worker: replace filesystem prompts with effective DCDL catalog

This commit is contained in:
2026-08-14 13:45:03 +09:00
parent 48ff977d06
commit 0ad7d6d210
45 changed files with 892 additions and 1895 deletions
+1 -20
View File
@@ -349,11 +349,6 @@ impl From<FeatureConfig> for FeatureConfigPartial {
pub struct WorkerMetaConfig {
#[serde(default)]
pub name: Option<String>,
/// Optional `PromptCatalog` manifest pack override. See
/// [`crate::WorkerMeta::prompt_pack`] for semantics. Relative paths
/// are resolved through [`WorkerManifestConfig::resolve_paths`].
#[serde(default)]
pub prompt_pack: Option<PathBuf>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -554,9 +549,6 @@ impl WorkerManifestConfig {
base.display()
);
resolve_auth_file(&mut self.model.auth, base);
if let Some(ref mut pack) = self.worker.prompt_pack {
*pack = join_if_relative(base, pack);
}
for rule in &mut self.scope.allow {
rule.target = join_if_relative(base, &rule.target);
}
@@ -718,7 +710,6 @@ impl WorkerMetaConfig {
fn merge(self, upper: Self) -> Self {
Self {
name: upper.name.or(self.name),
prompt_pack: upper.prompt_pack.or(self.prompt_pack),
}
}
}
@@ -1018,10 +1009,6 @@ impl TryFrom<WorkerManifestConfig> for WorkerManifest {
.worker
.name
.ok_or(ResolveError::MissingField("worker.name"))?;
let prompt_pack = cfg.worker.prompt_pack;
if let Some(ref p) = prompt_pack {
ensure_absolute("worker.prompt_pack", p)?;
}
validate_model_paths(&cfg.model, "model.auth.file")?;
@@ -1150,7 +1137,7 @@ impl TryFrom<WorkerManifestConfig> for WorkerManifest {
validate_mcp_config(&cfg.mcp)?;
Ok(WorkerManifest {
worker: WorkerMeta { name, prompt_pack },
worker: WorkerMeta { name },
model: cfg.model,
engine,
scope: cfg.scope,
@@ -1187,7 +1174,6 @@ mod tests {
WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("test".into()),
prompt_pack: None,
},
model: ModelManifest {
scheme: Some(SchemeKind::Anthropic),
@@ -1505,7 +1491,6 @@ mod tests {
let lower = WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("lower".into()),
prompt_pack: None,
},
model: ModelManifest {
model_id: Some("lower-model".into()),
@@ -1516,7 +1501,6 @@ mod tests {
let upper = WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("upper".into()),
prompt_pack: None,
},
..Default::default()
};
@@ -1925,7 +1909,6 @@ enabled = false
.merge(WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("feature-test".into()),
prompt_pack: None,
},
model: ModelManifest {
scheme: Some(SchemeKind::Anthropic),
@@ -2008,7 +1991,6 @@ enabled = true
.merge(WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("feature-merge-test".into()),
prompt_pack: None,
},
model: ModelManifest {
scheme: Some(SchemeKind::Anthropic),
@@ -2075,7 +2057,6 @@ permission = "write"
let overlay = WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some("x".into()),
prompt_pack: None,
},
model: ModelManifest {
scheme: Some(SchemeKind::Anthropic),
+3 -4
View File
@@ -42,10 +42,9 @@ pub const COMPACT_OVERVIEW_WARNING_TOKENS: u64 = 16_000;
/// See [`crate::CompactionConfig::overview_deadline_tokens`].
pub const COMPACT_OVERVIEW_DEADLINE_TOKENS: u64 = 40_000;
/// Default instruction asset reference used when `worker.instruction`
/// is omitted. See the `PromptLoader` prefix addressing scheme for the
/// `$yoi/` / `$user/` / `$workspace/` namespaces.
pub const DEFAULT_INSTRUCTION: &str = "$yoi/default";
/// Default exact catalog-root dotted Prompt name used when
/// `worker.instruction` is omitted.
pub const DEFAULT_INSTRUCTION: &str = "default";
/// Default language policy used by the main worker for normal prose
/// responses. See [`crate::EngineManifest::language`].
+4 -20
View File
@@ -500,29 +500,13 @@ pub struct MemoryConfig {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkerMeta {
pub name: String,
/// Optional path to a TOML override file read as the top layer of
/// `worker::PromptCatalog`. Subject to the same relative-path
/// resolution as other manifest paths (joined against the
/// manifest's base directory). `None` leaves the 4th overlay layer
/// empty; auto-discovered user and workspace packs still apply.
///
/// Note: unlike `worker.instruction`, this is a plain filesystem
/// path — not a `$prefix/` prompt reference. Pack files carry
/// structured TOML data, while `worker.instruction` points at a
/// minijinja `.md` template; the two use different addressing
/// conventions on purpose.
#[serde(default)]
pub prompt_pack: Option<PathBuf>,
}
/// Worker-level configuration embedded in the manifest.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EngineManifest {
/// Reference to the instruction prompt asset used as the body of
/// the worker's system prompt. Uses the `PromptLoader` prefix
/// addressing scheme (`$yoi/...`, `$user/...`,
/// `$workspace/...`) and is always populated after resolution —
/// unset manifests fall through to [`defaults::DEFAULT_INSTRUCTION`].
/// Exact catalog-root dotted Prompt name (for example `default` or
/// `role.coder`).
#[serde(default = "default_instruction")]
pub instruction: String,
/// Language policy used by the main worker for normal prose responses.
@@ -959,7 +943,7 @@ model_id = "claude-sonnet-4-20250514"
auth = { kind = "api_key", file = "/abs/keys/anthropic" }
[engine]
instruction = "$user/reviewer"
instruction = "role.reviewer"
max_tokens = 4096
temperature = 0.3
top_p = 0.9
@@ -995,7 +979,7 @@ permission = "write"
_ => panic!("expected ApiKey"),
};
assert_eq!(file, Some(std::path::Path::new("/abs/keys/anthropic")));
assert_eq!(manifest.engine.instruction, "$user/reviewer");
assert_eq!(manifest.engine.instruction, "role.reviewer");
assert_eq!(manifest.engine.max_tokens, Some(4096));
assert_eq!(manifest.engine.temperature, Some(0.3));
assert_eq!(manifest.engine.top_p, Some(0.9));
+1 -27
View File
@@ -3,7 +3,7 @@
//! 用途別に三つの base directory を持つ:
//!
//! - **`config_dir`** — 人が手で書く / 編集する設定。`profiles.toml`,
//! `providers.toml`, `models.toml`, `prompts/`, `prompts.toml`
//! `providers.toml`, `models.toml` 等
//! - **`data_dir`** — プログラムが書く永続データ。`sessions/` 等
//! - **`secret_data_dir`** — local secret store の読み書き base。既存
//! secret store は path-derived key を使うため、通常 data とは別に
@@ -85,16 +85,6 @@ pub fn user_profiles_path() -> Option<PathBuf> {
user_profiles_path_from_config_dir(config_dir())
}
/// `<config_dir>/prompts/` — user prompts ライブラリ。
pub fn user_prompts_dir() -> Option<PathBuf> {
user_prompts_dir_from_config_dir(config_dir())
}
/// `<config_dir>/prompts.toml` — user prompt pack。
pub fn user_pack_file() -> Option<PathBuf> {
user_pack_file_from_config_dir(config_dir())
}
/// `<config_dir>/<file_name>` — providers.toml / models.toml 等の
/// user override ファイル。
pub fn user_catalog_override(file_name: &str) -> Option<PathBuf> {
@@ -200,14 +190,6 @@ fn user_profiles_path_from_config_dir(config_dir: Option<PathBuf>) -> Option<Pat
Some(config_dir?.join("profiles.toml"))
}
fn user_prompts_dir_from_config_dir(config_dir: Option<PathBuf>) -> Option<PathBuf> {
Some(config_dir?.join("prompts"))
}
fn user_pack_file_from_config_dir(config_dir: Option<PathBuf>) -> Option<PathBuf> {
Some(config_dir?.join("prompts.toml"))
}
fn user_catalog_override_from_config_dir(
config_dir: Option<PathBuf>,
file_name: &str,
@@ -465,14 +447,6 @@ mod tests {
user_profiles_path_from_config_dir(config_dir.clone()).unwrap(),
PathBuf::from("/sand/config/profiles.toml")
);
assert_eq!(
user_prompts_dir_from_config_dir(config_dir.clone()).unwrap(),
PathBuf::from("/sand/config/prompts")
);
assert_eq!(
user_pack_file_from_config_dir(config_dir.clone()).unwrap(),
PathBuf::from("/sand/config/prompts.toml")
);
assert_eq!(
user_catalog_override_from_config_dir(config_dir, "providers.toml").unwrap(),
PathBuf::from("/sand/config/providers.toml")
-1
View File
@@ -547,7 +547,6 @@ fn resolve_profile_value(
let config = WorkerManifestConfig {
worker: WorkerMetaConfig {
name: Some(worker_name),
prompt_pack: None,
},
model: profile.model.unwrap_or_default(),
engine: profile.engine.unwrap_or_default(),