Compare commits
4 Commits
8f99d47af9
...
60f3029e54
| Author | SHA1 | Date | |
|---|---|---|---|
| 60f3029e54 | |||
| fe7ff9a516 | |||
| 33faedc1b1 | |||
| c9b1c5cb32 |
@@ -36,6 +36,7 @@ type EditableAgent = {
|
|||||||
pipelineId: string;
|
pipelineId: string;
|
||||||
promptSetId?: string;
|
promptSetId?: string;
|
||||||
toolKeys: string[];
|
toolKeys: string[];
|
||||||
|
toolKeysInput: string;
|
||||||
prompts: Record<string, string>;
|
prompts: Record<string, string>;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
llmName: string;
|
llmName: string;
|
||||||
@@ -459,6 +460,7 @@ function toEditable(
|
|||||||
pipelineId: config.pipeline_id,
|
pipelineId: config.pipeline_id,
|
||||||
promptSetId: config.prompt_set_id,
|
promptSetId: config.prompt_set_id,
|
||||||
toolKeys: config.tool_keys || [],
|
toolKeys: config.tool_keys || [],
|
||||||
|
toolKeysInput: (config.tool_keys || []).join(", "),
|
||||||
prompts: config.prompt_dict || {},
|
prompts: config.prompt_dict || {},
|
||||||
apiKey: config.api_key || DEFAULT_API_KEY,
|
apiKey: config.api_key || DEFAULT_API_KEY,
|
||||||
llmName: DEFAULT_LLM_NAME,
|
llmName: DEFAULT_LLM_NAME,
|
||||||
@@ -750,6 +752,7 @@ export default function App() {
|
|||||||
graphId,
|
graphId,
|
||||||
prompts: { ...defaults.prompt_dict },
|
prompts: { ...defaults.prompt_dict },
|
||||||
toolKeys: defaults.tool_keys || [],
|
toolKeys: defaults.tool_keys || [],
|
||||||
|
toolKeysInput: (defaults.tool_keys || []).join(", "),
|
||||||
actBackend:
|
actBackend:
|
||||||
graphId === "deepagent"
|
graphId === "deepagent"
|
||||||
? prev.actBackend || DEFAULT_DEEPAGENT_ACT_BACKEND
|
? prev.actBackend || DEFAULT_DEEPAGENT_ACT_BACKEND
|
||||||
@@ -1366,8 +1369,12 @@ export default function App() {
|
|||||||
<label>
|
<label>
|
||||||
tool_keys (comma separated)
|
tool_keys (comma separated)
|
||||||
<input
|
<input
|
||||||
value={editor.toolKeys.join(", ")}
|
value={editor.toolKeysInput}
|
||||||
onChange={(e) => updateEditor("toolKeys", parseToolCsv(e.target.value))}
|
onChange={(e) => {
|
||||||
|
const raw = e.target.value;
|
||||||
|
updateEditor("toolKeysInput", raw);
|
||||||
|
updateEditor("toolKeys", parseToolCsv(raw));
|
||||||
|
}}
|
||||||
placeholder="tool_a, tool_b"
|
placeholder="tool_a, tool_b"
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
/>
|
/>
|
||||||
|
|||||||
22
frontend/src/api/frontApis.test.ts
Normal file
22
frontend/src/api/frontApis.test.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { joinApiUrl } from "./frontApis";
|
||||||
|
|
||||||
|
describe("joinApiUrl", () => {
|
||||||
|
it("keeps same-origin paths when base url is slash", () => {
|
||||||
|
expect(joinApiUrl("/", "/v1/pipelines")).toBe("/v1/pipelines");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("joins absolute host and trims trailing slash", () => {
|
||||||
|
expect(joinApiUrl("http://127.0.0.1:8500/", "/v1/pipelines")).toBe(
|
||||||
|
"http://127.0.0.1:8500/v1/pipelines"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts path without leading slash", () => {
|
||||||
|
expect(joinApiUrl("http://127.0.0.1:8500", "v1/pipelines")).toBe(
|
||||||
|
"http://127.0.0.1:8500/v1/pipelines"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -22,6 +22,18 @@ import type {
|
|||||||
const API_BASE_URL =
|
const API_BASE_URL =
|
||||||
import.meta.env.VITE_FRONT_API_BASE_URL?.trim() || "http://127.0.0.1:8500";
|
import.meta.env.VITE_FRONT_API_BASE_URL?.trim() || "http://127.0.0.1:8500";
|
||||||
|
|
||||||
|
export function joinApiUrl(baseUrl: string, path: string): string {
|
||||||
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
||||||
|
const normalizedBase = baseUrl.trim();
|
||||||
|
|
||||||
|
// "/" is commonly used in Docker+nginx builds and should resolve as same-origin.
|
||||||
|
if (!normalizedBase || normalizedBase === "/") {
|
||||||
|
return normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${normalizedBase.replace(/\/+$/, "")}${normalizedPath}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Log which backend the frontend is targeting on startup, with file + line hint.
|
// Log which backend the frontend is targeting on startup, with file + line hint.
|
||||||
// This runs once when the module is loaded.
|
// This runs once when the module is loaded.
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@@ -30,7 +42,8 @@ console.info(
|
|||||||
);
|
);
|
||||||
|
|
||||||
async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
|
async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
|
||||||
const response = await fetch(`${API_BASE_URL}${path}`, {
|
const url = joinApiUrl(API_BASE_URL, path);
|
||||||
|
const response = await fetch(url, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(init?.headers || {}),
|
...(init?.headers || {}),
|
||||||
@@ -49,7 +62,24 @@ async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
|
|||||||
}
|
}
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
return (await response.json()) as T;
|
|
||||||
|
if (response.status === 204) {
|
||||||
|
return undefined as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bodyText = await response.text();
|
||||||
|
if (!bodyText.trim()) {
|
||||||
|
return undefined as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(bodyText) as T;
|
||||||
|
} catch {
|
||||||
|
const preview = bodyText.slice(0, 160).replace(/\s+/g, " ").trim();
|
||||||
|
throw new Error(
|
||||||
|
`Expected JSON response from ${url}, but received non-JSON content: ${preview || "<empty>"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function listAvailableGraphs(): Promise<AvailableGraphsResponse> {
|
export function listAvailableGraphs(): Promise<AvailableGraphsResponse> {
|
||||||
@@ -189,7 +219,10 @@ export async function streamAgentChatResponse(
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const { appId, sessionId, apiKey, message, onText, signal } = options;
|
const { appId, sessionId, apiKey, message, onText, signal } = options;
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${API_BASE_URL}/v1/apps/${encodeURIComponent(appId)}/sessions/${encodeURIComponent(sessionId)}/responses`,
|
joinApiUrl(
|
||||||
|
API_BASE_URL,
|
||||||
|
`/v1/apps/${encodeURIComponent(appId)}/sessions/${encodeURIComponent(sessionId)}/responses`
|
||||||
|
),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"root":["./src/App.tsx","./src/activeConfigSelection.test.ts","./src/activeConfigSelection.ts","./src/main.tsx","./src/types.ts","./src/vite-env.d.ts","./src/api/frontApis.ts"],"version":"5.9.3"}
|
{"root":["./src/App.tsx","./src/activeConfigSelection.test.ts","./src/activeConfigSelection.ts","./src/main.tsx","./src/types.ts","./src/vite-env.d.ts","./src/api/frontApis.test.ts","./src/api/frontApis.ts"],"version":"5.9.3"}
|
||||||
@@ -4,5 +4,15 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
|
proxy: {
|
||||||
|
"/v1": {
|
||||||
|
target: "http://127.0.0.1:8500",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
"/apps": {
|
||||||
|
target: "http://127.0.0.1:8500",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ export default defineConfig({
|
|||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
|
proxy: {
|
||||||
|
"/v1": {
|
||||||
|
target: "http://127.0.0.1:8500",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
"/apps": {
|
||||||
|
target: "http://127.0.0.1:8500",
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -75,23 +75,40 @@ def build_route(
|
|||||||
**_: Any,
|
**_: Any,
|
||||||
):
|
):
|
||||||
cmd_opt = [
|
cmd_opt = [
|
||||||
"--pipeline.pipeline-id", pipeline_id,
|
"--pipeline.pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
"route", # ------------
|
"route", # ------------
|
||||||
"--llm-name", llm_name,
|
"--llm-name",
|
||||||
"--api-key", api_key,
|
llm_name,
|
||||||
"--pipeline-id", pipeline_id,
|
"--api-key",
|
||||||
"--prompt-set-id", prompt_set,
|
api_key,
|
||||||
"tool_node", # ------------
|
"--pipeline-id",
|
||||||
"--llm-name", llm_name,
|
pipeline_id,
|
||||||
"--api-key", api_key,
|
"--prompt-set-id",
|
||||||
"--pipeline-id", pipeline_id,
|
prompt_set,
|
||||||
"--prompt-set-id", prompt_set,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if tool_keys:
|
if tool_keys:
|
||||||
cmd_opt.extend(
|
cmd_opt.extend(
|
||||||
["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys]
|
["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys]
|
||||||
)
|
)
|
||||||
|
# Tyro parses list options greedily across positional subcommands; repeat a
|
||||||
|
# parent-level option to terminate list parsing before `tool_node`.
|
||||||
|
cmd_opt.extend(["--pipeline-id", pipeline_id])
|
||||||
|
|
||||||
|
cmd_opt.extend(
|
||||||
|
[
|
||||||
|
"tool_node", # ------------
|
||||||
|
"--llm-name",
|
||||||
|
llm_name,
|
||||||
|
"--api-key",
|
||||||
|
api_key,
|
||||||
|
"--pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
|
"--prompt-set-id",
|
||||||
|
prompt_set,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt)
|
return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt)
|
||||||
|
|
||||||
@@ -106,12 +123,17 @@ def build_react(
|
|||||||
**_: Any,
|
**_: Any,
|
||||||
):
|
):
|
||||||
cmd_opt = [
|
cmd_opt = [
|
||||||
"--pipeline.pipeline-id", pipeline_id,
|
"--pipeline.pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
"react", # ------------
|
"react", # ------------
|
||||||
"--llm-name", llm_name,
|
"--llm-name",
|
||||||
"--api-key", api_key,
|
llm_name,
|
||||||
"--pipeline-id", pipeline_id,
|
"--api-key",
|
||||||
"--prompt-set-id", prompt_set,
|
api_key,
|
||||||
|
"--pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
|
"--prompt-set-id",
|
||||||
|
prompt_set,
|
||||||
]
|
]
|
||||||
if tool_keys:
|
if tool_keys:
|
||||||
cmd_opt.extend(
|
cmd_opt.extend(
|
||||||
@@ -146,22 +168,31 @@ def build_deep_agent(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cmd_opt = [
|
cmd_opt = [
|
||||||
"--pipeline.pipeline-id", pipeline_id,
|
"--pipeline.pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
"deepagent",
|
"deepagent",
|
||||||
"--llm-name", llm_name,
|
"--llm-name",
|
||||||
"--api-key", api_key,
|
llm_name,
|
||||||
"--pipeline-id", pipeline_id,
|
"--api-key",
|
||||||
"--prompt-set-id", prompt_set,
|
api_key,
|
||||||
backend_subcommand,
|
"--pipeline-id",
|
||||||
|
pipeline_id,
|
||||||
|
"--prompt-set-id",
|
||||||
|
prompt_set,
|
||||||
]
|
]
|
||||||
|
|
||||||
if tool_keys:
|
if tool_keys:
|
||||||
cmd_opt.extend(
|
cmd_opt.extend(
|
||||||
["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys]
|
["--tool-manager-config.client-tool-manager.tool-keys", *tool_keys]
|
||||||
)
|
)
|
||||||
|
# Same greedy-list behavior as `build_route`; terminate before backend subcommand.
|
||||||
|
cmd_opt.extend(["--pipeline-id", pipeline_id])
|
||||||
|
|
||||||
|
cmd_opt.append(backend_subcommand)
|
||||||
|
|
||||||
return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt)
|
return _build_and_load_pipeline_config(pipeline_id, pipeline_config_dir, cmd_opt)
|
||||||
|
|
||||||
|
|
||||||
# {pipeline_id: build_function}
|
# {pipeline_id: build_function}
|
||||||
GRAPH_BUILD_FNCS = {
|
GRAPH_BUILD_FNCS = {
|
||||||
"routing": build_route,
|
"routing": build_route,
|
||||||
|
|||||||
Reference in New Issue
Block a user