@rivus/agent 0.14.0 → 0.14.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
@@ -58,10 +58,7 @@ npx rivus --help
58
58
  Create the default Personal Agent Home without cloning this repository or installing another local Rivus copy:
59
59
 
60
60
  ```bash
61
- npm install --global \
62
- @rivus/agent \
63
- @earendil-works/pi-coding-agent@^0.80.6 \
64
- @larksuiteoapi/node-sdk@^1.70.0
61
+ npm install --global @rivus/agent
65
62
  rivus setup
66
63
  cp "$HOME/.rivus-agent/.env.example" "$HOME/.rivus-agent/.env"
67
64
  # Fill the Feishu and model-provider values in ~/.rivus-agent/.env.
@@ -71,11 +68,8 @@ rivus start
71
68
 
72
69
  `setup` refuses to overwrite existing Home files. `start`, `status`, and `check-config` read `RIVUS_HOME` or `~/.rivus-agent`, use its configured Workspace as cwd, and keep state outside npm installation files. `doctor` checks the Home, global modules, manifest, Workspace, and enabled Endpoint credential references without importing Plugin code or contacting external services. Existing standalone projects remain supported through `rivus init <directory>` and `rivus doctor <directory>`. See the [local deployment runbook](docs/en/operations/local-deployment.md).
73
70
 
74
- The Pi plus Feishu Bootstrap is an application-edge package export: install `@earendil-works/pi-coding-agent` and `@larksuiteoapi/node-sdk` beside the global Rivus package. The `@rivus/agent` core keeps those SDKs out of its mandatory runtime dependency graph.
75
-
76
- ```bash
77
- npm install @earendil-works/pi-coding-agent@^0.80.6 @larksuiteoapi/node-sdk@^1.70.0
78
- ```
71
+ The maintained Pi plus Feishu Bootstrap is the default Personal Home runtime, so its pinned Pi SDK and compatible
72
+ Feishu SDK are installed transitively with `@rivus/agent`. Optional adapter SDKs such as ACP remain separate peers.
79
73
 
80
74
  ## Quick Start
81
75
 
@@ -427,7 +421,7 @@ Recognized variables:
427
421
  - `RIVUS_WEATHER_DEFAULT_LOCATION` selects the example `current-weather` Tool's fallback city and defaults to `北京`; it is not a Core setting.
428
422
  - `RIVUS_TELEMETRY_ENVIRONMENT` defaults to `NODE_ENV`, then `local`; `RIVUS_TELEMETRY_SERVICE_NAME` defaults to `rivus-agent`.
429
423
 
430
- For both SDK bootstrap templates, `PI_MODEL` should use Pi's provider/model form when `PI_API_KEY`, `PI_API_KEY_FILE`, or `PI_BASE_URL` is set, for example `anthropic/claude-opus-4-5` or `zai/glm-5.1` for GLM BYOK. The templates apply the resolved Pi API key through Pi `AuthStorage.setRuntimeApiKey()`, resolve the model through Pi's public `ModelRegistry.find(provider, modelId)` API, and apply `PI_BASE_URL` by merging a local `.rivus/pi-models.json` provider override without removing existing custom models or other providers, matching Pi's `models.json` configuration model.
424
+ For both SDK bootstrap templates, `PI_MODEL` should use Pi's provider/model form when `PI_API_KEY`, `PI_API_KEY_FILE`, or `PI_BASE_URL` is set, for example `anthropic/claude-opus-4-5` or `zai/glm-5.2` for GLM BYOK. The templates create Pi's isolated `ModelRuntime`, apply the resolved API key with `setRuntimeApiKey()`, resolve the model with `getModel(provider, modelId)`, and apply `PI_BASE_URL` by merging a local `.rivus/pi-models.json` provider override without removing existing custom models or other providers, matching Pi's `models.json` configuration model.
431
425
 
432
426
  ## Core Usage
433
427
 
@@ -9,7 +9,7 @@ import { mkdir, readFile } from "node:fs/promises";
9
9
  import { join, relative } from "node:path";
10
10
  import { homedir } from "node:os";
11
11
  import * as Lark from "@larksuiteoapi/node-sdk";
12
- import { AuthStorage, ModelRegistry, SessionManager, createAgentSession } from "@earendil-works/pi-coding-agent";
12
+ import { ModelRuntime, SessionManager, createAgentSession } from "@earendil-works/pi-coding-agent";
13
13
  //#region examples/pi-feishu-deployment.bootstrap.ts
14
14
  const STATE_DIR = process.env.RIVUS_DEPLOYMENT_STATE_DIR?.trim() || ".rivus/deployment";
15
15
  const PI_AGENT_DIR = join(STATE_DIR, "pi-agent");
@@ -532,23 +532,25 @@ async function resolveFeishuBotOpenId(credentials, domain) {
532
532
  return openId;
533
533
  }
534
534
  async function createPiSessionOptions(context) {
535
- const authStorage = AuthStorage.create(PI_AUTH_FILE);
536
535
  const modelReference = optional(context.env.PI_MODEL);
537
536
  const configuredModel = modelReference ? parseModelReference(modelReference) : void 0;
538
537
  const provider = configuredModel?.provider;
539
538
  const apiKey = await resolvePiApiKey(context.env);
540
539
  const baseUrl = optional(context.env.PI_BASE_URL);
541
540
  if ((apiKey || baseUrl) && !provider) throw new Error("PI_API_KEY and PI_BASE_URL require PI_MODEL in provider/model form");
542
- if (apiKey) authStorage.setRuntimeApiKey(provider, apiKey);
543
541
  if (baseUrl) await writeProviderBaseUrlOverride(provider, baseUrl);
544
- const modelRegistry = ModelRegistry.create(authStorage, baseUrl ? PI_MODELS_FILE : void 0);
545
- const model = configuredModel ? modelRegistry.find(configuredModel.provider, configuredModel.modelId) : void 0;
546
- if (modelReference && !model) throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model registry`);
542
+ const modelRuntime = await ModelRuntime.create({
543
+ allowModelNetwork: false,
544
+ authPath: PI_AUTH_FILE,
545
+ modelsPath: baseUrl ? PI_MODELS_FILE : null
546
+ });
547
+ if (apiKey) await modelRuntime.setRuntimeApiKey(provider, apiKey);
548
+ const model = configuredModel ? modelRuntime.getModel(configuredModel.provider, configuredModel.modelId) : void 0;
549
+ if (modelReference && !model) throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model runtime`);
547
550
  const thinkingLevel = readThinkingLevel(context.env.PI_THINKING_LEVEL);
548
551
  return {
549
- authStorage,
550
552
  cwd: process.cwd(),
551
- modelRegistry,
553
+ modelRuntime,
552
554
  ...model ? { model } : {},
553
555
  ...thinkingLevel ? { thinkingLevel } : {}
554
556
  };
@@ -568,7 +570,7 @@ function optional(value) {
568
570
  }
569
571
  function parseModelReference(reference) {
570
572
  const separator = reference.indexOf("/");
571
- if (separator <= 0 || separator === reference.length - 1) throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.1");
573
+ if (separator <= 0 || separator === reference.length - 1) throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.2");
572
574
  return {
573
575
  modelId: reference.slice(separator + 1),
574
576
  provider: reference.slice(0, separator)
@@ -1108,7 +1108,7 @@ function decodeInboundDeliverySnapshots(raw, options) {
1108
1108
  if (delivery.revision !== (previous?.revision ?? 0) + 1) throw new Error(`invalid ${options.label} revision at line ${index + 1}`);
1109
1109
  try {
1110
1110
  if (previous) {
1111
- if (!isValidInboundDeliveryTransition(previous, delivery)) throw new Error("transition");
1111
+ if (!isValidPersistedTransition(previous, delivery, options.acceptLegacySameAttemptClaims ?? false)) throw new Error("transition");
1112
1112
  } else validateNewInboundDelivery(delivery);
1113
1113
  } catch {
1114
1114
  throw new Error(`invalid ${options.label} transition at line ${index + 1}`);
@@ -1153,6 +1153,14 @@ function decodeDelivery(value, payloadCodec) {
1153
1153
  function isEnvelope(value) {
1154
1154
  return isRecord$5(value) && value.version === 1 && "delivery" in value;
1155
1155
  }
1156
+ function isValidPersistedTransition(previous, next, acceptLegacySameAttemptClaims) {
1157
+ if (isValidInboundDeliveryTransition(previous, next)) return true;
1158
+ if (!acceptLegacySameAttemptClaims || previous.state.status !== "pending" || next.state.status !== "leased" || next.attempts !== previous.attempts) return false;
1159
+ return isValidInboundDeliveryTransition(previous, {
1160
+ ...next,
1161
+ attempts: next.attempts + 1
1162
+ });
1163
+ }
1156
1164
  //#endregion
1157
1165
  //#region src/modules/inbound-delivery/infrastructure/persistence/delivery/jsonl-inbound-delivery-repository.ts
1158
1166
  function openJsonlInboundDeliveryRepository(options) {
@@ -1160,6 +1168,7 @@ function openJsonlInboundDeliveryRepository(options) {
1160
1168
  catch: (error) => error,
1161
1169
  try: () => readPersistenceFile(options.filePath)
1162
1170
  }).pipe(Effect.map((raw) => decodeInboundDeliverySnapshots(raw, {
1171
+ ...options.acceptLegacySameAttemptClaims === void 0 ? {} : { acceptLegacySameAttemptClaims: options.acceptLegacySameAttemptClaims },
1163
1172
  label: options.label ?? "Inbound Delivery",
1164
1173
  payload: options.payload
1165
1174
  })), Effect.map((initial) => createInMemoryInboundDeliveryRepository({
@@ -1588,6 +1597,7 @@ function nonEmpty$1(value) {
1588
1597
  //#region src/adapters/compatibility/inbound-delivery/jsonl-feishu-inbox-repository.ts
1589
1598
  function openJsonlFeishuInboxRepository(options) {
1590
1599
  return Effect.runPromise(openJsonlInboundDeliveryRepository({
1600
+ acceptLegacySameAttemptClaims: true,
1591
1601
  filePath: options.filePath,
1592
1602
  label: "Feishu inbox",
1593
1603
  payload: feishuInboundDeliveryPayloadCodec
package/dist/cli.js CHANGED
@@ -416,8 +416,8 @@ function isMissingPath(error) {
416
416
  return error instanceof Error && "code" in error && error.code === "ENOENT";
417
417
  }
418
418
  function projectPackageJson(directory, manifest) {
419
- const pi = manifest.peerDependencies?.["@earendil-works/pi-coding-agent"];
420
- const lark = manifest.peerDependencies?.["@larksuiteoapi/node-sdk"];
419
+ const pi = manifest.dependencies?.["@earendil-works/pi-coding-agent"];
420
+ const lark = manifest.dependencies?.["@larksuiteoapi/node-sdk"];
421
421
  const effect = manifest.dependencies?.effect;
422
422
  if (!pi || !lark || !effect) throw new Error("Rivus package manifest is missing its Effect, Pi, or Feishu dependency range");
423
423
  const projectName = sanitizePackageName(basename(directory));
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
4
4
  import { join, relative } from "node:path";
5
5
  import { Effect } from "effect";
6
6
  import * as Lark from "@larksuiteoapi/node-sdk";
7
- import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent";
7
+ import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";
8
8
  import {
9
9
  createAgentsMdInstructionsProvider,
10
10
  createAgentHarness,
@@ -720,7 +720,6 @@ async function resolveFeishuBotOpenId(
720
720
  }
721
721
 
722
722
  async function createPiSessionOptions(context: RivusDeploymentBootstrapContext): Promise<PiSessionOptions> {
723
- const authStorage = AuthStorage.create(PI_AUTH_FILE);
724
723
  const modelReference = optional(context.env.PI_MODEL);
725
724
  const configuredModel = modelReference ? parseModelReference(modelReference) : undefined;
726
725
  const provider = configuredModel?.provider;
@@ -729,16 +728,19 @@ async function createPiSessionOptions(context: RivusDeploymentBootstrapContext):
729
728
  if ((apiKey || baseUrl) && !provider) {
730
729
  throw new Error("PI_API_KEY and PI_BASE_URL require PI_MODEL in provider/model form");
731
730
  }
732
- if (apiKey) authStorage.setRuntimeApiKey(provider!, apiKey);
733
731
  if (baseUrl) await writeProviderBaseUrlOverride(provider!, baseUrl);
734
- const modelRegistry = ModelRegistry.create(authStorage, baseUrl ? PI_MODELS_FILE : undefined);
735
- const model = configuredModel ? modelRegistry.find(configuredModel.provider, configuredModel.modelId) : undefined;
736
- if (modelReference && !model) throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model registry`);
732
+ const modelRuntime = await ModelRuntime.create({
733
+ allowModelNetwork: false,
734
+ authPath: PI_AUTH_FILE,
735
+ modelsPath: baseUrl ? PI_MODELS_FILE : null
736
+ });
737
+ if (apiKey) await modelRuntime.setRuntimeApiKey(provider!, apiKey);
738
+ const model = configuredModel ? modelRuntime.getModel(configuredModel.provider, configuredModel.modelId) : undefined;
739
+ if (modelReference && !model) throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model runtime`);
737
740
  const thinkingLevel = readThinkingLevel(context.env.PI_THINKING_LEVEL);
738
741
  return {
739
- authStorage,
740
742
  cwd: process.cwd(),
741
- modelRegistry,
743
+ modelRuntime,
742
744
  ...(model ? { model } : {}),
743
745
  ...(thinkingLevel ? { thinkingLevel } : {})
744
746
  };
@@ -762,7 +764,7 @@ function optional(value: string | undefined): string | undefined {
762
764
  function parseModelReference(reference: string): { readonly modelId: string; readonly provider: string } {
763
765
  const separator = reference.indexOf("/");
764
766
  if (separator <= 0 || separator === reference.length - 1) {
765
- throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.1");
767
+ throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.2");
766
768
  }
767
769
  return { modelId: reference.slice(separator + 1), provider: reference.slice(0, separator) };
768
770
  }
@@ -2,7 +2,7 @@ import { mkdir } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { Effect } from "effect";
4
4
  import * as Lark from "@larksuiteoapi/node-sdk";
5
- import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@earendil-works/pi-coding-agent";
5
+ import { createAgentSession, ModelRuntime, SessionManager } from "@earendil-works/pi-coding-agent";
6
6
  import {
7
7
  createJsonFetchRequest,
8
8
  createJsonFileFeishuCardTargetRegistry,
@@ -164,44 +164,45 @@ function createLazyFeishuWebSocketClient(options: {
164
164
  }
165
165
 
166
166
  async function createPiSessionOptions(context: RivusDaemonBootstrapContext): Promise<PiSessionOptions> {
167
- const authStorage = AuthStorage.create(PI_AUTH_FILE);
168
167
  const provider = readProviderFromModel(context.config.pi.model);
169
168
 
170
- if (context.config.pi.apiKey) {
169
+ if (context.config.pi.baseUrl) {
171
170
  if (!provider) {
172
- throw new Error("PI_API_KEY requires PI_MODEL in provider/model form, for example zai/glm-5.1");
171
+ throw new Error("PI_BASE_URL requires PI_MODEL in provider/model form, for example zai/glm-5.2");
173
172
  }
174
- authStorage.setRuntimeApiKey(provider, context.config.pi.apiKey);
173
+ await writeProviderBaseUrlOverride(provider, context.config.pi.baseUrl);
175
174
  }
176
175
 
177
- if (context.config.pi.baseUrl) {
176
+ const modelRuntime = await ModelRuntime.create({
177
+ allowModelNetwork: false,
178
+ authPath: PI_AUTH_FILE,
179
+ modelsPath: context.config.pi.baseUrl ? PI_MODELS_FILE : null
180
+ });
181
+ if (context.config.pi.apiKey) {
178
182
  if (!provider) {
179
- throw new Error("PI_BASE_URL requires PI_MODEL in provider/model form, for example zai/glm-5.1");
183
+ throw new Error("PI_API_KEY requires PI_MODEL in provider/model form, for example zai/glm-5.2");
180
184
  }
181
- await writeProviderBaseUrlOverride(provider, context.config.pi.baseUrl);
185
+ await modelRuntime.setRuntimeApiKey(provider, context.config.pi.apiKey);
182
186
  }
183
-
184
- const modelRegistry = ModelRegistry.create(authStorage, context.config.pi.baseUrl ? PI_MODELS_FILE : undefined);
185
- const model = context.config.pi.model ? resolveConfiguredPiModel(modelRegistry, context.config.pi.model) : undefined;
187
+ const model = context.config.pi.model ? resolveConfiguredPiModel(modelRuntime, context.config.pi.model) : undefined;
186
188
  return {
187
- authStorage,
188
189
  cwd: process.cwd(),
189
- modelRegistry,
190
+ modelRuntime,
190
191
  ...(model ? { model } : {}),
191
192
  ...(context.config.pi.thinkingLevel ? { thinkingLevel: context.config.pi.thinkingLevel } : {})
192
193
  };
193
194
  }
194
195
 
195
- function resolveConfiguredPiModel(modelRegistry: ModelRegistry, modelReference: string): PiSessionOptions["model"] {
196
+ function resolveConfiguredPiModel(modelRuntime: ModelRuntime, modelReference: string): PiSessionOptions["model"] {
196
197
  const provider = readProviderFromModel(modelReference);
197
198
  const modelId = readModelIdFromModel(modelReference);
198
199
  if (!provider || !modelId) {
199
- throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.1");
200
+ throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.2");
200
201
  }
201
202
 
202
- const model = modelRegistry.find(provider, modelId);
203
+ const model = modelRuntime.getModel(provider, modelId);
203
204
  if (!model) {
204
- throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model registry`);
205
+ throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model runtime`);
205
206
  }
206
207
  return model as PiSessionOptions["model"];
207
208
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivus/agent",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "A local agent daemon core built around a usable agent harness and domain events.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -88,35 +88,28 @@
88
88
  "version-packages:ci": "npm run version-packages && npm run check"
89
89
  },
90
90
  "dependencies": {
91
+ "@earendil-works/pi-coding-agent": "0.84.4",
92
+ "@larksuiteoapi/node-sdk": "1.71.1",
91
93
  "@opentelemetry/api": "^1.9.1",
92
94
  "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0",
93
95
  "@opentelemetry/resources": "^2.9.0",
94
96
  "@opentelemetry/sdk-trace-base": "^2.9.0",
95
97
  "@opentelemetry/sdk-trace-node": "^2.9.0",
98
+ "axios": "1.18.0",
96
99
  "effect": "^3.21.4",
97
100
  "typebox": "^1.1.38"
98
101
  },
99
102
  "peerDependencies": {
100
- "@agentclientprotocol/sdk": "^1.3.0",
101
- "@earendil-works/pi-coding-agent": "0.80.6",
102
- "@larksuiteoapi/node-sdk": "^1.70.0"
103
+ "@agentclientprotocol/sdk": "^1.3.0"
103
104
  },
104
105
  "peerDependenciesMeta": {
105
106
  "@agentclientprotocol/sdk": {
106
107
  "optional": true
107
- },
108
- "@earendil-works/pi-coding-agent": {
109
- "optional": true
110
- },
111
- "@larksuiteoapi/node-sdk": {
112
- "optional": true
113
108
  }
114
109
  },
115
110
  "devDependencies": {
116
111
  "@agentclientprotocol/sdk": "^1.3.0",
117
112
  "@changesets/cli": "^2.31.1",
118
- "@earendil-works/pi-coding-agent": "0.80.6",
119
- "@larksuiteoapi/node-sdk": "1.71.1",
120
113
  "@types/node": "24.13.3",
121
114
  "@vitest/coverage-v8": "4.1.10",
122
115
  "jscpd": "4.2.5",
@@ -128,7 +121,6 @@
128
121
  "node": "^24.11.0"
129
122
  },
130
123
  "overrides": {
131
- "axios": "1.16.0",
132
124
  "vite": "npm:@voidzero-dev/vite-plus-core@0.2.4"
133
125
  },
134
126
  "devEngines": {