pi-openai-toolkit 0.14.4 → 0.14.6
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/README.md +119 -147
- package/README.zh.md +119 -151
- package/docs/internals.md +42 -21
- package/package.json +127 -127
- package/src/auto-mode/classifier.ts +165 -165
- package/src/auto-mode/policy.ts +146 -146
- package/src/auto-mode/prompt.ts +279 -279
- package/src/auto-mode/reviewer.ts +325 -325
- package/src/auto-mode/transcript.ts +133 -133
- package/src/auto-mode/types.ts +137 -137
- package/src/codex-astra/effort-planner.ts +175 -175
- package/src/codex-astra/extension.ts +122 -122
- package/src/config.ts +621 -592
- package/src/context-management/codex-provider.ts +260 -260
- package/src/context-management/history-notes.ts +357 -325
- package/src/context-management/messages.ts +112 -106
- package/src/context-management/namespace-tools.ts +426 -426
- package/src/context-management/tool-contract.ts +23 -23
- package/src/context-management/tools.ts +306 -311
- package/src/context-management/types.ts +168 -161
- package/src/context-management/window-budget.ts +83 -83
- package/src/context-management/window-manager.ts +60 -51
- package/src/context-management/window-request.ts +125 -125
- package/src/debug.ts +1 -1
- package/src/extension-runtime.ts +34 -9
- package/src/image-generation/artifacts.ts +237 -237
- package/src/image-generation/client.ts +248 -248
- package/src/image-generation/eligibility.ts +18 -18
- package/src/image-generation/extension.ts +19 -2
- package/src/image-generation/protocol.ts +473 -405
- package/src/image-generation/references.ts +194 -194
- package/src/image-generation/render.ts +252 -252
- package/src/image-generation/service.ts +249 -243
- package/src/image-generation/types.ts +189 -184
- package/src/model-scope.ts +17 -17
- package/src/provider-headers.ts +23 -23
- package/src/responses-headers.ts +173 -108
- package/src/runtime.ts +513 -477
- package/src/types.ts +11 -0
- package/src/web-search/extension.ts +80 -80
- package/src/web-search/payload.ts +96 -96
- package/src/web-search/prompt.ts +20 -20
- package/src/web-search/types.ts +45 -45
package/src/types.ts
CHANGED
|
@@ -107,6 +107,12 @@ export type WebSearchConfig = {
|
|
|
107
107
|
|
|
108
108
|
export type ImageGenerationConfig = {
|
|
109
109
|
enabled: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Bare `image_generation` tool model ids this toolkit may send, without a `provider/` prefix.
|
|
112
|
+
* The first entry is the default; `openai_generate_image`'s optional `model` argument may
|
|
113
|
+
* select any other entry in this order-preserving list.
|
|
114
|
+
*/
|
|
115
|
+
models: string[];
|
|
110
116
|
};
|
|
111
117
|
|
|
112
118
|
/** `side-effect` reviews bash/write/edit plus extras; `all` reviews every tool call. */
|
|
@@ -527,8 +533,13 @@ export const DEFAULT_WEB_SEARCH_CONFIG: WebSearchConfig = {
|
|
|
527
533
|
models: [],
|
|
528
534
|
};
|
|
529
535
|
|
|
536
|
+
/** Single source of truth for the hosted image model used when nothing is configured. */
|
|
537
|
+
export const DEFAULT_IMAGE_GENERATION_MODEL = "gpt-image-2.5";
|
|
538
|
+
export const DEFAULT_IMAGE_GENERATION_MODELS: readonly string[] = [DEFAULT_IMAGE_GENERATION_MODEL];
|
|
539
|
+
|
|
530
540
|
export const DEFAULT_IMAGE_GENERATION_CONFIG: ImageGenerationConfig = {
|
|
531
541
|
enabled: false,
|
|
542
|
+
models: [...DEFAULT_IMAGE_GENERATION_MODELS],
|
|
532
543
|
};
|
|
533
544
|
|
|
534
545
|
export const DEFAULT_AUTO_MODE_CONFIG: AutoModeConfig = {
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { loadToolkitConfig } from "../config";
|
|
3
|
-
import { transformWebSearchPayload } from "./payload";
|
|
4
|
-
import { appendWebSearchPrompt } from "./prompt";
|
|
5
|
-
import { isWebSearchEnabledForModel, type WebSearchModel } from "./types";
|
|
6
|
-
|
|
7
|
-
function syncLocalWebSearchTool(
|
|
8
|
-
pi: ExtensionAPI,
|
|
9
|
-
model: WebSearchModel | undefined,
|
|
10
|
-
config: Parameters<typeof isWebSearchEnabledForModel>[1],
|
|
11
|
-
state: { wasActiveBeforeOwnership?: boolean; toolkitOwnsTool: boolean },
|
|
12
|
-
): void {
|
|
13
|
-
const eligible = isWebSearchEnabledForModel(model, config);
|
|
14
|
-
const activeTools = pi.getActiveTools();
|
|
15
|
-
|
|
16
|
-
if (eligible) {
|
|
17
|
-
if (!state.toolkitOwnsTool) {
|
|
18
|
-
state.wasActiveBeforeOwnership = activeTools.includes("web_search");
|
|
19
|
-
state.toolkitOwnsTool = true;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (activeTools.includes("web_search")) {
|
|
23
|
-
pi.setActiveTools(activeTools.filter((name) => name !== "web_search"));
|
|
24
|
-
}
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (!state.toolkitOwnsTool) return;
|
|
29
|
-
|
|
30
|
-
if (state.wasActiveBeforeOwnership && !activeTools.includes("web_search")) {
|
|
31
|
-
pi.setActiveTools([...activeTools, "web_search"]);
|
|
32
|
-
}
|
|
33
|
-
state.wasActiveBeforeOwnership = undefined;
|
|
34
|
-
state.toolkitOwnsTool = false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function registerWebSearchExtension(
|
|
38
|
-
pi: ExtensionAPI,
|
|
39
|
-
loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
|
|
40
|
-
): void {
|
|
41
|
-
const toolState = { wasActiveBeforeOwnership: undefined as boolean | undefined, toolkitOwnsTool: false };
|
|
42
|
-
|
|
43
|
-
pi.on("session_start", (_event, ctx) => {
|
|
44
|
-
const { config } = loadConfig();
|
|
45
|
-
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
pi.on("model_select", (event) => {
|
|
49
|
-
const { config } = loadConfig();
|
|
50
|
-
syncLocalWebSearchTool(pi, event.model, config.webSearch, toolState);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
pi.on("before_agent_start", (event, ctx) => {
|
|
54
|
-
const { config } = loadConfig();
|
|
55
|
-
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
56
|
-
const systemPrompt = appendWebSearchPrompt({
|
|
57
|
-
model: ctx.model,
|
|
58
|
-
config: config.webSearch,
|
|
59
|
-
systemPrompt: event.systemPrompt,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
return systemPrompt === event.systemPrompt ? undefined : { systemPrompt };
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
pi.on("before_provider_request", (event, ctx) => {
|
|
66
|
-
const { config } = loadConfig();
|
|
67
|
-
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
68
|
-
const transformed = transformWebSearchPayload({
|
|
69
|
-
model: ctx.model,
|
|
70
|
-
config: config.webSearch,
|
|
71
|
-
payload: event.payload,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return transformed.changed ? transformed.payload : undefined;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export default function webSearchExtension(pi: ExtensionAPI): void {
|
|
79
|
-
registerWebSearchExtension(pi);
|
|
80
|
-
}
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { loadToolkitConfig } from "../config";
|
|
3
|
+
import { transformWebSearchPayload } from "./payload";
|
|
4
|
+
import { appendWebSearchPrompt } from "./prompt";
|
|
5
|
+
import { isWebSearchEnabledForModel, type WebSearchModel } from "./types";
|
|
6
|
+
|
|
7
|
+
function syncLocalWebSearchTool(
|
|
8
|
+
pi: ExtensionAPI,
|
|
9
|
+
model: WebSearchModel | undefined,
|
|
10
|
+
config: Parameters<typeof isWebSearchEnabledForModel>[1],
|
|
11
|
+
state: { wasActiveBeforeOwnership?: boolean; toolkitOwnsTool: boolean },
|
|
12
|
+
): void {
|
|
13
|
+
const eligible = isWebSearchEnabledForModel(model, config);
|
|
14
|
+
const activeTools = pi.getActiveTools();
|
|
15
|
+
|
|
16
|
+
if (eligible) {
|
|
17
|
+
if (!state.toolkitOwnsTool) {
|
|
18
|
+
state.wasActiveBeforeOwnership = activeTools.includes("web_search");
|
|
19
|
+
state.toolkitOwnsTool = true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (activeTools.includes("web_search")) {
|
|
23
|
+
pi.setActiveTools(activeTools.filter((name) => name !== "web_search"));
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!state.toolkitOwnsTool) return;
|
|
29
|
+
|
|
30
|
+
if (state.wasActiveBeforeOwnership && !activeTools.includes("web_search")) {
|
|
31
|
+
pi.setActiveTools([...activeTools, "web_search"]);
|
|
32
|
+
}
|
|
33
|
+
state.wasActiveBeforeOwnership = undefined;
|
|
34
|
+
state.toolkitOwnsTool = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function registerWebSearchExtension(
|
|
38
|
+
pi: ExtensionAPI,
|
|
39
|
+
loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
|
|
40
|
+
): void {
|
|
41
|
+
const toolState = { wasActiveBeforeOwnership: undefined as boolean | undefined, toolkitOwnsTool: false };
|
|
42
|
+
|
|
43
|
+
pi.on("session_start", (_event, ctx) => {
|
|
44
|
+
const { config } = loadConfig();
|
|
45
|
+
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
pi.on("model_select", (event) => {
|
|
49
|
+
const { config } = loadConfig();
|
|
50
|
+
syncLocalWebSearchTool(pi, event.model, config.webSearch, toolState);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
pi.on("before_agent_start", (event, ctx) => {
|
|
54
|
+
const { config } = loadConfig();
|
|
55
|
+
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
56
|
+
const systemPrompt = appendWebSearchPrompt({
|
|
57
|
+
model: ctx.model,
|
|
58
|
+
config: config.webSearch,
|
|
59
|
+
systemPrompt: event.systemPrompt,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return systemPrompt === event.systemPrompt ? undefined : { systemPrompt };
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
pi.on("before_provider_request", (event, ctx) => {
|
|
66
|
+
const { config } = loadConfig();
|
|
67
|
+
syncLocalWebSearchTool(pi, ctx.model, config.webSearch, toolState);
|
|
68
|
+
const transformed = transformWebSearchPayload({
|
|
69
|
+
model: ctx.model,
|
|
70
|
+
config: config.webSearch,
|
|
71
|
+
payload: event.payload,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return transformed.changed ? transformed.payload : undefined;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default function webSearchExtension(pi: ExtensionAPI): void {
|
|
79
|
+
registerWebSearchExtension(pi);
|
|
80
|
+
}
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
import type { WebSearchConfig } from "../types";
|
|
2
|
-
import {
|
|
3
|
-
WEB_SEARCH_SOURCE_INCLUDE,
|
|
4
|
-
isWebSearchEnabledForModel,
|
|
5
|
-
type WebSearchModel,
|
|
6
|
-
type WebSearchPayloadTransform,
|
|
7
|
-
} from "./types";
|
|
8
|
-
|
|
9
|
-
type JsonObject = Record<string, unknown>;
|
|
10
|
-
|
|
11
|
-
function isRecord(value: unknown): value is JsonObject {
|
|
12
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function isLocalWebSearchFunction(tool: unknown): boolean {
|
|
16
|
-
return isRecord(tool) && tool.type === "function" && tool.name === "web_search";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function isNativeWebSearchTool(tool: unknown): boolean {
|
|
20
|
-
return isRecord(tool) && (tool.type === "web_search" || tool.type === "web_search_preview");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function transformWebSearchPayload(args: {
|
|
24
|
-
model: WebSearchModel | undefined;
|
|
25
|
-
config: WebSearchConfig;
|
|
26
|
-
payload: unknown;
|
|
27
|
-
}): WebSearchPayloadTransform {
|
|
28
|
-
const { model, config, payload } = args;
|
|
29
|
-
if (!config.enabled) {
|
|
30
|
-
return { payload, outcome: "disabled", changed: false };
|
|
31
|
-
}
|
|
32
|
-
if (!isWebSearchEnabledForModel(model, config)) {
|
|
33
|
-
return { payload, outcome: "unsupported-model", changed: false };
|
|
34
|
-
}
|
|
35
|
-
if (!isRecord(payload)) {
|
|
36
|
-
return { payload, outcome: "non-object-payload", changed: false };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const toolsValue = payload.tools;
|
|
40
|
-
if (toolsValue !== undefined && !Array.isArray(toolsValue)) {
|
|
41
|
-
return { payload, outcome: "invalid-tools", changed: false };
|
|
42
|
-
}
|
|
43
|
-
const tools = toolsValue ?? [];
|
|
44
|
-
const includeValue = payload.include;
|
|
45
|
-
if (includeValue !== undefined && !Array.isArray(includeValue)) {
|
|
46
|
-
return { payload, outcome: "invalid-include", changed: false };
|
|
47
|
-
}
|
|
48
|
-
const include = includeValue ?? [];
|
|
49
|
-
const normalizedTools: unknown[] = [];
|
|
50
|
-
let nativeToolCount = 0;
|
|
51
|
-
let localToolRemoved = false;
|
|
52
|
-
for (const tool of tools) {
|
|
53
|
-
if (isLocalWebSearchFunction(tool)) {
|
|
54
|
-
localToolRemoved = true;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (isNativeWebSearchTool(tool)) {
|
|
58
|
-
nativeToolCount += 1;
|
|
59
|
-
if (nativeToolCount > 1) continue;
|
|
60
|
-
}
|
|
61
|
-
normalizedTools.push(tool);
|
|
62
|
-
}
|
|
63
|
-
const hasNativeTool = nativeToolCount > 0;
|
|
64
|
-
if (!hasNativeTool) {
|
|
65
|
-
normalizedTools.push({ type: "web_search" });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const normalizedInclude: unknown[] = [];
|
|
69
|
-
let sourceIncludeCount = 0;
|
|
70
|
-
for (const item of include) {
|
|
71
|
-
if (item === WEB_SEARCH_SOURCE_INCLUDE) {
|
|
72
|
-
sourceIncludeCount += 1;
|
|
73
|
-
if (sourceIncludeCount > 1) continue;
|
|
74
|
-
}
|
|
75
|
-
normalizedInclude.push(item);
|
|
76
|
-
}
|
|
77
|
-
if (sourceIncludeCount === 0) {
|
|
78
|
-
normalizedInclude.push(WEB_SEARCH_SOURCE_INCLUDE);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const toolsChanged = localToolRemoved || !hasNativeTool || nativeToolCount > 1;
|
|
82
|
-
const includeChanged = sourceIncludeCount !== 1;
|
|
83
|
-
if (!toolsChanged && !includeChanged) {
|
|
84
|
-
return { payload, outcome: "existing-native-tool", changed: false };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
payload: {
|
|
89
|
-
...payload,
|
|
90
|
-
...(toolsChanged ? { tools: normalizedTools } : {}),
|
|
91
|
-
...(includeChanged ? { include: normalizedInclude } : {}),
|
|
92
|
-
},
|
|
93
|
-
outcome: hasNativeTool ? "existing-native-tool" : "injected-native-tool",
|
|
94
|
-
changed: true,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
1
|
+
import type { WebSearchConfig } from "../types";
|
|
2
|
+
import {
|
|
3
|
+
WEB_SEARCH_SOURCE_INCLUDE,
|
|
4
|
+
isWebSearchEnabledForModel,
|
|
5
|
+
type WebSearchModel,
|
|
6
|
+
type WebSearchPayloadTransform,
|
|
7
|
+
} from "./types";
|
|
8
|
+
|
|
9
|
+
type JsonObject = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
function isRecord(value: unknown): value is JsonObject {
|
|
12
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isLocalWebSearchFunction(tool: unknown): boolean {
|
|
16
|
+
return isRecord(tool) && tool.type === "function" && tool.name === "web_search";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isNativeWebSearchTool(tool: unknown): boolean {
|
|
20
|
+
return isRecord(tool) && (tool.type === "web_search" || tool.type === "web_search_preview");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function transformWebSearchPayload(args: {
|
|
24
|
+
model: WebSearchModel | undefined;
|
|
25
|
+
config: WebSearchConfig;
|
|
26
|
+
payload: unknown;
|
|
27
|
+
}): WebSearchPayloadTransform {
|
|
28
|
+
const { model, config, payload } = args;
|
|
29
|
+
if (!config.enabled) {
|
|
30
|
+
return { payload, outcome: "disabled", changed: false };
|
|
31
|
+
}
|
|
32
|
+
if (!isWebSearchEnabledForModel(model, config)) {
|
|
33
|
+
return { payload, outcome: "unsupported-model", changed: false };
|
|
34
|
+
}
|
|
35
|
+
if (!isRecord(payload)) {
|
|
36
|
+
return { payload, outcome: "non-object-payload", changed: false };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const toolsValue = payload.tools;
|
|
40
|
+
if (toolsValue !== undefined && !Array.isArray(toolsValue)) {
|
|
41
|
+
return { payload, outcome: "invalid-tools", changed: false };
|
|
42
|
+
}
|
|
43
|
+
const tools = toolsValue ?? [];
|
|
44
|
+
const includeValue = payload.include;
|
|
45
|
+
if (includeValue !== undefined && !Array.isArray(includeValue)) {
|
|
46
|
+
return { payload, outcome: "invalid-include", changed: false };
|
|
47
|
+
}
|
|
48
|
+
const include = includeValue ?? [];
|
|
49
|
+
const normalizedTools: unknown[] = [];
|
|
50
|
+
let nativeToolCount = 0;
|
|
51
|
+
let localToolRemoved = false;
|
|
52
|
+
for (const tool of tools) {
|
|
53
|
+
if (isLocalWebSearchFunction(tool)) {
|
|
54
|
+
localToolRemoved = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (isNativeWebSearchTool(tool)) {
|
|
58
|
+
nativeToolCount += 1;
|
|
59
|
+
if (nativeToolCount > 1) continue;
|
|
60
|
+
}
|
|
61
|
+
normalizedTools.push(tool);
|
|
62
|
+
}
|
|
63
|
+
const hasNativeTool = nativeToolCount > 0;
|
|
64
|
+
if (!hasNativeTool) {
|
|
65
|
+
normalizedTools.push({ type: "web_search" });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const normalizedInclude: unknown[] = [];
|
|
69
|
+
let sourceIncludeCount = 0;
|
|
70
|
+
for (const item of include) {
|
|
71
|
+
if (item === WEB_SEARCH_SOURCE_INCLUDE) {
|
|
72
|
+
sourceIncludeCount += 1;
|
|
73
|
+
if (sourceIncludeCount > 1) continue;
|
|
74
|
+
}
|
|
75
|
+
normalizedInclude.push(item);
|
|
76
|
+
}
|
|
77
|
+
if (sourceIncludeCount === 0) {
|
|
78
|
+
normalizedInclude.push(WEB_SEARCH_SOURCE_INCLUDE);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const toolsChanged = localToolRemoved || !hasNativeTool || nativeToolCount > 1;
|
|
82
|
+
const includeChanged = sourceIncludeCount !== 1;
|
|
83
|
+
if (!toolsChanged && !includeChanged) {
|
|
84
|
+
return { payload, outcome: "existing-native-tool", changed: false };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
payload: {
|
|
89
|
+
...payload,
|
|
90
|
+
...(toolsChanged ? { tools: normalizedTools } : {}),
|
|
91
|
+
...(includeChanged ? { include: normalizedInclude } : {}),
|
|
92
|
+
},
|
|
93
|
+
outcome: hasNativeTool ? "existing-native-tool" : "injected-native-tool",
|
|
94
|
+
changed: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
package/src/web-search/prompt.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import type { WebSearchConfig } from "../types";
|
|
2
|
-
import { isWebSearchEnabledForModel, WEB_SEARCH_PROMPT_MARKER, type WebSearchModel } from "./types";
|
|
3
|
-
|
|
4
|
-
export const WEB_SEARCH_PROMPT_SECTION = `${WEB_SEARCH_PROMPT_MARKER}
|
|
5
|
-
## Web Search
|
|
6
|
-
|
|
7
|
-
The hosted \`web_search\` tool is part of your tool list for this model. The API executes it server-side: it is a real callable tool even though no client-side function schema or description accompanies it. Call it whenever current or online information matters instead of guessing, cite the returned sources in the answer, and never claim that web search or internet access is unavailable while this section is present.`;
|
|
8
|
-
|
|
9
|
-
export function appendWebSearchPrompt(args: {
|
|
10
|
-
model: WebSearchModel | undefined;
|
|
11
|
-
config: WebSearchConfig;
|
|
12
|
-
systemPrompt: string;
|
|
13
|
-
}): string {
|
|
14
|
-
const { model, config, systemPrompt } = args;
|
|
15
|
-
if (!isWebSearchEnabledForModel(model, config) || systemPrompt.includes(WEB_SEARCH_PROMPT_MARKER)) {
|
|
16
|
-
return systemPrompt;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return `${systemPrompt.trimEnd()}\n\n${WEB_SEARCH_PROMPT_SECTION}`;
|
|
20
|
-
}
|
|
1
|
+
import type { WebSearchConfig } from "../types";
|
|
2
|
+
import { isWebSearchEnabledForModel, WEB_SEARCH_PROMPT_MARKER, type WebSearchModel } from "./types";
|
|
3
|
+
|
|
4
|
+
export const WEB_SEARCH_PROMPT_SECTION = `${WEB_SEARCH_PROMPT_MARKER}
|
|
5
|
+
## Web Search
|
|
6
|
+
|
|
7
|
+
The hosted \`web_search\` tool is part of your tool list for this model. The API executes it server-side: it is a real callable tool even though no client-side function schema or description accompanies it. Call it whenever current or online information matters instead of guessing, cite the returned sources in the answer, and never claim that web search or internet access is unavailable while this section is present.`;
|
|
8
|
+
|
|
9
|
+
export function appendWebSearchPrompt(args: {
|
|
10
|
+
model: WebSearchModel | undefined;
|
|
11
|
+
config: WebSearchConfig;
|
|
12
|
+
systemPrompt: string;
|
|
13
|
+
}): string {
|
|
14
|
+
const { model, config, systemPrompt } = args;
|
|
15
|
+
if (!isWebSearchEnabledForModel(model, config) || systemPrompt.includes(WEB_SEARCH_PROMPT_MARKER)) {
|
|
16
|
+
return systemPrompt;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return `${systemPrompt.trimEnd()}\n\n${WEB_SEARCH_PROMPT_SECTION}`;
|
|
20
|
+
}
|
package/src/web-search/types.ts
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import { getExactModelKey, isExactModelAllowed } from "../model-scope";
|
|
2
|
-
import type { WebSearchConfig } from "../types";
|
|
3
|
-
|
|
4
|
-
export const WEB_SEARCH_CAPABLE_APIS = ["openai-responses", "openai-codex-responses"] as const;
|
|
5
|
-
export const WEB_SEARCH_SOURCE_INCLUDE = "web_search_call.action.sources";
|
|
6
|
-
export const WEB_SEARCH_PROMPT_MARKER = "<!-- pi-openai-toolkit:web-search -->";
|
|
7
|
-
|
|
8
|
-
export type WebSearchCapableApi = (typeof WEB_SEARCH_CAPABLE_APIS)[number];
|
|
9
|
-
|
|
10
|
-
export type WebSearchModel = {
|
|
11
|
-
api?: string;
|
|
12
|
-
provider?: string;
|
|
13
|
-
id?: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type WebSearchPayloadOutcome =
|
|
17
|
-
| "disabled"
|
|
18
|
-
| "unsupported-model"
|
|
19
|
-
| "non-object-payload"
|
|
20
|
-
| "invalid-tools"
|
|
21
|
-
| "invalid-include"
|
|
22
|
-
| "existing-native-tool"
|
|
23
|
-
| "injected-native-tool";
|
|
24
|
-
|
|
25
|
-
export type WebSearchPayloadTransform = {
|
|
26
|
-
payload: unknown;
|
|
27
|
-
outcome: WebSearchPayloadOutcome;
|
|
28
|
-
changed: boolean;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export function getWebSearchModelKey(model: WebSearchModel | undefined): string | undefined {
|
|
32
|
-
return getExactModelKey(model);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function isWebSearchEnabledForModel(
|
|
36
|
-
model: WebSearchModel | undefined,
|
|
37
|
-
config: WebSearchConfig,
|
|
38
|
-
): boolean {
|
|
39
|
-
return (
|
|
40
|
-
config.enabled &&
|
|
41
|
-
typeof model?.api === "string" &&
|
|
42
|
-
(WEB_SEARCH_CAPABLE_APIS as readonly string[]).includes(model.api) &&
|
|
43
|
-
isExactModelAllowed(model, config.models)
|
|
44
|
-
);
|
|
45
|
-
}
|
|
1
|
+
import { getExactModelKey, isExactModelAllowed } from "../model-scope";
|
|
2
|
+
import type { WebSearchConfig } from "../types";
|
|
3
|
+
|
|
4
|
+
export const WEB_SEARCH_CAPABLE_APIS = ["openai-responses", "openai-codex-responses"] as const;
|
|
5
|
+
export const WEB_SEARCH_SOURCE_INCLUDE = "web_search_call.action.sources";
|
|
6
|
+
export const WEB_SEARCH_PROMPT_MARKER = "<!-- pi-openai-toolkit:web-search -->";
|
|
7
|
+
|
|
8
|
+
export type WebSearchCapableApi = (typeof WEB_SEARCH_CAPABLE_APIS)[number];
|
|
9
|
+
|
|
10
|
+
export type WebSearchModel = {
|
|
11
|
+
api?: string;
|
|
12
|
+
provider?: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type WebSearchPayloadOutcome =
|
|
17
|
+
| "disabled"
|
|
18
|
+
| "unsupported-model"
|
|
19
|
+
| "non-object-payload"
|
|
20
|
+
| "invalid-tools"
|
|
21
|
+
| "invalid-include"
|
|
22
|
+
| "existing-native-tool"
|
|
23
|
+
| "injected-native-tool";
|
|
24
|
+
|
|
25
|
+
export type WebSearchPayloadTransform = {
|
|
26
|
+
payload: unknown;
|
|
27
|
+
outcome: WebSearchPayloadOutcome;
|
|
28
|
+
changed: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function getWebSearchModelKey(model: WebSearchModel | undefined): string | undefined {
|
|
32
|
+
return getExactModelKey(model);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isWebSearchEnabledForModel(
|
|
36
|
+
model: WebSearchModel | undefined,
|
|
37
|
+
config: WebSearchConfig,
|
|
38
|
+
): boolean {
|
|
39
|
+
return (
|
|
40
|
+
config.enabled &&
|
|
41
|
+
typeof model?.api === "string" &&
|
|
42
|
+
(WEB_SEARCH_CAPABLE_APIS as readonly string[]).includes(model.api) &&
|
|
43
|
+
isExactModelAllowed(model, config.models)
|
|
44
|
+
);
|
|
45
|
+
}
|