@themoltnet/pi-runtime 0.15.3 → 0.17.0

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/index.d.ts CHANGED
@@ -438,7 +438,7 @@ export declare function createToolPolicyExtension(deps: ToolPolicyExtensionDeps)
438
438
  * Map a pi `tool_call` event to a gate decision, extracting the shell command
439
439
  * for `bash` and delegating to {@link decideToolCall}.
440
440
  */
441
- export declare function decideForEvent(event: ToolCallEvent, policy: SessionToolPolicy, analyze: ShellCommandAnalyzer['analyze'], structuredToolNames?: ReadonlySet<string>): GateDecision;
441
+ export declare function decideForEvent(event: ToolCallEvent, policy: SessionToolPolicy, analyze: ShellCommandAnalyzer['analyze']): GateDecision;
442
442
 
443
443
  /**
444
444
  * Decide whether a tool call is permitted by the resolved policy.
@@ -455,15 +455,19 @@ export declare function decideForEvent(event: ToolCallEvent, policy: SessionTool
455
455
  * allow-set can't bound it. This is the interim conservative stance for
456
456
  * issue #1348 — an operator who lists `bash` still cannot smuggle
457
457
  * `bash -c "curl … | sh"` past `enforce`.
458
- * 3. **Unauthorized executables** — any resolved executable without either a
459
- * non-colliding broad grant or a matching scoped shell-command rule.
458
+ * 3. **Unauthorized executables** — any resolved executable without a matching
459
+ * shell-command rule. Tool names in `allowedTools` never authorize a shell
460
+ * invocation.
461
+ * 4. **Output redirection** — a `bash` command that redirects output (`>`,
462
+ * `2>`, `>>`, `&>`, …). No shell-command rule authorizes it; file writes go
463
+ * through structured tools.
460
464
  *
461
465
  * KNOWN LIMITATION (follow-up): the `escapable` risk tier (GTFOBins binaries
462
466
  * like `find`, `tar`, `awk` that document shell-spawn / file-write techniques)
463
467
  * is NOT blocked on the tier alone. The analyzer already re-analyzes the
464
468
  * sub-commands it can see through documented escape flags (`find -exec`,
465
469
  * `tar --to-command`, …), but techniques it cannot parse statically could still
466
- * escape a name-based allow-set. Tightening `escapable` (e.g. an LLM judge or a
470
+ * escape an argv-prefix rule. Tightening `escapable` (e.g. an LLM judge or a
467
471
  * capability-aware allow-set) is tracked as future work.
468
472
  */
469
473
  export declare function decideToolCall(input: GateInput): GateDecision;
@@ -768,11 +772,15 @@ export declare interface GateInput {
768
772
  /** The shell command, when `toolName === 'bash'`. */
769
773
  command?: string;
770
774
  enforcement: ToolEnforcement;
771
- /** Names the policy allows (structured tool names + broad executables). */
775
+ /**
776
+ * Runtime and MCP tool names the policy allows. Matched against `toolName`
777
+ * only; a tool name never authorizes a shell invocation.
778
+ */
772
779
  allowedTools: ReadonlySet<string>;
773
- /** Structured tool names registered by the active runtime adapter. */
774
- structuredToolNames?: ReadonlySet<string>;
775
- /** Shell argv rules. Each rule matches the first N statically known tokens. */
780
+ /**
781
+ * Shell argv rules, the only authority for shell invocations. Each rule
782
+ * matches the first N statically known tokens.
783
+ */
776
784
  allowedShellCommands: readonly ShellCommandRule[];
777
785
  /**
778
786
  * Synchronous shell analyzer (`ShellCommandAnalyzer.analyze`). Injected so the
@@ -1450,7 +1458,7 @@ export declare interface SessionToolPolicy {
1450
1458
  }
1451
1459
 
1452
1460
  declare interface ShellCommandRule {
1453
- argvPrefix: readonly [string, string, ...string[]];
1461
+ argvPrefix: readonly [string, ...string[]];
1454
1462
  }
1455
1463
 
1456
1464
  export { SnapshotConfig }
@@ -1521,14 +1529,12 @@ export declare interface ToolPolicyDecisionContext {
1521
1529
  * - `{ allow: false, reason }` — block it (enforce mode).
1522
1530
  * - `{ audit, ... }` — would-block, but proceed and record it (watch mode).
1523
1531
  */
1524
- export declare type ToolPolicyDecisionReason = 'policy_off' | 'executor_protocol_tool' | 'policy_allowed' | 'shell_command_prefix_allowed' | 'shell_command_unresolvable' | 'arbitrary_code_interpreter' | 'shell_output_redirection_requires_broad_permission' | 'tool_not_permitted';
1532
+ export declare type ToolPolicyDecisionReason = 'policy_off' | 'executor_protocol_tool' | 'policy_allowed' | 'shell_command_prefix_allowed' | 'shell_command_unresolvable' | 'arbitrary_code_interpreter' | 'shell_output_redirection_not_permitted' | 'tool_not_permitted';
1525
1533
 
1526
1534
  export declare interface ToolPolicyExtensionDeps {
1527
1535
  policy: SessionToolPolicy;
1528
1536
  analyzer: ShellCommandAnalyzer;
1529
1537
  logger: ToolPolicyLogger;
1530
- /** Structured tool names registered by the active runtime adapter. */
1531
- structuredToolNames?: ReadonlySet<string>;
1532
1538
  context?: ToolPolicyDecisionContext;
1533
1539
  }
1534
1540
 
package/dist/index.js CHANGED
@@ -2890,18 +2890,6 @@ Type.Object({ profileId: Type.String({ format: "uuid" }) }, {
2890
2890
  $id: "RuntimeProfileRef",
2891
2891
  additionalProperties: false
2892
2892
  });
2893
- var RuntimeProfileLeaseTtlSec = Type.Integer({
2894
- minimum: 1,
2895
- maximum: 86400
2896
- });
2897
- var RuntimeProfileHeartbeatIntervalMs = Type.Integer({
2898
- minimum: 0,
2899
- maximum: 36e5
2900
- });
2901
- var RuntimeProfileMaxBatchSize = Type.Integer({
2902
- minimum: 1,
2903
- maximum: 1e3
2904
- });
2905
2893
  var RuntimeProfileMaxTurns = Type.Integer({
2906
2894
  minimum: 0,
2907
2895
  maximum: 1e4
@@ -2930,21 +2918,8 @@ Type.Object({
2930
2918
  maxOutputTokens: RuntimeProfileNullableMaxOutputTokens,
2931
2919
  runtimeKind: RuntimeProfileRuntimeKind,
2932
2920
  sandbox: RuntimeProfileSandbox,
2933
- sessionStorageMode: Type.Literal("local"),
2934
- workspaceStorageMode: Type.Literal("local"),
2935
2921
  defaultWorkspaceMode: Type.Union([RuntimeProfileWorkspaceMode, Type.Null()]),
2936
2922
  allowedWorkspaceModes: RuntimeProfileAllowedWorkspaceModes,
2937
- sessionTtlSec: Type.Integer({
2938
- minimum: 1,
2939
- maximum: 86400
2940
- }),
2941
- workspaceTtlSec: Type.Integer({
2942
- minimum: 1,
2943
- maximum: 86400
2944
- }),
2945
- leaseTtlSec: RuntimeProfileLeaseTtlSec,
2946
- heartbeatIntervalMs: RuntimeProfileHeartbeatIntervalMs,
2947
- maxBatchSize: RuntimeProfileMaxBatchSize,
2948
2923
  maxTurns: RuntimeProfileMaxTurns,
2949
2924
  maxBashTimeouts: RuntimeProfileMaxBashTimeouts,
2950
2925
  toolEnforcement: RuntimeProfileToolEnforcement,
@@ -3077,6 +3052,7 @@ var ResolvedRuntimeSlot = Type.Object({
3077
3052
  workspace: Type.Union([RuntimeWorkspace, Type.Null()])
3078
3053
  }, { $id: "ResolvedRuntimeSlot" });
3079
3054
  Type.Object({ items: Type.Array(ResolvedRuntimeSlot) }, { $id: "RuntimeSlotListResponse" });
3055
+ var MAX_RUNTIME_WARM_RETENTION_SEC = 86400;
3080
3056
  Type.Object({
3081
3057
  agentName: Type.String({
3082
3058
  minLength: 1,
@@ -3103,7 +3079,11 @@ Type.Object({
3103
3079
  worktreeBranch: Type.Optional(Type.String({ minLength: 1 })),
3104
3080
  workspaceKind: Type.Optional(RuntimeWorkspaceKind),
3105
3081
  lastTaskId: Type.String({ format: "uuid" }),
3106
- lastAttemptN: Type.Integer({ minimum: 1 })
3082
+ lastAttemptN: Type.Integer({ minimum: 1 }),
3083
+ warmRetentionSec: Type.Integer({
3084
+ minimum: 0,
3085
+ maximum: MAX_RUNTIME_WARM_RETENTION_SEC
3086
+ })
3107
3087
  }, {
3108
3088
  $id: "BeginRuntimeSlotBody",
3109
3089
  additionalProperties: false
@@ -3125,7 +3105,11 @@ Type.Object({
3125
3105
  slotKey: Type.String({ minLength: 1 }),
3126
3106
  taskId: Type.String({ format: "uuid" }),
3127
3107
  attemptN: Type.Integer({ minimum: 1 }),
3128
- sessionPath: Type.Optional(Type.String({ minLength: 1 }))
3108
+ sessionPath: Type.Optional(Type.String({ minLength: 1 })),
3109
+ warmRetentionSec: Type.Integer({
3110
+ minimum: 0,
3111
+ maximum: MAX_RUNTIME_WARM_RETENTION_SEC
3112
+ })
3129
3113
  }, {
3130
3114
  $id: "FinishRuntimeSlotBody",
3131
3115
  additionalProperties: false
@@ -3978,15 +3962,19 @@ function createGondolinBashOps(vm, localCwd, guestWorkspace, config) {
3978
3962
  * allow-set can't bound it. This is the interim conservative stance for
3979
3963
  * issue #1348 — an operator who lists `bash` still cannot smuggle
3980
3964
  * `bash -c "curl … | sh"` past `enforce`.
3981
- * 3. **Unauthorized executables** — any resolved executable without either a
3982
- * non-colliding broad grant or a matching scoped shell-command rule.
3965
+ * 3. **Unauthorized executables** — any resolved executable without a matching
3966
+ * shell-command rule. Tool names in `allowedTools` never authorize a shell
3967
+ * invocation.
3968
+ * 4. **Output redirection** — a `bash` command that redirects output (`>`,
3969
+ * `2>`, `>>`, `&>`, …). No shell-command rule authorizes it; file writes go
3970
+ * through structured tools.
3983
3971
  *
3984
3972
  * KNOWN LIMITATION (follow-up): the `escapable` risk tier (GTFOBins binaries
3985
3973
  * like `find`, `tar`, `awk` that document shell-spawn / file-write techniques)
3986
3974
  * is NOT blocked on the tier alone. The analyzer already re-analyzes the
3987
3975
  * sub-commands it can see through documented escape flags (`find -exec`,
3988
3976
  * `tar --to-command`, …), but techniques it cannot parse statically could still
3989
- * escape a name-based allow-set. Tightening `escapable` (e.g. an LLM judge or a
3977
+ * escape an argv-prefix rule. Tightening `escapable` (e.g. an LLM judge or a
3990
3978
  * capability-aware allow-set) is tracked as future work.
3991
3979
  */
3992
3980
  function decideToolCall(input) {
@@ -4011,20 +3999,21 @@ function decideToolCall(input) {
4011
3999
  return fenced(input.enforcement, "tool_not_permitted", `not permitted by tool policy: ${missing.join(", ")}`, `would block (watch): ${missing.join(", ")}`, missing);
4012
4000
  }
4013
4001
  const matchedShellCommands = [];
4014
- const structuredToolNames = input.structuredToolNames ?? DEFAULT_PI_STRUCTURED_TOOL_NAMES;
4015
4002
  const missingShellCommands = resolved.tools.filter((tool) => {
4016
- if (input.allowedTools.has(tool.name) && !structuredToolNames.has(tool.name)) return false;
4017
4003
  const matched = input.allowedShellCommands.find((rule) => matchesArgvPrefix(tool.argv, rule.argvPrefix));
4018
4004
  if (!matched) return true;
4019
4005
  matchedShellCommands.push(toMatchedShellCommand(tool.name, matched.argvPrefix));
4020
4006
  return false;
4021
4007
  }).map(toMissingShellCommand);
4022
- if (missingShellCommands.length === 0 && resolved.hasOutputRedirection && matchedShellCommands.length > 0) return fenced(input.enforcement, "shell_output_redirection_requires_broad_permission", "shell output redirection requires broad executable permission", "would block shell output redirection under scoped command policy", [...new Set(matchedShellCommands.map(({ executable }) => executable))], matchedShellCommands.map(({ executable, argvPrefixFingerprint, argvPrefixLength }) => ({
4023
- executable,
4024
- argvFingerprint: argvPrefixFingerprint,
4025
- argvLength: argvPrefixLength,
4026
- dynamicTokenCount: 0
4027
- })));
4008
+ if (missingShellCommands.length === 0 && resolved.hasOutputRedirection) {
4009
+ const executables = [...new Set(matchedShellCommands.map(({ executable }) => executable))];
4010
+ return fenced(input.enforcement, "shell_output_redirection_not_permitted", "shell output redirection is not permitted by tool policy", "would block shell output redirection (watch)", executables.length > 0 ? executables : void 0, matchedShellCommands.map(({ executable, argvPrefixFingerprint, argvPrefixLength }) => ({
4011
+ executable,
4012
+ argvFingerprint: argvPrefixFingerprint,
4013
+ argvLength: argvPrefixLength,
4014
+ dynamicTokenCount: 0
4015
+ })));
4016
+ }
4028
4017
  if (missingShellCommands.length === 0) return matchedShellCommands.length > 0 ? {
4029
4018
  allow: true,
4030
4019
  reasonCode: "shell_command_prefix_allowed",
@@ -4036,20 +4025,6 @@ function decideToolCall(input) {
4036
4025
  const missing = [...new Set(missingShellCommands.map(({ executable }) => executable))];
4037
4026
  return fenced(input.enforcement, "tool_not_permitted", `not permitted by tool policy: ${missing.join(", ")}`, `would block (watch): ${missing.join(", ")}`, missing, missingShellCommands);
4038
4027
  }
4039
- /**
4040
- * Protect direct gate callers that predate active-runtime tool projection.
4041
- * The session integration supplies the complete registered set, including
4042
- * custom tools, while these are Pi's built-in structured tool names.
4043
- */
4044
- var DEFAULT_PI_STRUCTURED_TOOL_NAMES = new Set([
4045
- "read",
4046
- "write",
4047
- "edit",
4048
- "bash",
4049
- "grep",
4050
- "ls",
4051
- "find"
4052
- ]);
4053
4028
  function fingerprintArgv(argv) {
4054
4029
  return `sha256:${createHash("sha256").update(JSON.stringify(argv.map((token) => token === null ? { dynamic: true } : token))).digest("hex").slice(0, 16)}`;
4055
4030
  }
@@ -4152,7 +4127,7 @@ async function resolveSessionToolPolicy(input) {
4152
4127
  enforcement: resolved.enforcement,
4153
4128
  allowedTools: new Set(resolved.allowedTools),
4154
4129
  allowedShellCommands: shellCommands.map((rule) => {
4155
- if (rule.argvPrefix.length < 2 || rule.argvPrefix.length > 8 || rule.argvPrefix.some((token) => !token)) throw new Error("runtime returned an invalid shell command rule");
4130
+ if (rule.argvPrefix.length < 1 || rule.argvPrefix.length > 8 || rule.argvPrefix.some((token) => !token)) throw new Error("runtime returned an invalid shell command rule");
4156
4131
  return { argvPrefix: rule.argvPrefix };
4157
4132
  }),
4158
4133
  executionPolicySnapshotHash: resolved.policySnapshotHash,
@@ -4212,14 +4187,13 @@ async function withTimeout$1(promise, timeoutMs) {
4212
4187
  * Map a pi `tool_call` event to a gate decision, extracting the shell command
4213
4188
  * for `bash` and delegating to {@link decideToolCall}.
4214
4189
  */
4215
- function decideForEvent(event, policy, analyze, structuredToolNames) {
4190
+ function decideForEvent(event, policy, analyze) {
4216
4191
  const command = event.toolName === "bash" ? event.input.command : void 0;
4217
4192
  return decideToolCall({
4218
4193
  toolName: event.toolName,
4219
4194
  command,
4220
4195
  enforcement: policy.enforcement,
4221
4196
  allowedTools: policy.allowedTools,
4222
- structuredToolNames,
4223
4197
  allowedShellCommands: policy.allowedShellCommands,
4224
4198
  analyze
4225
4199
  });
@@ -4238,7 +4212,7 @@ function createToolPolicyExtension(deps) {
4238
4212
  return (pi) => {
4239
4213
  if (deps.policy.enforcement === "off") return;
4240
4214
  pi.on("tool_call", (event) => {
4241
- const decision = decideForEvent(event, deps.policy, (command) => deps.analyzer.analyze(command), deps.structuredToolNames);
4215
+ const decision = decideForEvent(event, deps.policy, (command) => deps.analyzer.analyze(command));
4242
4216
  if ("allow" in decision && decision.allow) {
4243
4217
  deps.logger.info({
4244
4218
  ...decisionContext(deps),
@@ -4760,7 +4734,7 @@ function buildToolPolicyInstructions(policy) {
4760
4734
  lines.push(policy.allowedTools.length > 0 ? "- The visible structured-tool definitions are the authorized surface." : policy.enforcement === "enforce" ? "- No optional structured tools are authorized." : "- No optional structured tools are registered.");
4761
4735
  if (policy.enforcement === "watch") lines.push("- Watch mode records policy decisions but does not block tool calls.");
4762
4736
  else if (policy.allowedShellCommands.length === 0) lines.push("- No shell commands are authorized. `bash` is not available; do not", " attempt shell, filesystem, git, GitHub CLI, or MoltNet CLI commands.");
4763
- else lines.push("- Shell commands are restricted to these authorized argv prefixes:", ...renderShellCommandPrefixes(policy.allowedShellCommands), "- A visible `bash` tool does not grant broader shell authority. Do not", " attempt commands outside those prefixes.");
4737
+ else lines.push("- Shell commands are restricted to these authorized argv prefixes:", ...renderShellCommandPrefixes(policy.allowedShellCommands), "- A visible `bash` tool does not grant broader shell authority. Do not", " attempt commands outside those prefixes.", "- Output redirection (`>`, `2>`, `>>`, `&>`) is never authorized, even", " for an authorized prefix. Write files with the structured file tools.");
4764
4738
  lines.push("- Tools and commands absent from this effective policy are unavailable,", " even if advisory context mentions them.");
4765
4739
  return lines.join("\n");
4766
4740
  }
@@ -6483,14 +6457,6 @@ async function executePiTask(claimedTask, reporter, opts) {
6483
6457
  };
6484
6458
  const toolPolicyDecisionContext = buildToolPolicyDecisionContext(claimedTask, opts.runtimeProfileId);
6485
6459
  const taskHasSubagents = taskTypeUsesSubagents(task.taskType);
6486
- const structuredToolNames = new Set([
6487
- ...gondolinCustomTools.map((tool) => tool.name),
6488
- ...moltnetTools.map((tool) => tool.name),
6489
- ...submitTools.map((tool) => tool.name),
6490
- ...opts.runtimeDefinition?.tools.map((tool) => tool.descriptor.name) ?? [],
6491
- ...opts.runtimeDefinition?.extensions.flatMap((extension) => extension.declaredTools) ?? [],
6492
- ...taskHasSubagents ? ["subagent"] : []
6493
- ]);
6494
6460
  if (opts.runtimeProfileId && opts.toolEnforcement) {
6495
6461
  const policy = await resolveSessionToolPolicy({
6496
6462
  agent: moltnetAgent,
@@ -6515,7 +6481,6 @@ async function executePiTask(claimedTask, reporter, opts) {
6515
6481
  policy: resolvedToolPolicy,
6516
6482
  analyzer,
6517
6483
  logger: toolPolicyLogger,
6518
- structuredToolNames,
6519
6484
  context: toolPolicyDecisionContext
6520
6485
  }));
6521
6486
  }
@@ -1,8 +1,30 @@
1
+ /**
2
+ * Every input modality Pi understands. Canonical for the repo: daemon
3
+ * validation, CLI parsing and wire schemas derive their allowed values from
4
+ * this list so they cannot drift from what Pi actually accepts.
5
+ */
6
+ export declare const PI_MODEL_MODALITIES: readonly ["text", "image"];
7
+
8
+ /** Input modalities Pi understands for a model entry. */
9
+ export declare type PiModelModality = (typeof PI_MODEL_MODALITIES)[number];
10
+
11
+ /**
12
+ * A model entry in Pi's `models.json`. `input` declares the modalities the
13
+ * model accepts. Pi treats an entry with no `input` as text-only, so a vision
14
+ * model must declare `['text', 'image']` or image content parts never reach
15
+ * the provider.
16
+ */
17
+ export declare interface PiModelSpec {
18
+ id: string;
19
+ input?: readonly PiModelModality[];
20
+ }
21
+
1
22
  export declare interface WriteMultiProviderPiConfigInput extends WritePiConfigBase {
2
23
  /** Provider registry keyed by Pi provider id. */
3
24
  providers: Readonly<Record<string, WritePiProviderInput>>;
4
25
  provider?: never;
5
26
  model?: never;
27
+ input?: never;
6
28
  baseUrl?: never;
7
29
  apiKeyEnvRef?: never;
8
30
  }
@@ -27,8 +49,8 @@ export declare interface WritePiProviderInput {
27
49
  api: string;
28
50
  /** Provider base URL. */
29
51
  baseUrl: string;
30
- /** Model ids exposed by this provider. */
31
- models: readonly string[];
52
+ /** Models exposed by this provider. */
53
+ models: readonly PiModelSpec[];
32
54
  /** Optional Pi environment placeholder, e.g. `$OLLAMA_API_KEY`. */
33
55
  apiKeyEnvRef?: string;
34
56
  }
@@ -38,6 +60,8 @@ export declare interface WriteSingleProviderPiConfigInput extends WritePiConfigB
38
60
  provider: string;
39
61
  /** Pi model id, e.g. `qwen3-coder:480b-cloud`. */
40
62
  model: string;
63
+ /** Input modalities for `model`. Omitted leaves Pi's text-only default. */
64
+ input?: readonly PiModelModality[];
41
65
  /**
42
66
  * OpenAI-completions base URL for the provider. Defaults to Ollama Cloud.
43
67
  */
package/dist/pi-config.js CHANGED
@@ -3,6 +3,22 @@ import { join } from "node:path";
3
3
  //#region src/pi-config.ts
4
4
  /** Node-only writer used by daemon serve runs and live evals. */
5
5
  /**
6
+ * Every input modality Pi understands. Canonical for the repo: daemon
7
+ * validation, CLI parsing and wire schemas derive their allowed values from
8
+ * this list so they cannot drift from what Pi actually accepts.
9
+ */
10
+ var PI_MODEL_MODALITIES = ["text", "image"];
11
+ /**
12
+ * Normalise a model entry to Pi's on-disk shape. `input` is emitted only when
13
+ * declared, so a text-only model serializes as a bare `{ id }`.
14
+ */
15
+ function toPiModel(entry) {
16
+ return {
17
+ id: entry.id,
18
+ ...entry.input && entry.input.length > 0 ? { input: [...entry.input] } : {}
19
+ };
20
+ }
21
+ /**
6
22
  * Write Pi `models.json` + `settings.json`. Eval callers use the single-provider
7
23
  * form so scores stay attributable; serve callers may supply many providers.
8
24
  */
@@ -12,12 +28,15 @@ function writePiConfig(input) {
12
28
  api: provider.api,
13
29
  ...provider.apiKeyEnvRef ? { apiKey: provider.apiKeyEnvRef } : {},
14
30
  baseUrl: provider.baseUrl,
15
- models: provider.models.map((id) => ({ id }))
31
+ models: provider.models.map(toPiModel)
16
32
  }])) : { [input.provider]: {
17
33
  api: "openai-completions",
18
34
  apiKey: input.apiKeyEnvRef ?? "$OLLAMA_API_KEY",
19
35
  baseUrl: input.baseUrl ?? "https://ollama.com/v1",
20
- models: [{ id: input.model }]
36
+ models: [toPiModel({
37
+ id: input.model,
38
+ input: input.input
39
+ })]
21
40
  } };
22
41
  writeFileSync(join(input.piDir, "models.json"), JSON.stringify({ providers }, null, 2) + "\n", "utf8");
23
42
  const defaultSettings = multiProvider ? { enableInstallTelemetry: false } : {
@@ -35,4 +54,4 @@ function writePiConfig(input) {
35
54
  }, null, 2) + "\n", "utf8");
36
55
  }
37
56
  //#endregion
38
- export { writePiConfig };
57
+ export { PI_MODEL_MODALITIES, writePiConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/pi-runtime",
3
- "version": "0.15.3",
3
+ "version": "0.17.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Composable MoltNet runtime kernel for Pi agents in Gondolin VMs",
@@ -35,11 +35,11 @@
35
35
  "@opentelemetry/api": "^1.9.1",
36
36
  "multiformats": "^13.3.0",
37
37
  "typebox": "^1.2.8",
38
- "@themoltnet/os-keyring": "0.3.0",
39
38
  "@themoltnet/agent-runtime": "1.0.3",
40
- "@themoltnet/sandbox-gondolin": "0.5.1",
41
39
  "@themoltnet/sdk": "0.142.0",
42
- "@themoltnet/shell-command-analyzer": "0.3.0"
40
+ "@themoltnet/shell-command-analyzer": "0.3.0",
41
+ "@themoltnet/os-keyring": "0.3.0",
42
+ "@themoltnet/sandbox-gondolin": "0.5.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@earendil-works/pi-ai": "0.84.4",
@@ -57,9 +57,9 @@
57
57
  "vite-plugin-dts": "^4.5.4",
58
58
  "vitest": "^3.0.0",
59
59
  "@moltnet/crypto-service": "0.1.0",
60
- "@moltnet/runtime-profiles": "0.1.0",
61
60
  "@moltnet/models": "0.1.0",
62
- "@moltnet/tasks": "0.1.0"
61
+ "@moltnet/tasks": "0.1.0",
62
+ "@moltnet/runtime-profiles": "0.1.0"
63
63
  },
64
64
  "engines": {
65
65
  "node": ">=24"