@oh-my-pi/pi-coding-agent 12.10.0 → 12.11.0
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 +37 -0
- package/package.json +7 -7
- package/src/cli/web-search-cli.ts +1 -0
- package/src/commands/web-search.ts +1 -0
- package/src/commit/model-selection.ts +2 -2
- package/src/config/model-registry.ts +259 -297
- package/src/config/model-resolver.ts +5 -68
- package/src/config/settings-schema.ts +10 -0
- package/src/modes/components/model-selector.ts +24 -0
- package/src/modes/components/settings-defs.ts +11 -1
- package/src/modes/controllers/selector-controller.ts +4 -0
- package/src/modes/interactive-mode.ts +1 -0
- package/src/priority.json +28 -0
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/plan.md +1 -1
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/session/agent-session.ts +41 -8
- package/src/session/auth-storage.ts +87 -0
- package/src/tools/browser.ts +30 -2
- package/src/utils/title-generator.ts +3 -2
- package/src/web/search/index.ts +4 -4
- package/src/web/search/provider.ts +4 -1
- package/src/web/search/providers/anthropic.ts +2 -17
- package/src/web/search/providers/synthetic.ts +136 -0
- package/src/web/search/types.ts +10 -1
|
@@ -4,12 +4,7 @@
|
|
|
4
4
|
* Uses Claude's built-in web_search_20250305 tool to search the web.
|
|
5
5
|
* Returns synthesized answers with citations and source metadata.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
type AnthropicSystemBlock,
|
|
9
|
-
applyClaudeToolPrefix,
|
|
10
|
-
buildAnthropicSystemBlocks,
|
|
11
|
-
stripClaudeToolPrefix,
|
|
12
|
-
} from "@oh-my-pi/pi-ai";
|
|
7
|
+
import { type AnthropicSystemBlock, buildAnthropicSystemBlocks, stripClaudeToolPrefix } from "@oh-my-pi/pi-ai";
|
|
13
8
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
14
9
|
import { buildAnthropicHeaders, buildAnthropicUrl, findAnthropicAuth } from "../../../web/search/auth";
|
|
15
10
|
import type {
|
|
@@ -29,16 +24,6 @@ const DEFAULT_MAX_TOKENS = 4096;
|
|
|
29
24
|
const WEB_SEARCH_TOOL_NAME = "web_search";
|
|
30
25
|
const WEB_SEARCH_TOOL_TYPE = "web_search_20250305";
|
|
31
26
|
|
|
32
|
-
/**
|
|
33
|
-
* Applies OAuth-specific tool prefix to search tool name.
|
|
34
|
-
* @param name - The base tool name
|
|
35
|
-
* @param isOAuth - Whether OAuth authentication is being used
|
|
36
|
-
* @returns Tool name with prefix if OAuth, otherwise unchanged
|
|
37
|
-
*/
|
|
38
|
-
const applySearchToolPrefix = (name: string, isOAuth: boolean): string => {
|
|
39
|
-
return isOAuth ? applyClaudeToolPrefix(name) : name;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
27
|
export interface AnthropicSearchParams {
|
|
43
28
|
query: string;
|
|
44
29
|
system_prompt?: string;
|
|
@@ -107,7 +92,7 @@ async function callSearch(
|
|
|
107
92
|
tools: [
|
|
108
93
|
{
|
|
109
94
|
type: WEB_SEARCH_TOOL_TYPE,
|
|
110
|
-
name:
|
|
95
|
+
name: WEB_SEARCH_TOOL_NAME,
|
|
111
96
|
},
|
|
112
97
|
],
|
|
113
98
|
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic Web Search Provider
|
|
3
|
+
*
|
|
4
|
+
* Uses Synthetic's zero-data-retention web search API for coding agents.
|
|
5
|
+
* Endpoint: POST https://api.synthetic.new/v2/search
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
9
|
+
import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
|
|
10
|
+
import { AgentStorage } from "../../../session/agent-storage";
|
|
11
|
+
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
12
|
+
import { SearchProviderError } from "../../../web/search/types";
|
|
13
|
+
import type { SearchParams } from "./base";
|
|
14
|
+
import { SearchProvider } from "./base";
|
|
15
|
+
|
|
16
|
+
const SYNTHETIC_SEARCH_URL = "https://api.synthetic.new/v2/search";
|
|
17
|
+
|
|
18
|
+
interface SyntheticSearchResult {
|
|
19
|
+
url: string;
|
|
20
|
+
title: string;
|
|
21
|
+
text?: string;
|
|
22
|
+
published?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface SyntheticSearchResponse {
|
|
26
|
+
results: SyntheticSearchResult[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find Synthetic API key from environment or agent.db credentials.
|
|
31
|
+
* Priority: SYNTHETIC_API_KEY env var, then credentials stored under provider "synthetic".
|
|
32
|
+
*/
|
|
33
|
+
export async function findApiKey(): Promise<string | null> {
|
|
34
|
+
const envKey = getEnvApiKey("synthetic");
|
|
35
|
+
if (envKey) return envKey;
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const storage = await AgentStorage.open(getAgentDbPath());
|
|
39
|
+
const records = storage.listAuthCredentials("synthetic");
|
|
40
|
+
for (const record of records) {
|
|
41
|
+
const credential = record.credential;
|
|
42
|
+
if (credential.type === "api_key" && credential.key.trim().length > 0) {
|
|
43
|
+
return credential.key;
|
|
44
|
+
}
|
|
45
|
+
if (credential.type === "oauth" && credential.access.trim().length > 0) {
|
|
46
|
+
return credential.access;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Call Synthetic search API. */
|
|
57
|
+
async function callSyntheticSearch(
|
|
58
|
+
apiKey: string,
|
|
59
|
+
query: string,
|
|
60
|
+
signal?: AbortSignal,
|
|
61
|
+
): Promise<SyntheticSearchResponse> {
|
|
62
|
+
const response = await fetch(SYNTHETIC_SEARCH_URL, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: {
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
Authorization: `Bearer ${apiKey}`,
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify({ query }),
|
|
69
|
+
signal,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
const errorText = await response.text();
|
|
74
|
+
throw new SearchProviderError(
|
|
75
|
+
"synthetic",
|
|
76
|
+
`Synthetic API error (${response.status}): ${errorText}`,
|
|
77
|
+
response.status,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (await response.json()) as SyntheticSearchResponse;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Execute Synthetic web search. */
|
|
85
|
+
export async function searchSynthetic(params: {
|
|
86
|
+
query: string;
|
|
87
|
+
num_results?: number;
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
}): Promise<SearchResponse> {
|
|
90
|
+
const apiKey = await findApiKey();
|
|
91
|
+
if (!apiKey) {
|
|
92
|
+
throw new Error("Synthetic credentials not found. Set SYNTHETIC_API_KEY or login with 'omp /login synthetic'.");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const data = await callSyntheticSearch(apiKey, params.query, params.signal);
|
|
96
|
+
const sources: SearchSource[] = [];
|
|
97
|
+
|
|
98
|
+
for (const result of data.results ?? []) {
|
|
99
|
+
if (!result.url) continue;
|
|
100
|
+
sources.push({
|
|
101
|
+
title: result.title ?? result.url,
|
|
102
|
+
url: result.url,
|
|
103
|
+
snippet: result.text ?? undefined,
|
|
104
|
+
publishedDate: result.published ?? undefined,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const limitedSources = params.num_results ? sources.slice(0, params.num_results) : sources;
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
provider: "synthetic",
|
|
112
|
+
sources: limitedSources,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Search provider for Synthetic. */
|
|
117
|
+
export class SyntheticProvider extends SearchProvider {
|
|
118
|
+
readonly id = "synthetic";
|
|
119
|
+
readonly label = "Synthetic";
|
|
120
|
+
|
|
121
|
+
async isAvailable(): Promise<boolean> {
|
|
122
|
+
try {
|
|
123
|
+
return !!(await findApiKey());
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
search(params: SearchParams): Promise<SearchResponse> {
|
|
130
|
+
return searchSynthetic({
|
|
131
|
+
query: params.query,
|
|
132
|
+
num_results: params.numSearchResults ?? params.limit,
|
|
133
|
+
signal: params.signal,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/web/search/types.ts
CHANGED
|
@@ -5,7 +5,16 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/** Supported web search providers */
|
|
8
|
-
export type SearchProviderId =
|
|
8
|
+
export type SearchProviderId =
|
|
9
|
+
| "exa"
|
|
10
|
+
| "brave"
|
|
11
|
+
| "jina"
|
|
12
|
+
| "zai"
|
|
13
|
+
| "anthropic"
|
|
14
|
+
| "perplexity"
|
|
15
|
+
| "gemini"
|
|
16
|
+
| "codex"
|
|
17
|
+
| "synthetic";
|
|
9
18
|
|
|
10
19
|
/** Source returned by search (all providers) */
|
|
11
20
|
export interface SearchSource {
|