iop/apps/node/internal/adapters/mock/mock.go
toki 2d6fde0876 기능: IOP 모노레포 스캐폴드 초기 구현
apps/node 중심 구현 — TCP+JSON transport, Hexagonal Architecture,
mock/cli adapter, fx DI, SQLite 실행 이력 저장.
edge/control-plane/worker는 cobra placeholder.
유닛 테스트 및 통합 테스트 클라이언트 계획서 추가.
2026-05-02 13:20:35 +09:00

95 lines
2 KiB
Go

// 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,
Models: []string{"mock-echo", "mock-stream"},
MaxConcurrency: 16,
}, 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)
}