Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1559d2c
🐛 fix(prompt): send the repo name, not -/<name>, when push creates a …
codekiln Oct 14, 2026
f9a6ab4
📚 docs(prompt): say what the owner-dash test does
codekiln Oct 14, 2026
9ce26e9
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 14, 2026
6141cc8
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 14, 2026
2fd54d1
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 27, 2026
ecbb7a0
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
6e0e4df
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
8fe701e
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
7a8a5fa
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
29e732d
🩹 fix(test): read the empty config directory the structured prompt te…
codekiln Oct 30, 2026
531a80f
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
2581445
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
df0fc48
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 30, 2026
1f0750a
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Oct 31, 2026
fe3e81a
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Nov 1, 2026
298dad5
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Nov 1, 2026
f4a1a5e
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Nov 2, 2026
fe6ba0f
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Nov 2, 2026
09e6c14
Merge branch 'main' into m19-i820-prompt-push-owner-dash
codekiln Nov 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions cli/tests/prompt_structured_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -860,3 +860,88 @@ fn test_cli_push_prompt_update_with_auto_parent() {

// CLEANUP: Automatic via Drop trait
}

/// Deletes a repo by name on drop without creating it first, for tests where the CLI creates the repo.
struct NewRepoCleanup {
repo_name: String,
runtime: tokio::runtime::Runtime,
client: LangchainClient,
}

impl NewRepoCleanup {
fn new(repo_name: &str) -> Self {
Self {
repo_name: repo_name.to_string(),
runtime: create_runtime(),
client: create_sdk_client().expect("Failed to create SDK client"),
}
}
}

impl Drop for NewRepoCleanup {
fn drop(&mut self) {
println!("[CLEANUP] Deleting repo: {}", self.repo_name);
let _ = self
.runtime
.block_on(async { self.client.prompts().delete(&self.repo_name).await });
}
}

/// Guards [Issue #820 prompt push --owner - fails when it creates a new repo](https://github.com/codekiln/langstar/issues/820): pushing with `--owner -` to a repo that does not exist creates the repo and its first commit.
#[test]
#[cfg_attr(not(feature = "integration-tests"), ignore)]
#[serial]
fn test_cli_push_creates_new_repo_with_owner_dash() {
check_env_vars_private_prompts();

let repo_name = generate_unique_repo_name("test-push-owner-dash");
// CLEANUP: declared before the push so the repo is deleted even if an assertion fails
let _cleanup = NewRepoCleanup::new(&repo_name);

let schema_file = create_temp_schema_file();
let schema_path = schema_file.path().to_str().unwrap();
let bin = get_langstar_bin();

// TEST: push to a repo that does not exist yet
let mut push_cmd = Command::new(&bin);
push_cmd.env("LANGSTAR_CONFIG_DIR", config_dir::empty_config_dir());
push_cmd.args([
"prompt",
"push",
"--owner",
"-",
"--repo",
&repo_name,
"--template",
"Owner dash push: {input}",
"--input-variables",
"input",
"--schema",
schema_path,
]);
push_cmd.assert().success();

// VERIFY: the pulled manifest has the pushed template and schema
let mut pull_cmd = Command::new(&bin);
pull_cmd.env("LANGSTAR_CONFIG_DIR", config_dir::empty_config_dir());
pull_cmd.args([
"prompt",
"pull",
"--format",
"json",
"--",
&format!("-/{}", repo_name),
]);
let output = pull_cmd.assert().success();
let stdout = String::from_utf8_lossy(&output.get_output().stdout);
assert!(
stdout.contains("Owner dash push: {input}"),
"pulled manifest should contain the pushed template, got: {}",
stdout
);
assert!(
stdout.contains("TestOutput"),
"pulled manifest should contain the pushed schema title, got: {}",
stdout
);
}
25 changes: 23 additions & 2 deletions sdk/src/prompts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ pub struct Prompt {
pub is_public: bool,
}

/// The `repo_handle` to send when creating a repo: `-/name` (`-` is the current
/// workspace) becomes `name`, and every other handle is sent as given.
fn create_repo_handle(repo_handle: &str) -> &str {
repo_handle.strip_prefix("-/").unwrap_or(repo_handle)
}

/// Client for interacting with LangSmith Prompts API
pub struct PromptClient<'a> {
client: &'a LangchainClient,
Expand Down Expand Up @@ -465,7 +471,11 @@ impl<'a> PromptClient<'a> {
/// Create a new prompt repository
///
/// # Arguments
/// * `repo_handle` - The handle for the repository (e.g., "owner/repo-name")
/// * `repo_handle` - The handle for the repository (e.g., "owner/repo-name"). A
/// `-/repo-name` handle, where `-` means the current workspace, is sent as
/// just `repo-name`, because the API rejects a handle that contains `-/`.
/// [`langsmith-sdk`](https://github.com/langchain-ai/langsmith-sdk/blob/9966fd69a631369398d7598d8d725868f9c74339/python/langsmith/client.py#L9904)
/// also sends only the name.
/// * `description` - Optional description
/// * `readme` - Optional readme content
/// * `is_public` - Whether the repository is public (default: false)
Expand All @@ -490,7 +500,7 @@ impl<'a> PromptClient<'a> {
}

let request_body = CreateRepoRequest {
repo_handle: repo_handle.to_string(),
repo_handle: create_repo_handle(repo_handle).to_string(),
description,
readme,
is_public,
Expand Down Expand Up @@ -1263,6 +1273,17 @@ mod tests {
use crate::auth::AuthConfig;
use serde_json::json;

#[test]
fn test_create_repo_handle_drops_current_workspace_owner() {
assert_eq!(create_repo_handle("-/my-prompt"), "my-prompt");
}

#[test]
fn test_create_repo_handle_keeps_named_owner_and_bare_name() {
assert_eq!(create_repo_handle("acme/my-prompt"), "acme/my-prompt");
assert_eq!(create_repo_handle("my-prompt"), "my-prompt");
}

#[test]
fn test_prompt_client_creation() {
let auth = AuthConfig::new(Some("test".to_string()), None, None);
Expand Down
Loading