sync: migrate ai-operator to Gitea (2026-08-10)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package handoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
Config Config
|
||||
Store *Store
|
||||
Executor Executor
|
||||
}
|
||||
|
||||
type RequestInput struct {
|
||||
CallID string
|
||||
AsteriskChannelID string
|
||||
State string
|
||||
Language string
|
||||
RegionCode string
|
||||
Route string
|
||||
ReasonCode HandoffReasonCode
|
||||
ReasonText string
|
||||
Summary string
|
||||
Metadata map[string]string
|
||||
}
|
||||
|
||||
func NewManager(cfg Config, executor Executor) *Manager {
|
||||
if cfg.Mode == "" {
|
||||
cfg = DefaultConfig()
|
||||
}
|
||||
if executor == nil {
|
||||
executor = SafeExecutor{}
|
||||
}
|
||||
return &Manager{Config: cfg, Store: NewStore(), Executor: executor}
|
||||
}
|
||||
|
||||
func (m *Manager) Request(ctx context.Context, in RequestInput) (HandoffRequest, HandoffResult, error) {
|
||||
if existing, ok := m.Store.GetByCall(in.CallID); ok {
|
||||
result := HandoffResult{RequestID: existing.ID, Status: existing.Status, Mode: existing.Mode, MessageKey: "handoff.already_requested", Message: Message("handoff.already_requested", in.Language)}
|
||||
return existing, result, nil
|
||||
}
|
||||
mode := m.Config.Mode
|
||||
hasTarget := mode == HandoffModeHangupAfterMessage || mode == HandoffModeDisabledStub ||
|
||||
(mode == HandoffModeARIRedirect && m.Config.TargetEndpoint != "") ||
|
||||
(mode == HandoffModeDialplanContinue && m.Config.DialplanContext != "" && m.Config.DialplanExtension != "")
|
||||
decision := Authorize(PolicyContext{State: in.State, Route: in.Route, HandoffEnabled: m.Config.Enabled, HandoffMode: mode, AllowInTestRouteOnly: m.Config.AllowInTestRouteOnly, HasTarget: hasTarget})
|
||||
now := time.Now().UTC()
|
||||
req := HandoffRequest{
|
||||
ID: fmt.Sprintf("handoff-%d", now.UnixNano()),
|
||||
CallID: in.CallID,
|
||||
AsteriskChannelID: in.AsteriskChannelID,
|
||||
Mode: mode,
|
||||
Status: HandoffStatusRequested,
|
||||
ReasonCode: in.ReasonCode,
|
||||
ReasonText: SanitizeText(in.ReasonText, m.Config.MaxSummaryChars),
|
||||
Summary: SanitizeText(in.Summary, m.Config.MaxSummaryChars),
|
||||
Language: in.Language,
|
||||
RegionCode: in.RegionCode,
|
||||
Route: in.Route,
|
||||
TargetEndpoint: m.Config.TargetEndpoint,
|
||||
DialplanContext: m.Config.DialplanContext,
|
||||
DialplanExtension: m.Config.DialplanExtension,
|
||||
DialplanPriority: m.Config.DialplanPriority,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Metadata: in.Metadata,
|
||||
}
|
||||
if !decision.Allowed {
|
||||
req.Status = HandoffStatusFailed
|
||||
result := HandoffResult{RequestID: req.ID, Status: req.Status, Mode: req.Mode, MessageKey: decision.MessageKey, Message: Message(decision.MessageKey, in.Language), Error: decision.ReasonCode}
|
||||
m.Store.Put(req)
|
||||
return req, result, fmt.Errorf(decision.ReasonCode)
|
||||
}
|
||||
if decision.StubOnly {
|
||||
req.Mode = HandoffModeDisabledStub
|
||||
req.Status = HandoffStatusStubbed
|
||||
result := HandoffResult{RequestID: req.ID, Status: req.Status, Mode: req.Mode, MessageKey: decision.MessageKey, Message: Message(decision.MessageKey, in.Language)}
|
||||
m.Store.Put(req)
|
||||
return req, result, nil
|
||||
}
|
||||
result, err := m.Executor.Execute(ctx, req)
|
||||
req.Status = result.Status
|
||||
req.Error = result.Error
|
||||
completed := time.Now().UTC()
|
||||
if result.Status == HandoffStatusCompleted || result.Status == HandoffStatusFailed || result.Status == HandoffStatusStubbed {
|
||||
req.CompletedAt = &completed
|
||||
}
|
||||
req.UpdatedAt = completed
|
||||
m.Store.Put(req)
|
||||
return req, result, err
|
||||
}
|
||||
Reference in New Issue
Block a user