Skip to main content

systemprompt_cli/commands/core/contexts/
resolve.rs

1//! Context-id resolution from partial input.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use anyhow::{Context, Result, bail};
7use systemprompt_agent::repository::context::ContextRepository;
8use systemprompt_identifiers::{ContextId, UserId};
9
10pub async fn resolve_context(
11    identifier: &str,
12    user_id: &UserId,
13    repo: &ContextRepository,
14) -> Result<ContextId> {
15    let contexts = repo
16        .list_contexts_basic(user_id)
17        .await
18        .context("Failed to list contexts for resolution")?;
19
20    if let Some(ctx) = contexts
21        .iter()
22        .find(|c| c.context_id.as_str() == identifier)
23    {
24        return Ok(ctx.context_id.clone());
25    }
26
27    if identifier.len() >= 4 {
28        let matches: Vec<_> = contexts
29            .iter()
30            .filter(|c| c.context_id.as_str().starts_with(identifier))
31            .collect();
32
33        match matches.len() {
34            0 => {},
35            1 => return Ok(matches[0].context_id.clone()),
36            _ => {
37                let ids: Vec<&str> = matches.iter().map(|c| c.context_id.as_str()).collect();
38                bail!(
39                    "Ambiguous context ID prefix '{}'. Matches: {}",
40                    identifier,
41                    ids.join(", ")
42                );
43            },
44        }
45    }
46
47    if let Some(ctx) = contexts.iter().find(|c| c.name == identifier) {
48        return Ok(ctx.context_id.clone());
49    }
50
51    let lower_identifier = identifier.to_lowercase();
52    let name_matches: Vec<_> = contexts
53        .iter()
54        .filter(|c| c.name.to_lowercase() == lower_identifier)
55        .collect();
56
57    match name_matches.len() {
58        0 => bail!("Context not found: '{}'", identifier),
59        1 => Ok(name_matches[0].context_id.clone()),
60        _ => {
61            let names: Vec<&str> = name_matches.iter().map(|c| c.name.as_str()).collect();
62            bail!(
63                "Ambiguous context name '{}'. Matches: {}",
64                identifier,
65                names.join(", ")
66            );
67        },
68    }
69}