diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a4969f..16a59f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,12 @@ jobs: options: >- --health-cmd="rabbitmq-diagnostics -q ping" --health-interval=10s --health-timeout=5s --health-retries=12 + qdrant: + image: qdrant/qdrant:v1.19.2 + env: + QDRANT__TELEMETRY_DISABLED: 'true' + ports: + - 6333/tcp steps: - name: Checkout harness uses: actions/checkout@v4 @@ -124,4 +130,5 @@ jobs: TRITON_MYSQL_URL: mysql+pymysql://root:ci-only-password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/triton_agent_test TRITON_TEST_REDIS_URL: redis://127.0.0.1:${{ job.services.redis.ports['6379'] }}/0 TRITON_TEST_AMQP_URL: amqp://ci:ci-only-password@127.0.0.1:${{ job.services.rabbitmq.ports['5672'] }}/ + TRITON_TEST_QDRANT_URL: http://127.0.0.1:${{ job.services.qdrant.ports['6333'] }} run: pnpm test:all --reporter=verbose diff --git a/packages/dsh-triton-riscv/README.md b/packages/dsh-triton-riscv/README.md index a11f2bc..c81d748 100644 --- a/packages/dsh-triton-riscv/README.md +++ b/packages/dsh-triton-riscv/README.md @@ -94,13 +94,14 @@ See [backend options](python/codex_agent/README.md#redis-options). ### Development Tests -Vitest drives JavaScript, Python and native-host integration tests. After setup, +Vitest drives JavaScript, existing Python regressions, frontend and native-host integration tests. After setup, from the plugin directory, configure **disposable** services (never production): ```sh export TRITON_MYSQL_URL='mysql+pymysql://USER:PASSWORD@127.0.0.1:3306/triton_agent_test' export TRITON_TEST_REDIS_URL='redis://127.0.0.1:6379/0' export TRITON_TEST_AMQP_URL='amqp://guest:guest@127.0.0.1:5672/' +export TRITON_TEST_QDRANT_URL='http://127.0.0.1:6333' .venv/bin/python -I -m codex_agent.storage upgrade npm test ``` diff --git a/packages/dsh-triton-riscv/frontend/src/App.tsx b/packages/dsh-triton-riscv/frontend/src/App.tsx index 896e2d8..cbf3e6c 100644 --- a/packages/dsh-triton-riscv/frontend/src/App.tsx +++ b/packages/dsh-triton-riscv/frontend/src/App.tsx @@ -1,6 +1,22 @@ -import { Bot, Check, Menu, PanelRight, Pin, PinOff, Play, Plus, Send, Trash2, UserRound, X } from 'lucide-react' +import { + Bot, + Check, + GitBranch, + Menu, + PanelRight, + Pin, + PinOff, + Play, + Plus, + Send, + Trash2, + UserRound, + X, +} from 'lucide-react' import { FormEvent, KeyboardEvent, useEffect, useRef, useState } from 'react' import { api } from './api' +import { WorkflowPanel } from './WorkflowPanel' +import { workflowApi } from './workflow-api' import { MessageText, shortDate } from './format' import type { Bootstrap, Run, RunEvent, ProposalReview, Session, SessionBundle, ValidationPlanReview } from './types' @@ -288,6 +304,8 @@ function CommandApproval({ export default function App() { const [bootstrap, setBootstrap] = useState(null) const [sessions, setSessions] = useState([]) + const [workflowEnabled, setWorkflowEnabled] = useState(false) + const [mode, setMode] = useState<'chat' | 'workflow'>('chat') const [activeSessionId, setActiveSessionId] = useState(null) const [bundle, setBundle] = useState(null) const [activeRun, setActiveRun] = useState(null) @@ -413,6 +431,12 @@ export default function App() { useEffect(() => { let cancelled = false + void workflowApi + .config() + .then(config => { + if (!cancelled) setWorkflowEnabled(config.enabled) + }) + .catch(() => {}) const start = async () => { try { const [initialBootstrap, initialSessions] = await Promise.all([api.bootstrap(), api.listSessions()]) @@ -651,17 +675,37 @@ export default function App() {

{bundle?.session.title || '新对话'}

- DeepSeek Harness - +
+ + +
+ {mode === 'chat' && ( + + )}
{error && ( @@ -672,115 +716,121 @@ export default function App() { )} -
- {!bundle?.messages.length ? ( - - ) : ( - bundle.messages.map(message => { - return ( -
- {message.role === 'assistant' && ( -
- -
- )} + {mode === 'workflow' && activeSessionId ? ( + + ) : ( + <> +
+ {!bundle?.messages.length ? ( + + ) : ( + bundle.messages.map(message => { + return ( +
+ {message.role === 'assistant' && ( +
+ +
+ )} +
+
+ +
+
+ {message.role === 'user' && ( +
+ +
+ )} +
+ ) + }) + )} + {streamingText && ( +
+
+ +
- + +
- {message.role === 'user' && ( -
- +
+ )} + {agentWorking && !streamingText && ( +
+
+ +
+
+ - )} +
- ) - }) - )} - {streamingText && ( -
-
- -
-
-
- -
-
-
- )} - {agentWorking && !streamingText && ( -
-
- -
-
- + )} +
+
+ {approvalEvents.length > 0 && ( +
+ {approvalEvents.map(event => + event.payload.validation_run_id ? ( + + ) : ( + + ), + )}
-
- )} -
-
- {approvalEvents.length > 0 && ( -
- {approvalEvents.map(event => - event.payload.validation_run_id ? ( - - ) : ( - - ), )} -
+
+ {bootstrap?.suggestions.map(suggestion => ( + + ))} +
+
+