@pi-in-go/pigpen-acp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CREDITS.md +23 -0
  2. package/LICENSE +22 -0
  3. package/README.md +110 -0
  4. package/extensions/acp/cmd/pig-acp/e2e_llm_test.go +168 -0
  5. package/extensions/acp/cmd/pig-acp/e2e_test.go +541 -0
  6. package/extensions/acp/cmd/pig-acp/go.mod +6 -0
  7. package/extensions/acp/cmd/pig-acp/internal/acp/agent.go +784 -0
  8. package/extensions/acp/cmd/pig-acp/internal/acp/agent_builtin_test.go +536 -0
  9. package/extensions/acp/cmd/pig-acp/internal/acp/agent_commands_test.go +199 -0
  10. package/extensions/acp/cmd/pig-acp/internal/acp/agent_config_test.go +530 -0
  11. package/extensions/acp/cmd/pig-acp/internal/acp/agent_helpers_test.go +215 -0
  12. package/extensions/acp/cmd/pig-acp/internal/acp/agent_load_test.go +333 -0
  13. package/extensions/acp/cmd/pig-acp/internal/acp/agent_prompt.go +289 -0
  14. package/extensions/acp/cmd/pig-acp/internal/acp/agent_session_test.go +429 -0
  15. package/extensions/acp/cmd/pig-acp/internal/acp/auth.go +61 -0
  16. package/extensions/acp/cmd/pig-acp/internal/acp/bench_test.go +47 -0
  17. package/extensions/acp/cmd/pig-acp/internal/acp/helpers_test.go +421 -0
  18. package/extensions/acp/cmd/pig-acp/internal/acp/main_test.go +28 -0
  19. package/extensions/acp/cmd/pig-acp/internal/acp/mutation_extra_test.go +142 -0
  20. package/extensions/acp/cmd/pig-acp/internal/acp/paths.go +77 -0
  21. package/extensions/acp/cmd/pig-acp/internal/acp/pisessions.go +317 -0
  22. package/extensions/acp/cmd/pig-acp/internal/acp/protocol.go +188 -0
  23. package/extensions/acp/cmd/pig-acp/internal/acp/server.go +218 -0
  24. package/extensions/acp/cmd/pig-acp/internal/acp/server_test.go +386 -0
  25. package/extensions/acp/cmd/pig-acp/internal/acp/session.go +1068 -0
  26. package/extensions/acp/cmd/pig-acp/internal/acp/session_diff_test.go +183 -0
  27. package/extensions/acp/cmd/pig-acp/internal/acp/session_events_test.go +443 -0
  28. package/extensions/acp/cmd/pig-acp/internal/acp/session_extra_test.go +547 -0
  29. package/extensions/acp/cmd/pig-acp/internal/acp/session_usage_test.go +198 -0
  30. package/extensions/acp/cmd/pig-acp/internal/acp/settings.go +79 -0
  31. package/extensions/acp/cmd/pig-acp/internal/acp/slash.go +278 -0
  32. package/extensions/acp/cmd/pig-acp/internal/acp/slash_test.go +128 -0
  33. package/extensions/acp/cmd/pig-acp/internal/acp/startup.go +156 -0
  34. package/extensions/acp/cmd/pig-acp/internal/acp/store.go +118 -0
  35. package/extensions/acp/cmd/pig-acp/internal/acp/store_paths_test.go +466 -0
  36. package/extensions/acp/cmd/pig-acp/internal/acp/translate.go +352 -0
  37. package/extensions/acp/cmd/pig-acp/internal/acp/translate_test.go +105 -0
  38. package/extensions/acp/cmd/pig-acp/internal/acp/twin_test.go +28 -0
  39. package/extensions/acp/cmd/pig-acp/internal/acp/types.go +202 -0
  40. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/bench_test.go +24 -0
  41. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc.go +302 -0
  42. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/jsonrpc_test.go +320 -0
  43. package/extensions/acp/cmd/pig-acp/internal/jsonrpc/twin_test.go +28 -0
  44. package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_unix.go +19 -0
  45. package/extensions/acp/cmd/pig-acp/internal/pirpc/kill_windows.go +11 -0
  46. package/extensions/acp/cmd/pig-acp/internal/pirpc/process.go +530 -0
  47. package/extensions/acp/cmd/pig-acp/internal/pirpc/process_test.go +355 -0
  48. package/extensions/acp/cmd/pig-acp/internal/pirpc/twin_test.go +28 -0
  49. package/extensions/acp/cmd/pig-acp/main.go +177 -0
  50. package/extensions/acp/cmd/pig-acp/main_test.go +213 -0
  51. package/extensions/acp/cmd/pig-acp/sigpipe_unix.go +10 -0
  52. package/extensions/acp/cmd/pig-acp/sigpipe_windows.go +5 -0
  53. package/extensions/acp/cmd/pig-acp/testdata/ask/extension.go +28 -0
  54. package/extensions/acp/cmd/pig-acp/testdata/ask/go.mod +7 -0
  55. package/extensions/acp/cmd/pig-acp/testdata/ask/go.sum +2 -0
  56. package/extensions/acp/cmd/pig-acp/testdata/gate/extension.go +37 -0
  57. package/extensions/acp/cmd/pig-acp/testdata/gate/go.mod +7 -0
  58. package/extensions/acp/cmd/pig-acp/testdata/gate/go.sum +2 -0
  59. package/extensions/acp/cmd/pig-acp/twin_test.go +28 -0
  60. package/extensions/acp/extension.go +63 -0
  61. package/extensions/acp/extension_test.go +111 -0
  62. package/extensions/acp/fakehost_test.go +548 -0
  63. package/extensions/acp/go.mod +6 -0
  64. package/extensions/acp/go.sum +2 -0
  65. package/package.json +41 -0
  66. package/port/PORT.md +147 -0
  67. package/port/interop/package-lock.json +89 -0
  68. package/port/interop/package.json +13 -0
  69. package/port/interop/run.mjs +229 -0
  70. package/port/mutate.mjs +110 -0
  71. package/port/mutation-results.txt +107 -0
  72. package/port/mutations.json +748 -0
  73. package/port/oracle/pi-acp/LICENSE +21 -0
  74. package/port/oracle/pi-acp/README.md +209 -0
  75. package/port/oracle/pi-acp/package.json +65 -0
  76. package/port/oracle/pi-acp/src/acp/agent.ts +1661 -0
  77. package/port/oracle/pi-acp/src/acp/auth-required.ts +37 -0
  78. package/port/oracle/pi-acp/src/acp/auth.ts +59 -0
  79. package/port/oracle/pi-acp/src/acp/paths.ts +15 -0
  80. package/port/oracle/pi-acp/src/acp/pi-commands.ts +59 -0
  81. package/port/oracle/pi-acp/src/acp/pi-sessions.ts +333 -0
  82. package/port/oracle/pi-acp/src/acp/pi-settings.ts +75 -0
  83. package/port/oracle/pi-acp/src/acp/session-store.ts +68 -0
  84. package/port/oracle/pi-acp/src/acp/session.ts +1078 -0
  85. package/port/oracle/pi-acp/src/acp/slash-commands.ts +197 -0
  86. package/port/oracle/pi-acp/src/acp/translate/bash.ts +100 -0
  87. package/port/oracle/pi-acp/src/acp/translate/pi-messages.ts +17 -0
  88. package/port/oracle/pi-acp/src/acp/translate/pi-tools.ts +51 -0
  89. package/port/oracle/pi-acp/src/acp/translate/prompt.ts +71 -0
  90. package/port/oracle/pi-acp/src/index.ts +82 -0
  91. package/port/oracle/pi-acp/src/pi-rpc/command.ts +16 -0
  92. package/port/oracle/pi-acp/src/pi-rpc/process.ts +432 -0
  93. package/port/oracle/pi-acp/test/component/agent-steering-followup-modes.test.ts +143 -0
  94. package/port/oracle/pi-acp/test/component/session-diff.test.ts +214 -0
  95. package/port/oracle/pi-acp/test/component/session-events.test.ts +1102 -0
  96. package/port/oracle/pi-acp/test/component/session-list-and-load.test.ts +129 -0
  97. package/port/oracle/pi-acp/test/component/session-list-custom-session-dir.test.ts +52 -0
  98. package/port/oracle/pi-acp/test/component/session-list-scoped.test.ts +76 -0
  99. package/port/oracle/pi-acp/test/component/session-load-toolresult.test.ts +68 -0
  100. package/port/oracle/pi-acp/test/component/session-queue-cancel.test.ts +43 -0
  101. package/port/oracle/pi-acp/test/component/session-slash-commands.test.ts +37 -0
  102. package/port/oracle/pi-acp/test/component/session-thinking-modes.test.ts +22 -0
  103. package/port/oracle/pi-acp/test/component/session-title-long-session.test.ts +56 -0
  104. package/port/oracle/pi-acp/test/component/session-updatedAt-message-only.test.ts +57 -0
  105. package/port/oracle/pi-acp/test/helpers/fakes.ts +87 -0
  106. package/port/oracle/pi-acp/test/unit/auth-methods-terminal-auth-meta.test.ts +22 -0
  107. package/port/oracle/pi-acp/test/unit/builtin-commands.test.ts +60 -0
  108. package/port/oracle/pi-acp/test/unit/context-usage.test.ts +204 -0
  109. package/port/oracle/pi-acp/test/unit/merge-commands.test.ts +19 -0
  110. package/port/oracle/pi-acp/test/unit/model-thinking-levels.test.ts +268 -0
  111. package/port/oracle/pi-acp/test/unit/new-session-auth-required-when-no-models.test.ts +51 -0
  112. package/port/oracle/pi-acp/test/unit/new-session-pi-not-found.test.ts +26 -0
  113. package/port/oracle/pi-acp/test/unit/new-session-runtime-startup-errors.test.ts +148 -0
  114. package/port/oracle/pi-acp/test/unit/pi-command.test.ts +44 -0
  115. package/port/oracle/pi-acp/test/unit/pi-commands.test.ts +32 -0
  116. package/port/oracle/pi-acp/test/unit/pi-enable-embed-context-flag.test.ts +35 -0
  117. package/port/oracle/pi-acp/test/unit/pi-messages.test.ts +29 -0
  118. package/port/oracle/pi-acp/test/unit/pi-rpc-request-timeout.test.ts +137 -0
  119. package/port/oracle/pi-acp/test/unit/pi-rpc-session-path.test.ts +93 -0
  120. package/port/oracle/pi-acp/test/unit/pi-tools.test.ts +40 -0
  121. package/port/oracle/pi-acp/test/unit/prompt-to-pi-message.test.ts +74 -0
  122. package/port/oracle/pi-acp/test/unit/session-config-options.test.ts +217 -0
  123. package/port/oracle/pi-acp/test/unit/session-delete.test.ts +170 -0
  124. package/port/oracle/pi-acp/test/unit/session-restore.test.ts +239 -0
  125. package/port/oracle/pi-acp/test/unit/slash-commands.test.ts +36 -0
  126. package/port/oracle/pi-acp/test/unit/startup-info-env.test.ts +84 -0
  127. package/port/oracle/pi-acp/test/unit/startup-info-load-session.test.ts +53 -0
  128. package/port/oracle/pi-acp/test/unit/startup-info-project-packages.test.ts +74 -0
  129. package/port/oracle/pi-acp/test/unit/stdout-destroyed-does-not-crash.test.ts +32 -0
  130. package/port/oracle/pi-acp/test/unit/thinking-level-rpc.test.ts +43 -0
  131. package/port/schema/LICENSE +191 -0
  132. package/port/schema/schema.json +8015 -0
  133. package/port/upstream-tests.json +201 -0
  134. package/provenance.json +28 -0
@@ -0,0 +1,199 @@
1
+ package acp
2
+
3
+ // Twins of test/component/agent-steering-followup-modes.test.ts and
4
+ // test/unit/builtin-commands.test.ts, test/unit/pi-enable-embed-context-flag.test.ts,
5
+ // test/component/session-thinking-modes.test.ts.
6
+
7
+ import (
8
+ "regexp"
9
+ "testing"
10
+ )
11
+
12
+ func promptText(sessionID, text string) PromptRequest {
13
+ return PromptRequest{SessionID: sessionID, Prompt: []ContentBlock{{"type": "text", "text": text}}}
14
+ }
15
+
16
+ func lastChunkText(t *testing.T, c *fakeConn) string {
17
+ t.Helper()
18
+ ups := c.all()
19
+ if len(ups) == 0 {
20
+ t.Fatal("no updates")
21
+ }
22
+ last := ups[len(ups)-1].Update
23
+ if last["sessionUpdate"] != "agent_message_chunk" {
24
+ t.Fatalf("last update = %v", last)
25
+ }
26
+ return str(last["content"].(map[string]any)["text"])
27
+ }
28
+
29
+ func modeAgent(state map[string]any, proc *fakeProc) (*Agent, *fakeConn) {
30
+ conn := newFakeConn()
31
+ proc.getStateFn = func() (map[string]any, error) { return state, nil }
32
+ a, _ := testAgent(conn)
33
+ a.sessions = &fakeSessions{session: &fakeSession{id: "s1", proc: proc}, anyID: true}
34
+ return a, conn
35
+ }
36
+
37
+ func TestSteeringFollowUpModes(t *testing.T) {
38
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /steering reports current steeringMode", func(t *testing.T) {
39
+ a, conn := modeAgent(map[string]any{"steeringMode": "all"}, newFakeProc())
40
+ res, err := a.Prompt(promptText("s1", "/steering"))
41
+ if err != nil || res.StopReason != StopEndTurn {
42
+ t.Fatalf("res=%v err=%v", res, err)
43
+ }
44
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Steering mode: all`).MatchString(got) {
45
+ t.Errorf("text = %q", got)
46
+ }
47
+ })
48
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /steering sets steering mode", func(t *testing.T) {
49
+ proc := newFakeProc()
50
+ var setTo string
51
+ proc.setSteeringFn = func(m string) error { setTo = m; return nil }
52
+ a, conn := modeAgent(map[string]any{"steeringMode": "all"}, proc)
53
+ res, err := a.Prompt(promptText("s1", "/steering one-at-a-time"))
54
+ if err != nil || res.StopReason != StopEndTurn || setTo != "one-at-a-time" {
55
+ t.Fatalf("res=%v err=%v setTo=%q", res, err, setTo)
56
+ }
57
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Steering mode set to: one-at-a-time`).MatchString(got) {
58
+ t.Errorf("text = %q", got)
59
+ }
60
+ })
61
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /steering rejects invalid value", func(t *testing.T) {
62
+ proc := newFakeProc()
63
+ called := false
64
+ proc.setSteeringFn = func(string) error { called = true; return nil }
65
+ a, conn := modeAgent(map[string]any{"steeringMode": "all"}, proc)
66
+ res, err := a.Prompt(promptText("s1", "/steering nope"))
67
+ if err != nil || res.StopReason != StopEndTurn || called {
68
+ t.Fatalf("res=%v err=%v called=%v", res, err, called)
69
+ }
70
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Usage: /steering`).MatchString(got) {
71
+ t.Errorf("text = %q", got)
72
+ }
73
+ })
74
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /follow-up reports current followUpMode", func(t *testing.T) {
75
+ a, conn := modeAgent(map[string]any{"followUpMode": "one-at-a-time"}, newFakeProc())
76
+ res, err := a.Prompt(promptText("s1", "/follow-up"))
77
+ if err != nil || res.StopReason != StopEndTurn {
78
+ t.Fatalf("res=%v err=%v", res, err)
79
+ }
80
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Follow-up mode: one-at-a-time`).MatchString(got) {
81
+ t.Errorf("text = %q", got)
82
+ }
83
+ })
84
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /follow-up sets follow-up mode", func(t *testing.T) {
85
+ proc := newFakeProc()
86
+ var setTo string
87
+ proc.setFollowUpFn = func(m string) error { setTo = m; return nil }
88
+ a, conn := modeAgent(map[string]any{"followUpMode": "one-at-a-time"}, proc)
89
+ res, err := a.Prompt(promptText("s1", "/follow-up all"))
90
+ if err != nil || res.StopReason != StopEndTurn || setTo != "all" {
91
+ t.Fatalf("res=%v err=%v setTo=%q", res, err, setTo)
92
+ }
93
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Follow-up mode set to: all`).MatchString(got) {
94
+ t.Errorf("text = %q", got)
95
+ }
96
+ })
97
+ tw(t, "component/agent-steering-followup-modes", "PiAcpAgent: /follow-up rejects invalid value", func(t *testing.T) {
98
+ proc := newFakeProc()
99
+ called := false
100
+ proc.setFollowUpFn = func(string) error { called = true; return nil }
101
+ a, conn := modeAgent(map[string]any{"followUpMode": "one-at-a-time"}, proc)
102
+ res, err := a.Prompt(promptText("s1", "/follow-up ???"))
103
+ if err != nil || res.StopReason != StopEndTurn || called {
104
+ t.Fatalf("res=%v err=%v called=%v", res, err, called)
105
+ }
106
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Usage: /follow-up`).MatchString(got) {
107
+ t.Errorf("text = %q", got)
108
+ }
109
+ })
110
+ }
111
+
112
+ func TestBuiltinCommands(t *testing.T) {
113
+ tw(t, "unit/builtin-commands", "PiAcpAgent: /steering is handled adapter-side", func(t *testing.T) {
114
+ proc := newFakeProc()
115
+ a, conn := modeAgent(map[string]any{"steeringMode": "one-at-a-time"}, proc)
116
+ res, err := a.Prompt(promptText("s1", "/steering"))
117
+ if err != nil || res.StopReason != StopEndTurn {
118
+ t.Fatalf("res=%v err=%v", res, err)
119
+ }
120
+ if n := len(proc.promptList()); n != 0 {
121
+ t.Errorf("%d prompts reached pi", n)
122
+ }
123
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Steering mode: one-at-a-time`).MatchString(got) {
124
+ t.Errorf("text = %q", got)
125
+ }
126
+ })
127
+ tw(t, "unit/builtin-commands", "PiAcpAgent: /name sets session display name adapter-side", func(t *testing.T) {
128
+ proc := newFakeProc()
129
+ var setTo string
130
+ proc.setSessionNameFn = func(n string) error { setTo = n; return nil }
131
+ a, conn := modeAgent(map[string]any{}, proc)
132
+ res, err := a.Prompt(promptText("s1", "/name My Session"))
133
+ if err != nil || res.StopReason != StopEndTurn {
134
+ t.Fatalf("res=%v err=%v", res, err)
135
+ }
136
+ if n := len(proc.promptList()); n != 0 || setTo != "My Session" {
137
+ t.Errorf("prompts=%d setTo=%q", n, setTo)
138
+ }
139
+ info := conn.ofKind("session_info_update")
140
+ if len(info) == 0 || info[0].Update["title"] != "My Session" {
141
+ t.Errorf("session_info_update = %v", info)
142
+ }
143
+ if got := lastChunkText(t, conn); !regexp.MustCompile(`Session name set: My Session`).MatchString(got) {
144
+ t.Errorf("text = %q", got)
145
+ }
146
+ })
147
+ }
148
+
149
+ func TestEmbeddedContextFlag(t *testing.T) {
150
+ initWith := func(t *testing.T, key, value string, set bool) bool {
151
+ t.Helper()
152
+ t.Setenv("PI_ACP_ENABLE_EMBEDDED_CONTEXT", "")
153
+ t.Setenv("PIG_ACP_ENABLE_EMBEDDED_CONTEXT", "")
154
+ if set {
155
+ t.Setenv(key, value)
156
+ }
157
+ a, _ := testAgent(newFakeConn())
158
+ res, err := a.Initialize(InitializeRequest{ProtocolVersion: 1})
159
+ if err != nil {
160
+ t.Fatal(err)
161
+ }
162
+ return res.AgentCapabilities.PromptCapabilities.EmbeddedContext
163
+ }
164
+ tw(t, "unit/pi-enable-embed-context-flag", "PI_ACP_ENABLE_EMBEDDED_CONTEXT: defaults embeddedContext to false when undefined", func(t *testing.T) {
165
+ if initWith(t, "", "", false) {
166
+ t.Error("enabled by default")
167
+ }
168
+ })
169
+ tw(t, "unit/pi-enable-embed-context-flag", "PI_ACP_ENABLE_EMBEDDED_CONTEXT: 'false' keeps embeddedContext disabled", func(t *testing.T) {
170
+ if initWith(t, "PI_ACP_ENABLE_EMBEDDED_CONTEXT", "false", true) {
171
+ t.Error("enabled")
172
+ }
173
+ })
174
+ tw(t, "unit/pi-enable-embed-context-flag", "PI_ACP_ENABLE_EMBEDDED_CONTEXT: 'true' enables embeddedContext", func(t *testing.T) {
175
+ if !initWith(t, "PI_ACP_ENABLE_EMBEDDED_CONTEXT", "true", true) {
176
+ t.Error("not enabled")
177
+ }
178
+ })
179
+ // PiG spelling: PIG_ACP_* is the name, PI_ACP_* stays accepted (Pi compatibility rule).
180
+ t.Run("PIG_ACP_ENABLE_EMBEDDED_CONTEXT: 'true' enables embeddedContext", func(t *testing.T) {
181
+ if !initWith(t, "PIG_ACP_ENABLE_EMBEDDED_CONTEXT", "true", true) {
182
+ t.Error("not enabled")
183
+ }
184
+ })
185
+ }
186
+
187
+ func TestSessionThinkingModes(t *testing.T) {
188
+ tw(t, "component/session-thinking-modes", "PiAcpAgent: setSessionMode maps to pi setThinkingLevel + emits current_mode_update", func(t *testing.T) {
189
+ // The original only asserts that an unknown session is rejected as invalid params.
190
+ a, _ := testAgent(newFakeConn())
191
+ a.sessions = NewSessionManager(nil, newMemStore())
192
+ a.store = newMemStore()
193
+ _, err := a.SetSessionMode(SetSessionModeRequest{SessionID: "nope", ModeID: "invalid"})
194
+ re, ok := err.(*RequestError)
195
+ if !ok || re.Code != -32602 || !regexp.MustCompile(`(?i)invalid params`).MatchString(re.Message) {
196
+ t.Fatalf("err = %v", err)
197
+ }
198
+ })
199
+ }