Skip to content
This repository was archived by the owner on May 5, 2026. It is now read-only.

Commit e83dc5a

Browse files
eyurtsevjacoblee93
andauthored
Add output schemas to the playgrounds (#522)
Add output schema information to the playgrounds ![image](https://github.com/langchain-ai/langserve/assets/3205522/ce0e2ef4-3fa8-4ecd-8c21-08e1319879d5) --------- Co-authored-by: jacoblee93 <jacoblee93@gmail.com>
1 parent 3f1fc38 commit e83dc5a

11 files changed

Lines changed: 139 additions & 52 deletions

File tree

langserve/api_handler.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ async def playground(
13611361
return await serve_playground(
13621362
self._runnable.with_config(config),
13631363
self._runnable.with_config(config).input_schema,
1364+
self._runnable.with_config(config).output_schema,
13641365
self._config_keys,
13651366
playground_url,
13661367
file_path,

langserve/chat_playground/dist/assets/index-9018861a.js renamed to langserve/chat_playground/dist/assets/index-c5f8c3dc.js

Lines changed: 37 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

langserve/chat_playground/dist/index.html

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,35 @@
55
<link rel="icon" href="/____LANGSERVE_BASE_URL/favicon.ico" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
<title>Chat Playground</title>
8-
<script type="module" crossorigin src="/____LANGSERVE_BASE_URL/assets/index-9018861a.js"></script>
8+
<script type="module" crossorigin src="/____LANGSERVE_BASE_URL/assets/index-c5f8c3dc.js"></script>
99
<link rel="stylesheet" href="/____LANGSERVE_BASE_URL/assets/index-b47ed17e.css">
1010
</head>
1111
<body>
1212
<div id="root"></div>
1313
<script>
1414
try {
1515
window.CONFIG_SCHEMA = ____LANGSERVE_CONFIG_SCHEMA;
16+
} catch (e) {
17+
// pass
18+
}
19+
try {
1620
window.INPUT_SCHEMA = ____LANGSERVE_INPUT_SCHEMA;
21+
} catch (e) {
22+
// pass
23+
}
24+
try {
25+
window.OUTPUT_SCHEMA = ____LANGSERVE_OUTPUT_SCHEMA;
26+
} catch (e) {
27+
// pass
28+
}
29+
try {
1730
window.FEEDBACK_ENABLED = ____LANGSERVE_FEEDBACK_ENABLED;
31+
} catch (e) {
32+
// pass
33+
}
34+
try {
1835
window.PUBLIC_TRACE_LINK_ENABLED = ____LANGSERVE_PUBLIC_TRACE_LINK_ENABLED;
19-
} catch (error) {
36+
} catch (e) {
2037
// pass
2138
}
2239
</script>

langserve/chat_playground/index.html

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,27 @@
1111
<script>
1212
try {
1313
window.CONFIG_SCHEMA = ____LANGSERVE_CONFIG_SCHEMA;
14+
} catch (e) {
15+
// pass
16+
}
17+
try {
1418
window.INPUT_SCHEMA = ____LANGSERVE_INPUT_SCHEMA;
19+
} catch (e) {
20+
// pass
21+
}
22+
try {
23+
window.OUTPUT_SCHEMA = ____LANGSERVE_OUTPUT_SCHEMA;
24+
} catch (e) {
25+
// pass
26+
}
27+
try {
1528
window.FEEDBACK_ENABLED = ____LANGSERVE_FEEDBACK_ENABLED;
29+
} catch (e) {
30+
// pass
31+
}
32+
try {
1633
window.PUBLIC_TRACE_LINK_ENABLED = ____LANGSERVE_PUBLIC_TRACE_LINK_ENABLED;
17-
} catch (error) {
34+
} catch (e) {
1835
// pass
1936
}
2037
</script>

langserve/chat_playground/src/App.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,43 @@ import "./App.css";
22

33
import { ChatWindow } from "./components/ChatWindow";
44
import { AppCallbackContext, useAppStreamCallbacks } from "./useStreamCallback";
5-
import { useInputSchema } from "./useSchemas";
5+
import { useInputSchema, useOutputSchema } from "./useSchemas";
66
import { useStreamLog } from "./useStreamLog";
7-
import { resolveApiUrl } from "./utils/url";
87

98
export function App() {
109
const { context, callbacks } = useAppStreamCallbacks();
1110
const { startStream, stopStream } = useStreamLog(callbacks);
1211
const inputSchema = useInputSchema({});
12+
const outputSchema = useOutputSchema({});
1313
const inputProps = inputSchema?.data?.schema?.properties;
14-
const isLoading = inputProps === undefined;
14+
const outputDataSchema = outputSchema?.data?.schema;
15+
const isLoading = inputProps === undefined || outputDataSchema === undefined;
1516
const inputKeys = Object.keys(inputProps ?? {});
16-
const isSupported = isLoading || (inputKeys.length === 1 && inputProps[inputKeys[0]].type === "array");
17+
const isSupported = isLoading || (
18+
inputKeys.length === 1 &&
19+
inputProps[inputKeys[0]].type === "array" &&
20+
(
21+
outputDataSchema.anyOf?.find((option) => option.properties?.type?.enum?.includes("ai")) ||
22+
outputDataSchema.type === "string"
23+
)
24+
);
1725
return (
1826
<div className="flex items-center flex-col text-ls-black bg-background">
1927
<AppCallbackContext.Provider value={context}>
20-
{isSupported
21-
? <ChatWindow
28+
{isSupported
29+
? <ChatWindow
2230
startStream={startStream}
2331
stopStream={stopStream}
2432
inputKey={inputKeys[0]}
25-
></ChatWindow>
33+
></ChatWindow>
2634
: <div className="h-[100vh] w-[100vw] flex justify-center items-center text-xl">
2735
<span className="text-center">
28-
The chat playground is only supported for chains that take a single array of messages as input.
36+
The chat playground is only supported for chains that take a single array of messages as input
2937
<br/>
30-
You can test this chain in the standard <a href={resolveApiUrl("/playground").toString()}>LangServe playground</a>.
38+
and return either an AIMessage or a string.
39+
<br />
40+
<br />
41+
You can test this chain in the default LangServe playground instead. Please set <code>playground_type="default"</code>.
3142
</span>
3243
</div>}
3344
</AppCallbackContext.Provider>

langserve/chat_playground/src/useSchemas.tsx

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { resolveApiUrl } from "./utils/url";
2-
import { simplifySchema } from "./utils/simplifySchema";
31
import { JsonSchema } from "@jsonforms/core";
42
import { compressToEncodedURIComponent } from "lz-string";
3+
import { resolveApiUrl } from "./utils/url";
4+
import { simplifySchema } from "./utils/simplifySchema";
55

66
import useSWR from "swr";
77
import defaults from "./utils/defaults";
@@ -13,6 +13,8 @@ declare global {
1313
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1414
INPUT_SCHEMA?: any;
1515
// eslint-disable-next-line @typescript-eslint/no-explicit-any
16+
OUTPUT_SCHEMA?: any;
17+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1618
FEEDBACK_ENABLED?: any;
1719
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1820
PUBLIC_TRACE_LINK_ENABLED?: any;
@@ -96,3 +98,34 @@ export function useInputSchema(configData?: unknown) {
9698
{ keepPreviousData: true }
9799
);
98100
}
101+
102+
export function useOutputSchema(configData?: unknown) {
103+
return useSWR(
104+
["/output_schema", configData],
105+
async ([, configData]) => {
106+
// TODO: this won't work if we're already seeing a prefixed URL
107+
const prefix = configData
108+
? `/c/${compressToEncodedURIComponent(JSON.stringify(configData))}`
109+
: "";
110+
111+
let schema: JsonSchema | null = null;
112+
113+
if (!prefix && !import.meta.env.DEV && window.OUTPUT_SCHEMA) {
114+
schema = await simplifySchema(window.OUTPUT_SCHEMA);
115+
} else {
116+
const response = await fetch(resolveApiUrl(`${prefix}/output_schema`));
117+
if (!response.ok) throw new Error(await response.text());
118+
119+
const json = await response.json();
120+
schema = await simplifySchema(json);
121+
}
122+
123+
if (schema == null) return null;
124+
return {
125+
schema,
126+
defaults: defaults(schema),
127+
};
128+
},
129+
{ keepPreviousData: true }
130+
);
131+
}

langserve/chat_playground/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default defineConfig({
88
plugins: [svgr(), react()],
99
server: {
1010
proxy: {
11-
"^/____LANGSERVE_BASE_URL.*/(config_schema|input_schema|stream_log|feedback|public_trace_link)(/[a-zA-Z0-9-]*)?$": {
11+
"^/____LANGSERVE_BASE_URL.*/(config_schema|input_schema|output_schema|stream_log|feedback|public_trace_link)(/[a-zA-Z0-9-]*)?$": {
1212
target: "http://127.0.0.1:8000",
1313
changeOrigin: true,
1414
rewrite: (path) => path.replace("/____LANGSERVE_BASE_URL", ""),

langserve/playground.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def _get_mimetype(path: str) -> str:
5050
async def serve_playground(
5151
runnable: Runnable,
5252
input_schema: Type[BaseModel],
53+
output_schema: Type[BaseModel],
5354
config_keys: Sequence[str],
5455
base_url: str,
5556
file_path: str,
@@ -92,6 +93,7 @@ async def serve_playground(
9293
runnable.config_schema(include=config_keys).schema()
9394
),
9495
LANGSERVE_INPUT_SCHEMA=json.dumps(input_schema.schema()),
96+
LANGSERVE_OUTPUT_SCHEMA=json.dumps(output_schema.schema()),
9597
LANGSERVE_FEEDBACK_ENABLED=json.dumps(
9698
"true" if feedback_enabled else "false"
9799
),

langserve/playground/dist/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
try {
1515
window.CONFIG_SCHEMA = ____LANGSERVE_CONFIG_SCHEMA;
1616
window.INPUT_SCHEMA = ____LANGSERVE_INPUT_SCHEMA;
17+
window.OUTPUT_SCHEMA = ____LANGSERVE_OUTPUT_SCHEMA;
1718
window.FEEDBACK_ENABLED = ____LANGSERVE_FEEDBACK_ENABLED;
1819
window.PUBLIC_TRACE_LINK_ENABLED = ____LANGSERVE_PUBLIC_TRACE_LINK_ENABLED;
1920
} catch (error) {

langserve/playground/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
try {
1313
window.CONFIG_SCHEMA = ____LANGSERVE_CONFIG_SCHEMA;
1414
window.INPUT_SCHEMA = ____LANGSERVE_INPUT_SCHEMA;
15+
window.OUTPUT_SCHEMA = ____LANGSERVE_OUTPUT_SCHEMA;
1516
window.FEEDBACK_ENABLED = ____LANGSERVE_FEEDBACK_ENABLED;
1617
window.PUBLIC_TRACE_LINK_ENABLED = ____LANGSERVE_PUBLIC_TRACE_LINK_ENABLED;
1718
} catch (error) {

0 commit comments

Comments
 (0)