pi-qq 0.1.8 → 0.1.10
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/README.md +25 -1
- package/package.json +2 -1
- package/qq.ts +23 -18
package/README.md
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
# pi-qq
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/pi-qq)
|
|
4
|
+
[](https://www.npmjs.com/package/pi-qq)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
|
|
3
7
|
Ask quick side questions about your current [pi](https://pi.dev) session without polluting the main transcript.
|
|
4
8
|
|
|
9
|
+
```text
|
|
10
|
+
You: refactor this auth flow…
|
|
11
|
+
agent: [making changes]
|
|
12
|
+
You (alt+q): is there a reason we're not using the existing AuthClient?
|
|
13
|
+
↳ overlay: Yes — AuthClient does X, but this path needs Y because…
|
|
14
|
+
You: [keeps editing, transcript untouched]
|
|
15
|
+
```
|
|
16
|
+
|
|
5
17
|
`pi-qq` adds `/qq <question>` plus an **alt+q** / **Option+Q** shortcut that toggles `/qq ` in the editor. Answers appear in a dismissible bottom overlay, can be reopened from in-memory `/qq-history`, and never enter the main conversation.
|
|
6
18
|
|
|
19
|
+
## Try these first
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
/qq is this safe to merge?
|
|
23
|
+
/qq why are we doing it this way and not X?
|
|
24
|
+
/qq summarize what's happened so far
|
|
25
|
+
/qq what's the risk in this plan?
|
|
26
|
+
/qq what files have we touched this session?
|
|
27
|
+
/qq --recent did the last tool call succeed?
|
|
28
|
+
/qq --full what decisions have we made so far?
|
|
29
|
+
```
|
|
30
|
+
|
|
7
31
|
## Why try it?
|
|
8
32
|
|
|
9
33
|
- **A real side channel:** ask `/qq why are we changing this file?` while the main agent keeps working. The answer shows in a bottom overlay and does not enter the main transcript.
|
|
@@ -74,7 +98,7 @@ Press **alt+q** / **Option+Q** to toggle `/qq ` at the front of the editor:
|
|
|
74
98
|
- The main transcript is never polluted by `/qq` questions or answers.
|
|
75
99
|
- The side call receives read-only main-session context.
|
|
76
100
|
- Recent mode sends only the latest messages for speed; full mode sends broader but still bounded context, not unlimited history.
|
|
77
|
-
- Large text parts are clipped,
|
|
101
|
+
- Large text parts are clipped; images, tool calls, and tool results are converted into plain-text background so the side call never uses provider tool protocol.
|
|
78
102
|
- The side call has no tools.
|
|
79
103
|
- Recent `/qq` answers are kept in memory only so `/qq-history` can reopen them after dismissal.
|
|
80
104
|
- `/qq-history` is view-only; it is not used as context for future `/qq` model calls.
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-qq",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Ask transcript-safe, context-aware side questions in Pi with /qq or alt+q, then reopen recent answers with /qq-history.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
7
7
|
"pi-extension",
|
|
8
|
+
"pi-qq",
|
|
8
9
|
"quick-question",
|
|
9
10
|
"side-question",
|
|
10
11
|
"context-aware",
|
package/qq.ts
CHANGED
|
@@ -145,33 +145,38 @@ function clipText(text: string): string {
|
|
|
145
145
|
return `${text.slice(0, MAX_TEXT_CHARS_PER_PART)}\n[…truncated for /qq speed…]`;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
148
|
+
function contentPartsToText(content: Array<{ type: string }>): string {
|
|
149
|
+
const parts: string[] = [];
|
|
150
|
+
for (const part of content) {
|
|
151
|
+
if (part.type === "text" && "text" in part && typeof part.text === "string") {
|
|
152
|
+
parts.push(clipText(part.text));
|
|
153
|
+
} else if (part.type === "image") {
|
|
154
|
+
parts.push("[image omitted for /qq speed]");
|
|
155
|
+
} else if (part.type === "toolCall" && "name" in part && typeof part.name === "string") {
|
|
156
|
+
parts.push(`[assistant requested tool: ${part.name}]`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return parts.join("\n").trim();
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
function
|
|
163
|
-
|
|
164
|
-
return trimContentArray(content);
|
|
162
|
+
function userContentToText(content: UserMessage["content"]): string {
|
|
163
|
+
return typeof content === "string" ? clipText(content) : contentPartsToText(content);
|
|
165
164
|
}
|
|
166
165
|
|
|
167
166
|
function trimMessageForContext(message: Message): Message {
|
|
168
167
|
if (message.role === "assistant") {
|
|
169
|
-
|
|
168
|
+
const text = contentPartsToText(message.content) || "[assistant message omitted for /qq speed]";
|
|
169
|
+
return { ...message, content: [{ type: "text", text }] };
|
|
170
170
|
}
|
|
171
171
|
if (message.role === "user") {
|
|
172
|
-
return { ...message, content:
|
|
172
|
+
return { ...message, content: [{ type: "text", text: userContentToText(message.content) }] };
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
const text = contentPartsToText(message.content) || "[tool result omitted for /qq speed]";
|
|
175
|
+
return {
|
|
176
|
+
role: "user",
|
|
177
|
+
content: [{ type: "text", text: `[tool result: ${message.toolName}]\n${text}` }],
|
|
178
|
+
timestamp: message.timestamp,
|
|
179
|
+
};
|
|
175
180
|
}
|
|
176
181
|
|
|
177
182
|
function selectRecentContextMessages(messages: Message[]): Message[] {
|