@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 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 the local
8
- nteract `runtimed` daemon through `@runtimed/node`.
9
- - It also registers `python_add_dependencies`, `python_save_notebook`, and
10
- `/python-reset`.
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:
@@ -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 ensureSession(): Promise<Session> {
411
- if (session) return session;
412
- if (opening) return opening;
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
- "Install packages with the `python_add_dependencies` tool (it uses the notebook's UV env and hot-reloads without restarting the kernel).",
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's UV environment and hot-sync them so the running kernel can import them immediately. Accepts pip-style specs, e.g. 'matplotlib', 'numpy>=2', 'requests'.",
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 env (hot-installs without restarting the kernel).",
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
- for (const pkg of params.packages) {
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
- await old.close();
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
- await session.close();
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.0.1",
4
- "description": "nteract extensions for Pi",
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.1"
36
+ "@runtimed/node": "0.2.0"
30
37
  },
31
38
  "peerDependencies": {
32
39
  "@mariozechner/pi-coding-agent": "*",