save api key

This commit is contained in:
2026-02-12 17:35:36 +08:00
parent 9d7d81c0ac
commit c7db276df5
4 changed files with 37 additions and 11 deletions

View File

@@ -22,6 +22,7 @@ class GraphConfigUpsertRequest(BaseModel):
prompt_set_id: Optional[str] = Field(default=None)
tool_keys: List[str] = Field(default_factory=list)
prompt_dict: Dict[str, str] = Field(default_factory=dict)
api_key: Optional[str] = Field(default=None)
class GraphConfigUpsertResponse(BaseModel):
graph_id: str
@@ -29,6 +30,7 @@ class GraphConfigUpsertResponse(BaseModel):
prompt_set_id: str
tool_keys: List[str]
prompt_keys: List[str]
api_key: str
class GraphConfigReadResponse(BaseModel):
graph_id: Optional[str] = Field(default=None)
@@ -36,6 +38,7 @@ class GraphConfigReadResponse(BaseModel):
prompt_set_id: str
tool_keys: List[str]
prompt_dict: Dict[str, str]
api_key: str = Field(default="")
class GraphConfigListItem(BaseModel):
graph_id: Optional[str] = Field(default=None)
@@ -45,6 +48,7 @@ class GraphConfigListItem(BaseModel):
description: str
is_active: bool
tool_keys: List[str]
api_key: str = Field(default="")
created_at: Optional[str] = Field(default=None)
updated_at: Optional[str] = Field(default=None)
@@ -169,6 +173,7 @@ async def upsert_graph_config(body: GraphConfigUpsertRequest):
prompt_set_id=body.prompt_set_id,
tool_list=body.tool_keys,
prompt_dict=body.prompt_dict,
api_key=body.api_key,
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@@ -181,6 +186,7 @@ async def upsert_graph_config(body: GraphConfigUpsertRequest):
prompt_set_id=resolved_prompt_set_id,
tool_keys=body.tool_keys,
prompt_keys=list(body.prompt_dict.keys()),
api_key=(body.api_key or "").strip(),
)
@app.get("/v1/graph-configs", response_model=GraphConfigListResponse)
@@ -222,6 +228,7 @@ async def get_default_graph_config(pipeline_id: str):
prompt_set_id=active["prompt_set_id"],
tool_keys=tool_keys,
prompt_dict=prompt_dict,
api_key=(active.get("api_key") or ""),
)
@app.get("/v1/graphs/{graph_id}/default-config", response_model=GraphConfigReadResponse)
@@ -254,6 +261,7 @@ async def get_graph_config(pipeline_id: str, prompt_set_id: str):
prompt_set_id=prompt_set_id,
tool_keys=tool_keys,
prompt_dict=prompt_dict,
api_key=(meta.get("api_key") or ""),
)

View File

@@ -101,7 +101,7 @@ function toEditable(
toolKeys: config.tool_keys || [],
prompts: config.prompt_dict || {},
port: DEFAULT_PORT,
apiKey: DEFAULT_API_KEY,
apiKey: config.api_key || DEFAULT_API_KEY,
llmName: DEFAULT_LLM_NAME,
};
}
@@ -207,8 +207,8 @@ export default function App() {
const editable = toEditable(detail, false);
editable.id = id;
editable.port = editor?.pipelineId === editable.pipelineId ? editor.port : DEFAULT_PORT;
editable.apiKey = editor?.pipelineId === editable.pipelineId ? editor.apiKey : DEFAULT_API_KEY;
editable.llmName = editor?.pipelineId === editable.pipelineId ? editor.llmName : DEFAULT_LLM_NAME;
// apiKey is loaded from backend (persisted in DB) — don't override with default
setEditor(editable);
setStatusMessage("");
} catch (error) {
@@ -305,6 +305,7 @@ export default function App() {
prompt_set_id: "default",
tool_keys: [],
prompt_dict: fallbackPrompts,
api_key: "",
};
}
}
@@ -340,6 +341,7 @@ export default function App() {
prompt_set_id: editor.promptSetId,
tool_keys: editor.toolKeys,
prompt_dict: editor.prompts,
api_key: editor.apiKey.trim(),
});
await refreshConfigs();
@@ -347,7 +349,7 @@ export default function App() {
const saved = toEditable(detail, false);
saved.id = makeAgentKey(upsertResp.pipeline_id, upsertResp.prompt_set_id);
saved.port = editor.port;
saved.apiKey = editor.apiKey;
// apiKey is loaded from backend (persisted in DB) — don't override
saved.llmName = editor.llmName;
setEditor(saved);
setSelectedId(saved.id);

View File

@@ -6,6 +6,7 @@ export type GraphConfigListItem = {
description: string;
is_active: boolean;
tool_keys: string[];
api_key: string;
created_at?: string | null;
updated_at?: string | null;
};
@@ -21,6 +22,7 @@ export type GraphConfigReadResponse = {
prompt_set_id: string;
tool_keys: string[];
prompt_dict: Record<string, string>;
api_key: string;
};
export type GraphConfigUpsertRequest = {
@@ -29,6 +31,7 @@ export type GraphConfigUpsertRequest = {
prompt_set_id?: string;
tool_keys: string[];
prompt_dict: Record<string, string>;
api_key?: string;
};
export type GraphConfigUpsertResponse = {
@@ -37,6 +40,7 @@ export type GraphConfigUpsertResponse = {
prompt_set_id: string;
tool_keys: string[];
prompt_keys: string[];
api_key: string;
};
export type AvailableGraphsResponse = {

View File

@@ -28,7 +28,7 @@ class DBConfigManager:
if pipeline_id and graph_id:
cur.execute(
"""
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list, api_key
FROM prompt_sets
WHERE pipeline_id = %s AND graph_id = %s
ORDER BY updated_at DESC, created_at DESC
@@ -38,7 +38,7 @@ class DBConfigManager:
elif pipeline_id:
cur.execute(
"""
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list, api_key
FROM prompt_sets
WHERE pipeline_id = %s
ORDER BY updated_at DESC, created_at DESC
@@ -48,7 +48,7 @@ class DBConfigManager:
elif graph_id:
cur.execute(
"""
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list, api_key
FROM prompt_sets
WHERE graph_id = %s
ORDER BY updated_at DESC, created_at DESC
@@ -58,7 +58,7 @@ class DBConfigManager:
else:
cur.execute(
"""
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list, api_key
FROM prompt_sets
ORDER BY updated_at DESC, created_at DESC
"""
@@ -76,6 +76,7 @@ class DBConfigManager:
"created_at": row["created_at"].isoformat() if row["created_at"] else None,
"updated_at": row["updated_at"].isoformat() if row["updated_at"] else None,
"tool_keys": self._parse_tool_list(row.get("list")),
"api_key": row.get("api_key") or "",
}
for row in rows
]
@@ -88,7 +89,7 @@ class DBConfigManager:
with conn.cursor(row_factory=dict_row) as cur:
cur.execute(
"""
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list
SELECT id, pipeline_id, graph_id, name, description, is_active, created_at, updated_at, list, api_key
FROM prompt_sets
WHERE id = %s AND pipeline_id = %s
""",
@@ -109,6 +110,7 @@ class DBConfigManager:
"created_at": row["created_at"].isoformat() if row["created_at"] else None,
"updated_at": row["updated_at"].isoformat() if row["updated_at"] else None,
"tool_keys": self._parse_tool_list(row.get("list")),
"api_key": row.get("api_key") or "",
}
def get_config(
@@ -160,6 +162,7 @@ class DBConfigManager:
prompt_set_id: Optional[str],
tool_list: Optional[Sequence[str]],
prompt_dict: Optional[Mapping[str, str]],
api_key: Optional[str] = None,
) -> str:
"""
Persist prompt + tool configuration.
@@ -182,6 +185,7 @@ class DBConfigManager:
normalized_prompt_dict = self._normalize_prompt_dict(prompt_dict)
tool_csv = self._join_tool_list(tool_list)
normalized_api_key = self._normalize_api_key(api_key)
with psycopg.connect(self.conn_str) as conn:
resolved_set_id, _ = self._resolve_prompt_set(
@@ -200,10 +204,13 @@ class DBConfigManager:
cur.execute(
"""
UPDATE prompt_sets
SET list = %s, graph_id = COALESCE(%s, graph_id), updated_at = now()
SET list = %s,
graph_id = COALESCE(%s, graph_id),
api_key = COALESCE(%s, api_key),
updated_at = now()
WHERE id = %s
""",
(tool_csv, normalized_graph_id, resolved_set_id),
(tool_csv, normalized_graph_id, normalized_api_key, resolved_set_id),
)
keys = list(normalized_prompt_dict.keys())
@@ -340,4 +347,9 @@ class DBConfigManager:
if graph_id is None:
return None
value = str(graph_id).strip()
return value or None
return value or None
def _normalize_api_key(self, api_key: Optional[str]) -> Optional[str]:
if api_key is None:
return None
return str(api_key).strip()