pi-error-advisor 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.
- package/README.md +101 -0
- package/km_page1.png +0 -0
- package/package.json +32 -0
- package/src/index.ts +167 -0
- package/sso_debug.png +0 -0
- package/sso_html.txt +16 -0
- package/sso_login.png +0 -0
- package/sso_qr_attempt3.png +0 -0
- package/sso_qr_code.png +0 -0
- package/sso_qr_code2.png +0 -0
- package/tsconfig.json +15 -0
- package/types/pi-coding-agent.ts +104 -0
- package/vitest.config.ts +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# pi-error-advisor
|
|
2
|
+
|
|
3
|
+
Makes provider errors visible to the LLM in [Pi](https://pi.dev) — without writing anything to the session.
|
|
4
|
+
|
|
5
|
+
Pi's default behavior keeps errors UI-only: assistant error messages carry the error in the `errorMessage` field with empty content (which provider serializers drop entirely), and overflow recovery removes the error message from context before retrying. The model therefore never learns that a request failed, why compaction ran, or that retries were exhausted — it either regenerates blind or gets a dead session.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
pi-error-advisor synthesizes a short, clearly-labeled note into the outgoing request context whenever the previous turn failed:
|
|
10
|
+
|
|
11
|
+
1. **Retry exhaustion** — after Pi's automatic retries give up on a transient provider error (rate limit, overloaded, network), the model is told the failure was infrastructure: *retry the same approach, don't change plans*, and let the user know the provider was unavailable.
|
|
12
|
+
|
|
13
|
+
2. **Non-retryable provider errors** — 400/401/422-class failures surface the error text so the model can inform the user (e.g. expired auth → suggest `/login`) or recognize that something in the conversation history is being rejected.
|
|
14
|
+
|
|
15
|
+
3. **Overflow recovery** — when the conversation exceeds the context window and Pi compacts it, the model is told to keep responses concise. If compaction *didn't complete* (failure, auth problem, nothing to compact), the model is told to produce the shortest useful response and suggest `/compact` or a larger-context model.
|
|
16
|
+
|
|
17
|
+
4. **Silence where it belongs** — user aborts (Ctrl+C during compaction or retry backoff), manual and threshold compaction, and anything after a successful assistant turn produce no notes at all.
|
|
18
|
+
|
|
19
|
+
## Why Request-Time, Not Persisted
|
|
20
|
+
|
|
21
|
+
A previous iteration of this idea injected persisted advisory messages into the session. Upstream feedback (rightly) flagged that as detrimental: transient infrastructure noise becomes permanent conversation history, flows into compaction summaries and forks, and steers the model with fabricated context.
|
|
22
|
+
|
|
23
|
+
This extension takes the opposite approach — **everything happens in the `context` hook at request time**:
|
|
24
|
+
|
|
25
|
+
- Sessions, exports, compaction summaries, forks, and resumes are byte-identical with or without the extension.
|
|
26
|
+
- Notes are self-limiting: they stop as soon as a successful assistant turn lands.
|
|
27
|
+
- Notes are appended at the end of the message list, keeping the prompt-cache prefix stable.
|
|
28
|
+
- Uninstalling the extension leaves zero trace in any session.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
# Via GitHub URL
|
|
34
|
+
pi install https://github.com/yeshao/pi-error-advisor
|
|
35
|
+
|
|
36
|
+
# Or run ad hoc
|
|
37
|
+
pi --extension path/to/pi-error-advisor/src/index.ts
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How It Works
|
|
41
|
+
|
|
42
|
+
### Trailing-error scan (retry exhaustion, non-retryable errors)
|
|
43
|
+
|
|
44
|
+
On every request, the `context` hook scans backwards for the last assistant message with `stopReason: "error"` that has no completed assistant message after it. The error is classified with pi-ai's own `isContextOverflow` / `isRetryableAssistantError`, and one matching note is appended:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
[error-advisor] The previous request failed with a transient provider error after
|
|
48
|
+
automatic retries were exhausted: "overloaded_error". This was an infrastructure
|
|
49
|
+
problem, not a problem with your approach — do not change your plan because of it. …
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The scan stops at successful or aborted assistant messages and at compaction/branch summaries, so stale errors never resurface.
|
|
53
|
+
|
|
54
|
+
### Overflow compaction tracking
|
|
55
|
+
|
|
56
|
+
The overflow-recovery path removes the error message from context before retrying, so the scan can't see it. Instead the extension pairs `session_before_compact(reason: "overflow")` with `session_compact`:
|
|
57
|
+
|
|
58
|
+
- Both fired → compaction succeeded → one-shot "conversation was compacted, keep responses concise" note on the retry request.
|
|
59
|
+
- Only the first fired → by the time the next request is built, the compaction must have failed → one-shot "compaction did not complete" note plus a UI warning.
|
|
60
|
+
- The event's abort signal clears the pending flag, so user-cancelled compactions stay silent.
|
|
61
|
+
|
|
62
|
+
(`agent_end` can't be used for failure detection — it fires *before* post-run compaction.)
|
|
63
|
+
|
|
64
|
+
## Project Structure
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
pi-error-advisor/
|
|
68
|
+
├── package.json # Pi extension manifest
|
|
69
|
+
├── tsconfig.json
|
|
70
|
+
├── vitest.config.ts
|
|
71
|
+
├── README.md
|
|
72
|
+
├── src/
|
|
73
|
+
│ └── index.ts # Extension entry
|
|
74
|
+
├── tests/
|
|
75
|
+
│ └── error-advisor.test.ts
|
|
76
|
+
└── types/
|
|
77
|
+
└── pi-coding-agent.ts # Type stubs for standalone typecheck/tests
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
# Install dependencies
|
|
84
|
+
npm install
|
|
85
|
+
|
|
86
|
+
# Type check
|
|
87
|
+
npm run typecheck
|
|
88
|
+
|
|
89
|
+
# Run tests
|
|
90
|
+
npm test
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Tests exercise the real pi-ai error classification (`@earendil-works/pi-ai` is a dev dependency); only `@earendil-works/pi-coding-agent` is stubbed.
|
|
94
|
+
|
|
95
|
+
## Dependencies
|
|
96
|
+
|
|
97
|
+
Runtime: pi-ai's `isContextOverflow` / `isRetryableAssistantError` (provided by Pi as a peer dependency). No other runtime dependencies.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
package/km_page1.png
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-error-advisor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Makes provider errors visible to the LLM in Pi — request-time advisory notes for retry exhaustion, non-retryable errors, and context-overflow compaction, persisting nothing to the session",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"pi": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"./src/index.ts"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"test": "vitest run"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@earendil-works/pi-agent-core": "*",
|
|
18
|
+
"@earendil-works/pi-ai": "*",
|
|
19
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@earendil-works/pi-agent-core": "^0.80.6",
|
|
23
|
+
"@earendil-works/pi-ai": "^0.80.6",
|
|
24
|
+
"@types/node": "^20.0.0",
|
|
25
|
+
"typescript": "^5.5.0",
|
|
26
|
+
"vitest": "^2.0.0"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-error-advisor
|
|
3
|
+
*
|
|
4
|
+
* Makes provider errors visible to the LLM at request time — without writing
|
|
5
|
+
* anything to the session.
|
|
6
|
+
*
|
|
7
|
+
* Pi's default behavior keeps errors UI-only: assistant error messages carry
|
|
8
|
+
* the error in the `errorMessage` field with empty content (which provider
|
|
9
|
+
* serializers drop entirely), and overflow recovery removes the error message
|
|
10
|
+
* from context before retrying. The model therefore never learns that a
|
|
11
|
+
* request failed, why compaction ran, or that retries were exhausted.
|
|
12
|
+
*
|
|
13
|
+
* This extension synthesizes a short, clearly-labeled note into the outgoing
|
|
14
|
+
* request context whenever the previous turn failed:
|
|
15
|
+
*
|
|
16
|
+
* - Transient provider errors (rate limit / overloaded / network) after retry
|
|
17
|
+
* exhaustion: tells the model the failure was infrastructure — retry the
|
|
18
|
+
* same approach, don't change plans.
|
|
19
|
+
* - Non-retryable errors (400/401/422): surfaces the error text so the model
|
|
20
|
+
* can inform the user (e.g. expired auth) or adjust (e.g. rejected content).
|
|
21
|
+
* - Overflow recovery: notes that the conversation was compacted (or that
|
|
22
|
+
* compaction did not complete) so the model keeps responses concise.
|
|
23
|
+
*
|
|
24
|
+
* Nothing is persisted. The note is added in the `context` hook, which only
|
|
25
|
+
* affects the outgoing provider request: sessions, exports, compaction
|
|
26
|
+
* summaries, forks, and resumes are byte-identical with or without this
|
|
27
|
+
* extension. Notes are self-limiting — they stop as soon as a successful
|
|
28
|
+
* assistant turn lands.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
32
|
+
import type { AssistantMessage } from "@earendil-works/pi-ai";
|
|
33
|
+
import { isContextOverflow, isRetryableAssistantError } from "@earendil-works/pi-ai/compat";
|
|
34
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
35
|
+
|
|
36
|
+
const NOTE_PREFIX = "[error-advisor]";
|
|
37
|
+
const MAX_ERROR_TEXT = 300;
|
|
38
|
+
const ADVISOR_CUSTOM_TYPE = "error-advisor";
|
|
39
|
+
|
|
40
|
+
function makeNote(text: string): AgentMessage {
|
|
41
|
+
return {
|
|
42
|
+
role: "custom",
|
|
43
|
+
customType: ADVISOR_CUSTOM_TYPE,
|
|
44
|
+
content: [{ type: "text", text: `${NOTE_PREFIX} ${text}` }],
|
|
45
|
+
display: false,
|
|
46
|
+
timestamp: Date.now(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function truncate(text: string): string {
|
|
51
|
+
return text.length > MAX_ERROR_TEXT ? `${text.slice(0, MAX_ERROR_TEXT)}…` : text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find the trailing assistant error message: the last assistant message with
|
|
56
|
+
* stopReason "error" that has no completed assistant message after it.
|
|
57
|
+
*
|
|
58
|
+
* Stops scanning at: a successful/aborted assistant message (advice would be
|
|
59
|
+
* stale or unwanted — user aborts are not the model's business), or a
|
|
60
|
+
* compaction/branch summary (errors before a summary are ancient history).
|
|
61
|
+
*/
|
|
62
|
+
function findTrailingError(messages: AgentMessage[]): AssistantMessage | undefined {
|
|
63
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
64
|
+
const msg = messages[i];
|
|
65
|
+
if (msg.role === "compactionSummary" || msg.role === "branchSummary") {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
if (msg.role !== "assistant") {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const assistant = msg as AssistantMessage;
|
|
72
|
+
return assistant.stopReason === "error" ? assistant : undefined;
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function classifyError(msg: AssistantMessage): string {
|
|
78
|
+
const errorText = truncate(msg.errorMessage ?? "unknown error");
|
|
79
|
+
if (isContextOverflow(msg, 0)) {
|
|
80
|
+
return (
|
|
81
|
+
"The previous request exceeded the model's context window and could not be completed. " +
|
|
82
|
+
"Keep your responses concise. If this persists, suggest the user run /compact or switch to a larger-context model."
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (isRetryableAssistantError(msg)) {
|
|
86
|
+
return (
|
|
87
|
+
`The previous request failed with a transient provider error after automatic retries were exhausted: "${errorText}". ` +
|
|
88
|
+
"This was an infrastructure problem, not a problem with your approach — do not change your plan because of it. " +
|
|
89
|
+
"Briefly let the user know the provider was unavailable and that retrying later should work."
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return (
|
|
93
|
+
`The previous request failed with a non-retryable provider error: "${errorText}". ` +
|
|
94
|
+
"If it indicates an authentication problem, tell the user to check their credentials (e.g. /login). " +
|
|
95
|
+
"If it indicates a malformed request, part of the conversation history may contain content the provider rejects."
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default function errorAdvisor(pi: ExtensionAPI) {
|
|
100
|
+
// One-shot flags set by compaction events, consumed by the next context
|
|
101
|
+
// transform. These cover the overflow-recovery path, where the error
|
|
102
|
+
// message is removed from context before the retry — a stateless scan of
|
|
103
|
+
// the context can't see it, but the compaction events can.
|
|
104
|
+
//
|
|
105
|
+
// Failure inference: session_compact fires only on success, and there is
|
|
106
|
+
// no failure event. Event order matters — agent_end fires BEFORE the
|
|
107
|
+
// post-run compaction, so it cannot be used to detect failure. Instead:
|
|
108
|
+
// by the time the next `context` transform runs, an overflow compaction
|
|
109
|
+
// has either succeeded (session_compact cleared the pending flag before
|
|
110
|
+
// the retry request) or failed (the run died and this request belongs to
|
|
111
|
+
// the next prompt). A user abort clears the flag via the event's signal,
|
|
112
|
+
// so cancellations stay silent (user aborts are not the model's business).
|
|
113
|
+
let overflowCompacted = false;
|
|
114
|
+
let overflowCompactionPending = false;
|
|
115
|
+
|
|
116
|
+
pi.on("session_before_compact", async (event) => {
|
|
117
|
+
if (event.reason === "overflow") {
|
|
118
|
+
overflowCompactionPending = true;
|
|
119
|
+
event.signal.addEventListener("abort", () => {
|
|
120
|
+
overflowCompactionPending = false;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
pi.on("session_compact", async (event) => {
|
|
127
|
+
if (event.reason === "overflow") {
|
|
128
|
+
overflowCompactionPending = false;
|
|
129
|
+
overflowCompacted = true;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
pi.on("context", async (event, ctx) => {
|
|
134
|
+
const notes: string[] = [];
|
|
135
|
+
|
|
136
|
+
if (overflowCompacted) {
|
|
137
|
+
overflowCompacted = false;
|
|
138
|
+
notes.push(
|
|
139
|
+
"The conversation exceeded the model's context window and was automatically compacted. " +
|
|
140
|
+
"Keep your responses concise to avoid another overflow.",
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (overflowCompactionPending) {
|
|
144
|
+
overflowCompactionPending = false;
|
|
145
|
+
ctx.ui.notify("Overflow compaction did not complete; the request may fail again", "warning");
|
|
146
|
+
notes.push(
|
|
147
|
+
"The conversation exceeded the model's context window and automatic compaction did not complete. " +
|
|
148
|
+
"Produce the shortest useful response, and suggest the user run /compact or switch to a larger-context model.",
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Trailing provider error scan. Covers non-retryable errors (400/401)
|
|
153
|
+
// and retry exhaustion (the final failed attempt stays in context).
|
|
154
|
+
// Self-limiting: once a successful assistant message lands, the scan
|
|
155
|
+
// stops matching, so a note is only added while the failure is fresh.
|
|
156
|
+
const trailingError = findTrailingError(event.messages);
|
|
157
|
+
if (trailingError) {
|
|
158
|
+
notes.push(classifyError(trailingError));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (notes.length === 0) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
// Append at the end: keeps the message prefix stable for prompt caching.
|
|
165
|
+
return { messages: [...event.messages, ...notes.map(makeNote)] };
|
|
166
|
+
});
|
|
167
|
+
}
|
package/sso_debug.png
ADDED
|
Binary file
|
package/sso_html.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"html": "",
|
|
3
|
+
"lifecycle": {
|
|
4
|
+
"effectiveLaunch": {
|
|
5
|
+
"browserLaunched": true,
|
|
6
|
+
"engine": "chrome",
|
|
7
|
+
"launchHash": 6847324482101410000
|
|
8
|
+
},
|
|
9
|
+
"launched": false,
|
|
10
|
+
"relaunchedBrowser": false,
|
|
11
|
+
"restartedBackground": false,
|
|
12
|
+
"restoreStatus": "not_configured",
|
|
13
|
+
"reused": true,
|
|
14
|
+
"saveStatus": "not_attempted"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/sso_login.png
ADDED
|
Binary file
|
|
Binary file
|
package/sso_qr_code.png
ADDED
|
Binary file
|
package/sso_qr_code2.png
ADDED
|
Binary file
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"allowImportingTsExtensions": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"paths": {
|
|
11
|
+
"@earendil-works/pi-coding-agent": ["./types/pi-coding-agent"]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"include": ["src", "types", "tests"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Minimal type stubs for @earendil-works/pi-coding-agent used by pi-error-advisor.
|
|
2
|
+
// Only the members actually referenced are declared. At runtime under Pi, the
|
|
3
|
+
// real package provides these; the stub exists so `tsc --noEmit` and vitest can
|
|
4
|
+
// run standalone without the full coding-agent as a dev dependency.
|
|
5
|
+
|
|
6
|
+
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
|
|
7
|
+
|
|
8
|
+
/** Mirrors coding-agent's BashExecutionMessage. */
|
|
9
|
+
export interface BashExecutionMessage {
|
|
10
|
+
role: "bashExecution";
|
|
11
|
+
command: string;
|
|
12
|
+
output: string;
|
|
13
|
+
exitCode: number | undefined;
|
|
14
|
+
cancelled: boolean;
|
|
15
|
+
truncated: boolean;
|
|
16
|
+
fullOutputPath?: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
excludeFromContext?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Mirrors coding-agent's CustomMessage. */
|
|
22
|
+
export interface CustomMessage<T = unknown> {
|
|
23
|
+
role: "custom";
|
|
24
|
+
customType: string;
|
|
25
|
+
content: string | (TextContent | ImageContent)[];
|
|
26
|
+
display: boolean;
|
|
27
|
+
details?: T;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Mirrors coding-agent's BranchSummaryMessage. */
|
|
32
|
+
export interface BranchSummaryMessage {
|
|
33
|
+
role: "branchSummary";
|
|
34
|
+
summary: string;
|
|
35
|
+
fromId: string;
|
|
36
|
+
timestamp: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Mirrors coding-agent's CompactionSummaryMessage. */
|
|
40
|
+
export interface CompactionSummaryMessage {
|
|
41
|
+
role: "compactionSummary";
|
|
42
|
+
summary: string;
|
|
43
|
+
tokensBefore: number;
|
|
44
|
+
timestamp: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Replicate coding-agent's declaration merging so AgentMessage includes the
|
|
48
|
+
// custom roles — identical to what the real package declares.
|
|
49
|
+
declare module "@earendil-works/pi-agent-core" {
|
|
50
|
+
interface CustomAgentMessages {
|
|
51
|
+
bashExecution: BashExecutionMessage;
|
|
52
|
+
custom: CustomMessage;
|
|
53
|
+
branchSummary: BranchSummaryMessage;
|
|
54
|
+
compactionSummary: CompactionSummaryMessage;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
59
|
+
|
|
60
|
+
export interface ContextEvent {
|
|
61
|
+
type: "context";
|
|
62
|
+
messages: AgentMessage[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ContextEventResult {
|
|
66
|
+
messages?: AgentMessage[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface SessionBeforeCompactEvent {
|
|
70
|
+
type: "session_before_compact";
|
|
71
|
+
reason: "manual" | "threshold" | "overflow";
|
|
72
|
+
willRetry: boolean;
|
|
73
|
+
signal: AbortSignal;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SessionCompactEvent {
|
|
77
|
+
type: "session_compact";
|
|
78
|
+
reason: "manual" | "threshold" | "overflow";
|
|
79
|
+
willRetry: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ExtensionUIContext {
|
|
83
|
+
notify(message: string, level?: "info" | "warning" | "error"): void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ExtensionContext {
|
|
87
|
+
ui: ExtensionUIContext;
|
|
88
|
+
cwd: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ExtensionAPI {
|
|
92
|
+
on(
|
|
93
|
+
event: "context",
|
|
94
|
+
handler: (event: ContextEvent, ctx: ExtensionContext) => Promise<ContextEventResult | undefined>,
|
|
95
|
+
): void;
|
|
96
|
+
on(
|
|
97
|
+
event: "session_before_compact",
|
|
98
|
+
handler: (event: SessionBeforeCompactEvent, ctx: ExtensionContext) => Promise<unknown>,
|
|
99
|
+
): void;
|
|
100
|
+
on(
|
|
101
|
+
event: "session_compact",
|
|
102
|
+
handler: (event: SessionCompactEvent, ctx: ExtensionContext) => Promise<unknown>,
|
|
103
|
+
): void;
|
|
104
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { defineConfig } from "vitest/config";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
resolve: {
|
|
6
|
+
alias: {
|
|
7
|
+
"@earendil-works/pi-coding-agent": resolve(__dirname, "types/pi-coding-agent.ts"),
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
test: {
|
|
11
|
+
globals: true,
|
|
12
|
+
},
|
|
13
|
+
});
|