@ramarivera/coding-buddy 0.4.0-alpha.9 → 0.7.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.
- package/.claude-plugin/marketplace.json +45 -0
- package/.claude-plugin/plugin.json +30 -0
- package/LICENSE +1 -1
- package/README.md +96 -45
- package/adapters/omp/commands.ts +201 -0
- package/adapters/omp/context.ts +22 -0
- package/adapters/omp/events.ts +551 -0
- package/adapters/omp/identity.ts +10 -0
- package/adapters/omp/index.ts +39 -0
- package/adapters/omp/logger.ts +52 -0
- package/adapters/omp/prompt.ts +60 -0
- package/adapters/omp/renderers.ts +73 -0
- package/adapters/omp/storage.ts +25 -0
- package/adapters/omp/ui.ts +85 -0
- package/adapters/pi/commands.ts +64 -37
- package/adapters/pi/events.ts +147 -72
- package/adapters/pi/index.ts +9 -4
- package/adapters/pi/storage.ts +14 -285
- package/adapters/pi/ui.ts +56 -5
- package/adapters/shared/file-storage.ts +526 -0
- package/{adapters/claude/install → cli}/backup.ts +130 -33
- package/cli/buddy-shell.ts +1 -1
- package/{adapters/claude/install → cli}/disable.ts +19 -32
- package/cli/doctor.ts +231 -0
- package/{adapters/claude/install → cli}/hunt.ts +7 -9
- package/cli/index.ts +30 -26
- package/{adapters/claude/install → cli}/install.ts +65 -83
- package/{adapters/claude/install → cli}/pick.ts +136 -57
- package/{adapters/claude/install → cli}/settings.ts +2 -2
- package/{adapters/claude/install → cli}/show.ts +4 -4
- package/{adapters/claude/install → cli}/test-statusline.sh +2 -2
- package/{adapters/claude/install → cli}/test-statusline.ts +21 -11
- package/cli/tui.tsx +106 -17
- package/{adapters/claude/install → cli}/uninstall.ts +40 -47
- package/cli/upgrade.ts +46 -13
- package/cli/validate-species.ts +209 -0
- package/cli/verify.ts +3 -3
- package/core/achievements.ts +12 -20
- package/core/art-data.ts +26 -0
- package/core/command-service.ts +99 -97
- package/core/engine.ts +83 -1
- package/core/ports.ts +10 -0
- package/core/reactions.ts +533 -95
- package/core/slot-slug.ts +22 -0
- package/{adapters/claude/hooks → hooks}/buddy-comment.sh +22 -9
- package/hooks/file-type-react.sh +403 -0
- package/hooks/hooks.json +52 -0
- package/hooks/mood-react.sh +210 -0
- package/{adapters/claude/hooks → hooks}/name-react.sh +3 -4
- package/hooks/react.sh +1364 -0
- package/hooks/suggest.sh +55 -0
- package/package.json +70 -31
- package/scripts/gen-emoji-widths.ts +34 -0
- package/scripts/paths.sh +33 -2
- package/scripts/postinstall.cjs +42 -0
- package/scripts/snapshot-statusline.sh +54 -0
- package/server/achievements.ts +1419 -15
- package/server/art.ts +450 -1
- package/server/award-xp.ts +48 -0
- package/server/check-suggestions.ts +102 -0
- package/server/consolidate.ts +33 -0
- package/{adapters/claude/server → server}/index.ts +556 -95
- package/server/mcp-launcher.sh +16 -6
- package/server/memory.ts +404 -0
- package/server/mood.ts +254 -0
- package/server/path.ts +70 -18
- package/server/shift-mood.ts +43 -0
- package/server/state.ts +552 -3
- package/server/suggestions.ts +335 -0
- package/server/theme.ts +53 -0
- package/server/xp.ts +435 -0
- package/{adapters/claude/skills → skills}/buddy/SKILL.md +36 -7
- package/statusline/buddy-status.sh +402 -0
- package/statusline/combined-status.sh +135 -0
- package/statusline/emoji-widths.data +4 -0
- package/adapters/claude/hooks/hooks.json +0 -35
- package/adapters/claude/hooks/react.sh +0 -207
- package/adapters/claude/install/doctor.ts +0 -172
- package/adapters/claude/plugin/marketplace.json +0 -40
- package/adapters/claude/plugin/plugin.json +0 -26
- package/adapters/claude/rendering/art.ts +0 -264
- package/adapters/claude/server/instructions.ts +0 -24
- package/adapters/claude/server/path.ts +0 -12
- package/adapters/claude/server/resources.ts +0 -38
- package/adapters/claude/statusline/buddy-status.sh +0 -408
- package/adapters/claude/storage/achievements.ts +0 -253
- package/adapters/claude/storage/identity.ts +0 -13
- package/adapters/claude/storage/paths.ts +0 -33
- package/adapters/claude/storage/settings.ts +0 -91
- package/adapters/claude/storage/state.ts +0 -365
- package/adapters/pi/README.md +0 -83
- package/adapters/pi/tools.ts +0 -6
- package/server/engine.ts +0 -1
- package/server/reactions.ts +0 -1
package/adapters/pi/events.ts
CHANGED
|
@@ -10,25 +10,30 @@ import type {
|
|
|
10
10
|
import { isBashToolResult } from "@mariozechner/pi-coding-agent";
|
|
11
11
|
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
|
12
12
|
import { complete, type AssistantMessage, type TextContent, type UserMessage } from "@mariozechner/pi-ai";
|
|
13
|
-
import { BuddyCommandService } from "../../core/command-service.ts";
|
|
13
|
+
import { BuddyCommandService, type ReactionResult } from "../../core/command-service.ts";
|
|
14
14
|
import type { Achievement } from "../../core/achievements.ts";
|
|
15
15
|
import type { BuddyTurnCommentModelConfig, Companion } from "../../core/model.ts";
|
|
16
|
-
import { getNameReaction, getSuccessReaction } from "../../core/reactions.ts";
|
|
16
|
+
import { getNameReaction, getSuccessReaction, isNameMentioned } from "../../core/reactions.ts";
|
|
17
17
|
import { PiBuddyStorage } from "./storage.ts";
|
|
18
18
|
import { buildBuddyReactionPrompt, buildBuddyReactionSystemPrompt, normalizeBuddyComment, stripBuddyComments } from "./prompt.ts";
|
|
19
19
|
import { PiBuddyUI } from "./ui.ts";
|
|
20
|
-
import { PiBuddyLogger } from "./logger.ts";
|
|
21
20
|
|
|
21
|
+
export interface PiBuddyLog {
|
|
22
|
+
info(event: string, data?: Record<string, unknown>): void;
|
|
23
|
+
warn(event: string, data?: Record<string, unknown>): void;
|
|
24
|
+
error(event: string, data?: Record<string, unknown>): void;
|
|
25
|
+
debug(event: string, data?: Record<string, unknown>): void;
|
|
26
|
+
}
|
|
22
27
|
interface RegisterBuddyEventsDeps {
|
|
23
28
|
service: BuddyCommandService;
|
|
24
29
|
storage: PiBuddyStorage;
|
|
25
30
|
ui: PiBuddyUI;
|
|
26
|
-
logger:
|
|
31
|
+
logger: PiBuddyLog;
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsDeps): void {
|
|
30
35
|
pi.on("session_start", async (_event: SessionStartEvent, ctx: ExtensionContext) => {
|
|
31
|
-
const result = deps.service.
|
|
36
|
+
const result = deps.service.startSession();
|
|
32
37
|
deps.logger.info("session_start", {
|
|
33
38
|
companion: result.companion.name,
|
|
34
39
|
species: result.companion.bones.species,
|
|
@@ -37,8 +42,8 @@ export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsD
|
|
|
37
42
|
deps.ui.refresh(ctx, result.companion, deps.storage.loadLatest(), result.achievements);
|
|
38
43
|
if (result.created) {
|
|
39
44
|
ctx.ui.notify(`A new buddy hatched: ${result.companion.name}`, "info");
|
|
40
|
-
deps.ui.notifyAchievements(ctx, result.achievements);
|
|
41
45
|
}
|
|
46
|
+
deps.ui.notifyAchievements(ctx, result.achievements);
|
|
42
47
|
});
|
|
43
48
|
|
|
44
49
|
pi.on("input", async (event: InputEvent, ctx: ExtensionContext): Promise<InputEventResult> => {
|
|
@@ -51,15 +56,14 @@ export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsD
|
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
const companion = deps.service.ensureCompanion().companion;
|
|
54
|
-
|
|
55
|
-
if (!pattern.test(event.text)) {
|
|
59
|
+
if (!isNameMentioned(event.text, companion.name)) {
|
|
56
60
|
return { action: "continue" };
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
deps.logger.info("name_mention_detected", {
|
|
60
64
|
companion: companion.name,
|
|
61
65
|
species: companion.bones.species,
|
|
62
|
-
|
|
66
|
+
textLength: event.text.length,
|
|
63
67
|
});
|
|
64
68
|
|
|
65
69
|
const reaction = getNameReaction(companion.bones.species);
|
|
@@ -74,44 +78,68 @@ export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsD
|
|
|
74
78
|
deps.logger.debug("tool_result_skipped", { reason: "muted" });
|
|
75
79
|
return;
|
|
76
80
|
}
|
|
77
|
-
if (!shouldEmitPassiveReaction(deps.storage)) {
|
|
78
|
-
deps.logger.debug("tool_result_skipped", { reason: "cooldown" });
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
81
|
|
|
82
82
|
const text = extractToolText(event);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| ReturnType<BuddyCommandService["recordTestFailure"]>
|
|
86
|
-
| ReturnType<BuddyCommandService["recordLargeDiff"]>
|
|
87
|
-
| ReturnType<BuddyCommandService["recordComment"]>
|
|
88
|
-
| undefined;
|
|
89
|
-
|
|
83
|
+
const canEmit = shouldEmitPassiveReaction(deps.storage);
|
|
84
|
+
let result: ReactionResult | undefined;
|
|
90
85
|
const companion = deps.service.ensureCompanion().companion;
|
|
91
|
-
if (event
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
if (isBashToolResult(event)) {
|
|
87
|
+
if (looksLikeTestFailure(text)) {
|
|
88
|
+
const count = extractFailureCount(text);
|
|
89
|
+
if (canEmit) {
|
|
90
|
+
result = deps.service.recordTestFailure(undefined, count);
|
|
91
|
+
} else {
|
|
92
|
+
const achievements = deps.service.trackTestFailure(undefined, count);
|
|
93
|
+
if (achievements.length > 0) { deps.ui.refresh(ctx, companion, deps.storage.loadLatest(), achievements); }
|
|
94
|
+
}
|
|
95
|
+
} else if (event.isError) {
|
|
96
|
+
const line = firstLineNumber(text);
|
|
97
|
+
if (canEmit) {
|
|
98
|
+
result = deps.service.recordToolError(undefined, line);
|
|
99
|
+
} else {
|
|
100
|
+
const achievements = deps.service.trackToolError(undefined, line);
|
|
101
|
+
if (achievements.length > 0) { deps.ui.refresh(ctx, companion, deps.storage.loadLatest(), achievements); }
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
const diffLines = extractLargeDiffLines(text);
|
|
105
|
+
if (diffLines >= 80) {
|
|
106
|
+
if (canEmit) {
|
|
107
|
+
result = deps.service.recordLargeDiff(diffLines);
|
|
108
|
+
} else {
|
|
109
|
+
const achievements = deps.service.trackLargeDiff(diffLines);
|
|
110
|
+
if (achievements.length > 0) { deps.ui.refresh(ctx, companion, deps.storage.loadLatest(), achievements); }
|
|
111
|
+
}
|
|
112
|
+
} else if (canEmit && looksLikeSuccess(text)) {
|
|
113
|
+
result = deps.service.recordComment(getSuccessReaction(companion.bones.species), "turn");
|
|
114
|
+
}
|
|
101
115
|
}
|
|
116
|
+
} else if (event.isError) {
|
|
117
|
+
const line = firstLineNumber(text);
|
|
118
|
+
if (canEmit) {
|
|
119
|
+
result = deps.service.recordToolError(undefined, line);
|
|
120
|
+
} else {
|
|
121
|
+
const achievements = deps.service.trackToolError(undefined, line);
|
|
122
|
+
if (achievements.length > 0) { deps.ui.refresh(ctx, companion, deps.storage.loadLatest(), achievements); }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!canEmit) {
|
|
127
|
+
deps.logger.debug("tool_result_skipped", { reason: "cooldown" });
|
|
128
|
+
return;
|
|
102
129
|
}
|
|
103
130
|
|
|
104
131
|
if (!result) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
textPreview
|
|
108
|
-
}
|
|
132
|
+
const ignoredData: Record<string, unknown> = { isError: event.isError, textLength: text.length };
|
|
133
|
+
if (diagnosticPreviewsEnabled()) {
|
|
134
|
+
ignoredData.textPreview = text.slice(0, 200);
|
|
135
|
+
}
|
|
136
|
+
deps.logger.debug("tool_result_ignored", ignoredData);
|
|
109
137
|
return;
|
|
110
138
|
}
|
|
111
139
|
deps.logger.info("tool_result_reaction", {
|
|
112
140
|
reason: result.state.reason,
|
|
113
|
-
|
|
114
|
-
|
|
141
|
+
reactionLength: result.state.reaction.length,
|
|
142
|
+
textLength: text.length,
|
|
115
143
|
});
|
|
116
144
|
deps.ui.refresh(ctx, result.companion, result.state, result.achievements);
|
|
117
145
|
deps.ui.notifyAchievements(ctx, result.achievements);
|
|
@@ -125,18 +153,24 @@ export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsD
|
|
|
125
153
|
return;
|
|
126
154
|
}
|
|
127
155
|
|
|
128
|
-
const generated = await generateTurnComment(
|
|
156
|
+
const generated = await generateTurnComment(
|
|
157
|
+
ctx,
|
|
158
|
+
progress.companion,
|
|
159
|
+
event,
|
|
160
|
+
deps.logger,
|
|
161
|
+
complete,
|
|
162
|
+
deps.storage.loadPiConfig().turnCommentModel,
|
|
163
|
+
);
|
|
129
164
|
if (!generated.comment) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
});
|
|
165
|
+
const assistantLength = isAssistantMessage(event.message) ? getAssistantText(event.message).length : 0;
|
|
166
|
+
deps.logger.warn("turn_end_comment_missing", { assistantLength });
|
|
133
167
|
deps.ui.refresh(ctx, progress.companion, deps.storage.loadLatest(), progress.achievements);
|
|
134
168
|
return;
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
deps.logger.info("turn_end_reaction", {
|
|
138
172
|
source: generated.source,
|
|
139
|
-
|
|
173
|
+
reactionLength: generated.comment.length,
|
|
140
174
|
});
|
|
141
175
|
|
|
142
176
|
const reaction = deps.service.recordComment(generated.comment, "turn");
|
|
@@ -144,6 +178,13 @@ export function registerBuddyEvents(pi: ExtensionAPI, deps: RegisterBuddyEventsD
|
|
|
144
178
|
deps.ui.refresh(ctx, reaction.companion, reaction.state, achievements);
|
|
145
179
|
deps.ui.notifyAchievements(ctx, achievements);
|
|
146
180
|
});
|
|
181
|
+
pi.on("session_shutdown", () => {
|
|
182
|
+
deps.ui.cancelTimers();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function diagnosticPreviewsEnabled(): boolean {
|
|
186
|
+
const value = process.env.BUDDY_DIAGNOSTIC_PREVIEWS;
|
|
187
|
+
return value === "1" || value === "true";
|
|
147
188
|
}
|
|
148
189
|
|
|
149
190
|
function shouldEmitPassiveReaction(storage: PiBuddyStorage): boolean {
|
|
@@ -167,8 +208,33 @@ function extractToolText(event: ToolResultEvent): string {
|
|
|
167
208
|
return "";
|
|
168
209
|
}
|
|
169
210
|
|
|
170
|
-
|
|
171
|
-
|
|
211
|
+
const EXPLICIT_FAILURE_PATTERN = /\b(?:[1-9][0-9]*\s+)?(?:tests?|specs?)\s+(?:failed|failing|did\s+not\s+pass)\b/i;
|
|
212
|
+
|
|
213
|
+
function hasTestContext(line: string): boolean {
|
|
214
|
+
return /\b(?:bun\s+test|npm\s+test|yarn\s+test|pnpm\s+test|vitest|jest|mocha|ava|tap|pytest|cargo\s+test|go\s+test|dotnet\s+test|phpunit|rspec|test\s+suite|test\s+runner|tests?\s+(?:passed|failed|ok)|TAP\s*version|1\.\.\d+|#\s+(?:tests|pass|fail|todo|skip|ok))\b/i.test(line);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isGenericFailureMarker(line: string): boolean {
|
|
218
|
+
return /^\s*(?:FAIL|not\s+ok|[✗✘×])\s*$/i.test(line) ||
|
|
219
|
+
/\b[✗✘×]\b/.test(line) ||
|
|
220
|
+
/(?:^|[\r\n])\s*FAIL(?:\s|$)/i.test(line) ||
|
|
221
|
+
/\bnot\s+ok\b/i.test(line);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function looksLikeTestFailure(text: string): boolean {
|
|
225
|
+
if (EXPLICIT_FAILURE_PATTERN.test(text)) return true;
|
|
226
|
+
|
|
227
|
+
const lines = text.split(/\r?\n/);
|
|
228
|
+
const contextWindow: string[] = [];
|
|
229
|
+
for (const rawLine of lines) {
|
|
230
|
+
const line = rawLine.trim();
|
|
231
|
+
contextWindow.push(line);
|
|
232
|
+
if (contextWindow.length > 3) contextWindow.shift();
|
|
233
|
+
if (isGenericFailureMarker(line) && contextWindow.some((contextLine) => hasTestContext(contextLine))) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
172
238
|
}
|
|
173
239
|
|
|
174
240
|
function looksLikeSuccess(text: string): boolean {
|
|
@@ -198,10 +264,6 @@ function firstLineNumber(text: string): number | undefined {
|
|
|
198
264
|
return match ? Number(match[1]) : undefined;
|
|
199
265
|
}
|
|
200
266
|
|
|
201
|
-
function escapeRegExp(value: string): string {
|
|
202
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
203
|
-
}
|
|
204
|
-
|
|
205
267
|
function mergeAchievements(first: Achievement[], second: Achievement[]): Achievement[] {
|
|
206
268
|
const merged = new Map<string, Achievement>();
|
|
207
269
|
for (const achievement of [...first, ...second]) {
|
|
@@ -221,11 +283,18 @@ function getAssistantText(message: AssistantMessage): string {
|
|
|
221
283
|
.join("\n");
|
|
222
284
|
}
|
|
223
285
|
|
|
224
|
-
|
|
286
|
+
type TurnCommentCompleter = (
|
|
287
|
+
model: Parameters<typeof complete>[0],
|
|
288
|
+
context: Parameters<typeof complete>[1],
|
|
289
|
+
options: Parameters<typeof complete>[2],
|
|
290
|
+
) => Promise<AssistantMessage>;
|
|
291
|
+
export async function generateTurnComment(
|
|
225
292
|
ctx: ExtensionContext,
|
|
226
293
|
companion: Companion,
|
|
227
294
|
event: TurnEndEvent,
|
|
228
|
-
logger:
|
|
295
|
+
logger: PiBuddyLog,
|
|
296
|
+
completeTurnComment: TurnCommentCompleter = complete,
|
|
297
|
+
modelOverride?: BuddyTurnCommentModelConfig,
|
|
229
298
|
): Promise<{ comment: string | null; source: "llm" | "fallback" | "none" }> {
|
|
230
299
|
const assistantText = isAssistantMessage(event.message) ? getAssistantText(event.message) : "";
|
|
231
300
|
if (!assistantText.trim()) {
|
|
@@ -233,7 +302,7 @@ async function generateTurnComment(
|
|
|
233
302
|
return { comment: null, source: "none" };
|
|
234
303
|
}
|
|
235
304
|
|
|
236
|
-
const turnCommentModel = resolveTurnCommentModel(ctx, logger);
|
|
305
|
+
const turnCommentModel = resolveTurnCommentModel(ctx, logger, modelOverride);
|
|
237
306
|
if (turnCommentModel) {
|
|
238
307
|
const toolResultsText = getToolResultsText(event);
|
|
239
308
|
const userText = getUserPromptText(ctx);
|
|
@@ -242,21 +311,26 @@ async function generateTurnComment(
|
|
|
242
311
|
logger.info("turn_comment_llm_attempt", {
|
|
243
312
|
modelProvider: turnCommentModel.provider,
|
|
244
313
|
modelId: turnCommentModel.id,
|
|
245
|
-
assistantPreview: assistantText.slice(0, 200),
|
|
246
|
-
toolPreview: toolResultsText.slice(0, 200),
|
|
247
314
|
assistantLength: assistantText.length,
|
|
248
315
|
toolLength: toolResultsText.length,
|
|
316
|
+
userTextLength: userText.length,
|
|
249
317
|
promptLength: promptText.length,
|
|
250
318
|
systemPromptLength: systemPrompt.length,
|
|
251
319
|
toolResultCount: event.toolResults.length,
|
|
252
320
|
});
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
userText,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
321
|
+
const promptDebugData: Record<string, unknown> = {
|
|
322
|
+
assistantLength: assistantText.length,
|
|
323
|
+
toolLength: toolResultsText.length,
|
|
324
|
+
userTextLength: userText.length,
|
|
325
|
+
};
|
|
326
|
+
if (diagnosticPreviewsEnabled()) {
|
|
327
|
+
promptDebugData.systemPromptPreview = systemPrompt.slice(0, 800);
|
|
328
|
+
promptDebugData.promptPreview = promptText.slice(0, 1200);
|
|
329
|
+
promptDebugData.userTextPreview = userText.slice(0, 200);
|
|
330
|
+
promptDebugData.assistantPreview = assistantText.slice(0, 200);
|
|
331
|
+
promptDebugData.toolPreview = toolResultsText.slice(0, 200);
|
|
332
|
+
}
|
|
333
|
+
logger.debug("turn_comment_llm_prompt", promptDebugData);
|
|
260
334
|
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(turnCommentModel);
|
|
261
335
|
logger.debug("turn_comment_auth", {
|
|
262
336
|
ok: auth.ok,
|
|
@@ -271,7 +345,7 @@ async function generateTurnComment(
|
|
|
271
345
|
};
|
|
272
346
|
|
|
273
347
|
try {
|
|
274
|
-
const response = await
|
|
348
|
+
const response = await completeTurnComment(
|
|
275
349
|
turnCommentModel,
|
|
276
350
|
{
|
|
277
351
|
systemPrompt,
|
|
@@ -294,14 +368,11 @@ async function generateTurnComment(
|
|
|
294
368
|
errorMessage: "errorMessage" in response ? (response as { errorMessage?: string }).errorMessage : undefined,
|
|
295
369
|
contentTypes: response.content.map((block) => block.type),
|
|
296
370
|
contentCount: response.content.length,
|
|
297
|
-
rawPreview: text.slice(0, 200),
|
|
298
371
|
rawLength: text.length,
|
|
299
|
-
normalized,
|
|
372
|
+
normalizedLength: normalized.length,
|
|
300
373
|
});
|
|
301
374
|
if (normalized) return { comment: normalized, source: "llm" };
|
|
302
|
-
logger.warn("turn_comment_llm_empty", {
|
|
303
|
-
rawPreview: text.slice(0, 200),
|
|
304
|
-
});
|
|
375
|
+
logger.warn("turn_comment_llm_empty", { rawLength: text.length });
|
|
305
376
|
}
|
|
306
377
|
} catch (error) {
|
|
307
378
|
logger.error("turn_comment_llm_error", {
|
|
@@ -321,19 +392,23 @@ async function generateTurnComment(
|
|
|
321
392
|
|
|
322
393
|
const fallback = deriveTurnComment(companion, event.message);
|
|
323
394
|
logger.warn("turn_comment_fallback", {
|
|
324
|
-
fallback,
|
|
325
|
-
|
|
395
|
+
fallbackLength: fallback?.length ?? 0,
|
|
396
|
+
assistantLength: assistantText.length,
|
|
326
397
|
});
|
|
327
398
|
return { comment: fallback, source: fallback ? "fallback" : "none" };
|
|
328
399
|
}
|
|
329
400
|
|
|
401
|
+
export interface PiTurnCommentModelContext {
|
|
402
|
+
model: ExtensionContext["model"];
|
|
403
|
+
modelRegistry: Pick<ExtensionContext["modelRegistry"], "find">;
|
|
404
|
+
}
|
|
405
|
+
|
|
330
406
|
export function resolveTurnCommentModel(
|
|
331
|
-
ctx:
|
|
332
|
-
logger?:
|
|
407
|
+
ctx: PiTurnCommentModelContext,
|
|
408
|
+
logger?: PiBuddyLog,
|
|
333
409
|
override?: BuddyTurnCommentModelConfig,
|
|
334
|
-
): NonNullable<
|
|
335
|
-
const
|
|
336
|
-
const activeOverride = configuredOverride;
|
|
410
|
+
): NonNullable<PiTurnCommentModelContext["model"]> | null {
|
|
411
|
+
const activeOverride = override;
|
|
337
412
|
if (activeOverride?.provider && activeOverride.model) {
|
|
338
413
|
const model = ctx.modelRegistry.find(activeOverride.provider, activeOverride.model);
|
|
339
414
|
if (model) {
|
package/adapters/pi/index.ts
CHANGED
|
@@ -5,11 +5,17 @@ import { PiBuddyLogger } from "./logger.ts";
|
|
|
5
5
|
import { registerBuddyCommands } from "./commands.ts";
|
|
6
6
|
import { registerBuddyEvents } from "./events.ts";
|
|
7
7
|
import { PiBuddyStorage } from "./storage.ts";
|
|
8
|
-
import { registerBuddyTools } from "./tools.ts";
|
|
9
8
|
import { PiBuddyUI } from "./ui.ts";
|
|
10
9
|
|
|
11
|
-
export
|
|
12
|
-
|
|
10
|
+
export interface PiBuddyExtensionOptions {
|
|
11
|
+
stateDir?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function registerPiBuddyExtension(
|
|
15
|
+
pi: ExtensionAPI,
|
|
16
|
+
options: PiBuddyExtensionOptions = {},
|
|
17
|
+
): void {
|
|
18
|
+
const storage = new PiBuddyStorage(options.stateDir);
|
|
13
19
|
const identity = new PiIdentityProvider(storage);
|
|
14
20
|
const logger = new PiBuddyLogger(storage);
|
|
15
21
|
const service = new BuddyCommandService({
|
|
@@ -23,5 +29,4 @@ export default function registerPiBuddyExtension(pi: ExtensionAPI): void {
|
|
|
23
29
|
|
|
24
30
|
registerBuddyCommands(pi, { service, storage, ui });
|
|
25
31
|
registerBuddyEvents(pi, { service, storage, ui, logger });
|
|
26
|
-
registerBuddyTools(pi);
|
|
27
32
|
}
|