- Implement 12 Temporal activities for memory operations - Activities: create, update, search, context, diagnose, analyze, document - Add activity registration and worker setup - Full retry/timeout configuration with observability - Include workflow patterns and examples - All tests passing (23/23) Documentation: - MEMORY_INTEGRATION.md: High-level integration guide - MEMORY_ACTIVITIES.md: Complete activities reference - REGISTERED_ACTIVITIES.md: Registry and calling conventions
304 lines
7.7 KiB
Go
304 lines
7.7 KiB
Go
package memory
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"go.temporal.io/sdk/workflow"
|
|
)
|
|
|
|
// LearningWorkflow learns from task execution
|
|
// Pattern: Execute → Learn → Document
|
|
func LearningWorkflow(ctx workflow.Context, taskID string, executor string) (string, error) {
|
|
// Execute task (placeholder - replace with actual activity)
|
|
taskResult := fmt.Sprintf("Task %s executed by %s", taskID, executor)
|
|
|
|
// Learn from execution
|
|
knowledgeID, err := ExecuteLearnFromExecution(
|
|
ctx,
|
|
taskID,
|
|
taskResult,
|
|
[]string{"execution", "learning"},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("learn from execution: %w", err)
|
|
}
|
|
|
|
return knowledgeID, nil
|
|
}
|
|
|
|
// DiagnosticWorkflow diagnoses issue using memory service
|
|
// Pattern: Get Context → Extract Recommendations → Apply
|
|
func DiagnosticWorkflow(ctx workflow.Context, tool, issue string) ([]string, error) {
|
|
// Get recommendations
|
|
recommendations, err := ExecuteDiagnoseIssue(
|
|
ctx,
|
|
tool,
|
|
issue,
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("diagnose: %w", err)
|
|
}
|
|
|
|
return recommendations, nil
|
|
}
|
|
|
|
// SearchAndApplyWorkflow searches knowledge and applies it
|
|
// Pattern: Search → Filter → Apply
|
|
func SearchAndApplyWorkflow(ctx workflow.Context, query string) ([]KnowledgeRecord, error) {
|
|
// Search knowledge
|
|
records, err := ExecuteSearchKnowledge(
|
|
ctx,
|
|
query,
|
|
&RetrievalOptions{
|
|
Limit: 10,
|
|
LevelFilter: []string{"L1", "L2"},
|
|
Floor: 0.7,
|
|
},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("search: %w", err)
|
|
}
|
|
|
|
return records, nil
|
|
}
|
|
|
|
// ContextualDecisionWorkflow makes decisions with memory context
|
|
// Pattern: Get Context → Make Decision → Document Decision
|
|
func ContextualDecisionWorkflow(ctx workflow.Context, tool, task string, decision string) (string, error) {
|
|
// Get context
|
|
svcCtx, err := ExecuteGetContext(
|
|
ctx,
|
|
tool,
|
|
task,
|
|
8192,
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("get context: %w", err)
|
|
}
|
|
|
|
// Build reasoning from lessons
|
|
reasoning := fmt.Sprintf("Based on %d lessons from memory service (tier %d)", len(svcCtx.Lessons), svcCtx.Tier)
|
|
|
|
// Document decision
|
|
docID, err := ExecuteDocumentDecision(
|
|
ctx,
|
|
tool,
|
|
decision,
|
|
reasoning,
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("document decision: %w", err)
|
|
}
|
|
|
|
return docID, nil
|
|
}
|
|
|
|
// ErrorRecoveryWorkflow analyzes error and searches for recovery
|
|
// Pattern: Error → Analyze → Search → Recover
|
|
func ErrorRecoveryWorkflow(ctx workflow.Context, errorMsg string) ([]string, error) {
|
|
// Analyze error
|
|
records, err := ExecuteAnalyzeError(
|
|
ctx,
|
|
errorMsg,
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("analyze error: %w", err)
|
|
}
|
|
|
|
// Extract recovery recommendations
|
|
recommendations := make([]string, 0)
|
|
for _, record := range records {
|
|
if record.Level == "L1" { // High confidence
|
|
recommendations = append(recommendations, record.Content)
|
|
}
|
|
}
|
|
|
|
return recommendations, nil
|
|
}
|
|
|
|
// HealthAwareWorkflow checks health before proceeding
|
|
// Pattern: HealthCheck → Conditional Proceed
|
|
func HealthAwareWorkflow(ctx workflow.Context, taskID string) (bool, error) {
|
|
// Check health
|
|
healthy, err := ExecuteHealthCheck(ctx, DefaultActivityOptions())
|
|
if err != nil {
|
|
return false, fmt.Errorf("health check: %w", err)
|
|
}
|
|
|
|
if !healthy {
|
|
return false, fmt.Errorf("memory service unhealthy, skipping task %s", taskID)
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// IterativeLearnWorkflow learns iteratively
|
|
// Pattern: Execute → Learn → Refine → Learn Again
|
|
func IterativeLearnWorkflow(ctx workflow.Context, topic string, iterations int) ([]string, error) {
|
|
knowledgeIDs := make([]string, 0)
|
|
|
|
for i := 0; i < iterations; i++ {
|
|
// Learn current iteration
|
|
id, err := ExecuteLearnFromExecution(
|
|
ctx,
|
|
fmt.Sprintf("%s-iteration-%d", topic, i+1),
|
|
fmt.Sprintf("Iteration %d: %s", i+1, topic),
|
|
[]string{"iteration", fmt.Sprintf("iteration-%d", i+1)},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("learn iteration %d: %w", i+1, err)
|
|
}
|
|
|
|
knowledgeIDs = append(knowledgeIDs, id)
|
|
|
|
// Search for related knowledge
|
|
records, err := ExecuteSearchKnowledge(
|
|
ctx,
|
|
topic,
|
|
&RetrievalOptions{Limit: 5, Floor: 0.6},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("search iteration %d: %w", i+1, err)
|
|
}
|
|
|
|
// Log found records
|
|
if len(records) > 0 {
|
|
workflow.GetLogger(ctx).Info("Iteration found related records", "iteration", i+1, "records", len(records))
|
|
}
|
|
}
|
|
|
|
return knowledgeIDs, nil
|
|
}
|
|
|
|
// ConditionalLearningWorkflow learns only on success
|
|
// Pattern: Execute → If Success → Learn
|
|
func ConditionalLearningWorkflow(ctx workflow.Context, taskID string, shouldSucceed bool) (string, error) {
|
|
if !shouldSucceed {
|
|
return "", fmt.Errorf("task failed, skipping learning")
|
|
}
|
|
|
|
// Only learn on success
|
|
result := fmt.Sprintf("Task %s succeeded", taskID)
|
|
|
|
id, err := ExecuteLearnFromExecution(
|
|
ctx,
|
|
taskID,
|
|
result,
|
|
[]string{"success"},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("learn from success: %w", err)
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
// MultiStepWorkflow performs multiple memory operations
|
|
// Pattern: Create → Search → Context → Document
|
|
func MultiStepWorkflow(ctx workflow.Context, topic string) (map[string]interface{}, error) {
|
|
results := make(map[string]interface{})
|
|
|
|
// Step 1: Create knowledge
|
|
createID, err := ExecuteCreateKnowledge(
|
|
ctx,
|
|
&KnowledgeRecord{
|
|
Level: "L1",
|
|
Title: fmt.Sprintf("Initial: %s", topic),
|
|
Content: fmt.Sprintf("Starting workflow for %s", topic),
|
|
Source: "workflow://multi-step",
|
|
},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create knowledge: %w", err)
|
|
}
|
|
results["created"] = createID
|
|
|
|
// Step 2: Search knowledge
|
|
searchRecords, err := ExecuteSearchKnowledge(
|
|
ctx,
|
|
topic,
|
|
&RetrievalOptions{Limit: 5},
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("search knowledge: %w", err)
|
|
}
|
|
results["found"] = len(searchRecords)
|
|
|
|
// Step 3: Get context
|
|
svcCtx, err := ExecuteGetContext(
|
|
ctx,
|
|
"workflow",
|
|
topic,
|
|
8192,
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get context: %w", err)
|
|
}
|
|
results["context_tier"] = svcCtx.Tier
|
|
results["lessons"] = len(svcCtx.Lessons)
|
|
results["skills"] = len(svcCtx.Skills)
|
|
|
|
// Step 4: Document completion
|
|
docID, err := ExecuteDocumentDecision(
|
|
ctx,
|
|
"workflow_completion",
|
|
fmt.Sprintf("Completed multi-step workflow for %s", topic),
|
|
fmt.Sprintf("Found %d records, tier %d context", len(searchRecords), svcCtx.Tier),
|
|
DefaultActivityOptions(),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("document completion: %w", err)
|
|
}
|
|
results["documented"] = docID
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// ParallelLearnWorkflow learns from multiple sources in parallel
|
|
// Pattern: Execute Multiple Tasks in Parallel → Learn from Each
|
|
func ParallelLearnWorkflow(ctx workflow.Context, taskIDs []string) ([]string, error) {
|
|
// Create parallel activities
|
|
futures := make([]workflow.Future, len(taskIDs))
|
|
|
|
for i, taskID := range taskIDs {
|
|
// Execute each task in parallel
|
|
future := workflow.ExecuteActivity(
|
|
workflow.WithActivityOptions(
|
|
ctx,
|
|
workflow.ActivityOptions{
|
|
ScheduleToCloseTimeout: DefaultActivityOptions().RetryBackoff * 60,
|
|
StartToCloseTimeout: DefaultActivityOptions().RetryBackoff * 30,
|
|
},
|
|
),
|
|
"LearnFromExecutionActivity",
|
|
taskID,
|
|
fmt.Sprintf("Result from %s", taskID),
|
|
[]string{"parallel", taskID},
|
|
)
|
|
futures[i] = future
|
|
}
|
|
|
|
// Collect results
|
|
results := make([]string, len(futures))
|
|
for i, future := range futures {
|
|
err := future.Get(ctx, &results[i])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parallel learn task %d: %w", i, err)
|
|
}
|
|
}
|
|
|
|
return results, nil
|
|
}
|