@oh-my-pi/pi-coding-agent 15.10.5 → 15.10.7

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/types/exa/index.d.ts +1 -19
  3. package/dist/types/exa/mcp-client.d.ts +10 -3
  4. package/dist/types/exa/types.d.ts +0 -83
  5. package/dist/types/modes/controllers/mcp-command-controller.d.ts +8 -0
  6. package/dist/types/modes/interactive-mode.d.ts +8 -0
  7. package/dist/types/modes/types.d.ts +1 -0
  8. package/dist/types/task/render.d.ts +1 -0
  9. package/dist/types/tools/index.d.ts +0 -2
  10. package/dist/types/utils/git.d.ts +6 -0
  11. package/package.json +9 -9
  12. package/src/cli/auth-gateway-cli.ts +3 -2
  13. package/src/commit/agentic/tools/split-commit.ts +8 -1
  14. package/src/config/model-provider-priority.ts +1 -0
  15. package/src/exa/index.ts +1 -26
  16. package/src/exa/mcp-client.ts +10 -10
  17. package/src/exa/types.ts +0 -97
  18. package/src/internal-urls/docs-index.generated.ts +1 -1
  19. package/src/mcp/manager.ts +17 -16
  20. package/src/modes/components/agent-dashboard.ts +6 -4
  21. package/src/modes/controllers/event-controller.ts +8 -0
  22. package/src/modes/controllers/input-controller.ts +24 -1
  23. package/src/modes/controllers/mcp-command-controller.ts +24 -5
  24. package/src/modes/interactive-mode.ts +33 -1
  25. package/src/modes/types.ts +1 -0
  26. package/src/prompts/tools/read.md +0 -1
  27. package/src/session/agent-session.ts +77 -41
  28. package/src/slash-commands/builtin-registry.ts +8 -0
  29. package/src/task/index.ts +9 -1
  30. package/src/task/render.ts +22 -12
  31. package/src/tools/index.ts +0 -4
  32. package/src/utils/git.ts +41 -0
  33. package/dist/types/exa/factory.d.ts +0 -13
  34. package/dist/types/exa/render.d.ts +0 -19
  35. package/dist/types/exa/researcher.d.ts +0 -9
  36. package/dist/types/exa/search.d.ts +0 -9
  37. package/dist/types/exa/websets.d.ts +0 -9
  38. package/src/exa/factory.ts +0 -60
  39. package/src/exa/render.ts +0 -244
  40. package/src/exa/researcher.ts +0 -36
  41. package/src/exa/search.ts +0 -47
  42. package/src/exa/websets.ts +0 -248
package/CHANGELOG.md CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.10.7] - 2026-06-08
6
+
7
+ ### Fixed
8
+
9
+ - Fixed MCP OAuth fallback rendering to show a short terminal hyperlink and keep the raw authorization URL on one unwrapped copy line ([#2121](https://github.com/can1357/oh-my-pi/issues/2121)).
10
+ - Fixed `omp` startup blocking 25–30 s on a single unresponsive MCP server when no cached tools were available for it. `MCPManager.connectServers` used to fall through to an unbounded `Promise.allSettled` over every still-pending server without a cached tool list, so one server stuck waiting on the per-request MCP timeout (`OMP_MCP_TIMEOUT_MS`, default 30 000 ms) gated the entire UI ready signal. Pending-without-cache servers are now left in flight: their tools surface via the existing background `#onToolsChanged` → `refreshMCPTools` path the moment the connect completes, and failures continue to log through the background catch handler ([#2100](https://github.com/can1357/oh-my-pi/issues/2100)).
11
+
12
+ ## [15.10.6] - 2026-06-08
13
+
14
+ ### Added
15
+
16
+ - Added a `/plan-review` command that manually (re-)opens the plan-review overlay while plan mode is active. Since there is no fixed plan filename, it reviews the newest `local://<slug>-plan.md` the agent wrote — useful for pulling the review back up after dismissing it, or reviewing a plan the agent wrote without calling `resolve`.
17
+
18
+ ### Changed
19
+
20
+ - Reverted the `task` tool's result-header glyph from the `⇶` signature icon back to the quiet `status.done` bullet (`•`): white while a subagent is running, accent once it finishes. The reviewer verdict line and per-agent result lines use the same bullet.
21
+
22
+ ### Fixed
23
+
24
+ - Fixed `/login` API-key prompts (OpenCode Zen, Perplexity OTP, GitHub Enterprise URL, manual OAuth redirect URL, …) silently dropping pasted content on kitty/Linux/Wayland — and any other terminal supporting OSC 5522 enhanced paste. `InputController` enables kitty's enhanced clipboard protocol on TUI start and consumes the resulting OSC 5522 packets in an `addInputListener` that runs before focus dispatch, so the paste never reached the modal `Input`'s bracketed-paste handler; the routing then stuffed the text into the main `CustomEditor` unconditionally, even when `selector-controller` had detached the editor and focused a temporary OAuth input. The pasted API key accumulated in the hidden editor and only resurfaced in the main prompt when the user dismissed the modal with Enter or Esc. The enhanced-paste callback now consults `ui.getFocused()` and routes the text to the focused component when it exposes a `pasteText` hook, falling back to the editor only when no modal target is in focus; image pastes refuse with a status message instead of stuffing a binary blob into the hidden editor. ([#2127](https://github.com/can1357/oh-my-pi/issues/2127))
25
+ - Fixed an auto-compaction dead loop when `compaction.strategy` was `shake` and the configured threshold was low enough that a single shake pass could not bring the context below it (e.g. a 50K-token threshold on a session well above it). Each pass auto-continued, the next agent turn re-triggered the threshold check, and the second shake had nothing new to drop, so the session spun forever. The shake recovery path now estimates post-shake context and, when it is still above the threshold (or shake reclaimed nothing on overflow recovery), surfaces a one-shot warning and falls back to the summarization-driven `context-full` compaction so progress actually resumes ([#2119](https://github.com/can1357/oh-my-pi/issues/2119)).
26
+ - Fixed `/skill:` prompts so magic keywords and turn-budget directives in skill args inject the same hidden notices as normal user prompts, matching the editor highlight behavior ([#2128](https://github.com/can1357/oh-my-pi/issues/2128)).
27
+ - Fixed MCP OAuth fallback rendering to show a short terminal hyperlink and keep the raw authorization URL on one unwrapped copy line ([#2121](https://github.com/can1357/oh-my-pi/issues/2121)).
28
+ - Fixed the `task` tool rendering a success bullet and a `success` frame state for detail-less error results (e.g. an argument-validation failure that never executes): the header now shows the error glyph with an error border and `error` state, and surfaces the dispatched agent name.
29
+ - Fixed Agent Control Center new-agent creation so Windows Ctrl+Enter sequences submitted as a single LF generate the agent instead of inserting a newline ([#2118](https://github.com/can1357/oh-my-pi/issues/2118)).
30
+ - Fixed plan-mode subagents preserving read-only specialty tools such as `report_finding` while still stripping mutating tools ([#1998](https://github.com/can1357/oh-my-pi/issues/1998)).
31
+ - Removed unreachable standalone Exa tool-suite exports and stale tool-count barrel exposure while keeping the live Exa `web_search` provider helpers ([#2093](https://github.com/can1357/oh-my-pi/issues/2093)).
32
+ - Fixed `omp commit` split plans accepting hunk selectors that resolve to no parsed hunks, which crashed the apply step after the index reset and left the working tree fully unstaged ([#2098](https://github.com/can1357/oh-my-pi/issues/2098)).
33
+
5
34
  ## [15.10.5] - 2026-06-08
6
35
 
7
36
  ### Added
@@ -1,20 +1,2 @@
1
- /**
2
- * Exa MCP Tools
3
- *
4
- * 22 tools for Exa's MCP servers:
5
- * - 4 search tools (search, deep, code, crawl)
6
- * - 1 LinkedIn search tool
7
- * - 1 company research tool
8
- * - 2 researcher tools (start, poll)
9
- * - 14 websets tools (CRUD, items, search, enrichment, monitor)
10
- */
11
- import type { CustomTool } from "../extensibility/custom-tools/types";
12
- import type { ExaRenderDetails } from "./types";
13
- /** All Exa tools (22 total) - static export for backward compatibility */
14
- export declare const exaTools: CustomTool<any, ExaRenderDetails>[];
15
1
  export * from "./mcp-client";
16
- export { renderExaCall, renderExaResult } from "./render";
17
- export { researcherTools } from "./researcher";
18
- export { searchTools } from "./search";
19
- export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult, MCPToolWrapperConfig } from "./types";
20
- export { websetsTools } from "./websets";
2
+ export type { ExaSearchResponse, MCPCallResponse, MCPTool, MCPToolsResponse, MCPToolWrapperConfig } from "./types";
@@ -1,7 +1,13 @@
1
1
  import type { TSchema } from "@oh-my-pi/pi-ai";
2
2
  import type { CustomTool, CustomToolResult } from "../extensibility/custom-tools/types";
3
3
  import { type CallMcpOptions } from "../mcp/json-rpc";
4
- import type { ExaRenderDetails, ExaSearchResponse, MCPTool, MCPToolWrapperConfig } from "./types";
4
+ import type { ExaSearchResponse, MCPTool, MCPToolWrapperConfig } from "./types";
5
+ type MCPWrappedToolDetails = {
6
+ response?: ExaSearchResponse;
7
+ error?: string;
8
+ toolName?: string;
9
+ raw?: unknown;
10
+ };
5
11
  /** Find EXA_API_KEY from Bun.env or .env files */
6
12
  export declare function findApiKey(): string | null;
7
13
  /** Fetch available tools from Exa MCP */
@@ -29,14 +35,14 @@ export declare function fetchMCPToolSchema(apiKey: string, mcpToolName: string,
29
35
  * This allows tools to be generated from MCP server schemas without hardcoding,
30
36
  * reducing drift when MCP servers add new parameters.
31
37
  */
32
- export declare class MCPWrappedTool implements CustomTool<TSchema, ExaRenderDetails> {
38
+ export declare class MCPWrappedTool implements CustomTool<TSchema, MCPWrappedToolDetails> {
33
39
  private readonly config;
34
40
  readonly parameters: TSchema;
35
41
  readonly description: string;
36
42
  readonly name: string;
37
43
  readonly label: string;
38
44
  constructor(config: MCPToolWrapperConfig, parameters: TSchema, description: string);
39
- execute(_toolCallId: string, params: unknown, _onUpdate?: unknown, _ctx?: unknown, _signal?: AbortSignal): Promise<CustomToolResult<ExaRenderDetails>>;
45
+ execute(_toolCallId: string, params: unknown, _onUpdate?: unknown, _ctx?: unknown, _signal?: AbortSignal): Promise<CustomToolResult<MCPWrappedToolDetails>>;
40
46
  }
41
47
  /**
42
48
  * Create a CustomTool by fetching schema from MCP server.
@@ -44,3 +50,4 @@ export declare class MCPWrappedTool implements CustomTool<TSchema, ExaRenderDeta
44
50
  * Falls back to provided fallback schema if MCP fetch fails.
45
51
  */
46
52
  export declare function createMCPToolFromServer(apiKey: string, config: MCPToolWrapperConfig, fallbackSchema: TSchema, fallbackDescription: string): Promise<MCPWrappedTool>;
53
+ export {};
@@ -4,9 +4,6 @@
4
4
  * Types for the Exa MCP client and tool implementations.
5
5
  */
6
6
  import type { TSchema } from "@oh-my-pi/pi-ai";
7
- /** MCP endpoint URLs */
8
- export declare const EXA_MCP_URL = "https://mcp.exa.ai/mcp";
9
- export declare const WEBSETS_MCP_URL = "https://websetsmcp.exa.ai/mcp";
10
7
  /** MCP tool definition from server */
11
8
  export interface MCPTool {
12
9
  name: string;
@@ -73,83 +70,3 @@ export interface ExaSearchResponse {
73
70
  searchTime?: number;
74
71
  requestId?: string;
75
72
  }
76
- /** Researcher task status */
77
- export interface ResearcherStatus {
78
- id: string;
79
- status: "pending" | "running" | "completed" | "failed";
80
- result?: string;
81
- error?: string;
82
- }
83
- /** Webset definition */
84
- export interface Webset {
85
- id: string;
86
- name: string;
87
- description?: string;
88
- createdAt?: string;
89
- updatedAt?: string;
90
- }
91
- /** Webset item */
92
- export interface WebsetItem {
93
- id: string;
94
- websetId: string;
95
- url: string;
96
- title?: string;
97
- content?: string;
98
- metadata?: Record<string, unknown>;
99
- }
100
- /** Webset search */
101
- export interface WebsetSearch {
102
- id: string;
103
- websetId: string;
104
- query: string;
105
- status: "pending" | "running" | "completed" | "cancelled";
106
- resultCount?: number;
107
- }
108
- /** Webset enrichment */
109
- export interface WebsetEnrichment {
110
- id: string;
111
- websetId: string;
112
- name: string;
113
- prompt: string;
114
- status: "pending" | "running" | "completed" | "cancelled";
115
- }
116
- /** Tool name mappings: MCP name -> our tool name */
117
- export declare const EXA_TOOL_MAPPINGS: {
118
- readonly web_search_exa: "exa_search";
119
- readonly get_code_context_exa: "exa_search_code";
120
- readonly crawling_exa: "exa_crawl";
121
- readonly linkedin_search_exa: "exa_linkedin";
122
- readonly company_research_exa: "exa_company";
123
- readonly deep_researcher_start: "exa_researcher_start";
124
- readonly deep_researcher_check: "exa_researcher_poll";
125
- };
126
- export declare const WEBSETS_TOOL_MAPPINGS: {
127
- readonly create_webset: "webset_create";
128
- readonly list_websets: "webset_list";
129
- readonly get_webset: "webset_get";
130
- readonly update_webset: "webset_update";
131
- readonly delete_webset: "webset_delete";
132
- readonly list_webset_items: "webset_items_list";
133
- readonly get_item: "webset_item_get";
134
- readonly create_search: "webset_search_create";
135
- readonly get_search: "webset_search_get";
136
- readonly cancel_search: "webset_search_cancel";
137
- readonly create_enrichment: "webset_enrichment_create";
138
- readonly get_enrichment: "webset_enrichment_get";
139
- readonly update_enrichment: "webset_enrichment_update";
140
- readonly delete_enrichment: "webset_enrichment_delete";
141
- readonly cancel_enrichment: "webset_enrichment_cancel";
142
- readonly create_monitor: "webset_monitor_create";
143
- };
144
- export type ExaMcpToolName = keyof typeof EXA_TOOL_MAPPINGS;
145
- export type WebsetsMcpToolName = keyof typeof WEBSETS_TOOL_MAPPINGS;
146
- export type ExaToolName = (typeof EXA_TOOL_MAPPINGS)[ExaMcpToolName];
147
- export type WebsetsToolName = (typeof WEBSETS_TOOL_MAPPINGS)[WebsetsMcpToolName];
148
- /** Render details for TUI */
149
- export interface ExaRenderDetails {
150
- response?: ExaSearchResponse;
151
- error?: string;
152
- toolName?: string;
153
- /** Raw result for non-search responses */
154
- raw?: unknown;
155
- }
@@ -1,4 +1,12 @@
1
+ import { type Component } from "@oh-my-pi/pi-tui";
1
2
  import type { InteractiveModeContext } from "../types";
3
+ /** Renders the MCP OAuth fallback URL without hard-wrapping the copy target. */
4
+ export declare class MCPAuthorizationLinkPrompt implements Component {
5
+ #private;
6
+ constructor(url: string);
7
+ invalidate(): void;
8
+ render(_width: number): string[];
9
+ }
2
10
  export declare class MCPCommandController {
3
11
  #private;
4
12
  private ctx;
@@ -161,6 +161,14 @@ export declare class InteractiveMode implements InteractiveModeContext {
161
161
  }): Promise<string | undefined>;
162
162
  handlePlanModeCommand(initialPrompt?: string): Promise<void>;
163
163
  handleGoalModeCommand(rest?: string): Promise<void>;
164
+ /** Manually (re-)open the plan-review overlay — bound to `/plan-review`. Lets
165
+ * the operator pull the review back up after dismissing it, or review a plan
166
+ * the agent wrote without calling `resolve`. There is no fixed plan filename:
167
+ * `getPlanReferencePath()` is empty until a plan is actually approved (and does
168
+ * not survive a restart), so this drives off the newest `local://<slug>-plan.md`
169
+ * the agent wrote — the files persist in the session artifacts dir, so the scan
170
+ * works before any review and across restarts. */
171
+ openPlanReview(): Promise<void>;
164
172
  handlePlanApproval(details: PlanApprovalDetails): Promise<void>;
165
173
  stop(): void;
166
174
  shutdown(): Promise<void>;
@@ -290,6 +290,7 @@ export interface InteractiveModeContext {
290
290
  disableLoopMode(): void;
291
291
  pauseLoop(): void;
292
292
  handlePlanApproval(details: PlanApprovalDetails): Promise<void>;
293
+ openPlanReview(): Promise<void>;
293
294
  initHooksAndCustomTools(): Promise<void>;
294
295
  emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string): Promise<void>;
295
296
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
@@ -19,6 +19,7 @@ export declare function renderResult(result: {
19
19
  text?: string;
20
20
  }>;
21
21
  details?: TaskToolDetails;
22
+ isError?: boolean;
22
23
  }, options: RenderResultOptions, theme: Theme, args?: TaskParams): Component;
23
24
  export declare const taskToolRenderer: {
24
25
  renderCall: typeof renderCall;
@@ -23,8 +23,6 @@ import type { WorkspaceTree } from "../workspace-tree";
23
23
  import { type CheckpointState } from "./checkpoint";
24
24
  import { type TodoPhase } from "./todo";
25
25
  export * from "../edit";
26
- export * from "../exa";
27
- export type * from "../exa/types";
28
26
  export * from "../goals";
29
27
  export * from "../lsp";
30
28
  export * from "../session/streaming-output";
@@ -34,6 +34,10 @@ export interface StageHunksOptions {
34
34
  readonly rawDiff?: string;
35
35
  readonly signal?: AbortSignal;
36
36
  }
37
+ export interface HunkSelectionValidationError {
38
+ readonly path: string;
39
+ readonly message: string;
40
+ }
37
41
  export interface DiffOptions {
38
42
  readonly allowFailure?: boolean;
39
43
  readonly base?: string;
@@ -128,6 +132,8 @@ interface CommandOptions {
128
132
  * module never auto-acquire — callers wrap the critical section themselves.
129
133
  */
130
134
  export declare function withRepoLock<T>(cwd: string, fn: () => Promise<T>, signal?: AbortSignal): Promise<T>;
135
+ export declare function createHunkSelectionValidator(rawDiff: string): (selections: readonly HunkSelection[]) => HunkSelectionValidationError[];
136
+ export declare function validateHunkSelections(rawDiff: string, selections: readonly HunkSelection[]): HunkSelectionValidationError[];
131
137
  declare function parseStatusPorcelain(text: string): GitStatusSummary;
132
138
  /** Run `git diff` with the given options. Returns raw diff text. */
133
139
  export declare const diff: ((cwd: string, options?: DiffOptions) => Promise<string>) & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "15.10.5",
4
+ "version": "15.10.7",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -47,14 +47,14 @@
47
47
  "@agentclientprotocol/sdk": "0.22.1",
48
48
  "@babel/parser": "^7.29.7",
49
49
  "@mozilla/readability": "^0.6.0",
50
- "@oh-my-pi/hashline": "15.10.5",
51
- "@oh-my-pi/omp-stats": "15.10.5",
52
- "@oh-my-pi/pi-agent-core": "15.10.5",
53
- "@oh-my-pi/pi-ai": "15.10.5",
54
- "@oh-my-pi/pi-mnemopi": "15.10.5",
55
- "@oh-my-pi/pi-natives": "15.10.5",
56
- "@oh-my-pi/pi-tui": "15.10.5",
57
- "@oh-my-pi/pi-utils": "15.10.5",
50
+ "@oh-my-pi/hashline": "15.10.7",
51
+ "@oh-my-pi/omp-stats": "15.10.7",
52
+ "@oh-my-pi/pi-agent-core": "15.10.7",
53
+ "@oh-my-pi/pi-ai": "15.10.7",
54
+ "@oh-my-pi/pi-mnemopi": "15.10.7",
55
+ "@oh-my-pi/pi-natives": "15.10.7",
56
+ "@oh-my-pi/pi-tui": "15.10.7",
57
+ "@oh-my-pi/pi-utils": "15.10.7",
58
58
  "@opentelemetry/api": "^1.9.1",
59
59
  "@opentelemetry/context-async-hooks": "^2.7.1",
60
60
  "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0",
@@ -175,8 +175,9 @@ async function runServe(flags: AuthGatewayCommandArgs["flags"]): Promise<void> {
175
175
  for (const provider of getBundledProviders()) {
176
176
  if (!providersWithCreds.has(provider)) continue;
177
177
  for (const model of getBundledModels(provider as GeneratedProvider)) {
178
- // First-write-wins so a canonical model id collisions across providers
179
- // stick to the provider listed first by getBundledProviders.
178
+ // Always set the qualified key (no collision possible)
179
+ modelById.set(`${model.provider}/${model.id}`, model);
180
+ // Bare id as fallback for legacy clients (first-write-wins)
180
181
  if (!modelById.has(model.id)) modelById.set(model.id, model);
181
182
  }
182
183
  }
@@ -68,6 +68,7 @@ export function createSplitCommitTool(
68
68
  const errors: string[] = [];
69
69
  const warnings: string[] = [];
70
70
  const diffText = await git.diff(cwd, { cached: true });
71
+ const validateHunksForDiff = git.createHunkSelectionValidator(diffText);
71
72
 
72
73
  const commits: SplitCommitGroup[] = params.commits.map((commit, index) => {
73
74
  const scope = commit.scope?.trim() || null;
@@ -102,7 +103,7 @@ export function createSplitCommitTool(
102
103
  }
103
104
  warnings.push(...summaryValidation.warnings.map(warning => `Commit ${index + 1}: ${warning}`));
104
105
  warnings.push(...typeValidation.warnings.map(warning => `Commit ${index + 1}: ${warning}`));
105
- const hunkValidation = validateHunkSelectors(index, changes, files);
106
+ const hunkValidation = validateHunkSelectors(index, changes, files, validateHunksForDiff);
106
107
  warnings.push(...hunkValidation.warnings);
107
108
  errors.push(...hunkValidation.errors);
108
109
  errors.push(...validateDependencies(index, dependencies, params.commits.length));
@@ -186,6 +187,7 @@ function validateHunkSelectors(
186
187
  commitIndex: number,
187
188
  changes: SplitCommitGroup["changes"],
188
189
  files: string[],
190
+ validateHunksForDiff: (changes: SplitCommitGroup["changes"]) => git.HunkSelectionValidationError[],
189
191
  ): { errors: string[]; warnings: string[] } {
190
192
  const errors: string[] = [];
191
193
  const warnings: string[] = [];
@@ -215,6 +217,11 @@ function validateHunkSelectors(
215
217
  }
216
218
  }
217
219
  }
220
+ if (errors.length === 0) {
221
+ for (const error of validateHunksForDiff(changes)) {
222
+ errors.push(`${prefix}: ${error.message}`);
223
+ }
224
+ }
218
225
  return { errors, warnings };
219
226
  }
220
227
 
@@ -21,6 +21,7 @@ const DEFAULT_MODEL_PROVIDER_ORDER = [
21
21
  "fireworks",
22
22
  "cerebras",
23
23
  "openrouter",
24
+ "aimlapi",
24
25
  "together",
25
26
 
26
27
  // Generic gateways and editor/proxy providers. These are useful when picked
package/src/exa/index.ts CHANGED
@@ -1,27 +1,2 @@
1
- /**
2
- * Exa MCP Tools
3
- *
4
- * 22 tools for Exa's MCP servers:
5
- * - 4 search tools (search, deep, code, crawl)
6
- * - 1 LinkedIn search tool
7
- * - 1 company research tool
8
- * - 2 researcher tools (start, poll)
9
- * - 14 websets tools (CRUD, items, search, enrichment, monitor)
10
- */
11
- import type { CustomTool } from "../extensibility/custom-tools/types";
12
- import { researcherTools } from "./researcher";
13
- import { searchTools } from "./search";
14
- import type { ExaRenderDetails } from "./types";
15
- import { websetsTools } from "./websets";
16
-
17
- /** All Exa tools (22 total) - static export for backward compatibility */
18
- export const exaTools: CustomTool<any, ExaRenderDetails>[] = [...searchTools, ...researcherTools, ...websetsTools];
19
-
20
1
  export * from "./mcp-client";
21
- export { renderExaCall, renderExaResult } from "./render";
22
- export { researcherTools } from "./researcher";
23
- // Re-export individual modules for selective importing
24
- export { searchTools } from "./search";
25
- // Re-export types and utilities
26
- export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult, MCPToolWrapperConfig } from "./types";
27
- export { websetsTools } from "./websets";
2
+ export type { ExaSearchResponse, MCPCallResponse, MCPTool, MCPToolsResponse, MCPToolWrapperConfig } from "./types";
@@ -2,14 +2,14 @@ import type { TSchema } from "@oh-my-pi/pi-ai";
2
2
  import { $env, logger } from "@oh-my-pi/pi-utils";
3
3
  import type { CustomTool, CustomToolResult } from "../extensibility/custom-tools/types";
4
4
  import { type CallMcpOptions, callMCP } from "../mcp/json-rpc";
5
- import type {
6
- ExaRenderDetails,
7
- ExaSearchResponse,
8
- MCPCallResponse,
9
- MCPTool,
10
- MCPToolsResponse,
11
- MCPToolWrapperConfig,
12
- } from "./types";
5
+ import type { ExaSearchResponse, MCPCallResponse, MCPTool, MCPToolsResponse, MCPToolWrapperConfig } from "./types";
6
+
7
+ type MCPWrappedToolDetails = {
8
+ response?: ExaSearchResponse;
9
+ error?: string;
10
+ toolName?: string;
11
+ raw?: unknown;
12
+ };
13
13
 
14
14
  /** Find EXA_API_KEY from Bun.env or .env files */
15
15
  export function findApiKey(): string | null {
@@ -296,7 +296,7 @@ export async function fetchMCPToolSchema(
296
296
  * This allows tools to be generated from MCP server schemas without hardcoding,
297
297
  * reducing drift when MCP servers add new parameters.
298
298
  */
299
- export class MCPWrappedTool implements CustomTool<TSchema, ExaRenderDetails> {
299
+ export class MCPWrappedTool implements CustomTool<TSchema, MCPWrappedToolDetails> {
300
300
  readonly name: string;
301
301
  readonly label: string;
302
302
 
@@ -315,7 +315,7 @@ export class MCPWrappedTool implements CustomTool<TSchema, ExaRenderDetails> {
315
315
  _onUpdate?: unknown,
316
316
  _ctx?: unknown,
317
317
  _signal?: AbortSignal,
318
- ): Promise<CustomToolResult<ExaRenderDetails>> {
318
+ ): Promise<CustomToolResult<MCPWrappedToolDetails>> {
319
319
  try {
320
320
  const apiKey = findApiKey();
321
321
  // Websets tools require an API key; basic Exa MCP tools work without one
package/src/exa/types.ts CHANGED
@@ -5,10 +5,6 @@
5
5
  */
6
6
  import type { TSchema } from "@oh-my-pi/pi-ai";
7
7
 
8
- /** MCP endpoint URLs */
9
- export const EXA_MCP_URL = "https://mcp.exa.ai/mcp";
10
- export const WEBSETS_MCP_URL = "https://websetsmcp.exa.ai/mcp";
11
-
12
8
  /** MCP tool definition from server */
13
9
  export interface MCPTool {
14
10
  name: string;
@@ -71,96 +67,3 @@ export interface ExaSearchResponse {
71
67
  searchTime?: number;
72
68
  requestId?: string;
73
69
  }
74
-
75
- /** Researcher task status */
76
- export interface ResearcherStatus {
77
- id: string;
78
- status: "pending" | "running" | "completed" | "failed";
79
- result?: string;
80
- error?: string;
81
- }
82
-
83
- /** Webset definition */
84
- export interface Webset {
85
- id: string;
86
- name: string;
87
- description?: string;
88
- createdAt?: string;
89
- updatedAt?: string;
90
- }
91
-
92
- /** Webset item */
93
- export interface WebsetItem {
94
- id: string;
95
- websetId: string;
96
- url: string;
97
- title?: string;
98
- content?: string;
99
- metadata?: Record<string, unknown>;
100
- }
101
-
102
- /** Webset search */
103
- export interface WebsetSearch {
104
- id: string;
105
- websetId: string;
106
- query: string;
107
- status: "pending" | "running" | "completed" | "cancelled";
108
- resultCount?: number;
109
- }
110
-
111
- /** Webset enrichment */
112
- export interface WebsetEnrichment {
113
- id: string;
114
- websetId: string;
115
- name: string;
116
- prompt: string;
117
- status: "pending" | "running" | "completed" | "cancelled";
118
- }
119
-
120
- /** Tool name mappings: MCP name -> our tool name */
121
- export const EXA_TOOL_MAPPINGS = {
122
- // Search tools
123
- web_search_exa: "exa_search",
124
- get_code_context_exa: "exa_search_code",
125
- crawling_exa: "exa_crawl",
126
- // LinkedIn
127
- linkedin_search_exa: "exa_linkedin",
128
- // Company
129
- company_research_exa: "exa_company",
130
- // Researcher
131
- deep_researcher_start: "exa_researcher_start",
132
- deep_researcher_check: "exa_researcher_poll",
133
- } as const;
134
-
135
- export const WEBSETS_TOOL_MAPPINGS = {
136
- create_webset: "webset_create",
137
- list_websets: "webset_list",
138
- get_webset: "webset_get",
139
- update_webset: "webset_update",
140
- delete_webset: "webset_delete",
141
- list_webset_items: "webset_items_list",
142
- get_item: "webset_item_get",
143
- create_search: "webset_search_create",
144
- get_search: "webset_search_get",
145
- cancel_search: "webset_search_cancel",
146
- create_enrichment: "webset_enrichment_create",
147
- get_enrichment: "webset_enrichment_get",
148
- update_enrichment: "webset_enrichment_update",
149
- delete_enrichment: "webset_enrichment_delete",
150
- cancel_enrichment: "webset_enrichment_cancel",
151
- create_monitor: "webset_monitor_create",
152
- } as const;
153
-
154
- export type ExaMcpToolName = keyof typeof EXA_TOOL_MAPPINGS;
155
- export type WebsetsMcpToolName = keyof typeof WEBSETS_TOOL_MAPPINGS;
156
- export type ExaToolName = (typeof EXA_TOOL_MAPPINGS)[ExaMcpToolName];
157
- export type WebsetsToolName = (typeof WEBSETS_TOOL_MAPPINGS)[WebsetsMcpToolName];
158
-
159
- /** Render details for TUI */
160
- export interface ExaRenderDetails {
161
- response?: ExaSearchResponse;
162
- error?: string;
163
- toolName?: string;
164
- /** Raw result for non-search responses */
165
- raw?: unknown;
166
- }