show auth key once the agent is created

This commit is contained in:
2026-02-12 16:39:23 +08:00
parent c87c883313
commit 56124069e1
3 changed files with 111 additions and 1 deletions

View File

@@ -29,6 +29,14 @@ type EditableAgent = {
llmName: string; llmName: string;
}; };
type LaunchCredentials = {
url: string;
authType: string;
authHeaderName: string;
authKey: string;
authKeyMasked: string;
};
const DEFAULT_ENTRY_POINT = "fastapi_server/server_dashscope.py"; const DEFAULT_ENTRY_POINT = "fastapi_server/server_dashscope.py";
const DEFAULT_LLM_NAME = "qwen-plus"; const DEFAULT_LLM_NAME = "qwen-plus";
const DEFAULT_PORT = 8100; const DEFAULT_PORT = 8100;
@@ -106,6 +114,7 @@ export default function App() {
const [selectedId, setSelectedId] = useState<string | null>(null); const [selectedId, setSelectedId] = useState<string | null>(null);
const [editor, setEditor] = useState<EditableAgent | null>(null); const [editor, setEditor] = useState<EditableAgent | null>(null);
const [statusMessage, setStatusMessage] = useState<string>(""); const [statusMessage, setStatusMessage] = useState<string>("");
const [launchCredentials, setLaunchCredentials] = useState<LaunchCredentials | null>(null);
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const configKeySet = useMemo( const configKeySet = useMemo(
@@ -401,6 +410,7 @@ export default function App() {
setBusy(true); setBusy(true);
setStatusMessage("Starting agent..."); setStatusMessage("Starting agent...");
setLaunchCredentials(null);
try { try {
const resp = await createPipeline({ const resp = await createPipeline({
graph_id: editor.graphId, graph_id: editor.graphId,
@@ -414,6 +424,13 @@ export default function App() {
}); });
await refreshRunning(); await refreshRunning();
setStatusMessage(`Agent started. URL: ${resp.url}`); setStatusMessage(`Agent started. URL: ${resp.url}`);
setLaunchCredentials({
url: resp.url,
authType: resp.auth_type,
authHeaderName: resp.auth_header_name,
authKey: resp.auth_key_once,
authKeyMasked: resp.auth_key_masked,
});
} catch (error) { } catch (error) {
setStatusMessage((error as Error).message); setStatusMessage((error as Error).message);
} finally { } finally {
@@ -459,6 +476,23 @@ export default function App() {
})), })),
]; ];
const graphArchImage = editor ? getGraphArchImage(editor.graphId) : null; const graphArchImage = editor ? getGraphArchImage(editor.graphId) : null;
const authHeaderValue = launchCredentials
? `${launchCredentials.authHeaderName}: Bearer ${launchCredentials.authKey}`
: "";
const canUseClipboard = typeof navigator !== "undefined" && Boolean(navigator.clipboard);
async function copyText(text: string, label: string): Promise<void> {
if (!canUseClipboard) {
setStatusMessage(`Clipboard is not available. Please copy ${label} manually.`);
return;
}
try {
await navigator.clipboard.writeText(text);
setStatusMessage(`${label} copied.`);
} catch {
setStatusMessage(`Failed to copy ${label}.`);
}
}
return ( return (
<div className="app"> <div className="app">
@@ -517,6 +551,47 @@ export default function App() {
</header> </header>
{statusMessage ? <p className="status">{statusMessage}</p> : null} {statusMessage ? <p className="status">{statusMessage}</p> : null}
{launchCredentials ? (
<div className="launch-credentials">
<h3>Access Credentials (shown once)</h3>
<div>
<strong>URL:</strong>{" "}
<a href={launchCredentials.url} target="_blank" rel="noreferrer">
{launchCredentials.url}
</a>
<button
type="button"
onClick={() => copyText(launchCredentials.url, "URL")}
disabled={busy}
>
Copy URL
</button>
</div>
<div>
<strong>{launchCredentials.authType} key:</strong> {launchCredentials.authKey}
<button
type="button"
onClick={() => copyText(launchCredentials.authKey, "auth key")}
disabled={busy}
>
Copy Key
</button>
</div>
<div>
<strong>Header:</strong> <code>{authHeaderValue}</code>
<button
type="button"
onClick={() => copyText(authHeaderValue, "auth header")}
disabled={busy}
>
Copy Header
</button>
</div>
<p className="empty">
Stored after launch as masked value: {launchCredentials.authKeyMasked}
</p>
</div>
) : null}
{!editor ? ( {!editor ? (
<div className="empty-panel"> <div className="empty-panel">
@@ -646,6 +721,9 @@ export default function App() {
{run.url} {run.url}
</a> </a>
</div> </div>
<div>
<strong>auth:</strong> {run.auth_header_name} Bearer {run.auth_key_masked}
</div>
</div> </div>
)) ))
)} )}

View File

@@ -108,6 +108,33 @@ button:disabled {
padding: 10px; padding: 10px;
} }
.launch-credentials {
background: #fff4df;
border: 1px solid #f0d5a8;
border-radius: 8px;
margin-top: 12px;
padding: 12px;
}
.launch-credentials h3 {
margin: 0 0 8px;
}
.launch-credentials > div {
align-items: center;
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 6px 0;
}
.launch-credentials code {
background: #fff;
border: 1px solid #f0d5a8;
border-radius: 4px;
padding: 2px 6px;
}
.empty-panel { .empty-panel {
margin-top: 30px; margin-top: 30px;
} }

View File

@@ -62,9 +62,14 @@ export type PipelineRunInfo = {
prompt_set_id: string; prompt_set_id: string;
url: string; url: string;
port: number; port: number;
auth_type: string;
auth_header_name: string;
auth_key_masked: string;
}; };
export type PipelineCreateResponse = PipelineRunInfo; export type PipelineCreateResponse = PipelineRunInfo & {
auth_key_once: string;
};
export type PipelineListResponse = { export type PipelineListResponse = {
items: PipelineRunInfo[]; items: PipelineRunInfo[];