Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
69
backend/vtm/orchestrator/orchestrator.go
Normal file
69
backend/vtm/orchestrator/orchestrator.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Orchestrator orchestrates VTM workflows
|
||||
type Orchestrator struct {
|
||||
workflows map[string]Workflow
|
||||
}
|
||||
|
||||
// NewOrchestrator creates a new orchestrator
|
||||
func NewOrchestrator() *Orchestrator {
|
||||
return &Orchestrator{
|
||||
workflows: make(map[string]Workflow),
|
||||
}
|
||||
}
|
||||
|
||||
// Workflow interface for VTM workflows
|
||||
type Workflow interface {
|
||||
Execute(ctx context.Context, input map[string]interface{}) (*WorkflowResult, error)
|
||||
Name() string
|
||||
}
|
||||
|
||||
// WorkflowResult represents workflow execution result
|
||||
type WorkflowResult struct {
|
||||
Status string
|
||||
NextStep string
|
||||
Data map[string]interface{}
|
||||
RequiresInput bool
|
||||
}
|
||||
|
||||
// RegisterWorkflow registers a workflow
|
||||
func (o *Orchestrator) RegisterWorkflow(workflow Workflow) {
|
||||
o.workflows[workflow.Name()] = workflow
|
||||
}
|
||||
|
||||
// ExecuteWorkflow executes a workflow
|
||||
func (o *Orchestrator) ExecuteWorkflow(ctx context.Context, workflowName string, input map[string]interface{}) (*WorkflowResult, error) {
|
||||
workflow, ok := o.workflows[workflowName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("workflow not found: %s", workflowName)
|
||||
}
|
||||
|
||||
return workflow.Execute(ctx, input)
|
||||
}
|
||||
|
||||
// AccountOpeningWorkflow implements Workflow for account opening
|
||||
type AccountOpeningWorkflow struct{}
|
||||
|
||||
func NewAccountOpeningWorkflow() *AccountOpeningWorkflow {
|
||||
return &AccountOpeningWorkflow{}
|
||||
}
|
||||
|
||||
func (w *AccountOpeningWorkflow) Name() string {
|
||||
return "account_opening"
|
||||
}
|
||||
|
||||
func (w *AccountOpeningWorkflow) Execute(ctx context.Context, input map[string]interface{}) (*WorkflowResult, error) {
|
||||
// Implementation would handle account opening workflow
|
||||
return &WorkflowResult{
|
||||
Status: "in_progress",
|
||||
NextStep: "kyc_verification",
|
||||
Data: make(map[string]interface{}),
|
||||
RequiresInput: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
99
backend/vtm/state/state.go
Normal file
99
backend/vtm/state/state.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// StateManager manages conversation state
|
||||
type StateManager struct {
|
||||
db *pgxpool.Pool
|
||||
}
|
||||
|
||||
// NewStateManager creates a new state manager
|
||||
func NewStateManager(db *pgxpool.Pool) *StateManager {
|
||||
return &StateManager{db: db}
|
||||
}
|
||||
|
||||
// ConversationState represents conversation state
|
||||
type ConversationState struct {
|
||||
SessionID string
|
||||
UserID string
|
||||
Workflow string
|
||||
Step string
|
||||
Context map[string]interface{}
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
// SaveState saves conversation state
|
||||
func (s *StateManager) SaveState(ctx context.Context, state *ConversationState) error {
|
||||
contextJSON, err := json.Marshal(state.Context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal context: %w", err)
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO conversation_states (
|
||||
session_id, user_id, workflow, step, context, created_at, updated_at, expires_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
ON CONFLICT (session_id) DO UPDATE SET
|
||||
workflow = $3,
|
||||
step = $4,
|
||||
context = $5,
|
||||
updated_at = $7,
|
||||
expires_at = $8
|
||||
`
|
||||
|
||||
_, err = s.db.Exec(ctx, query,
|
||||
state.SessionID,
|
||||
state.UserID,
|
||||
state.Workflow,
|
||||
state.Step,
|
||||
contextJSON,
|
||||
state.CreatedAt,
|
||||
time.Now(),
|
||||
state.ExpiresAt,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetState gets conversation state
|
||||
func (s *StateManager) GetState(ctx context.Context, sessionID string) (*ConversationState, error) {
|
||||
query := `
|
||||
SELECT session_id, user_id, workflow, step, context, created_at, updated_at, expires_at
|
||||
FROM conversation_states
|
||||
WHERE session_id = $1
|
||||
`
|
||||
|
||||
var state ConversationState
|
||||
var contextJSON []byte
|
||||
|
||||
err := s.db.QueryRow(ctx, query, sessionID).Scan(
|
||||
&state.SessionID,
|
||||
&state.UserID,
|
||||
&state.Workflow,
|
||||
&state.Step,
|
||||
&contextJSON,
|
||||
&state.CreatedAt,
|
||||
&state.UpdatedAt,
|
||||
&state.ExpiresAt,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get state: %w", err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(contextJSON, &state.Context); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal context: %w", err)
|
||||
}
|
||||
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user