feat(search): web_search onto the injected port — Google CSE retired, research honestly disabled
Chunk A of the search port wave (2026-09-20), per master's assignment: - web.ts: the Google Custom Search backend is gone — web_search now runs on the core search port (SearchProvider), injected as a dependency (import law: the tool never imports server code). createWebTools(search) resolves the LIVE provider fresh per call; null = the honest unavailability string (no silent fallback, owner decision). web_fetch unchanged (needs no engine). - runner: JobRunnerDeps.searchProvider — the server composition threaded into the researcher; jobs already in flight when a key disappears still fail honestly through the same seam, never crash. - jobTools: the research dispatch tool DROPS from the teacher's registry when ctx.searchAvailable() is false (owner decision: registry-level drop — the model never sees the tool, no doomed dispatch, no error card). Absent seam = available (tests). chat-handler injects server/searchAvailable + searchProvider. - tests: stubFetch (the Google wire stub) retired; jobs.test.ts threads a recording stub provider through all four research runners and asserts the scripted query hit the port; new web-search.test.ts covers the factory contract (null → honest string, hits, error strings, fresh resolution, web_fetch independence) + the registry drop matrix. Gates: typecheck, 793/793 tests, lint, build — all green.
This commit is contained in:
@@ -11,6 +11,7 @@ import { claimSteers, deliverJobResult, setContextRespawn, setJobRespawn, setTur
|
||||
import { recordToPiMessages } from "./pi/record-adapter.ts";
|
||||
import { createPiTurnResponse } from "./pi/ui-stream.ts";
|
||||
import { effectiveSettings, MODEL_PINS, stores } from "./stores.ts";
|
||||
import { searchAvailable, searchProvider } from "./search.ts";
|
||||
import { extractionEnabled, graphContextEnabled, resolveRoleSpec } from "../core/settings-resolution.ts";
|
||||
import { beginTurn, endTurn } from "./turn-liveness.ts";
|
||||
import { persistTurn, triggerExtraction, triggerGraphContext, withMessageIds } from "./turn-service.ts";
|
||||
@@ -45,6 +46,11 @@ const jobRunner = createJobRunner({
|
||||
// per-role overrides reached rolePins but never the engines.
|
||||
engineFor: (role) =>
|
||||
piEngineForSpec(resolveRoleSpec(role, stores.settingsStore.readSettings(), MODEL_PINS)),
|
||||
// Search port wave (2026-09-20): the researcher's web_search runs on the
|
||||
// injected port — resolved FRESH per job (key rotations land immediately).
|
||||
// null = honestly unavailable; the dispatch-level drop (below) uses the
|
||||
// same signal so keyless servers never see the research tool at all.
|
||||
searchProvider,
|
||||
});
|
||||
/** The app's ONE extraction pipeline instance — both front doors share it:
|
||||
* quiz-triggered session runs (turn-service) and notes imports
|
||||
@@ -252,6 +258,9 @@ export async function handleChatRequest(
|
||||
chatStore: stores.chatStore,
|
||||
jobStore: stores.jobStore,
|
||||
spawn: (job, input) => void jobRunner.runJob(job.id, input),
|
||||
// The registry drop's signal (2026-09-20): no live engine
|
||||
// = no research tool in the teacher's registry.
|
||||
searchAvailable,
|
||||
},
|
||||
agentOpts,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user