Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ailly.dev #56

Merged
merged 2 commits into from
Apr 22, 2024
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
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"dependencies": {
"@ailly/core": "1.3.0-rc2",
"@davidsouther/jiffies": "^2.1.4",
"@davidsouther/jiffies": "^2.2.0",
"yaml": "^2.4.1"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@
"devDependencies": {
"@types/mime-types": "^2.1.4",
"@types/mustache": "^4.2.5",
"vitest": "^0.34.6"
"vitest": "^1.5.0"
}
}
1 change: 0 additions & 1 deletion core/src/ailly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export { GitignoreFs } from "./content/gitignore_fs.js";
export { getPlugin } from "./plugin/index.js";
import { getEngine } from "./engine/index.js";
export { getEngine } from "./engine/index.js";
export { RAG } from "./plugin/rag.js";
export * from "./util.js";

export const DEFAULT_ENGINE = "bedrock";
Expand Down
2 changes: 1 addition & 1 deletion core/src/content/content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ test("it loads responses", async () => {
test.each([
["prompt.md", "prompt"],
["prompt.md.ailly.md", "response"],
])("it splits ordered filenames: %s -> %s", (file, type) => {
])("it splits ordered filenames: %s -> %s", (file: string, type: string) => {
const split = splitOrderedName(file);
expect(split.type).toBe(type);
});
Expand Down
9 changes: 8 additions & 1 deletion core/src/engine/noop.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { Content } from "../content/content.js";

export const DEFAULT_MODEL = "NOOP";
const NOOP_TIMEOUT = 750;
export const name = "noop";
export async function format(c: Content[]): Promise<void> {}
export async function generate<D extends {} = {}>(
c: Content,
_: unknown
): Promise<{ debug: D; message: string }> {
await new Promise<void>((resolve) => {
setTimeout(() => resolve(), NOOP_TIMEOUT);
});
return {
message:
process.env["AILLY_NOOP_RESPONSE"] ?? `noop response for ${c.name}`,
process.env["AILLY_NOOP_RESPONSE"] ??
`noop response for ${c.name}:\n${c.context.system
?.map((s) => s.content)
.join("\n")}\n${c.prompt}`,
debug: { system: c.context.system } as unknown as D,
};
}
Expand Down
7 changes: 3 additions & 4 deletions core/src/plugin/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as rag from "./rag.js";
import { PipelineSettings } from "../ailly.js";
import type { Content, View } from "../content/content.js";
import type { Engine } from "../engine/index.js";
import { RAG } from "./rag.js";

export interface PluginBuilder {
(engine: Engine, settings: PipelineSettings): Promise<Plugin>;
Expand All @@ -15,9 +15,8 @@ export interface Plugin {
}

export const PLUGINS: Record<string, { default: PluginBuilder }> = {
noop: { default: rag.RAG.empty as unknown as PluginBuilder },
none: { default: rag.RAG.empty as unknown as PluginBuilder },
rag: { default: rag.RAG.build as unknown as PluginBuilder },
noop: { default: RAG.empty as unknown as PluginBuilder },
none: { default: RAG.empty as unknown as PluginBuilder },
};

export async function getPlugin(
Expand Down
90 changes: 9 additions & 81 deletions core/src/plugin/rag.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,27 @@
import { join } from "node:path";
import { LocalIndex } from "vectra/lib/LocalIndex.js";

import type { Content } from "../content/content.js";
import type { Engine } from "../engine/index.js";
import type { PipelineSettings } from "../ailly.js";
import { LOGGER } from "../util.js";

function ragDb(path: string) {
return join(path, ".vectors");
}

export class RAG {
index: LocalIndex;

static async build(
engine: Engine,
{ root: path }: PipelineSettings
): Promise<RAG> {
const rag = new RAG(engine, ragDb(path));
if (!(await rag.index.isIndexCreated())) await rag.index.createIndex();
return rag;
}

static async empty(engine: Engine, path: string): Promise<RAG> {
return new NoopRAG(engine, path);
static async empty(engine: Engine): Promise<RAG> {
return new RAG(engine);
}

protected constructor(readonly engine: Engine, path: string) {
this.index = new LocalIndex(path);
}

protected async add(content: Content) {
const text = content.prompt;
const vector = await this.engine.vector(content.prompt, {});
await this.index.insertItem({
vector,
metadata: { text, name: content.name, path: content.path },
});
}

async update(content: Content[]) {
const _content = [...content];
await this.index.beginUpdate();
await new Promise<void>(async (resolve, reject) => {
const nextPiece = async () => {
const piece = _content.pop()!;
if (!piece) {
return resolve();
}
try {
LOGGER.info(`Adding to RAG ${piece.name} (${piece.path})`);
await this.add(piece);
LOGGER.info(`Completed adding to RAG ${piece.name} (${piece.path})`);
} catch (e) {
LOGGER.warn(`Error adding to RAG ${piece.name} (${piece.path})`);
LOGGER.info(`${e}`);
}
nextPiece();
};
nextPiece();
});
await this.index.endUpdate();
}
protected constructor(readonly engine: Engine) {}

async query(data: string, results = 3) {
const vector = await this.engine.vector(data, {});
const query = await this.index.queryItems(vector, results);
return query.map(({ score, item }) => ({
score,
content: item.metadata.text as string,
name: "unknown",
}));
}

async augment(content: Content) {
content.meta = content.meta ?? {};
const results = await this.query(content.prompt);
content.context.augment = results;
}

async clean(content: Content) {}
}

export class NoopRAG extends RAG {
override update(content: Content[]): Promise<void> {
update(content: Content[]): Promise<void> {
return Promise.resolve();
}
override augment(content: Content): Promise<void> {

augment(content: Content): Promise<void> {
return Promise.resolve();
}

override query(
query(
data: string,
results?: number
): Promise<{ score: number; content: string; name: string }[]> {
return Promise.resolve([]);
}

async clean(content: Content) {}
}
80 changes: 80 additions & 0 deletions core/src/plugin/vectra_rag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { join } from "node:path";
import { LocalIndex } from "vectra/lib/LocalIndex.js";
import { RAG } from "./rag.js";
import { Engine } from "../engine/index.js";
import { PipelineSettings } from "../ailly.js";
import { Content } from "../content/content.js";
import { LOGGER } from "../util.js";

function ragDb(path: string) {
return join(path, ".vectors");
}

export class VectraRAG extends RAG {
index: LocalIndex;

static async build(
engine: Engine,
{ root: path }: PipelineSettings
): Promise<RAG> {
const rag = new VectraRAG(engine, ragDb(path));
if (!(await rag.index.isIndexCreated())) await rag.index.createIndex();
return rag;
}

protected constructor(readonly engine: Engine, path: string) {
super(engine);
this.index = new LocalIndex(path);
}

protected async add(content: Content) {
const text = content.prompt;
const vector = await this.engine.vector(content.prompt, {});
await this.index.insertItem({
vector,
metadata: { text, name: content.name, path: content.path },
});
}

override async update(content: Content[]) {
const _content = [...content];
await this.index.beginUpdate();
await new Promise<void>(async (resolve, reject) => {
const nextPiece = async () => {
const piece = _content.pop()!;
if (!piece) {
return resolve();
}
try {
LOGGER.info(`Adding to RAG ${piece.name} (${piece.path})`);
await this.add(piece);
LOGGER.info(`Completed adding to RAG ${piece.name} (${piece.path})`);
} catch (e) {
LOGGER.warn(`Error adding to RAG ${piece.name} (${piece.path})`);
LOGGER.info(`${e}`);
}
nextPiece();
};
nextPiece();
});
await this.index.endUpdate();
}

override async query(data: string, results = 3) {
const vector = await this.engine.vector(data, {});
const query = await this.index.queryItems(vector, results);
return query.map(({ score, item }) => ({
score,
content: item.metadata.text as string,
name: "unknown",
}));
}

override async augment(content: Content) {
content.meta = content.meta ?? {};
const results = await this.query(content.prompt);
content.context.augment = results;
}

override async clean(content: Content) {}
}
Loading