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
19 changes: 14 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,34 @@ module.exports = {
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json',
project: './tsconfig.eslint.json',
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'@typescript-eslint/recommended-requiring-type-checking',
'plugin:@typescript-eslint/recommended',
],
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
}],
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/no-var-requires': 'off',
'no-case-declarations': 'off',
'no-control-regex': 'off',
'no-misleading-character-class': 'off',
'no-prototype-builtins': 'off',
'no-useless-escape': 'off',
'prefer-const': 'off',
},
env: {
node: true,
es6: true,
},
};
};
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Dependencies
node_modules/
package-lock.json

# Build output
dist/
Expand Down
44 changes: 44 additions & 0 deletions examples/guarded-ollama-local-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Governed local Ollama chat example.
*
* Start Ollama first:
* ollama run llama3.2
*/

import { TealOllama, TealEngine, TealAudit, ConsoleOutput } from '../src';

async function main(): Promise<void> {
const engine = new TealEngine({
tools: {
'ollama.chat': { allowed: true }
}
});

const audit = new TealAudit({
outputs: [new ConsoleOutput()]
});

const ollama = new TealOllama({
agentId: 'local-ollama-agent',
model: process.env.OLLAMA_MODEL || 'llama3.2',
baseURL: process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
engine,
audit
});

const response = await ollama.chat.create({
messages: [
{ role: 'system', content: 'You are concise and cite uncertainty.' },
{ role: 'user', content: 'Give me a three-bullet local AI safety checklist.' }
],
temperature: 0.2
});

console.log(response.choices[0].message.content);
console.log(response.metadata);
}

main().catch(error => {
console.error(error);
process.exit(1);
});
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
transform: {
'^.+\\.ts$': 'ts-jest',
},
setupFiles: ['<rootDir>/jest.setup.js'],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
Expand All @@ -34,4 +35,4 @@ module.exports = {
statements: 95
}
}
};
};
83 changes: 83 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const webStreams = require('stream/web');
const { Blob } = require('buffer');

for (const name of ['ReadableStream', 'TransformStream', 'WritableStream']) {
if (typeof globalThis[name] === 'undefined' && webStreams[name]) {
globalThis[name] = webStreams[name];
}
}

if (typeof globalThis.Blob === 'undefined' && Blob) {
globalThis.Blob = Blob;
}

class TestHeaders {
constructor(init = {}) {
this.values = new Map();

if (init instanceof TestHeaders) {
for (const [key, value] of init.entries()) {
this.set(key, value);
}
return;
}

if (Array.isArray(init)) {
for (const [key, value] of init) {
this.set(key, value);
}
return;
}

for (const [key, value] of Object.entries(init)) {
this.set(key, value);
}
}

set(key, value) {
this.values.set(String(key).toLowerCase(), String(value));
}

entries() {
return this.values.entries();
}
}

class TestRequest {
constructor(url, options = {}) {
this.url = String(url);
this.method = options.method || 'GET';
this.headers = options.headers || {};
this.body = options.body;
this.keepalive = Boolean(options.keepalive);
}
}

class TestResponse {
constructor(body, options = {}) {
this.body = body;
this.status = options.status || 200;
this.statusText = options.statusText || '';
this.headers = new TestHeaders(options.headers);
}

blob() {
return Promise.resolve(new Blob([this.body || '']));
}
}

if (typeof globalThis.Headers === 'undefined') {
globalThis.Headers = TestHeaders;
}

if (typeof globalThis.Request === 'undefined') {
globalThis.Request = TestRequest;
}

if (typeof globalThis.Response === 'undefined') {
globalThis.Response = TestResponse;
}

if (typeof globalThis.fetch === 'undefined') {
globalThis.fetch = () => Promise.reject(new Error('fetch is not available in this Jest environment'));
}
Loading
Loading