@oh-my-pi/pi-coding-agent 17.2.8 → 17.2.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/CHANGELOG.md +94 -1
- package/dist/{CHANGELOG-0b0w17se.md → CHANGELOG-rhwzpexa.md} +94 -1
- package/dist/cli.js +13216 -15614
- package/dist/types/async/job-manager.d.ts +12 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/discovery/agents.d.ts +11 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/loader.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +10 -0
- package/dist/types/hindsight/state.d.ts +0 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/lsp/utils.d.ts +8 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/modes/acp/acp-agent.d.ts +1 -1
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
- package/dist/types/modes/acp/acp-mode.d.ts +1 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +38 -0
- package/dist/types/modes/components/agent-hub-renderer.d.ts +41 -0
- package/dist/types/modes/components/agent-hub.d.ts +12 -5
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/session-observer-registry.d.ts +2 -0
- package/dist/types/registry/agent-lifecycle.d.ts +1 -1
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/session/agent-session-types.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +8 -4
- package/dist/types/session/session-entries.d.ts +10 -0
- package/dist/types/session/session-loader.d.ts +11 -1
- package/dist/types/session/session-manager.d.ts +9 -1
- package/dist/types/session/session-tools.d.ts +10 -1
- package/dist/types/session/turn-recovery.d.ts +6 -2
- package/dist/types/slash-commands/acp-builtins.d.ts +1 -1
- package/dist/types/slash-commands/available-commands.d.ts +1 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +2 -3
- package/dist/types/task/read-only-policy.d.ts +3 -0
- package/dist/types/task/structured-subagent.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/launch.d.ts +3 -0
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/read.d.ts +3 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +21 -3
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/changelog.d.ts +3 -2
- package/dist/types/utils/late-cleanup.d.ts +2 -0
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +4 -3
- package/dist/types/web/scrapers/readthedocs.d.ts +0 -3
- package/dist/types/web/search/providers/browser-headers.d.ts +2 -3
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/api-demo.ts +5 -6
- package/examples/extensions/chalk-logger.ts +1 -1
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/package.json +15 -31
- package/scripts/bundle-dist.ts +1 -11
- package/scripts/omp +11 -2
- package/src/advisor/runtime.ts +54 -0
- package/src/async/job-manager.ts +26 -0
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +24 -2
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/flag-tables.ts +4 -0
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/help-extra.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +4 -4
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +3 -57
- package/src/cli/usage-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli/worktree-cli.ts +1 -1
- package/src/commands/say.ts +1 -1
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/cli.ts +1 -1
- package/src/config/config-file.ts +2 -2
- package/src/config/keybindings.ts +3 -3
- package/src/config/model-discovery.ts +36 -2
- package/src/config/model-registry.ts +4 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/discovery/agents.ts +73 -3
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +5 -4
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +1 -1
- package/src/discovery/claude.ts +8 -5
- package/src/discovery/cursor.ts +8 -5
- package/src/discovery/gemini.ts +11 -8
- package/src/discovery/vscode.ts +1 -0
- package/src/discovery/windsurf.ts +4 -2
- package/src/edit/hashline/filesystem.ts +7 -7
- package/src/eval/agent-bridge.ts +1 -3
- package/src/eval/jl/prelude.jl +4 -4
- package/src/eval/js/shared/prelude.txt +2 -2
- package/src/eval/py/prelude.py +0 -3
- package/src/eval/py/runner.py +38 -1
- package/src/eval/rb/prelude.rb +1 -2
- package/src/extensibility/custom-commands/loader.ts +4 -4
- package/src/extensibility/custom-commands/types.ts +5 -5
- package/src/extensibility/custom-tools/loader.ts +4 -4
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -6
- package/src/extensibility/extensions/types.ts +39 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +23 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/hindsight/state.ts +2 -22
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +33 -0
- package/src/launch/terminal-output.ts +1 -1
- package/src/lsp/client.ts +2 -2
- package/src/lsp/utils.ts +29 -0
- package/src/main.ts +85 -21
- package/src/markit/converters/docx.ts +1 -1
- package/src/markit/converters/epub.ts +1 -1
- package/src/markit/converters/pptx.ts +1 -1
- package/src/markit/converters/xlsx.ts +1 -1
- package/src/modes/acp/acp-agent.ts +7 -6
- package/src/modes/acp/acp-client-bridge.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/acp/acp-mode.ts +1 -1
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +670 -192
- package/src/modes/components/agent-transcript-viewer.ts +1 -3
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/bordered-loader.ts +1 -1
- package/src/modes/components/custom-editor.ts +2 -2
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/hook-input.ts +1 -1
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/session-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -3
- package/src/modes/controllers/event-controller.ts +188 -7
- package/src/modes/controllers/extension-ui-controller.ts +4 -3
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +40 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/print-mode.ts +29 -12
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/session-observer-registry.ts +5 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +35 -10
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +11 -5
- package/src/session/agent-session-types.ts +8 -0
- package/src/session/agent-session.ts +177 -188
- package/src/session/session-entries.ts +10 -0
- package/src/session/session-listing.ts +1 -1
- package/src/session/session-loader.ts +74 -8
- package/src/session/session-manager.ts +22 -2
- package/src/session/session-paths.ts +105 -110
- package/src/session/session-tools.ts +28 -1
- package/src/session/settings-stream-fn.ts +7 -3
- package/src/session/turn-recovery.ts +236 -18
- package/src/session/unexpected-stop-classifier.ts +12 -3
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/helpers/stats-dashboard.ts +2 -1
- package/src/task/agents.ts +1 -1
- package/src/task/executor.ts +173 -47
- package/src/task/index.ts +9 -28
- package/src/task/isolation-runner.ts +43 -12
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +31 -6
- package/src/task/types.ts +4 -0
- package/src/tiny/worker.ts +1 -1
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-interceptor.ts +8 -4
- package/src/tools/bash.ts +6 -6
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +76 -19
- package/src/tools/browser/readable.ts +9 -9
- package/src/tools/browser/tab-supervisor.ts +12 -3
- package/src/tools/browser/tab-worker-entry.ts +1 -1
- package/src/tools/browser/tab-worker.ts +101 -12
- package/src/tools/fetch.ts +1 -1
- package/src/tools/glob.ts +4 -2
- package/src/tools/path-utils.ts +22 -5
- package/src/tools/read.ts +22 -5
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +38 -9
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/changelog.ts +5 -4
- package/src/utils/clipboard.ts +10 -2
- package/src/utils/external-editor.ts +4 -2
- package/src/utils/jj.ts +1 -1
- package/src/utils/late-cleanup.ts +17 -0
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +202 -58
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/hackage.ts +1 -12
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +2 -1
- package/src/web/scrapers/twitter.ts +2 -2
- package/src/web/scrapers/types.ts +1 -1
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +12 -39
- package/src/web/search/providers/codex.ts +3 -26
- package/src/web/search/providers/duckduckgo.ts +1 -1
- package/src/web/search/providers/ecosia.ts +2 -2
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/firecrawl.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +2 -2
- package/src/web/search/providers/perplexity.ts +1 -1
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/startpage.ts +2 -2
- package/src/markit/converters/mammoth.d.ts +0 -24
package/src/vibe/runtime.ts
CHANGED
|
@@ -25,7 +25,6 @@ import { MCPManager } from "../mcp/manager";
|
|
|
25
25
|
import vibeTurnResultTemplate from "../prompts/tools/vibe-turn-result.md" with { type: "text" };
|
|
26
26
|
import { AgentLifecycleManager } from "../registry/agent-lifecycle";
|
|
27
27
|
import { type AgentRef, AgentRegistry, MAIN_AGENT_ID } from "../registry/agent-registry";
|
|
28
|
-
import type { SessionEntry } from "../session/session-entries";
|
|
29
28
|
import { SessionManager, SessionPersistenceIndeterminateError } from "../session/session-manager";
|
|
30
29
|
import { getBundledAgent } from "../task/agents";
|
|
31
30
|
import { type ExecutorOptions, runSubagentFollowUpTurn, runSubprocess } from "../task/executor";
|
|
@@ -70,8 +69,8 @@ const TRACE_LINE_MAX = 120;
|
|
|
70
69
|
const DEFAULT_WAIT_TIMEOUT_MS = 30_000;
|
|
71
70
|
/** Response text cap inside a delivered turn result; full output stays at agent://<id>. */
|
|
72
71
|
const RESPONSE_PREVIEW_MAX = 6000;
|
|
73
|
-
/** Grace period for
|
|
74
|
-
const
|
|
72
|
+
/** Grace period for Vibe cancellation/release cleanup before teardown detaches (ms). */
|
|
73
|
+
const VIBE_TEARDOWN_GRACE_MS = 5_000;
|
|
75
74
|
|
|
76
75
|
const VIBE_LIFECYCLE_CUSTOM_TYPE = "vibe-session-lifecycle";
|
|
77
76
|
const VIBE_LIFECYCLE_VERSION = 1;
|
|
@@ -252,6 +251,48 @@ export interface VibeWaitOutcome {
|
|
|
252
251
|
timedOut: boolean;
|
|
253
252
|
}
|
|
254
253
|
|
|
254
|
+
type VibeTeardownStatus = "pending" | "settled" | "failed";
|
|
255
|
+
|
|
256
|
+
interface TrackedVibeTeardown {
|
|
257
|
+
promise: Promise<void>;
|
|
258
|
+
status: () => VibeTeardownStatus;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Observe cleanup without propagating a detached late rejection. */
|
|
262
|
+
function trackVibeTeardown(promise: Promise<unknown>, onError: (error: unknown) => void): TrackedVibeTeardown {
|
|
263
|
+
let status: VibeTeardownStatus = "pending";
|
|
264
|
+
return {
|
|
265
|
+
promise: promise.then(
|
|
266
|
+
() => {
|
|
267
|
+
status = "settled";
|
|
268
|
+
},
|
|
269
|
+
error => {
|
|
270
|
+
status = "failed";
|
|
271
|
+
onError(error);
|
|
272
|
+
},
|
|
273
|
+
),
|
|
274
|
+
status: () => status,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Wait for cleanup only until the caller's shared absolute deadline. */
|
|
279
|
+
async function waitForVibeTeardown(tasks: readonly TrackedVibeTeardown[], deadline: number): Promise<boolean> {
|
|
280
|
+
if (tasks.length === 0 || tasks.every(task => task.status() !== "pending")) return true;
|
|
281
|
+
const remainingMs = deadline - Date.now();
|
|
282
|
+
if (remainingMs <= 0) return false;
|
|
283
|
+
const timeout = Promise.withResolvers<void>();
|
|
284
|
+
const timer = setTimeout(timeout.resolve, remainingMs);
|
|
285
|
+
timer.unref?.();
|
|
286
|
+
try {
|
|
287
|
+
return await Promise.race([
|
|
288
|
+
Promise.allSettled(tasks.map(task => task.promise)).then(() => true),
|
|
289
|
+
timeout.promise.then(() => false),
|
|
290
|
+
]);
|
|
291
|
+
} finally {
|
|
292
|
+
clearTimeout(timer);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
255
296
|
/** Normalize a text fragment to one bounded roster/trace line. */
|
|
256
297
|
function firstLine(text: string, max = 100): string {
|
|
257
298
|
return oneLineLabel(text, max);
|
|
@@ -321,11 +362,12 @@ function parseLifecycleEvent(value: unknown): VibeLifecycleEvent | undefined {
|
|
|
321
362
|
return undefined;
|
|
322
363
|
}
|
|
323
364
|
|
|
324
|
-
/** Child ids claimed by
|
|
325
|
-
export function persistedVibeChildIds(entries: Iterable<
|
|
365
|
+
/** Child ids claimed by valid Vibe spawn records from untrusted persisted JSON. */
|
|
366
|
+
export function persistedVibeChildIds(entries: Iterable<unknown>): Set<string> {
|
|
326
367
|
const ids = new Set<string>();
|
|
327
|
-
for (const
|
|
328
|
-
|
|
368
|
+
for (const value of entries) {
|
|
369
|
+
const entry = objectRecord(value);
|
|
370
|
+
if (entry?.type !== "custom" || entry.customType !== VIBE_LIFECYCLE_CUSTOM_TYPE) continue;
|
|
329
371
|
const event = parseLifecycleEvent(entry.data);
|
|
330
372
|
if (
|
|
331
373
|
event?.action === "spawn" &&
|
|
@@ -354,24 +396,6 @@ function mergeTrace(turn: VibeTurn, progress: AgentProgress): void {
|
|
|
354
396
|
/** Thrown from a turn job body so the job manager marks the job failed while carrying the formatted result. */
|
|
355
397
|
export class VibeTurnError extends Error {}
|
|
356
398
|
|
|
357
|
-
async function awaitCancelledTurnJobs(jobs: ReadonlySet<AsyncJob>): Promise<void> {
|
|
358
|
-
if (jobs.size === 0) return;
|
|
359
|
-
const settled = Promise.allSettled([...jobs].map(job => job.promise)).then(() => true);
|
|
360
|
-
const timeout = Promise.withResolvers<false>();
|
|
361
|
-
const timer = setTimeout(() => timeout.resolve(false), CANCELLED_TURN_SETTLE_GRACE_MS);
|
|
362
|
-
timer.unref();
|
|
363
|
-
try {
|
|
364
|
-
if (!(await Promise.race([settled, timeout.promise]))) {
|
|
365
|
-
logger.warn("vibe: detached cancelled turn that did not settle within teardown grace period", {
|
|
366
|
-
jobCount: jobs.size,
|
|
367
|
-
graceMs: CANCELLED_TURN_SETTLE_GRACE_MS,
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
} finally {
|
|
371
|
-
clearTimeout(timer);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
399
|
/**
|
|
376
400
|
* Process-global registry of vibe worker sessions, scoped by both owner agent
|
|
377
401
|
* id and stable parent session id. Persisted lifecycle events rebuild idle
|
|
@@ -419,6 +443,12 @@ export class VibeSessionRegistry {
|
|
|
419
443
|
readonly #records = new Map<string, VibeRecord>();
|
|
420
444
|
readonly #terminationTails = new Map<string, Promise<void>>();
|
|
421
445
|
readonly #terminatedScopes = new Set<string>();
|
|
446
|
+
#teardownGraceMs = VIBE_TEARDOWN_GRACE_MS;
|
|
447
|
+
|
|
448
|
+
/** Override the teardown grace period for deterministic lifecycle tests. */
|
|
449
|
+
setTeardownGraceForTesting(timeoutMs: number): void {
|
|
450
|
+
this.#teardownGraceMs = Math.max(1, timeoutMs);
|
|
451
|
+
}
|
|
422
452
|
|
|
423
453
|
ownerScope(session: VibeParentSession): VibeOwnerScope {
|
|
424
454
|
const parentSessionId = session.getSessionId?.();
|
|
@@ -709,11 +739,50 @@ export class VibeSessionRegistry {
|
|
|
709
739
|
}
|
|
710
740
|
}
|
|
711
741
|
|
|
742
|
+
#trackAgentRelease(id: string, ref: AgentRef, action: "detach" | "release"): TrackedVibeTeardown {
|
|
743
|
+
return trackVibeTeardown(AgentLifecycleManager.global().release(id, ref), error => {
|
|
744
|
+
logger.warn(`vibe: failed to ${action} worker session`, {
|
|
745
|
+
id,
|
|
746
|
+
error: error instanceof Error ? error.message : String(error),
|
|
747
|
+
});
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
#finishAgentRelease(id: string, ref: AgentRef, task: TrackedVibeTeardown, action: "detach" | "release"): void {
|
|
752
|
+
if (task.status() === "settled") return;
|
|
753
|
+
if (task.status() === "pending") {
|
|
754
|
+
logger.warn(`vibe: timed out waiting to ${action} worker session; detaching registry ref`, { id });
|
|
755
|
+
}
|
|
756
|
+
AgentRegistry.global().unregister(id, ref);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
async #releaseRefWithinDeadline(
|
|
760
|
+
id: string,
|
|
761
|
+
ref: AgentRef,
|
|
762
|
+
deadline: number,
|
|
763
|
+
action: "detach" | "release",
|
|
764
|
+
): Promise<void> {
|
|
765
|
+
const task = this.#trackAgentRelease(id, ref, action);
|
|
766
|
+
await waitForVibeTeardown([task], deadline);
|
|
767
|
+
this.#finishAgentRelease(id, ref, task, action);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
#trackJobSettlement(record: VibeRecord, job: AsyncJob): TrackedVibeTeardown {
|
|
771
|
+
return trackVibeTeardown(job.promise, error => {
|
|
772
|
+
logger.warn("vibe: cancelled worker turn cleanup failed", {
|
|
773
|
+
id: record.id,
|
|
774
|
+
jobId: job.id,
|
|
775
|
+
error: error instanceof Error ? error.message : String(error),
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
712
780
|
async #markTerminalRef(
|
|
713
781
|
id: string,
|
|
714
782
|
ownerId: string,
|
|
715
783
|
childSessionFile: string,
|
|
716
784
|
expected?: AgentRef | null,
|
|
785
|
+
teardownDeadline?: number,
|
|
717
786
|
): Promise<void> {
|
|
718
787
|
const registry = AgentRegistry.global();
|
|
719
788
|
const existing = registry.get(id);
|
|
@@ -726,7 +795,9 @@ export class VibeSessionRegistry {
|
|
|
726
795
|
}
|
|
727
796
|
if (existing?.status === "aborted" && !existing.session) return;
|
|
728
797
|
if (existing && !registry.setStatus(id, "aborted", existing)) return;
|
|
729
|
-
if (existing &&
|
|
798
|
+
if (existing && teardownDeadline !== undefined) {
|
|
799
|
+
await this.#releaseRefWithinDeadline(id, existing, teardownDeadline, "release");
|
|
800
|
+
} else if (existing && AgentLifecycleManager.global().has(id, existing)) {
|
|
730
801
|
await AgentLifecycleManager.global().release(id, existing);
|
|
731
802
|
} else if (existing?.session) {
|
|
732
803
|
await existing.session.dispose();
|
|
@@ -1086,21 +1157,50 @@ export class VibeSessionRegistry {
|
|
|
1086
1157
|
this.#records.delete(scopeKey(scope, record.id));
|
|
1087
1158
|
if (record.turn && manager) manager.cancel(record.turn.jobId, { ownerId: record.ownerId });
|
|
1088
1159
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1160
|
+
const deadline = Date.now() + this.#teardownGraceMs;
|
|
1161
|
+
const cleanup = teardown.map(entry => ({
|
|
1162
|
+
...entry,
|
|
1163
|
+
releaseTask: entry.ref ? this.#trackAgentRelease(entry.record.id, entry.ref, "detach") : undefined,
|
|
1164
|
+
jobTask: entry.job ? this.#trackJobSettlement(entry.record, entry.job) : undefined,
|
|
1165
|
+
}));
|
|
1166
|
+
await waitForVibeTeardown(
|
|
1167
|
+
cleanup.flatMap(entry => [entry.releaseTask, entry.jobTask].filter(task => task !== undefined)),
|
|
1168
|
+
deadline,
|
|
1169
|
+
);
|
|
1170
|
+
for (const { record, ref, releaseTask, job, jobTask } of cleanup) {
|
|
1171
|
+
if (ref && releaseTask) this.#finishAgentRelease(record.id, ref, releaseTask, "detach");
|
|
1172
|
+
if (job && jobTask?.status() === "pending") {
|
|
1173
|
+
logger.warn("vibe: timed out waiting for cancelled worker turn; cleanup continues in the background", {
|
|
1095
1174
|
id: record.id,
|
|
1096
|
-
|
|
1175
|
+
jobId: job.id,
|
|
1097
1176
|
});
|
|
1177
|
+
this.#continueSuspendedCleanup(scope, record, jobTask);
|
|
1178
|
+
}
|
|
1179
|
+
if (this.#records.has(scopeKey(scope, record.id))) continue;
|
|
1180
|
+
const lateRef = this.#registeredAgent(record);
|
|
1181
|
+
if (lateRef && lateRef !== ref) {
|
|
1182
|
+
await this.#releaseRefWithinDeadline(record.id, lateRef, deadline, "detach");
|
|
1098
1183
|
}
|
|
1099
1184
|
}
|
|
1100
|
-
await awaitCancelledTurnJobs(new Set(teardown.flatMap(entry => (entry.job ? [entry.job] : []))));
|
|
1101
1185
|
return records.length;
|
|
1102
1186
|
}
|
|
1103
1187
|
|
|
1188
|
+
#continueSuspendedCleanup(scope: VibeOwnerScope, record: VibeRecord, jobTask: TrackedVibeTeardown): void {
|
|
1189
|
+
void jobTask.promise
|
|
1190
|
+
.then(async () => {
|
|
1191
|
+
if (this.#records.has(scopeKey(scope, record.id))) return;
|
|
1192
|
+
const lateRef = this.#registeredAgent(record);
|
|
1193
|
+
if (!lateRef) return;
|
|
1194
|
+
await this.#releaseRefWithinDeadline(record.id, lateRef, Date.now() + this.#teardownGraceMs, "detach");
|
|
1195
|
+
})
|
|
1196
|
+
.catch(error => {
|
|
1197
|
+
logger.warn("vibe: failed to finish suspended worker cleanup", {
|
|
1198
|
+
id: record.id,
|
|
1199
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1200
|
+
});
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1104
1204
|
/** Terminate one worker; a tombstone failure still tears it down before reconciliation and error delivery. */
|
|
1105
1205
|
async kill(session: ToolSession, id: string): Promise<VibeKillOutcome> {
|
|
1106
1206
|
const scope = this.ownerScope(session);
|
|
@@ -1144,15 +1244,21 @@ export class VibeSessionRegistry {
|
|
|
1144
1244
|
await this.#persistModeExit(session, scope, records);
|
|
1145
1245
|
} catch (error) {
|
|
1146
1246
|
if (error instanceof SessionPersistenceIndeterminateError) {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1247
|
+
const teardownDeadline = Date.now() + this.#teardownGraceMs;
|
|
1248
|
+
await Promise.all(
|
|
1249
|
+
records.map(record =>
|
|
1250
|
+
this.#killRecord(record, session.asyncJobManager, session, "mode-exit", false, teardownDeadline),
|
|
1251
|
+
),
|
|
1252
|
+
);
|
|
1150
1253
|
}
|
|
1151
1254
|
throw error;
|
|
1152
1255
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1256
|
+
const teardownDeadline = Date.now() + this.#teardownGraceMs;
|
|
1257
|
+
await Promise.all(
|
|
1258
|
+
records.map(record =>
|
|
1259
|
+
this.#killRecord(record, session.asyncJobManager, session, "mode-exit", true, teardownDeadline),
|
|
1260
|
+
),
|
|
1261
|
+
);
|
|
1156
1262
|
return records.length;
|
|
1157
1263
|
}
|
|
1158
1264
|
|
|
@@ -1162,6 +1268,7 @@ export class VibeSessionRegistry {
|
|
|
1162
1268
|
session: VibeParentSession,
|
|
1163
1269
|
reason: VibeTombstoneReason,
|
|
1164
1270
|
persistTerminal = true,
|
|
1271
|
+
teardownDeadline?: number,
|
|
1165
1272
|
): Promise<VibeKillOutcome> {
|
|
1166
1273
|
const registered = this.#registeredAgent(record);
|
|
1167
1274
|
const settlingJobs = new Set<AsyncJob>();
|
|
@@ -1198,26 +1305,29 @@ export class VibeSessionRegistry {
|
|
|
1198
1305
|
record.state = "dead";
|
|
1199
1306
|
record.lastActivityAt = Date.now();
|
|
1200
1307
|
record.lastActivity = "killed";
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1308
|
+
const deadline = teardownDeadline ?? Date.now() + this.#teardownGraceMs;
|
|
1309
|
+
const releaseTask = registered ? this.#trackAgentRelease(record.id, registered, "release") : undefined;
|
|
1310
|
+
const jobCleanup = [...settlingJobs].map(job => ({ job, task: this.#trackJobSettlement(record, job) }));
|
|
1311
|
+
await waitForVibeTeardown(
|
|
1312
|
+
[releaseTask, ...jobCleanup.map(entry => entry.task)].filter(task => task !== undefined),
|
|
1313
|
+
deadline,
|
|
1314
|
+
);
|
|
1315
|
+
if (registered && releaseTask) this.#finishAgentRelease(record.id, registered, releaseTask, "release");
|
|
1316
|
+
const pendingJobs = jobCleanup.filter(entry => entry.task.status() === "pending");
|
|
1317
|
+
for (const { job } of pendingJobs) {
|
|
1318
|
+
logger.warn("vibe: timed out waiting for cancelled worker turn; cleanup continues in the background", {
|
|
1319
|
+
id: record.id,
|
|
1320
|
+
jobId: job.id,
|
|
1321
|
+
});
|
|
1210
1322
|
}
|
|
1211
|
-
await awaitCancelledTurnJobs(settlingJobs);
|
|
1212
1323
|
const terminalRef = registered ?? this.#registeredAgent(record) ?? null;
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
}
|
|
1324
|
+
await this.#markTerminalRecord(record, terminalRef, deadline);
|
|
1325
|
+
if (pendingJobs.length > 0) {
|
|
1326
|
+
this.#continueKilledCleanup(
|
|
1327
|
+
record,
|
|
1328
|
+
pendingJobs.map(entry => entry.task),
|
|
1329
|
+
registered,
|
|
1330
|
+
);
|
|
1221
1331
|
}
|
|
1222
1332
|
if (persistenceError) {
|
|
1223
1333
|
let finalPersistenceError = persistenceError;
|
|
@@ -1246,6 +1356,40 @@ export class VibeSessionRegistry {
|
|
|
1246
1356
|
return { id: record.id, cancelledTurn };
|
|
1247
1357
|
}
|
|
1248
1358
|
|
|
1359
|
+
async #markTerminalRecord(
|
|
1360
|
+
record: VibeRecord,
|
|
1361
|
+
expected: AgentRef | null | undefined,
|
|
1362
|
+
teardownDeadline: number,
|
|
1363
|
+
): Promise<void> {
|
|
1364
|
+
if (!record.childSessionFile) return;
|
|
1365
|
+
try {
|
|
1366
|
+
const persisted = await SessionManager.peekSessionInit(record.childSessionFile);
|
|
1367
|
+
if (persisted?.init) {
|
|
1368
|
+
await this.#markTerminalRef(record.id, record.ownerId, record.childSessionFile, expected, teardownDeadline);
|
|
1369
|
+
}
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
logger.warn("vibe: failed to retain terminal worker transcript", {
|
|
1372
|
+
id: record.id,
|
|
1373
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
#continueKilledCleanup(
|
|
1379
|
+
record: VibeRecord,
|
|
1380
|
+
jobTasks: readonly TrackedVibeTeardown[],
|
|
1381
|
+
expected: AgentRef | undefined,
|
|
1382
|
+
): void {
|
|
1383
|
+
void Promise.allSettled(jobTasks.map(task => task.promise))
|
|
1384
|
+
.then(() => this.#markTerminalRecord(record, expected, Date.now() + this.#teardownGraceMs))
|
|
1385
|
+
.catch(error => {
|
|
1386
|
+
logger.warn("vibe: failed to finish killed worker cleanup", {
|
|
1387
|
+
id: record.id,
|
|
1388
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1249
1393
|
/** Build the ExecutorOptions for a first spawn, mirroring the `task`/eval-bridge plumbing. */
|
|
1250
1394
|
async #buildSpawnOptions(
|
|
1251
1395
|
session: ToolSession,
|
|
@@ -30,7 +30,7 @@ export const handleArxiv: SpecialHandler = async (
|
|
|
30
30
|
if (!result.ok) return null;
|
|
31
31
|
|
|
32
32
|
// Parse the Atom feed response
|
|
33
|
-
const { parseHTML } = await import("
|
|
33
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
34
34
|
const doc = parseHTML(result.content).document;
|
|
35
35
|
const entry = doc.querySelector("entry");
|
|
36
36
|
|
|
@@ -96,7 +96,7 @@ export const handleGoPkg: SpecialHandler = async (
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const { parseHTML } = await import("
|
|
99
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
100
100
|
const doc = parseHTML(pageResult.content).document;
|
|
101
101
|
|
|
102
102
|
// Extract actual module path from breadcrumb or header
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
|
+
import { compareVersions, tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
3
3
|
import { buildResult, loadPage } from "./types";
|
|
4
4
|
|
|
@@ -20,17 +20,6 @@ interface ParsedCabal {
|
|
|
20
20
|
stability?: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function compareVersions(a: string, b: string): number {
|
|
24
|
-
const aParts = a.split(".").map(part => Number.parseInt(part, 10) || 0);
|
|
25
|
-
const bParts = b.split(".").map(part => Number.parseInt(part, 10) || 0);
|
|
26
|
-
const max = Math.max(aParts.length, bParts.length);
|
|
27
|
-
for (let i = 0; i < max; i++) {
|
|
28
|
-
const delta = (aParts[i] || 0) - (bParts[i] || 0);
|
|
29
|
-
if (delta !== 0) return delta;
|
|
30
|
-
}
|
|
31
|
-
return 0;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
23
|
function extractCabalField(content: string, fieldName: string): string | undefined {
|
|
35
24
|
const pattern = new RegExp(`^${fieldName}:\\s*(.*)$`, "im");
|
|
36
25
|
const match = content.match(pattern);
|
package/src/web/scrapers/iacr.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const handleIacr: SpecialHandler = async (
|
|
|
29
29
|
|
|
30
30
|
if (!result.ok) return null;
|
|
31
31
|
|
|
32
|
-
const { parseHTML } = await import("
|
|
32
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
33
33
|
const doc = parseHTML(result.content).document;
|
|
34
34
|
|
|
35
35
|
// Extract metadata from the page
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Read the Docs handler for web-fetch
|
|
3
3
|
*/
|
|
4
|
+
import type { Element } from "@oh-my-pi/pi-utils/dom";
|
|
4
5
|
import { buildResult, htmlToBasicMarkdown, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
5
6
|
|
|
6
7
|
export const handleReadTheDocs: SpecialHandler = async (
|
|
@@ -38,7 +39,7 @@ export const handleReadTheDocs: SpecialHandler = async (
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
// Parse HTML
|
|
41
|
-
const { parseHTML } = await import("
|
|
42
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
42
43
|
const root = parseHTML(result.content).document;
|
|
43
44
|
|
|
44
45
|
// Extract main content from common Read the Docs selectors
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HTMLElement } from "
|
|
1
|
+
import type { HTMLElement } from "@oh-my-pi/pi-utils/dom";
|
|
2
2
|
import { ToolAbortError } from "../../tools/tool-errors";
|
|
3
3
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
4
4
|
import { buildResult, loadPage } from "./types";
|
|
@@ -33,7 +33,7 @@ export const handleTwitter: SpecialHandler = async (
|
|
|
33
33
|
|
|
34
34
|
if (result.ok && result.content.length > 500) {
|
|
35
35
|
// Parse the Nitter HTML
|
|
36
|
-
const { parseHTML } = await import("
|
|
36
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
37
37
|
const doc = parseHTML(result.content).document;
|
|
38
38
|
|
|
39
39
|
// Extract tweet content
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { scheduler } from "node:timers/promises";
|
|
5
5
|
import { ptree } from "@oh-my-pi/pi-utils";
|
|
6
|
-
import type TurndownService from "turndown";
|
|
6
|
+
import type TurndownService from "@oh-my-pi/pi-utils/turndown";
|
|
7
7
|
|
|
8
8
|
import type { AgentStorage } from "../../session/agent-storage";
|
|
9
9
|
import { ToolAbortError } from "../../tools/tool-errors";
|
|
@@ -44,7 +44,7 @@ export const handleWikipedia: SpecialHandler = async (
|
|
|
44
44
|
const contentResult = await loadPage(contentUrl, { timeout, signal });
|
|
45
45
|
|
|
46
46
|
if (contentResult.ok) {
|
|
47
|
-
const { parseHTML } = await import("
|
|
47
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
48
48
|
const doc = parseHTML(contentResult.content).document;
|
|
49
49
|
|
|
50
50
|
// Extract main content sections
|
|
@@ -1,28 +1,13 @@
|
|
|
1
|
-
import { HeaderGenerator } from "
|
|
1
|
+
import { HeaderGenerator } from "@oh-my-pi/pi-utils/headers";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
generator ??= new HeaderGenerator({
|
|
13
|
-
browserListQuery: "last 3 versions",
|
|
14
|
-
devices: ["desktop"],
|
|
15
|
-
operatingSystems: ["windows", "macos", "linux"],
|
|
16
|
-
locales: ["en-US", "en"],
|
|
17
|
-
httpVersion: "2",
|
|
18
|
-
strict: false,
|
|
19
|
-
});
|
|
20
|
-
return generator;
|
|
21
|
-
} catch {
|
|
22
|
-
generatorUnavailable = true;
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
3
|
+
const generator = new HeaderGenerator({
|
|
4
|
+
browserListQuery: "last 3 versions",
|
|
5
|
+
devices: ["desktop"],
|
|
6
|
+
operatingSystems: ["windows", "macos", "linux"],
|
|
7
|
+
locales: ["en-US", "en"],
|
|
8
|
+
httpVersion: "2",
|
|
9
|
+
strict: false,
|
|
10
|
+
});
|
|
26
11
|
|
|
27
12
|
// A fallback desktop Mac Chrome navigation fingerprint matching
|
|
28
13
|
// the previous static default setup for deterministic or non-randomized calls.
|
|
@@ -84,9 +69,8 @@ function canonicalizeHeaderNames(headers: Record<string, string>): Record<string
|
|
|
84
69
|
|
|
85
70
|
/**
|
|
86
71
|
* Build a fresh, internally consistent desktop navigation fingerprint for one HTTP request.
|
|
87
|
-
* By default, this randomizes across
|
|
88
|
-
*
|
|
89
|
-
* stable Mac Chrome identity.
|
|
72
|
+
* By default, this randomizes across coherent modern Chrome, Firefox, and Safari profiles.
|
|
73
|
+
* Set `randomized` to `false` when a fetch must preserve a stable Mac Chrome identity.
|
|
90
74
|
*/
|
|
91
75
|
export function buildBrowserNavigationHeaders(options?: { randomized?: boolean }): Record<string, string> {
|
|
92
76
|
const randomized = options?.randomized !== false;
|
|
@@ -94,16 +78,5 @@ export function buildBrowserNavigationHeaders(options?: { randomized?: boolean }
|
|
|
94
78
|
return { ...CHROME_FALLBACK_HEADERS };
|
|
95
79
|
}
|
|
96
80
|
|
|
97
|
-
|
|
98
|
-
if (!generator) {
|
|
99
|
-
return { ...CHROME_FALLBACK_HEADERS };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
// Generate realistic, consistent headers with the Bayesian generator
|
|
104
|
-
return canonicalizeHeaderNames(generator.getHeaders());
|
|
105
|
-
} catch {
|
|
106
|
-
// Gracefully recover to the robust default profile on unexpected generator errors
|
|
107
|
-
return { ...CHROME_FALLBACK_HEADERS };
|
|
108
|
-
}
|
|
81
|
+
return canonicalizeHeaderNames(generator.getHeaders());
|
|
109
82
|
}
|
|
@@ -13,11 +13,7 @@ import {
|
|
|
13
13
|
withAuth,
|
|
14
14
|
withOAuthAccess,
|
|
15
15
|
} from "@oh-my-pi/pi-ai";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
createOpenAICodexCompatibilityMetadata,
|
|
19
|
-
resolveCodexResponsesUrl,
|
|
20
|
-
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
16
|
+
import { resolveCodexResponsesUrl } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
21
17
|
import { getBundledModels } from "@oh-my-pi/pi-catalog/models";
|
|
22
18
|
import {
|
|
23
19
|
CODEX_BASE_URL,
|
|
@@ -447,7 +443,6 @@ async function callCodexSearch(
|
|
|
447
443
|
systemPrompt?: string;
|
|
448
444
|
searchContextSize?: "low" | "medium" | "high";
|
|
449
445
|
model: CodexModelCandidate;
|
|
450
|
-
sessionId?: string;
|
|
451
446
|
fetch?: FetchImpl;
|
|
452
447
|
transport: CodexSearchTransport;
|
|
453
448
|
},
|
|
@@ -455,7 +450,6 @@ async function callCodexSearch(
|
|
|
455
450
|
const headers = buildCodexHeaders(auth.accessToken, auth.accountId, options.transport.headers);
|
|
456
451
|
|
|
457
452
|
const requestedModel = options.model.modelId;
|
|
458
|
-
const usesResponsesLite = options.model.catalogModel?.useResponsesLite === true;
|
|
459
453
|
|
|
460
454
|
const body: Record<string, unknown> = {
|
|
461
455
|
model: requestedModel,
|
|
@@ -477,21 +471,6 @@ async function callCodexSearch(
|
|
|
477
471
|
tool_choice: { type: "web_search" },
|
|
478
472
|
instructions: options.systemPrompt ?? DEFAULT_INSTRUCTIONS,
|
|
479
473
|
};
|
|
480
|
-
if (usesResponsesLite) {
|
|
481
|
-
const metadata = createOpenAICodexCompatibilityMetadata({
|
|
482
|
-
sessionId: options.sessionId,
|
|
483
|
-
requestKind: "turn",
|
|
484
|
-
startNewTurn: true,
|
|
485
|
-
});
|
|
486
|
-
for (const name in metadata.headers) {
|
|
487
|
-
const value = metadata.headers[name];
|
|
488
|
-
if (value !== undefined) headers.set(name, value);
|
|
489
|
-
}
|
|
490
|
-
headers.set(OPENAI_HEADERS.RESPONSES_LITE, "true");
|
|
491
|
-
body.client_metadata = metadata.clientMetadata;
|
|
492
|
-
body.reasoning = { context: "all_turns" };
|
|
493
|
-
applyCodexResponsesLiteShape(body);
|
|
494
|
-
}
|
|
495
474
|
|
|
496
475
|
const fetchImpl = options.fetch ?? fetch;
|
|
497
476
|
const response = await fetchImpl(options.transport.url, {
|
|
@@ -519,9 +498,8 @@ async function callCodexSearch(
|
|
|
519
498
|
let model = requestedModel;
|
|
520
499
|
let requestId = "";
|
|
521
500
|
let usage: { inputTokens: number; outputTokens: number; totalTokens: number } | undefined;
|
|
522
|
-
//
|
|
523
|
-
//
|
|
524
|
-
// command must reject that rather than return a non-search completion.
|
|
501
|
+
// A search command must reject a completion that did not invoke the hosted
|
|
502
|
+
// tool rather than returning an answer from the model's own knowledge (#6988).
|
|
525
503
|
let webSearchInvoked = false;
|
|
526
504
|
|
|
527
505
|
for await (const rawEvent of readSseJson<Record<string, unknown>>(response.body, options.signal)) {
|
|
@@ -651,7 +629,6 @@ async function runCodexSearchCandidates(options: {
|
|
|
651
629
|
systemPrompt: options.params.systemPrompt,
|
|
652
630
|
searchContextSize: "high",
|
|
653
631
|
model: candidate,
|
|
654
|
-
sessionId: options.params.sessionId,
|
|
655
632
|
fetch: options.params.fetch,
|
|
656
633
|
transport: options.transport,
|
|
657
634
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthStorage } from "@oh-my-pi/pi-ai";
|
|
2
|
-
import { parseHTML } from "
|
|
2
|
+
import { parseHTML } from "@oh-my-pi/pi-utils/dom";
|
|
3
3
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
4
4
|
import { SearchProviderError } from "../../../web/search/types";
|
|
5
5
|
import { formatScraperQuery } from "../query";
|
|
@@ -173,7 +173,7 @@ export class EcosiaProvider extends SearchProvider {
|
|
|
173
173
|
return true;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
176
|
+
override isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
177
177
|
return true;
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -458,7 +458,7 @@ export class ExaProvider extends SearchProvider {
|
|
|
458
458
|
* still uses {@link isAvailable} so an unrelated configured provider
|
|
459
459
|
* keeps priority over the public fallback.
|
|
460
460
|
*/
|
|
461
|
-
isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
461
|
+
override isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
462
462
|
return this.#settingsAllowSearch();
|
|
463
463
|
}
|
|
464
464
|
|
|
@@ -203,7 +203,7 @@ export class FirecrawlProvider extends SearchProvider {
|
|
|
203
203
|
* Firecrawl supports keyless mode, so an explicit user selection
|
|
204
204
|
* (`webSearch: firecrawl`) works without any credential configured.
|
|
205
205
|
*/
|
|
206
|
-
isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
206
|
+
override isExplicitlyAvailable(_authStorage: AuthStorage): boolean {
|
|
207
207
|
return true;
|
|
208
208
|
}
|
|
209
209
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthStorage } from "@oh-my-pi/pi-ai";
|
|
2
|
-
import { parseHTML } from "
|
|
2
|
+
import { type Element, parseHTML } from "@oh-my-pi/pi-utils/dom";
|
|
3
3
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
4
4
|
import { SearchProviderError } from "../../../web/search/types";
|
|
5
5
|
import { formatScraperQuery } from "../query";
|