From 31d87449f80711a83c51dc4c3d10111ea086d491 Mon Sep 17 00:00:00 2001 From: saladday <1203511142@qq.com> Date: Mon, 28 Sep 2026 18:25:33 +0800 Subject: [PATCH 1/5] feat(example): add Parsar application on public Core API --- CONTRIBUTING.md | 13 + Makefile | 9 +- README.md | 4 + example/README.md | 5 + example/parsar/LICENSE | 21 + example/parsar/MOTION-PRIMITIVES-LICENSE | 22 + example/parsar/README.md | 116 ++++ example/parsar/index.html | 10 + example/parsar/package.json | 43 ++ example/parsar/paths.mjs | 6 + example/parsar/playwright.config.ts | 40 ++ example/parsar/public/favicon.png | Bin 0 -> 7963 bytes example/parsar/public/parsar-mark-dark.png | Bin 0 -> 28899 bytes example/parsar/public/parsar-mark-light.png | Bin 0 -> 32993 bytes example/parsar/server.mjs | 200 ++++++ example/parsar/src/Agents.tsx | 234 +++++++ example/parsar/src/App.tsx | 103 +++ example/parsar/src/Composer.tsx | 134 ++++ example/parsar/src/NewTask.tsx | 195 ++++++ example/parsar/src/TaskDetail.tsx | 150 +++++ example/parsar/src/Tasks.tsx | 115 ++++ example/parsar/src/components/Activity.tsx | 145 +++++ example/parsar/src/components/shared.tsx | 98 +++ example/parsar/src/components/ui/button.tsx | 70 ++ example/parsar/src/components/ui/dialog.tsx | 116 ++++ .../parsar/src/components/ui/empty-state.tsx | 37 ++ example/parsar/src/components/ui/input.tsx | 29 + example/parsar/src/components/ui/ledger.tsx | 349 ++++++++++ example/parsar/src/components/ui/menu.tsx | 12 + .../src/components/ui/property-list.tsx | 51 ++ example/parsar/src/components/ui/select.tsx | 74 +++ .../parsar/src/components/ui/status-icon.tsx | 94 +++ example/parsar/src/components/ui/textarea.tsx | 20 + example/parsar/src/lib/api.test.ts | 38 ++ example/parsar/src/lib/api.ts | 63 ++ .../src/lib/use-ledger-scroll-anchor.ts | 52 ++ example/parsar/src/lib/utils.ts | 6 + example/parsar/src/main.tsx | 19 + example/parsar/src/style.css | 488 ++++++++++++++ example/parsar/tests/fixture.mjs | 192 ++++++ example/parsar/tests/live.mjs | 131 ++++ example/parsar/tests/server.test.mjs | 131 ++++ example/parsar/tests/workflow.spec.ts | 134 ++++ example/parsar/tsconfig.json | 19 + example/parsar/vite.config.ts | 14 + pnpm-lock.yaml | 606 ++++++++++++++++++ pnpm-workspace.yaml | 1 + scripts/name-allowlist.json | 30 + 48 files changed, 4438 insertions(+), 1 deletion(-) create mode 100644 example/README.md create mode 100644 example/parsar/LICENSE create mode 100644 example/parsar/MOTION-PRIMITIVES-LICENSE create mode 100644 example/parsar/README.md create mode 100644 example/parsar/index.html create mode 100644 example/parsar/package.json create mode 100644 example/parsar/paths.mjs create mode 100644 example/parsar/playwright.config.ts create mode 100644 example/parsar/public/favicon.png create mode 100644 example/parsar/public/parsar-mark-dark.png create mode 100644 example/parsar/public/parsar-mark-light.png create mode 100644 example/parsar/server.mjs create mode 100644 example/parsar/src/Agents.tsx create mode 100644 example/parsar/src/App.tsx create mode 100644 example/parsar/src/Composer.tsx create mode 100644 example/parsar/src/NewTask.tsx create mode 100644 example/parsar/src/TaskDetail.tsx create mode 100644 example/parsar/src/Tasks.tsx create mode 100644 example/parsar/src/components/Activity.tsx create mode 100644 example/parsar/src/components/shared.tsx create mode 100644 example/parsar/src/components/ui/button.tsx create mode 100644 example/parsar/src/components/ui/dialog.tsx create mode 100644 example/parsar/src/components/ui/empty-state.tsx create mode 100644 example/parsar/src/components/ui/input.tsx create mode 100644 example/parsar/src/components/ui/ledger.tsx create mode 100644 example/parsar/src/components/ui/menu.tsx create mode 100644 example/parsar/src/components/ui/property-list.tsx create mode 100644 example/parsar/src/components/ui/select.tsx create mode 100644 example/parsar/src/components/ui/status-icon.tsx create mode 100644 example/parsar/src/components/ui/textarea.tsx create mode 100644 example/parsar/src/lib/api.test.ts create mode 100644 example/parsar/src/lib/api.ts create mode 100644 example/parsar/src/lib/use-ledger-scroll-anchor.ts create mode 100644 example/parsar/src/lib/utils.ts create mode 100644 example/parsar/src/main.tsx create mode 100644 example/parsar/src/style.css create mode 100644 example/parsar/tests/fixture.mjs create mode 100644 example/parsar/tests/live.mjs create mode 100644 example/parsar/tests/server.test.mjs create mode 100644 example/parsar/tests/workflow.spec.ts create mode 100644 example/parsar/tsconfig.json create mode 100644 example/parsar/vite.config.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b32f49e9c..b3e6a2113 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,15 @@ business assets, the Parsar product Web, product API and product migrations rema in Parsar. Do not import `server/`, `apps/parsar/`, product CLI/plugin packages or their deployment stack. +`example/parsar/` is an optional, independently started application example, +authorized to reuse the Parsar product's UI primitives and branding. It uses only +the public `/v1` application API through `OpenAIAgentsClient`, with a Project API +key held by its loopback server. It is not the Core administrator console and is +not included in Core distributions. It imports no product backend or database. +One task maps to one Core Session; Session metadata stores only its display title +and application marker. Core remains the sole owner of execution state and history. +Changes to examples must not make the Core service depend on an example. + Preserve copied runtime and protocol behavior. Existing Go import paths remain unchanged and do not require fetching the original repository. Installed commands and environment settings use the OpenAgentCore names documented below. The source snapshot and per-file @@ -174,6 +183,10 @@ split oversized components before extending them. Use `internal/obs/log` for log ## Required checks +`make check-example` validates the optional application example with TypeScript, +proxy/history tests, a build and fixture browser acceptance; it also runs in +`make check`. Its synthetic responses are not live model qualification. + Run `make check` before completion. The standalone gate includes all daemon/shared Go tests, Core contract/client/service tests, Core Web and TypeScript client checks (including fixture-only Playwright acceptance), a real dedicated PostgreSQL test diff --git a/Makefile b/Makefile index b1e3112bf..18a04ec5e 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ SWAG_VERSION ?= v1.16.4 help: @printf '%s\n' 'make build-agents-api Build standalone Core commands' 'make build-daemon Build the execution daemon' 'make check Run Core, persistence and runtime checks' 'See README.md for runtime prerequisites and deployment.' -check: check-docs check-names check-distribution check-database check-sqlc check-go check-microsandbox-provider check-agents-api check-claude-sdk check-web check-mcode-harness check-agents-executor +check: check-docs check-names check-distribution check-database check-sqlc check-go check-microsandbox-provider check-agents-api check-claude-sdk check-web check-example check-mcode-harness check-agents-executor @printf 'OpenAgentCore checks passed.\n' .PHONY: check-names @@ -85,6 +85,13 @@ check-web: node-deps build-claude-sdk-runtime: ./scripts/build-claude-sdk-runtime.sh +.PHONY: check-example +check-example: node-deps + pnpm --filter @oac/parsar-example typecheck + pnpm --filter @oac/parsar-example test + pnpm --filter @oac/parsar-example build + pnpm --filter @oac/parsar-example test:e2e + check-mcode-harness: node --test packages/mcode-harness/*.test.mjs @for script in packages/mcode-harness/*.mjs; do node --check "$$script"; done diff --git a/README.md b/README.md index fb6bd0525..e33b60332 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,10 @@ native differences. ## Documentation +For a complete application example using the Parsar product UI, see +[`example/parsar`](example/parsar/README.md): Agent configuration, task submission, +execution history, follow-up messages and cancellation through the public API. + | Page | Covers | | --- | --- | | [Install Core and Web](docs/getting-started/install.md) | Prerequisites, download, installer options, HTTPS and the reverse proxy, first sign-in | diff --git a/example/README.md b/example/README.md new file mode 100644 index 000000000..eca9f343f --- /dev/null +++ b/example/README.md @@ -0,0 +1,5 @@ +# Application examples + +- [Parsar](parsar/README.md): a small task application using the public Agents API + and the Parsar product UI. Start here for an end-to-end application rather than + isolated API snippets. diff --git a/example/parsar/LICENSE b/example/parsar/LICENSE new file mode 100644 index 000000000..60d8db904 --- /dev/null +++ b/example/parsar/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 MiniMax-AI-Dev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/example/parsar/MOTION-PRIMITIVES-LICENSE b/example/parsar/MOTION-PRIMITIVES-LICENSE new file mode 100644 index 000000000..1a911b3bb --- /dev/null +++ b/example/parsar/MOTION-PRIMITIVES-LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2024 ibelick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +app/page.tsx diff --git a/example/parsar/README.md b/example/parsar/README.md new file mode 100644 index 000000000..158b6bba8 --- /dev/null +++ b/example/parsar/README.md @@ -0,0 +1,116 @@ +# Parsar example + +A small, complete Parsar application on OpenAgentCore: configure an Agent, submit +a task, inspect its history, continue the conversation and cancel execution. +The UI reuses the original product's Issue Ledger, dialogs, controls, status icons, +light/dark tokens and brand assets. There is one task list and one Agent list; +task details are a second page, configuration lives in dialogs, and optional help +uses focusable question-mark tooltips. + +## Run + +Use Node 22+ and pnpm 10.30.3 from the repository root. First install and configure +[Core](../../docs/getting-started/install.md), including a supported model/provider +and a ready node for hosted execution. Create a dedicated Project and issue its +API key in the Core administrator console. A Core key cannot execute tasks. + +Keep the following settings in your shell or a private environment file outside +the checkout. They are server-only and must never use a `VITE_` prefix: + +```sh +export OAC_EXAMPLE_CORE_URL='http://127.0.0.1:8091' +export OAC_EXAMPLE_PROJECT_KEY='' +pnpm install --frozen-lockfile +pnpm --filter @oac/parsar-example dev +``` + +Open http://127.0.0.1:18180. The Core URL is an origin without `/v1`; use HTTPS +for a remote deployment. Set `OAC_EXAMPLE_PORT` to change the local port. +For a built version: + +```sh +pnpm --filter @oac/parsar-example build +pnpm --filter @oac/parsar-example start +``` + +Builds and caches go under `${OAC_DEV_HOME:-$HOME/.oac}`. The example binds only +to loopback and is intended for one trusted local user. It has no user login or +public hosting mode. The server injects the Project key into an allowlisted set +of `/v1` requests and rejects cross-origin browser calls. It exposes no Core +administrator or machine routes. + +1. Open **Agents**, create an Agent with a model available in your deployment, + and optionally select a harness. Provider credentials come from Core deployment + configuration; this example does not edit provider secrets. +2. Open **Tasks**, create a task and select that Agent. Use the hosted environment + for coding/tools, or `none` for the deployment's qualified text-only profile. +3. Open the task to inspect messages and expandable tool output, send a follow-up + or cancel execution. Refreshing the page reloads Core's saved history. + +## Boundaries + +- The example uses `packages/agents-client`'s `OpenAIAgentsClient` and no product + server, database, administrator client or native runtime code. +- Each task is one Core Session. Its display title is Session metadata; Agents, + Turns, Items and execution status remain Core-owned. Lists show the configured + Project's resources, so use a dedicated Project for an isolated trial. +- The detail page polls persisted history every two seconds; it does not promise + token streaming or SSE replay. Item history is paginated up to 10,000 items; + exceeding that bound produces an explicit error. Task and Agent lists support + cursor pagination. +- Session `idle` is not a success claim. Details use the latest persisted Turn + for completed/cancelled status. A cancellation acknowledgement is not completion. +- Creation and message retries retain the same request and idempotency key in + this tab's session storage, including after reload. A lost response locks the + pending input for an explicit same-request retry. No write is retried automatically. + Session storage contains task text; closing the tab clears this local retry aid. +- Team orchestration, approval/function-result handling, self-hosted enrollment, + files/artifact browsing, multiple users, permissions, billing and IM are omitted. + Required actions remain visible and can be cancelled; they are never approved + automatically. Existing resources are read through the same Project API. + +## Validate + +```sh +make check-example +make check +``` + +`check-example` includes TypeScript, proxy isolation/error tests, history/status +tests, a build and Playwright browser workflows. Install Chrome with +`pnpm exec playwright install chrome` if needed. Browser fixtures use ports +18180/18181 and synthetic model results; they do not prove live model execution. +Their screenshots/traces go under `~/.oac/tests/parsar-example/` (or `OAC_DEV_HOME`). +The opt-in browser probe runs against an already started example server backed by +an isolated live Project (it creates one Agent and task): + +```sh +OAC_EXAMPLE_LIVE_URL=http://127.0.0.1:18180 \ +OAC_EXAMPLE_LIVE_MODEL='' \ +pnpm --filter @oac/parsar-example test:live +``` + +It defaults to Claude Code; set `OAC_EXAMPLE_LIVE_HARNESS` to the UI option label +for another qualified harness. It exercises actual output, reload, follow-up and +persisted cancellation and leaves its task available for inspection. + +Manual acceptance additionally needs your configured Core, Project key and provider: +create an Agent and task, verify actual output, reload its history, then send a +longer follow-up and cancel it. Verify Core's final Turn status before claiming +cancellation. Never commit credentials or real task content as test fixtures. + +## UI provenance + +The copied `src/components/ui/*`, `src/lib/utils.ts`, +`src/lib/use-ledger-scroll-anchor.ts`, `src/style.css` and `public/*` come from +[Parsar](https://github.com/MiniMax-AI-Dev/parsar) revision `90fafede`, under +the accompanying [MIT license](LICENSE). Strict indexed-access adjustments in the +Ledger, the responsive body minimum width and the example's application pages are +local adaptations. + +The animated navigation selection and execution shimmer adapt the +[Motion Primitives](https://github.com/ibelick/motion-primitives) Animated Background +and Text Shimmer patterns, using Motion with reduced-motion support and Parsar +tokens. Its [MIT notice](MOTION-PRIMITIVES-LICENSE) is retained. Markdown uses the +same React Markdown foundation as Parsar, with GFM and copyable code blocks; no +additional agent runtime or model SDK is introduced for presentation. diff --git a/example/parsar/index.html b/example/parsar/index.html new file mode 100644 index 000000000..3a8a297b5 --- /dev/null +++ b/example/parsar/index.html @@ -0,0 +1,10 @@ + + + + + + + Parsar · OpenAgentCore + +
+ diff --git a/example/parsar/package.json b/example/parsar/package.json new file mode 100644 index 000000000..694fa5d6f --- /dev/null +++ b/example/parsar/package.json @@ -0,0 +1,43 @@ +{ + "name": "@oac/parsar-example", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "node server.mjs --dev", + "build": "vite build", + "start": "node server.mjs", + "typecheck": "tsc --noEmit", + "test": "node --test tests/server.test.mjs && vitest run", + "test:e2e": "playwright test --config playwright.config.ts", + "test:live": "node tests/live.mjs" + }, + "dependencies": { + "@agents-core-web/agents-client": "workspace:*", + "@tanstack/react-query": "^5.103.2", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^1.22.0", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", + "tailwind-merge": "^3.7.0", + "@radix-ui/react-dialog": "^1.1.18", + "@radix-ui/react-select": "2.3.2", + "@radix-ui/react-slot": "^1.3.0", + "motion": "^13.4.3", + "@radix-ui/react-tooltip": "^1.2.11" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.1.0", + "@vitejs/plugin-react": "^6.0.4", + "tailwindcss": "^4.3.3", + "typescript": "^5.8.3", + "vite": "^8.1.4", + "vitest": "^4.1.9", + "@tailwindcss/typography": "^0.5.20" + } +} diff --git a/example/parsar/paths.mjs b/example/parsar/paths.mjs new file mode 100644 index 000000000..c9964c2f9 --- /dev/null +++ b/example/parsar/paths.mjs @@ -0,0 +1,6 @@ +import { homedir } from "node:os"; +import { isAbsolute, join } from "node:path"; + +const home = process.env.OAC_DEV_HOME || join(homedir(), ".oac"); +if (!isAbsolute(home)) throw new Error("OAC_DEV_HOME must be absolute."); +export const buildDirectory = join(home, "build", "parsar-example"); diff --git a/example/parsar/playwright.config.ts b/example/parsar/playwright.config.ts new file mode 100644 index 000000000..34a41a075 --- /dev/null +++ b/example/parsar/playwright.config.ts @@ -0,0 +1,40 @@ +import { defineConfig } from "@playwright/test"; +import { homedir } from "node:os"; +import { join } from "node:path"; + +export default defineConfig({ + testDir: "tests", + testMatch: "*.spec.ts", + workers: 1, + timeout: 30_000, + outputDir: join( + process.env.OAC_DEV_HOME || join(homedir(), ".oac"), + "tests", + "parsar-example", + ), + reporter: "line", + use: { + baseURL: "http://127.0.0.1:18180", + channel: "chrome", + reducedMotion: "reduce", + screenshot: "only-on-failure", + trace: "retain-on-failure", + }, + webServer: [ + { + command: "node tests/fixture.mjs", + url: "http://127.0.0.1:18181/health", + reuseExistingServer: false, + }, + { + command: "node server.mjs --dev", + url: "http://127.0.0.1:18180", + env: { + OAC_EXAMPLE_CORE_URL: "http://127.0.0.1:18181", + OAC_EXAMPLE_PROJECT_KEY: "fixture-project-key", + OAC_EXAMPLE_PORT: "18180", + }, + reuseExistingServer: false, + }, + ], +}); diff --git a/example/parsar/public/favicon.png b/example/parsar/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..83ad57715d733063ffd94ceb4686ab64350aea10 GIT binary patch literal 7963 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 bCp4xh_}M^@)f@7ErZ+$x{2ElLWEJrr2_Ik8 literal 0 HcmV?d00001 diff --git a/example/parsar/public/parsar-mark-dark.png b/example/parsar/public/parsar-mark-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8a38b4d34b0734f8cf5f347304a9ab1c0a82f614 GIT binary patch literal 28899 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 QFE4~B$*I9BWXyv82kRa7umAu6 literal 0 HcmV?d00001 diff --git a/example/parsar/public/parsar-mark-light.png b/example/parsar/public/parsar-mark-light.png new file mode 100644 index 0000000000000000000000000000000000000000..2d3f2bed915bd93aaf5454fb8630b3b3b605cd99 GIT binary patch literal 32993 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 65535) + throw new Error("Invalid OAC_EXAMPLE_PORT."); + return { target: target.origin, key, port }; +} + +function fail(res, status, message) { + res.writeHead(status, { + "Content-Type": "application/json", + "Cache-Control": "no-store", + }); + res.end(JSON.stringify({ error: { message } })); +} + +export function createHandler(config, { fetchImpl = fetch, frontend } = {}) { + return async (req, res) => { + res.setHeader("X-Content-Type-Options", "nosniff"); + res.setHeader("Referrer-Policy", "no-referrer"); + const hosts = [`127.0.0.1:${config.port}`, `localhost:${config.port}`]; + if ( + !hosts.includes(req.headers.host) || + (req.headers.origin && + req.headers.origin !== `http://${req.headers.host}`) || + req.headers["sec-fetch-site"] === "cross-site" + ) { + return fail( + res, + 403, + "This local example accepts same-origin requests only.", + ); + } + const url = new URL(req.url, `http://${req.headers.host}`); + if ( + url.pathname.startsWith("/v1/") || + url.pathname.startsWith("/core/") || + url.pathname.startsWith("/api/") + ) { + if ( + !routes.some( + ([pattern, methods]) => + pattern.test(url.pathname) && methods.includes(req.method), + ) + ) { + return fail(res, 404, "This example does not expose that route."); + } + if ( + req.method !== "GET" && + req.headers.origin !== `http://${req.headers.host}` + ) { + return fail( + res, + 403, + "A same-origin Origin header is required for writes.", + ); + } + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 30_000); + res.on("close", () => controller.abort()); + try { + const chunks = []; + let size = 0; + for await (const chunk of req) { + size += chunk.length; + if (size > 1024 * 1024) return fail(res, 413, "Request too large."); + chunks.push(chunk); + } + const headers = { + Authorization: `Bearer ${config.key}`, + "OpenAI-Beta": "agents=v1", + "Content-Type": "application/json", + }; + if (req.headers["idempotency-key"]) + headers["Idempotency-Key"] = req.headers["idempotency-key"]; + const upstream = await fetchImpl( + `${config.target}${url.pathname}${url.search}`, + { + method: req.method, + headers, + redirect: "manual", + signal: controller.signal, + ...(req.method === "POST" ? { body: Buffer.concat(chunks) } : {}), + }, + ); + if (upstream.status >= 300 && upstream.status < 400) + return fail( + res, + 502, + "Core returned a redirect; check its configured origin.", + ); + const body = await upstream.text(); + res.writeHead(upstream.status, { + "Content-Type": "application/json", + "Cache-Control": "no-store", + }); + res.end(body); + } catch { + if (!res.destroyed) + fail( + res, + 502, + "Cannot reach Core. Check the example server configuration and retry the same request.", + ); + } finally { + clearTimeout(timer); + } + return; + } + if (!["GET", "HEAD"].includes(req.method)) + return fail(res, 405, "Method not allowed."); + if (frontend) return frontend(req, res); + try { + const path = resolve( + buildDirectory, + `.${decodeURIComponent(url.pathname)}`, + ); + if ( + !path.startsWith(`${buildDirectory}${sep}`) && + path !== buildDirectory + ) + return fail(res, 404, "Not found."); + const asset = extname(path) + ? path + : resolve(buildDirectory, "index.html"); + const content = await readFile(asset); + res.writeHead(200, { + "Content-Type": mime[extname(asset)] || "application/octet-stream", + "Cache-Control": "no-cache", + }); + res.end(req.method === "HEAD" ? undefined : content); + } catch { + fail(res, 404, "Page not found. Run the example build first."); + } + }; +} + +if ( + process.argv[1] && + import.meta.url === pathToFileURL(process.argv[1]).href +) { + const config = configuration(); + const server = createServer(); + const vite = process.argv.includes("--dev") + ? await ( + await import("vite") + ).createServer({ root, server: { middlewareMode: true, hmr: { server } }, appType: "spa" }) + : undefined; + server.on("request", createHandler(config, { frontend: vite?.middlewares })); + server.listen(config.port, "127.0.0.1", () => { + process.stdout.write(`Parsar: http://127.0.0.1:${config.port}\n`); + }); + for (const signal of ["SIGINT", "SIGTERM"]) + process.on(signal, () => { + server.close(); + void vite?.close(); + }); +} diff --git a/example/parsar/src/Agents.tsx b/example/parsar/src/Agents.tsx new file mode 100644 index 000000000..ad3831a04 --- /dev/null +++ b/example/parsar/src/Agents.tsx @@ -0,0 +1,234 @@ +import { useState } from "react"; +import { + useInfiniteQuery, + useMutation, + useQueryClient, +} from "@tanstack/react-query"; +import { Bot, Plus } from "lucide-react"; +import type { + CoreHarnessKind, + SavedAgent, +} from "@agents-core-web/agents-client"; +import { api, application } from "./lib/api"; +import { Button } from "./components/ui/button"; +import { Input } from "./components/ui/input"; +import { Textarea } from "./components/ui/textarea"; +import { Select, SelectOption } from "./components/ui/select"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "./components/ui/dialog"; +import { + col, + Ledger, + LedgerHeader, + LedgerRow, + InitialTile, +} from "./components/ui/ledger"; +import { EmptyState } from "./components/ui/empty-state"; +import { ErrorNotice, Field, Help, PageHeader } from "./components/shared"; + +export function useAgents() { + return useInfiniteQuery({ + queryKey: ["agents"], + initialPageParam: undefined as string | undefined, + queryFn: ({ pageParam, signal }) => + api.listAgents({ limit: 100, after: pageParam, signal }), + getNextPageParam: (page) => + page.has_more ? page.last_id || undefined : undefined, + }); +} + +export function Agents() { + const query = useAgents(); + const [editing, setEditing] = useState(null); + const agents = query.data?.pages.flatMap((page) => page.data) || []; + return ( + <> + + + 配置可重复使用的 Agent。模型和运行引擎需要在 Core 部署中可用。 + + + + void query.refetch()} /> + {query.isPending ? ( + + ) : agents.length === 0 && !query.error ? ( + + ) : ( + + + + 名称 + 模型 + 运行引擎 + +

    + {agents.map((agent) => ( + setEditing(agent)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setEditing(agent); + } + }} + > + + + {agent.name || "未命名 Agent"} + + {agent.model} + {agent.x_agents_core?.harness || "部署默认"} + + ))} +
+ + )} + {query.hasNextPage && ( +
+ +
+ )} + {editing && ( + setEditing(null)} + /> + )} + + ); +} + +function AgentEditor({ + agent, + close, +}: { + agent?: SavedAgent; + close: () => void; +}) { + const cache = useQueryClient(); + const [name, setName] = useState(agent?.name || ""); + const [model, setModel] = useState(agent?.model || ""); + const [instructions, setInstructions] = useState(agent?.instructions || ""); + const [harness, setHarness] = useState( + agent?.x_agents_core?.harness || "", + ); + const save = useMutation({ + mutationFn: () => { + const input = { + name: name.trim(), + model: model.trim(), + instructions, + ...(harness ? { x_agents_core: { harness } } : {}), + }; + return agent + ? api.updateAgent(agent.id, input) + : api.createAgent({ + ...input, + metadata: { application }, + multi_agent: { enabled: false }, + text: { verbosity: "medium" }, + tools: [{ type: "web_search", mode: "disabled" }], + }); + }, + onSuccess: () => { + void cache.invalidateQueries({ queryKey: ["agents"] }); + close(); + }, + }); + return ( + { + if (!open && !save.isPending) close(); + }} + > + + + {agent ? "编辑 Agent" : "新建 Agent"} + +
{ + e.preventDefault(); + save.mutate(); + }} + > + + setName(e.target.value)} + /> + + + setModel(e.target.value)} + placeholder="输入部署支持的模型名称" + /> + + + + + +