Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5ecf272
feat(kernel-utils): Add importHook
grypez Jul 10, 2025
8c2bac1
feat(cli): Add two node holes to bundleFile
grypez Jul 8, 2025
d35aec1
feat(ocap-kernel): Add minorly configurable vat endowments
grypez Jul 16, 2025
74d057c
feat(nodejs): Add ollama fetch endowment
grypez Jul 16, 2025
ea7bb44
feat(nodejs): Add ollama abort endowment
grypez Jul 16, 2025
429186b
feat(kernel-browser-runtime): browserify fs and path
grypez Jul 17, 2025
0b0059a
feat(agents): Initial commit
grypez Jul 8, 2025
11ecc74
feat(nodejs): Expand host name
grypez Jul 17, 2025
837ca47
feat(agents): Add ollama:pull script
grypez Jul 17, 2025
4eccf15
chore(agents): Add build:vats command
grypez Jul 18, 2025
25dfa07
test(agents): Run llm integration only in dev mode
grypez Jul 18, 2025
bbaf161
test(agents): Provide basic test coverage
grypez Jul 18, 2025
882b18e
thresholds
grypez Jul 18, 2025
4931b47
remove unused
grypez Jul 18, 2025
cc22e7d
chore(kernel-browser-runtime): Add web-llm dependency
grypez Jul 21, 2025
015ed3b
refactor(nodejs): Comport OllamaLlmProvider
grypez Jul 21, 2025
8e1be51
refactor(agents): Export implementations from package.json
grypez Jul 22, 2025
d57072a
refactor(agents): Mimic kernel-store package pattern
grypez Jul 22, 2025
cb70398
fix(agents): Remove unused build:vats directive
grypez Jul 22, 2025
dd51953
refactor(kernel-test): Use ollama/browser llm-provider
grypez Jul 22, 2025
42754e5
refactor(nodejs): Move llm-provider implementation to agents
grypez Jul 22, 2025
0e41e16
thresholds
grypez Jul 22, 2025
0e47822
test(kernel-test): Only run agents in test:agents
grypez Jul 22, 2025
22d0ee7
fix: Remove unused dependencies
grypez Jul 22, 2025
f54a104
feat(kernel-ui): Chat skeleton
grypez Jul 23, 2025
9d77130
chore(extension): Add agents dep
grypez Jul 28, 2025
bbede4a
feat(ocap-kernel): Add more endowments
grypez Jul 28, 2025
f4b1316
fix(agents): Response parsing
grypez Jul 28, 2025
6132555
feat(agents): Add a WASM model
grypez Jul 28, 2025
d8e9e40
feat(kernel-browser-runtime): Add a tiny llama
grypez Jul 28, 2025
351754e
feat(extension): Use llm vat power in sample-vat
grypez Jul 28, 2025
dd551d5
chore(kernel-ui): lint
grypez Jul 28, 2025
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
10 changes: 10 additions & 0 deletions packages/agents/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

[Unreleased]: https://github.com/MetaMask/ocap-kernel/
15 changes: 15 additions & 0 deletions packages/agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# `@ocap/agents`

A starting point for LLM integration

## Installation

`yarn add @ocap/agents`

or

`npm install @ocap/agents`

## Contributing

This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/ocap-kernel#readme).
3 changes: 3 additions & 0 deletions packages/agents/llm-provider/ollama-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable import-x/unambiguous */
// Re-exported for compatibility with Browserify.
module.exports = require('../dist/llm-provider/ollama-browser.cjs');
3 changes: 3 additions & 0 deletions packages/agents/llm-provider/ollama.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable import-x/unambiguous */
// Re-exported for compatibility with Browserify.
module.exports = require('../dist/llm-provider/ollama.cjs');
3 changes: 3 additions & 0 deletions packages/agents/llm-provider/web-llm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable import-x/unambiguous */
// Re-exported for compatibility with Browserify.
module.exports = require('../dist/llm-provider/web-llm.cjs');
121 changes: 121 additions & 0 deletions packages/agents/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"name": "@ocap/agents",
"version": "0.0.0",
"private": true,
"description": "A starting point for LLM integration",
"homepage": "https://github.com/MetaMask/ocap-kernel/tree/main/packages/agents#readme",
"bugs": {
"url": "https://github.com/MetaMask/ocap-kernel/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/ocap-kernel.git"
},
"type": "module",
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./llm-provider/ollama": {
"import": {
"types": "./dist/llm-provider/ollama.d.mts",
"default": "./dist/llm-provider/ollama.mjs"
},
"require": {
"types": "./dist/llm-provider/ollama.d.cts",
"default": "./dist/llm-provider/ollama.cjs"
}
},
"./llm-provider/ollama-browser": {
"import": {
"types": "./dist/llm-provider/ollama-browser.d.mts",
"default": "./dist/llm-provider/ollama-browser.mjs"
},
"require": {
"types": "./dist/llm-provider/ollama-browser.d.cts",
"default": "./dist/llm-provider/ollama-browser.cjs"
}
},
"./llm-provider/web-llm": {
"import": {
"types": "./dist/llm-provider/web-llm.d.mts",
"default": "./dist/llm-provider/web-llm.mjs"
},
"require": {
"types": "./dist/llm-provider/web-llm.d.cts",
"default": "./dist/llm-provider/web-llm.cjs"
}
}
},
"files": [
"dist/",
"wasm/"
],
"scripts": {
"build": "ts-bridge --project tsconfig.build.json --clean",
"build:docs": "typedoc",
"changelog:validate": "../../scripts/validate-changelog.sh @ocap/agents",
"clean": "rimraf --glob './*.tsbuildinfo' ./.eslintcache ./coverage ./dist",
"lint": "yarn lint:eslint && yarn lint:misc --check && yarn constraints && yarn lint:dependencies",
"lint:dependencies": "depcheck",
"lint:eslint": "eslint . --cache",
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write && yarn constraints --fix && yarn lint:dependencies",
"lint:misc": "prettier --no-error-on-unmatched-pattern '**/*.json' '**/*.md' '**/*.html' '!**/CHANGELOG.old.md' '**/*.yml' '!.yarnrc.yml' '!merged-packages/**' --ignore-path ../../.gitignore",
"ollama:pull": "node scripts/ollama-pull.js",
"publish:preview": "yarn npm publish --tag preview",
"test": "vitest run --config vitest.config.ts",
"test:clean": "yarn test --no-cache --coverage.clean",
"test:dev": "yarn test --mode development",
"test:verbose": "yarn test --reporter verbose",
"test:watch": "vitest --config vitest.config.ts"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.17.4",
"@metamask/auto-changelog": "^5.0.1",
"@metamask/eslint-config": "^14.0.0",
"@metamask/eslint-config-nodejs": "^14.0.0",
"@metamask/eslint-config-typescript": "^14.0.0",
"@ocap/cli": "workspace:^",
"@ocap/test-utils": "workspace:^",
"@ts-bridge/cli": "^0.6.3",
"@ts-bridge/shims": "^0.1.1",
"@types/node": "^22.13.1",
"@typescript-eslint/eslint-plugin": "^8.29.0",
"@typescript-eslint/parser": "^8.29.0",
"@typescript-eslint/utils": "^8.29.0",
"@vitest/eslint-plugin": "^1.1.44",
"depcheck": "^1.4.7",
"eslint": "^9.23.0",
"eslint-config-prettier": "^10.1.1",
"eslint-import-resolver-typescript": "^4.3.1",
"eslint-plugin-import-x": "^4.10.0",
"eslint-plugin-jsdoc": "^50.6.9",
"eslint-plugin-n": "^17.17.0",
"eslint-plugin-prettier": "^5.2.6",
"eslint-plugin-promise": "^7.2.1",
"prettier": "^3.5.3",
"rimraf": "^6.0.1",
"typedoc": "^0.28.1",
"typescript": "~5.8.2",
"typescript-eslint": "^8.29.0",
"vite": "^6.3.5",
"vitest": "^3.1.3"
},
"engines": {
"node": "^20 || >=22"
},
"dependencies": {
"@endo/far": "^1.1.11",
"@metamask/streams": "workspace:^",
"@mlc-ai/web-llm": "^0.2.79",
"ollama": "^0.5.16"
}
}
38 changes: 38 additions & 0 deletions packages/agents/scripts/ollama-pull.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Ollama } from 'ollama';

main().catch(console.error);

/**
* The main function for the script.
*/
async function main() {
// Make a new ollama client.
const ollama = new Ollama({ host: 'http://localhost:11434' });

let nDots = 0;
const interval = setInterval(() => (nDots = (nDots + 1) % 4), 250);
try {
const model = process.argv[2];
const labelDuring = `Pulling ${model}`;
const labelAfter = `Pulled ${model}`;
const makeProgress = (fraction) =>
[
labelDuring,
`${'.'.repeat(nDots)}${' '.repeat(4 - nDots)}`,
'[',
`${'='.repeat(Math.floor(fraction * 10))}`,
`${' '.repeat(10 - Math.floor(fraction * 10))}`,
']',
` ${Math.floor(fraction * 100)}%`,
].join('');
const result = await ollama.pull({ model, stream: true });
for await (const chunk of result) {
process.stdout.write(`${makeProgress(chunk.completed / chunk.total)}\r`);
}
console.log(
`${labelAfter} ${' '.repeat(15 + labelDuring.length - labelAfter.length)}`,
);
} finally {
clearInterval(interval);
}
}
12 changes: 12 additions & 0 deletions packages/agents/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* The default archetypes to use when no archetype is provided. LLM service
* providers are not required to provide every model recorded here. The cost of
* this freedom is they should declare their own default archetype values.
*/
export const defaultArchetypes = {
general: 'llama3.2:latest',
fast: 'llama3.2:latest',
thinker: 'deepseek-r1:3b',
'code:writer': 'llama3.2:latest',
'code:reader': 'llama3.2:latest',
} as const;
11 changes: 11 additions & 0 deletions packages/agents/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export { makeLlmService } from './llm-service.ts';
export type {
InstanceConfig,
LlmInstance,
LlmProvider,
Message,
ModelArchetype,
ModelConfig,
} from './types.ts';
export { defaultArchetypes } from './constants.ts';
export { parseInstanceConfig } from './utils.ts';
21 changes: 21 additions & 0 deletions packages/agents/src/llm-provider/ollama-browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Ollama } from 'ollama/browser';

import { makeOllamaBaseLlmProvider } from './ollama-shared.ts';
import type { OllamaFace, OllamaLlmProviderOptions } from './ollama-shared.ts';
import type { LlmProvider } from '../types.ts';

/**
* Make an LLM provider that uses the `ollama/browser` import from ollama.
*
* @see https://ollama.com/
*
* @param ollama - The Ollama instance to use.
* @param options - The options for the LLM provider.
* @returns An LLM provider that uses an `ollama/browser` client.
*/
export function makeOllamaBrowserLlmProvider(
ollama: Ollama,
options: OllamaLlmProviderOptions = {},
): LlmProvider {
return makeOllamaBaseLlmProvider(ollama as unknown as OllamaFace, options);
}
106 changes: 106 additions & 0 deletions packages/agents/src/llm-provider/ollama-shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import type {
ModelArchetype,
InstanceConfig,
LlmInstance,
LlmProvider,
Message,
ModelConfig,
} from '../types.ts';
import { parseInstanceConfig } from '../utils.ts';

// Exported for testing.
export const defaultArchetypes: Record<ModelArchetype, string> = {
general: 'llama3.2:latest',
fast: 'llama3.2:latest',
thinker: 'llama3.2:latest',
'code:writer': 'llama3.2:latest',
'code:reader': 'llama3.2:latest',
};

export type OllamaLlmProviderOptions = {
archetypes?: Partial<Record<ModelArchetype, string>>;
};

type StreamedResponse<Content> = Promise<AsyncIterable<Content>>;

/**
* The interface this library depends upon from `ollama[/browser]`.
*/
export type OllamaFace = {
generate: (params: {
prompt: string;
stream: true;
}) => StreamedResponse<{ response: string }>;
chat: (params: {
messages: Message[];
stream: true;
}) => StreamedResponse<{ message: { content: string } }>;
};

/**
* Make an Ollama LLM provider.
*
* @param ollama - The Ollama instance to use.
* @param options - The options for the Ollama LLM provider.
* @param options.archetypes - The archetypes to use.
* @returns An LlmProvider which uses the provided ollama instance.
*/
export function makeOllamaBaseLlmProvider(
ollama: OllamaFace,
options: OllamaLlmProviderOptions = {},
): LlmProvider {
const archetypes = { ...defaultArchetypes, ...options.archetypes };
return {
/**
* Get the configuration for an archetype.
*
* @param archetype - The archetype to get the configuration for.
* @returns The configuration for the archetype.
*/
getArchetypeConfig(archetype: ModelArchetype): ModelConfig {
return { model: archetypes[archetype] };
},
/**
* Make an LLM instance.
*
* @param config - The configuration for the LLM instance.
* @returns An LLM instance.
*/
async makeInstance(config: InstanceConfig): Promise<LlmInstance> {
const requestParams = {
...parseInstanceConfig(config, archetypes),
stream: true,
} as const;
return {
/**
* Generate text from the LLM.
*
* @param prompt - The prompt to generate text from.
* @returns A generator of text chunks.
*/
generate: async (prompt: string) => {
const response = await ollama.generate({ prompt, ...requestParams });
return (async function* () {
for await (const chunk of response) {
yield chunk.response;
}
})();
},
/**
* Chat with the LLM.
*
* @param messages - The messages to chat with.
* @returns A generator of message chunks.
*/
chat: async (messages: Message[]) => {
const response = await ollama.chat({ messages, ...requestParams });
return (async function* () {
for await (const chunk of response) {
yield chunk.message.content;
}
})();
},
};
},
};
}
19 changes: 19 additions & 0 deletions packages/agents/src/llm-provider/ollama.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Ollama } from 'ollama';

import type { LlmProvider } from '../types.ts';
import { makeOllamaBaseLlmProvider } from './ollama-shared.ts';
import type { OllamaFace, OllamaLlmProviderOptions } from './ollama-shared.ts';

/**
* Make an LLM provider that uses the ollama library.
*
* @param ollama - The Ollama instance to use.
* @param options - The options for the LLM provider.
* @returns An LLM provider that uses the Ollama library.
*/
export function makeOllamaLlmProvider(
ollama: Ollama,
options: OllamaLlmProviderOptions = {},
): LlmProvider {
return makeOllamaBaseLlmProvider(ollama as unknown as OllamaFace, options);
}
Loading
Loading