pi-openai-toolkit 0.8.0 → 0.9.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/README.md +56 -13
- package/README_zh.md +56 -13
- package/extensions/auto-mode.ts +1 -0
- package/package.json +10 -3
- package/src/auto-mode/extension.ts +273 -0
- package/src/auto-mode/policy.ts +77 -0
- package/src/auto-mode/reviewer.ts +239 -0
- package/src/auto-mode/types.ts +58 -0
- package/src/config.ts +103 -16
- package/src/extension-runtime.ts +12 -4
- package/src/image-generation/eligibility.ts +7 -7
- package/src/image-generation/extension.ts +160 -160
- package/src/native-fallback.ts +19 -6
- package/src/types.ts +52 -10
- package/tsconfig.check.json +5 -0
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
import { StringEnum, Type, type Static } from "@earendil-works/pi-ai";
|
|
2
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { loadToolkitConfig } from "../config";
|
|
4
|
-
import { executeImageGeneration } from "./service";
|
|
5
|
-
import { isImageGenerationEnabledForModel } from "./eligibility";
|
|
6
|
-
import { renderImageGenerationResult } from "./render";
|
|
7
|
-
import {
|
|
8
|
-
IMAGE_GENERATION_QUALITIES,
|
|
9
|
-
IMAGE_GENERATION_SIZES,
|
|
10
|
-
IMAGE_GENERATION_TOOL_NAME,
|
|
11
|
-
MAX_IMAGE_PATH_CHARS,
|
|
12
|
-
MAX_IMAGE_PROMPT_CHARS,
|
|
13
|
-
MAX_REFERENCE_IMAGE_COUNT,
|
|
14
|
-
ImageGenerationError,
|
|
15
|
-
sanitizeImageDiagnostic,
|
|
16
|
-
type ImageGenerationDetails,
|
|
17
|
-
} from "./types";
|
|
18
|
-
|
|
19
|
-
const registeredApis = new WeakSet<object>();
|
|
20
|
-
|
|
21
|
-
const GenerateImageParameters = Type.Object(
|
|
22
|
-
{
|
|
23
|
-
prompt: Type.String({
|
|
24
|
-
minLength: 1,
|
|
25
|
-
maxLength: MAX_IMAGE_PROMPT_CHARS,
|
|
26
|
-
description: "Image generation or edit prompt. Preserve the user's requested subject and constraints.",
|
|
27
|
-
}),
|
|
28
|
-
referenceImagePaths: Type.Optional(
|
|
29
|
-
Type.Union(
|
|
30
|
-
[
|
|
31
|
-
Type.Null(),
|
|
32
|
-
Type.Array(Type.String({ minLength: 1, maxLength: MAX_IMAGE_PATH_CHARS }), {
|
|
33
|
-
minItems: 1,
|
|
34
|
-
maxItems: MAX_REFERENCE_IMAGE_COUNT,
|
|
35
|
-
}),
|
|
36
|
-
],
|
|
37
|
-
{
|
|
38
|
-
description:
|
|
39
|
-
"Use null when the user did not explicitly identify reference images; otherwise provide one to five user-identified local image paths.",
|
|
40
|
-
},
|
|
41
|
-
),
|
|
42
|
-
),
|
|
43
|
-
outputPath: Type.Optional(
|
|
44
|
-
Type.Union(
|
|
45
|
-
[
|
|
46
|
-
Type.Null(),
|
|
47
|
-
Type.String({
|
|
48
|
-
minLength: 1,
|
|
49
|
-
maxLength: MAX_IMAGE_PATH_CHARS,
|
|
50
|
-
}),
|
|
51
|
-
],
|
|
52
|
-
{
|
|
53
|
-
description:
|
|
54
|
-
"Use null when the user did not explicitly request a destination; otherwise provide the requested explicit .png file path.",
|
|
55
|
-
},
|
|
56
|
-
),
|
|
57
|
-
),
|
|
58
|
-
size: Type.Optional(
|
|
59
|
-
StringEnum(IMAGE_GENERATION_SIZES, {
|
|
60
|
-
description: "Requested PNG dimensions, or auto.",
|
|
61
|
-
}),
|
|
62
|
-
),
|
|
63
|
-
quality: Type.Optional(
|
|
64
|
-
StringEnum(IMAGE_GENERATION_QUALITIES, {
|
|
65
|
-
description: "Requested image quality, or auto.",
|
|
66
|
-
}),
|
|
67
|
-
),
|
|
68
|
-
},
|
|
69
|
-
{ additionalProperties: false },
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
type GenerateImageToolParams = Static<typeof GenerateImageParameters>;
|
|
73
|
-
|
|
74
|
-
function syncImageGenerationTool(
|
|
75
|
-
pi: ExtensionAPI,
|
|
76
|
-
model: Parameters<typeof isImageGenerationEnabledForModel>[0],
|
|
77
|
-
config: Parameters<typeof isImageGenerationEnabledForModel>[1],
|
|
78
|
-
): void {
|
|
79
|
-
const eligible = isImageGenerationEnabledForModel(model, config);
|
|
80
|
-
const activeTools = pi.getActiveTools();
|
|
81
|
-
const active = activeTools.includes(IMAGE_GENERATION_TOOL_NAME);
|
|
82
|
-
if (eligible && !active) {
|
|
83
|
-
pi.setActiveTools([...activeTools, IMAGE_GENERATION_TOOL_NAME]);
|
|
84
|
-
} else if (!eligible && active) {
|
|
85
|
-
pi.setActiveTools(activeTools.filter((name) => name !== IMAGE_GENERATION_TOOL_NAME));
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function registerImageGenerationExtension(
|
|
90
|
-
pi: ExtensionAPI,
|
|
91
|
-
loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
|
|
92
|
-
executeImage: typeof executeImageGeneration = executeImageGeneration,
|
|
93
|
-
): void {
|
|
94
|
-
if (registeredApis.has(pi)) return;
|
|
95
|
-
registeredApis.add(pi);
|
|
96
|
-
|
|
97
|
-
pi.registerTool<typeof GenerateImageParameters, ImageGenerationDetails, Record<string, never>>({
|
|
98
|
-
name: IMAGE_GENERATION_TOOL_NAME,
|
|
99
|
-
label: "OpenAI Generate Image",
|
|
100
|
-
description:
|
|
101
|
-
"Generate a PNG image, or edit from one to five user-approved local reference images, through the current
|
|
102
|
-
promptSnippet: "Generate or edit PNG images through the current
|
|
103
|
-
promptGuidelines: [
|
|
104
|
-
"Use openai_generate_image when the user explicitly asks to create, draw, render, or edit a raster image.",
|
|
105
|
-
"Do not call openai_generate_image speculatively: it consumes the user's provider or gateway image quota.",
|
|
106
|
-
"Keep the image prompt faithful to the user's requested subject and constraints; do not invent unrequested style details.",
|
|
107
|
-
"Set referenceImagePaths to null unless the user explicitly identified local files; never invent paths or placeholder strings, and remember upload requires user approval.",
|
|
108
|
-
"Set outputPath to null unless the user explicitly asks for a destination; never invent a destination or placeholder string, and otherwise use the default Pi agent artifact.",
|
|
109
|
-
"Do not substitute Python, browser automation, shell scripts, or unrelated image tools for an eligible image request.",
|
|
110
|
-
],
|
|
111
|
-
parameters: GenerateImageParameters,
|
|
112
|
-
executionMode: "sequential",
|
|
113
|
-
async execute(toolCallId, params: GenerateImageToolParams, signal, _onUpdate, ctx) {
|
|
114
|
-
try {
|
|
115
|
-
const result = await executeImage({
|
|
116
|
-
params,
|
|
117
|
-
toolCallId,
|
|
118
|
-
signal,
|
|
119
|
-
ctx,
|
|
120
|
-
});
|
|
121
|
-
return {
|
|
122
|
-
content: [{ type: "text", text: result.text }],
|
|
123
|
-
details: result.details,
|
|
124
|
-
};
|
|
125
|
-
} catch (error) {
|
|
126
|
-
if (error instanceof ImageGenerationError) {
|
|
127
|
-
throw new Error(error.message);
|
|
128
|
-
}
|
|
129
|
-
throw new Error(
|
|
130
|
-
sanitizeImageDiagnostic(error instanceof Error ? error.message : error, "Image generation failed."),
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
renderResult: renderImageGenerationResult,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
pi.on("session_start", (_event, ctx) => {
|
|
138
|
-
const { config } = loadConfig();
|
|
139
|
-
syncImageGenerationTool(pi, ctx.model, config.imageGeneration);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
pi.on("model_select", (event) => {
|
|
143
|
-
const { config } = loadConfig();
|
|
144
|
-
syncImageGenerationTool(pi, event.model, config.imageGeneration);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
pi.on("before_agent_start", (_event, ctx) => {
|
|
148
|
-
const { config } = loadConfig();
|
|
149
|
-
syncImageGenerationTool(pi, ctx.model, config.imageGeneration);
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export default function imageGenerationExtension(pi: ExtensionAPI): void {
|
|
154
|
-
registerImageGenerationExtension(pi);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export const _extensionTest = {
|
|
158
|
-
GenerateImageParameters,
|
|
159
|
-
syncImageGenerationTool,
|
|
160
|
-
};
|
|
1
|
+
import { StringEnum, Type, type Static } from "@earendil-works/pi-ai";
|
|
2
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { loadToolkitConfig } from "../config";
|
|
4
|
+
import { executeImageGeneration } from "./service";
|
|
5
|
+
import { isImageGenerationEnabledForModel } from "./eligibility";
|
|
6
|
+
import { renderImageGenerationResult } from "./render";
|
|
7
|
+
import {
|
|
8
|
+
IMAGE_GENERATION_QUALITIES,
|
|
9
|
+
IMAGE_GENERATION_SIZES,
|
|
10
|
+
IMAGE_GENERATION_TOOL_NAME,
|
|
11
|
+
MAX_IMAGE_PATH_CHARS,
|
|
12
|
+
MAX_IMAGE_PROMPT_CHARS,
|
|
13
|
+
MAX_REFERENCE_IMAGE_COUNT,
|
|
14
|
+
ImageGenerationError,
|
|
15
|
+
sanitizeImageDiagnostic,
|
|
16
|
+
type ImageGenerationDetails,
|
|
17
|
+
} from "./types";
|
|
18
|
+
|
|
19
|
+
const registeredApis = new WeakSet<object>();
|
|
20
|
+
|
|
21
|
+
const GenerateImageParameters = Type.Object(
|
|
22
|
+
{
|
|
23
|
+
prompt: Type.String({
|
|
24
|
+
minLength: 1,
|
|
25
|
+
maxLength: MAX_IMAGE_PROMPT_CHARS,
|
|
26
|
+
description: "Image generation or edit prompt. Preserve the user's requested subject and constraints.",
|
|
27
|
+
}),
|
|
28
|
+
referenceImagePaths: Type.Optional(
|
|
29
|
+
Type.Union(
|
|
30
|
+
[
|
|
31
|
+
Type.Null(),
|
|
32
|
+
Type.Array(Type.String({ minLength: 1, maxLength: MAX_IMAGE_PATH_CHARS }), {
|
|
33
|
+
minItems: 1,
|
|
34
|
+
maxItems: MAX_REFERENCE_IMAGE_COUNT,
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
{
|
|
38
|
+
description:
|
|
39
|
+
"Use null when the user did not explicitly identify reference images; otherwise provide one to five user-identified local image paths.",
|
|
40
|
+
},
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
outputPath: Type.Optional(
|
|
44
|
+
Type.Union(
|
|
45
|
+
[
|
|
46
|
+
Type.Null(),
|
|
47
|
+
Type.String({
|
|
48
|
+
minLength: 1,
|
|
49
|
+
maxLength: MAX_IMAGE_PATH_CHARS,
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
{
|
|
53
|
+
description:
|
|
54
|
+
"Use null when the user did not explicitly request a destination; otherwise provide the requested explicit .png file path.",
|
|
55
|
+
},
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
size: Type.Optional(
|
|
59
|
+
StringEnum(IMAGE_GENERATION_SIZES, {
|
|
60
|
+
description: "Requested PNG dimensions, or auto.",
|
|
61
|
+
}),
|
|
62
|
+
),
|
|
63
|
+
quality: Type.Optional(
|
|
64
|
+
StringEnum(IMAGE_GENERATION_QUALITIES, {
|
|
65
|
+
description: "Requested image quality, or auto.",
|
|
66
|
+
}),
|
|
67
|
+
),
|
|
68
|
+
},
|
|
69
|
+
{ additionalProperties: false },
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
type GenerateImageToolParams = Static<typeof GenerateImageParameters>;
|
|
73
|
+
|
|
74
|
+
function syncImageGenerationTool(
|
|
75
|
+
pi: ExtensionAPI,
|
|
76
|
+
model: Parameters<typeof isImageGenerationEnabledForModel>[0],
|
|
77
|
+
config: Parameters<typeof isImageGenerationEnabledForModel>[1],
|
|
78
|
+
): void {
|
|
79
|
+
const eligible = isImageGenerationEnabledForModel(model, config);
|
|
80
|
+
const activeTools = pi.getActiveTools();
|
|
81
|
+
const active = activeTools.includes(IMAGE_GENERATION_TOOL_NAME);
|
|
82
|
+
if (eligible && !active) {
|
|
83
|
+
pi.setActiveTools([...activeTools, IMAGE_GENERATION_TOOL_NAME]);
|
|
84
|
+
} else if (!eligible && active) {
|
|
85
|
+
pi.setActiveTools(activeTools.filter((name) => name !== IMAGE_GENERATION_TOOL_NAME));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function registerImageGenerationExtension(
|
|
90
|
+
pi: ExtensionAPI,
|
|
91
|
+
loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
|
|
92
|
+
executeImage: typeof executeImageGeneration = executeImageGeneration,
|
|
93
|
+
): void {
|
|
94
|
+
if (registeredApis.has(pi)) return;
|
|
95
|
+
registeredApis.add(pi);
|
|
96
|
+
|
|
97
|
+
pi.registerTool<typeof GenerateImageParameters, ImageGenerationDetails, Record<string, never>>({
|
|
98
|
+
name: IMAGE_GENERATION_TOOL_NAME,
|
|
99
|
+
label: "OpenAI Generate Image",
|
|
100
|
+
description:
|
|
101
|
+
"Generate a PNG image, or edit from one to five user-approved local reference images, through the current Responses-capable model and the hosted gpt-image-2 image_generation tool. This is a paid provider operation.",
|
|
102
|
+
promptSnippet: "Generate or edit PNG images through the current Responses-capable model and gpt-image-2.",
|
|
103
|
+
promptGuidelines: [
|
|
104
|
+
"Use openai_generate_image when the user explicitly asks to create, draw, render, or edit a raster image and the active model speaks a Responses API.",
|
|
105
|
+
"Do not call openai_generate_image speculatively: it consumes the user's provider or gateway image quota.",
|
|
106
|
+
"Keep the image prompt faithful to the user's requested subject and constraints; do not invent unrequested style details.",
|
|
107
|
+
"Set referenceImagePaths to null unless the user explicitly identified local files; never invent paths or placeholder strings, and remember upload requires user approval.",
|
|
108
|
+
"Set outputPath to null unless the user explicitly asks for a destination; never invent a destination or placeholder string, and otherwise use the default Pi agent artifact.",
|
|
109
|
+
"Do not substitute Python, browser automation, shell scripts, or unrelated image tools for an eligible image request.",
|
|
110
|
+
],
|
|
111
|
+
parameters: GenerateImageParameters,
|
|
112
|
+
executionMode: "sequential",
|
|
113
|
+
async execute(toolCallId, params: GenerateImageToolParams, signal, _onUpdate, ctx) {
|
|
114
|
+
try {
|
|
115
|
+
const result = await executeImage({
|
|
116
|
+
params,
|
|
117
|
+
toolCallId,
|
|
118
|
+
signal,
|
|
119
|
+
ctx,
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
content: [{ type: "text", text: result.text }],
|
|
123
|
+
details: result.details,
|
|
124
|
+
};
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (error instanceof ImageGenerationError) {
|
|
127
|
+
throw new Error(error.message);
|
|
128
|
+
}
|
|
129
|
+
throw new Error(
|
|
130
|
+
sanitizeImageDiagnostic(error instanceof Error ? error.message : error, "Image generation failed."),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
renderResult: renderImageGenerationResult,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
pi.on("session_start", (_event, ctx) => {
|
|
138
|
+
const { config } = loadConfig();
|
|
139
|
+
syncImageGenerationTool(pi, ctx.model, config.imageGeneration);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
pi.on("model_select", (event) => {
|
|
143
|
+
const { config } = loadConfig();
|
|
144
|
+
syncImageGenerationTool(pi, event.model, config.imageGeneration);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
pi.on("before_agent_start", (_event, ctx) => {
|
|
148
|
+
const { config } = loadConfig();
|
|
149
|
+
syncImageGenerationTool(pi, ctx.model, config.imageGeneration);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export default function imageGenerationExtension(pi: ExtensionAPI): void {
|
|
154
|
+
registerImageGenerationExtension(pi);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export const _extensionTest = {
|
|
158
|
+
GenerateImageParameters,
|
|
159
|
+
syncImageGenerationTool,
|
|
160
|
+
};
|
package/src/native-fallback.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { CompactionConfig } from "./types";
|
|
|
12
12
|
export { parseModelSpec } from "./runtime";
|
|
13
13
|
|
|
14
14
|
export type NativeFallbackFailureReason =
|
|
15
|
+
| "disabled"
|
|
15
16
|
| "no-model-configured"
|
|
16
17
|
| "invalid-model-spec"
|
|
17
18
|
| "model-not-found"
|
|
@@ -53,23 +54,35 @@ function toErrorMessage(error: unknown): string {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
|
-
* Run pi's native compaction method with
|
|
57
|
+
* Run pi's native compaction method with a caller-resolved summary model.
|
|
57
58
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* The two compaction chains stay separate: the caller passes `remoteCompactModel` only when a
|
|
60
|
+
* remote v2 request was actually attempted and failed, and `nativeFallback.model` only when the
|
|
61
|
+
* active model cannot use remote v2 at all. This function never inspects `remoteCompactModel`
|
|
62
|
+
* itself, so a model that cannot compact remotely can never inherit the remote producer.
|
|
63
|
+
*
|
|
64
|
+
* Only the "resolved model differs from the current one" case is handled here: when the feature
|
|
65
|
+
* is disabled, nothing is resolved, or it equals the current model, the caller returns undefined
|
|
66
|
+
* from session_before_compact so pi runs the same native path itself, keeping its internal
|
|
61
67
|
* streamFn/thinkingLevel wiring.
|
|
62
68
|
*/
|
|
63
69
|
export async function runNativeFallbackCompaction(args: {
|
|
64
70
|
ctx: ExtensionContext;
|
|
65
71
|
event: SessionBeforeCompactEvent;
|
|
66
72
|
config: CompactionConfig;
|
|
73
|
+
/** Model spec supplied by the caller for this specific fallback reason. */
|
|
74
|
+
modelSpec?: string;
|
|
67
75
|
compactFn?: NativeCompactFn;
|
|
68
76
|
}): Promise<NativeFallbackResult> {
|
|
69
77
|
const { ctx, event, config } = args;
|
|
70
78
|
const compactFn = args.compactFn ?? compact;
|
|
79
|
+
const nativeFallback = config.nativeFallback;
|
|
80
|
+
|
|
81
|
+
if (!nativeFallback.enabled) {
|
|
82
|
+
return { ok: false, reason: "disabled" };
|
|
83
|
+
}
|
|
71
84
|
|
|
72
|
-
const spec =
|
|
85
|
+
const spec = args.modelSpec?.trim() ?? "";
|
|
73
86
|
if (!spec) {
|
|
74
87
|
return { ok: false, reason: "no-model-configured" };
|
|
75
88
|
}
|
|
@@ -106,7 +119,7 @@ export async function runNativeFallbackCompaction(args: {
|
|
|
106
119
|
mergeProviderHeaders(auth.headers),
|
|
107
120
|
event.customInstructions,
|
|
108
121
|
event.signal,
|
|
109
|
-
|
|
122
|
+
nativeFallback.thinkingLevel,
|
|
110
123
|
undefined,
|
|
111
124
|
auth.env,
|
|
112
125
|
);
|
package/src/types.ts
CHANGED
|
@@ -5,6 +5,7 @@ export const TOOLKIT_ID = "pi-openai-toolkit";
|
|
|
5
5
|
export const COMPACTION_EXTENSION_ID = `${TOOLKIT_ID}:compaction`;
|
|
6
6
|
export const WEB_SEARCH_EXTENSION_ID = `${TOOLKIT_ID}:web-search`;
|
|
7
7
|
export const IMAGE_GENERATION_EXTENSION_ID = `${TOOLKIT_ID}:image-generation`;
|
|
8
|
+
export const AUTO_MODE_EXTENSION_ID = `${TOOLKIT_ID}:auto-mode`;
|
|
8
9
|
export const DEFAULT_ARTIFACT_ROOT = "~/.pi/agent/artifacts/pi-openai-toolkit/compaction";
|
|
9
10
|
export const REDACTED_VALUE = "[REDACTED]";
|
|
10
11
|
/**
|
|
@@ -39,6 +40,20 @@ export type DebugArtifactKind =
|
|
|
39
40
|
|
|
40
41
|
export type CompactionContinuationMode = "inline" | "followUp" | "off";
|
|
41
42
|
|
|
43
|
+
/** Native-method fallback compaction: which model runs pi's compact() and how deeply. */
|
|
44
|
+
export type NativeFallbackConfig = {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* "provider/model-id" used for native-method fallback compaction when the active model
|
|
48
|
+
* cannot use remote v2 at all. A failed remote request is instead summarized by
|
|
49
|
+
* `remoteCompactModel`; the two sources never substitute for each other. Unset means the
|
|
50
|
+
* active model via pi's default path.
|
|
51
|
+
*/
|
|
52
|
+
model?: string;
|
|
53
|
+
/** Thinking level passed to pi's native compact() when the fallback model runs. */
|
|
54
|
+
thinkingLevel: ThinkingLevel;
|
|
55
|
+
};
|
|
56
|
+
|
|
42
57
|
export type AutoCompactionConfig = {
|
|
43
58
|
enabled: boolean;
|
|
44
59
|
continuation: CompactionContinuationMode;
|
|
@@ -58,13 +73,8 @@ export type CompactionConfig = {
|
|
|
58
73
|
* remains the checkpoint consumer and continues handling normal requests.
|
|
59
74
|
*/
|
|
60
75
|
remoteCompactModel?: string;
|
|
61
|
-
/**
|
|
62
|
-
|
|
63
|
-
* or when the compact endpoint fails). Unset = current model via pi's default path.
|
|
64
|
-
*/
|
|
65
|
-
model?: string;
|
|
66
|
-
/** Thinking level passed to pi's native compact() when the fallback model runs. */
|
|
67
|
-
thinkingLevel: ThinkingLevel;
|
|
76
|
+
/** Native-method fallback compaction policy (non-Responses APIs, or when the compact endpoint fails). */
|
|
77
|
+
nativeFallback: NativeFallbackConfig;
|
|
68
78
|
/** Threshold-triggered compaction and same-tool-loop continuation policy. */
|
|
69
79
|
autoCompaction: AutoCompactionConfig;
|
|
70
80
|
/** Subset of RESPONSES_COMPACT_CAPABLE_APIS that should use remote compaction. */
|
|
@@ -85,14 +95,32 @@ export type WebSearchConfig = {
|
|
|
85
95
|
|
|
86
96
|
export type ImageGenerationConfig = {
|
|
87
97
|
enabled: boolean;
|
|
88
|
-
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** `side-effect` reviews bash/write/edit plus extras; `all` reviews every tool call. */
|
|
101
|
+
export type AutoModeGate = "side-effect" | "all";
|
|
102
|
+
|
|
103
|
+
export type AutoModeConfig = {
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
/** Exact provider/model keys whose sessions may engage auto mode. */
|
|
89
106
|
models: string[];
|
|
107
|
+
/** "provider/model-id" that approves gated tool calls while auto mode is engaged. */
|
|
108
|
+
reviewerModel?: string;
|
|
109
|
+
gate: AutoModeGate;
|
|
110
|
+
/** Extra tool names reviewed on top of the side-effect default set. */
|
|
111
|
+
extraTools: string[];
|
|
112
|
+
/** Reviewer deadline in ms; expiry degrades to human confirmation or fail-closed. */
|
|
113
|
+
timeoutMs: number;
|
|
90
114
|
};
|
|
91
115
|
|
|
116
|
+
export const REVIEWER_TIMEOUT_MIN_MS = 1_000;
|
|
117
|
+
export const REVIEWER_TIMEOUT_MAX_MS = 120_000;
|
|
118
|
+
|
|
92
119
|
export type ToolkitConfig = {
|
|
93
120
|
compaction: CompactionConfig;
|
|
94
121
|
webSearch: WebSearchConfig;
|
|
95
122
|
imageGeneration: ImageGenerationConfig;
|
|
123
|
+
autoMode: AutoModeConfig;
|
|
96
124
|
};
|
|
97
125
|
|
|
98
126
|
export type LoadedToolkitConfig = {
|
|
@@ -425,12 +453,17 @@ export const DEFAULT_AUTO_COMPACTION_CONFIG: AutoCompactionConfig = {
|
|
|
425
453
|
reserveTokens: undefined,
|
|
426
454
|
};
|
|
427
455
|
|
|
456
|
+
export const DEFAULT_NATIVE_FALLBACK_CONFIG: NativeFallbackConfig = {
|
|
457
|
+
enabled: true,
|
|
458
|
+
model: undefined,
|
|
459
|
+
thinkingLevel: "off",
|
|
460
|
+
};
|
|
461
|
+
|
|
428
462
|
export const DEFAULT_COMPACTION_CONFIG: CompactionConfig = {
|
|
429
463
|
enabled: true,
|
|
430
464
|
allowCompactionContinuityBreak: false,
|
|
431
465
|
remoteCompactModel: undefined,
|
|
432
|
-
|
|
433
|
-
thinkingLevel: "off",
|
|
466
|
+
nativeFallback: { ...DEFAULT_NATIVE_FALLBACK_CONFIG },
|
|
434
467
|
autoCompaction: { ...DEFAULT_AUTO_COMPACTION_CONFIG },
|
|
435
468
|
responsesApis: [...RESPONSES_COMPACT_CAPABLE_APIS],
|
|
436
469
|
notifyOnLoad: false,
|
|
@@ -447,12 +480,21 @@ export const DEFAULT_WEB_SEARCH_CONFIG: WebSearchConfig = {
|
|
|
447
480
|
};
|
|
448
481
|
|
|
449
482
|
export const DEFAULT_IMAGE_GENERATION_CONFIG: ImageGenerationConfig = {
|
|
483
|
+
enabled: false,
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
export const DEFAULT_AUTO_MODE_CONFIG: AutoModeConfig = {
|
|
450
487
|
enabled: true,
|
|
451
488
|
models: [],
|
|
489
|
+
reviewerModel: undefined,
|
|
490
|
+
gate: "side-effect",
|
|
491
|
+
extraTools: [],
|
|
492
|
+
timeoutMs: 30_000,
|
|
452
493
|
};
|
|
453
494
|
|
|
454
495
|
export const DEFAULT_TOOLKIT_CONFIG: ToolkitConfig = {
|
|
455
496
|
compaction: DEFAULT_COMPACTION_CONFIG,
|
|
456
497
|
webSearch: DEFAULT_WEB_SEARCH_CONFIG,
|
|
457
498
|
imageGeneration: DEFAULT_IMAGE_GENERATION_CONFIG,
|
|
499
|
+
autoMode: DEFAULT_AUTO_MODE_CONFIG,
|
|
458
500
|
};
|
package/tsconfig.check.json
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"extensions/compaction.ts",
|
|
16
16
|
"extensions/web-search.ts",
|
|
17
17
|
"extensions/image-generation.ts",
|
|
18
|
+
"extensions/auto-mode.ts",
|
|
18
19
|
"src/compact-client.ts",
|
|
19
20
|
"src/config.ts",
|
|
20
21
|
"src/debug.ts",
|
|
@@ -31,6 +32,10 @@
|
|
|
31
32
|
"src/image-generation/render.ts",
|
|
32
33
|
"src/image-generation/service.ts",
|
|
33
34
|
"src/image-generation/types.ts",
|
|
35
|
+
"src/auto-mode/extension.ts",
|
|
36
|
+
"src/auto-mode/policy.ts",
|
|
37
|
+
"src/auto-mode/reviewer.ts",
|
|
38
|
+
"src/auto-mode/types.ts",
|
|
34
39
|
"src/model-scope.ts",
|
|
35
40
|
"src/native-fallback.ts",
|
|
36
41
|
"src/payload-rewrite.ts",
|