@selesai/code 0.13.25 → 0.13.27
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/CHANGELOG.md +85 -0
- package/dist/cli/args.js +1 -0
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/core/agent-session-auto-handoff.test.js +14 -4
- package/dist/core/agent-session-length-continuation.test.js +2 -1
- package/dist/core/agent-session.d.ts +58 -7
- package/dist/core/agent-session.js +339 -169
- package/dist/core/bug-report-upload.d.ts +11 -0
- package/dist/core/bug-report-upload.js +21 -0
- package/dist/core/bug-report.d.ts +175 -0
- package/dist/core/bug-report.js +291 -0
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-warmer.d.ts +101 -0
- package/dist/core/cache-warmer.js +341 -0
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/compaction.d.ts +6 -5
- package/dist/core/compaction/compaction.js +49 -42
- package/dist/core/crash-log.d.ts +21 -0
- package/dist/core/crash-log.js +70 -0
- package/dist/core/experimental.d.ts +0 -4
- package/dist/core/experimental.js +0 -4
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-loader.js +3 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-static-loader.js +3 -0
- package/dist/core/extensions/loader.js +39 -49
- package/dist/core/extensions/runner.d.ts +10 -7
- package/dist/core/extensions/runner.js +85 -67
- package/dist/core/extensions/types.d.ts +66 -52
- package/dist/core/extensions/virtual-modules.d.ts +2 -0
- package/dist/core/extensions/virtual-modules.js +39 -0
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/handoff.d.ts +1 -0
- package/dist/core/handoff.js +1 -0
- package/dist/core/index.d.ts +2 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/model-config.d.ts +101 -20
- package/dist/core/model-config.js +25 -18
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-runtime.js +5 -3
- package/dist/core/provider-composer.d.ts +7 -2
- package/dist/core/provider-composer.js +10 -5
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.js +6 -0
- package/dist/core/sdk.js +60 -38
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-format.test.d.ts +1 -0
- package/dist/core/session-format.test.js +96 -0
- package/dist/core/session-manager.d.ts +29 -6
- package/dist/core/session-manager.js +159 -96
- package/dist/core/settings-manager.d.ts +22 -5
- package/dist/core/settings-manager.js +56 -23
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/system-prompt.d.ts +49 -4
- package/dist/core/system-prompt.js +155 -102
- package/dist/core/system-prompt.test.js +61 -23
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.js +10 -4
- package/dist/core/tools/edit.js +1 -2
- package/dist/core/tools/read.js +1 -2
- package/dist/core/tools/renderers/bash.js +9 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/defaults/models.json +2 -72
- package/dist/extensions/handoff-new.test.ts +13 -13
- package/dist/extensions/handoff-new.ts +17 -6
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +14 -6
- package/dist/extensions/pi-web-agent/src/extension.ts +3 -1
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +7 -3
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +3 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +2 -0
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +4 -2
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +4 -1
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +2 -1
- package/dist/extensions/pi-web-agent/src/types.ts +4 -0
- package/dist/index.d.ts +3 -2
- package/dist/main.js +13 -9
- package/dist/migrations.js +2 -2
- package/dist/modes/interactive/bug-report.d.ts +15 -0
- package/dist/modes/interactive/bug-report.js +205 -0
- package/dist/modes/interactive/chat-viewport.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.js +7 -2
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.js +11 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
- package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
- package/dist/modes/interactive/components/status-indicator.js +7 -7
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tree-selector.js +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts +15 -2
- package/dist/modes/interactive/interactive-mode.js +257 -81
- package/dist/modes/interactive/session-share.d.ts +2 -0
- package/dist/modes/interactive/session-share.js +8 -4
- package/dist/modes/interactive/tui-renderer.js +2 -2
- package/dist/modes/rpc/rpc-mode.js +7 -2
- package/dist/utils/clipboard-command.d.ts +6 -0
- package/dist/utils/clipboard-command.js +44 -0
- package/dist/utils/clipboard-image.js +55 -89
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.js +118 -108
- package/dist/utils/wsl.d.ts +2 -0
- package/dist/utils/wsl.js +14 -0
- package/dist/utils/zip.d.ts +6 -0
- package/dist/utils/zip.js +59 -0
- package/package.json +9 -9
- package/dist/utils/clipboard-native.d.ts +0 -10
- package/dist/utils/clipboard-native.js +0 -19
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"id": "celestial-pro",
|
|
15
15
|
"name": "Celestial Pro",
|
|
16
16
|
"reasoning": true,
|
|
17
|
-
"input": ["text"],
|
|
17
|
+
"input": ["text", "image"],
|
|
18
18
|
"contextWindow": 393216,
|
|
19
19
|
"maxTokens": 64000,
|
|
20
20
|
"thinkingLevelMap": {
|
|
@@ -67,51 +67,13 @@
|
|
|
67
67
|
"requiresReasoningContentOnAssistantMessages": true
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
{
|
|
71
|
-
"id": "deepseek-v4-flash",
|
|
72
|
-
"name": "DeepSeek V4 Flash",
|
|
73
|
-
"reasoning": true,
|
|
74
|
-
"input": ["text"],
|
|
75
|
-
"contextWindow": 512000,
|
|
76
|
-
"maxTokens": 64000,
|
|
77
|
-
"thinkingLevelMap": {
|
|
78
|
-
"minimal": null,
|
|
79
|
-
"low": null,
|
|
80
|
-
"medium": null,
|
|
81
|
-
"high": "high",
|
|
82
|
-
"xhigh": null,
|
|
83
|
-
"max": "max"
|
|
84
|
-
},
|
|
85
|
-
"compat": {
|
|
86
|
-
"requiresReasoningContentOnAssistantMessages": true
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
"id": "deepseek-v4-flash-vision-exp",
|
|
91
|
-
"name": "DeepSeek V4 Flash Vision Exp",
|
|
92
|
-
"reasoning": true,
|
|
93
|
-
"input": ["text", "image"],
|
|
94
|
-
"contextWindow": 512000,
|
|
95
|
-
"maxTokens": 128000,
|
|
96
|
-
"thinkingLevelMap": {
|
|
97
|
-
"minimal": null,
|
|
98
|
-
"low": null,
|
|
99
|
-
"medium": null,
|
|
100
|
-
"high": "high",
|
|
101
|
-
"xhigh": null,
|
|
102
|
-
"max": "max"
|
|
103
|
-
},
|
|
104
|
-
"compat": {
|
|
105
|
-
"requiresReasoningContentOnAssistantMessages": true
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
70
|
{
|
|
109
71
|
"id": "deepseek-v4.1-flash",
|
|
110
72
|
"name": "DeepSeek V4.1 Flash",
|
|
111
73
|
"reasoning": true,
|
|
112
74
|
"input": ["text", "image"],
|
|
113
75
|
"contextWindow": 512000,
|
|
114
|
-
"maxTokens":
|
|
76
|
+
"maxTokens": 64000,
|
|
115
77
|
"thinkingLevelMap": {
|
|
116
78
|
"minimal": null,
|
|
117
79
|
"low": null,
|
|
@@ -207,38 +169,6 @@
|
|
|
207
169
|
"max": "max"
|
|
208
170
|
}
|
|
209
171
|
},
|
|
210
|
-
{
|
|
211
|
-
"id": "kimi-k2.7-code",
|
|
212
|
-
"name": "Kimi K2.7 Code",
|
|
213
|
-
"reasoning": true,
|
|
214
|
-
"input": ["text", "image"],
|
|
215
|
-
"contextWindow": 262128,
|
|
216
|
-
"maxTokens": 64000,
|
|
217
|
-
"thinkingLevelMap": {
|
|
218
|
-
"minimal": null,
|
|
219
|
-
"low": "low",
|
|
220
|
-
"medium": null,
|
|
221
|
-
"high": "high",
|
|
222
|
-
"xhigh": null,
|
|
223
|
-
"max": "max"
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
"id": "glm-5.2",
|
|
228
|
-
"name": "GLM-5.2",
|
|
229
|
-
"reasoning": true,
|
|
230
|
-
"input": ["text"],
|
|
231
|
-
"contextWindow": 1000000,
|
|
232
|
-
"maxTokens": 64000,
|
|
233
|
-
"thinkingLevelMap": {
|
|
234
|
-
"minimal": null,
|
|
235
|
-
"low": "low",
|
|
236
|
-
"medium": null,
|
|
237
|
-
"high": "high",
|
|
238
|
-
"xhigh": null,
|
|
239
|
-
"max": null
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
172
|
{
|
|
243
173
|
"id": "glm-5.3-flash",
|
|
244
174
|
"name": "GLM-5.3 Flash",
|
|
@@ -226,11 +226,11 @@ describe("handoff-new extension", () => {
|
|
|
226
226
|
expect(calls.newSession).not.toBeNull();
|
|
227
227
|
});
|
|
228
228
|
|
|
229
|
-
it("non-tui mode generation error notifies and opens no session", async () => {
|
|
229
|
+
it("non-tui mode generation error notifies, rejects, and opens no session", async () => {
|
|
230
230
|
(complete as any).mockRejectedValueOnce(new Error("api down"));
|
|
231
231
|
const { commands } = createPiHarness();
|
|
232
232
|
const { ctx, calls } = createCtx({ mode: "rpc" });
|
|
233
|
-
await commands.get("handoff-new")!.handler("goal", ctx);
|
|
233
|
+
await expect(commands.get("handoff-new")!.handler("goal", ctx)).rejects.toThrow("api down");
|
|
234
234
|
expect(calls.newSession).toBeNull();
|
|
235
235
|
expect(calls.notify.some((n) => /api down/.test(n.msg))).toBe(true);
|
|
236
236
|
});
|
|
@@ -259,10 +259,10 @@ describe("handoff-new extension", () => {
|
|
|
259
259
|
expect(calls.notify.some((n) => /Cancelled/.test(n.msg))).toBe(true);
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
-
it("empty generated handoff
|
|
262
|
+
it("empty generated handoff notifies, rejects, and opens no blank session", async () => {
|
|
263
263
|
const { commands } = createPiHarness();
|
|
264
264
|
const { ctx, calls } = createCtx({ customResult: " " });
|
|
265
|
-
await commands.get("handoff-new")!.handler("goal", ctx);
|
|
265
|
+
await expect(commands.get("handoff-new")!.handler("goal", ctx)).rejects.toThrow("returned no text");
|
|
266
266
|
expect(calls.newSession).toBeNull();
|
|
267
267
|
expect(calls.notify.some((n) => /returned no text/.test(n.msg))).toBe(true);
|
|
268
268
|
});
|
|
@@ -358,29 +358,29 @@ describe("handoff-new extension", () => {
|
|
|
358
358
|
expect(calls.notify.some((n) => /Cancelled/.test(n.msg))).toBe(true);
|
|
359
359
|
});
|
|
360
360
|
|
|
361
|
-
it("factory: missing API key
|
|
361
|
+
it("factory: missing API key notifies and rejects", async () => {
|
|
362
362
|
const { commands } = createPiHarness();
|
|
363
363
|
const { ctx, calls } = createFactoryCtx({ auth: { ok: true, error: "no key" } });
|
|
364
|
-
await commands.get("handoff-new")!.handler("goal", ctx);
|
|
364
|
+
await expect(commands.get("handoff-new")!.handler("goal", ctx)).rejects.toThrow("No API key");
|
|
365
365
|
expect(calls.newSession).toBeNull();
|
|
366
|
-
expect(calls.notify.some((n) => /
|
|
366
|
+
expect(calls.notify.some((n) => /No API key/.test(n.msg))).toBe(true);
|
|
367
367
|
});
|
|
368
368
|
|
|
369
|
-
it("factory: auth error
|
|
369
|
+
it("factory: auth error notifies and rejects", async () => {
|
|
370
370
|
const { commands } = createPiHarness();
|
|
371
371
|
const { ctx, calls } = createFactoryCtx({ auth: { ok: false, error: "auth failed" } });
|
|
372
|
-
await commands.get("handoff-new")!.handler("goal", ctx);
|
|
372
|
+
await expect(commands.get("handoff-new")!.handler("goal", ctx)).rejects.toThrow("auth failed");
|
|
373
373
|
expect(calls.newSession).toBeNull();
|
|
374
|
-
expect(calls.notify.some((n) => /
|
|
374
|
+
expect(calls.notify.some((n) => /auth failed/.test(n.msg))).toBe(true);
|
|
375
375
|
});
|
|
376
376
|
|
|
377
|
-
it("factory: complete rejection
|
|
377
|
+
it("factory: complete rejection notifies and rejects", async () => {
|
|
378
378
|
(complete as any).mockRejectedValueOnce(new Error("network down"));
|
|
379
379
|
const { commands } = createPiHarness();
|
|
380
380
|
const { ctx, calls } = createFactoryCtx({});
|
|
381
|
-
await commands.get("handoff-new")!.handler("goal", ctx);
|
|
381
|
+
await expect(commands.get("handoff-new")!.handler("goal", ctx)).rejects.toThrow("network down");
|
|
382
382
|
expect(calls.newSession).toBeNull();
|
|
383
|
-
expect(calls.notify.some((n) => /
|
|
383
|
+
expect(calls.notify.some((n) => /network down/.test(n.msg))).toBe(true);
|
|
384
384
|
});
|
|
385
385
|
|
|
386
386
|
it("factory: loader onAbort resolves null", async () => {
|
|
@@ -74,15 +74,20 @@ async function handoffNew(args: string, ctx: ExtensionCommandContext) {
|
|
|
74
74
|
const aiContext = buildAiContext(conversationText, goal);
|
|
75
75
|
|
|
76
76
|
let result: string | null;
|
|
77
|
+
let generationError: unknown;
|
|
77
78
|
if (ctx.mode === "tui") {
|
|
79
|
+
let cancelled = false;
|
|
78
80
|
result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
|
|
79
81
|
const loader = new BorderedLoader(tui, theme, `Generating handoff prompt...`);
|
|
80
|
-
loader.onAbort = () =>
|
|
82
|
+
loader.onAbort = () => {
|
|
83
|
+
cancelled = true;
|
|
84
|
+
done(null);
|
|
85
|
+
};
|
|
81
86
|
|
|
82
87
|
generateHandoffText(ctx, aiContext, loader.signal)
|
|
83
88
|
.then(done)
|
|
84
89
|
.catch((err) => {
|
|
85
|
-
|
|
90
|
+
if (!cancelled) generationError = err;
|
|
86
91
|
done(null);
|
|
87
92
|
});
|
|
88
93
|
|
|
@@ -94,18 +99,24 @@ async function handoffNew(args: string, ctx: ExtensionCommandContext) {
|
|
|
94
99
|
try {
|
|
95
100
|
result = await generateHandoffText(ctx, aiContext, ctx.signal);
|
|
96
101
|
} catch (err) {
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
generationError = err;
|
|
103
|
+
result = null;
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
|
|
107
|
+
if (generationError !== undefined) {
|
|
108
|
+
const error = generationError instanceof Error ? generationError : new Error(String(generationError));
|
|
109
|
+
ctx.ui.notify(error.message, "error");
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
102
112
|
if (result === null) {
|
|
103
113
|
ctx.ui.notify("Cancelled", "info");
|
|
104
114
|
return;
|
|
105
115
|
}
|
|
106
116
|
if (!result.trim()) {
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
const error = new Error("Handoff generation returned no text");
|
|
118
|
+
ctx.ui.notify(error.message, "error");
|
|
119
|
+
throw error;
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
// Read the name before newSession: the original ctx is invalidated once
|
|
@@ -213,13 +213,21 @@ export function createBackendSet(
|
|
|
213
213
|
});
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
216
|
+
// The keyless Tavily safety net, kept even under fanout — it wraps whatever search ended up
|
|
217
|
+
// being so a total failure still has somewhere to go. It used to arm only for the bare
|
|
218
|
+
// no-account DuckDuckGo default, which skipped every hosted provider configured with
|
|
219
|
+
// `fallback: duckduckgo`: when that fallback then hit a DNS-blocked or bot-walled DuckDuckGo
|
|
220
|
+
// the whole search died even though keyless Tavily was sitting right there. Arm it whenever
|
|
221
|
+
// DuckDuckGo is reachable in the chain. Opt out with PI_WEB_AGENT_DISABLE_KEYLESS_FALLBACK=1.
|
|
219
222
|
const keylessFallbackDisabled = process.env.PI_WEB_AGENT_DISABLE_KEYLESS_FALLBACK === '1';
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
// Fanout with no explicit provider list means "all usable", which always includes DuckDuckGo.
|
|
224
|
+
const fanoutActive = config.search.fanout?.mode !== undefined && config.search.fanout.mode !== 'off';
|
|
225
|
+
const duckDuckGoInChain =
|
|
226
|
+
!config.search.provider ||
|
|
227
|
+
config.search.provider === 'duckduckgo' ||
|
|
228
|
+
config.search.fallback === 'duckduckgo' ||
|
|
229
|
+
(fanoutActive && (config.search.fanout?.providers?.includes('duckduckgo') ?? true));
|
|
230
|
+
if (duckDuckGoInChain && !keylessFallbackDisabled) {
|
|
223
231
|
search = withSearchFallback(search, createTavilySearch({ keyless: true }), 'duckduckgo');
|
|
224
232
|
}
|
|
225
233
|
|
|
@@ -23,7 +23,9 @@ function serializeForModel(result: WebExploreResponse): string {
|
|
|
23
23
|
return `Research failed: ${result.error?.message ?? 'Unknown research failure.'}`;
|
|
24
24
|
}
|
|
25
25
|
if (result.findings.length === 0 && result.sources.length === 0) {
|
|
26
|
-
return
|
|
26
|
+
return result.metadata?.failureReason
|
|
27
|
+
? `No usable evidence found: ${result.metadata.failureReason}`
|
|
28
|
+
: 'No usable evidence found.';
|
|
27
29
|
}
|
|
28
30
|
return [
|
|
29
31
|
result.findings.join('\n\n'),
|
|
@@ -28,23 +28,27 @@ function joinReasons(reasons: string[]) {
|
|
|
28
28
|
return `${reasons.slice(0, -1).join(', ')}, and ${reasons.at(-1)}`;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function caveatText(partial: boolean, caveatReasons: EvidenceCaveatReason[] = []) {
|
|
31
|
+
function caveatText(partial: boolean, caveatReasons: EvidenceCaveatReason[] = [], failureReason?: string) {
|
|
32
32
|
if (!partial) return undefined;
|
|
33
33
|
const specificReasons = caveatReasons.map(sentenceForReason);
|
|
34
34
|
if (specificReasons.length > 0) {
|
|
35
35
|
return `Evidence is partial: ${joinReasons(specificReasons)}.`;
|
|
36
36
|
}
|
|
37
|
+
// With nothing to show, the budget line is a cover-up: say what actually failed.
|
|
38
|
+
if (failureReason) return `No usable evidence: ${failureReason}`;
|
|
37
39
|
return 'Evidence is partial, so this answer is based on the strongest source found within the bounded research budget.';
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export function synthesizeAnswer({
|
|
41
43
|
evidence,
|
|
42
44
|
partial,
|
|
43
|
-
caveatReasons = []
|
|
45
|
+
caveatReasons = [],
|
|
46
|
+
failureReason
|
|
44
47
|
}: {
|
|
45
48
|
evidence: ResearchEvidence[];
|
|
46
49
|
partial: boolean;
|
|
47
50
|
caveatReasons?: EvidenceCaveatReason[];
|
|
51
|
+
failureReason?: string;
|
|
48
52
|
}) {
|
|
49
53
|
const findings = evidence.slice(0, 5).map((item) => {
|
|
50
54
|
const summary = normalizeSummary(item.summary);
|
|
@@ -55,6 +59,6 @@ export function synthesizeAnswer({
|
|
|
55
59
|
|
|
56
60
|
return {
|
|
57
61
|
findings,
|
|
58
|
-
caveat: caveatText(partial, caveatReasons)
|
|
62
|
+
caveat: caveatText(partial, caveatReasons, failureReason)
|
|
59
63
|
};
|
|
60
64
|
}
|
|
@@ -136,6 +136,9 @@ function buildMetadata({
|
|
|
136
136
|
headlessAttempts,
|
|
137
137
|
exhaustedBudget,
|
|
138
138
|
caveatReasons,
|
|
139
|
+
// The first gap is why the run came up dry; it was collected and then thrown away, which
|
|
140
|
+
// is how a DNS-blocked DuckDuckGo surfaced as a contentless "No usable evidence found".
|
|
141
|
+
failureReason: allEvidence.length === 0 ? allGaps[0]?.message : undefined,
|
|
139
142
|
fanoutProviders,
|
|
140
143
|
fanoutSkipped
|
|
141
144
|
};
|
|
@@ -48,6 +48,8 @@ export type ResearchRunMetadata = {
|
|
|
48
48
|
fetchedPages: number;
|
|
49
49
|
headlessAttempts: number;
|
|
50
50
|
exhaustedBudget: boolean;
|
|
51
|
+
caveatReasons?: string[];
|
|
52
|
+
failureReason?: string;
|
|
51
53
|
fanoutProviders?: SearchProviderName[];
|
|
52
54
|
fanoutSkipped?: SearchProviderName[];
|
|
53
55
|
};
|
|
@@ -34,7 +34,7 @@ export function buildExplorePresentation(result: WebExploreResponse): Presentati
|
|
|
34
34
|
const hasEvidence = result.findings.length > 0 || result.sources.length > 0;
|
|
35
35
|
const evidenceLines = hasEvidence
|
|
36
36
|
? result.findings.map((finding, index) => `- [${internalReaderLabel(result.sources[index]?.method)}] ${finding}`)
|
|
37
|
-
: ['No usable evidence found.'];
|
|
37
|
+
: [result.metadata?.failureReason ? `No usable evidence: ${result.metadata.failureReason}` : 'No usable evidence found.'];
|
|
38
38
|
const preview = [
|
|
39
39
|
...evidenceLines,
|
|
40
40
|
internalSummary ? `\n${internalSummary}` : undefined
|
|
@@ -55,7 +55,9 @@ export function buildExplorePresentation(result: WebExploreResponse): Presentati
|
|
|
55
55
|
|
|
56
56
|
const compact = hasEvidence
|
|
57
57
|
? `Reviewed ${result.sources.length} sources · synthesized answer with ${result.findings.length} findings`
|
|
58
|
-
:
|
|
58
|
+
: result.metadata?.failureReason
|
|
59
|
+
? `No usable evidence: ${result.metadata.failureReason}`
|
|
60
|
+
: 'No usable evidence found';
|
|
59
61
|
|
|
60
62
|
return {
|
|
61
63
|
mode: 'compact',
|
|
@@ -6,7 +6,10 @@ import type { SearchResult, WebSearchResponse } from '../types.js';
|
|
|
6
6
|
|
|
7
7
|
export const TOKENIN_SEARCH_TOOL_NAME = 'firecrawl';
|
|
8
8
|
export const TOKENIN_DEFAULT_BASE_URL = 'https://lite.andlet.me/v1';
|
|
9
|
-
|
|
9
|
+
// ponytail: measured 20-36s per query through the LiteLLM proxy, so the old 10s ceiling
|
|
10
|
+
// aborted every search and quietly punted to the fallback chain. Ceiling: a dead proxy now
|
|
11
|
+
// costs 45s before falling back. Lower it if your proxy is local; raise it if still timing out.
|
|
12
|
+
const TOKENIN_SEARCH_TIMEOUT_MS = 45_000;
|
|
10
13
|
|
|
11
14
|
type TokenInAccount = { id: string; label: string; apiKey: string; baseUrl?: string };
|
|
12
15
|
type TokenInAuth = { accounts: TokenInAccount[]; activeId: string | null };
|
|
@@ -52,7 +52,8 @@ export function createWebExploreTool({
|
|
|
52
52
|
const synthesized = synthesizeAnswer({
|
|
53
53
|
evidence: result.evidence,
|
|
54
54
|
partial: result.decision.action !== 'answer',
|
|
55
|
-
caveatReasons: result.metadata?.caveatReasons as EvidenceCaveatReason[] | undefined
|
|
55
|
+
caveatReasons: result.metadata?.caveatReasons as EvidenceCaveatReason[] | undefined,
|
|
56
|
+
failureReason: result.metadata?.failureReason
|
|
56
57
|
});
|
|
57
58
|
|
|
58
59
|
const shaped: WebExploreResponse = {
|
|
@@ -95,6 +95,10 @@ export type WebExploreResponse = {
|
|
|
95
95
|
headlessAttempts: number;
|
|
96
96
|
exhaustedBudget: boolean;
|
|
97
97
|
caveatReasons?: string[];
|
|
98
|
+
// Why nothing came back, when nothing came back. Carried from the research pass's first
|
|
99
|
+
// gap so the empty result reads as "DuckDuckGo search request failed: fetch failed"
|
|
100
|
+
// instead of a bare "No usable evidence found".
|
|
101
|
+
failureReason?: string;
|
|
98
102
|
fanoutProviders?: SearchProviderName[];
|
|
99
103
|
fanoutSkipped?: SearchProviderName[];
|
|
100
104
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,11 @@ export { type Args, parseArgs } from "./cli/args.ts";
|
|
|
2
2
|
export { CONFIG_DIR_NAME, getAgentDir, getDocsPath, getModelsPath, getSettingsPath, getExamplesPath, getPackageDir, getReadmePath, VERSION, } from "./config.ts";
|
|
3
3
|
export { AgentSession, type AgentSessionConfig, type AgentSessionEvent, type AgentSessionEventListener, type ModelCycleResult, type ParsedSkillBlock, type ParsedSkillBlocks, type PromptOptions, parseSkillBlock, parseSkillBlocks, type SessionStats, } from "./core/agent-session.ts";
|
|
4
4
|
export { readStoredCredential } from "./core/auth-storage.ts";
|
|
5
|
+
export type { CacheWarmingDecision, CacheWarmingStatus } from "./core/cache-warmer.ts";
|
|
5
6
|
export { ensureTool, getToolPath, type ManagedTool } from "./utils/tools-manager.ts";
|
|
6
7
|
export { type BranchPreparation, type BranchSummaryResult, type CollectEntriesResult, type CompactionResult, type CutPointResult, calculateContextTokens, collectEntriesForBranchSummary, compact, DEFAULT_COMPACTION_SETTINGS, estimateTokens, type FileOperations, findCutPoint, findTurnStartIndex, type GenerateBranchSummaryOptions, generateBranchSummary, generateSummary, generateSummaryWithUsage, getLastAssistantUsage, prepareBranchEntries, serializeConversation, shouldCompact, } from "./core/compaction/index.ts";
|
|
7
8
|
export { createEventBus, type EventBus, type EventBusController } from "./core/event-bus.ts";
|
|
8
|
-
export type { AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BuildSystemPromptOptions, CompactOptions, ContextEvent, ContextUsage, CustomToolCallEvent, EditToolCallEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, GrepToolCallEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, MessageEndEvent, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, RegisteredCommand, RegisteredTool, ResolvedCommand, ResolvedSkillInfo, SessionBeforeCompactEvent, SessionBeforeForkEvent, SessionBeforeSwitchEvent, SessionBeforeTreeEvent, SessionCompactEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SlashCommandInfo, SlashCommandSource, SourceInfo, TerminalInputHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, TurnEndEvent, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, } from "./core/extensions/index.ts";
|
|
9
|
+
export type { AfterProviderResponseEvent, AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BuildSystemPromptOptions, CacheWarmingDecisionEvent, CacheWarmingDecisionEventResult, CompactOptions, ContextEvent, ContextEventResult, ContextUsage, CustomToolCallEvent, EditToolCallEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, GrepToolCallEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, MessageEndEvent, MessageEndEventResult, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, NormalizedBuildSystemPromptOptions, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, RegisteredCommand, RegisteredTool, ResolvedCommand, ResolvedSkillInfo, ResourcesDiscoverEvent, ResourcesDiscoverResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionCompactEvent, SessionCompactFailedEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SlashCommandInfo, SlashCommandSource, SourceInfo, TerminalInputHandler, ThinkingLevelSelectEvent, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TurnEndEvent, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, } from "./core/extensions/index.ts";
|
|
9
10
|
export { createExtensionRuntime, defineTool, discoverAndLoadExtensions, ExtensionRunner, isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, wrapRegisteredTool, wrapRegisteredTools, } from "./core/extensions/index.ts";
|
|
10
11
|
export type { ReadonlyFooterDataProvider } from "./core/footer-data-provider.ts";
|
|
11
12
|
export { convertToLlm } from "./core/messages.ts";
|
|
@@ -18,7 +19,7 @@ export type { ResourceCollision, ResourceDiagnostic, ResourceLoader } from "./co
|
|
|
18
19
|
export { DefaultResourceLoader, loadProjectContextFiles } from "./core/resource-loader.ts";
|
|
19
20
|
export { AgentSessionRuntime, type AgentSessionRuntimeDiagnostic, type AgentSessionServices, type CreateAgentSessionFromServicesOptions, type CreateAgentSessionOptions, type CreateAgentSessionResult, type CreateAgentSessionRuntimeFactory, type CreateAgentSessionRuntimeResult, type CreateAgentSessionServicesOptions, createAgentSession, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, type PromptTemplate, } from "./core/sdk.ts";
|
|
20
21
|
export { type BranchSummaryEntry, buildContextEntries, buildSessionContext, type CompactionEntry, CURRENT_SESSION_VERSION, type CustomEntry, type CustomMessageEntry, type FileEntry, getLatestCompactionEntry, type ModelChangeEntry, migrateSessionEntries, type NewSessionOptions, parseSessionEntries, type SessionContext, type SessionEntry, type SessionEntryBase, type SessionHeader, type SessionInfo, type SessionInfoEntry, SessionManager, type SessionMessageEntry, type SessionTreeNode, sessionEntryToContextMessages, type ThinkingLevelChangeEntry, } from "./core/session-manager.ts";
|
|
21
|
-
export { type AutoHandoffSettings, type CompactionSettings, type DefaultProjectTrust, type FullscreenExitOutput, type ImageSettings, type PackageSource, type RetrySettings, SettingsManager, type SettingsManagerCreateOptions, type TuiMode, } from "./core/settings-manager.ts";
|
|
22
|
+
export { type AutoHandoffSettings, type CacheWarmingMode, type CompactionModelOverride, type CompactionSettings, type DefaultProjectTrust, type FullscreenExitOutput, type ImageSettings, type PackageSource, type RetrySettings, SettingsManager, type SettingsManagerCreateOptions, type TuiMode, } from "./core/settings-manager.ts";
|
|
22
23
|
export { formatSkillsForPrompt, type LoadSkillsFromDirOptions, type LoadSkillsResult, loadSkills, loadSkillsFromDir, type Skill, type SkillFrontmatter, } from "./core/skills.ts";
|
|
23
24
|
export { createSyntheticSourceInfo } from "./core/source-info.ts";
|
|
24
25
|
export { type EditDiffResult, generateDiffString, generateUnifiedPatch } from "./core/tools/edit-diff.ts";
|
package/dist/main.js
CHANGED
|
@@ -151,19 +151,23 @@ async function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {
|
|
|
151
151
|
* Resolve a session argument to a file path.
|
|
152
152
|
* If it looks like a path, use as-is. Otherwise try to match as session ID prefix.
|
|
153
153
|
*/
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
return localMatch ? { type: "local", path: localMatch.path } : undefined;
|
|
154
|
+
function findLocalSessionByExactId(sessionId, cwd, sessionDir) {
|
|
155
|
+
const path = SessionManager.findById(cwd, sessionId, sessionDir);
|
|
156
|
+
return path ? { type: "local", path } : undefined;
|
|
158
157
|
}
|
|
159
158
|
async function resolveSessionPath(sessionArg, cwd, sessionDir) {
|
|
160
159
|
// If it looks like a file path, resolve it before handing it to the session manager.
|
|
161
160
|
if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
|
|
162
161
|
return { type: "path", path: resolvePath(sessionArg, cwd) };
|
|
163
162
|
}
|
|
164
|
-
//
|
|
163
|
+
// Exact IDs only require reading session headers. Fall back to the full
|
|
164
|
+
// metadata listing for prefix matches.
|
|
165
|
+
const exactLocalMatch = findLocalSessionByExactId(sessionArg, cwd, sessionDir);
|
|
166
|
+
if (exactLocalMatch) {
|
|
167
|
+
return exactLocalMatch;
|
|
168
|
+
}
|
|
165
169
|
const localSessions = await SessionManager.list(cwd, sessionDir);
|
|
166
|
-
const localMatch = localSessions.find((s) => s.id
|
|
170
|
+
const localMatch = localSessions.find((s) => s.id.startsWith(sessionArg));
|
|
167
171
|
if (localMatch) {
|
|
168
172
|
return { type: "local", path: localMatch.path };
|
|
169
173
|
}
|
|
@@ -250,7 +254,7 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
|
250
254
|
}
|
|
251
255
|
if (parsed.fork) {
|
|
252
256
|
if (parsed.sessionId) {
|
|
253
|
-
const existingTarget =
|
|
257
|
+
const existingTarget = findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
|
254
258
|
if (existingTarget) {
|
|
255
259
|
console.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));
|
|
256
260
|
process.exit(1);
|
|
@@ -289,7 +293,7 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
|
289
293
|
}
|
|
290
294
|
if (parsed.resume) {
|
|
291
295
|
try {
|
|
292
|
-
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), (onProgress) => SessionManager.listAll(sessionDir, onProgress), settingsManager);
|
|
296
|
+
const selectedPath = await selectSession((onProgress, signal) => SessionManager.list(cwd, sessionDir, onProgress, signal), (onProgress, signal) => SessionManager.listAll(sessionDir, onProgress, signal), settingsManager);
|
|
293
297
|
if (!selectedPath) {
|
|
294
298
|
console.log(chalk.dim("No session selected"));
|
|
295
299
|
process.exit(0);
|
|
@@ -304,7 +308,7 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
|
304
308
|
return SessionManager.continueRecent(cwd, sessionDir);
|
|
305
309
|
}
|
|
306
310
|
if (parsed.sessionId) {
|
|
307
|
-
const existingSession =
|
|
311
|
+
const existingSession = findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
|
308
312
|
if (existingSession) {
|
|
309
313
|
return SessionManager.open(existingSession.path, sessionDir);
|
|
310
314
|
}
|
package/dist/migrations.js
CHANGED
|
@@ -6,8 +6,8 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, w
|
|
|
6
6
|
import { dirname, join } from "path";
|
|
7
7
|
import { CONFIG_DIR_NAME, getAgentDir, getBinDir } from "./config.js";
|
|
8
8
|
import { migrateKeybindingsConfig } from "./core/keybindings.js";
|
|
9
|
-
const MIGRATION_GUIDE_URL = "https://github.com/earendil-works/pi
|
|
10
|
-
const EXTENSIONS_DOC_URL = "https://github.com/earendil-works/pi
|
|
9
|
+
const MIGRATION_GUIDE_URL = "https://github.com/earendil-works/pi/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration";
|
|
10
|
+
const EXTENSIONS_DOC_URL = "https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md";
|
|
11
11
|
/**
|
|
12
12
|
* Migrate legacy oauth.json and settings.json apiKeys to auth.json.
|
|
13
13
|
*
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Container, EditorComponent, TUI } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { AgentSession } from "../../core/agent-session.ts";
|
|
3
|
+
import type { KeybindingsManager } from "../../core/keybindings.ts";
|
|
4
|
+
interface BugReportContext {
|
|
5
|
+
session: AgentSession;
|
|
6
|
+
ui: TUI;
|
|
7
|
+
editorContainer: Container;
|
|
8
|
+
editor: EditorComponent;
|
|
9
|
+
keybindings: KeybindingsManager;
|
|
10
|
+
showStatus: (message: string) => void;
|
|
11
|
+
showError: (message: string) => void;
|
|
12
|
+
}
|
|
13
|
+
/** Run the `/bug` flow: consent, optional summary, then upload or export. */
|
|
14
|
+
export declare function reportBug(context: BugReportContext, initialHint?: string): Promise<void>;
|
|
15
|
+
export {};
|