diff --git a/cmd/entire/cli/agent/opencode/transcript.go b/cmd/entire/cli/agent/opencode/transcript.go
index fabe2bd1d..b7b5f43f2 100644
--- a/cmd/entire/cli/agent/opencode/transcript.go
+++ b/cmd/entire/cli/agent/opencode/transcript.go
@@ -209,8 +209,48 @@ func ExtractTextFromParts(parts []Part) string {
return strings.Join(texts, "\n")
}
+// Tags used by oh-my-opencode and similar orchestration tools to inject
+// context into the conversation with role "user" — not actual user prompts.
+const (
+ systemReminderOpen = ""
+ systemReminderClose = ""
+)
+
+// isSystemReminderOnly reports whether content consists entirely of
+// ... blocks (after trimming whitespace).
+// Delegates to stripSystemReminders to correctly handle multiple blocks
+// (HasPrefix+HasSuffix would false-positive on "arealb").
+func isSystemReminderOnly(content string) bool {
+ if strings.TrimSpace(content) == "" {
+ return false
+ }
+ return stripSystemReminders(content) == ""
+}
+
+// stripSystemReminders removes all ...
+// sections from content and returns the remaining text. If nothing remains
+// after stripping (or the content was system-reminder-only), it returns "".
+func stripSystemReminders(content string) string {
+ result := content
+ for {
+ start := strings.Index(result, systemReminderOpen)
+ if start == -1 {
+ break
+ }
+ end := strings.Index(result[start:], systemReminderClose)
+ if end == -1 {
+ break
+ }
+ end += start + len(systemReminderClose)
+ result = result[:start] + result[end:]
+ }
+ return strings.TrimSpace(result)
+}
+
// ExtractAllUserPrompts extracts all user prompts from raw export JSON transcript bytes.
// This is a package-level function used by the condensation path.
+// Messages that consist entirely of tags (e.g. from oh-my-opencode)
+// are excluded. Mixed messages have their system-reminder sections stripped.
func ExtractAllUserPrompts(data []byte) ([]string, error) {
session, err := ParseExportSession(data)
if err != nil {
@@ -226,6 +266,13 @@ func ExtractAllUserPrompts(data []byte) ([]string, error) {
continue
}
content := ExtractTextFromParts(msg.Parts)
+ if content == "" {
+ continue
+ }
+ if isSystemReminderOnly(content) {
+ continue
+ }
+ content = stripSystemReminders(content)
if content != "" {
prompts = append(prompts, content)
}
diff --git a/cmd/entire/cli/agent/opencode/transcript_test.go b/cmd/entire/cli/agent/opencode/transcript_test.go
index 5bcd6e57e..1395226b2 100644
--- a/cmd/entire/cli/agent/opencode/transcript_test.go
+++ b/cmd/entire/cli/agent/opencode/transcript_test.go
@@ -668,6 +668,226 @@ func TestExtractModifiedFiles(t *testing.T) {
}
}
+func TestExtractAllUserPrompts(t *testing.T) {
+ t.Parallel()
+
+ prompts, err := ExtractAllUserPrompts([]byte(testExportJSON))
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(prompts) != 2 {
+ t.Fatalf("expected 2 prompts, got %d: %v", len(prompts), prompts)
+ }
+ if prompts[0] != "Fix the bug in main.go" {
+ t.Errorf("expected first prompt 'Fix the bug in main.go', got %q", prompts[0])
+ }
+ if prompts[1] != "Also fix util.go" {
+ t.Errorf("expected second prompt 'Also fix util.go', got %q", prompts[1])
+ }
+}
+
+func TestExtractAllUserPrompts_SystemReminderOnly(t *testing.T) {
+ t.Parallel()
+
+ session := ExportSession{
+ Info: SessionInfo{ID: "test-sysreminder"},
+ Messages: []ExportMessage{
+ {
+ Info: MessageInfo{ID: "msg-1", Role: "user"},
+ Parts: []Part{
+ {Type: "text", Text: "Fix the bug"},
+ },
+ },
+ {
+ Info: MessageInfo{ID: "msg-2", Role: "user"},
+ Parts: []Part{
+ {Type: "text", Text: "\nAs you answer the user's questions, you can use the following context:\nContents of CLAUDE.md...\n"},
+ },
+ },
+ {
+ Info: MessageInfo{ID: "msg-3", Role: "user"},
+ Parts: []Part{
+ {Type: "text", Text: "Now fix util.go"},
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(session)
+ if err != nil {
+ t.Fatalf("failed to marshal: %v", err)
+ }
+
+ prompts, err := ExtractAllUserPrompts(data)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(prompts) != 2 {
+ t.Fatalf("expected 2 prompts (system-reminder excluded), got %d: %v", len(prompts), prompts)
+ }
+ if prompts[0] != "Fix the bug" {
+ t.Errorf("expected 'Fix the bug', got %q", prompts[0])
+ }
+ if prompts[1] != "Now fix util.go" {
+ t.Errorf("expected 'Now fix util.go', got %q", prompts[1])
+ }
+}
+
+func TestExtractAllUserPrompts_SystemReminderMixed(t *testing.T) {
+ t.Parallel()
+
+ session := ExportSession{
+ Info: SessionInfo{ID: "test-mixed"},
+ Messages: []ExportMessage{
+ {
+ Info: MessageInfo{ID: "msg-1", Role: "user"},
+ Parts: []Part{
+ {Type: "text", Text: "Fix the bug\n\nCLAUDE.md contents here\n"},
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(session)
+ if err != nil {
+ t.Fatalf("failed to marshal: %v", err)
+ }
+
+ prompts, err := ExtractAllUserPrompts(data)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(prompts) != 1 {
+ t.Fatalf("expected 1 prompt, got %d: %v", len(prompts), prompts)
+ }
+ if prompts[0] != "Fix the bug" {
+ t.Errorf("expected 'Fix the bug', got %q", prompts[0])
+ }
+}
+
+func TestExtractAllUserPrompts_SystemReminderWithWhitespace(t *testing.T) {
+ t.Parallel()
+
+ session := ExportSession{
+ Info: SessionInfo{ID: "test-whitespace"},
+ Messages: []ExportMessage{
+ {
+ Info: MessageInfo{ID: "msg-1", Role: "user"},
+ Parts: []Part{
+ {Type: "text", Text: " \n\nsome context\n\n "},
+ },
+ },
+ },
+ }
+ data, err := json.Marshal(session)
+ if err != nil {
+ t.Fatalf("failed to marshal: %v", err)
+ }
+
+ prompts, err := ExtractAllUserPrompts(data)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(prompts) != 0 {
+ t.Fatalf("expected 0 prompts (whitespace + system-reminder), got %d: %v", len(prompts), prompts)
+ }
+}
+
+func TestIsSystemReminderOnly(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ content string
+ want bool
+ }{
+ {
+ name: "exact system-reminder",
+ content: "context here",
+ want: true,
+ },
+ {
+ name: "with surrounding whitespace",
+ content: " \ncontext\n ",
+ want: true,
+ },
+ {
+ name: "not system-reminder",
+ content: "Fix the bug",
+ want: false,
+ },
+ {
+ name: "mixed content",
+ content: "Fix the bug\ncontext",
+ want: false,
+ },
+ {
+ name: "empty",
+ content: "",
+ want: false,
+ },
+ {
+ // Multiple blocks with real content between them — starts with open tag
+ // and ends with close tag, but is NOT system-reminder-only.
+ name: "real content between multiple blocks",
+ content: "aFix thisb",
+ want: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+ if got := isSystemReminderOnly(tt.content); got != tt.want {
+ t.Errorf("isSystemReminderOnly(%q) = %v, want %v", tt.content, got, tt.want)
+ }
+ })
+ }
+}
+
+func TestStripSystemReminders(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ content string
+ want string
+ }{
+ {
+ name: "no system-reminder",
+ content: "Fix the bug",
+ want: "Fix the bug",
+ },
+ {
+ name: "only system-reminder",
+ content: "context",
+ want: "",
+ },
+ {
+ name: "mixed content",
+ content: "Fix the bug\ncontext",
+ want: "Fix the bug",
+ },
+ {
+ name: "system-reminder in middle",
+ content: "First part\ncontext\nSecond part",
+ want: "First part\n\nSecond part",
+ },
+ {
+ name: "multiple system-reminders",
+ content: "aFix thisb",
+ want: "Fix this",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+ if got := stripSystemReminders(tt.content); got != tt.want {
+ t.Errorf("stripSystemReminders(%q) = %q, want %q", tt.content, got, tt.want)
+ }
+ })
+ }
+}
+
// Compile-time interface checks are in transcript.go.
// Verify the unused import guard by referencing the agent package.
var _ = agent.AgentNameOpenCode