Skip to main content

soma_codemode/execute/
proxy.rs

1use serde_json::Value;
2
3use crate::host::CodeModeHost;
4use crate::preamble::{
5    generate_discovery_js, generate_js_proxy_from_catalog, generate_local_provider_js,
6};
7use crate::types::{CodeModeCaller, CodeModeSurface, ToolDescriptor, ToolScope};
8use crate::ToolError;
9
10pub(crate) async fn load_entries<H: CodeModeHost>(
11    host: Option<&H>,
12    caller: &CodeModeCaller,
13    surface: CodeModeSurface,
14    scope: &ToolScope,
15) -> Result<Vec<ToolDescriptor>, ToolError> {
16    match host {
17        Some(host) => Ok(host
18            .list_tools(caller, surface, scope, true, true)
19            .await?
20            .entries
21            .iter()
22            .filter(|entry| scope.allows(&entry.id))
23            .cloned()
24            .collect()),
25        None => Ok(Vec::new()),
26    }
27}
28
29pub(crate) fn build_proxy(
30    entries: &[ToolDescriptor],
31    blend_weight: f32,
32) -> Result<String, ToolError> {
33    let values = entries
34        .iter()
35        .map(|entry| serde_json::to_value(entry).map_err(serialize_error))
36        .collect::<Result<Vec<Value>, _>>()?;
37    let mut proxy = String::new();
38    proxy.push_str(generate_local_provider_js());
39    #[cfg(feature = "openapi")]
40    proxy.push_str(crate::preamble::generate_openapi_provider_js());
41    proxy.push_str(
42        &generate_discovery_js(&values, blend_weight).map_err(ToolError::internal_message)?,
43    );
44    proxy.push_str(&generate_js_proxy_from_catalog(entries).map_err(ToolError::internal_message)?);
45    proxy.push_str(
46        r#"
47codemode.run = (name, input = {}) => globalThis.__somaRunSnippet(name, input);
48codemode.step = (name, fn) => globalThis.__somaCodemodeStep(name, fn);
49codemode.search = async (query = "") => {
50  const q = String(query || "").toLowerCase();
51  return globalThis.__codemodeDiscovery.filter((entry) => JSON.stringify(entry).toLowerCase().includes(q));
52};
53codemode.describe = async (query = "") => ({
54  tools: (await codemode.search(query)).map((entry) => ({
55    id: entry.id,
56    signature: entry.signature,
57    dts: entry.dts,
58    description: entry.description
59  }))
60});
61"#,
62    );
63    Ok(proxy)
64}
65
66fn serialize_error(error: serde_json::Error) -> ToolError {
67    ToolError::internal_message(format!("failed to serialize Code Mode value: {error}"))
68}