langchain - 💡(How to fix) Fix LangSmith Prompt Hub: UI Model config shows base_url (OpenRouter) but pullPromptCommit manifest omits base_url / wrong secret id for same commit [1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#37018Fetched 2026-04-27 05:28:54
View on GitHub
Comments
1
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×3commented ×1issue_type_added ×1

When configuring a prompt in LangSmith UI with OpenAI-compatible provider, OpenRouter base_url, and OPENROUTER_API_KEY, the Playground from the prompt works. However, Client.pullPromptCommit(...) for the same commit hash returns a manifest where the hydrated ChatOpenAI block does not include base_url and the secret is resolved as OPENAI_API_KEY instead of OPENROUTER_API_KEY, causing 401 / wrong endpoint behavior in application code that trusts the hub manifest.

This suggests a desync between UI-stored model configuration and the serialized manifest returned by the Hub API for the same commit.


Error Message

Error Message and Stack Trace (if applicable)

Root Cause

When configuring a prompt in LangSmith UI with OpenAI-compatible provider, OpenRouter base_url, and OPENROUTER_API_KEY, the Playground from the prompt works. However, Client.pullPromptCommit(...) for the same commit hash returns a manifest where the hydrated ChatOpenAI block does not include base_url and the secret is resolved as OPENAI_API_KEY instead of OPENROUTER_API_KEY, causing 401 / wrong endpoint behavior in application code that trusts the hub manifest.

This suggests a desync between UI-stored model configuration and the serialized manifest returned by the Hub API for the same commit.


Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Request

Please confirm whether this is:

  • A) Hub API not serializing base_url / custom endpoint into manifest for OpenAI-compatible configs, or
  • B) UI displaying config that is not yet written into the commit manifest, or
  • C) expected behavior with documented workaround.

Code Example

"""
Minimal repro: compare LangSmith UI model config vs Hub API manifest.

Prereqs:
  pip install "langsmith>=0.5"

Env:
  export LANGSMITH_API_KEY="lsv2_..."
  # Optional (non-default host):
  # export LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
"""

from __future__ import annotations

import json
import os
import sys
from typing import Any

from langsmith import Client


PROMPT_IDENTIFIER = os.environ.get("PROMPT_IDENTIFIER", "summary-session")
# Use full name if needed, e.g. "my-org/summary-session"


def _walk(obj: Any, path: str = "$") -> None:
    if isinstance(obj, dict):
        lc_id = obj.get("id")
        if lc_id == ["langchain", "chat_models", "openai", "ChatOpenAI"]:
            kwargs = obj.get("kwargs") or {}
            print(f"\n--- Found ChatOpenAI at {path} ---")
            print("model:", kwargs.get("model"))
            print("base_url:", kwargs.get("base_url"))
            print("openai_api_key:", kwargs.get("openai_api_key"))
            print("use_responses_api:", kwargs.get("use_responses_api"))
        for k, v in obj.items():
            _walk(v, f"{path}.{k}")
    elif isinstance(obj, list):
        for i, item in enumerate(obj):
            _walk(item, f"{path}[{i}]")


def main() -> int:
    if not os.environ.get("LANGSMITH_API_KEY"):
        print("Missing LANGSMITH_API_KEY", file=sys.stderr)
        return 2

    client = Client(
        api_key=os.environ["LANGSMITH_API_KEY"],
        api_url=os.environ.get("LANGSMITH_ENDPOINT"),
    )

    commit = client.pull_prompt_commit(
        PROMPT_IDENTIFIER,
        include_model=True,
        skip_cache=True,
    )

    print("prompt_identifier:", PROMPT_IDENTIFIER)
    print("commit_hash:", getattr(commit, "commit_hash", None))

    manifest = getattr(commit, "manifest", None)
    if manifest is None:
        print("No manifest on commit object", file=sys.stderr)
        return 3

    print("\n=== Raw manifest (JSON) ===")
    print(json.dumps(manifest, indent=2, default=str))

    print("\n=== ChatOpenAI kwargs scan ===")
    _walk(manifest)

    return 0


if __name__ == "__main__":
    raise SystemExit(main())

---



---

import { Client } from "langsmith";

const client = new Client({
  apiKey: process.env.LANGSMITH_API_KEY,
  apiUrl: process.env.LANGSMITH_ENDPOINT, // if applicable
});

const commit = await client.pullPromptCommit("summary-session", {
  includeModel: true,
  skipCache: true,
});

console.log("commit_hash:", commit.commit_hash);
console.log(JSON.stringify(commit.manifest, null, 2));

---

{
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "runnables",
    "RunnableSequence"
  ],
  "kwargs": {
    "first": {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "prompts",
        "structured",
        "StructuredPrompt"
      ],
      "kwargs": {
        "messages": [
          {
            "lc": 1,
            "type": "constructor",
            "id": [
              "langchain_core",
              "prompts",
              "chat",
              "SystemMessagePromptTemplate"
            ],
            "kwargs": {
              "prompt": {
                "lc": 1,
                "type": "constructor",
                "id": [
                  "langchain_core",
                  "prompts",
                  "prompt",
                  "PromptTemplate"
                ],
                "kwargs": {
                  "input_variables": [],
                  "template_format": "mustache",
                  "template": "You are an expert Customer Support Data Extractor. Your task is to analyze a raw chat transcript between a customer and an agent (or AI) and distill it into a highly concise, structured session summary. This summary acts as the short-term memory (Level 2) for an AI agent.\n\n### INSTRUCTIONS\n1. Analyze Intent: Identify the primary reason the customer initiated the conversation.\n2. Determine Outcome: Evaluate the final state of the conversation (e.g., Resolved, Escalated, Dropped, Pending, Unresolved).\n3. Extract Entities: Identify specific, actionable data points such as order IDs, phone numbers, email addresses, product names, or appointment dates. Exclude conversational filler.\n4. Summarize: Write a chronological, factual overview of the session. Focus purely on the core problem, actions taken, and the resolution. Do not include greetings or pleasantries.\n5. Language Constraint: You MUST translate and write the values for `summary`, `intent`, `outcome`, and `keyEntities` entirely in Vietnamese.\n\n### OUTPUT FORMAT\nYou must respond strictly with a valid JSON object matching the exact schema below. Do not include markdown code blocks (e.g.,
RAW_BUFFERClick to expand / collapse

Submission checklist

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

No response

Reproduction Steps / Example Code (Python)

"""
Minimal repro: compare LangSmith UI model config vs Hub API manifest.

Prereqs:
  pip install "langsmith>=0.5"

Env:
  export LANGSMITH_API_KEY="lsv2_..."
  # Optional (non-default host):
  # export LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
"""

from __future__ import annotations

import json
import os
import sys
from typing import Any

from langsmith import Client


PROMPT_IDENTIFIER = os.environ.get("PROMPT_IDENTIFIER", "summary-session")
# Use full name if needed, e.g. "my-org/summary-session"


def _walk(obj: Any, path: str = "$") -> None:
    if isinstance(obj, dict):
        lc_id = obj.get("id")
        if lc_id == ["langchain", "chat_models", "openai", "ChatOpenAI"]:
            kwargs = obj.get("kwargs") or {}
            print(f"\n--- Found ChatOpenAI at {path} ---")
            print("model:", kwargs.get("model"))
            print("base_url:", kwargs.get("base_url"))
            print("openai_api_key:", kwargs.get("openai_api_key"))
            print("use_responses_api:", kwargs.get("use_responses_api"))
        for k, v in obj.items():
            _walk(v, f"{path}.{k}")
    elif isinstance(obj, list):
        for i, item in enumerate(obj):
            _walk(item, f"{path}[{i}]")


def main() -> int:
    if not os.environ.get("LANGSMITH_API_KEY"):
        print("Missing LANGSMITH_API_KEY", file=sys.stderr)
        return 2

    client = Client(
        api_key=os.environ["LANGSMITH_API_KEY"],
        api_url=os.environ.get("LANGSMITH_ENDPOINT"),
    )

    commit = client.pull_prompt_commit(
        PROMPT_IDENTIFIER,
        include_model=True,
        skip_cache=True,
    )

    print("prompt_identifier:", PROMPT_IDENTIFIER)
    print("commit_hash:", getattr(commit, "commit_hash", None))

    manifest = getattr(commit, "manifest", None)
    if manifest is None:
        print("No manifest on commit object", file=sys.stderr)
        return 3

    print("\n=== Raw manifest (JSON) ===")
    print(json.dumps(manifest, indent=2, default=str))

    print("\n=== ChatOpenAI kwargs scan ===")
    _walk(manifest)

    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Error Message and Stack Trace (if applicable)

Description

Summary

When configuring a prompt in LangSmith UI with OpenAI-compatible provider, OpenRouter base_url, and OPENROUTER_API_KEY, the Playground from the prompt works. However, Client.pullPromptCommit(...) for the same commit hash returns a manifest where the hydrated ChatOpenAI block does not include base_url and the secret is resolved as OPENAI_API_KEY instead of OPENROUTER_API_KEY, causing 401 / wrong endpoint behavior in application code that trusts the hub manifest.

This suggests a desync between UI-stored model configuration and the serialized manifest returned by the Hub API for the same commit.


Environment

  • LangSmith region / deployment: (cloud / self-hosted — specify)
  • SDK: langsmith v0.5.23 (or your exact version)
  • LangChain hub pull: langchain/hub/node v1.3.4 (or your exact version)
  • OS / Node: (e.g. Node 22, macOS)

Steps to reproduce

  1. Create or open a private prompt repo, e.g. summary-session.
  2. In Model configuration, set:
    • Provider: OpenAI-compatible / OpenAI endpoint
    • Base URL: https://openrouter.ai/api/v1
    • API key env name: OPENROUTER_API_KEY
    • Model: e.g. google/gemini-3-flash-preview (or any OpenRouter model id)
  3. Save and create a new commit; note the commit hash shown in UI.
  4. In Playground opened from the prompt (not from an old trace), run — confirm it succeeds.
  5. In application code (or a minimal script), call:
import { Client } from "langsmith";

const client = new Client({
  apiKey: process.env.LANGSMITH_API_KEY,
  apiUrl: process.env.LANGSMITH_ENDPOINT, // if applicable
});

const commit = await client.pullPromptCommit("summary-session", {
  includeModel: true,
  skipCache: true,
});

console.log("commit_hash:", commit.commit_hash);
console.log(JSON.stringify(commit.manifest, null, 2));
  1. Inspect the ChatOpenAI / model kwargs inside commit.manifest.

Expected behavior

The manifest returned by pullPromptCommit for that commit should include the same runtime fields as configured in UI, at minimum:

  • base_url (or equivalent) = https://openrouter.ai/api/v1
  • Secret reference consistent with UI (e.g. OPENROUTER_API_KEY), or documented mapping rules if UI uses a different internal representation.

Actual behavior

For commit hash <PASTE_COMMIT_HASH>, the manifest shows e.g.:

  • ChatOpenAI kwargs include model as configured but
  • base_url is missing
  • openai_api_key secret id is OPENAI_API_KEY (not OPENROUTER_API_KEY)

(attached JSON below)


Evidence (required)

1) Commit hash (single source of truth)

  • Commit hash from UI: <PASTE_FULL_HASH>
  • Commit hash from API response (commit.commit_hash): <PASTE_SAME_HASH>
    (They should match; if they differ, note both.)

2) Raw manifest from API

Paste full redacted JSON from pullPromptCommit (redact any non-secret fields if needed; do not paste real API keys):

{
  "lc": 1,
  "type": "constructor",
  "id": [
    "langchain_core",
    "runnables",
    "RunnableSequence"
  ],
  "kwargs": {
    "first": {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "prompts",
        "structured",
        "StructuredPrompt"
      ],
      "kwargs": {
        "messages": [
          {
            "lc": 1,
            "type": "constructor",
            "id": [
              "langchain_core",
              "prompts",
              "chat",
              "SystemMessagePromptTemplate"
            ],
            "kwargs": {
              "prompt": {
                "lc": 1,
                "type": "constructor",
                "id": [
                  "langchain_core",
                  "prompts",
                  "prompt",
                  "PromptTemplate"
                ],
                "kwargs": {
                  "input_variables": [],
                  "template_format": "mustache",
                  "template": "You are an expert Customer Support Data Extractor. Your task is to analyze a raw chat transcript between a customer and an agent (or AI) and distill it into a highly concise, structured session summary. This summary acts as the short-term memory (Level 2) for an AI agent.\n\n### INSTRUCTIONS\n1. Analyze Intent: Identify the primary reason the customer initiated the conversation.\n2. Determine Outcome: Evaluate the final state of the conversation (e.g., Resolved, Escalated, Dropped, Pending, Unresolved).\n3. Extract Entities: Identify specific, actionable data points such as order IDs, phone numbers, email addresses, product names, or appointment dates. Exclude conversational filler.\n4. Summarize: Write a chronological, factual overview of the session. Focus purely on the core problem, actions taken, and the resolution. Do not include greetings or pleasantries.\n5. Language Constraint: You MUST translate and write the values for `summary`, `intent`, `outcome`, and `keyEntities` entirely in Vietnamese.\n\n### OUTPUT FORMAT\nYou must respond strictly with a valid JSON object matching the exact schema below. Do not include markdown code blocks (e.g., ```json) or any conversational text.\n\n{\n  \"summary\": \"String (A factual summary of the conversation in Vietnamese)\",\n  \"intent\": \"String (The primary goal of the user in Vietnamese)\",\n  \"outcome\": \"String (The final resolution or state in Vietnamese)\",\n  \"keyEntities\": [\"String\", \"String\"] // Array of strings. Use an empty array [] if no entities are found.\n}"
                }
              }
            }
          },
          {
            "lc": 1,
            "type": "constructor",
            "id": [
              "langchain_core",
              "prompts",
              "chat",
              "HumanMessagePromptTemplate"
            ],
            "kwargs": {
              "prompt": {
                "lc": 1,
                "type": "constructor",
                "id": [
                  "langchain_core",
                  "prompts",
                  "prompt",
                  "PromptTemplate"
                ],
                "kwargs": {
                  "input_variables": [
                    "messages"
                  ],
                  "template_format": "mustache",
                  "template": "Here is the raw chat transcript:\n<transcript>\n{{messages}}\n</transcript>"
                }
              }
            }
          }
        ],
        "input_variables": [
          "messages"
        ],
        "template_format": "mustache",
        "schema_": {
          "title": "SessionSummaryResult",
          "type": "object",
          "properties": {
            "summary": {
              "type": "string",
              "description": "A concise paragraph summarizing the interaction."
            },
            "intent": {
              "type": "string",
              "description": "The primary goal or reason the customer reached out."
            },
            "outcome": {
              "type": "string",
              "description": "The final status or result of the session."
            },
            "keyEntities": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Important entities like product names, prices, dates, etc."
            }
          },
          "required": [
            "summary",
            "intent",
            "outcome",
            "keyEntities"
          ]
        }
      }
    },
    "last": {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "runnables",
        "RunnableBinding"
      ],
      "kwargs": {
        "bound": {
          "lc": 1,
          "type": "constructor",
          "id": [
            "langchain_core",
            "runnables",
            "RunnableSequence"
          ],
          "kwargs": {
            "first": {
              "lc": 1,
              "type": "constructor",
              "id": [
                "langchain",
                "chat_models",
                "openai",
                "ChatOpenAI"
              ],
              "kwargs": {
                "model": "google/gemini-3-flash-preview",
                "use_responses_api": true,
                "openai_api_key": {
                  "lc": 1,
                  "type": "secret",
                  "id": [
                    "OPENAI_API_KEY"
                  ]
                }
              }
            },
            "last": {
              "lc": 1,
              "type": "constructor",
              "id": [
                "langchain_core",
                "output_parsers",
                "JsonOutputParser"
              ],
              "kwargs": {}
            }
          }
        },
        "kwargs": {}
      }
    },
    "metadata": {
      "lc_hub_owner": "-",
      "lc_hub_repo": "summary-session",
      "lc_hub_commit_hash": "d1cff76d6fbadfd146185721658f2bf611a68c64f98c6b6efc8fb70b697ff98e"
    }
  }
}

3) Screenshot of UI for the same commit

Attach screenshot showing:

  • Prompt name / repo
  • Selected commit d1cff7... (or full hash)
  • Model panel with Base URL = https://openrouter.ai/api/v1
  • API key name = OPENROUTER_API_KEY

4) Optional: metadata block from manifest

If present, include kwargs.metadata with lc_hub_commit_hash matching UI.


Impact

  • includeModel: true pulls in app deserialize to OpenAI-default routing unless clients apply manual env overrides (OPENAI_BASE_URL, secret aliasing).
  • Breaks “single source of truth” for model config in LangSmith Hub vs application runtime.

Request

Please confirm whether this is:

  • A) Hub API not serializing base_url / custom endpoint into manifest for OpenAI-compatible configs, or
  • B) UI displaying config that is not yet written into the commit manifest, or
  • C) expected behavior with documented workaround.

If (A) or (B), we’d like a fix or explicit contract for how OpenRouter / custom base URL must be stored so pullPromptCommit round-trips correctly.


Checklist before submit

  • Same prompt identifier in UI and in code (summary-session vs owner/summary-session documented)
  • skipCache: true on pullPromptCommit to rule out client cache
  • LangSmith API key is for the same workspace as the UI
  • No PII / secrets in screenshots or JSON

System Info

Runtime

  • OS: macOS Darwin 24.6.0
  • Node.js: v22.14.0
  • Package manager: pnpm 10.12.1

Dependencies (workspace root, pnpm list --depth 0)

  • langsmith: 0.5.23
  • langchain: 1.3.4
  • @langchain/core: 1.1.41

Package.json ranges (reference)

  • langsmith: ^0.5.25
  • langchain: ^1.3.4
  • @langchain/core: ^1.1.41

Service

  • App: service-agent (NestJS), pulls prompts via langchain/hub/node + langsmith Client.pullPromptCommit

LangSmith

  • Deployment: LangSmith Cloud (EU)

extent analysis

TL;DR

The issue can be fixed by ensuring that the base_url and openai_api_key are correctly serialized into the manifest for OpenAI-compatible configurations, possibly by updating the LangSmith Hub API or the langsmith client library.

Guidance

  • Verify that the base_url and openai_api_key are correctly configured in the LangSmith UI and that the changes are saved and committed.
  • Check the LangSmith Hub API documentation to see if there are any specific requirements or workarounds for serializing custom endpoints and API keys into the manifest.
  • Consider updating the langsmith client library to the latest version to ensure that any fixes or improvements related to manifest serialization are included.
  • If the issue persists, try to reproduce it with a minimal example and provide more detailed debugging information, such as API request and response logs.

Example

No code example is provided as the issue is related to the serialization of the manifest and not a specific code snippet.

Notes

The issue seems to be related to the deserialization of the manifest and the serialization of custom endpoints and API keys. It is unclear if this is a bug in the LangSmith Hub API, the langsmith client library, or a configuration issue.

Recommendation

Apply a workaround by manually configuring the base_url and openai_api_key in the application code, if possible, until the root cause of the issue is identified and fixed.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The manifest returned by pullPromptCommit for that commit should include the same runtime fields as configured in UI, at minimum:

  • base_url (or equivalent) = https://openrouter.ai/api/v1
  • Secret reference consistent with UI (e.g. OPENROUTER_API_KEY), or documented mapping rules if UI uses a different internal representation.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - 💡(How to fix) Fix LangSmith Prompt Hub: UI Model config shows base_url (OpenRouter) but pullPromptCommit manifest omits base_url / wrong secret id for same commit [1 comments, 1 participants]