Skip to main content

systemprompt_cli/commands/core/artifacts/
list.rs

1use anyhow::{Context, Result};
2use clap::Args;
3use systemprompt_agent::repository::content::artifact::ArtifactRepository;
4use systemprompt_database::DbPool;
5use systemprompt_identifiers::ContextId;
6use systemprompt_logging::CliService;
7
8use super::types::{ArtifactListOutput, ArtifactSummary};
9use crate::cli_settings::CliConfig;
10use crate::context::CommandContext;
11use crate::presentation::tables::artifact_list_table;
12use crate::session::get_or_create_session;
13use crate::shared::CommandOutput;
14
15#[derive(Debug, Args)]
16pub struct ListArgs {
17    #[arg(long = "context-id", short = 'c', help = "Filter by context ID")]
18    pub context: Option<String>,
19
20    #[arg(
21        long,
22        short = 'l',
23        default_value = "20",
24        help = "Maximum artifacts to show"
25    )]
26    pub limit: i32,
27}
28
29pub(super) async fn execute(args: ListArgs, ctx: &CommandContext) -> Result<CommandOutput> {
30    let session_ctx = get_or_create_session(ctx).await?;
31    let pool = ctx.db_pool().await?;
32    execute_with_pool(args, &session_ctx.session.user_id, &pool, &ctx.cli).await
33}
34
35pub async fn execute_with_pool(
36    args: ListArgs,
37    user_id: &systemprompt_identifiers::UserId,
38    pool: &DbPool,
39    config: &CliConfig,
40) -> Result<CommandOutput> {
41    let repo = ArtifactRepository::new(pool)?;
42
43    let artifacts = if let Some(ref ctx_id) = args.context {
44        let context_id = ContextId::new(ctx_id);
45        repo.get_artifacts_by_context(&context_id)
46            .await
47            .context("Failed to fetch artifacts by context")?
48    } else {
49        repo.get_artifacts_by_user_id(user_id, Some(args.limit))
50            .await
51            .context("Failed to fetch artifacts")?
52    };
53
54    let summaries: Vec<ArtifactSummary> = artifacts
55        .iter()
56        .take(args.limit as usize)
57        .map(|a| ArtifactSummary {
58            artifact_id: a.id.clone(),
59            name: a.title.clone(),
60            artifact_type: a.metadata.artifact_type.clone(),
61            tool_name: a.metadata.tool_name.clone(),
62            task_id: a.metadata.task_id.clone(),
63            created_at: chrono::DateTime::parse_from_rfc3339(&a.metadata.created_at)
64                .map_or_else(|_| chrono::Utc::now(), |dt| dt.with_timezone(&chrono::Utc)),
65        })
66        .collect();
67
68    let total = summaries.len();
69
70    let output = ArtifactListOutput {
71        artifacts: summaries.clone(),
72        total,
73        context: args.context.clone(),
74    };
75
76    if !config.is_json_output() {
77        CliService::section("Artifacts");
78
79        if summaries.is_empty() {
80            CliService::info("No artifacts found");
81        } else {
82            CliService::output(&artifact_list_table(&summaries));
83
84            CliService::info(&format!("Showing {} artifact(s)", total));
85        }
86    }
87
88    Ok(CommandOutput::table_of(
89        vec!["id", "name", "artifact_type", "tool_name", "created_at"],
90        &output.artifacts,
91    )
92    .with_title("Artifacts"))
93}