Skip to main content

systemprompt_cli/commands/core/contexts/
new.rs

1//! `core contexts new` command.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use anyhow::{Context, Result};
7use chrono::Utc;
8use clap::Args;
9use systemprompt_agent::models::context::ContextKind;
10use systemprompt_agent::repository::context::ContextRepository;
11use systemprompt_cloud::{SessionKey, SessionStore};
12use systemprompt_logging::CliService;
13
14use super::types::ContextSwitchedOutput;
15use crate::CliConfig;
16use crate::context::CommandContext;
17use crate::paths::ResolvedPaths;
18use crate::session::{CliSessionContext, get_or_create_session};
19use crate::shared::CommandOutput;
20use std::path::Path;
21use systemprompt_database::DbPool;
22
23#[derive(Debug, Args)]
24pub struct NewArgs {
25    #[arg(long, help = "Name for the new context")]
26    pub name: Option<String>,
27}
28
29pub(super) async fn execute(args: NewArgs, ctx: &CommandContext) -> Result<CommandOutput> {
30    let session_ctx = get_or_create_session(ctx).await?;
31    let pool = ctx.db_pool().await?;
32    let sessions_dir = ResolvedPaths::discover().sessions_dir();
33    execute_resolved(args, &ctx.cli, &session_ctx, &pool, &sessions_dir).await
34}
35
36pub async fn execute_resolved(
37    args: NewArgs,
38    cli: &CliConfig,
39    session_ctx: &CliSessionContext,
40    pool: &DbPool,
41    sessions_dir: &Path,
42) -> Result<CommandOutput> {
43    let repo = ContextRepository::new(pool)?;
44
45    let name = args
46        .name
47        .unwrap_or_else(|| format!("Context - {}", Utc::now().format("%Y-%m-%d %H:%M")));
48
49    let context_id = repo
50        .create_context(
51            &session_ctx.session.user_id,
52            Some(&session_ctx.session.session_id),
53            &name,
54            ContextKind::User,
55        )
56        .await
57        .context("Failed to create context")?;
58
59    let mut store = SessionStore::load_or_create(sessions_dir)?;
60
61    let session_key = SessionKey::from_tenant_id(
62        session_ctx
63            .profile
64            .cloud
65            .as_ref()
66            .and_then(|c| c.tenant_id.as_ref()),
67    );
68
69    let mut session = session_ctx.session.clone();
70    session.set_context_id(context_id.clone());
71    store.upsert_session(&session_key, session);
72    store.save(sessions_dir)?;
73
74    let output = ContextSwitchedOutput {
75        id: context_id.clone(),
76        name: name.clone(),
77        message: format!("Created and switched to context '{}'", name),
78    };
79
80    if !cli.is_json_output() {
81        CliService::success(&output.message);
82        CliService::key_value("ID", context_id.as_str());
83        CliService::key_value("Name", &name);
84    }
85
86    Ok(CommandOutput::card_value("New Context Created", &output))
87}