// Package mock provides a mock Adapter that echoes input with streaming deltas. // Useful for testing transport and pipeline correctness without real models. package mock import ( "context" "fmt" "strings" "time" "go.uber.org/zap" "iop/apps/node/internal/runtime" ) const Name = "mock" type Mock struct { logger *zap.Logger } func New(logger *zap.Logger) *Mock { return &Mock{logger: logger} } func (m *Mock) Name() string { return Name } func (m *Mock) Capabilities(_ context.Context) (runtime.Capabilities, error) { return runtime.Capabilities{ AdapterName: Name, Targets: []string{"mock-echo", "mock-stream"}, MaxConcurrency: 16, ProviderStatus: runtime.ProviderStatusAvailable, }, nil } func (m *Mock) ProbeProvider(ctx context.Context, target string) (runtime.ProviderProbeResult, error) { targets := []string{"mock-echo", "mock-stream"} return runtime.ProviderProbeResult{ AdapterName: Name, Target: target, Targets: targets, Status: runtime.ProviderStatusAvailable, }, nil } func (m *Mock) Execute(ctx context.Context, spec runtime.ExecutionSpec, sink runtime.EventSink) error { m.logger.Info("mock adapter executing", zap.String("run_id", spec.RunID)) if err := sink.Emit(ctx, runtime.RuntimeEvent{ RunID: spec.RunID, Type: runtime.EventTypeStart, Timestamp: time.Now(), }); err != nil { return err } prompt := extractPrompt(spec.Input) words := strings.Fields(fmt.Sprintf("echo: %s", prompt)) if len(words) == 0 { words = []string{"(empty", "input)"} } for _, word := range words { select { case <-ctx.Done(): return ctx.Err() default: } if err := sink.Emit(ctx, runtime.RuntimeEvent{ RunID: spec.RunID, Type: runtime.EventTypeDelta, Delta: word + " ", Timestamp: time.Now(), }); err != nil { return err } time.Sleep(30 * time.Millisecond) } return sink.Emit(ctx, runtime.RuntimeEvent{ RunID: spec.RunID, Type: runtime.EventTypeComplete, Message: "mock execution complete", Usage: &runtime.UsageStats{ InputTokens: len(strings.Fields(prompt)), OutputTokens: len(words), }, Timestamp: time.Now(), }) } func extractPrompt(input map[string]any) string { if input == nil { return "" } if v, ok := input["prompt"]; ok { if s, ok := v.(string); ok { return s } } if v, ok := input["messages"]; ok { return fmt.Sprintf("%v", v) } return fmt.Sprintf("%v", input) }