feat(agent): connect agents to real BOC data
- Add AgentDataProvider with real DB queries for finance, CRM, sales, HR - Inject live data into Anthropic prompts for context-aware responses - Reuse existing ledgerDB connection for agent data access - Agents now respond with actual numbers from the system
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -36,10 +37,11 @@ type AgentChatResponse struct {
|
|||||||
type AgentOrchestrator struct {
|
type AgentOrchestrator struct {
|
||||||
anthropicKey string
|
anthropicKey string
|
||||||
apiEndpoint string
|
apiEndpoint string
|
||||||
|
dataProvider *AgentDataProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAgentOrchestrator creates a new agent orchestrator
|
// NewAgentOrchestrator creates a new agent orchestrator
|
||||||
func NewAgentOrchestrator() *AgentOrchestrator {
|
func NewAgentOrchestrator(db, ledgerDB *sql.DB) *AgentOrchestrator {
|
||||||
key := os.Getenv("ANTHROPIC_API_KEY")
|
key := os.Getenv("ANTHROPIC_API_KEY")
|
||||||
if key == "" {
|
if key == "" {
|
||||||
log.Warn().Msg("ANTHROPIC_API_KEY not set, agent will use mock responses")
|
log.Warn().Msg("ANTHROPIC_API_KEY not set, agent will use mock responses")
|
||||||
@@ -48,6 +50,7 @@ func NewAgentOrchestrator() *AgentOrchestrator {
|
|||||||
return &AgentOrchestrator{
|
return &AgentOrchestrator{
|
||||||
anthropicKey: key,
|
anthropicKey: key,
|
||||||
apiEndpoint: "https://api.anthropic.com/v1/messages",
|
apiEndpoint: "https://api.anthropic.com/v1/messages",
|
||||||
|
dataProvider: NewAgentDataProvider(db, ledgerDB),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +84,20 @@ func (o *AgentOrchestrator) HandleAgentChat(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hämta real-time data för agenten
|
||||||
|
dataContext := ""
|
||||||
|
if o.dataProvider != nil {
|
||||||
|
dataContext = o.dataProvider.FormatDataForPrompt(req.Rum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bygg enhanced prompt med data
|
||||||
|
enhancedPrompt := req.SystemPrompt
|
||||||
|
if dataContext != "" {
|
||||||
|
enhancedPrompt = req.SystemPrompt + dataContext
|
||||||
|
}
|
||||||
|
|
||||||
// Call Anthropic API
|
// Call Anthropic API
|
||||||
svar, err := o.callAnthropic(req.SystemPrompt, req.Meddelanden)
|
svar, err := o.callAnthropic(enhancedPrompt, req.Meddelanden)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("rum", req.Rum).Msg("Agent chat failed")
|
log.Error().Err(err).Str("rum", req.Rum).Msg("Agent chat failed")
|
||||||
// Fallback to mock
|
// Fallback to mock
|
||||||
|
|||||||
@@ -0,0 +1,425 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AgentDataProvider hämtar riktig data från BOC för agenterna
|
||||||
|
type AgentDataProvider struct {
|
||||||
|
db *sql.DB
|
||||||
|
ledgerDB *sql.DB
|
||||||
|
amosURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAgentDataProvider skapar en ny data provider
|
||||||
|
func NewAgentDataProvider(db, ledgerDB *sql.DB) *AgentDataProvider {
|
||||||
|
return &AgentDataProvider{
|
||||||
|
db: db,
|
||||||
|
ledgerDB: ledgerDB,
|
||||||
|
amosURL: os.Getenv("AMOS_BASE_URL"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinanceData innehåller finansiell data för Finance Agent
|
||||||
|
type FinanceData struct {
|
||||||
|
Balance *BalanceSnapshot `json:"balance,omitempty"`
|
||||||
|
Income *IncomeSnapshot `json:"income,omitempty"`
|
||||||
|
Cashflow *CashflowSummary `json:"cashflow,omitempty"`
|
||||||
|
Invoices []InvoiceSummary `json:"invoices,omitempty"`
|
||||||
|
Period string `json:"period"`
|
||||||
|
GeneratedAt string `json:"generated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BalanceSnapshot struct {
|
||||||
|
TotalAssets float64 `json:"total_assets"`
|
||||||
|
TotalLiabilities float64 `json:"total_liabilities"`
|
||||||
|
TotalEquity float64 `json:"total_equity"`
|
||||||
|
LiquidityRatio float64 `json:"liquidity_ratio"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IncomeSnapshot struct {
|
||||||
|
Revenue float64 `json:"revenue"`
|
||||||
|
Expenses float64 `json:"expenses"`
|
||||||
|
NetIncome float64 `json:"net_income"`
|
||||||
|
Margin float64 `json:"margin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CashflowSummary struct {
|
||||||
|
Inflow float64 `json:"inflow"`
|
||||||
|
Outflow float64 `json:"outflow"`
|
||||||
|
Net float64 `json:"net"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvoiceSummary struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Customer string `json:"customer"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
DueDate string `json:"due_date"`
|
||||||
|
DaysOverdue int `json:"days_overdue,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRMData innehåller CRM-data för CRM Agent
|
||||||
|
type CRMData struct {
|
||||||
|
CustomerCount int `json:"customer_count"`
|
||||||
|
LeadCount int `json:"lead_count"`
|
||||||
|
PipelineValue float64 `json:"pipeline_value"`
|
||||||
|
RecentCustomers []CustomerBrief `json:"recent_customers,omitempty"`
|
||||||
|
RecentLeads []LeadBrief `json:"recent_leads,omitempty"`
|
||||||
|
GeneratedAt string `json:"generated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CustomerBrief struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Company string `json:"company"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LeadBrief struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SalesData innehåller säljdata för Sales Agent
|
||||||
|
type SalesData struct {
|
||||||
|
TotalDeals int `json:"total_deals"`
|
||||||
|
MRR float64 `json:"mrr"`
|
||||||
|
ARR float64 `json:"arr"`
|
||||||
|
PipelineStages []StageBrief `json:"pipeline_stages,omitempty"`
|
||||||
|
RecentDeals []DealBrief `json:"recent_deals,omitempty"`
|
||||||
|
GeneratedAt string `json:"generated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StageBrief struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Deals int `json:"deals"`
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DealBrief struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
Stage string `json:"stage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HRData innehåller HR-data för HR Agent
|
||||||
|
type HRData struct {
|
||||||
|
EmployeeCount int `json:"employee_count"`
|
||||||
|
ActiveLeaves int `json:"active_leaves"`
|
||||||
|
Departments []DeptSummary `json:"departments,omitempty"`
|
||||||
|
RecentHires []EmployeeBrief `json:"recent_hires,omitempty"`
|
||||||
|
GeneratedAt string `json:"generated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeptSummary struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmployeeBrief struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Department string `json:"department"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFinanceData hämtar finansiell data
|
||||||
|
func (p *AgentDataProvider) GetFinanceData() (*FinanceData, error) {
|
||||||
|
data := &FinanceData{
|
||||||
|
Period: time.Now().Format("2006-01"),
|
||||||
|
GeneratedAt: time.Now().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hämta balansräkning
|
||||||
|
if p.ledgerDB != nil {
|
||||||
|
var assets, liabilities, equity float64
|
||||||
|
err := p.ledgerDB.QueryRow(`
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(CASE WHEN account_code < 2000 THEN balance ELSE 0 END), 0) as assets,
|
||||||
|
COALESCE(SUM(CASE WHEN account_code >= 2000 AND account_code < 3000 THEN balance ELSE 0 END), 0) as liabilities,
|
||||||
|
COALESCE(SUM(CASE WHEN account_code >= 3000 THEN balance ELSE 0 END), 0) as equity
|
||||||
|
FROM account_balances
|
||||||
|
WHERE period = $1
|
||||||
|
`, data.Period).Scan(&assets, &liabilities, &equity)
|
||||||
|
if err == nil {
|
||||||
|
data.Balance = &BalanceSnapshot{
|
||||||
|
TotalAssets: assets,
|
||||||
|
TotalLiabilities: liabilities,
|
||||||
|
TotalEquity: equity,
|
||||||
|
LiquidityRatio: assets / liabilities * 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hämta resultaträkning
|
||||||
|
var revenue, expenses float64
|
||||||
|
err = p.ledgerDB.QueryRow(`
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(CASE WHEN account_code >= 3000 AND account_code < 4000 THEN credit - debit ELSE 0 END), 0) as revenue,
|
||||||
|
COALESCE(SUM(CASE WHEN account_code >= 4000 AND account_code < 8000 THEN debit - credit ELSE 0 END), 0) as expenses
|
||||||
|
FROM journal_entries
|
||||||
|
WHERE DATE_TRUNC('month', entry_date) = DATE_TRUNC('month', CURRENT_DATE)
|
||||||
|
`).Scan(&revenue, &expenses)
|
||||||
|
if err == nil {
|
||||||
|
netIncome := revenue - expenses
|
||||||
|
margin := 0.0
|
||||||
|
if revenue > 0 {
|
||||||
|
margin = (netIncome / revenue) * 100
|
||||||
|
}
|
||||||
|
data.Income = &IncomeSnapshot{
|
||||||
|
Revenue: revenue,
|
||||||
|
Expenses: expenses,
|
||||||
|
NetIncome: netIncome,
|
||||||
|
Margin: margin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hämta fakturor
|
||||||
|
rows, err := p.ledgerDB.Query(`
|
||||||
|
SELECT id, customer_name, amount, status, due_date,
|
||||||
|
CASE WHEN due_date < CURRENT_DATE AND status != 'paid'
|
||||||
|
THEN EXTRACT(DAY FROM CURRENT_DATE - due_date)::int
|
||||||
|
ELSE 0 END as days_overdue
|
||||||
|
FROM invoices
|
||||||
|
WHERE created_at > CURRENT_DATE - INTERVAL '90 days'
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT 10
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var inv InvoiceSummary
|
||||||
|
rows.Scan(&inv.ID, &inv.Customer, &inv.Amount, &inv.Status, &inv.DueDate, &inv.DaysOverdue)
|
||||||
|
data.Invoices = append(data.Invoices, inv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCRMData hämtar CRM-data
|
||||||
|
func (p *AgentDataProvider) GetCRMData() (*CRMData, error) {
|
||||||
|
data := &CRMData{
|
||||||
|
GeneratedAt: time.Now().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.db != nil {
|
||||||
|
// Kundantal
|
||||||
|
p.db.QueryRow("SELECT COUNT(*) FROM customers WHERE status = 'active'").Scan(&data.CustomerCount)
|
||||||
|
|
||||||
|
// Leadantal
|
||||||
|
p.db.QueryRow("SELECT COUNT(*) FROM leads WHERE status != 'converted'").Scan(&data.LeadCount)
|
||||||
|
|
||||||
|
// Pipeline-värde
|
||||||
|
p.db.QueryRow("SELECT COALESCE(SUM(value), 0) FROM pipeline_deals WHERE status = 'open'").Scan(&data.PipelineValue)
|
||||||
|
|
||||||
|
// Senaste kunder
|
||||||
|
rows, err := p.db.Query(`
|
||||||
|
SELECT id, name, company, status
|
||||||
|
FROM customers
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT 5
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var c CustomerBrief
|
||||||
|
rows.Scan(&c.ID, &c.Name, &c.Company, &c.Status)
|
||||||
|
data.RecentCustomers = append(data.RecentCustomers, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Senaste leads
|
||||||
|
rows, err = p.db.Query(`
|
||||||
|
SELECT id, name, source, status
|
||||||
|
FROM leads
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT 5
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var l LeadBrief
|
||||||
|
rows.Scan(&l.ID, &l.Name, &l.Source, &l.Status)
|
||||||
|
data.RecentLeads = append(data.RecentLeads, l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSalesData hämtar säljdata
|
||||||
|
func (p *AgentDataProvider) GetSalesData() (*SalesData, error) {
|
||||||
|
data := &SalesData{
|
||||||
|
GeneratedAt: time.Now().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.db != nil {
|
||||||
|
// Totalt antal deals
|
||||||
|
p.db.QueryRow("SELECT COUNT(*) FROM sales_deals").Scan(&data.TotalDeals)
|
||||||
|
|
||||||
|
// MRR
|
||||||
|
p.db.QueryRow("SELECT COALESCE(SUM(monthly_value), 0) FROM sales_deals WHERE status = 'active'").Scan(&data.MRR)
|
||||||
|
|
||||||
|
// ARR
|
||||||
|
data.ARR = data.MRR * 12
|
||||||
|
|
||||||
|
// Pipeline-stages
|
||||||
|
rows, err := p.db.Query(`
|
||||||
|
SELECT stage_name, COUNT(*), COALESCE(SUM(value), 0)
|
||||||
|
FROM sales_deals
|
||||||
|
WHERE status = 'open'
|
||||||
|
GROUP BY stage_name
|
||||||
|
ORDER BY stage_name
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var s StageBrief
|
||||||
|
rows.Scan(&s.Name, &s.Deals, &s.Value)
|
||||||
|
data.PipelineStages = append(data.PipelineStages, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Senaste deals
|
||||||
|
rows, err = p.db.Query(`
|
||||||
|
SELECT id, name, value, stage
|
||||||
|
FROM sales_deals
|
||||||
|
ORDER BY updated_at DESC
|
||||||
|
LIMIT 5
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var d DealBrief
|
||||||
|
rows.Scan(&d.ID, &d.Name, &d.Value, &d.Stage)
|
||||||
|
data.RecentDeals = append(data.RecentDeals, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHRData hämtar HR-data
|
||||||
|
func (p *AgentDataProvider) GetHRData() (*HRData, error) {
|
||||||
|
data := &HRData{
|
||||||
|
GeneratedAt: time.Now().Format(time.RFC3339),
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.db != nil {
|
||||||
|
// Antal anställda
|
||||||
|
p.db.QueryRow("SELECT COUNT(*) FROM employees WHERE status = 'active'").Scan(&data.EmployeeCount)
|
||||||
|
|
||||||
|
// Aktiva ledigheter
|
||||||
|
p.db.QueryRow(`
|
||||||
|
SELECT COUNT(*) FROM leaves
|
||||||
|
WHERE status = 'approved'
|
||||||
|
AND start_date <= CURRENT_DATE
|
||||||
|
AND end_date >= CURRENT_DATE
|
||||||
|
`).Scan(&data.ActiveLeaves)
|
||||||
|
|
||||||
|
// Avdelningar
|
||||||
|
rows, err := p.db.Query(`
|
||||||
|
SELECT department, COUNT(*)
|
||||||
|
FROM employees
|
||||||
|
WHERE status = 'active'
|
||||||
|
GROUP BY department
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var d DeptSummary
|
||||||
|
rows.Scan(&d.Name, &d.Count)
|
||||||
|
data.Departments = append(data.Departments, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Senaste anställningar
|
||||||
|
rows, err = p.db.Query(`
|
||||||
|
SELECT id, first_name || ' ' || last_name as name, department, status
|
||||||
|
FROM employees
|
||||||
|
ORDER BY start_date DESC
|
||||||
|
LIMIT 5
|
||||||
|
`)
|
||||||
|
if err == nil {
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var e EmployeeBrief
|
||||||
|
rows.Scan(&e.ID, &e.Name, &e.Department, &e.Status)
|
||||||
|
data.RecentHires = append(data.RecentHires, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDataForAgent hämtar data baserat på agent-typ
|
||||||
|
func (p *AgentDataProvider) GetDataForAgent(rum string) (map[string]interface{}, error) {
|
||||||
|
switch rum {
|
||||||
|
case "finance":
|
||||||
|
data, err := p.GetFinanceData()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Str("rum", rum).Msg("Failed to get finance data")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return structToMap(data), nil
|
||||||
|
case "crm":
|
||||||
|
data, err := p.GetCRMData()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Str("rum", rum).Msg("Failed to get CRM data")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return structToMap(data), nil
|
||||||
|
case "sales":
|
||||||
|
data, err := p.GetSalesData()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Str("rum", rum).Msg("Failed to get sales data")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return structToMap(data), nil
|
||||||
|
case "hr":
|
||||||
|
data, err := p.GetHRData()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Str("rum", rum).Msg("Failed to get HR data")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return structToMap(data), nil
|
||||||
|
default:
|
||||||
|
return map[string]interface{}{
|
||||||
|
"message": "No real-time data available for this agent type",
|
||||||
|
"rum": rum,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// structToMap konverterar en struct till map via JSON
|
||||||
|
func structToMap(v interface{}) map[string]interface{} {
|
||||||
|
var result map[string]interface{}
|
||||||
|
b, _ := json.Marshal(v)
|
||||||
|
json.Unmarshal(b, &result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatDataForPrompt formaterar data för Anthropic prompt
|
||||||
|
func (p *AgentDataProvider) FormatDataForPrompt(rum string) string {
|
||||||
|
data, err := p.GetDataForAgent(rum)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, _ := json.MarshalIndent(data, "", " ")
|
||||||
|
return fmt.Sprintf("\n\nAKTUELL DATA FRÅN SYSTEMET:\n%s\n\nAnvänd denna data för att ge exakta, datadrivna svar. Om data saknas för en specifik fråga, be användaren specificera.", string(jsonData))
|
||||||
|
}
|
||||||
+3
-3
@@ -118,9 +118,9 @@ func main() {
|
|||||||
autoEngine := automation.NewEngine(database, logger)
|
autoEngine := automation.NewEngine(database, logger)
|
||||||
autoH := handlers.NewAutomationHandler(database, autoEngine)
|
autoH := handlers.NewAutomationHandler(database, autoEngine)
|
||||||
|
|
||||||
// Agent Orchestrator
|
// Agent Orchestrator — med datakoppling till ledger (återanvänd befintlig ledgerDB)
|
||||||
agentOrchestrator := handlers.NewAgentOrchestrator()
|
agentOrchestrator := handlers.NewAgentOrchestrator(database, ledgerDB)
|
||||||
logger.Info().Msg("Agent Orchestrator initialized")
|
logger.Info().Msg("Agent Orchestrator initialized with real-time data")
|
||||||
|
|
||||||
// Auth: JWTService med förbättrad validering
|
// Auth: JWTService med förbättrad validering
|
||||||
jwtService := auth.NewJWTService(cfg.JWTSecret, "boc-auth", "boc")
|
jwtService := auth.NewJWTService(cfg.JWTSecret, "boc-auth", "boc")
|
||||||
|
|||||||
Reference in New Issue
Block a user