Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions src/data/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,42 +69,8 @@ const ACTORS: Integration[] = [
},
];

const AGENTOS: Integration[] = [
{
title: "Flue",
description: "Run Flue agents inside agentOS sandboxes.",
slug: "flue",
category: "Frameworks",
icon: { src: "/images/vendors/flue.svg" },
badge: "Beta",
sourceUrl:
"https://github.com/rivet-dev/rivet/tree/main/integrations/flue-runtime",
},
{
title: "Vercel Eve",
description: "Use agentOS as the execution layer for Vercel Eve.",
slug: "vercel-eve",
category: "Frameworks",
icon: { src: "/images/vendors/eve.svg" },
badge: "Beta",
sourceUrl:
"https://github.com/rivet-dev/rivet/tree/main/integrations/workflow-world",
},
{
title: "Rivet Actors",
description: "Run agentOS on Rivet Actors for persistence and scheduling.",
slug: "rivet-actors",
category: "Platform",
icon: { src: "/images/frameworks/rivet.svg" },
exampleUrl: "https://github.com/rivet-dev/rivet/tree/main/examples/agent-os",
sourceUrl:
"https://github.com/rivet-dev/rivet/tree/main/rivetkit-typescript/packages/rivetkit/src/agent-os",
},
];

export const INTEGRATIONS: Record<string, Integration[]> = {
actors: ACTORS,
agentos: AGENTOS,
};

/** Cards on a product's Integrations overview page. */
Expand Down
104 changes: 34 additions & 70 deletions src/data/registry-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,66 +54,48 @@ const TYPE_LABELS: Record<string, string> = {
deploy: "Deploy",
};

const SANDBOX_INSTALL = "npm install @rivet-dev/agentos-sandbox sandbox-agent";

// Turn a package's last path segment into a JS identifier, e.g.
// `@agentos-software/build-essential` -> `buildEssential`.
function toIdent(packageName: string): string {
return packageName
.replace(/^.*\//, "")
.replace(/-([a-z0-9])/g, (_, char: string) => char.toUpperCase());
}

function softwareExample(packageName: string): string {
const ident = toIdent(packageName);
return `import { agentOS, setup } from "@rivet-dev/agentos";
import ${ident} from "${packageName}";

// Add the package to your VM's software so its commands are available inside the VM
const vm = agentOS({ software: [${ident}] });

export const registry = setup({ use: { vm } });`;
}

function agentExample(title: string, agentId: string, packageName: string): string {
return `import { agentOS, setup } from "@rivet-dev/agentos";
import ${agentId} from "${packageName}";

// Register the ${title} adapter as VM software
const vm = agentOS({ software: [${agentId}] });

export const registry = setup({ use: { vm } });

// Then start a session from your client with the "${agentId}" agent id:
// await agent.openSession({ agent: "${agentId}", env: { /* API keys */ } });`;
const SANDBOX_INSTALL = "npm install @rivet-dev/agentos-core @rivet-dev/agentos-sandbox sandbox-agent";

function softwareExample(artifactName: string): string {
return `import { AgentOs } from "@rivet-dev/agentos-core";

// Each release publishes registry packages next to a manifest. Use a release
// version, or \`latest\`.
const base = "https://releases.rivet.dev/agent-os/latest/software/";
const { artifacts } = await (await fetch(\`\${base}manifest.json\`)).json();
const pkg = artifacts.find((artifact) => artifact.name === "${artifactName}");

const vm = await AgentOs.create();

// The bytes are verified against the digest before the package's commands
// appear on /opt/agentos/bin.
await vm.software.install({
type: "url",
url: new URL(pkg.path, base).href,
expectedDigest: pkg.digest,
});`;
}

function sandboxExample(provider: { slug: string; title: string } | null): string {
const [importLine, comment, sandbox] = provider
? [
`import { ${provider.slug} } from "sandbox-agent/${provider.slug}";`,
`// Start a ${provider.title}-backed sandbox and mount it into the VM`,
`${provider.slug}()`,
`sandboxAgentProvider(${provider.slug}())`,
]
: [
`import { docker } from "sandbox-agent/docker";`,
"// Mount the sandbox filesystem and expose its process bindings to the VM",
"docker()",
"// Mount the sandbox filesystem and register its host functions in the VM",
"sandboxAgentProvider(docker())",
];
return `import { agentOS, setup } from "@rivet-dev/agentos";
import { createSandboxFs, createSandboxBindings } from "@rivet-dev/agentos-sandbox";
import { SandboxAgent } from "sandbox-agent";
return `import { AgentOs } from "@rivet-dev/agentos-core";
import { sandboxAgentProvider } from "@rivet-dev/agentos-sandbox";
${importLine}

${comment}
const sandbox = await SandboxAgent.start({ sandbox: ${sandbox} });

const vm = agentOS({
mounts: [{ path: "/home/agentos/sandbox", plugin: createSandboxFs({ client: sandbox }) }],
bindings: [createSandboxBindings({ client: sandbox })],
});

export const registry = setup({ use: { vm } });`;
const vm = await AgentOs.create({
sandbox: { provider: ${sandbox} },
});`;
}

/** What a reader does with an entry: install it, set it up, or read a note. */
Expand All @@ -130,15 +112,7 @@ function usage(entry: RegistryEntry): Pick<RegistryDoc, "install" | "setup" | "n
case "external":
return {};
case "docs":
return entry.package && entry.agentId
? {
setup: {
title: "Add to agentOS",
summary: `Register the ${entry.title} adapter as VM software, then open a session with the "${entry.agentId}" agent id.`,
code: agentExample(entry.title, entry.agentId, entry.package),
},
}
: { note: "Built into agentOS, with no separate install. See the docs for setup and usage." };
return { note: "Built into agentOS, with no separate install. See the docs for setup and usage." };
case "config":
return {
setup: {
Expand All @@ -150,11 +124,11 @@ function usage(entry: RegistryEntry): Pick<RegistryDoc, "install" | "setup" | "n
case "available":
if (isSoftware) {
return {
install: `npm install ${entry.package}`,
setup: {
title: "Add to agentOS",
summary: "Register it as VM software so its commands are available inside the VM.",
code: softwareExample(entry.package),
summary:
"Install the package's .aospkg release artifact into a VM so its commands are available inside the VM.",
code: softwareExample(entry.artifactName ?? entry.slug),
},
};
}
Expand All @@ -165,22 +139,12 @@ function usage(entry: RegistryEntry): Pick<RegistryDoc, "install" | "setup" | "n
title: "Add to agentOS",
summary: isSandboxExt
? `Mount a ${entry.title} sandbox into the VM with @rivet-dev/agentos-sandbox.`
: "Mount the sandbox filesystem and register the process bindings with @rivet-dev/agentos-sandbox.",
: "Mount the sandbox filesystem and register its host functions with @rivet-dev/agentos-sandbox.",
code: sandboxExample(isSandboxExt ? entry : null),
},
};
}
if (entry.types.includes("agent") && entry.agentId) {
return {
install: `npm install ${entry.package}`,
setup: {
title: "Add to agentOS",
summary: `Register the ${entry.title} adapter as VM software, then open a session with the "${entry.agentId}" agent id.`,
code: agentExample(entry.title, entry.agentId, entry.package),
},
};
}
return { install: `npm install ${entry.package}` };
return entry.package ? { install: `npm install ${entry.package}` } : {};
}
}

Expand Down
77 changes: 26 additions & 51 deletions src/data/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ export interface RegistryEntryBase extends SeoOverrides {

export interface RegistryEntryAvailable extends RegistryEntryBase {
status: "available";
package: string;
// npm package that provides it. Registry software has no npm package; it
// ships as an immutable `.aospkg` release artifact named `artifactName`.
package?: string;
artifactName?: string;
}

export interface RegistryEntryComingSoon extends RegistryEntryBase {
Expand Down Expand Up @@ -108,11 +111,12 @@ import rawGenerated from "@/generated/artifacts/registry.json";
// for this site rather than editing every package manifest upstream.
const generated = {
...rawGenerated,
entries: rawGenerated.entries.map((entry) =>
typeof entry.docsHref === "string" && entry.docsHref.startsWith("/docs/")
? { ...entry, docsHref: `/agentos${entry.docsHref}` }
: entry,
),
entries: rawGenerated.entries.map((entry) => {
const docsHref = (entry as { docsHref?: unknown }).docsHref;
return typeof docsHref === "string" && docsHref.startsWith("/docs/")
? { ...entry, docsHref: `/agentos${docsHref}` }
: entry;
}),
} as typeof rawGenerated;
import { DEPLOY_TARGETS } from "./deploy-targets";

Expand All @@ -129,18 +133,6 @@ const generatedRegistry: RegistryEntry[] = generated.entries.map(
);

const curatedRegistry: RegistryEntry[] = [
// Agents
{
slug: "custom-agent",
title: "Custom Agent",
status: "docs",
docsHref: "/agentos/docs/agents/custom",
description:
"Bring your own coding agent to agentOS by speaking the Agent Client Protocol (ACP) inside the VM.",
types: ["agent"],
icon: "Wrench",
},

// File Systems
{
slug: "host-dir",
Expand All @@ -152,50 +144,42 @@ const curatedRegistry: RegistryEntry[] = [
"Project a real host directory into the VM, Docker-style. The guest sees only the mounted subtree, never the wider host filesystem.",
types: ["file-system"],
icon: "HardDrive",
configExample: `import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";
configExample: `import { AgentOs } from "@rivet-dev/agentos-core";

const vm = agentOS({
software: [pi],
const vm = await AgentOs.create({
mounts: [
{
path: "/home/agentos/repo",
plugin: { id: "host_dir", config: { hostPath: "/path/to/repo" } },
readOnly: true,
},
],
});

export const registry = setup({ use: { vm } });`,
});`,
},
{
slug: "s3",
title: "S3",
status: "config",
configId: 'plugin: { id: "s3" }',
configId: 'plugin: { id: "chunked_s3" }',
docsHref: "/agentos/docs/filesystem",
description:
"Mount an S3-compatible bucket as a filesystem. File contents are chunked into S3 objects, keeping large files, partial reads/writes, and snapshots efficient.",
types: ["file-system"],
featured: true,
image: "/images/registry/s3.svg",
configExample: `import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";
configExample: `import { AgentOs } from "@rivet-dev/agentos-core";

const vm = agentOS({
software: [pi],
const vm = await AgentOs.create({
mounts: [
{
path: "/home/agentos/data",
plugin: {
id: "s3",
id: "chunked_s3",
config: { bucket: "my-bucket", prefix: "agent-data/", region: "us-east-1" },
},
},
],
});

export const registry = setup({ use: { vm } });`,
});`,
},
{
slug: "google-drive",
Expand All @@ -208,11 +192,9 @@ export const registry = setup({ use: { vm } });`,
types: ["file-system"],
featured: true,
image: "/images/registry/google-drive.svg",
configExample: `import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";
configExample: `import { AgentOs } from "@rivet-dev/agentos-core";

const vm = agentOS({
software: [pi],
const vm = await AgentOs.create({
mounts: [
{
path: "/home/agentos/drive",
Expand All @@ -228,9 +210,7 @@ const vm = agentOS({
},
},
],
});

export const registry = setup({ use: { vm } });`,
});`,
},
{
slug: "memory",
Expand All @@ -242,21 +222,16 @@ export const registry = setup({ use: { vm } });`,
"Mount an ephemeral in-memory directory. Fast scratch space that is discarded when the VM is destroyed.",
types: ["file-system"],
icon: "HardDrive",
configExample: `import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";
configExample: `import { AgentOs } from "@rivet-dev/agentos-core";

const vm = agentOS({
software: [pi],
const vm = await AgentOs.create({
mounts: [
// Ephemeral scratch space for large intermediate artifacts (build
// output, downloads, caches). Lives in memory only: it never touches
// the VM's persisted filesystem, so it stays out of snapshots and is
// discarded when the VM is disposed.
// output, downloads, caches). Lives in memory only and is discarded when
// the VM is disposed.
{ path: "/tmp/scratch", plugin: { id: "memory", config: {} } },
],
});

export const registry = setup({ use: { vm } });`,
});`,
},
// Bindings
{
Expand Down
20 changes: 7 additions & 13 deletions src/sitemap/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,9 @@ function withOverviewTitle(

/**
* A product's Documentation sidebar: its bundle's own sidebar, plus the pages
* this site adds to it. The Registry is a fold at the end of the opening
* General group, and a non-site product's Integrations becomes a fold just above the
* bundle's closing Reference group (or at the end when there is none).
* this site adds to it. The Registry and a non-site product's Integrations are
* folds at the end of the opening General group, so they sit inside a group
* like every other page.
*/
function docsSidebar(meta: ProductMetadata, bundleDocs: SidebarItem[]): SidebarItem[] {
const has = (section: "integrations" | "registry") =>
Expand All @@ -265,25 +265,19 @@ function docsSidebar(meta: ProductMetadata, bundleDocs: SidebarItem[]): SidebarI
has("integrations") && meta.id !== SITE_INTEGRATIONS_PRODUCT
? integrationFold(meta.id)
: undefined;
const folds = [...(has("registry") ? [registryFold(meta.id)] : []), ...(fold ? [fold] : [])];
const docs = [...bundleDocs];
if (has("registry")) {
const registry = registryFold(meta.id);
if (folds.length > 0) {
const general = docs.findIndex(
(item) => "pages" in item && "title" in item && item.title === "General",
);
const group = docs[general];
if (group && "pages" in group) {
docs[general] = { ...group, pages: [...group.pages, registry] };
docs[general] = { ...group, pages: [...group.pages, ...folds] };
} else {
docs.unshift(registry);
docs.unshift(...folds);
}
}
if (fold) {
const reference = docs.findIndex(
(item) => "title" in item && item.title === "Reference",
);
docs.splice(reference === -1 ? docs.length : reference, 0, fold);
}
return docs;
}

Expand Down
Loading