@oh-my-pi/pi-coding-agent 14.5.12 → 14.5.13
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 +32 -0
- package/package.json +18 -10
- package/src/cli/jupyter-cli.ts +1 -1
- package/src/config/model-equivalence.ts +49 -16
- package/src/config/model-registry.ts +100 -25
- package/src/config/model-resolver.ts +29 -15
- package/src/config/settings-schema.ts +20 -6
- package/src/config/settings.ts +9 -8
- package/src/config.ts +9 -0
- package/src/eval/backend.ts +43 -0
- package/src/eval/eval.lark +43 -0
- package/src/eval/index.ts +5 -0
- package/src/eval/js/context-manager.ts +717 -0
- package/src/eval/js/executor.ts +131 -0
- package/src/eval/js/index.ts +46 -0
- package/src/eval/js/prelude.ts +2 -0
- package/src/eval/js/prelude.txt +84 -0
- package/src/eval/js/tool-bridge.ts +124 -0
- package/src/eval/parse.ts +337 -0
- package/src/{ipy → eval/py}/executor.ts +2 -180
- package/src/{ipy → eval/py}/gateway-coordinator.ts +2 -2
- package/src/eval/py/index.ts +58 -0
- package/src/{ipy → eval/py}/kernel.ts +5 -41
- package/src/{ipy → eval/py}/prelude.py +39 -227
- package/src/eval/types.ts +48 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +8 -10
- package/src/extensibility/extensions/types.ts +2 -3
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/lsp/client.ts +9 -0
- package/src/lsp/index.ts +395 -0
- package/src/lsp/types.ts +15 -4
- package/src/main.ts +25 -14
- package/src/mcp/oauth-flow.ts +1 -1
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/components/{python-execution.ts → eval-execution.ts} +11 -4
- package/src/modes/components/login-dialog.ts +1 -1
- package/src/modes/components/oauth-selector.ts +2 -1
- package/src/modes/components/tool-execution.ts +3 -4
- package/src/modes/controllers/command-controller.ts +28 -8
- package/src/modes/controllers/input-controller.ts +4 -4
- package/src/modes/controllers/selector-controller.ts +2 -1
- package/src/modes/interactive-mode.ts +4 -5
- package/src/modes/types.ts +3 -3
- package/src/modes/utils/ui-helpers.ts +2 -2
- package/src/prompts/system/system-prompt.md +3 -3
- package/src/prompts/tools/eval.md +92 -0
- package/src/prompts/tools/lsp.md +7 -3
- package/src/sdk.ts +45 -31
- package/src/session/agent-session.ts +42 -42
- package/src/session/messages.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/system-prompt.ts +34 -66
- package/src/task/executor.ts +5 -9
- package/src/tools/browser/launch.ts +22 -0
- package/src/tools/browser/registry.ts +25 -244
- package/src/tools/browser/render.ts +1 -1
- package/src/tools/browser/tab-protocol.ts +101 -0
- package/src/tools/browser/tab-supervisor.ts +429 -0
- package/src/tools/browser/tab-worker-entry.ts +21 -0
- package/src/tools/browser/tab-worker.ts +1006 -0
- package/src/tools/browser.ts +12 -29
- package/src/tools/checkpoint.ts +2 -2
- package/src/tools/{python.ts → eval.ts} +324 -315
- package/src/tools/exit-plan-mode.ts +1 -1
- package/src/tools/index.ts +62 -100
- package/src/tools/read.ts +0 -6
- package/src/tools/recipe/runners/pkg.ts +34 -32
- package/src/tools/renderers.ts +2 -2
- package/src/tools/resolve.ts +7 -2
- package/src/tools/todo-write.ts +0 -1
- package/src/tools/tool-timeouts.ts +2 -2
- package/src/utils/markit.ts +15 -7
- package/src/utils/tools-manager.ts +5 -5
- package/src/web/search/index.ts +5 -5
- package/src/web/search/provider.ts +121 -39
- package/src/web/search/providers/gemini.ts +2 -2
- package/src/web/search/render.ts +2 -2
- package/src/ipy/modules.ts +0 -144
- package/src/prompts/tools/python.md +0 -57
- package/src/tools/browser/vm.ts +0 -792
- /package/src/{ipy → eval/py}/cancellation.ts +0 -0
- /package/src/{ipy → eval/py}/prelude.ts +0 -0
- /package/src/{ipy → eval/py}/runtime.ts +0 -0
|
@@ -1,39 +1,121 @@
|
|
|
1
|
-
|
|
1
|
+
// Lazy registry of web search providers.
|
|
2
|
+
//
|
|
3
|
+
// Each provider is loaded on first use; importing this module loads zero
|
|
4
|
+
// provider implementations. Provider modules are heavy (each pulls in
|
|
5
|
+
// fetch/parse/format helpers) and only one — at most — is needed per session,
|
|
6
|
+
// so eager construction was wasted work at startup.
|
|
7
|
+
//
|
|
8
|
+
// The `label`/`id` metadata is kept inline so callers needing a display name
|
|
9
|
+
// (error formatting, UI listings) do not force a load.
|
|
10
|
+
|
|
2
11
|
import type { SearchProvider } from "./providers/base";
|
|
3
|
-
import { BraveProvider } from "./providers/brave";
|
|
4
|
-
import { CodexProvider } from "./providers/codex";
|
|
5
|
-
import { ExaProvider } from "./providers/exa";
|
|
6
|
-
import { GeminiProvider } from "./providers/gemini";
|
|
7
|
-
import { JinaProvider } from "./providers/jina";
|
|
8
|
-
import { KagiProvider } from "./providers/kagi";
|
|
9
|
-
import { KimiProvider } from "./providers/kimi";
|
|
10
|
-
import { ParallelProvider } from "./providers/parallel";
|
|
11
|
-
import { PerplexityProvider } from "./providers/perplexity";
|
|
12
|
-
import { SearXNGProvider } from "./providers/searxng";
|
|
13
|
-
import { SyntheticProvider } from "./providers/synthetic";
|
|
14
|
-
import { TavilyProvider } from "./providers/tavily";
|
|
15
|
-
import { ZaiProvider } from "./providers/zai";
|
|
16
12
|
import type { SearchProviderId } from "./types";
|
|
17
13
|
|
|
18
14
|
export type { SearchParams } from "./providers/base";
|
|
19
15
|
export { SearchProvider } from "./providers/base";
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
interface ProviderMeta {
|
|
18
|
+
id: SearchProviderId;
|
|
19
|
+
label: string;
|
|
20
|
+
load: () => Promise<SearchProvider>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Lazy factories. Each `load()` dynamic-imports its provider module on first call. */
|
|
24
|
+
const PROVIDER_META: Record<SearchProviderId, ProviderMeta> = {
|
|
25
|
+
exa: {
|
|
26
|
+
id: "exa",
|
|
27
|
+
label: "Exa",
|
|
28
|
+
load: async () => new (await import("./providers/exa")).ExaProvider(),
|
|
29
|
+
},
|
|
30
|
+
brave: {
|
|
31
|
+
id: "brave",
|
|
32
|
+
label: "Brave",
|
|
33
|
+
load: async () => new (await import("./providers/brave")).BraveProvider(),
|
|
34
|
+
},
|
|
35
|
+
jina: {
|
|
36
|
+
id: "jina",
|
|
37
|
+
label: "Jina",
|
|
38
|
+
load: async () => new (await import("./providers/jina")).JinaProvider(),
|
|
39
|
+
},
|
|
40
|
+
perplexity: {
|
|
41
|
+
id: "perplexity",
|
|
42
|
+
label: "Perplexity",
|
|
43
|
+
load: async () => new (await import("./providers/perplexity")).PerplexityProvider(),
|
|
44
|
+
},
|
|
45
|
+
kimi: {
|
|
46
|
+
id: "kimi",
|
|
47
|
+
label: "Kimi",
|
|
48
|
+
load: async () => new (await import("./providers/kimi")).KimiProvider(),
|
|
49
|
+
},
|
|
50
|
+
zai: {
|
|
51
|
+
id: "zai",
|
|
52
|
+
label: "Z.AI",
|
|
53
|
+
load: async () => new (await import("./providers/zai")).ZaiProvider(),
|
|
54
|
+
},
|
|
55
|
+
anthropic: {
|
|
56
|
+
id: "anthropic",
|
|
57
|
+
label: "Anthropic",
|
|
58
|
+
load: async () => new (await import("./providers/anthropic")).AnthropicProvider(),
|
|
59
|
+
},
|
|
60
|
+
gemini: {
|
|
61
|
+
id: "gemini",
|
|
62
|
+
label: "Gemini",
|
|
63
|
+
load: async () => new (await import("./providers/gemini")).GeminiProvider(),
|
|
64
|
+
},
|
|
65
|
+
codex: {
|
|
66
|
+
id: "codex",
|
|
67
|
+
label: "Codex",
|
|
68
|
+
load: async () => new (await import("./providers/codex")).CodexProvider(),
|
|
69
|
+
},
|
|
70
|
+
tavily: {
|
|
71
|
+
id: "tavily",
|
|
72
|
+
label: "Tavily",
|
|
73
|
+
load: async () => new (await import("./providers/tavily")).TavilyProvider(),
|
|
74
|
+
},
|
|
75
|
+
parallel: {
|
|
76
|
+
id: "parallel",
|
|
77
|
+
label: "Parallel",
|
|
78
|
+
load: async () => new (await import("./providers/parallel")).ParallelProvider(),
|
|
79
|
+
},
|
|
80
|
+
kagi: {
|
|
81
|
+
id: "kagi",
|
|
82
|
+
label: "Kagi",
|
|
83
|
+
load: async () => new (await import("./providers/kagi")).KagiProvider(),
|
|
84
|
+
},
|
|
85
|
+
synthetic: {
|
|
86
|
+
id: "synthetic",
|
|
87
|
+
label: "Synthetic",
|
|
88
|
+
load: async () => new (await import("./providers/synthetic")).SyntheticProvider(),
|
|
89
|
+
},
|
|
90
|
+
searxng: {
|
|
91
|
+
id: "searxng",
|
|
92
|
+
label: "SearXNG",
|
|
93
|
+
load: async () => new (await import("./providers/searxng")).SearXNGProvider(),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const instanceCache = new Map<SearchProviderId, SearchProvider>();
|
|
98
|
+
|
|
99
|
+
/** Cheap, sync metadata accessor — never triggers a provider load. */
|
|
100
|
+
export function getSearchProviderLabel(id: SearchProviderId): string {
|
|
101
|
+
return PROVIDER_META[id]?.label ?? id;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resolve and cache a provider instance. First call for a given id loads the
|
|
106
|
+
* underlying module; subsequent calls return the cached singleton.
|
|
107
|
+
*/
|
|
108
|
+
export async function getSearchProvider(id: SearchProviderId): Promise<SearchProvider> {
|
|
109
|
+
const cached = instanceCache.get(id);
|
|
110
|
+
if (cached) return cached;
|
|
111
|
+
const meta = PROVIDER_META[id];
|
|
112
|
+
if (!meta) {
|
|
113
|
+
throw new Error(`Unknown search provider: ${id}`);
|
|
114
|
+
}
|
|
115
|
+
const provider = await meta.load();
|
|
116
|
+
instanceCache.set(id, provider);
|
|
117
|
+
return provider;
|
|
118
|
+
}
|
|
37
119
|
|
|
38
120
|
export const SEARCH_PROVIDER_ORDER: SearchProviderId[] = [
|
|
39
121
|
"tavily",
|
|
@@ -52,10 +134,6 @@ export const SEARCH_PROVIDER_ORDER: SearchProviderId[] = [
|
|
|
52
134
|
"searxng",
|
|
53
135
|
];
|
|
54
136
|
|
|
55
|
-
export function getSearchProvider(provider: SearchProviderId): SearchProvider {
|
|
56
|
-
return SEARCH_PROVIDERS[provider];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
137
|
/** Preferred provider set via settings (default: auto) */
|
|
60
138
|
let preferredProvId: SearchProviderId | "auto" = "auto";
|
|
61
139
|
|
|
@@ -64,22 +142,26 @@ export function setPreferredSearchProvider(provider: SearchProviderId | "auto"):
|
|
|
64
142
|
preferredProvId = provider;
|
|
65
143
|
}
|
|
66
144
|
|
|
67
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* Determine which providers are configured and currently available.
|
|
147
|
+
* Each candidate is loaded (and its `isAvailable()` called) only as the chain
|
|
148
|
+
* is walked, so unconfigured providers never pay the load cost.
|
|
149
|
+
*/
|
|
68
150
|
export async function resolveProviderChain(
|
|
69
151
|
preferredProvider: SearchProviderId | "auto" = preferredProvId,
|
|
70
152
|
): Promise<SearchProvider[]> {
|
|
71
153
|
const providers: SearchProvider[] = [];
|
|
72
154
|
|
|
73
155
|
if (preferredProvider !== "auto") {
|
|
74
|
-
|
|
75
|
-
|
|
156
|
+
const provider = await getSearchProvider(preferredProvider);
|
|
157
|
+
if (await provider.isAvailable()) {
|
|
158
|
+
providers.push(provider);
|
|
76
159
|
}
|
|
77
160
|
}
|
|
78
161
|
|
|
79
162
|
for (const id of SEARCH_PROVIDER_ORDER) {
|
|
80
163
|
if (id === preferredProvider) continue;
|
|
81
|
-
|
|
82
|
-
const provider = getSearchProvider(id);
|
|
164
|
+
const provider = await getSearchProvider(id);
|
|
83
165
|
if (await provider.isAvailable()) {
|
|
84
166
|
providers.push(provider);
|
|
85
167
|
}
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
extractRetryDelay,
|
|
11
11
|
getAntigravityHeaders,
|
|
12
12
|
getGeminiCliHeaders,
|
|
13
|
-
refreshAntigravityToken,
|
|
14
|
-
refreshGoogleCloudToken,
|
|
15
13
|
} from "@oh-my-pi/pi-ai";
|
|
14
|
+
import { refreshAntigravityToken } from "@oh-my-pi/pi-ai/utils/oauth/google-antigravity";
|
|
15
|
+
import { refreshGoogleCloudToken } from "@oh-my-pi/pi-ai/utils/oauth/google-gemini-cli";
|
|
16
16
|
import { getAgentDbPath } from "@oh-my-pi/pi-utils";
|
|
17
17
|
import { AgentStorage } from "../../../session/agent-storage";
|
|
18
18
|
import type { SearchCitation, SearchResponse, SearchSource } from "../../../web/search/types";
|
package/src/web/search/render.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from "../../tools/render-utils";
|
|
23
23
|
import { renderStatusLine, renderTreeList } from "../../tui";
|
|
24
24
|
import { CachedOutputBlock } from "../../tui/output-block";
|
|
25
|
-
import {
|
|
25
|
+
import { getSearchProviderLabel } from "./provider";
|
|
26
26
|
import type { SearchResponse } from "./types";
|
|
27
27
|
|
|
28
28
|
const MAX_COLLAPSED_ANSWER_LINES = PREVIEW_LIMITS.COLLAPSED_LINES;
|
|
@@ -112,7 +112,7 @@ export function renderSearchResult(
|
|
|
112
112
|
: [];
|
|
113
113
|
const totalAnswerLines = answerLines.length;
|
|
114
114
|
|
|
115
|
-
const providerLabel = provider !== "none" ?
|
|
115
|
+
const providerLabel = provider !== "none" ? getSearchProviderLabel(provider) : "None";
|
|
116
116
|
const queryPreview = args?.query
|
|
117
117
|
? truncateToWidth(args.query, 80)
|
|
118
118
|
: searchQueries[0]
|
package/src/ipy/modules.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs/promises";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { getAgentModulesDir, getProjectDir, getProjectModulesDir } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import { getExecutionCancellationError } from "./cancellation";
|
|
5
|
-
|
|
6
|
-
export type PythonModuleSource = "user" | "project";
|
|
7
|
-
|
|
8
|
-
export interface PythonModuleEntry {
|
|
9
|
-
path: string;
|
|
10
|
-
content: string;
|
|
11
|
-
source: PythonModuleSource;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface PythonModuleExecuteResult {
|
|
15
|
-
status: "ok" | "error";
|
|
16
|
-
cancelled: boolean;
|
|
17
|
-
timedOut?: boolean;
|
|
18
|
-
error?: { name: string; value: string; traceback: string[] };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface PythonModuleExecutor {
|
|
22
|
-
execute: (
|
|
23
|
-
code: string,
|
|
24
|
-
options?: { signal?: AbortSignal; timeoutMs?: number; silent?: boolean; storeHistory?: boolean },
|
|
25
|
-
) => Promise<PythonModuleExecuteResult>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface DiscoverPythonModulesOptions {
|
|
29
|
-
/** Working directory for project-level modules. Default: getProjectDir() */
|
|
30
|
-
cwd?: string;
|
|
31
|
-
/** Agent directory for user-level modules. Default: from getAgentDir() */
|
|
32
|
-
agentDir?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface LoadPythonModulesOptions extends DiscoverPythonModulesOptions {
|
|
36
|
-
signal?: AbortSignal;
|
|
37
|
-
timeoutMs?: number;
|
|
38
|
-
deadlineMs?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface ModuleCandidate {
|
|
42
|
-
name: string;
|
|
43
|
-
path: string;
|
|
44
|
-
source: PythonModuleSource;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function listModuleCandidates(dir: string, source: PythonModuleSource): Promise<ModuleCandidate[]> {
|
|
48
|
-
try {
|
|
49
|
-
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
50
|
-
return entries
|
|
51
|
-
.filter(entry => entry.isFile() && entry.name.endsWith(".py"))
|
|
52
|
-
.map(entry => ({
|
|
53
|
-
name: entry.name,
|
|
54
|
-
path: path.resolve(dir, entry.name),
|
|
55
|
-
source,
|
|
56
|
-
}));
|
|
57
|
-
} catch {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function readModuleContent(candidate: ModuleCandidate): Promise<PythonModuleEntry> {
|
|
63
|
-
try {
|
|
64
|
-
const content = await Bun.file(candidate.path).text();
|
|
65
|
-
return { path: candidate.path, content, source: candidate.source };
|
|
66
|
-
} catch (err) {
|
|
67
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
-
throw new Error(`Failed to read Python module ${candidate.path}: ${message}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function createTimeoutError(message: string): Error {
|
|
73
|
-
const error = new Error(message);
|
|
74
|
-
error.name = "TimeoutError";
|
|
75
|
-
return error;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function requireModuleExecutionTimeoutMs(options: LoadPythonModulesOptions): number | undefined {
|
|
79
|
-
if (options.deadlineMs === undefined) {
|
|
80
|
-
return options.timeoutMs;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const remainingMs = options.deadlineMs - Date.now();
|
|
84
|
-
if (remainingMs <= 0) {
|
|
85
|
-
throw createTimeoutError("Python module loading timed out");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return remainingMs;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Discover Python prelude extension modules from user and project directories.
|
|
93
|
-
*/
|
|
94
|
-
export async function discoverPythonModules(options: DiscoverPythonModulesOptions = {}): Promise<PythonModuleEntry[]> {
|
|
95
|
-
const cwd = options.cwd ?? getProjectDir();
|
|
96
|
-
|
|
97
|
-
const userDir = getAgentModulesDir(options.agentDir);
|
|
98
|
-
const projectDir = getProjectModulesDir(cwd);
|
|
99
|
-
|
|
100
|
-
const userCandidates = await listModuleCandidates(userDir, "user");
|
|
101
|
-
const projectCandidates = await listModuleCandidates(projectDir, "project");
|
|
102
|
-
|
|
103
|
-
const byName = new Map<string, ModuleCandidate>();
|
|
104
|
-
for (const candidate of userCandidates) {
|
|
105
|
-
if (!byName.has(candidate.name)) {
|
|
106
|
-
byName.set(candidate.name, candidate);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
for (const candidate of projectCandidates) {
|
|
110
|
-
const existing = byName.get(candidate.name);
|
|
111
|
-
if (!existing || existing.source === "user") {
|
|
112
|
-
byName.set(candidate.name, candidate);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const sorted = Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
117
|
-
return Promise.all(sorted.map(candidate => readModuleContent(candidate)));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Load Python prelude extension modules into an active kernel.
|
|
122
|
-
*/
|
|
123
|
-
export async function loadPythonModules(
|
|
124
|
-
executor: PythonModuleExecutor,
|
|
125
|
-
options: LoadPythonModulesOptions = {},
|
|
126
|
-
): Promise<PythonModuleEntry[]> {
|
|
127
|
-
const modules = await discoverPythonModules(options);
|
|
128
|
-
for (const module of modules) {
|
|
129
|
-
const result = await executor.execute(module.content, {
|
|
130
|
-
signal: options.signal,
|
|
131
|
-
timeoutMs: requireModuleExecutionTimeoutMs(options),
|
|
132
|
-
silent: true,
|
|
133
|
-
storeHistory: false,
|
|
134
|
-
});
|
|
135
|
-
if (result.cancelled) {
|
|
136
|
-
throw getExecutionCancellationError(result, options.signal, `Failed to load Python module ${module.path}`);
|
|
137
|
-
}
|
|
138
|
-
if (result.status === "error") {
|
|
139
|
-
const details = result.error ? `${result.error.name}: ${result.error.value}` : "unknown error";
|
|
140
|
-
throw new Error(`Failed to load Python module ${module.path}: ${details}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return modules;
|
|
144
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
Runs Python cells sequentially in persistent IPython kernel.
|
|
2
|
-
|
|
3
|
-
<instruction>
|
|
4
|
-
Kernel persists across calls and cells; **imports, variables, and functions survive — use this.**
|
|
5
|
-
|
|
6
|
-
**Work incrementally:** one logical step per cell (imports, define, test, use). Pass multiple small cells in one call. Define small reusable functions you can debug individually. You **MUST** put workflow explanations in the assistant message or cell title — never inside cell code.
|
|
7
|
-
|
|
8
|
-
**On failure:** errors identify the failing cell (e.g., "Cell 3 failed"). Resubmit only the fixed cell (or fixed cell + remaining cells).
|
|
9
|
-
</instruction>
|
|
10
|
-
|
|
11
|
-
{{#if categories.length}}
|
|
12
|
-
<prelude>
|
|
13
|
-
All helpers auto-print results and return values for chaining.
|
|
14
|
-
|
|
15
|
-
{{#each categories}}
|
|
16
|
-
### {{name}}
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
{{#each functions}}
|
|
20
|
-
{{name}}{{signature}}
|
|
21
|
-
{{docstring}}
|
|
22
|
-
{{/each}}
|
|
23
|
-
```
|
|
24
|
-
{{/each}}
|
|
25
|
-
</prelude>
|
|
26
|
-
{{/if}}
|
|
27
|
-
|
|
28
|
-
<output>
|
|
29
|
-
User sees output like Jupyter notebook; rich displays render fully:
|
|
30
|
-
- `display(JSON(data))` → interactive JSON tree
|
|
31
|
-
- `display(HTML(…))` → rendered HTML
|
|
32
|
-
- `display(Markdown(…))` → formatted markdown
|
|
33
|
-
- `plt.show()` → inline figures
|
|
34
|
-
|
|
35
|
-
**You will see object repr** (e.g., `<IPython.core.display.JSON object>`). Trust `display()`; you **MUST NOT** assume the user sees only the repr.
|
|
36
|
-
</output>
|
|
37
|
-
|
|
38
|
-
<caution>
|
|
39
|
-
- Per-call mode uses a fresh kernel each call
|
|
40
|
-
- You **MUST** use `reset: true` to clear state when session mode is active
|
|
41
|
-
</caution>
|
|
42
|
-
|
|
43
|
-
<critical>
|
|
44
|
-
- You **MUST** use `run()` for shell commands; you **MUST NOT** use raw `subprocess`
|
|
45
|
-
</critical>
|
|
46
|
-
|
|
47
|
-
<examples>
|
|
48
|
-
# Multiple small cells
|
|
49
|
-
```python
|
|
50
|
-
cells: [
|
|
51
|
-
{"title": "imports", "code": "import json\nfrom pathlib import Path"},
|
|
52
|
-
{"title": "parse helper", "code": "def parse_config(path):\n return json.loads(Path(path).read_text())"},
|
|
53
|
-
{"title": "test helper", "code": "parse_config('config.json')"},
|
|
54
|
-
{"title": "use helper", "code": "configs = [parse_config(p) for p in Path('.').glob('*.json')]"}
|
|
55
|
-
]
|
|
56
|
-
```
|
|
57
|
-
</examples>
|