返回 DeepSeek-Reasonix
skill_raw_test.go
根目录 / internal / acp / skill_raw_test.go
1 package acp
2
3 import (
4 "context"
5 "strings"
6 "testing"
7
8 "reasonix/internal/agent"
9 "reasonix/internal/agent/testutil"
10 "reasonix/internal/control"
11 "reasonix/internal/provider"
12 "reasonix/internal/skill"
13 "reasonix/internal/tool"
14 )
15
16 type skillRawFactory struct {
17 provider *testutil.MockProvider
18 executor chan *agent.Agent
19 dir string
20 }
21
22 func (f *skillRawFactory) SessionDir() string { return f.dir }
23
24 func (f *skillRawFactory) NewSession(_ context.Context, p SessionParams) (*control.Controller, error) {
25 executor := agent.New(f.provider, tool.NewRegistry(), agent.NewSession("test agent"),
26 agent.Options{MaxSteps: 2}, p.Sink)
27 ctrl := control.New(control.Options{
28 Runner: executor, Executor: executor, Sink: p.Sink,
29 SessionDir: f.dir,
30 Skills: []skill.Skill{
31 {Name: "probe", Description: "probe skill", Body: "PROBE BODY\nthen /other", Triggers: []string{"probe", "tidy"}, AutoUse: "require"},
32 {Name: "other", Description: "other skill", Body: "OTHER BODY", Triggers: []string{"other"}, AutoUse: "require"},
33 },
34 })
35 f.executor <- executor
36 return ctrl, nil
37 }
38
39 func TestACPSkillPromptKeepsTypedTextAsRawInput(t *testing.T) {
40 factory := &skillRawFactory{
41 provider: testutil.NewMock("test", testutil.Turn{Text: "done"}),
42 executor: make(chan *agent.Agent, 1),
43 dir: t.TempDir(),
44 }
45 client, stop := startServer(t, factory)
46 defer stop()
47 sid := openSession(t, client)
48 executor := <-factory.executor
49
50 const typed = "/probe tidy the notes"
51 prompt := client.callAsync("session/prompt", SessionPromptParams{
52 SessionID: sid,
53 Prompt: []ContentBlock{{Type: "text", Text: typed}},
54 })
55 _, resp := drainPrompt(t, client, prompt)
56 if resp.Error != nil {
57 t.Fatalf("session/prompt: %v", resp.Error)
58 }
59
60 req := factory.provider.LastRequest()
61 if req == nil {
62 t.Fatal("no provider request")
63 }
64 var delivered string
65 for _, msg := range req.Messages {
66 if msg.Role == provider.RoleUser {
67 delivered = msg.Content
68 }
69 }
70 if !strings.Contains(delivered, "PROBE BODY") || !strings.Contains(delivered, "Arguments: tidy the notes") {
71 t.Fatalf("provider did not receive the rendered skill invocation: %q", delivered)
72 }
73 if strings.Contains(delivered, "<capability-route") {
74 t.Fatalf("already-pinned skill was routed again: %q", delivered)
75 }
76 for _, msg := range executor.Session().Snapshot() {
77 if msg.Role == provider.RoleUser && strings.Contains(msg.Content, "PROBE BODY") {
78 if msg.RawContent != typed {
79 t.Fatalf("raw user input = %q, want %q", msg.RawContent, typed)
80 }
81 return
82 }
83 }
84 t.Fatal("no user turn in history")
85 }
86
86 lines GO