@seqyuan/pi-kernel-plot 0.2.1
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/dist/extensions/kernel-plot.d.ts +2 -0
- package/dist/extensions/kernel-plot.js +1 -0
- package/dist/src/core-adapter.d.ts +2 -0
- package/dist/src/core-adapter.js +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +0 -0
- package/dist/src/prompt.d.ts +2 -0
- package/dist/src/prompt.js +1 -0
- package/dist/src/render.d.ts +8 -0
- package/dist/src/render.js +3 -0
- package/dist/src/tools.d.ts +210 -0
- package/dist/src/tools.js +7 -0
- package/dist/src/types.d.ts +107 -0
- package/dist/src/types.js +0 -0
- package/package.json +70 -0
- package/skills/kernel-plot/SKILL.md +93 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createKernelPlotTools as n}from"../src/tools.js";function a(o){const e=n();o.registerTool(e.run),o.registerTool(e.stop),o.registerTool(e.artifacts),o.registerTool(e.configure),o.on("session_shutdown",async(r,s)=>{await e.disposeSession(s).catch(t=>{s.ui.notify(`kernel plot cleanup failed: ${t instanceof Error?t.message:String(t)}`,"warning")})})}export{a as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let r;async function o(){try{return await import("@seqyuan/kernel-lite-core")}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`Cannot load @seqyuan/kernel-lite-core. Install or build packages/kernel-lite-core before using kernel_plot tools. Original error: ${t}`)}}async function n(){const e=await o();if(typeof e.createKernelLiteCore=="function")return await e.createKernelLiteCore();if(typeof e.run=="function"&&typeof e.listArtifacts=="function")return{run:e.run,stopSession:async t=>{if(typeof e.stopSession=="function"){await e.stopSession(t);return}if(typeof e.stop=="function"){await e.stop(t);return}throw new Error("@seqyuan/kernel-lite-core does not export stopSession or stop")},listArtifacts:e.listArtifacts,dispose:async()=>{typeof e.dispose=="function"&&await e.dispose()}};throw new Error("@seqyuan/kernel-lite-core must export createKernelLiteCore(), or top-level run(), listArtifacts(), and stop()/stopSession() functions")}async function s(){return r??=n(),await r}export{s as getKernelLiteCore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e="Run short R/Python plotting code in a warm kernel and save artifacts to disk.",t=["Use kernel_plot_run for iterative R/Python plotting when data should stay in memory across turns.",'Use kernel_plot_run with runtime: "worker" for one-shot reproducible scripts.',"In kernel_plot_run code, save every output under WARMPLOT_OUTPUT_DIR.","Do not rely on notebook display; explicitly save PNG, SVG, PDF, HTML, CSV, TSV, or JSON files.","After a failed kernel_plot_run, inspect stderr and rerun only the minimal corrected code.","Use kernel_plot_stop when the user is done with a large object or asks to free memory."];export{t as kernelPlotPromptGuidelines,e as kernelPlotRunPromptSnippet};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{Text as e}from"@earendil-works/pi-tui";function a(t){return!Number.isFinite(t)||t<0?"unknown":t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/1024/1024).toFixed(1)} MB`}function i(t){return`- ${t.path} (${t.kind}, ${a(t.size)})`}function s(t){const n=t.details;if(!n||n.schema!=="kernel-plot.result.v1"){const r=t.content.find(o=>o.type==="text")?.text??"";return new e(r,0,0)}if(n.kind==="run"){const r=[`kernel_plot_run ${n.run.status}`,`run_id: ${n.run.runId}`,`runtime: ${n.run.runtime}`,`artifacts: ${n.artifacts.length}`,...n.artifacts.slice(0,8).map(i)];return new e(r.join(`
|
|
2
|
+
`),0,0)}if(n.kind==="stop")return new e(`kernel_plot_stop stopped ${n.stopped.language??"all languages"}`,0,0);const u=[`kernel_plot_artifacts ${n.artifacts.length}`,...n.artifacts.slice(0,12).map(i)];return new e(u.join(`
|
|
3
|
+
`),0,0)}export{s as renderKernelPlotResult};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { type ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { renderKernelPlotResult } from "./render.js";
|
|
3
|
+
import type { KernelLanguage, KernelPlotArtifactsDetails, KernelPlotRunDetails, KernelPlotStopDetails, KernelPlotToolDetails, ToolContent } from "./types.js";
|
|
4
|
+
interface RunParams {
|
|
5
|
+
language: KernelLanguage;
|
|
6
|
+
code: string;
|
|
7
|
+
runtime?: "kernel-lite" | "worker";
|
|
8
|
+
title?: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
interface StopParams {
|
|
12
|
+
language?: KernelLanguage;
|
|
13
|
+
}
|
|
14
|
+
interface ArtifactsParams {
|
|
15
|
+
limit?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function createKernelPlotTools(): {
|
|
18
|
+
run: {
|
|
19
|
+
name: string;
|
|
20
|
+
label: string;
|
|
21
|
+
description: string;
|
|
22
|
+
promptSnippet: string;
|
|
23
|
+
promptGuidelines: string[];
|
|
24
|
+
executionMode: "sequential";
|
|
25
|
+
parameters: unknown;
|
|
26
|
+
execute(_toolCallId: string, params: RunParams, signal: AbortSignal, _onUpdate: unknown, ctx: ExtensionContext): Promise<{
|
|
27
|
+
content: ToolContent;
|
|
28
|
+
details: KernelPlotRunDetails;
|
|
29
|
+
}>;
|
|
30
|
+
renderResult: typeof renderKernelPlotResult;
|
|
31
|
+
};
|
|
32
|
+
stop: {
|
|
33
|
+
name: string;
|
|
34
|
+
label: string;
|
|
35
|
+
description: string;
|
|
36
|
+
promptSnippet: string;
|
|
37
|
+
promptGuidelines: string[];
|
|
38
|
+
executionMode: "sequential";
|
|
39
|
+
parameters: unknown;
|
|
40
|
+
execute(_toolCallId: string, params: StopParams, _signal: AbortSignal, _onUpdate: unknown, ctx: ExtensionContext): Promise<{
|
|
41
|
+
content: {
|
|
42
|
+
type: string;
|
|
43
|
+
text: string;
|
|
44
|
+
}[];
|
|
45
|
+
details: KernelPlotStopDetails;
|
|
46
|
+
}>;
|
|
47
|
+
renderResult: typeof renderKernelPlotResult;
|
|
48
|
+
};
|
|
49
|
+
artifacts: {
|
|
50
|
+
name: string;
|
|
51
|
+
label: string;
|
|
52
|
+
description: string;
|
|
53
|
+
promptSnippet: string;
|
|
54
|
+
promptGuidelines: string[];
|
|
55
|
+
parameters: unknown;
|
|
56
|
+
execute(_toolCallId: string, params: ArtifactsParams, _signal: AbortSignal, _onUpdate: unknown, ctx: ExtensionContext): Promise<{
|
|
57
|
+
content: {
|
|
58
|
+
type: string;
|
|
59
|
+
text: string;
|
|
60
|
+
}[];
|
|
61
|
+
details: KernelPlotArtifactsDetails;
|
|
62
|
+
}>;
|
|
63
|
+
renderResult: typeof renderKernelPlotResult;
|
|
64
|
+
};
|
|
65
|
+
configure: {
|
|
66
|
+
name: string;
|
|
67
|
+
label: string;
|
|
68
|
+
description: string;
|
|
69
|
+
promptSnippet: string;
|
|
70
|
+
promptGuidelines: string[];
|
|
71
|
+
parameters: unknown;
|
|
72
|
+
execute(_toolCallId: string, params: {
|
|
73
|
+
action: "list" | "select" | "add" | "edit" | "delete" | "scan";
|
|
74
|
+
language?: KernelLanguage;
|
|
75
|
+
kernelId?: string;
|
|
76
|
+
config?: {
|
|
77
|
+
command: string;
|
|
78
|
+
args?: string;
|
|
79
|
+
displayName?: string;
|
|
80
|
+
env?: string;
|
|
81
|
+
};
|
|
82
|
+
}, _signal: AbortSignal, _onUpdate: unknown, ctx: ExtensionContext): Promise<{
|
|
83
|
+
content: {
|
|
84
|
+
type: string;
|
|
85
|
+
text: string;
|
|
86
|
+
}[];
|
|
87
|
+
details: {
|
|
88
|
+
schema: string;
|
|
89
|
+
kind: string;
|
|
90
|
+
action: string;
|
|
91
|
+
kernels: {
|
|
92
|
+
id: string;
|
|
93
|
+
language: import("@seqyuan/kernel-lite-core").KernelLanguage;
|
|
94
|
+
displayName: string;
|
|
95
|
+
command: string;
|
|
96
|
+
isDefault: boolean;
|
|
97
|
+
isSelected: boolean;
|
|
98
|
+
}[];
|
|
99
|
+
projectConfig: string;
|
|
100
|
+
globalConfig: string;
|
|
101
|
+
selectedKernel?: undefined;
|
|
102
|
+
kernel?: undefined;
|
|
103
|
+
deletedKernelId?: undefined;
|
|
104
|
+
newKernels?: undefined;
|
|
105
|
+
errors?: undefined;
|
|
106
|
+
scanTime?: undefined;
|
|
107
|
+
};
|
|
108
|
+
} | {
|
|
109
|
+
content: {
|
|
110
|
+
type: string;
|
|
111
|
+
text: string;
|
|
112
|
+
}[];
|
|
113
|
+
details: {
|
|
114
|
+
schema: string;
|
|
115
|
+
kind: string;
|
|
116
|
+
action: string;
|
|
117
|
+
selectedKernel: {
|
|
118
|
+
language: import("@seqyuan/kernel-lite-core").KernelLanguage;
|
|
119
|
+
command: string;
|
|
120
|
+
args: string[];
|
|
121
|
+
displayName: string;
|
|
122
|
+
env: Record<string, string>;
|
|
123
|
+
id: string;
|
|
124
|
+
};
|
|
125
|
+
kernels?: undefined;
|
|
126
|
+
projectConfig?: undefined;
|
|
127
|
+
globalConfig?: undefined;
|
|
128
|
+
kernel?: undefined;
|
|
129
|
+
deletedKernelId?: undefined;
|
|
130
|
+
newKernels?: undefined;
|
|
131
|
+
errors?: undefined;
|
|
132
|
+
scanTime?: undefined;
|
|
133
|
+
};
|
|
134
|
+
} | {
|
|
135
|
+
content: {
|
|
136
|
+
type: string;
|
|
137
|
+
text: string;
|
|
138
|
+
}[];
|
|
139
|
+
details: {
|
|
140
|
+
schema: string;
|
|
141
|
+
kind: string;
|
|
142
|
+
action: string;
|
|
143
|
+
kernel: {
|
|
144
|
+
language: KernelLanguage;
|
|
145
|
+
command: string;
|
|
146
|
+
args: any;
|
|
147
|
+
displayName: string;
|
|
148
|
+
env: any;
|
|
149
|
+
id: string;
|
|
150
|
+
};
|
|
151
|
+
kernels?: undefined;
|
|
152
|
+
projectConfig?: undefined;
|
|
153
|
+
globalConfig?: undefined;
|
|
154
|
+
selectedKernel?: undefined;
|
|
155
|
+
deletedKernelId?: undefined;
|
|
156
|
+
newKernels?: undefined;
|
|
157
|
+
errors?: undefined;
|
|
158
|
+
scanTime?: undefined;
|
|
159
|
+
};
|
|
160
|
+
} | {
|
|
161
|
+
content: {
|
|
162
|
+
type: string;
|
|
163
|
+
text: string;
|
|
164
|
+
}[];
|
|
165
|
+
details: {
|
|
166
|
+
schema: string;
|
|
167
|
+
kind: string;
|
|
168
|
+
action: string;
|
|
169
|
+
deletedKernelId: string;
|
|
170
|
+
kernels?: undefined;
|
|
171
|
+
projectConfig?: undefined;
|
|
172
|
+
globalConfig?: undefined;
|
|
173
|
+
selectedKernel?: undefined;
|
|
174
|
+
kernel?: undefined;
|
|
175
|
+
newKernels?: undefined;
|
|
176
|
+
errors?: undefined;
|
|
177
|
+
scanTime?: undefined;
|
|
178
|
+
};
|
|
179
|
+
} | {
|
|
180
|
+
content: {
|
|
181
|
+
type: string;
|
|
182
|
+
text: string;
|
|
183
|
+
}[];
|
|
184
|
+
details: {
|
|
185
|
+
schema: string;
|
|
186
|
+
kind: string;
|
|
187
|
+
action: string;
|
|
188
|
+
newKernels: {
|
|
189
|
+
language: import("@seqyuan/kernel-lite-core").KernelLanguage;
|
|
190
|
+
command: string;
|
|
191
|
+
args: string[];
|
|
192
|
+
displayName: string;
|
|
193
|
+
env: Record<string, string>;
|
|
194
|
+
id: string;
|
|
195
|
+
}[];
|
|
196
|
+
errors: string[];
|
|
197
|
+
scanTime: string;
|
|
198
|
+
kernels?: undefined;
|
|
199
|
+
projectConfig?: undefined;
|
|
200
|
+
globalConfig?: undefined;
|
|
201
|
+
selectedKernel?: undefined;
|
|
202
|
+
kernel?: undefined;
|
|
203
|
+
deletedKernelId?: undefined;
|
|
204
|
+
};
|
|
205
|
+
}>;
|
|
206
|
+
renderResult: typeof renderKernelPlotResult;
|
|
207
|
+
};
|
|
208
|
+
disposeSession(ctx: ExtensionContext): Promise<void>;
|
|
209
|
+
};
|
|
210
|
+
export type { KernelLanguage, KernelPlotToolDetails };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{StringEnum as I,Type as n}from"@earendil-works/pi-ai";import{defineTool as _}from"@earendil-works/pi-coding-agent";import{readFile as T,stat as A}from"node:fs/promises";import{getKernelLiteCore as $}from"./core-adapter.js";import{kernelPlotPromptGuidelines as v,kernelPlotRunPromptSnippet as U}from"./prompt.js";import{renderKernelPlotResult as S}from"./render.js";const L=4e3,M=2*1024*1024,K=I(["python","r"],{description:"Runtime language for the plotting code."}),D=I(["kernel-lite","worker"],{description:"kernel-lite keeps language state warm; worker runs a one-shot script."});function P(t,l=L){const a=t??"";return a.length<=l?a:`${a.slice(0,l)}
|
|
2
|
+
[truncated ${a.length-l} chars]`}function b(t){return t.sessionManager.getSessionId()}function N(t){return t.length===0?["artifacts: none"]:["artifacts:",...t.map(l=>`- ${l.path}`)]}function G(t){const l=[`kernel_plot_run ${t.status}`,`run_id: ${t.runId}`,`runtime: ${t.runtime}`,`script: ${t.scriptPath}`,`stdout: ${t.stdoutPath}`,`stderr: ${t.stderrPath}`],a=P(t.stdout,1200).trim(),k=P(t.stderr,1200).trim();return a&&l.push("stdout:",a),k&&l.push("stderr:",k),t.error&&l.push(`error: ${t.error}`),l.push(...N(t.artifacts)),l.join(`
|
|
3
|
+
`)}async function q(t){const l=t.find(a=>a.kind==="image"&&(a.mimeType==="image/png"||a.mimeType==="image/jpeg"||a.mimeType==="image/webp"));if(l)try{const a=await A(l.path);return!a.isFile()||a.size>M?void 0:{type:"image",data:(await T(l.path)).toString("base64"),mimeType:l.mimeType}}catch{return}}function J(t){return{schema:"kernel-plot.result.v1",kind:"run",run:{runId:t.runId,status:t.status,language:t.language,runtime:t.runtime,title:t.title,stdoutPath:t.stdoutPath,stderrPath:t.stderrPath,scriptPath:t.scriptPath,outputDir:t.outputDir,stdoutPreview:P(t.stdout),stderrPreview:P(t.stderr),error:t.error},artifacts:t.artifacts,nextAction:t.status==="succeeded"?"Inspect the artifact paths or continue iterating with kernel_plot_run.":"Inspect stderr and rerun only the minimal corrected code."}}function F(t){return["kernel_plot_artifacts",...N(t)].join(`
|
|
4
|
+
`)}function Y(){const t=_({name:"kernel_plot_run",label:"Kernel Plot Run",description:"Execute short R or Python plotting code in a warm kernel-lite runtime or one-shot worker and archive generated artifacts.",promptSnippet:U,promptGuidelines:v,executionMode:"sequential",parameters:n.Object({language:K,code:n.String({description:"R or Python code. Save files under WARMPLOT_OUTPUT_DIR or PI_KERNEL_PLOT_OUTPUT_DIR."}),runtime:n.Optional(D),title:n.Optional(n.String({description:"Short title for the run."})),timeoutMs:n.Optional(n.Number({description:"Execution timeout in milliseconds."}))}),async execute(h,e,w,O,c){const d=await(await $()).run({cwd:c.cwd,ownerId:b(c),language:e.language,runtime:e.runtime,code:e.code,title:e.title,timeoutMs:e.timeoutMs,signal:w}),g=[{type:"text",text:G(d)}],m=await q(d.artifacts);return m&&g.push(m),{content:g,details:J(d)}},renderResult:S}),l=_({name:"kernel_plot_stop",label:"Kernel Plot Stop",description:"Stop the current Pi session's warm plotting kernel for one language or all languages.",promptSnippet:"Stop warm R/Python plotting kernels and release their memory.",promptGuidelines:v,executionMode:"sequential",parameters:n.Object({language:n.Optional(K)}),async execute(h,e,w,O,c){const f=await $(),d=b(c);await f.stopSession({ownerId:d,language:e.language});const g={schema:"kernel-plot.result.v1",kind:"stop",stopped:{ownerId:d,language:e.language},artifacts:[],nextAction:"Use kernel_plot_run to start a fresh warm kernel when needed."};return{content:[{type:"text",text:`kernel_plot_stop stopped ${e.language??"all languages"}`}],details:g}},renderResult:S}),a=_({name:"kernel_plot_artifacts",label:"Kernel Plot Artifacts",description:"List recent archived plotting artifacts for the current Pi session.",promptSnippet:"List recent R/Python plotting artifact paths for this session.",promptGuidelines:v,parameters:n.Object({limit:n.Optional(n.Number({description:"Maximum number of recent artifacts to list."}))}),async execute(h,e,w,O,c){const f=await $(),d=b(c),g=await f.listArtifacts({cwd:c.cwd,ownerId:d,limit:e.limit}),m={schema:"kernel-plot.result.v1",kind:"artifacts",ownerId:d,artifacts:g,nextAction:"Open or inspect the listed artifact paths, or continue plotting with kernel_plot_run."};return{content:[{type:"text",text:F(g)}],details:m}},renderResult:S}),k=_({name:"kernel_plot_configure",label:"Kernel Plot Configure",description:"Configure Python/R kernel environments for plotting. Supports listing, selecting, adding, editing, deleting kernels, and scanning environments.",promptSnippet:"Configure which Python/R interpreter to use for plotting.",promptGuidelines:v,parameters:n.Object({action:I(["list","select","add","edit","delete","scan"],{description:"Action to perform: list kernels, select for project, add new, edit existing, delete, or scan environments."}),language:n.Optional(I(["python","r"],{description:"Filter by language (for list/scan) or specify language (for select)."})),kernelId:n.Optional(n.String({description:"Kernel ID for select/edit/delete actions."})),config:n.Optional(n.Object({command:n.String({description:"Path to interpreter executable."}),args:n.Optional(n.String({description:"Command-line arguments (JSON array string)."})),displayName:n.Optional(n.String({description:"Human-readable name."})),env:n.Optional(n.String({description:"Environment variables (JSON object string)."}))}))}),async execute(h,e,w,O,c){const{loadGlobalConfig:f,saveGlobalConfig:d,loadProjectConfig:g,saveProjectConfig:m,scanAllEnvironments:C,scanPythonEnvironments:E,scanREnvironments:R}=await import("@seqyuan/kernel-lite-core"),r=await f(),x=await g(c.cwd);switch(e.action){case"list":{const o=Object.entries(r.kernels).filter(([u,i])=>!e.language||i.language===e.language).map(([u,i])=>({id:u,language:i.language,displayName:i.displayName,command:i.command,isDefault:r.defaultKernel[i.language]===u,isSelected:x?.selectedKernels[i.language]===u}));return{content:[{type:"text",text:["Available kernels:",...o.map(u=>`- ${u.id}: ${u.displayName} (${u.command})${u.isDefault?" [default]":""}${u.isSelected?" [selected]":""}`)].join(`
|
|
5
|
+
`)}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"list",kernels:o,projectConfig:`${c.cwd}/.pi/warmplot.json`,globalConfig:"~/.config/warmplot.json"}}}case"select":{if(!e.language||!e.kernelId)throw new Error("select action requires language and kernelId");const o=r.kernels[e.kernelId];if(!o)throw new Error(`Kernel '${e.kernelId}' not found. Available: ${Object.keys(r.kernels).join(", ")}`);const s=x||{version:"1.0",selectedKernels:{}};return s.selectedKernels[e.language]=e.kernelId,await m(c.cwd,s),{content:[{type:"text",text:`Selected '${e.kernelId}' (${o.displayName}) for ${e.language} in this project.
|
|
6
|
+
Config saved to ${c.cwd}/.pi/warmplot.json`}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"select",selectedKernel:{id:e.kernelId,...o}}}}case"add":{if(!e.kernelId||!e.config?.command)throw new Error("add action requires kernelId and config.command");if(r.kernels[e.kernelId])throw new Error(`Kernel '${e.kernelId}' already exists. Use 'edit' action to modify it.`);const o=e.config.command.toLowerCase(),s=o.includes("python")?"python":o.includes("r")?"r":"python",u=e.config.args?JSON.parse(e.config.args):s==="python"?["-u"]:["--slave","--vanilla"],i=e.config.env?JSON.parse(e.config.env):{},p={language:s,command:e.config.command,args:u,displayName:e.config.displayName||`${s} (${e.kernelId})`,env:i};return r.kernels[e.kernelId]=p,await d(r),{content:[{type:"text",text:`Added kernel '${e.kernelId}': ${p.displayName} (${p.command})`}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"add",kernel:{id:e.kernelId,...p}}}}case"edit":{if(!e.kernelId||!e.config)throw new Error("edit action requires kernelId and config");const o=r.kernels[e.kernelId];if(!o)throw new Error(`Kernel '${e.kernelId}' not found. Available: ${Object.keys(r.kernels).join(", ")}`);const s={...o,...e.config.command&&{command:e.config.command},...e.config.args&&{args:JSON.parse(e.config.args)},...e.config.displayName&&{displayName:e.config.displayName},...e.config.env&&{env:{...o.env,...JSON.parse(e.config.env)}}};return r.kernels[e.kernelId]=s,await d(r),{content:[{type:"text",text:`Updated kernel '${e.kernelId}': ${s.displayName} (${s.command})`}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"edit",kernel:{id:e.kernelId,...s}}}}case"delete":{if(!e.kernelId)throw new Error("delete action requires kernelId");if(!r.kernels[e.kernelId])throw new Error(`Kernel '${e.kernelId}' not found`);if(e.kernelId==="default-python"||e.kernelId==="default-r")throw new Error("Cannot delete system default kernels");delete r.kernels[e.kernelId];for(const o of["python","r"])r.defaultKernel[o]===e.kernelId&&delete r.defaultKernel[o];return await d(r),{content:[{type:"text",text:`Deleted kernel '${e.kernelId}'`}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"delete",deletedKernelId:e.kernelId}}}case"scan":{const o=e.language?e.language==="python"?await E(c.cwd):await R(c.cwd):await C(c.cwd),s=[];for(const i of o.newKernels){const p=i.displayName.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-");let y=p,j=1;for(;r.kernels[y];)y=`${p}-${j}`,j++;r.kernels[y]=i,s.push({id:y,...i})}return r.scanCache={lastScan:new Date().toISOString(),scannedKernels:Object.keys(r.kernels)},await d(r),{content:[{type:"text",text:[`Scanned environments, found ${s.length} new kernels:`,...s.map(i=>`- ${i.id}: ${i.displayName} (${i.command})`),...o.errors.length>0?["","Warnings:",...o.errors.map(i=>`- ${i}`)]:[]].join(`
|
|
7
|
+
`)}],details:{schema:"kernel-plot.result.v1",kind:"configure",action:"scan",newKernels:s,errors:o.errors,scanTime:r.scanCache.lastScan}}}default:throw new Error(`Unknown action: ${e.action}`)}},renderResult:S});return{run:t,stop:l,artifacts:a,configure:k,async disposeSession(h){await(await $()).stopSession({ownerId:b(h)})}}}export{Y as createKernelPlotTools};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export type KernelLanguage = "python" | "r";
|
|
2
|
+
export type KernelRuntime = "kernel-lite" | "worker" | "jupyter";
|
|
3
|
+
export type KernelRunStatus = "queued" | "running" | "succeeded" | "failed" | "cancelled" | "timed_out";
|
|
4
|
+
export type ArtifactKind = "image" | "html" | "document" | "text" | "data" | "other";
|
|
5
|
+
export interface ExecuteKernelRunInput {
|
|
6
|
+
cwd: string;
|
|
7
|
+
ownerId: string;
|
|
8
|
+
language: KernelLanguage;
|
|
9
|
+
runtime?: Exclude<KernelRuntime, "jupyter">;
|
|
10
|
+
code: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
archiveRoot?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
export interface KernelArtifact {
|
|
18
|
+
path: string;
|
|
19
|
+
relativePath: string;
|
|
20
|
+
archivePath: string;
|
|
21
|
+
name: string;
|
|
22
|
+
mimeType: string;
|
|
23
|
+
kind: ArtifactKind;
|
|
24
|
+
size: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ExecuteKernelRunResult {
|
|
27
|
+
runId: string;
|
|
28
|
+
ownerId: string;
|
|
29
|
+
language: KernelLanguage;
|
|
30
|
+
runtime: KernelRuntime;
|
|
31
|
+
status: KernelRunStatus;
|
|
32
|
+
title?: string;
|
|
33
|
+
stdout: string;
|
|
34
|
+
stderr: string;
|
|
35
|
+
exitCode: number | null;
|
|
36
|
+
error: string | null;
|
|
37
|
+
cancelled: boolean;
|
|
38
|
+
timedOut: boolean;
|
|
39
|
+
scriptPath: string;
|
|
40
|
+
stdoutPath: string;
|
|
41
|
+
stderrPath: string;
|
|
42
|
+
outputDir: string;
|
|
43
|
+
artifacts: KernelArtifact[];
|
|
44
|
+
createdAt: string;
|
|
45
|
+
completedAt: string;
|
|
46
|
+
}
|
|
47
|
+
export interface KernelLiteCore {
|
|
48
|
+
run(input: ExecuteKernelRunInput): Promise<ExecuteKernelRunResult>;
|
|
49
|
+
stopSession(input: {
|
|
50
|
+
cwd?: string;
|
|
51
|
+
ownerId: string;
|
|
52
|
+
language?: KernelLanguage;
|
|
53
|
+
}): Promise<void>;
|
|
54
|
+
cancelRun?(runId: string, reason?: string): Promise<boolean>;
|
|
55
|
+
listArtifacts(input: {
|
|
56
|
+
cwd: string;
|
|
57
|
+
ownerId: string;
|
|
58
|
+
limit?: number;
|
|
59
|
+
}): Promise<KernelArtifact[]>;
|
|
60
|
+
dispose(): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
export type ToolContent = Array<{
|
|
63
|
+
type: "text";
|
|
64
|
+
text: string;
|
|
65
|
+
} | {
|
|
66
|
+
type: "image";
|
|
67
|
+
data: string;
|
|
68
|
+
mimeType: string;
|
|
69
|
+
}>;
|
|
70
|
+
export interface KernelPlotRunDetails {
|
|
71
|
+
schema: "kernel-plot.result.v1";
|
|
72
|
+
kind: "run";
|
|
73
|
+
run: {
|
|
74
|
+
runId: string;
|
|
75
|
+
status: KernelRunStatus;
|
|
76
|
+
language: KernelLanguage;
|
|
77
|
+
runtime: KernelRuntime;
|
|
78
|
+
title?: string;
|
|
79
|
+
stdoutPath: string;
|
|
80
|
+
stderrPath: string;
|
|
81
|
+
scriptPath: string;
|
|
82
|
+
outputDir: string;
|
|
83
|
+
stdoutPreview: string;
|
|
84
|
+
stderrPreview: string;
|
|
85
|
+
error: string | null;
|
|
86
|
+
};
|
|
87
|
+
artifacts: KernelArtifact[];
|
|
88
|
+
nextAction: string;
|
|
89
|
+
}
|
|
90
|
+
export interface KernelPlotStopDetails {
|
|
91
|
+
schema: "kernel-plot.result.v1";
|
|
92
|
+
kind: "stop";
|
|
93
|
+
stopped: {
|
|
94
|
+
ownerId: string;
|
|
95
|
+
language?: KernelLanguage;
|
|
96
|
+
};
|
|
97
|
+
artifacts: KernelArtifact[];
|
|
98
|
+
nextAction: string;
|
|
99
|
+
}
|
|
100
|
+
export interface KernelPlotArtifactsDetails {
|
|
101
|
+
schema: "kernel-plot.result.v1";
|
|
102
|
+
kind: "artifacts";
|
|
103
|
+
ownerId: string;
|
|
104
|
+
artifacts: KernelArtifact[];
|
|
105
|
+
nextAction: string;
|
|
106
|
+
}
|
|
107
|
+
export type KernelPlotToolDetails = KernelPlotRunDetails | KernelPlotStopDetails | KernelPlotArtifactsDetails;
|
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@seqyuan/pi-kernel-plot",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Pi package adapter for warm R/Python kernel plotting artifacts.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/seqyuan/warmplot.git",
|
|
9
|
+
"directory": "packages/pi-kernel-plot"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/seqyuan/warmplot/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/seqyuan/warmplot#readme",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"registry": "https://registry.npmjs.org/"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"pi-package",
|
|
22
|
+
"kernel",
|
|
23
|
+
"plot",
|
|
24
|
+
"python",
|
|
25
|
+
"r"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"!dist/**/*.map",
|
|
30
|
+
"!dist/**/*.tsbuildinfo",
|
|
31
|
+
"skills",
|
|
32
|
+
"package.json",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"pi": {
|
|
36
|
+
"extensions": [
|
|
37
|
+
"./dist/extensions/kernel-plot.js"
|
|
38
|
+
],
|
|
39
|
+
"skills": [
|
|
40
|
+
"./skills"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"prepack": "node ../../scripts/check-pack-protection.mjs .",
|
|
45
|
+
"prepublishOnly": "node ../../scripts/check-pack-protection.mjs ."
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@seqyuan/kernel-lite-core": "^0.2.1"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"@earendil-works/pi-ai": "*",
|
|
52
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
53
|
+
"@earendil-works/pi-tui": "*",
|
|
54
|
+
"typebox": "*"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"@earendil-works/pi-ai": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@earendil-works/pi-coding-agent": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@earendil-works/pi-tui": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"typebox": {
|
|
67
|
+
"optional": true
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kernel-plot
|
|
3
|
+
description: Use Pi kernel plotting tools for iterative R/Python data visualization, saving artifacts from warm kernel sessions under WARMPLOT_OUTPUT_DIR.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Kernel Plot
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants iterative R or Python plotting, especially when data should stay loaded across turns.
|
|
9
|
+
|
|
10
|
+
## Tool Choice
|
|
11
|
+
|
|
12
|
+
- Use `kernel_plot_configure` to manage Python/R environments (list, select, scan, add, edit, delete kernels).
|
|
13
|
+
- Use `kernel_plot_run` with the default `kernel-lite` runtime for short iterative plotting code that benefits from warm memory.
|
|
14
|
+
- Use `kernel_plot_run` with `runtime: "worker"` for one-shot scripts that should run from a clean process.
|
|
15
|
+
- Use `kernel_plot_artifacts` to list recent outputs from the current Pi session.
|
|
16
|
+
- Use `kernel_plot_stop` when the user is done with large objects or asks to free memory.
|
|
17
|
+
|
|
18
|
+
## Kernel Configuration
|
|
19
|
+
|
|
20
|
+
Before running code, you can configure which Python/R environment to use:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
# List available kernels
|
|
24
|
+
kernel_plot_configure({ action: "list" })
|
|
25
|
+
|
|
26
|
+
# Scan for new environments (conda, virtualenv, pyenv, etc.)
|
|
27
|
+
kernel_plot_configure({ action: "scan" })
|
|
28
|
+
|
|
29
|
+
# Select a kernel for this project
|
|
30
|
+
kernel_plot_configure({ action: "select", language: "python", kernelId: "conda-bio" })
|
|
31
|
+
|
|
32
|
+
# Add a custom kernel
|
|
33
|
+
kernel_plot_configure({
|
|
34
|
+
action: "add",
|
|
35
|
+
kernelId: "my-venv",
|
|
36
|
+
config: {
|
|
37
|
+
command: "/path/to/venv/bin/python",
|
|
38
|
+
displayName: "My Project Venv"
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The selected kernel persists for the current project in `.pi/warmplot.json`. Global kernel configurations are stored in `~/.config/warmplot.json`.
|
|
44
|
+
|
|
45
|
+
**Kernel Selection Priority:**
|
|
46
|
+
1. Project configuration (`.pi/warmplot.json`)
|
|
47
|
+
2. Global default (`~/.config/warmplot.json`)
|
|
48
|
+
3. System PATH (`python3` or `R`)
|
|
49
|
+
|
|
50
|
+
## Runtime Rules
|
|
51
|
+
|
|
52
|
+
- Always save outputs under `WARMPLOT_OUTPUT_DIR`.
|
|
53
|
+
- Treat `PI_KERNEL_PLOT_OUTPUT_DIR` and `OPENANNO_PLOT_OUTPUT_DIR` as compatibility aliases if present.
|
|
54
|
+
- Do not rely on notebook display hooks. Save figures or tables explicitly.
|
|
55
|
+
- Prefer deterministic names such as `umap_by_cluster.png`, `markers_heatmap.pdf`, or `cluster_counts.csv`.
|
|
56
|
+
- Print concise summaries only. Write large tables to CSV, TSV, JSON, or parquet-like outputs supported by the environment.
|
|
57
|
+
|
|
58
|
+
## Python Patterns
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import os
|
|
62
|
+
from pathlib import Path
|
|
63
|
+
|
|
64
|
+
out = Path(os.environ["WARMPLOT_OUTPUT_DIR"])
|
|
65
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
|
|
67
|
+
# matplotlib
|
|
68
|
+
fig = ax.get_figure()
|
|
69
|
+
fig.savefig(out / "plot.png", dpi=300, bbox_inches="tight")
|
|
70
|
+
|
|
71
|
+
# plotly
|
|
72
|
+
fig.write_html(out / "plot.html", include_plotlyjs="cdn")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
For Scanpy workflows, keep the main object name stable, usually `adata`, so later calls can reuse it.
|
|
76
|
+
|
|
77
|
+
## R Patterns
|
|
78
|
+
|
|
79
|
+
```r
|
|
80
|
+
out <- Sys.getenv("WARMPLOT_OUTPUT_DIR")
|
|
81
|
+
dir.create(out, recursive = TRUE, showWarnings = FALSE)
|
|
82
|
+
|
|
83
|
+
ggsave(file.path(out, "plot.png"), p, width = 7, height = 5, dpi = 300)
|
|
84
|
+
write.csv(markers, file.path(out, "markers.csv"), row.names = FALSE)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For Seurat workflows, keep the main object name stable, usually `obj`, so later calls can reuse it.
|
|
88
|
+
|
|
89
|
+
## Failure Handling
|
|
90
|
+
|
|
91
|
+
- If a run fails, inspect stderr first.
|
|
92
|
+
- Rerun only the minimal corrected code unless the user asks for a full rerun.
|
|
93
|
+
- If warm state is likely corrupted, call `kernel_plot_stop` for the affected language and rerun setup code.
|