@lincoln504/pi-research 1.3.0 → 1.3.1
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/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.1] - 2026-08-06
|
|
9
|
+
|
|
10
|
+
A dedicated post-release investigation pass over 1.3.0 — three independent
|
|
11
|
+
agents (fresh-eyes code review, packaging/release-artifact audit, isolated
|
|
12
|
+
runtime CLI smoke test) plus a full from-scratch local gate run — to confirm
|
|
13
|
+
the shipped artifact and codebase were correct before considering the
|
|
14
|
+
release closed. The packaging audit and runtime smoke test found nothing;
|
|
15
|
+
the code review found one real, currently-live defect, fixed below.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **The pi-extension research tool could report a cancelled-but-partial run as an ordinary success.** `DeepResearchOrchestrator.run()` does not throw on cancellation once at least one researcher has produced a report — it resolves normally with a fallback synthesis (the same documented contract 1.3.0's `cmdResearch` fix was built around). `research-tool-definition.ts`'s abort check only lived in its `catch` block, so this resolves-normally path fell straight through to unconditional success handling: metrics recorded `status: 'success'`, and the text handed back to the calling agent carried no indication it was a partial report. This matters more here than at the CLI: `AgentToolResult`'s `details` field is logs/UI-only by its own type contract, so `content[].text` is the *only* channel the calling agent has to learn a report is partial rather than complete — a silent miscategorization here could lead an agent to treat cut-short research as a finished answer. Same bug class as the 1.3.0 CLI fix, at a call site that round's review missed. Fixed by checking the abort signal immediately after `runResearch()` resolves: the metrics status now reflects the real outcome, and a cancellation note is prepended to the report text itself.
|
|
20
|
+
|
|
21
|
+
Not a minor bump: unlike 1.3.0's `cmdResearch` fix, this does not touch the CLI's exit-code contract — it is scoped entirely to the pi-extension tool call path.
|
|
22
|
+
|
|
8
23
|
## [1.3.0] - 2026-08-06
|
|
9
24
|
|
|
10
25
|
Bundles three unreleased fix rounds that accumulated on top of 1.2.0 (each
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: pi-research
|
|
3
3
|
description: "Multi-agent web research for any coding agent. Use for anything requiring current information from the internet — news, trends, product/service/company facts, statistics, people, places, events, APIs, library behavior, or 'what is X / how does X work' questions. Also use to search a local knowledge store of previously researched findings before doing live research. Powered by the pi-research engine (search, stealth scraping, security databases, Stack Exchange). Not for reading local files, running project commands, or analyzing this repository's own source."
|
|
4
4
|
license: MIT
|
|
5
|
-
metadata: { "author": "Lincoln Deen", "version": "1.3.
|
|
5
|
+
metadata: { "author": "Lincoln Deen", "version": "1.3.1", "package": "@lincoln504/pi-research", "engine": "pi-research-sdk", "openclaw": { "requires": { "bins": ["node"] } } }
|
|
6
6
|
allowed-tools: Bash(node:*)
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -259,7 +259,7 @@ export function createResearchTool(iface?: ConfigInterface): ToolDefinition {
|
|
|
259
259
|
metrics.increment('session_runs_started_total');
|
|
260
260
|
|
|
261
261
|
try {
|
|
262
|
-
const researchRunResult = await runWithRunRegistry<{ result: string; tokens: number; researchId: string }>(runRegistry, () =>
|
|
262
|
+
const researchRunResult = await runWithRunRegistry<{ result: string; tokens: number; researchId: string; cancelled: boolean }>(runRegistry, () =>
|
|
263
263
|
logger.runCapturingStderr(async () => {
|
|
264
264
|
const config = getConfig(ctx.cwd, iface);
|
|
265
265
|
validateConfig(config);
|
|
@@ -389,6 +389,17 @@ export function createResearchTool(iface?: ConfigInterface): ToolDefinition {
|
|
|
389
389
|
config,
|
|
390
390
|
}, internalAbort.signal);
|
|
391
391
|
|
|
392
|
+
// DeepResearchOrchestrator.run() does not throw on cancellation once at
|
|
393
|
+
// least one researcher has produced a report — it returns a fallback
|
|
394
|
+
// synthesis through its normal return path (see
|
|
395
|
+
// deep-research-orchestrator.ts's synthesisService.hasReports branch).
|
|
396
|
+
// Left unchecked, a cancel mid-run that still yields a partial report
|
|
397
|
+
// would fall straight through as if the run had completed normally,
|
|
398
|
+
// with no indication in the returned text — the only channel the
|
|
399
|
+
// calling agent sees — that it is reading a partial result. Mirrors the
|
|
400
|
+
// CLI's cancellation-latch check on its own success path (cmdResearch).
|
|
401
|
+
const wasCancelled = aborted?.aborted === true || internalAbort.signal.aborted;
|
|
402
|
+
|
|
392
403
|
// Stop wave animation
|
|
393
404
|
if (observerState && panelState) stopObserverWaveAnimation(observerState, panelState);
|
|
394
405
|
|
|
@@ -418,10 +429,17 @@ export function createResearchTool(iface?: ConfigInterface): ToolDefinition {
|
|
|
418
429
|
const synthesisService = await getService<IResearchSynthesisService>(ServiceNames.RESEARCH_SYNTHESIS_SERVICE, ctx, container);
|
|
419
430
|
finalResult = synthesisService.appendMetadata(finalResult, selectedModel!.id);
|
|
420
431
|
|
|
421
|
-
|
|
432
|
+
// The calling agent only ever sees `content[].text` — `details` is
|
|
433
|
+
// logs/UI-only (AgentToolResult's own doc comment) — so a cancellation
|
|
434
|
+
// note has to live IN the report text itself, not just in metadata.
|
|
435
|
+
if (wasCancelled) {
|
|
436
|
+
finalResult = `*Research cancelled — the report below is a partial synthesis from what had been collected before the run was stopped.*\n\n${finalResult}`;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return { result: finalResult, tokens: runTokens, researchId, cancelled: wasCancelled };
|
|
422
440
|
} catch (error) {
|
|
423
441
|
if (aborted?.aborted || internalAbort.signal.aborted) {
|
|
424
|
-
return { result: 'Research cancelled.', tokens: 0, researchId };
|
|
442
|
+
return { result: 'Research cancelled.', tokens: 0, researchId, cancelled: true };
|
|
425
443
|
}
|
|
426
444
|
throw error;
|
|
427
445
|
} finally {
|
|
@@ -431,17 +449,27 @@ export function createResearchTool(iface?: ConfigInterface): ToolDefinition {
|
|
|
431
449
|
return researchRunResult;
|
|
432
450
|
})); // end runCapturingStderr / runWithRunRegistry
|
|
433
451
|
|
|
434
|
-
// Snapshot the run registry
|
|
452
|
+
// Snapshot the run registry. Both branches that produce researchRunResult
|
|
453
|
+
// (the success path above and its inner catch) can represent a cancelled
|
|
454
|
+
// run — status must reflect that, not assume every non-throwing outcome
|
|
455
|
+
// was an ordinary success.
|
|
435
456
|
metrics.recordRunSummary({
|
|
436
457
|
runId: researchId,
|
|
437
458
|
startedAt: runStartedAt,
|
|
438
459
|
completedAt: Date.now(),
|
|
439
460
|
durationMs: Date.now() - runStartedAt,
|
|
440
|
-
status: 'success',
|
|
461
|
+
status: researchRunResult.cancelled ? 'cancelled' : 'success',
|
|
441
462
|
snapshot: runRegistry.getSnapshot(),
|
|
442
463
|
});
|
|
443
464
|
|
|
444
|
-
return {
|
|
465
|
+
return {
|
|
466
|
+
content: [{ type: 'text', text: researchRunResult.result }],
|
|
467
|
+
details: {
|
|
468
|
+
totalTokens: researchRunResult.tokens,
|
|
469
|
+
researchId: researchRunResult.researchId,
|
|
470
|
+
...(researchRunResult.cancelled ? { cancelled: true } : {}),
|
|
471
|
+
},
|
|
472
|
+
};
|
|
445
473
|
} catch (error) {
|
|
446
474
|
if (aborted?.aborted || internalAbort.signal.aborted) {
|
|
447
475
|
metrics.recordRunSummary({
|