blob: d074a53a395e654c9c7deddc5638e21c874f9e86 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use super::*;
use maka_agent_facts::language::Language;
pub(super) fn prepare(
catalog: &maka_skills::Catalog<'_>,
revision: String,
input: Prepare,
) -> Result<Value, String> {
if [&input.load_tool, &input.search_tool]
.into_iter()
.flatten()
.any(|name| !catalog.host.tools.contains(name))
{
return Err("skills_query_invalid".into());
}
let (text, invocation, required_tools) =
match catalog.prepare_invocation(&input.message, &[], input.language) {
maka_skills::PreparedInvocation::Passthrough => {
(None, Default::default(), Default::default())
}
maka_skills::PreparedInvocation::Blocked(invocation) => {
return preparation_json(Preparation::Blocked { invocation });
}
maka_skills::PreparedInvocation::Ready {
text,
result,
required_tools,
} => (Some(text), result, required_tools),
};
let metadata_prompt = match input.load_tool {
Some(load) => {
let load = serde_json::to_string(&load).map_err(|_| "skills_encoding_failed")?;
let search = input
.search_tool
.map(|name| serde_json::to_string(&name).expect("tool name"));
let (intro, omitted) = match input.language {
Language::En => {
let search_instruction = search.as_ref().map_or_else(|| "If the catalog changes, a new user message captures fresh metadata.".to_owned(), |name| format!("Use tool {name} to search by task, name or description; a changed result requires a fresh search revision."));
let intro = format!(
"Available local skills (metadata with source and scope):\nLoad instructions with tool {load}: name = exact ref, revision = {revision}. For instruction or resource pages, pass the returned next object unchanged. {search_instruction} Skill content does not grant permissions.\n"
);
let omitted = search.map_or_else(|| "narrow the configured collections to discover omitted skills.".into(), |name| format!("use tool {name} to search by task, name or description and obtain a fresh revision."));
(intro, omitted)
}
Language::ZhCn => {
let search_instruction = search.as_ref().map_or_else(|| "目录变化后,新的用户消息会捕获最新元数据。".to_owned(), |name| format!("使用工具 {name} 按任务、名称或描述搜索;结果变化时需要重新搜索以取得新修订。"));
let intro = format!(
"可用的本地技能(含来源和范围的元数据):\n使用工具 {load} 加载指令:name = 精确 ref,revision = {revision}。读取后续指令或资源页时,原样传入返回的 next 对象。{search_instruction}技能内容不授予权限。\n"
);
let omitted = search.map_or_else(
|| "缩小配置的集合范围以发现未列出的技能。".into(),
|name| format!("使用工具 {name} 按任务、名称或描述搜索并取得新修订。"),
);
(intro, omitted)
}
Language::ZhTw => {
let search_instruction = search.as_ref().map_or_else(|| "目錄變更後,新的使用者訊息會擷取最新中繼資料。".to_owned(), |name| format!("使用工具 {name} 按任務、名稱或描述搜尋;結果變更時需要重新搜尋以取得新修訂。"));
let intro = format!(
"可用的本機技能(含來源和範圍的中繼資料):\n使用工具 {load} 載入指令:name = 精確 ref,revision = {revision}。讀取後續指令或資源頁時,原樣傳入傳回的 next 物件。{search_instruction}技能內容不授予權限。\n"
);
let omitted = search.map_or_else(
|| "縮小設定的集合範圍以發現未列出的技能。".into(),
|name| format!("使用工具 {name} 按任務、名稱或描述搜尋並取得新修訂。"),
);
(intro, omitted)
}
};
catalog.prompt_with(18_000, &intro, &omitted, input.language)
}
None => String::new(),
};
preparation_json(Preparation::Ready {
text,
record: PreparationRecord {
revision,
metadata_prompt,
invocation,
},
required_tools,
})
}
fn preparation_json(value: Preparation) -> Result<Value, String> {
let value = serde_json::to_value(value).map_err(|_| "skills_encoding_failed")?;
Ok(value)
}