Commit Graph
93 Commits
Author SHA1 Message Date
Eric Wang 97de142e6d feat(storage): add selectable SQLite and PostgreSQL persistence
- Select one storage backend per instance via AGENT_STORAGE, retaining
  memory as the backward-compatible default. Manage the selected async
  repository, official checkpointer and connection pools in lifespan;
  fail startup on unavailable or uninitialized storage without fallback.
- Add SQLite and PostgreSQL adapters, schema initialization CLI, sample
  PostgreSQL compose configuration and a Windows-compatible serve entry.
  SQLite enforces single-instance file ownership; PostgreSQL uses a
  dedicated pool for session advisory locks plus version/epoch fencing.
- Make repository IO and commit callbacks awaitable. Persist business
  fields, a complete committed graph snapshot and turn result/version in
  one business transaction before success. Rebuild execution checkpoints
  from that snapshot, discarding uncommitted progress after interruption.
- Support optional Idempotency-Key on durable chat requests. Replay
  committed results and return 409 on changed request content; delete
  removes business/history data and replay records while retaining only
  an epoch/version tombstone to reject stale commits.
- Document migration, database switching boundaries, backup/deployment
  expectations and crash recovery. Ignore generated database files.

Validation: 315 tests passed with real SQLite and isolated PostgreSQL,
including abrupt child-process exits before/after business commit;
both backends passed CLI migration and actual HTTP server restart smoke.
Existing API tests were rechecked after isolating them from user storage.
An initial Windows CreateProcess permission failure did not recur in the
full diagnostic run; failure assertions were not skipped or relaxed.
2026-10-24 13:41:54 +08:00
Eric Wang 3caf17494f fix(api): report checkpoint deletion failures and classify SSE errors
Delete checkpoints before removing business fields. Suppress only an
explicit CheckpointNotFoundError; propagate storage failures and
cancellation so the endpoint cannot report false success. Prefer async
checkpoint deletion and fail clearly when cleanup is unsupported.

Classify SSE error events as 401 for authentication, 429 for rate limits,
and 500 for other failures, using the same fixed messages as non-stream
responses. Errors terminate the stream without a success done event or
provider exception text in the response.

Validation: 286 offline tests passed (19 added), including failed-delete
HTTP retry with preserved business/checkpoint state, explicit missing
threads, cancellation, missing cleanup capability, and HTTP SSE errors
before and after text output.
2026-10-23 19:48:29 +08:00
Eric Wang 24e2cfbe10 fix(backends): make streamed replies and session state consistent
- Validate stage prefixes before forwarding model tokens. Invalid prefixes
  may use the existing repair budget; once output starts, validation failure
  aborts the turn without appending a regenerated reply. Bound the token
  queue and close inner streams when consumption stops.
- Replace delete-time lock eviction with reference-counted session locks
  covering holders and waiters. Serialize set/get with chat/stream/delete
  and release cancelled waiters without replacing a live lock.
- Store person synonyms under workflow-native driver keys and expose
  consistent alias views to single/group reads and graph prompt injection.
- Separate committed field patches from public formUpdate visibility.
  Commit callbacks keep repository fields synchronized even when updates
  are hidden or the consumer closes after graph completion.
- Disable OpenAI SDK automatic retries. Own bounded retry attempts in the
  application, use 1/2/4 second backoff, retry streams only before text is
  emitted, enforce attempt timeouts, and close upstream/client resources.
- Translate FastGPT SDK max_retries (total attempts) from the configured
  extra-retry count, and verify the real SDK loop uses four attempts.
- Document the per-LLM budget and streaming failure semantics without
  claiming the whole multi-call HTTP turn has the same timeout.

Validation: 267 offline tests passed, including actual SDK requests through
MockTransport, stream repair/abort, timeout/close, lock races, aliases and
formUpdate visibility; existing four dependency deprecation warnings.
2026-10-23 15:54:51 +08:00
Eric Wang 952bffe6f0 feat(streaming): real incremental SSE - model tokens flow through graph to client (assignment 8)
Replaces the 'complete answer sliced into chunks' stopgap with token-
level streaming. Graph nodes are untouched: they still consume the
batched LLMService.complete interface and validate full replies.

- agent/llm: OpenAILLMService.stream_tokens() iterates the provider
  stream with the same message construction, temperature and extra_body
  forwarding as complete(); identical error classification (401 ->
  LLMAuthError, 429 -> LLMRateLimitError, timeout via asyncio.timeout
  around the whole iteration); deliberately no retries (tokens already
  emitted cannot be recalled)
- backends/langgraph: _TokenPassThroughLLM wraps the injected LLM for
  stream turns - dialogue calls push tokens to a queue bridge while
  accumulating the full text for node validation; calls marked with the
  【字段提取】 marker take the silent inner.complete path so extraction
  JSON never leaks into the client stream; LLMs without stream_tokens
  fall back to single-chunk push (fake/test compatibility)
- stream(): graph runs in a background task; the generator yields
  TextDelta per token and FormUpdate after the turn; graph-task errors
  re-raise with the existing ChatBackend error mapping; generator close
  (client disconnect) cancels the graph task and the in-flight LLM call
- fixed-answer turns with no LLM call (welcome) fall back to emitting
  the full response text, preserving previous behavior
- endpoint untouched: its buffering parser already handles arbitrary
  chunk boundaries (state tags split across tokens, stage-first order)

Verified: 241 unit tests (11 new streaming tests: token incrementality,
extraction bypass, FormUpdate ordering, error mapping on both paths,
disconnect cancellation, fallback chunking, SSE protocol end-to-end
with per-token text_delta events)
2026-10-23 00:20:03 +08:00
Eric Wang 20e151b097 feat(services): register workflow-native driver keys in field registry
Workflow reconciliation (see previous commit) showed the 20261022
state variable really stores person identity under driver{i}ID /
driver{i}Phonenumber (x2), while the API get_info group keys
(sfzmhm{i}/sjhm{i}) have zero references in any workflow version -
the legacy group read always returned empty for workflow-produced data.

- registry: +4 keys (driver1/2ID, driver1/2Phonenumber) in
  human1/human2 groups, SENSITIVE, documented as synonymous with
  sfzmhm{i}/sjhm{i}; 24 -> 28 specs
- driver{i}License deliberately NOT registered: the sandbox reads
  state.hphm{i} and only renames the output for confirmation prompts -
  it is not a state key, set_info rejects it as unknown (workflow
  never consumes it)
- intentional diff documented: acdhuman1/2 group output now includes
  the driver keys (legacy FastGPT output did not) - fixes the legacy
  'workflow person data unreadable by group' gap; synonym merging
  (driver1ID vs sfzmhm1) deferred pending caller confirmation
- tests: registry size 28, driver keys present with sensitive level,
  License alias excluded

Verified: 230 unit tests
2026-10-22 23:40:27 +08:00
Eric Wang 11131885a6 feat(api): warn on unrecognized stage codes (B4 gray-release monitoring)
LLM/output stage codes outside STATUS_CODE_MAP were passed through
silently with an empty nextStage - undetectable drift between the
prompt output code set and the endpoint mapping table.

- endpoints: _stage_label / _warn_unknown_stage_code helpers; both
  streaming and non-streaming paths emit a warning with sessionId,
  clientMode, raw and normalized codes when the label lookup misses
  (transparency behavior unchanged: code passes through, label empty)
- known codes and covered internal normalizations (e.g. 2020->0002)
  stay silent; the warning fires on the normalized value

Verified: 229 unit tests (4 new monitoring tests)
2026-10-22 23:19:11 +08:00
Eric Wang b8008da959 feat(config): configurable conversation history window (B3)
FastGPT maintains full history server-side; LangGraph truncated the
injected history at a hardcoded 50 messages, so long conversations
behaved differently across backends.

- Config.AGENT_HISTORY_MESSAGES (env): max messages injected into the
  model prompt (recent N, both roles counted); default 50 unchanged;
  larger values support long conversations; 0 = no truncation, matching
  FastGPT's full-history semantics. Only the injected window is
  affected - dialogue stays fully persisted in the checkpoint.
- validate(): rejects negative values; 0 and positive accepted
- conversation_history reads the config (import-time class attribute,
  monkeypatched in tests); explicit None-check keeps 0 falsy-safe
- .env.example documents the knob

Verified: 225 unit tests (6 new history-window tests)
2026-10-22 23:01:40 +08:00
Eric Wang f04e5ff612 feat(services): per-session serialization for chat/stream/delete (A2 concurrency isolation)
FastGPT serializes requests per chatId server-side; the LangGraph
backend held all state in memory with no locking, so two concurrent
requests on one session could interleave (checkpoint write races,
garbled no_reply/turn bookkeeping).

- AccidentAppService holds per-session asyncio locks; chat(), stream()
  and delete_session() execute under the session lock (LLM call
  included - same-session turns are strictly serialized, different
  sessions never contend)
- set_info/get_info stay synchronous and lock-free: repository
  load/apply_update are atomic dict operations with no mixed
  intermediate state; a racing set vs chat yields one complete value
- delete pops the lock entry after cleanup; a chat that arrived
  concurrently executes afterwards against the fresh (deleted)
  session - matching FastGPT's delete-then-chat new-conversation
  semantics
- tests: same-session concurrent chats serialize (interval pairing
  probe), different sessions run parallel, delete waits for in-flight
  chat, chat-vs-set interleave leaves no torn values

Verified: 219 unit tests (4 new concurrency tests)
2026-10-22 22:53:13 +08:00
Eric Wang 833725d8a3 feat(config): align LLM timeout/retry SLA with FastGPT client (60s/3)
Replaces the unequal SLA (LLM 30s/2 retries vs FastGPT client 60s/3)
that made the LangGraph backend look less stable under gray release.

- core/fastgpt_client: FASTGPT_TIMEOUT_SECONDS / FASTGPT_MAX_RETRIES
  module constants (were inline literals in lifespan)
- agent/llm: OpenAILLMService defaults 60.0s / 3 retries
- core/config: named-profile fallback defaults 60/3 (prefixed and
  JSON-dict forms)
- contract test test/backends/test_sla_alignment.py pins both sides to
  the same constants so the SLA cannot drift apart again
- retry backoff intentionally differs (FastGPT fixed 1s vs LLM
  exponential) and is documented; aligned parameters are per-call
  timeout and max retry count

Verified: 215 unit tests (3 new SLA contract tests)
2026-10-22 22:31:28 +08:00
Eric Wang ca73b1e8c5 feat(backends): map LLM auth/rate-limit errors to backend-neutral errors
Closes the error-code gap between LangGraph and FastGPT backends: the
endpoint's 401/429 branches previously could never trigger under the
LangGraph backend because all provider failures collapsed into LLMAPIError
(500).

- agent/llm: LLMAuthError / LLMRateLimitError as LLMAPIError subclasses;
  OpenAILLMService raises them from openai AuthenticationError (401, no
  retry) and RateLimitError (429, after bounded retries exhausted)
- backends/langgraph: _complete_turn translates LLMAuthError ->
  ChatBackendAuthenticationError and LLMRateLimitError ->
  ChatBackendRateLimitError; stream reuses complete() so the mapping
  applies to both paths; other errors (timeout etc.) propagate unchanged
- endpoint untouched: existing 401/429 response branches now fire for
  both backends

Verified: 212 unit tests (7 new error-mapping tests)
2026-10-22 21:50:56 +08:00
Eric Wang 2bbbaf07af docs(services): workflow 20261022 field reconciliation for assignment 6
Reconciled the field registry against workflow/20261022 (synced with
main@c7ca781) and historical versions 20250419-20261021:
- form six keys match the workflow form variable (bNJkeXot) and the
  更新表单 whitelist semantics exactly
- acd business keys originate from the 20250419 extraction schema
  (dropped by the workflow since 20251015, kept as the API contract)
- person group keys (xm1/sfzmwh1/sjwh1/csbw1...) exist in no workflow
  version - they are the API server's own contract
- the form<->business key mapping is migration-new semantics bridging
  both sides, fixed by bidirectional tests
Finding: workflow 20261022 state uses driver1ID/driver1License/
driver1Phonenumber naming, which never matched the API get_info group
keys - existing behavior read empty; recorded in the audit backlog to
confirm which naming live callers actually use
2026-10-22 21:38:10 +08:00
Eric Wang 7f52f1c4d0 feat(services): assignment 6 full - form/business key mapping and stream write-back
- fields_registry: FORM_TO_BUSINESS_KEY bidirectional mapping between
  the graph's six form keys (has_injury...) and the acd business keys
  (ywrysw...); bjrjs/ywmtc have no form source (set_info only);
  business_patch_from_form maps graph diffs to whitelisted business keys
  and filters internal/unknown keys
- app_service: chat injection now maps repository business keys back to
  form keys; both complete() and stream() write back field diffs
  (FormUpdate events captured in stream, closing the skeleton gap);
  form keys never leak into the business repository
- docs/assignment6-compat.md: mapping table documented, stream write-back
  backlog item resolved
- tests: mapping coverage, write-back mapping end-to-end, reverse
  mapping injection (bjrjs/ywmtc excluded), stream FormUpdate write-back

Verified: 205 unit tests
2026-10-22 21:07:01 +08:00
Eric Wang 8717d9066c feat(services): assignment 6 skeleton - app service, field registry, in-memory repository
- fields_registry: 24 business keys in acd/human1/human2 groups with
  value_type, writable and SensitiveLevel metadata; strict bool/int
  parsing (no bool('0') trap); INTERNAL_FIELD_KEYS protection list
- repository: SessionRepository protocol + InMemorySessionRepository
  (idempotent delete; PostgreSQL swap-in is assignment 7)
- AccidentAppService: chat/set_info/get_info/delete_session share one
  business state - chat injects latest repository fields into the graph
  and writes back validated field diffs; set/get/delete make zero LLM
  calls and zero helper conversations (includeInputInfo accepted but
  unused); unknown get keys keep the '' JSON-empty-string contract,
  unknown set keys are rejected by whitelist
- ChatInput.injected_fields neutral contract extension; LangGraphBackend
  merges injected fields into graph input (set_info visible next chat)
- endpoints: thin layer - langgraph mode routes business state through
  the app service (fastgpt mode keeps the legacy path); delete cleans
  repository + graph checkpoint, idempotent
- tests: registry completeness (sfzmwh/sjwh/csbw included), app service
  combos with LLM-call spy, HTTP acceptance flow (set -> get -> chat ->
  groups -> delete -> no leak, idempotent re-delete)
- docs/assignment6-compat.md: behavior diff list vs FastGPT status quo
  and the audit backlog (arbitrary set_info key usage, stream formUpdate
  write-back, sensitive-field display boundary)

Verified: 200 unit tests (172 existing + 28 new)
2026-10-22 20:50:10 +08:00
Eric Wang 6c1fbd0295 docs(config): add GPT6 Luna and disable-thinking examples 2026-10-22 20:23:37 +08:00
Eric Wang e5d2a78886 feat(config): named LLM provider list via env vars, runtime selection
- Config.llm_profiles: LLM_PROVIDERS declares names, each group defined by
  LLM_<NAME>_BASE_URL/_API_KEY/_MODEL (required) and optional _TIMEOUT_SECONDS/
  _MAX_RETRIES/_TEMPERATURE/_EXTRA_BODY; JSON-dict form of LLM_PROVIDERS also
  supported. LLM_PROVIDER selects the active group at runtime; empty/fake =
  offline scripted model
- removed fixed openai/kimi groups (AGENT_LLM_PROVIDER, KIMI_LLM_*)
- validate(): incomplete groups and unknown LLM_PROVIDER fail fast with
  the configured-name list
- OpenAILLMService: http client trust_env from LLM_HTTP_TRUST_ENV (default
  False - local gateways must bypass the Windows system proxy)
- build_llm_service(provider): explicit name or LLM_PROVIDER default
- .env/.env.example: deepseek + kimi groups side by side, switch by
  LLM_PROVIDER=kimi (thinking off via EXTRA_BODY reasoning_effort=none)
- eval probe scripts updated to the new config interface

Verified: 172 unit tests; live calls succeed on both providers
(deepseek 28s, kimi 6.6s, both emitting valid <state> prefixes)
2026-10-22 13:59:18 +08:00
Eric Wang e72d9c9bc0 feat(agent): align with workflow@20261022 - turn_context messages and prompt tails
- merge main (b0ff2e0..c7ca781): workflow/20261022 moves dynamic context
  out of fixed prompts - collection/extraction prompts carry no inline vars;
  reference time and current form travel in the user message <turn_context>
  block; photo/confirm data kept at prompt tails
- prompts: all 8 files regenerated from 20261022 (byte-identity tests
  point at the new export)
- collect: user message = <turn_context>(本轮参考时间) + <user_input>;
  extraction message adds 当前表单; single trusted clock per turn threads
  through reply/extraction/repair
- photo: raw input only (20261022 photo nodes use system_text, no wrapper)
- workflow fake llm: unwraps <user_input> before event parsing
- fields: accident_time normalized to extraction format (YYYY年M月D日H点m分,
  strip zero padding) - fixes form assertion mismatch with padded output
- evals/run.py: trust_env=False - bypass Windows system proxy (registry
  proxy at 192.168.0.4:7897 was intercepting localhost and returning 503)
- verified: 172 unit tests; ALL golden suites pass on real model
  (46/46): collection_skip 12/12, photo_skip 4/4, no_false 2/2,
  button_guidance 12/12, non_motor_vehicle 14/14, time_confirmation 2/2
2026-10-22 12:28:24 +08:00
Eric Wang f9ec20cd81 Merge branch 'main' into langgraph-migration 2026-10-22 11:30:15 +08:00
Eric Wang c7ca781b28 perf(workflow): move photo and confirmation data to prompt tails 2026-10-22 11:26:15 +08:00
Eric Wang dd45c9d870 perf(workflow): move dynamic context out of fixed prompts 2026-10-22 10:58:20 +08:00
Eric Wang b0ff2e03b6 fix(workflow): align collection and extraction prompts for 20261022 2026-10-22 10:30:57 +08:00
Eric Wang 9e28f69b3c feat(agent): trusted time evidence and collection prompt optimization
- time_context.py: server-side observation clocks for relative-time
  evidence (anti client-forgery); resolves X分钟前/小时前 against the
  observation timestamp of the turn that produced them, never re-basing
  history on the current clock; flags historical references without a
  reliable baseline
- state: dialogue_timestamps keyed by dialogue message index, persisted
  with checkpoint; welcome seeds index 0
- collect: single clock per turn shared by reply/extraction/repair;
  time_evidence injected into runtime context; reply_validator hook
  rejects time claims lacking evidence (one shared repair budget);
  model still interprets facts and chooses actions
- prompts: collection prompt restructured (shorter, state-bound-to-action
  table, gatekeeper principle, time source rules); extraction prompt
  aligned; workflow@20261021 json updated to match
- evals: prompt_probes / prompt_compare / time_boundary probe scripts
  (supplementary checks, original cases untouched)
- docs: collection-prompt-optimization.md (method + baselines),
  time-boundary-fix.md (problem, design, verification)
- gitignore: editor artifact dirs (.agents/.claude/.vscode, skills-lock)

Verified: 171 unit tests pass (16 new time-context tests)
2026-10-22 09:41:32 +08:00
Eric Wang a890f41f6f chore(prompts): regenerate collection prompt from workflow@20261021-r2
- merge main (fb9271e): collection prompt restructured (state-bound-to-action,
  gatekeeper principle); fill_missing eval cases relaxed to semantic regexes
- prompts/collection.md regenerated; byte-identity test updated and passing
- rerun golden evals: collection_skip 11/12, time_confirmation 1/2
  (inter-run variance; only single_no_inferred_count fails consistently -
  model routes without asking vehicle count after time confirmation)
2026-10-21 17:28:44 +08:00
Eric Wang 894cb220ed Merge branch 'main' into langgraph-migration 2026-10-21 17:13:10 +08:00
Eric Wang 74db6be385 feat(agent): form pipeline + collection prompt workflow@20261021
- merge main: workflow/20261021 (collection prompt adds step-5 mandatory
  time readback-confirm before routing; non-motor/0003 branch rework;
  accident_cause unified schema), updated eval suites (photo_skip/
  button_guidance rewritten, no_false trimmed to asr, new
  non_motor_vehicle + time_confirmation with form/reply assertions),
  runner gains form/formMatches/replyMatches expectations
- prompts/collection.md regenerated from 20261021; extraction prompt
  archived (contentExtract description, 6-key whitelist)
- collect: extraction call per turn (extraction.md + current time/form
  injected), merge follows 更新表单 semantics (meaningful values only,
  number/string equality, diff -> turn_patch); accident_fields now uses
  external form keys
- backend: form_update flows to ChatResult and SSE formUpdate event
  (stream emits prefix, FormUpdate, body)
- fields: FORM_FIELDS whitelist with strict type validation
- verified: 155 unit tests; golden evals on real model - photo_skip 4/4,
  no_false 2/2, photo_button_guidance 12/12, non_motor_vehicle 14/14,
  collection_skip 10/12, time_confirmation 1/2; remaining 3 failures are
  model sequence/literal-template adherence, recorded in plan appendix
2026-10-21 17:10:33 +08:00
Eric Wang fb9271efc5 fix(workflow): bind collection states to actions and relax eval wording 2026-10-21 16:51:19 +08:00
Eric Wang 4ead44ef3f Merge branch 'main' into langgraph-migration 2026-10-21 15:42:04 +08:00
Eric Wang 248eb41c78 fix(workflow): align non-motor accident extraction and evaluations 2026-10-21 15:34:11 +08:00
Eric Wang 11cffa01c9 docs: record progress, decisions and open questions in migration plan
- plan: assignment status table, five landed architecture decisions
  (propose-validate, context_schema DI, verbatim alignment, no LangGraph
  Server/SDK with rationale, 2004 semantics), real-model eval results
  (collection 12/12; photo_skip 0/4 and no_false 2/8 share the '对'
  routing pattern), three open questions with next actions, code map
- 2004 task rewritten as plate-confirm with both paths whitelisted
- graduation requirement reworded: illegal transitions never committed
- README: current status section pointing to plan appendix
2026-10-21 15:11:19 +08:00
Eric Wang 6d0a2169c8 refactor(agent): inject deps via context_schema, LLM-driven photo/confirm nodes
- graph.py: LangGraph-native DI - StateGraph(context_schema=GraphDeps),
  nodes take (state, runtime: Runtime[GraphDeps]); build_graph() decoupled
  from LLM; deleted scaffold _event_reply/_fake_llm_propose/stub nodes
- photo.py: model proposes stage+body via per-mode prompts (direct/addon);
  validator enforces clientMode exits; deterministic event forcing removed
- confirm.py: single runtime for single/dual confirm, extraction call
  isolated per person_index
- llm.py: workflow_fake_llm() (offline workflow-faithful responder,
  history-aware) for smoke/tests
- backend: LangGraphBackend(graph, llm) passes context per call
- tests: invoke helpers inject GraphDeps; illegal-proposal test asserts
  error + state untouched via second well-behaved fake

Verified: 143 passed; smoke turns 1/2/1 with original welcome text
2026-10-21 15:11:16 +08:00
Eric Wang a5407e03b2 feat(agent): align prompts and runtime with workflow@20261020
- archive workflow/20261020 export (diff vs 20261016: collection prompt
  only - state-decides-body rule, route when info complete)
- prompts: collection.md updated; 6 photo/confirm prompts archived with
  source nodeIds; render_prompt replaces {{$vars}} (Asia/Shanghai clock,
  person fields, explicit 'not provided' for missing prefills)
- llm: message history passed as user/assistant roles (chatNode history=50);
  optional LLM_TEMPERATURE; FakeLLMService supports history-aware responders
- collect: context via system supplement, raw user input as user message
  (Text Editor#2 parity), shared validated_reply (one call, one repair)
- welcome: Assigned Reply#3 original text, stored in dialogue history
- transitions: 2004 plate-confirm entries (2003->2004/2005, 2004->2005)
- verified: prompt files byte-identical to workflow JSON (parametrized test)
2026-10-21 15:10:51 +08:00
Eric Wang 1c6b1a513d feat(agent): LLM-powered collection node with welcome stage and session-scoped delete (assignment 4)
- prompts/collection.md: versioned collection system prompt extracted
  from workflow node yQaBxfrWjbRr with source/version/porting notes
- llm.py: LLMService protocol; FakeLLMService (scripted, records
  calls); OpenAILLMService (async, wait_for timeout with cancellation,
  retry only on timeout/429/connection, errors normalized)
- collect.py: run_collect reference impl - one LLM call produces
  state prefix + body, controlled repair (max 1 retry) for missing
  prefix or illegal stage proposal, whitelist guard, CollectReplyError
  without raw model content; dialogue history + confirmed fields
  injected into prompt so the model skips known info (作业4-5)
- fields.py / clock.py: three-state field candidates (unknown/
  candidate/confirmed), per-type validation (count not inferred from
  description, future time rejected), injectable Clock
- graph.py: welcome node - first message returns fixed 1001 greeting
  without LLM (mirrors workflow is_first_message -> Assigned Reply#3),
  route empty stage to welcome
- endpoints/delete_session: backend switch - langgraph clears graph
  checkpoint, fastgpt path unchanged
- config: AGENT_LLM_PROVIDER fake|openai with validation
- untrack .env (secrets), move template to root .env.example

Verified:
- pytest 103 passed; smoke turns 1/2/1
- Real LLM e2e: POST /chat multi-turn context works
- Golden eval collection_skip_known_info: 12/12 cases pass
- Golden eval no_false: 8/10 cases pass; 4 confirm/photo cases fail
  at final step - model routes on short reply '对' (prompt-adherence
  gap, photo/confirm stages are assignment 5 scope); recorded in
  evals/results/20261020-144856

Known limits: field extraction from model reply not wired (stub);
photo/confirm nodes still scaffold; clarify counting is approximate.
2026-10-20 14:53:46 +08:00
Eric Wang 8323d53a70 feat(agent): domain events and transition whitelist validation (assignment 3)
Architecture (mirrors workflow/20261016 chatNode structure):
- events.py: client markers parsed to typed ClientEvent (sources
  verified against workflow JSON); plain text like '拍好了' is not an event
- transitions.py: LEGAL_TRANSITIONS whitelist drafted from chatNode
  prompts and Condition edges (16 entries, each with source_ref);
  is_legal_transition rejects unlisted/terminal-violating moves
- graph.py: multi-node graph (collect/single_photo/dual_photo/...
  matching workflow chatNodes), route_by_stage conditional edges,
  _fake_llm_propose simulates LLM stage-code proposals (assignment 4
  replaces with real LLM); code only keeps context bookkeeping
  (no_reply_count) and validation
- state.py: expanded domain fields (pending_question, accident/
  person fields, clarify/no-reply counts, turn_patch, state_version)

Key finding: 单车拍照#6/双车拍照#7 are browser_addon branches ending
at 0000, so 2005/2015 allow both 300x (direct) and 0000.

Verified: pytest 87 passed (24 transition/event tests newly green).
Known limit: stage proposals come from a fake LLM; per-stage scripts
and real LLM integration are assignments 4-5.
2026-10-19 16:25:04 +08:00
Eric Wang 5d68b731d4 feat(backends): wire LangGraph backend behind AGENT_BACKEND switch (assignment 2)
- src/backends/langgraph.py: LangGraphBackend implements ChatBackend;
  complete() runs one graph turn per session (thread_id=sessionId) and
  returns state-prefixed content; stream() emits the full state prefix
  before body fragments (full-answer slicing, not yet real incremental
  output - assignment 8)
- src/core/config.py: AGENT_BACKEND=fastgpt|langgraph, langgraph mode
  no longer requires FastGPT credentials at startup
- src/core/fastgpt_client.py: lifespan builds the backend by switch
- test/backends/test_langgraph_backend.py: adapter acceptance tests

Verified:
- pytest: 48 passed
- AGENT_BACKEND=langgraph uvicorn: POST /chat -> 1002;
  browser_addon -> browser_addon.1002; SSE = stage_code, text_delta,
  single done

Known limit: stream slices a complete answer; no formUpdate deltas yet
(assignment 6).
2026-10-19 14:29:31 +08:00
Eric Wang 5020903791 feat(agent): add LangGraph scaffold for assignment 1
- src/agent/state.py: minimal five-field AgentState
- src/agent/graph.py: START -> normalize_input -> reply -> END,
  compiled with InMemorySaver; reply emits <state>1002</state> prefix
- examples/langgraph_smoke.py: offline smoke, turns 1/2/1 verified
- test/agent/test_scaffold.py: turn accumulation, thread isolation,
  fixed-template assertions (3 passed)
- requirements.txt: pin langgraph==1.2.9

Known limit: InMemorySaver state disappears on process exit.
2026-10-19 13:32:43 +08:00
Eric Wang a9a1393f64 test: align backend boundary and schema contract tests with current behavior 2026-10-19 13:32:34 +08:00
Eric Wang a6ce570499 docs: add project README, env guide and assignment baseline notes 2026-10-19 13:32:31 +08:00
Eric Wang 3fe99e71fd remove root dir .env 2026-10-16 17:02:02 +08:00
Eric Wang dea2ea5b71 feat(workflow): add new workflow for accident information collection
- Introduced a comprehensive JSON configuration for a new workflow that includes user guidance, input handling, and AI chat integration.
- The workflow features nodes for system configuration, workflow start, and accident information collection, enhancing user interaction and data collection capabilities.
- Implemented various input types and configurations to support dynamic user interactions and improve overall workflow efficiency.
2026-10-16 17:01:47 +08:00
Eric Wang 81b2335d9e docs: rewrite LangGraph migration plan as staged assignments 2026-10-16 16:15:18 +08:00
Eric Wang 89cc965b5a Merge remote-tracking branch 'gitea/main' into langgraph-migration 2026-10-16 16:02:35 +08:00
Eric Wang 6b8a548df3 fix(workflow): offer photo button guidance only when needed 2026-10-16 15:58:41 +08:00
Eric Wang 5f60093eee Merge branch 'main' into langgraph-migration 2026-10-16 15:51:29 +08:00
Eric Wang 22853f1b5a fix(workflow): skip known accident details and guide off-topic replies 2026-10-16 15:16:16 +08:00
Eric Wang 4787d6eb79 fix(workflow): skip plate confirmation after photos and guide driver verification 2026-10-16 14:21:45 +08:00
Eric Wang ee7bff32dd feat(workflow): add October 16 accident information collection workflow 2026-10-16 11:33:04 +08:00
Eric Wang f179d9ffb0 fix(prompt): 新增状态码语义权威规则与不在现场分支
- 1002 状态下正文严禁出现转人工表述,以状态码为准
- 补全步骤6'不在现场'分支:记录后保持1002继续收集
- 最终输出自检增加状态码-正文一致性检查
2026-10-14 18:05:54 +08:00
Eric Wang e26e724a53 Add new prompt file for traffic accident reporting AI
- Introduced a comprehensive prompt file detailing the role and operational guidelines for a traffic accident reporting AI.
- Established strict output formatting rules to ensure clarity in user interactions, including state management and response protocols.
- Emphasized safety prioritization and robust handling of user inputs, particularly regarding the assessment of potential injuries and the transition to human assistance.
2026-10-12 10:42:28 +08:00
Eric Wang 34d09f53bb Merge branch 'main' of http://182.92.86.220:8300/wx44wx/ZNJJ-api-server
# Conflicts:
#	docs/视频快处智能信息采集机器人交互接口文档V1.0.10.docx
#	src/api/endpoints.py
#	src/core/fastgpt_client.py
2026-10-11 21:39:49 +08:00
Xin Wang e261e97916 Update form extraction logic in endpoints.py
- Changed the module name for form extraction to "更新表单" for clarity.
- Enhanced the extraction process to accommodate various output formats from nodes, ensuring compatibility with different structures.
- Improved handling of empty or invalid form updates, returning an empty object when necessary to maintain robustness.
2026-08-11 14:58:47 +08:00
Xin Wang bfc91b6f66 Remove outdated document for version 1.0.10 of accident reporting AI, streamlining the repository and eliminating unnecessary files. 2026-07-30 14:20:21 +08:00
Xin Wang f40643dd87 Refine prompts and evaluation cases for accident reporting AI
- Updated prompts to enhance clarity and consistency in user interactions, particularly focusing on safety prioritization and accurate information collection.
- Introduced new YAML evaluation cases to test various user input scenarios, ensuring robust handling of short, ambiguous, or irrelevant responses.
- Enhanced guidelines for transitioning to human assistance, emphasizing strict conditions for triggering state changes based on user responses.
2026-07-30 14:19:57 +08:00
Xin Wang be35e48686 Add user interaction guidelines for online confirmation in accident reporting prompts
- Introduced new section for user inputs that confirm system availability, detailing specific phrases that indicate active engagement.
- Clarified response protocol for such inputs, ensuring the system maintains its current state and provides brief confirmations.
- Enhanced overall user experience by addressing common interaction scenarios in the accident reporting process.
2026-07-29 12:43:03 +08:00
Xin Wang 4e621e2f0c Enhance evaluation runner with transcript handling and new case formats
- Updated the evaluation runner to support live dialogue printing and transcript saving in both Markdown and JSON formats.
- Introduced new data classes for managing transcripts and their components, improving structure and readability.
- Modified existing YAML case files to align with the new direct client mode and updated stage codes.
- Added new test cases for the direct client mode, ensuring comprehensive coverage of user interactions.
2026-07-29 11:13:07 +08:00
Xin Wang 3187713bfe Enhance client mode handling in ProcessRequest_chat
- Introduced a normalization function for client mode to default to "direct" when input is empty or None.
- Updated the clientMode field to use a new type with BeforeValidator for improved validation.
- Added a test to ensure empty client mode inputs correctly default to "direct".
2026-07-29 10:02:35 +08:00
Xin Wang 473fffd2f0 Add new prompts for traffic accident reporting AI
- Introduced two new prompt files for traffic accident reporting, detailing the interaction protocol and state management for both single and dual vehicle scenarios.
- Established strict output formatting rules to ensure clarity and consistency in user interactions, including handling of user responses.
- Enhanced guidelines for safety prioritization and accurate information collection during the accident reporting process.
2026-07-28 17:34:22 +08:00
Xin Wang 08e290bcdf Update prompts for vehicle accident reporting
- Revised state codes to enhance clarity in user interactions, replacing previous codes with new ones indicating successful verification and transition to human assistance.
- Adjusted output messages to reflect the updated state management, ensuring a smoother user experience during the information confirmation phase.
- Improved guidelines for handling user responses, emphasizing accurate information collection and efficient transition to human support.
2026-07-28 15:41:21 +08:00
Xin Wang f99c171418 Add new prompts for dual vehicle accident scene guidance
- Introduced a detailed prompt file for dual vehicle accident photo capture and verification, outlining the interaction protocol and state management.
- Established strict output formatting rules to ensure clarity and consistency in user interactions.
- Included comprehensive guidelines for handling various user responses, prioritizing accurate information collection during dual vehicle accident reporting.
2026-07-28 15:19:23 +08:00
Xin Wang 5501913779 Add new prompt for traffic accident reporting AI
- Introduced a detailed prompt file for a traffic accident reporting AI, outlining the interaction protocol and state management.
- Established strict output formatting rules to ensure clarity and consistency in user interactions.
- Included comprehensive guidelines for handling various user responses, prioritizing safety and accurate information collection during accident reporting.
2026-07-28 15:18:53 +08:00
Xin Wang 7ed45089ec Add new prompt for traffic accident reporting AI
- Introduced a comprehensive prompt file for a traffic accident reporting AI, detailing the interaction protocol and state management.
- Established strict output formatting rules to ensure clarity and consistency in user interactions.
- Included guidelines for handling various user responses, emphasizing safety and accurate information collection during accident reporting.
2026-07-28 15:08:18 +08:00
Xin Wang 776f6e82b3 Add new documentation for version 1.0.10
- Introduced a comprehensive document detailing the interaction interface design for the intelligent information collection robot.
- Updated version history with new features, including the addition of the clientMode parameter and its impact on output formatting.
- Enhanced clarity in the API request and response structures, including examples for better understanding of the interaction flow.
2026-07-28 11:10:50 +08:00
Eric Wang 5c719ed2ea Refactor chat backend integration and introduce new backend-neutral architecture
- Replaced direct FastGPT client usage with a backend-neutral chat interface, allowing for improved flexibility and maintainability.
- Introduced a new `ChatBackend` protocol and implemented `FastGPTBackend` to handle chat operations.
- Updated the chat endpoint to utilize the new backend structure, enhancing the handling of chat requests and responses.
- Added comprehensive tests to ensure compatibility and functionality of the new backend integration.
2026-07-26 07:25:24 +08:00
Eric Wang 893eb2f2f7 Update environment variables and add LangGraph backend migration plan
- Updated ANALYSIS_AUTH_TOKEN and APP_ID in the .env file for enhanced security and configuration.
- Added a comprehensive migration plan document for transitioning the LangGraph backend, detailing the background, scope, goals, and architectural decisions for the project.
2026-07-26 07:24:30 +08:00
Eric Wang 88ba48ac77 Update docs 2026-07-24 17:33:34 +08:00
Eric Wang ce97a16f5b Add new prompts for accident scene photo guidance
- Introduced new files for single and dual vehicle accident photo guidance, detailing step-by-step instructions and state management protocols.
- Implemented strict output formatting and error handling for user interactions during the photo capture process.
- Enhanced the overall structure to ensure clarity and consistency in guiding users through the accident documentation process.
2026-07-24 08:17:14 +08:00
Eric Wang 6f91f45065 Add new state code for photo recognition failure in chat stream mode
- Updated documentation and API endpoint to include a new state code '0005' for handling cases where photo recognition fails consecutively, directing to human assistance.
- Ensured consistency between documentation and code for improved clarity in state management.
2026-07-23 23:34:13 +08:00
Xin Wang 3836b443b1 Update structured form update content in documentation for version 1.0.8
- Revised the formUpdate section to clarify the conditions under which structured updates are pushed.
- Added specific examples for accident vehicle count and cause of the incident to enhance understanding.
- Adjusted text_delta examples for improved clarity in response handling.
2026-06-18 11:07:20 +08:00
Xin Wang aa2768acc0 Update API request structure in fastapi.http
- Replaced hardcoded URLs with a base URL variable for better configurability.
- Updated request payloads to use sessionId and timeStamp variables.
- Enhanced the chat request with new parameters: needFormUpdate and useTextChunk.
- Adjusted response content types and lengths for consistency.
- Updated timestamps in response headers for accuracy.
2026-06-18 10:45:33 +08:00
Xin Wang 83353c54d1 Remove outdated document for version 1.0.8 and replace it with an updated version containing comprehensive interface design details and enhancements. The new document includes additional parameters and examples for improved clarity on the chat interface and structured information handling. 2026-06-18 10:27:52 +08:00
Xin Wang edf85e21cc Update base URL in API configuration for deployment 2026-06-17 12:36:46 +08:00
Xin Wang 1ea1d86d5a Update continue greeting 2026-06-03 12:52:38 +08:00
Xin Wang 30c413b6d4 Refactor voice websocket documentation to clarify input handling and remove deprecated sections. Updated the demo process to indicate that image uploads are no longer required, streamlining user interaction with the voice service. 2026-06-01 11:24:31 +08:00
Xin Wang 0ef5de399a Add voice ws docs 2026-06-01 11:18:41 +08:00
Xin Wang 6df6c16e1d Implement UserStartedSpeakingFrame handling in voice pipeline
- Added support for UserStartedSpeakingFrame to enhance user interaction tracking.
- Updated the pipeline to reset idle prompt count when a user starts speaking, improving responsiveness during conversations.
- Integrated new event handlers for better management of user turn events and upstream frame processing.
2026-05-29 16:51:51 +08:00
Xin Wang 13f5f44f61 Enhance voice configuration with idle prompt features and new TTS settings
- Added idle prompt timeout, maximum count, and text to multiple voice configuration files to improve user interaction during idle periods.
- Updated greeting mode to 'fastgpt_opener' in relevant configurations for a more dynamic greeting experience.
- Introduced a new voice configuration file for xfyun TTS, including detailed service settings and parameters.
- Refactored the pipeline to handle idle prompts and user turn events, ensuring smoother interaction flow.
- Adjusted the VAD and turn configurations to accommodate new idle prompt features.
2026-05-29 16:27:05 +08:00
Xin Wang f49212afc9 Add camera functionality to voice demo with UI updates and state management
- Introduced a camera drawer for capturing images during the conversation flow.
- Added prompts for various camera states to guide users through the photo capture process.
- Updated HTML structure to include camera-related elements and integrated them with existing chat functionality.
- Enhanced JavaScript logic to manage camera state and button enabling/disabling based on connection status.
- Updated CSS for styling the camera drawer and its components, ensuring responsive design across devices.
- Adjusted README to reflect the new demo URL for voice functionality.
2026-05-28 15:13:54 +08:00
Xin Wang ed9621dfe0 Update VOICE_CONFIG to use new FastGPT state-enabled configuration and add TEXT_DELTA log group for websocket responses. 2026-05-28 13:46:33 +08:00
Xin WangandCursor 9e2374f492 Add voice state tags, SuperTTS configs, and demo WS log groups.
Parse leading <state> tags from LLM replies and emit response.state over the product websocket while stripping tags from TTS/text streams. Add FastGPT+Xfyun voice configs (including state-enabled preset), SuperTTS support, and context sync for interrupted turns. Refresh the voice demo with a state indicator and collapsible audio delta websocket log groups.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 11:32:20 +08:00
Xin Wang b14ef64665 Add configuration files for FastGPT and Xfyun voice services, enhancing LLM service capabilities. Update LLMConfig to include chat_id, variables, detail, and timeout settings. Refactor create_llm_service to support FastGPT integration and adjust pipeline to handle chat_id and greeting prompts. Implement context synchronization for interrupted assistant turns in text streaming. 2026-05-26 10:56:38 +08:00
Xin Wang e4e47f637e Refactor pipeline to correctly include assistant_aggregator in the run_pipeline_with_serializer function. 2026-05-23 00:19:34 +08:00
Xin Wang c7f2f4e5f3 update default env 2026-05-22 16:41:24 +08:00
Xin WangandCursor a10f0a586b Add VOICE_CONFIG env var to select the voice pipeline config file.
Defaults to config/voice.json; relative paths resolve from project root.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 16:29:27 +08:00
Xin WangandCursor bc2aa5b133 Integrate product-ws voice demo on port 8000 alongside REST API.
Add src/voice Pipecat pipeline, browser demo at /voice-demo, and config/voice.json.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 16:26:06 +08:00
Xin WangandCursor 0b6b40aba4 Add set_info logging for key/value updates
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 14:29:42 +08:00
Xin Wang 87e616ab55 提示词添加车辆预先提取和手机号多次拼接输入 2026-02-03 17:33:45 +08:00
Xin Wang 34848dd6a0 add nostream chat example 2026-02-02 18:16:51 +08:00
Xin Wang 30306addee Add stream text output 2026-02-02 17:54:55 +08:00
Xin Wang 32c491cd3f fix delete chat bug and update fastapi http file 2026-01-08 17:32:06 +08:00
Xin Wang d5f81ef79f use fastgpt python sdk 2026-01-08 16:22:25 +08:00
Xin Wang c6869f773e Add document 2025-06-20 13:57:51 +08:00
Xin Wang fe4a3b52fd Add more fastapi test 2025-06-20 13:57:30 +08:00
Xin Wang a09a035f0e Add http notebook for manual test 2025-06-20 11:08:18 +08:00
Xin Wang 2a490edff5 Add env and entrypoint 2025-06-20 10:03:39 +08:00
Xin Wang a1a4bceb9a Add api server code and workflow 2025-04-29 15:03:02 +08:00