Skip to content

feat(forms): add unified form submission system - #1

Closed
qdaxb wants to merge 5 commits into
mainfrom
wegent/unified-form-submission-system
Closed

qdaxb wants to merge 5 commits into
mainfrom
wegent/unified-form-submission-system

Conversation

@qdaxb

@qdaxb qdaxb commented Jan 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add unified form submission system with pluggable handler architecture
  • Implement backend REST API endpoint POST /api/forms/submit for all form types
  • Create database model form_submissions for submission tracking and auditing
  • Add WebSocket events for real-time form status updates
  • Implement handlers for clarification, final_prompt, and pipeline_confirmation
  • Create reusable GenericForm component with dynamic field rendering
  • Support multiple field types: single_choice, multiple_choice, text_input, datetime_picker, number_input
  • Add frontend hook useFormSubmission for submission state management
  • Include comprehensive unit tests for backend handlers and frontend components

Architecture

Backend:
- POST /api/forms/submit -> FormSubmissionService -> Handler Registry -> Specific Handler
- WebSocket events: form:submitted, form:processing, form:completed, form:error

Frontend:
- GenericForm -> FormFieldRenderer -> Field Components (SingleChoice, MultipleChoice, etc.)
- useFormSubmission hook for state management and WebSocket integration

New Files

Backend:

  • backend/app/services/forms/ - Forms service module with registry pattern
  • backend/app/api/endpoints/adapter/forms.py - REST API endpoint
  • backend/app/models/form_submission.py - Database model
  • backend/app/schemas/form.py - Pydantic schemas
  • backend/alembic/versions/q7r8s9t0u1v2_add_form_submissions_table.py - Migration

Frontend:

  • frontend/src/features/tasks/components/forms/ - Form components
  • frontend/src/apis/forms.ts - API client
  • frontend/src/types/form.ts - TypeScript types

Test plan

  • Backend unit tests pass for form handlers and registry
  • Frontend component tests pass for GenericForm
  • Manual test: Submit clarification form via new API
  • Manual test: Submit pipeline confirmation via new API
  • Verify WebSocket events are emitted correctly
  • Verify form submissions are persisted in database

qdaxb and others added 5 commits January 11, 2026 01:01
Implement a pluggable form submission architecture that provides:
- Backend forms service module with registry pattern for handler registration
- REST API endpoint POST /api/forms/submit for unified form submissions
- Database model form_submissions for tracking submissions
- WebSocket events for form status updates (submitted, processing, completed, error)
- Handlers for clarification, final_prompt, and pipeline_confirmation
- Frontend GenericForm component with dynamic field rendering
- Form field components: SingleChoice, MultipleChoice, TextInput, DateTimePicker, NumberInput
- useFormSubmission hook for submission state management
- TypeScript types and API client for form operations
- Unit tests for backend handlers and registry
- Component tests for GenericForm

This architecture supports future extension for slot filling and custom form scenarios.
Change db_session to test_db to match conftest.py fixture definition

Co-Authored-By: Claude <noreply@anthropic.com>
Remove unused useMemo import that was causing ESLint error

Co-Authored-By: Claude <noreply@anthropic.com>
Fix import path from @/features/tasks/contexts/socketContext to @/contexts/SocketContext

Co-Authored-By: Claude <noreply@anthropic.com>
SocketContext is not exported, use the exported useSocket hook instead

Co-Authored-By: Claude <noreply@anthropic.com>
kissghosts referenced this pull request in kissghosts/Wegent Mar 4, 2026
…el position

1. Fix "+" button not working when left sidebar is collapsed on Knowledge Base Classic page:
   - Add useTaskContext and useChatStreamContext imports
   - Implement proper handleNewTask function that clears selected task,
     clears streams, and navigates to knowledge base chat page
   - Replace empty onNewTask handler with the new function

2. Reposition collapsed document panel button to be symmetrical with left sidebar:
   - Change position from vertical center (top-1/2) to top (top-2 sm:top-3)
   - Change button style from tall vertical button to horizontal pill-style
   - Add "+" button when onNewChat is provided for consistency
   - Remove unused BookOpen import

Fixes #1, #2
@feifei325 feifei325 closed this in db2d7f2 Mar 6, 2026
qdaxb pushed a commit that referenced this pull request Jun 10, 2026
* feat(chat): add context status metrics and toolbar indicator

* feat(chat): finalize Phase 1 chat status toolbar and reconnect recovery

- Replace QuotaUsage with ChatToolbarStatus driven by chat:status_updated
- Wire useChatStatusIndicator to derive a fallback snapshot from the
  latest persisted AI message so toolbar status survives cold reloads
  before any live socket event arrives
- Type UnifiedMessage.result.context_metrics so persisted snapshots
  flow through the state machine without runtime casts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(chat_shell): add TruncationPolicy and GuardSource Protocol (T1)

Introduce the shared types module for Phase 2 context governance:
- TruncationPolicy: frozen dataclass with kind (bytes/tokens) and limit
- GuardSource: runtime_checkable Protocol for guard source adapters
- DEFAULT_EMERGENCY_RATIO = 0.3 and default_emergency_policy helper

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(chat_shell): add ToolOutputGuardAdapter and compact tool string format (T2)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(chat_shell): tighten compact footer detection and dedupe encoding (T2 review)

* feat(chat_shell): add UnifiedContextGuard with source + compression pipeline (T3)

Phase 2 unified context guard. Runs as LangGraph pre_model_hook before every
model call (pre-turn and mid-turn alike) and applies:

1. Source-level pass: convert raw tool messages to compact form via the
   registered GuardSource adapters; mark `compacted=true` so subsequent
   passes treat them as already-handled.
2. Request-level compression: when live state exceeds the model trigger
   limit, run MessageCompressor and translate its diff into LangGraph
   state updates (RemoveMessage for dropped ids, fresh BaseMessage for
   synthesized summaries; compacted=true marker propagates).
3. Emergency re-truncation: stub for T7; logs a warning when compression
   alone is insufficient.

Skips messages without a stable id since add_messages cannot upsert them
without doubling content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(chat_shell): wire UnifiedContextGuard as pre_model_hook (T4)

Phase 2 wiring task:

- chat_service constructs UnifiedContextGuard with ToolOutputGuardAdapter
  as the only source. The guard is chained AFTER guidance_consumer's hook
  via chain_pre_model_hooks so guidance injection observes already-budgeted
  state and writes its llm_input_messages on top of the compacted view.
- agent.build_messages no longer invokes MessageCompressor — budget
  enforcement now lives entirely in the pre_model_hook, which fires on
  pre-turn AND every mid-turn follow-up. Cache-breakpoint application
  remains in build_messages on the assembled layout.
- Drops the now-unused MessageCompressor import from agent.py.
- Adds guard/composition.py with chain_pre_model_hooks, supporting mixed
  sync/async hooks; messages updates concatenate, llm_input_messages from
  the last hook wins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(chat_shell): finalize Phase 2 context governance (T7+T8+T9 + review)

Completes Phase 2 by adding emergency re-truncation, removing legacy
serialization-time truncation, refactoring the metrics tracker to
emit-only, and addressing the review findings on the resulting code.

T7 — Emergency re-truncation
- UnifiedContextGuard stage 3 now re-renders source-owned messages
  under each source's emergency policy, biggest-first with early stop
  once usage drops below trigger.
- ToolOutputGuardAdapter accepts an emergency_ratio (defaults to
  DEFAULT_EMERGENCY_RATIO); chat_service passes settings.EMERGENCY_TOOL_OUTPUT_RATIO.
- Synthesized messages from stage 2 are excluded from the candidate set
  so the upsert-by-id contract holds.

T8 — Delete legacy _truncate_tool_result_for_storage
- graph_builder._serialize_messages_chain no longer chops tool results
  at serialization time; budget enforcement is owned by the guard.
- Removed MAX_TOOL_RESULT_LENGTH from config and its tests.

T9 — Tracker → emit-only wrapper
- ContextMetricsTracker no longer keeps its own messages duplicate.
  Single API: capture(messages, phase). Snapshot computation is
  delegated to an injected metrics_fn so accounting flows from one
  source.
- chat_service captures BUILD_MESSAGES at turn start and FINAL at end
  with messages + agent_builder._last_messages_chain.
- tools/events drops the per-tool tracker calls.

Review fixes
- #1: extract_raw now parses already-compact strings via the new
  _split_compact helper, so stage 3 emergency re-render no longer
  produces nested headers / fabricated total_tokens counts.
- #2: UnifiedContextGuard.__call__ is async and emits a metrics
  snapshot via the injected tracker on every invocation. Phase is
  PHASE_AFTER_COMPACTION when compaction happened, PHASE_AFTER_TOOL_END
  otherwise; bucket-throttling in should_emit_status_update suppresses
  redundant emits. Tests converted to async.
- #3: ToolResultTruncationStrategy now skips messages flagged
  additional_kwargs.compacted=True. Without this, stage 2 compression
  would corrupt the guard's fixed-format compact strings, leaving a
  misleading total_tokens count and mixing two truncation notices.
- #5: Documented the source-disjointness assumption in
  _apply_source_pass — registered GuardSources must have non-overlapping
  applies_to predicates.
- #6: calculate_context_metrics accepts pre-built TokenCounter and
  ModelContextConfig; guard.metrics() reuses its instance state
  instead of constructing fresh ones on every snapshot.
- #8: Kept default_emergency_policy as a documented public reference
  helper for future GuardSource impls.
- #9: _dict_to_base_message forwards d.get('id') so the compressor's
  synthesized ids survive the round-trip.
- #10: New test verifies cache_control markers in additional_kwargs
  survive guard compaction (Anthropic prompt-cache compatibility).

Tests
- 14 new tests across guard composition, tracker emit, compact-string
  roundtrip, id propagation, cache-breakpoint preservation, and
  compressor skip behavior. Total chat_shell suite: 549 passing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(chat-shell): finalize phase2 context guard

* fix(chat-shell): tune tool guard controls and diagnostics

* feat(knowledge): add listing pagination and guard fixes

* fix(frontend): improve chat toolbar status sections

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qdaxb
qdaxb deleted the wegent/unified-form-submission-system branch September 18, 2026 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant