mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Implements the per-intent rotation shape from #85: a task created with llm_rotate=true distributes worker intents round-robin over its LLM chain heads, so lane A can hunt on one model while lane B hunts on another (different lenses per intent, no extra tokens). Default stays the classic ordered failover from the active head; planner/goals/mainagent keep the active head always. Mechanics: the engine pins the next chain head into the run context when a worker claims an intent; the pin travels through the provider resolver (hooks.current now takes ctx). A pin is only a dispatch preference - it must belong to the task chain and never bypasses failover state (an exhausted chain stays exhausted). Schema: tasks.llm_rotate boolean, default false, idempotent ALTER; exposed on the create payload and the task DTO. Closes #85 (the ensemble/P4 shape stays parked as before)
33 lines
757 B
Go
33 lines
757 B
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestLLMProfilePinRoundTrip(t *testing.T) {
|
|
ctx := context.Background()
|
|
if _, ok := llmProfilePinFrom(ctx); ok {
|
|
t.Fatal("empty context must carry no pin")
|
|
}
|
|
pinned := withLLMProfilePin(ctx, 42)
|
|
got, ok := llmProfilePinFrom(pinned)
|
|
if !ok || got != 42 {
|
|
t.Fatalf("pin roundtrip got=%d ok=%v", got, ok)
|
|
}
|
|
}
|
|
|
|
func TestNextRotatedProfileRoundRobin(t *testing.T) {
|
|
tk := &Task{LLMProfileIDs: []int64{3, 1, 2}}
|
|
want := []int64{3, 1, 2, 3, 1}
|
|
for i, w := range want {
|
|
got, ok := tk.nextRotatedProfile()
|
|
if !ok || got != w {
|
|
t.Fatalf("rotation %d: got=%d ok=%v want=%d", i, got, ok, w)
|
|
}
|
|
}
|
|
if _, ok := (&Task{}).nextRotatedProfile(); ok {
|
|
t.Fatal("empty chain must not rotate")
|
|
}
|
|
}
|