Skip to content

Commit 20ac6e3

Browse files
chrisli30will-dzweilicious
authored
feat(summarizer): point summary endpoint at Studio (retire context-memory) (#622)
Co-authored-by: Will Zimmerman <will@avaprotocol.org> Co-authored-by: Wei Lin <wei@avaprotocol.org>
1 parent 62d90e4 commit 20ac6e3

6 files changed

Lines changed: 51 additions & 47 deletions

core/taskengine/engine.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -339,23 +339,18 @@ func New(db storage.Storage, config *config.Config, queue *apqueue.Queue, logger
339339
// Initialize AI summarizer (global) from aggregator config
340340
// Only context-memory API is supported - all email content generation is delegated to context-memory
341341
// The aggregator acts as a pass-through for the context-memory response to SendGrid
342-
contextMemorySummarizer := NewContextMemorySummarizerFromAggregatorConfig(config)
342+
contextMemorySummarizer, err := NewContextMemorySummarizerFromAggregatorConfig(config)
343+
if err != nil {
344+
// notifications.summary is enabled but misconfigured — refuse to boot rather than
345+
// silently fall back, so a broken summarizer config surfaces loudly at startup.
346+
logger.Fatal("Invalid notifications.summary configuration — refusing to start", "error", err)
347+
}
343348
if contextMemorySummarizer != nil {
344349
SetSummarizer(contextMemorySummarizer)
345350
logger.Info("AI summarizer initialized", "provider", "context-memory", "base_url", config.NotificationsSummary.APIEndpoint)
346351
} else {
347-
// Log why context-memory is not available
348-
if !config.NotificationsSummary.Enabled {
349-
logger.Debug("Context-memory API not available: NotificationsSummary.Enabled is false")
350-
} else if strings.ToLower(config.NotificationsSummary.Provider) != "context-memory" {
351-
logger.Debug("Context-memory API not configured: provider is not 'context-memory'", "provider", config.NotificationsSummary.Provider)
352-
} else if strings.TrimSpace(config.NotificationsSummary.APIEndpoint) == "" {
353-
logger.Debug("Context-memory API not available: api_endpoint not configured in notifications.summary")
354-
} else if strings.TrimSpace(config.NotificationsSummary.APIKey) == "" {
355-
logger.Debug("Context-memory API not available: api_key not configured in notifications.summary")
356-
}
357-
// No summarizer configured - deterministic fallback will be used
358-
logger.Debug("Context-memory API not configured, will use deterministic fallback")
352+
// Summarization not enabled — the deterministic summarizer is used.
353+
logger.Debug("notifications.summary.enabled is false; using deterministic summarizer")
359354
}
360355

361356
// Initialize global macro variables and secrets from config

core/taskengine/summarizer.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package taskengine
22

33
import (
44
"context"
5+
"fmt"
56
"net/http"
67
"strings"
78
"time"
@@ -108,31 +109,34 @@ func ComposeSummarySmart(vm *VM, currentStepName string) Summary {
108109
return s
109110
}
110111

111-
// NewContextMemorySummarizerFromAggregatorConfig creates a ContextMemorySummarizer from aggregator config
112-
// Reads api_endpoint and api_key from notifications.summary section
113-
func NewContextMemorySummarizerFromAggregatorConfig(c *config.Config) Summarizer {
114-
if c == nil {
115-
return nil
116-
}
117-
if !c.NotificationsSummary.Enabled || strings.ToLower(c.NotificationsSummary.Provider) != "context-memory" {
118-
return nil
119-
}
120-
baseURL := c.NotificationsSummary.APIEndpoint
121-
if strings.TrimSpace(baseURL) == "" {
122-
return nil
112+
// NewContextMemorySummarizerFromAggregatorConfig builds the workflow summarizer from the
113+
// aggregator's notifications.summary config (api_endpoint + api_key).
114+
//
115+
// Returns (nil, nil) when summarization is disabled — a valid "off" mode in which callers
116+
// use the deterministic summarizer. Returns (nil, error) when summarization is ENABLED but
117+
// misconfigured (unsupported provider, or empty endpoint/key) so the daemon fails fast at
118+
// startup instead of silently degrading. There is no hardcoded endpoint default: the origin
119+
// must come from config (avs-infra: ${SUMMARIZER_API_URL} / ${SUMMARIZER_API_KEY}).
120+
func NewContextMemorySummarizerFromAggregatorConfig(c *config.Config) (Summarizer, error) {
121+
if c == nil || !c.NotificationsSummary.Enabled {
122+
return nil, nil // Not enabled — deterministic fallback is used.
123123
}
124-
authToken := c.NotificationsSummary.APIKey
125-
if strings.TrimSpace(authToken) == "" {
126-
return nil
124+
if strings.ToLower(c.NotificationsSummary.Provider) != "context-memory" {
125+
return nil, fmt.Errorf("notifications.summary.enabled is true but provider %q is unsupported (expected \"context-memory\")", c.NotificationsSummary.Provider)
127126
}
127+
baseURL := strings.TrimSpace(c.NotificationsSummary.APIEndpoint)
128128
if baseURL == "" {
129-
baseURL = ContextAPIURL
129+
return nil, fmt.Errorf("notifications.summary.enabled is true but api_endpoint is empty (set SUMMARIZER_API_URL to the Studio origin, e.g. https://app.avaprotocol.org)")
130+
}
131+
authToken := strings.TrimSpace(c.NotificationsSummary.APIKey)
132+
if authToken == "" {
133+
return nil, fmt.Errorf("notifications.summary.enabled is true but api_key is empty (set SUMMARIZER_API_KEY)")
130134
}
131135
return &ContextMemorySummarizer{
132136
baseURL: baseURL,
133137
authToken: authToken,
134138
httpClient: &http.Client{Timeout: 30 * time.Second},
135-
}
139+
}, nil
136140
}
137141

138142
// FormatForMessageChannels converts a Summary into a concise chat message

core/taskengine/summarizer_context_memory.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,20 @@ import (
1515
"github.com/ethereum/go-ethereum/common"
1616
)
1717

18-
const (
19-
// ContextAPIURL is the production URL for the context-api service
20-
ContextAPIURL = "https://context-api.avaprotocol.org"
21-
)
22-
23-
// ContextMemorySummarizer implements Summarizer using the context-memory API
18+
// ContextMemorySummarizer implements Summarizer by posting to the workflow-summary
19+
// endpoint (Studio's /api/summarize; the standalone context-memory service is deprecated).
2420
type ContextMemorySummarizer struct {
2521
baseURL string
2622
authToken string
2723
httpClient *http.Client
2824
}
2925

30-
// NewContextMemorySummarizer creates a new summarizer that calls context-memory API
31-
// baseURL defaults to ContextAPIURL (production) if empty
26+
// NewContextMemorySummarizer creates a summarizer that posts to {baseURL}/api/summarize.
27+
// baseURL MUST be a bare origin (no "/api/summarize" path and no trailing slash) — the
28+
// client appends the path itself; including it would double the path. No default is
29+
// applied: the origin must be supplied explicitly (production wiring fails fast at
30+
// startup when it is missing, see NewContextMemorySummarizerFromAggregatorConfig).
3231
func NewContextMemorySummarizer(baseURL, authToken string) Summarizer {
33-
if baseURL == "" {
34-
baseURL = ContextAPIURL
35-
}
3632
return &ContextMemorySummarizer{
3733
baseURL: baseURL,
3834
authToken: authToken,

core/taskengine/summarizer_context_memory_integration_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ type EdgeDefinition struct {
7373
Target string `json:"target"`
7474
}
7575

76-
// getContextMemoryURL returns the base URL for context-memory API
77-
// Uses CONTEXT_MEMORY_URL env var if set, otherwise defaults to production URL from source code
76+
// getContextMemoryURL returns the base URL for the summarizer API in tests.
77+
// Uses CONTEXT_MEMORY_URL env var if set, otherwise the production origin above.
7878
func getContextMemoryURL() string {
7979
if url := os.Getenv("CONTEXT_MEMORY_URL"); url != "" {
8080
return url
8181
}
82-
return ContextAPIURL
82+
return defaultSummarizerURL
8383
}
8484

8585
// baseURL shared across tests to avoid redeclaration issues

core/taskengine/summarizer_format_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import (
1515
const (
1616
// Default auth token for local context-memory tests
1717
ContextMemoryAuthToken = "test-auth-token-12345"
18+
19+
// defaultSummarizerURL is the production Studio origin, used ONLY as a convenience
20+
// fallback in tests when CONTEXT_MEMORY_URL is unset. Production code has no hardcoded
21+
// default — it reads the origin from notifications.summary.api_endpoint and fails fast
22+
// at startup if it is missing.
23+
defaultSummarizerURL = "https://app.avaprotocol.org"
1824
)
1925

2026
type fakeSummarizer struct {
@@ -61,7 +67,7 @@ func TestComposeSummarySmart_UsesAISummarizer(t *testing.T) {
6167
// Use real context-memory API
6268
baseURL := os.Getenv("CONTEXT_MEMORY_URL")
6369
if baseURL == "" {
64-
baseURL = ContextAPIURL // Default to production URL from source code
70+
baseURL = defaultSummarizerURL // Test-only fallback when CONTEXT_MEMORY_URL is unset
6571
}
6672
t.Logf("Using real context-memory API at: %s", baseURL)
6773
summarizer := NewContextMemorySummarizer(baseURL, authToken)
@@ -523,7 +529,7 @@ func TestComposeSummarySmart_WithRealWorkflowState(t *testing.T) {
523529
// Use real context-memory API (defaults to localhost:3000)
524530
baseURL := os.Getenv("CONTEXT_MEMORY_URL")
525531
if baseURL == "" {
526-
baseURL = ContextAPIURL // Default to production URL from source code
532+
baseURL = defaultSummarizerURL // Test-only fallback when CONTEXT_MEMORY_URL is unset
527533
}
528534
t.Logf("Using real context-memory API at: %s", baseURL)
529535
summarizer := NewContextMemorySummarizer(baseURL, authToken)

core/taskengine/vm_runner_rest_sendgrid_integration_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ func TestSendGridEmailWithContextMemoryResponse(t *testing.T) {
8484
}
8585
// Override context_api_endpoint to use mock server
8686
mockConfig.MacroSecrets["context_api_endpoint"] = contextMemoryServer.URL
87-
summarizer := NewContextMemorySummarizerFromAggregatorConfig(&mockConfig)
87+
summarizer, err := NewContextMemorySummarizerFromAggregatorConfig(&mockConfig)
88+
if err != nil {
89+
t.Fatalf("Failed to create context-memory summarizer from config: %v", err)
90+
}
8891
if summarizer == nil {
8992
t.Fatal("Failed to create context-memory summarizer from config")
9093
}

0 commit comments

Comments
 (0)