mirror of
https://github.com/langchain-ai/langsmith-java.git
synced 2026-08-24 22:01:31 -04:00
chore: convert to kotlin
This commit is contained in:
committed by
stainless-app[bot]
parent
3fdd586165
commit
802f5a118c
@@ -8,10 +8,15 @@ This module contains runnable examples organized by feature:
|
||||
|
||||
All examples require:
|
||||
```bash
|
||||
./gradlew :langsmith-java-example:run -Pexample=ExampleName -Dlangchain.langsmithApiKey=your_api_key
|
||||
```
|
||||
|
||||
Alternatively, you can use environment variables:
|
||||
```bash
|
||||
export LANGSMITH_API_KEY=your_api_key
|
||||
```
|
||||
|
||||
The `LANGCHAIN_BASE_URL` environment variable is optional and defaults to `https://api.smith.langchain.com` if not set.
|
||||
The `langchain.baseUrl` system property (or `LANGCHAIN_BASE_URL` environment variable) is optional and defaults to `https://api.smith.langchain.com/` if not set.
|
||||
|
||||
## OpenTelemetry Tracing Examples
|
||||
|
||||
@@ -37,10 +42,10 @@ open http://localhost:16686
|
||||
Make actual OpenAI API calls with automatic tracing to LangSmith.
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_openai_key
|
||||
export LANGSMITH_PROJECT=my-project # optional, defaults to "default"
|
||||
|
||||
./gradlew :langsmith-java-example:run -Pexample=OtelOpenAI
|
||||
./gradlew :langsmith-java-example:run -Pexample=OtelOpenAI \
|
||||
-Dlangchain.langsmithApiKey=your_api_key \
|
||||
-DOPENAI_API_KEY=your_openai_key \
|
||||
-DLANGSMITH_PROJECT=my-project # optional, defaults to "default"
|
||||
```
|
||||
|
||||
View traces at https://smith.langchain.com
|
||||
@@ -50,9 +55,9 @@ View traces at https://smith.langchain.com
|
||||
Send mock traces to LangSmith without external API calls.
|
||||
|
||||
```bash
|
||||
export LANGSMITH_PROJECT=my-project # optional, defaults to "default"
|
||||
|
||||
./gradlew :langsmith-java-example:run -Pexample=OtelLangSmith
|
||||
./gradlew :langsmith-java-example:run -Pexample=OtelLangSmith \
|
||||
-Dlangchain.langsmithApiKey=your_api_key \
|
||||
-DLANGSMITH_PROJECT=my-project # optional, defaults to "default"
|
||||
```
|
||||
|
||||
View traces at https://smith.langchain.com
|
||||
@@ -62,10 +67,10 @@ View traces at https://smith.langchain.com
|
||||
REST API with OpenTelemetry traces sent to LangSmith.
|
||||
|
||||
```bash
|
||||
export LANGSMITH_PROJECT=my-project # optional
|
||||
|
||||
# Start server
|
||||
./gradlew :langsmith-java-example:run -Pexample=SpringBootLangSmith
|
||||
./gradlew :langsmith-java-example:run -Pexample=SpringBootLangSmith \
|
||||
-Dlangchain.langsmithApiKey=your_api_key \
|
||||
-DLANGSMITH_PROJECT=my-project # optional
|
||||
|
||||
# In another terminal, test endpoints:
|
||||
curl -X POST http://localhost:8080/api/chat \
|
||||
@@ -84,7 +89,8 @@ Located in `src/main/java/com/langchain/smith/example/prompt/`
|
||||
**RECOMMENDED** - Clean, simple example following the same pattern as the Dataset example.
|
||||
|
||||
```bash
|
||||
./gradlew :langsmith-java-example:run -Pexample=PromptManagement
|
||||
./gradlew :langsmith-java-example:run -Pexample=PromptManagement \
|
||||
-Dlangchain.langsmithApiKey=your_api_key
|
||||
```
|
||||
|
||||
**Features demonstrated:**
|
||||
|
||||
-374
@@ -1,374 +0,0 @@
|
||||
package com.langchain.smith.example.prompt;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.langchain.smith.client.LangsmithClient;
|
||||
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
|
||||
import com.langchain.smith.core.JsonValue;
|
||||
import com.langchain.smith.models.commits.CommitListParams;
|
||||
import com.langchain.smith.models.commits.CommitListResponse;
|
||||
import com.langchain.smith.models.commits.CommitManifestResponse;
|
||||
import com.langchain.smith.models.commits.CommitRetrieveParams;
|
||||
import com.langchain.smith.models.commits.CommitUpdateParams;
|
||||
import com.langchain.smith.models.repos.RepoCreateParams;
|
||||
import com.langchain.smith.models.repos.RepoListParams;
|
||||
import com.langchain.smith.models.repos.RepoListResponse;
|
||||
import com.langchain.smith.models.repos.RepoWithLookups;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Demonstrates how to manage prompts programmatically using the LangSmith Java
|
||||
* SDK.
|
||||
*
|
||||
* <p>
|
||||
* This example shows:
|
||||
* - Creating prompt repositories (repos)
|
||||
* - Adding prompt content as commits (with variables)
|
||||
* - Listing prompts with filters
|
||||
* - Retrieving prompt content
|
||||
* - Pulling specific versions
|
||||
*
|
||||
* <p>
|
||||
* Prerequisites:
|
||||
* - `LANGSMITH_API_KEY`: Your LangSmith API key
|
||||
* - `LANGCHAIN_BASE_URL`: LangSmith API URL (https://api.smith.langchain.com)
|
||||
*
|
||||
* <p>
|
||||
* Running:
|
||||
* ```bash
|
||||
* ./gradlew :langsmith-java-example:run -Pexample=PromptManagement
|
||||
* ```
|
||||
*/
|
||||
public class PromptManagementExample {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== LangSmith Prompt Management Example ===\n");
|
||||
|
||||
LangsmithClient client = LangsmithOkHttpClient.fromEnv();
|
||||
String owner = getOwnerFromEnv();
|
||||
String promptName = "joke-generator";
|
||||
|
||||
try {
|
||||
// 1. Check if prompt already exists
|
||||
System.out.println("1. Checking for existing prompt using client.repos().list()...");
|
||||
RepoWithLookups existing = findPrompt(client, promptName);
|
||||
boolean promptExists = existing != null;
|
||||
|
||||
if (promptExists) {
|
||||
System.out.println(" ℹ Prompt '" + promptName + "' already exists");
|
||||
System.out.println(" View: https://smith.langchain.com/prompts/" + existing.fullName());
|
||||
System.out.println(" Skipping creation steps...\n");
|
||||
} else {
|
||||
System.out.println(" ✓ No existing prompt found\n");
|
||||
|
||||
// 2. Create prompt repository (metadata only)
|
||||
System.out.println("2. Creating prompt repository using client.repos().create()...");
|
||||
client.repos()
|
||||
.create(RepoCreateParams.builder()
|
||||
.repoHandle(promptName)
|
||||
.description("A joke generator that accepts a topic variable")
|
||||
.isPublic(false)
|
||||
.build());
|
||||
System.out.println(" ✓ Created prompt repository: " + promptName + "\n");
|
||||
}
|
||||
|
||||
// 3. Add prompt content as a commit (only if prompt is new or has no commits)
|
||||
boolean commitCreated = false;
|
||||
if (promptExists) {
|
||||
String parentCommitHash = getLatestCommitHash(client, promptName, owner);
|
||||
if (parentCommitHash != null) {
|
||||
System.out.println("3. Prompt already has content, skipping commit creation...");
|
||||
System.out.println(" ℹ To update the prompt, delete it first or modify the content\n");
|
||||
} else {
|
||||
commitCreated = createCommit(client, promptName, owner, null);
|
||||
}
|
||||
} else {
|
||||
commitCreated = createCommit(client, promptName, owner, null);
|
||||
}
|
||||
|
||||
// 4. List prompts
|
||||
System.out.println("4. Listing prompts using client.repos().list()...");
|
||||
RepoListResponse allPrompts = client.repos()
|
||||
.list(RepoListParams.builder()
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.limit(100L)
|
||||
.build());
|
||||
System.out.println(" ✓ Found " + allPrompts.repos().size() + " prompt(s) in your organization");
|
||||
|
||||
RepoListResponse jokePrompts = client.repos()
|
||||
.list(RepoListParams.builder()
|
||||
.query("joke")
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.limit(100L)
|
||||
.build());
|
||||
System.out.println(
|
||||
" ✓ Found " + jokePrompts.repos().size() + " prompt(s) matching 'joke' in your organization\n");
|
||||
|
||||
// 5. Pull prompt content (retrieve latest commit)
|
||||
System.out.println("5. Pulling prompt content using client.commits().list() and retrieve()...");
|
||||
|
||||
String commitHash = getLatestCommitHash(client, promptName, owner);
|
||||
if (commitHash == null) {
|
||||
throw new RuntimeException("No commits found for prompt");
|
||||
}
|
||||
|
||||
System.out.println(" ✓ Latest commit: " + commitHash.substring(0, 8) + "...");
|
||||
|
||||
// Retrieve the manifest
|
||||
CommitManifestResponse manifestResponse = client.commits()
|
||||
.retrieve(
|
||||
commitHash,
|
||||
CommitRetrieveParams.builder()
|
||||
.owner(owner)
|
||||
.repo(promptName)
|
||||
.build());
|
||||
|
||||
String promptContent = extractPromptContent(manifestResponse._manifest());
|
||||
System.out.println(" ✓ Prompt content: \"" + promptContent + "\"\n");
|
||||
|
||||
// 6. Demonstrate using the prompt with a value
|
||||
System.out.println("6. Using the prompt with a value...");
|
||||
String filledPrompt = promptContent.replace("{topic}", "dogs");
|
||||
System.out.println(" Template: \"" + promptContent + "\"");
|
||||
System.out.println(" Filled: \"" + filledPrompt + "\"\n");
|
||||
|
||||
// Summary
|
||||
System.out.println("=== Summary ===");
|
||||
if (!promptExists) {
|
||||
System.out.println("✓ Created prompt repository");
|
||||
} else {
|
||||
System.out.println("ℹ Prompt already existed (skipped creation)");
|
||||
}
|
||||
if (commitCreated) {
|
||||
System.out.println("✓ Added prompt content as commit");
|
||||
} else {
|
||||
System.out.println("ℹ Prompt content unchanged (skipped commit)");
|
||||
}
|
||||
System.out.println("✓ Listed and filtered prompts");
|
||||
System.out.println("✓ Retrieved prompt content");
|
||||
System.out.println("✓ Demonstrated using prompt with a value");
|
||||
System.out.println();
|
||||
System.out.println("Learn more:");
|
||||
System.out.println("https://docs.langchain.com/langsmith/manage-prompts-programmatically");
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("\nError: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chat prompt manifest with multiple messages (system + user) compatible with LangSmith.
|
||||
*/
|
||||
private static Map<String, Object> createChatPromptWithMultipleMessages(
|
||||
String systemMessage, String userMessage, String[] inputVariables) {
|
||||
Map<String, Object> manifest = new HashMap<>();
|
||||
manifest.put("lc", 1);
|
||||
manifest.put("type", "constructor");
|
||||
manifest.put("id", new String[] {"langchain", "prompts", "chat", "ChatPromptTemplate"});
|
||||
|
||||
Map<String, Object> kwargs = new HashMap<>();
|
||||
kwargs.put("input_variables", inputVariables);
|
||||
|
||||
java.util.List<Map<String, Object>> messages = new java.util.ArrayList<>();
|
||||
messages.add(createMessagePrompt("system", systemMessage));
|
||||
messages.add(createMessagePrompt("human", userMessage));
|
||||
|
||||
kwargs.put("messages", messages.toArray());
|
||||
manifest.put("kwargs", kwargs);
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message prompt (system, human, or AI).
|
||||
*/
|
||||
private static Map<String, Object> createMessagePrompt(String messageType, String template) {
|
||||
String className;
|
||||
switch (messageType.toLowerCase()) {
|
||||
case "system":
|
||||
className = "SystemMessagePromptTemplate";
|
||||
break;
|
||||
case "ai":
|
||||
case "assistant":
|
||||
className = "AIMessagePromptTemplate";
|
||||
break;
|
||||
case "human":
|
||||
case "user":
|
||||
default:
|
||||
className = "HumanMessagePromptTemplate";
|
||||
break;
|
||||
}
|
||||
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message.put("lc", 1);
|
||||
message.put("type", "constructor");
|
||||
message.put("id", new String[] {"langchain", "core", "prompts", "chat", className});
|
||||
|
||||
Map<String, Object> stringPrompt = new HashMap<>();
|
||||
stringPrompt.put("lc", 1);
|
||||
stringPrompt.put("type", "prompt");
|
||||
stringPrompt.put("id", new String[] {"langchain", "prompts", "prompt", "StringPromptTemplate"});
|
||||
Map<String, Object> stringPromptKwargs = new HashMap<>();
|
||||
stringPromptKwargs.put("template", template);
|
||||
stringPrompt.put("kwargs", stringPromptKwargs);
|
||||
|
||||
Map<String, Object> msgKwargs = new HashMap<>();
|
||||
msgKwargs.put("prompt", stringPrompt);
|
||||
message.put("kwargs", msgKwargs);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines message type from the message object's id field.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static String getMessageType(Map<String, Object> message) {
|
||||
try {
|
||||
Object idObj = message.get("id");
|
||||
String className = null;
|
||||
|
||||
if (idObj instanceof Object[]) {
|
||||
Object[] idArray = (Object[]) idObj;
|
||||
if (idArray.length > 0) {
|
||||
className = idArray[idArray.length - 1].toString();
|
||||
}
|
||||
} else if (idObj instanceof java.util.List) {
|
||||
java.util.List<Object> idList = (java.util.List<Object>) idObj;
|
||||
if (!idList.isEmpty()) {
|
||||
className = idList.get(idList.size() - 1).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (className != null) {
|
||||
if (className.contains("System")) {
|
||||
return "system";
|
||||
} else if (className.contains("AI") || className.contains("Assistant")) {
|
||||
return "assistant";
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Default to "user" if we can't determine the type
|
||||
}
|
||||
return "user";
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a prompt by exact repo handle match.
|
||||
*
|
||||
* @return the prompt if found, null otherwise
|
||||
*/
|
||||
private static RepoWithLookups findPrompt(LangsmithClient client, String promptName) {
|
||||
RepoListResponse existingRepos = client.repos()
|
||||
.list(RepoListParams.builder()
|
||||
.query(promptName)
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.build());
|
||||
|
||||
for (RepoWithLookups repo : existingRepos.repos()) {
|
||||
if (repo.repoHandle().equals(promptName)) {
|
||||
return repo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get the latest commit hash for a prompt repository.
|
||||
*/
|
||||
private static String getLatestCommitHash(LangsmithClient client, String promptName, String owner) {
|
||||
try {
|
||||
CommitListResponse commits = client.commits()
|
||||
.list(
|
||||
promptName,
|
||||
CommitListParams.builder()
|
||||
.owner(owner)
|
||||
.repo(promptName)
|
||||
.limit(1L)
|
||||
.build());
|
||||
if (!commits.commits().isEmpty()) {
|
||||
return commits.commits().get(0).commitHash();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// No commits found
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a commit with prompt content.
|
||||
*
|
||||
* @return true if commit was created, false otherwise
|
||||
*/
|
||||
private static boolean createCommit(LangsmithClient client, String promptName, String owner, String parentCommit) {
|
||||
System.out.println("3. Adding prompt content using client.commits().update()...");
|
||||
Map<String, Object> manifest = createChatPromptWithMultipleMessages(
|
||||
"You are a helpful assistant that tells jokes.", "Tell me a joke about {topic}", new String[] {"topic"
|
||||
});
|
||||
|
||||
CommitUpdateParams.Builder builder =
|
||||
CommitUpdateParams.builder().owner(owner).manifest(JsonValue.from(manifest));
|
||||
if (parentCommit != null) {
|
||||
builder.parentCommit(parentCommit);
|
||||
}
|
||||
|
||||
try {
|
||||
client.commits().update(promptName, builder.build());
|
||||
System.out.println(" ✓ Added prompt content as commit\n");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to create commit", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts prompt content from a manifest for display (shows all messages).
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static String extractPromptContent(JsonValue manifestJson) {
|
||||
try {
|
||||
Map<String, Object> manifest = MAPPER.convertValue(manifestJson, Map.class);
|
||||
Map<String, Object> kwargs = (Map<String, Object>) manifest.get("kwargs");
|
||||
Object messagesObj = kwargs.get("messages");
|
||||
|
||||
Object[] messages;
|
||||
if (messagesObj instanceof Object[]) {
|
||||
messages = (Object[]) messagesObj;
|
||||
} else if (messagesObj instanceof java.util.List) {
|
||||
java.util.List<Object> messagesList = (java.util.List<Object>) messagesObj;
|
||||
messages = messagesList.toArray(new Object[0]);
|
||||
} else {
|
||||
return "Unable to parse prompt content";
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < messages.length; i++) {
|
||||
Map<String, Object> message = (Map<String, Object>) messages[i];
|
||||
Map<String, Object> msgKwargs = (Map<String, Object>) message.get("kwargs");
|
||||
Map<String, Object> prompt = (Map<String, Object>) msgKwargs.get("prompt");
|
||||
Map<String, Object> promptKwargs = (Map<String, Object>) prompt.get("kwargs");
|
||||
String template = promptKwargs.get("template").toString();
|
||||
String messageType = getMessageType(message);
|
||||
|
||||
if (i > 0) {
|
||||
result.append(" | ");
|
||||
}
|
||||
result.append(messageType).append(": \"").append(template).append("\"");
|
||||
}
|
||||
return result.toString();
|
||||
} catch (Exception e) {
|
||||
return "Unable to parse prompt content";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getOwnerFromEnv() {
|
||||
String owner = System.getenv("LANGSMITH_OWNER");
|
||||
return (owner == null || owner.isEmpty()) ? "-" : owner;
|
||||
}
|
||||
}
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
package com.langchain.smith.example
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.langchain.smith.client.LangsmithClient
|
||||
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
|
||||
import com.langchain.smith.core.JsonValue
|
||||
import com.langchain.smith.models.commits.CommitManifestResponse
|
||||
import com.langchain.smith.models.commits.CommitRetrieveParams
|
||||
import com.langchain.smith.models.commits.CommitUpdateParams
|
||||
import com.langchain.smith.models.repos.RepoCreateParams
|
||||
import com.langchain.smith.models.repos.RepoListParams
|
||||
import com.langchain.smith.models.repos.RepoWithLookups
|
||||
|
||||
/**
|
||||
* Demonstrates how to manage prompts programmatically using the LangSmith Java
|
||||
* SDK.
|
||||
*
|
||||
* This example shows:
|
||||
* - Creating prompt repositories (repos)
|
||||
* - Adding prompt content as commits (with variables)
|
||||
* - Listing prompts with filters
|
||||
* - Retrieving prompt content
|
||||
* - Pulling specific versions
|
||||
*
|
||||
* Prerequisites:
|
||||
* - `LANGSMITH_API_KEY`: Your LangSmith API key
|
||||
* - `LANGCHAIN_BASE_URL`: LangSmith API URL (https://api.smith.langchain.com)
|
||||
*
|
||||
* Running:
|
||||
* ```bash
|
||||
* ./gradlew :langsmith-java-example:run -Pexample=PromptManagement
|
||||
* ```
|
||||
*/
|
||||
private val MAPPER = ObjectMapper()
|
||||
|
||||
fun main() {
|
||||
println("=== LangSmith Prompt Management Example ===\n")
|
||||
|
||||
val client = LangsmithOkHttpClient.fromEnv()
|
||||
val owner = getOwnerFromEnv()
|
||||
val promptName = "joke-generator"
|
||||
|
||||
try {
|
||||
// 1. Check if prompt already exists
|
||||
println("1. Checking for existing prompt using client.repos().list()...")
|
||||
val existing = findPrompt(client, promptName)
|
||||
val promptExists = existing.isPresent
|
||||
|
||||
if (promptExists) {
|
||||
val repo = existing.get()
|
||||
println("2. Prompt '$promptName' already exists")
|
||||
println(" View: https://smith.langchain.com/prompts/${repo.fullName()}")
|
||||
println(" Skipping creation steps...\n")
|
||||
} else {
|
||||
println(" ✓ No existing prompt found\n")
|
||||
|
||||
// 2. Create prompt repository (metadata only)
|
||||
println("2. Creating prompt repository using client.repos().create()...")
|
||||
client.repos()
|
||||
.create(
|
||||
RepoCreateParams.builder()
|
||||
.repoHandle(promptName)
|
||||
.description("A joke generator that accepts a topic variable")
|
||||
.isPublic(false)
|
||||
.build()
|
||||
)
|
||||
println(" ✓ Created prompt repository: $promptName\n")
|
||||
}
|
||||
|
||||
// 3. Add prompt content as a commit (only if prompt is new or has no commits)
|
||||
val commitCreated = if (!promptExists || !hasLatestCommit(client, promptName, owner)) {
|
||||
createCommit(client, promptName, owner, null)
|
||||
} else {
|
||||
println("3. Prompt already has content, skipping commit creation...")
|
||||
println(" To update the prompt, delete it first or modify the content\n")
|
||||
false
|
||||
}
|
||||
|
||||
// 4. List prompts
|
||||
println("4. Listing prompts using client.repos().list()...")
|
||||
val allPrompts = client.repos()
|
||||
.list(
|
||||
RepoListParams.builder()
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.build()
|
||||
)
|
||||
println(" ✓ Found ${allPrompts.repos().size} prompt(s) in your organization")
|
||||
|
||||
val jokePrompts = client.repos()
|
||||
.list(
|
||||
RepoListParams.builder()
|
||||
.query("joke")
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.build()
|
||||
)
|
||||
println(" ✓ Found ${jokePrompts.repos().size} prompt(s) matching 'joke' in your organization\n")
|
||||
|
||||
// 5. Pull prompt content (retrieve latest commit)
|
||||
println("5. Pulling prompt content using client.commits().retrieve() with commit='latest'...")
|
||||
|
||||
// Retrieve the manifest using "latest" as the commit hash
|
||||
val manifestResponse = client.commits()
|
||||
.retrieve(
|
||||
"latest",
|
||||
CommitRetrieveParams.builder()
|
||||
.owner(owner)
|
||||
.repo(promptName)
|
||||
.build()
|
||||
)
|
||||
|
||||
println(" ✓ Retrieved latest commit manifest")
|
||||
|
||||
val promptContent = extractPromptContent(manifestResponse._manifest())
|
||||
println(" ✓ Prompt content: \"$promptContent\"\n")
|
||||
|
||||
// 6. Demonstrate using the prompt with a value
|
||||
println("6. Using the prompt with a value...")
|
||||
val filledPrompt = promptContent.replace("{topic}", "dogs")
|
||||
println(" Template: \"$promptContent\"")
|
||||
println(" Filled: \"$filledPrompt\"\n")
|
||||
|
||||
// Summary
|
||||
println("=== Summary ===")
|
||||
if (!promptExists) {
|
||||
println("✓ Created prompt repository")
|
||||
} else {
|
||||
println("ℹ Prompt already existed (skipped creation)")
|
||||
}
|
||||
if (commitCreated) {
|
||||
println("✓ Added prompt content as commit")
|
||||
} else {
|
||||
println("ℹ Prompt content unchanged (skipped commit)")
|
||||
}
|
||||
println("✓ Listed and filtered prompts")
|
||||
println("✓ Retrieved prompt content")
|
||||
println("✓ Demonstrated using prompt with a value")
|
||||
println()
|
||||
println("Learn more:")
|
||||
println("https://docs.langchain.com/langsmith/manage-prompts-programmatically")
|
||||
|
||||
} catch (e: Exception) {
|
||||
System.err.println("\nError: ${e.message}")
|
||||
e.printStackTrace()
|
||||
System.exit(1)
|
||||
} finally {
|
||||
client.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chat prompt manifest with multiple messages (system + user) compatible with LangSmith.
|
||||
*/
|
||||
private fun createChatPromptWithMultipleMessages(
|
||||
systemMessage: String,
|
||||
userMessage: String,
|
||||
inputVariables: Array<String>
|
||||
): Map<String, Any> {
|
||||
val messages = listOf(
|
||||
createMessagePrompt("system", systemMessage),
|
||||
createMessagePrompt("human", userMessage)
|
||||
)
|
||||
|
||||
return mapOf(
|
||||
"lc" to 1,
|
||||
"type" to "constructor",
|
||||
"id" to arrayOf("langchain", "prompts", "chat", "ChatPromptTemplate"),
|
||||
"kwargs" to mapOf(
|
||||
"input_variables" to inputVariables,
|
||||
"messages" to messages.toTypedArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message prompt (system, human, or AI).
|
||||
*/
|
||||
private fun createMessagePrompt(messageType: String, template: String): Map<String, Any> {
|
||||
val className = when (messageType.lowercase()) {
|
||||
"system" -> "SystemMessagePromptTemplate"
|
||||
"ai", "assistant" -> "AIMessagePromptTemplate"
|
||||
"human", "user" -> "HumanMessagePromptTemplate"
|
||||
else -> "HumanMessagePromptTemplate"
|
||||
}
|
||||
|
||||
val stringPrompt = mutableMapOf<String, Any>(
|
||||
"lc" to 1,
|
||||
"type" to "prompt",
|
||||
"id" to arrayOf("langchain", "prompts", "prompt", "StringPromptTemplate"),
|
||||
"kwargs" to mapOf("template" to template)
|
||||
)
|
||||
|
||||
return mapOf(
|
||||
"lc" to 1,
|
||||
"type" to "constructor",
|
||||
"id" to arrayOf("langchain", "core", "prompts", "chat", className),
|
||||
"kwargs" to mapOf("prompt" to stringPrompt)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines message type from the message object's id field.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun getMessageType(message: Map<String, Any>): String {
|
||||
return runCatching {
|
||||
val idObj = message["id"]
|
||||
val className = when (idObj) {
|
||||
is Array<*> -> idObj.lastOrNull()?.toString()
|
||||
is List<*> -> idObj.lastOrNull()?.toString()
|
||||
else -> null
|
||||
}
|
||||
|
||||
when {
|
||||
className?.contains("System") == true -> "system"
|
||||
className?.contains("AI") == true || className?.contains("Assistant") == true -> "assistant"
|
||||
else -> "user"
|
||||
}
|
||||
}.getOrDefault("user")
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a prompt by exact repo handle match.
|
||||
*/
|
||||
private fun findPrompt(client: LangsmithClient, promptName: String): java.util.Optional<RepoWithLookups> {
|
||||
val existingRepos = client.repos()
|
||||
.list(
|
||||
RepoListParams.builder()
|
||||
.query(promptName)
|
||||
.isPublic(RepoListParams.IsPublic.FALSE)
|
||||
.build()
|
||||
)
|
||||
|
||||
return existingRepos.repos().stream()
|
||||
.filter { it.repoHandle() == promptName }
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a prompt repository has a latest commit.
|
||||
*/
|
||||
private fun hasLatestCommit(client: LangsmithClient, promptName: String, owner: String): Boolean {
|
||||
return runCatching {
|
||||
client.commits().retrieve(
|
||||
"latest",
|
||||
CommitRetrieveParams.builder()
|
||||
.owner(owner)
|
||||
.repo(promptName)
|
||||
.build()
|
||||
)
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a commit with prompt content.
|
||||
*
|
||||
* @return true if commit was created, false otherwise
|
||||
*/
|
||||
private fun createCommit(
|
||||
client: LangsmithClient,
|
||||
promptName: String,
|
||||
owner: String,
|
||||
parentCommit: String?
|
||||
): Boolean {
|
||||
println("3. Adding prompt content using client.commits().update()...")
|
||||
val manifest = createChatPromptWithMultipleMessages(
|
||||
"You are a helpful assistant that tells jokes.",
|
||||
"Tell me a joke about {topic}",
|
||||
arrayOf("topic")
|
||||
)
|
||||
|
||||
val params = CommitUpdateParams.builder()
|
||||
.owner(owner)
|
||||
.manifest(JsonValue.from(manifest))
|
||||
.apply { parentCommit?.let { parentCommit(it) } }
|
||||
.build()
|
||||
|
||||
return runCatching {
|
||||
client.commits().update(promptName, params)
|
||||
println(" ✓ Added prompt content as commit\n")
|
||||
true
|
||||
}.getOrElse { e ->
|
||||
throw RuntimeException("Failed to create commit", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts prompt content from a manifest for display (shows all messages).
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun extractPromptContent(manifestJson: JsonValue): String {
|
||||
return runCatching {
|
||||
val manifest = MAPPER.convertValue(manifestJson, Map::class.java) as Map<String, Any>
|
||||
val kwargs = manifest["kwargs"] as Map<String, Any>
|
||||
val messagesObj = kwargs["messages"] ?: return "Unable to parse prompt content"
|
||||
|
||||
val messages = when (messagesObj) {
|
||||
is Array<*> -> messagesObj
|
||||
is List<*> -> messagesObj.toTypedArray()
|
||||
else -> return "Unable to parse prompt content"
|
||||
}
|
||||
|
||||
messages.mapIndexed { index, messageObj ->
|
||||
val message = messageObj as Map<String, Any>
|
||||
val msgKwargs = message["kwargs"] as Map<String, Any>
|
||||
val prompt = msgKwargs["prompt"] as Map<String, Any>
|
||||
val promptKwargs = prompt["kwargs"] as Map<String, Any>
|
||||
val template = promptKwargs["template"].toString()
|
||||
val messageType = getMessageType(message)
|
||||
val prefix = if (index > 0) " | " else ""
|
||||
"$prefix$messageType: \"$template\""
|
||||
}.joinToString("")
|
||||
}.getOrDefault("Unable to parse prompt content")
|
||||
}
|
||||
|
||||
private fun getOwnerFromEnv(): String =
|
||||
System.getenv("LANGSMITH_OWNER")?.takeIf { it.isNotEmpty() } ?: "-"
|
||||
|
||||
Reference in New Issue
Block a user