pi-codebuddy-sdk 0.1.12 → 0.1.13

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/provider.ts +59 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-codebuddy-sdk",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "CodeBuddy Agent SDK provider for Pi — native tool execution, 29+ models, thinking controls, session pool",
5
5
  "author": "slahser",
6
6
  "license": "MIT",
package/src/provider.ts CHANGED
@@ -83,20 +83,70 @@ function extractLatestUserText(context: Context): string {
83
83
  const messages = context.messages;
84
84
  for (let i = messages.length - 1; i >= 0; i--) {
85
85
  if (messages[i].role === "user") {
86
- const content = (messages[i] as any).content;
87
- if (typeof content === "string") return content;
88
- if (Array.isArray(content)) {
89
- const texts = content
90
- .filter((c: any) => c?.type === "text")
91
- .map((c: any) => c.text)
92
- .join("\n");
93
- if (texts) return texts;
94
- }
86
+ let raw = extractRawContent((messages[i] as any).content);
87
+ if (!raw) continue;
88
+ // Strip context-mode session state injection prepended to user messages.
89
+ // Pi's context-mode adds its hierarchy/state before the actual user input.
90
+ raw = stripContextModeInjection(raw);
91
+ if (raw) return raw;
95
92
  }
96
93
  }
97
94
  return "Continue.";
98
95
  }
99
96
 
97
+ function extractRawContent(content: unknown): string {
98
+ if (typeof content === "string") return content;
99
+ if (!Array.isArray(content)) return "";
100
+ return content
101
+ .filter((c: any) => c?.type === "text")
102
+ .map((c: any) => c.text)
103
+ .join("\n");
104
+ }
105
+
106
+ /**
107
+ * Pi context-mode prepends its session state to user messages.
108
+ * Strip it to keep CodeBuddy from treating it as conversation content.
109
+ *
110
+ * Injected format:
111
+ * context-mode active. Hierarchy: ...
112
+ * <session_state source="compaction">
113
+ * <session_mode>investigate</session_mode>
114
+ * </session_state>
115
+ * [actual user message]
116
+ */
117
+ function stripContextModeInjection(text: string): string {
118
+ // Find the end of context-mode injection
119
+ // Pattern: </session_state> followed by newlines then actual message
120
+ const sessionEnd = text.lastIndexOf("</session_state>");
121
+ if (sessionEnd >= 0) {
122
+ const after = text.slice(sessionEnd + "</session_state>".length).trimStart();
123
+ if (after) return after;
124
+ }
125
+
126
+ // Fallback: look for "context-mode active" header and take everything after it + session_state
127
+ const cmStart = text.indexOf("context-mode active.");
128
+ if (cmStart >= 0) {
129
+ // Find first blank line after </session_state> or end of XML
130
+ const afterSession = afterSessionState(text);
131
+ if (afterSession) return afterSession;
132
+ }
133
+
134
+ return text;
135
+ }
136
+
137
+ function afterSessionState(text: string): string | null {
138
+ // Try to find the actual user message after context-mode XML injection
139
+ const patterns = [
140
+ /context-mode active\.[\s\S]*?<\/session_state>\s*\n+([\s\S]+)$/,
141
+ /<session_state[\s\S]*?<\/session_state>\s*\n+([\s\S]+)$/,
142
+ ];
143
+ for (const re of patterns) {
144
+ const m = text.match(re);
145
+ if (m?.[1]?.trim()) return m[1].trim();
146
+ }
147
+ return null;
148
+ }
149
+
100
150
  // ── thinking config mapping ──
101
151
 
102
152
  const DEFAULT_THINKING_BUDGETS: Record<string, number> = {