@code-yeongyu/senpi 2026.7.16 → 2026.7.17-3
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 +81 -0
- package/dist/core/dynamic-prompt/build.d.ts +7 -0
- package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
- package/dist/core/dynamic-prompt/build.js +5 -0
- package/dist/core/dynamic-prompt/build.js.map +1 -1
- package/dist/core/dynamic-prompt/workstation.d.ts +35 -0
- package/dist/core/dynamic-prompt/workstation.d.ts.map +1 -0
- package/dist/core/dynamic-prompt/workstation.js +81 -0
- package/dist/core/dynamic-prompt/workstation.js.map +1 -0
- package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts +6 -2
- package/dist/core/extensions/builtin/anthropic-web-search/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/anthropic-web-search/index.js +73 -5
- package/dist/core/extensions/builtin/anthropic-web-search/index.js.map +1 -1
- package/dist/core/extensions/builtin/goal/command-registration.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/command-registration.js +4 -5
- package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts +43 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.d.ts.map +1 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.js +58 -0
- package/dist/core/extensions/builtin/goal/elapsed-ticker.js.map +1 -0
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +39 -14
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/tool-registration.js +3 -4
- package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
- package/dist/core/extensions/builtin/goal/ui.d.ts +2 -2
- package/dist/core/extensions/builtin/goal/ui.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/ui.js +8 -4
- package/dist/core/extensions/builtin/goal/ui.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/native-search.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/policy.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/policy.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/status.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/status.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tier-b.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/expose/tier-b.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tier-b.js +10 -10
- package/dist/core/extensions/builtin/mcp/expose/tier-b.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tool-search.d.ts +3 -3
- package/dist/core/extensions/builtin/mcp/expose/tool-search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/tool-search.js +14 -14
- package/dist/core/extensions/builtin/mcp/expose/tool-search.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/index.js +5 -5
- package/dist/core/extensions/builtin/mcp/index.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts +2 -2
- package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/service.js +2 -2
- package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-7.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js +5 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-opus-4-8.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.2.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.3-codex.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.4.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-6.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k2-7.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js +14 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js +13 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js +2 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/renderers.js.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts +27 -0
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.d.ts.map +1 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +60 -1
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js.map +1 -1
- package/dist/core/extensions/types.d.ts +5 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +1 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution-renderer.js +1 -0
- package/dist/modes/interactive/components/tool-execution-renderer.js.map +1 -1
- package/docs/AGENTS.md +70 -0
- package/docs/mcp.md +5 -5
- package/docs/settings.md +1 -1
- package/examples/AGENTS.md +3 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +49 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +59 -19
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +68 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +6 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +6 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/README.md +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +58 -7
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +2 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +25 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +70 -131
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +26 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +36 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +0 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +20 -38
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts +0 -110
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +0 -90
- package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -0
- package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js +171 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/tool-schema-compat.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +6 -6
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
1
2
|
import type { ExtensionContext } from "@code-yeongyu/senpi";
|
|
2
3
|
import type { KernelToHostMessage } from "./bridge/protocol.ts";
|
|
3
4
|
import type { AgentExecuteTool } from "./bridges/agent-bridge.ts";
|
|
@@ -35,6 +36,8 @@ const SESSION_LIFECYCLE_EVENTS = [
|
|
|
35
36
|
|
|
36
37
|
type SessionLifecycleEvent = (typeof SESSION_LIFECYCLE_EVENTS)[number];
|
|
37
38
|
|
|
39
|
+
type CodemodeEvent = SessionLifecycleEvent | "model_select";
|
|
40
|
+
|
|
38
41
|
type TrackedExecution = {
|
|
39
42
|
readonly promise: Promise<unknown>;
|
|
40
43
|
readonly controller: AbortController;
|
|
@@ -51,7 +54,7 @@ type SessionRuntime = {
|
|
|
51
54
|
|
|
52
55
|
export interface CodemodeExtensionAPI {
|
|
53
56
|
registerTool(tool: ReturnType<typeof createEvalTool>): void;
|
|
54
|
-
on(event:
|
|
57
|
+
on(event: CodemodeEvent, handler: (event: unknown, ctx: ExtensionContext) => Promise<void> | void): void;
|
|
55
58
|
executeTool: AgentExecuteTool;
|
|
56
59
|
getActiveTools(): string[];
|
|
57
60
|
}
|
|
@@ -75,6 +78,32 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
75
78
|
const manager = new SessionManagerProxy();
|
|
76
79
|
const complete = options.complete ?? ((request, ctx) => createCompletionHandler()(ctx)(request));
|
|
77
80
|
const renderers = { renderCall: renderEvalCall, renderResult: renderEvalResult };
|
|
81
|
+
let activeRuntime: SessionRuntime | undefined;
|
|
82
|
+
let activeModelId: string | undefined;
|
|
83
|
+
const registerEvalForRuntime = (runtime: SessionRuntime, modelId: string | undefined): void => {
|
|
84
|
+
pi.registerTool(
|
|
85
|
+
createEvalTool({
|
|
86
|
+
enabledLanguages: runtime.enabledLanguages,
|
|
87
|
+
kernelManager: manager,
|
|
88
|
+
cellTimeoutSeconds: runtime.settings.cellTimeoutSeconds,
|
|
89
|
+
executeTool: runtime.executeTool,
|
|
90
|
+
complete,
|
|
91
|
+
settings: runtime.settings,
|
|
92
|
+
artifactsDir: runtime.artifactsDir,
|
|
93
|
+
executionTracker: manager,
|
|
94
|
+
renderers,
|
|
95
|
+
spawns: runtime.spawns,
|
|
96
|
+
spawnDefaultAgent: runtime.settings.taskTools.task,
|
|
97
|
+
hostLine: hostLine(),
|
|
98
|
+
...(modelId === undefined ? {} : { modelId }),
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
const dropRuntime = async (): Promise<void> => {
|
|
103
|
+
activeRuntime = undefined;
|
|
104
|
+
activeModelId = undefined;
|
|
105
|
+
await manager.dispose();
|
|
106
|
+
};
|
|
78
107
|
pi.registerTool(
|
|
79
108
|
createEvalTool({
|
|
80
109
|
enabledLanguages: { py: true, js: true, rb: true, jl: true },
|
|
@@ -85,6 +114,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
85
114
|
settings: defaultCodemodeSettings,
|
|
86
115
|
executionTracker: manager,
|
|
87
116
|
renderers,
|
|
117
|
+
hostLine: hostLine(),
|
|
88
118
|
}),
|
|
89
119
|
);
|
|
90
120
|
|
|
@@ -92,25 +122,35 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
|
|
|
92
122
|
const generation = manager.beginReplacement();
|
|
93
123
|
const runtime = await createRuntime(pi, ctx, event, complete, options);
|
|
94
124
|
if (!(await manager.replace(generation, runtime.manager))) return;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
);
|
|
125
|
+
activeRuntime = runtime;
|
|
126
|
+
activeModelId = ctx.model?.id;
|
|
127
|
+
registerEvalForRuntime(runtime, activeModelId);
|
|
128
|
+
});
|
|
129
|
+
pi.on("session_shutdown", async () => dropRuntime());
|
|
130
|
+
pi.on("session_before_switch", async () => dropRuntime());
|
|
131
|
+
pi.on("session_before_fork", async () => dropRuntime());
|
|
132
|
+
pi.on("model_select", async (event) => {
|
|
133
|
+
const runtime = activeRuntime;
|
|
134
|
+
if (runtime === undefined) return;
|
|
135
|
+
const modelId = modelIdFrom(event);
|
|
136
|
+
if (modelId === undefined || modelId === activeModelId) return;
|
|
137
|
+
activeModelId = modelId;
|
|
138
|
+
registerEvalForRuntime(runtime, modelId);
|
|
110
139
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function hostLine(): string {
|
|
143
|
+
const cpu = os.cpus()[0]?.model?.trim();
|
|
144
|
+
return [`${os.platform()} ${os.arch()}`, cpu, `${os.availableParallelism()} cores`]
|
|
145
|
+
.filter((part): part is string => !!part)
|
|
146
|
+
.join(" \u00b7 ");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function modelIdFrom(event: unknown): string | undefined {
|
|
150
|
+
if (typeof event !== "object" || event === null || !("model" in event)) return undefined;
|
|
151
|
+
const model = event.model;
|
|
152
|
+
if (typeof model !== "object" || model === null || !("id" in model)) return undefined;
|
|
153
|
+
return typeof model.id === "string" ? model.id : undefined;
|
|
114
154
|
}
|
|
115
155
|
|
|
116
156
|
class SessionManagerProxy implements CodemodeSessionManager, EvalExecutionTracker {
|
|
@@ -14,6 +14,35 @@ export interface EvalPromptParts {
|
|
|
14
14
|
export interface EvalPromptOptions {
|
|
15
15
|
readonly spawns: boolean;
|
|
16
16
|
readonly spawnDefaultAgent?: string;
|
|
17
|
+
/** Active model id; selects the emphasis dialect of the batching guidance. */
|
|
18
|
+
readonly modelId?: string;
|
|
19
|
+
/** Preformatted host line (e.g. "darwin arm64 · Apple M5 Max · 18 cores"); enables the host-sizing note. */
|
|
20
|
+
readonly hostLine?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Prompt dialect for the eval-first batching emphasis. */
|
|
24
|
+
export type EvalEmphasisStyle = "default" | "claude" | "codex" | "kimi";
|
|
25
|
+
|
|
26
|
+
const CLAUDE_MODEL_RE = /(^|[/.:])claude[-.]/i;
|
|
27
|
+
const GLM_MODEL_RE = /(^|[/.:@-])glm[-.]?\d/i;
|
|
28
|
+
const KIMI_MODEL_RE = /(^|[/.:])kimi[-.]/i;
|
|
29
|
+
const OPENAI_MODEL_RE = /(^|[/.:])(gpt|chatgpt|codex)[-.]|(^|[/.:])o[134](?:[-.]|$)/i;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Selects the eval-first batching dialect for a model id:
|
|
33
|
+
* - `claude`: Claude/GLM — direct imperatives; both are steered most reliably
|
|
34
|
+
* by explicit tagged directives (GLM prompting guidance routes to Claude's).
|
|
35
|
+
* - `codex`: OpenAI reasoning families — terse bounded rules, no emphasis spam.
|
|
36
|
+
* - `kimi`: Kimi K-series — positive operational constraints; all-caps NEVER
|
|
37
|
+
* directives make K2.x overthink instead of comply.
|
|
38
|
+
* - `default`: everything else (and no model) — maximum-emphasis fallback.
|
|
39
|
+
*/
|
|
40
|
+
export function evalEmphasisStyle(modelId: string | undefined): EvalEmphasisStyle {
|
|
41
|
+
if (!modelId) return "default";
|
|
42
|
+
if (CLAUDE_MODEL_RE.test(modelId) || GLM_MODEL_RE.test(modelId)) return "claude";
|
|
43
|
+
if (KIMI_MODEL_RE.test(modelId)) return "kimi";
|
|
44
|
+
if (OPENAI_MODEL_RE.test(modelId)) return "codex";
|
|
45
|
+
return "default";
|
|
17
46
|
}
|
|
18
47
|
|
|
19
48
|
type ContextValue = string | boolean;
|
|
@@ -57,7 +86,24 @@ const EVAL_PROMPT_TEMPLATE = `Run one step of code in a persistent kernel.
|
|
|
57
86
|
|
|
58
87
|
Work incrementally: imports in one call, define in the next, test, then use — each its own eval call. Re-run setup ONLY after \`reset\`, a kernel crash, or a \`NameError\`/\`ReferenceError\` proving the state is gone.
|
|
59
88
|
|
|
60
|
-
|
|
89
|
+
{{#if styleClaude}}<eval_first_batching>
|
|
90
|
+
\`eval\` is your default execution surface: if a step needs more than one tool call, write ONE cell that performs the whole step — never issue the calls one at a time.
|
|
91
|
+
- Enumerate every lookup the step needs, then run all independent ones simultaneously with \`parallel(thunks)\` inside the cell; keep calls sequential only when one result feeds the next.
|
|
92
|
+
- Write real code around the calls: loop or comprehend over file sets with \`read()\`/stdlib, branch per case, and wrap risky calls in try/except so one failure degrades only its item — recover or retry inside the cell, keep the batch alive.
|
|
93
|
+
- Post-process \`tool.<name>()\` results programmatically and return distilled facts, not raw dumps.
|
|
94
|
+
</eval_first_batching>{{/if}}{{#if styleCodex}}Route multi-call steps through eval: one cell per step, independent lookups dispatched together via \`parallel(thunks)\`; keep work sequential only when one result determines the next action.
|
|
95
|
+
- Loop or comprehend over file sets with \`read()\`/stdlib instead of reading files one call at a time; post-process \`tool.<name>()\` results programmatically.
|
|
96
|
+
- Wrap failable calls in try/except inside the cell; a failed item degrades only itself. After two distinct failed strategies for the same fact, fall back to direct tool calls.
|
|
97
|
+
- Reduce large results in-kernel to the facts the task needs before returning.{{/if}}{{#if styleKimi}}Treat eval as the standard way to execute any step involving several tool calls: write one cell that performs the whole step.
|
|
98
|
+
- When lookups are independent, run them together with \`parallel(thunks)\` in that cell; when one result feeds the next, keep them sequential inside the same cell.
|
|
99
|
+
- Loop or comprehend over file sets with \`read()\`/stdlib, post-process \`tool.<name>()\` results programmatically, and put try/except around each risky call so the rest of the batch completes.
|
|
100
|
+
- Filter and aggregate results in the kernel, then return the distilled facts.{{/if}}{{#if styleDefault}}**EVAL IS YOUR PRIMARY EXECUTION SURFACE.** Any step that needs MORE THAN ONE tool call MUST be written as ONE cell — NEVER as a chain of single tool calls.
|
|
101
|
+
- **PLAN THE WHOLE STEP, THEN BATCH IT.** Enumerate every read/search/lookup the step needs and dispatch ALL independent ones through \`parallel(thunks)\` in one cell.
|
|
102
|
+
- **WRITE REAL CODE, NOT CALL LISTS.** Loop or comprehend over file sets with \`read()\`/stdlib, branch \`if\`/\`else\` per case, post-process \`tool.<name>()\` results programmatically, and wrap EVERY risky call in try/except so ONE failure NEVER kills the batch.
|
|
103
|
+
- **DISTILL IN-KERNEL.** Filter, diff, and aggregate in code before returning; return facts, NOT dumps.{{/if}}
|
|
104
|
+
{{#if hostLine}}
|
|
105
|
+
Host: {{hostLine}} — cells execute here. Size \`parallel(thunks)\` pools to its cores; \`tool.<name>()\` shell commands must fit this platform, even when the code you are writing targets another machine.
|
|
106
|
+
{{/if}}
|
|
61
107
|
|
|
62
108
|
Fields:
|
|
63
109
|
|
|
@@ -129,6 +175,7 @@ export function buildEvalPrompt(
|
|
|
129
175
|
throw new Error("no kernels enabled for eval prompt");
|
|
130
176
|
}
|
|
131
177
|
const spawnDefaultAgent = options.spawnDefaultAgent ?? "task";
|
|
178
|
+
const style = evalEmphasisStyle(options.modelId);
|
|
132
179
|
const context: Context = {
|
|
133
180
|
py: enabled.py,
|
|
134
181
|
js: enabled.js,
|
|
@@ -136,6 +183,11 @@ export function buildEvalPrompt(
|
|
|
136
183
|
jl: enabled.jl,
|
|
137
184
|
spawns: options.spawns,
|
|
138
185
|
spawnDefaultAgent,
|
|
186
|
+
styleClaude: style === "claude",
|
|
187
|
+
styleCodex: style === "codex",
|
|
188
|
+
styleKimi: style === "kimi",
|
|
189
|
+
styleDefault: style === "default",
|
|
190
|
+
hostLine: options.hostLine ?? "",
|
|
139
191
|
};
|
|
140
192
|
const examples = REUSE_CHAIN_EXAMPLES.filter((example) => enabled[example.language])
|
|
141
193
|
.map((example) => {
|
|
@@ -155,12 +207,26 @@ export function buildEvalPrompt(
|
|
|
155
207
|
description,
|
|
156
208
|
promptSnippet: "Run one incremental code cell in a persistent language kernel.",
|
|
157
209
|
promptGuidelines: [
|
|
158
|
-
|
|
210
|
+
BATCHING_GUIDELINES[style],
|
|
159
211
|
"Use eval reset only when a language kernel must be wiped; reset is scoped to the selected language.",
|
|
160
212
|
],
|
|
161
213
|
};
|
|
162
214
|
}
|
|
163
215
|
|
|
216
|
+
/**
|
|
217
|
+
* System-prompt guideline per emphasis dialect. The default dialect carries
|
|
218
|
+
* maximum emphasis so unmapped models still batch through eval; the others are
|
|
219
|
+
* tuned to what steers that family reliably.
|
|
220
|
+
*/
|
|
221
|
+
const BATCHING_GUIDELINES: Record<EvalEmphasisStyle, string> = {
|
|
222
|
+
default:
|
|
223
|
+
"**EVAL FIRST.** Any step needing MORE THAN ONE tool call MUST be ONE eval cell: run independent calls in parallel, wrap risky calls in try/except, and return distilled facts — NEVER a chain of single tool calls.",
|
|
224
|
+
claude:
|
|
225
|
+
"Prefer eval for any step needing more than one tool call: one cell that runs independent calls in parallel, handles per-call failures in code, and returns distilled facts.",
|
|
226
|
+
codex: "Route multi-call steps through eval: one cell per step, independent calls dispatched in parallel; fall back to direct tool calls when one call is sufficient or each result changes the next decision.",
|
|
227
|
+
kimi: "Treat eval as the standard way to execute multi-call steps: one cell that runs independent calls in parallel, handles failures per item, and returns distilled facts.",
|
|
228
|
+
};
|
|
229
|
+
|
|
164
230
|
function renderTemplate(template: string, context: Context): string {
|
|
165
231
|
let index = 0;
|
|
166
232
|
const [rendered, nextIndex] = renderUntil(template, context, index, []);
|
|
@@ -39,6 +39,10 @@ export interface CreateEvalToolOptions {
|
|
|
39
39
|
readonly spawns?: boolean;
|
|
40
40
|
/** Default agent name surfaced in the agent() helper docs when spawns are enabled. */
|
|
41
41
|
readonly spawnDefaultAgent?: string;
|
|
42
|
+
/** Active model id; selects the emphasis dialect of the eval prompt. */
|
|
43
|
+
readonly modelId?: string;
|
|
44
|
+
/** Preformatted host line rendered into the prompt's host-sizing note. */
|
|
45
|
+
readonly hostLine?: string;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
interface EvalCellInvocation {
|
|
@@ -152,6 +156,8 @@ export function createEvalTool(options: CreateEvalToolOptions): ToolDefinition<E
|
|
|
152
156
|
const prompt = buildEvalPrompt(options.enabledLanguages, {
|
|
153
157
|
spawns: options.spawns ?? false,
|
|
154
158
|
...(options.spawnDefaultAgent === undefined ? {} : { spawnDefaultAgent: options.spawnDefaultAgent }),
|
|
159
|
+
...(options.modelId === undefined ? {} : { modelId: options.modelId }),
|
|
160
|
+
...(options.hostLine === undefined ? {} : { hostLine: options.hostLine }),
|
|
155
161
|
});
|
|
156
162
|
const languages = enabledLanguageList(options.enabledLanguages);
|
|
157
163
|
return {
|
|
@@ -725,6 +725,12 @@ export function renderEvalCall(
|
|
|
725
725
|
context: RenderContext,
|
|
726
726
|
): EvalRenderComponent {
|
|
727
727
|
const component = componentFor(context);
|
|
728
|
+
if (context.hasResult === true) {
|
|
729
|
+
// The result renderer owns the full pending -> running -> done frame once a result exists.
|
|
730
|
+
// Rendering the call frame too would stack a duplicate box, so yield to it here.
|
|
731
|
+
component.setBlocks([]);
|
|
732
|
+
return component;
|
|
733
|
+
}
|
|
728
734
|
if (theme === undefined && context.spinnerFrame === undefined) {
|
|
729
735
|
const title = args.title === undefined ? "" : ` ${args.title}`;
|
|
730
736
|
const reset = args.reset === true ? " reset" : "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-agent-core",
|
|
3
3
|
"private": true,
|
|
4
|
-
"version": "2026.7.
|
|
4
|
+
"version": "2026.7.17-3",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"prepublishOnly": "npm run clean && npm run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@earendil-works/pi-ai": "^2026.7.
|
|
33
|
+
"@earendil-works/pi-ai": "^2026.7.17-3",
|
|
34
34
|
"ignore": "7.0.5",
|
|
35
35
|
"typebox": "1.1.38",
|
|
36
36
|
"yaml": "2.9.0"
|
|
@@ -747,7 +747,7 @@ Many models support thinking/reasoning capabilities where they can show their in
|
|
|
747
747
|
const model = models.getModel('anthropic', 'claude-sonnet-4-5')!;
|
|
748
748
|
// or models.getModel('openai', 'gpt-5-mini');
|
|
749
749
|
// or models.getModel('google', 'gemini-2.5-flash');
|
|
750
|
-
// or models.getModel('xai', 'grok-
|
|
750
|
+
// or models.getModel('xai', 'grok-4.5');
|
|
751
751
|
|
|
752
752
|
// Check if model supports reasoning
|
|
753
753
|
if (model.reasoning) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAWX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAgKrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"anthropic-messages.d.ts","sourceRoot":"","sources":["../../src/api/anthropic-messages.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAU1C,OAAO,KAAK,EAWX,mBAAmB,EAEnB,cAAc,EACd,aAAa,EAMb,MAAM,aAAa,CAAC;AAgKrB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,CAAC;AA6DhE,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACtD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;CACnB;AAuiBD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,gBAAgB,CAwUzE,CAAC;AAoEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,oBAAoB,EAAE,mBAAmB,CA2ClF,CAAC"}
|
|
@@ -152,6 +152,12 @@ function getAnthropicCompat(model) {
|
|
|
152
152
|
supportsForcedToolChoice: model.compat?.supportsForcedToolChoice ?? !CLAUDE_FABLE_OR_MYTHOS_MODEL_ID.test(model.id),
|
|
153
153
|
allowEmptySignature: model.compat?.allowEmptySignature ?? false,
|
|
154
154
|
supportsToolReferences: model.compat?.supportsToolReferences ?? defaultSupportsToolReferences(model),
|
|
155
|
+
// Default: first-party Anthropic only. Anthropic-compatible providers
|
|
156
|
+
// (kimi-coding, fireworks, copilot, gateways) may execute the server-side
|
|
157
|
+
// search but reject the replayed server_tool_use / web_search_tool_result
|
|
158
|
+
// blocks on the next request (kimi-coding 400s with `tool_call_id is not
|
|
159
|
+
// found`).
|
|
160
|
+
supportsWebSearch: model.compat?.supportsWebSearch ?? isAnthropicApiBaseUrl(model.baseUrl),
|
|
155
161
|
};
|
|
156
162
|
}
|
|
157
163
|
/**
|
|
@@ -227,6 +233,23 @@ function lastAnthropicFallbackBoundary(content) {
|
|
|
227
233
|
function isAnthropicServerToolUseBlock(raw) {
|
|
228
234
|
return isRecord(raw) && raw.type === "server_tool_use" && typeof raw.id === "string";
|
|
229
235
|
}
|
|
236
|
+
// Only tool_use-shaped provider-native blocks (server_tool_use, mcp_tool_use)
|
|
237
|
+
// stream their input via input_json_delta. Result-shaped blocks must replay
|
|
238
|
+
// byte-for-byte (encrypted_content), so never merge an `input` into them.
|
|
239
|
+
function isProviderNativeToolUseBlock(raw) {
|
|
240
|
+
return isRecord(raw) && (raw.type === "server_tool_use" || raw.type === "mcp_tool_use");
|
|
241
|
+
}
|
|
242
|
+
// Endpoints without `supportsWebSearch` reject replayed web-search server-tool
|
|
243
|
+
// blocks (kimi-coding 400s with `tool_call_id is not found`), wedging every
|
|
244
|
+
// subsequent request of the session. Dropping the pair loses the searched
|
|
245
|
+
// context but keeps the conversation usable.
|
|
246
|
+
function isAnthropicWebSearchReplayBlock(raw) {
|
|
247
|
+
if (!isRecord(raw))
|
|
248
|
+
return false;
|
|
249
|
+
if (raw.type === "web_search_tool_result")
|
|
250
|
+
return true;
|
|
251
|
+
return raw.type === "server_tool_use" && raw.name === "web_search";
|
|
252
|
+
}
|
|
230
253
|
// tool_use ids referenced by server-tool result blocks in content[0, boundary).
|
|
231
254
|
// A pre-boundary `server_tool_use` whose id is absent here is unpaired — the
|
|
232
255
|
// fallback interrupted the declined attempt before its result arrived — so
|
|
@@ -339,27 +362,28 @@ function rejectsComputerUseBeta(model) {
|
|
|
339
362
|
return ((model.provider === "cloudflare-ai-gateway" && model.baseUrl.includes("anthropic")) ||
|
|
340
363
|
matchesModelMarker(model, UNSUPPORTED_NATIVE_COMPUTER_TOOL_MODEL_MARKERS));
|
|
341
364
|
}
|
|
365
|
+
function isAnthropicWebSearchToolType(toolType) {
|
|
366
|
+
return toolType.startsWith("web_search_");
|
|
367
|
+
}
|
|
342
368
|
function sanitizeUnsupportedNativeTools(model, params) {
|
|
343
369
|
const payload = params;
|
|
344
370
|
const headers = stringRecord(payload.headers);
|
|
345
371
|
const headerSanitization = rejectsComputerUseBeta(model)
|
|
346
372
|
? removeComputerUseBetaHeader(headers)
|
|
347
373
|
: { changed: false };
|
|
374
|
+
const rejectsNativeWebSearch = !getAnthropicCompat(model).supportsWebSearch;
|
|
348
375
|
const tools = payload.tools;
|
|
349
376
|
const sanitized = { ...payload };
|
|
350
377
|
let changed = false;
|
|
351
|
-
const removedToolNames = new Set();
|
|
352
378
|
if (Array.isArray(tools)) {
|
|
353
379
|
const supportedTools = [];
|
|
354
380
|
for (const tool of tools) {
|
|
355
381
|
const hookTool = tool;
|
|
356
382
|
if (isRecord(hookTool) &&
|
|
357
383
|
typeof hookTool.type === "string" &&
|
|
358
|
-
rejectsNativeComputerTool(model, hookTool.type)
|
|
384
|
+
(rejectsNativeComputerTool(model, hookTool.type) ||
|
|
385
|
+
(rejectsNativeWebSearch && isAnthropicWebSearchToolType(hookTool.type)))) {
|
|
359
386
|
changed = true;
|
|
360
|
-
if (typeof hookTool.name === "string") {
|
|
361
|
-
removedToolNames.add(hookTool.name);
|
|
362
|
-
}
|
|
363
387
|
continue;
|
|
364
388
|
}
|
|
365
389
|
supportedTools.push(tool);
|
|
@@ -384,7 +408,10 @@ function sanitizeUnsupportedNativeTools(model, params) {
|
|
|
384
408
|
}
|
|
385
409
|
if (changed && isRecord(sanitized.tool_choice)) {
|
|
386
410
|
const toolChoiceName = sanitized.tool_choice.name;
|
|
387
|
-
const
|
|
411
|
+
const hasSelectedTool = typeof toolChoiceName === "string" &&
|
|
412
|
+
Array.isArray(sanitized.tools) &&
|
|
413
|
+
sanitized.tools.some((tool) => isRecord(tool) && tool.name === toolChoiceName);
|
|
414
|
+
const shouldRemoveToolChoice = sanitized.tools === undefined || (typeof toolChoiceName === "string" && !hasSelectedTool);
|
|
388
415
|
if (shouldRemoveToolChoice) {
|
|
389
416
|
delete sanitized.tool_choice;
|
|
390
417
|
}
|
|
@@ -764,6 +791,12 @@ export const stream = (model, context, options) => {
|
|
|
764
791
|
partial: output,
|
|
765
792
|
});
|
|
766
793
|
}
|
|
794
|
+
else if (block && block.type === "providerNative" && isProviderNativeToolUseBlock(block.raw)) {
|
|
795
|
+
// Server-side tool blocks (server_tool_use) stream their input
|
|
796
|
+
// the same way tool_use does; the block captured at
|
|
797
|
+
// content_block_start still has `input: {}`.
|
|
798
|
+
block.partialJson = (block.partialJson ?? "") + event.delta.partial_json;
|
|
799
|
+
}
|
|
767
800
|
}
|
|
768
801
|
else if (event.delta.type === "signature_delta") {
|
|
769
802
|
const index = blocks.findIndex((b) => b.index === event.index);
|
|
@@ -807,6 +840,13 @@ export const stream = (model, context, options) => {
|
|
|
807
840
|
partial: output,
|
|
808
841
|
});
|
|
809
842
|
}
|
|
843
|
+
else if (block.type === "providerNative") {
|
|
844
|
+
const partialJson = block.partialJson;
|
|
845
|
+
delete block.partialJson;
|
|
846
|
+
if (partialJson !== undefined && isRecord(block.raw)) {
|
|
847
|
+
block.raw = { ...block.raw, input: parseStreamingJson(partialJson) };
|
|
848
|
+
}
|
|
849
|
+
}
|
|
810
850
|
}
|
|
811
851
|
}
|
|
812
852
|
else if (event.type === "message_delta") {
|
|
@@ -859,6 +899,13 @@ export const stream = (model, context, options) => {
|
|
|
859
899
|
catch (error) {
|
|
860
900
|
for (const block of output.content) {
|
|
861
901
|
delete block.index;
|
|
902
|
+
// An aborted stream never reaches content_block_stop; keep whatever
|
|
903
|
+
// provider-native input accumulated, mirroring toolCall's partial
|
|
904
|
+
// arguments.
|
|
905
|
+
const scratch = block.partialJson;
|
|
906
|
+
if (block.type === "providerNative" && scratch !== undefined && isRecord(block.raw)) {
|
|
907
|
+
block.raw = { ...block.raw, input: parseStreamingJson(scratch) };
|
|
908
|
+
}
|
|
862
909
|
// partialJson is only a streaming scratch buffer; never persist it.
|
|
863
910
|
delete block.partialJson;
|
|
864
911
|
}
|
|
@@ -1199,6 +1246,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
1199
1246
|
// Tool calls from a declined pre-fallback attempt are dropped from their
|
|
1200
1247
|
// assistant turn below; drop their tool_results in lockstep so none dangle.
|
|
1201
1248
|
const discardedFallbackToolCallIds = collectDiscardedFallbackToolCallIds(transformedMessages, model);
|
|
1249
|
+
const rejectsNativeWebSearchReplay = !getAnthropicCompat(model).supportsWebSearch;
|
|
1202
1250
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1203
1251
|
const msg = transformedMessages[i];
|
|
1204
1252
|
if (msg.role === "user") {
|
|
@@ -1320,8 +1368,11 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
1320
1368
|
});
|
|
1321
1369
|
}
|
|
1322
1370
|
else if (block.type === "providerNative") {
|
|
1323
|
-
if (isSameModel &&
|
|
1371
|
+
if (isSameModel &&
|
|
1372
|
+
isReplayableAnthropicProviderNativeBlock(block.raw) &&
|
|
1373
|
+
!(rejectsNativeWebSearchReplay && isAnthropicWebSearchReplayBlock(block.raw))) {
|
|
1324
1374
|
blocks.push(block.raw);
|
|
1375
|
+
}
|
|
1325
1376
|
}
|
|
1326
1377
|
}
|
|
1327
1378
|
if (blocks.length === 0)
|