Skip to content

Commit b359079

Browse files
committed
fix: resolve adapter packages from software package dependencies
_resolveHostPackageJson now tries require.resolve from each software root's host directory before falling back to moduleAccessCwd. This lets pi-acp (a dependency of @rivet-dev/agent-os-pi) be found when the software package is passed via software: [pi]. Also update sessions.ts quickstart to pass software: [pi].
1 parent e82ace3 commit b359079

File tree

2 files changed

+61
-28
lines changed

2 files changed

+61
-28
lines changed

examples/quickstart/src/sessions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AgentOs } from "@rivet-dev/agent-os";
2+
import pi from "@rivet-dev/agent-os-pi";
23

3-
const os = await AgentOs.create();
4+
const os = await AgentOs.create({ software: [pi] });
45
const { sessionId } = await os.createSession("pi");
56

67
os.onSessionEvent(sessionId, (event) => {

packages/core/src/agent-os.ts

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
relative as relativeHostPath,
2020
resolve as resolveHostPath,
2121
} from "node:path";
22+
import { createRequire } from "node:module";
2223
import { fileURLToPath } from "node:url";
2324
import { type ToolKit, validateToolkits } from "./host-tools.js";
2425
import { generateToolReference } from "./host-tools-prompt.js";
@@ -2537,23 +2538,7 @@ export class AgentOs {
25372538
}
25382539

25392540
private _resolvePackageBin(packageName: string, binName?: string): string {
2540-
const vmPrefix = `/root/node_modules/${packageName}`;
2541-
let hostPkgJsonPath: string | null = null;
2542-
for (const root of this._softwareRoots) {
2543-
if (root.vmPath === vmPrefix) {
2544-
hostPkgJsonPath = join(root.hostPath, "package.json");
2545-
break;
2546-
}
2547-
}
2548-
// Fall back to CWD-based node_modules.
2549-
if (!hostPkgJsonPath) {
2550-
hostPkgJsonPath = join(
2551-
this._moduleAccessCwd,
2552-
"node_modules",
2553-
packageName,
2554-
"package.json",
2555-
);
2556-
}
2541+
const hostPkgJsonPath = this._resolveHostPackageJson(packageName);
25572542
const pkg = JSON.parse(readFileSync(hostPkgJsonPath, "utf-8"));
25582543

25592544
let binEntry: string | undefined;
@@ -2575,16 +2560,7 @@ export class AgentOs {
25752560

25762561
private _resolvePackageDir(packageName: string): string {
25772562
const vmPrefix = `/root/node_modules/${packageName}`;
2578-
let hostPackageDir: string | null = null;
2579-
for (const root of this._softwareRoots) {
2580-
if (root.vmPath === vmPrefix) {
2581-
hostPackageDir = root.hostPath;
2582-
break;
2583-
}
2584-
}
2585-
if (!hostPackageDir) {
2586-
hostPackageDir = join(this._moduleAccessCwd, "node_modules", packageName);
2587-
}
2563+
const hostPackageDir = dirname(this._resolveHostPackageJson(packageName));
25882564

25892565
const resolvedHostDir = realpathSync(hostPackageDir);
25902566
const repoNodeModules = join(
@@ -2612,6 +2588,62 @@ export class AgentOs {
26122588
return vmPrefix;
26132589
}
26142590

2591+
/**
2592+
* Resolve the host-side package.json path for a package.
2593+
* Tries (in order):
2594+
* 1. Software roots (packages registered via `software: [...]`)
2595+
* 2. moduleAccessCwd/node_modules/<package>
2596+
* 3. Node require.resolve from each software root (finds dependencies of software packages)
2597+
* 4. Node require.resolve from moduleAccessCwd (handles pnpm hoisting)
2598+
*/
2599+
private _resolveHostPackageJson(packageName: string): string {
2600+
const vmPrefix = `/root/node_modules/${packageName}`;
2601+
2602+
// 1. Check software roots for a direct match.
2603+
for (const root of this._softwareRoots) {
2604+
if (root.vmPath === vmPrefix) {
2605+
return join(root.hostPath, "package.json");
2606+
}
2607+
}
2608+
2609+
// 2. Check moduleAccessCwd/node_modules.
2610+
const cwdCandidate = join(
2611+
this._moduleAccessCwd,
2612+
"node_modules",
2613+
packageName,
2614+
"package.json",
2615+
);
2616+
if (existsSync(cwdCandidate)) {
2617+
return cwdCandidate;
2618+
}
2619+
2620+
// 3. Try resolving from each software root's host directory.
2621+
// This finds dependencies of software packages (e.g. pi-acp
2622+
// as a dependency of @rivet-dev/agent-os-pi).
2623+
for (const root of this._softwareRoots) {
2624+
try {
2625+
const req = createRequire(join(root.hostPath, "package.json"));
2626+
return req.resolve(`${packageName}/package.json`);
2627+
} catch {
2628+
// Not resolvable from this root, try next.
2629+
}
2630+
}
2631+
2632+
// 4. Try Node resolution from moduleAccessCwd.
2633+
try {
2634+
const req = createRequire(
2635+
join(this._moduleAccessCwd, "package.json"),
2636+
);
2637+
return req.resolve(`${packageName}/package.json`);
2638+
} catch {
2639+
// Fall through to throw a descriptive error.
2640+
}
2641+
2642+
throw new Error(
2643+
`Cannot find package '${packageName}'. Ensure it is installed or provided via the software option.`,
2644+
);
2645+
}
2646+
26152647
/**
26162648
* Resolve an agent config by ID. Package-provided configs take
26172649
* precedence over the hardcoded AGENT_CONFIGS.

0 commit comments

Comments
 (0)