@nteract/pi 0.0.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -7
- package/extensions/repl.ts +71 -14
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
# @nteract/pi
|
|
2
2
|
|
|
3
|
-
Pi extensions for nteract.
|
|
3
|
+
Pi extensions for running Python through the local nteract `runtimed` daemon.
|
|
4
|
+
The package provides a persistent notebook-backed REPL for coding agents and
|
|
5
|
+
terminal workflows that need stateful Python execution.
|
|
4
6
|
|
|
5
7
|
## Extensions
|
|
6
8
|
|
|
7
|
-
- `extensions/repl.ts` registers a persistent `python` tool backed by
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
9
|
+
- `extensions/repl.ts` registers a persistent `python` tool backed by
|
|
10
|
+
`@runtimed/node`.
|
|
11
|
+
- `python` accepts an optional `dependencies` array. On first use, those
|
|
12
|
+
packages are recorded before the kernel starts; on later calls they are
|
|
13
|
+
hot-synced before executing the cell.
|
|
14
|
+
- `python_add_dependencies` batch-records notebook dependencies and hot-syncs
|
|
15
|
+
them into the environment using the direct Node binding.
|
|
16
|
+
- `python_save_notebook` saves the backing notebook.
|
|
17
|
+
- `/python-reset` shuts down the backing notebook room and starts fresh on the
|
|
18
|
+
next `python` call.
|
|
11
19
|
|
|
12
20
|
## Install
|
|
13
21
|
|
|
14
|
-
Once published:
|
|
15
|
-
|
|
16
22
|
```bash
|
|
17
23
|
pi install npm:@nteract/pi@next
|
|
18
24
|
```
|
|
19
25
|
|
|
26
|
+
Use the `next` tag for prerelease builds until the package is promoted to the
|
|
27
|
+
default npm tag.
|
|
28
|
+
|
|
20
29
|
## Local Use
|
|
21
30
|
|
|
22
31
|
From this checkout:
|
package/extensions/repl.ts
CHANGED
|
@@ -26,15 +26,19 @@ import { Type } from "typebox";
|
|
|
26
26
|
type RuntimedNode = {
|
|
27
27
|
defaultSocketPath(): string;
|
|
28
28
|
socketPathForChannel(channel: "stable" | "nightly"): string;
|
|
29
|
+
PackageManager?: { Uv: "uv"; Conda: "conda"; Pixi: "pixi" };
|
|
29
30
|
createNotebook(opts?: {
|
|
30
31
|
runtime?: string;
|
|
31
32
|
workingDir?: string;
|
|
32
33
|
socketPath?: string;
|
|
33
34
|
peerLabel?: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
dependencies?: string[];
|
|
37
|
+
packageManager?: "uv" | "conda" | "pixi";
|
|
34
38
|
}): Promise<Session>;
|
|
35
39
|
openNotebook(
|
|
36
40
|
notebookId: string,
|
|
37
|
-
opts?: { socketPath?: string; peerLabel?: string },
|
|
41
|
+
opts?: { socketPath?: string; peerLabel?: string; description?: string },
|
|
38
42
|
): Promise<Session>;
|
|
39
43
|
readParquetFile(
|
|
40
44
|
filePath: string,
|
|
@@ -78,8 +82,20 @@ type Session = {
|
|
|
78
82
|
readonly notebookId: string;
|
|
79
83
|
runCell(source: string, opts?: { timeoutMs?: number; cellType?: string }): Promise<CellResult>;
|
|
80
84
|
addUvDependency(pkg: string): Promise<void>;
|
|
85
|
+
addDependencies?(
|
|
86
|
+
packages: string[],
|
|
87
|
+
opts?: { packageManager?: "uv" | "conda" | "pixi" },
|
|
88
|
+
): Promise<void>;
|
|
89
|
+
getDependencyStatus?(): Promise<{ uv?: { dependencies: string[] }; fingerprint?: string }>;
|
|
90
|
+
getRuntimeStatus?(): Promise<{
|
|
91
|
+
status: string;
|
|
92
|
+
lifecycle: string;
|
|
93
|
+
errorReason?: string;
|
|
94
|
+
errorDetails?: string;
|
|
95
|
+
}>;
|
|
81
96
|
syncEnvironment(): Promise<void>;
|
|
82
97
|
saveNotebook(path?: string): Promise<void>;
|
|
98
|
+
shutdownNotebook?(): Promise<boolean>;
|
|
83
99
|
close(): Promise<void>;
|
|
84
100
|
};
|
|
85
101
|
|
|
@@ -388,6 +404,12 @@ const PYTHON_PARAMS = Type.Object({
|
|
|
388
404
|
description:
|
|
389
405
|
"Python source to execute in the persistent notebook session. Use print(...) for side effects; the last expression's repr is returned as the result.",
|
|
390
406
|
}),
|
|
407
|
+
dependencies: Type.Optional(
|
|
408
|
+
Type.Array(Type.String(), {
|
|
409
|
+
description:
|
|
410
|
+
"Packages to add before executing this code. On the first call they are recorded before the kernel starts; on later calls they are hot-synced into the running environment.",
|
|
411
|
+
}),
|
|
412
|
+
),
|
|
391
413
|
timeout_secs: Type.Optional(
|
|
392
414
|
Type.Number({
|
|
393
415
|
description: "Max seconds to wait for execution (default 120).",
|
|
@@ -407,15 +429,41 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
407
429
|
let opening: Promise<Session> | null = null;
|
|
408
430
|
let nextExecCount: number | null = 1;
|
|
409
431
|
|
|
410
|
-
async function
|
|
411
|
-
|
|
412
|
-
if (
|
|
432
|
+
async function addDependenciesAndSync(sess: Session, packages: string[]): Promise<void> {
|
|
433
|
+
const unique = Array.from(new Set(packages.map((pkg) => pkg.trim()).filter(Boolean)));
|
|
434
|
+
if (!unique.length) return;
|
|
435
|
+
if (sess.addDependencies) {
|
|
436
|
+
await sess.addDependencies(unique, { packageManager: rn.PackageManager?.Uv ?? "uv" });
|
|
437
|
+
} else {
|
|
438
|
+
for (const pkg of unique) {
|
|
439
|
+
await sess.addUvDependency(pkg);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
await sess.syncEnvironment();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async function ensureSession(initialDependencies: string[] = []): Promise<Session> {
|
|
446
|
+
const dependencies = Array.from(
|
|
447
|
+
new Set(initialDependencies.map((pkg) => pkg.trim()).filter(Boolean)),
|
|
448
|
+
);
|
|
449
|
+
if (session) {
|
|
450
|
+
await addDependenciesAndSync(session, dependencies);
|
|
451
|
+
return session;
|
|
452
|
+
}
|
|
453
|
+
if (opening) {
|
|
454
|
+
const opened = await opening;
|
|
455
|
+
await addDependenciesAndSync(opened, dependencies);
|
|
456
|
+
return opened;
|
|
457
|
+
}
|
|
413
458
|
opening = (async () => {
|
|
414
459
|
const socketPath = resolveSocketPath(rn);
|
|
415
460
|
session = await rn.createNotebook({
|
|
416
461
|
runtime: "python",
|
|
417
462
|
socketPath,
|
|
418
463
|
peerLabel: "pi",
|
|
464
|
+
description: "pi Python REPL",
|
|
465
|
+
dependencies,
|
|
466
|
+
packageManager: rn.PackageManager?.Uv ?? "uv",
|
|
419
467
|
});
|
|
420
468
|
return session;
|
|
421
469
|
})();
|
|
@@ -438,7 +486,8 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
438
486
|
"State (imports, variables) persists across `python` calls in this session.",
|
|
439
487
|
"Use print() for side-effect output; the last expression is echoed back as the result.",
|
|
440
488
|
"Matplotlib / PIL images are returned inline — you can iterate on plots by looking at them.",
|
|
441
|
-
"
|
|
489
|
+
"If code needs imports that may be missing, pass `dependencies` on the same `python` call so first-use packages are recorded before kernel start when possible.",
|
|
490
|
+
"Install additional packages with the `python_add_dependencies` tool (it uses the notebook environment and hot-reloads without restarting the kernel).",
|
|
442
491
|
],
|
|
443
492
|
parameters: PYTHON_PARAMS,
|
|
444
493
|
renderCall(args, theme, _context) {
|
|
@@ -545,7 +594,7 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
545
594
|
},
|
|
546
595
|
async execute(_toolCallId, params, signal) {
|
|
547
596
|
if (signal?.aborted) throw new Error("aborted");
|
|
548
|
-
const sess = await ensureSession();
|
|
597
|
+
const sess = await ensureSession(params.dependencies ?? []);
|
|
549
598
|
const timeoutSecs = Math.max(1, params.timeout_secs ?? 120);
|
|
550
599
|
const result = await sess.runCell(params.code, {
|
|
551
600
|
timeoutMs: Math.round(timeoutSecs * 1000),
|
|
@@ -574,6 +623,9 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
574
623
|
execution_count: result.executionCount,
|
|
575
624
|
is_error: isError,
|
|
576
625
|
parquet_blob_path: parquetBlobPath,
|
|
626
|
+
runtime: sess.getRuntimeStatus
|
|
627
|
+
? await sess.getRuntimeStatus().catch(() => undefined)
|
|
628
|
+
: undefined,
|
|
577
629
|
},
|
|
578
630
|
};
|
|
579
631
|
},
|
|
@@ -583,9 +635,9 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
583
635
|
name: "python_add_dependencies",
|
|
584
636
|
label: "Add Dependencies (nteract)",
|
|
585
637
|
description:
|
|
586
|
-
"Add packages to the current nteract notebook
|
|
638
|
+
"Add packages to the current nteract notebook environment and hot-sync them so the running kernel can import them immediately. Accepts pip-style specs, e.g. 'matplotlib', 'numpy>=2', 'requests'.",
|
|
587
639
|
promptSnippet:
|
|
588
|
-
"python_add_dependencies: add packages to the persistent Python notebook
|
|
640
|
+
"python_add_dependencies: add packages to the persistent Python notebook environment (hot-installs without restarting the kernel).",
|
|
589
641
|
parameters: Type.Object({
|
|
590
642
|
packages: Type.Array(Type.String(), {
|
|
591
643
|
description: "Package specs (e.g. ['matplotlib', 'pandas>=2']).",
|
|
@@ -597,10 +649,7 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
597
649
|
return { content: [{ type: "text", text: "No packages given." }], details: {} };
|
|
598
650
|
}
|
|
599
651
|
const sess = await ensureSession();
|
|
600
|
-
|
|
601
|
-
await sess.addUvDependency(pkg);
|
|
602
|
-
}
|
|
603
|
-
await sess.syncEnvironment();
|
|
652
|
+
await addDependenciesAndSync(sess, params.packages);
|
|
604
653
|
return {
|
|
605
654
|
content: [
|
|
606
655
|
{
|
|
@@ -648,7 +697,11 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
648
697
|
nextExecCount = 1;
|
|
649
698
|
if (old) {
|
|
650
699
|
try {
|
|
651
|
-
|
|
700
|
+
if (old.shutdownNotebook) {
|
|
701
|
+
await old.shutdownNotebook();
|
|
702
|
+
} else {
|
|
703
|
+
await old.close();
|
|
704
|
+
}
|
|
652
705
|
} catch {}
|
|
653
706
|
}
|
|
654
707
|
ctx.ui.notify(
|
|
@@ -661,7 +714,11 @@ export default function nteractReplExtension(pi: ExtensionAPI) {
|
|
|
661
714
|
pi.on("session_shutdown", async () => {
|
|
662
715
|
if (session) {
|
|
663
716
|
try {
|
|
664
|
-
|
|
717
|
+
if (session.shutdownNotebook) {
|
|
718
|
+
await session.shutdownNotebook();
|
|
719
|
+
} else {
|
|
720
|
+
await session.close();
|
|
721
|
+
}
|
|
665
722
|
} catch {}
|
|
666
723
|
session = null;
|
|
667
724
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nteract/pi",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Pi extensions that run Python through the local nteract runtimed daemon.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
7
7
|
"repository": {
|
|
@@ -9,12 +9,19 @@
|
|
|
9
9
|
"url": "git+https://github.com/nteract/desktop.git",
|
|
10
10
|
"directory": "plugins/nteract/pi"
|
|
11
11
|
},
|
|
12
|
+
"homepage": "https://github.com/nteract/desktop/tree/main/plugins/nteract/pi#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/nteract/desktop/issues"
|
|
15
|
+
},
|
|
12
16
|
"keywords": [
|
|
13
17
|
"pi-package",
|
|
14
18
|
"nteract",
|
|
19
|
+
"runtimed",
|
|
15
20
|
"notebook",
|
|
16
21
|
"python",
|
|
17
|
-
"repl"
|
|
22
|
+
"repl",
|
|
23
|
+
"jupyter",
|
|
24
|
+
"agent"
|
|
18
25
|
],
|
|
19
26
|
"pi": {
|
|
20
27
|
"extensions": [
|
|
@@ -26,7 +33,7 @@
|
|
|
26
33
|
"extensions"
|
|
27
34
|
],
|
|
28
35
|
"dependencies": {
|
|
29
|
-
"@runtimed/node": "0.0
|
|
36
|
+
"@runtimed/node": "0.2.0"
|
|
30
37
|
},
|
|
31
38
|
"peerDependencies": {
|
|
32
39
|
"@mariozechner/pi-coding-agent": "*",
|