Skip to content

Commit

Permalink
include context
Browse files Browse the repository at this point in the history
  • Loading branch information
actualwitch committed Feb 7, 2025
1 parent 5ace980 commit c1ca66e
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 88 deletions.
8 changes: 4 additions & 4 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,11 @@

"punycode": ["[email protected]", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],

"react": ["[email protected]d85cf3e5-20250205", "", {}, "sha512-jpLQ+iB3ky8ik5XGOIeIOQI3tK9XodDyuU09zIjwgb2nADvDgo45tNuU9gII05LHetooQO4ScekTjFHr0hgKRw=="],
"react": ["[email protected]ff628334-20250205", "", {}, "sha512-lJUElq6aqp9uYWXx+yGb1yzVU/vvdu1ffQ+Ly56jlKPrgJQeZvX3dTmSjIcbTJJGq9OhvoRWz/0PUC1r3lx0xw=="],

"react-aria": ["[email protected]", "", { "dependencies": { "@internationalized/string": "^3.2.5", "@react-aria/breadcrumbs": "^3.5.20", "@react-aria/button": "^3.11.1", "@react-aria/calendar": "^3.7.0", "@react-aria/checkbox": "^3.15.1", "@react-aria/color": "^3.0.3", "@react-aria/combobox": "^3.11.1", "@react-aria/datepicker": "^3.13.0", "@react-aria/dialog": "^3.5.21", "@react-aria/disclosure": "^3.0.1", "@react-aria/dnd": "^3.8.1", "@react-aria/focus": "^3.19.1", "@react-aria/gridlist": "^3.10.1", "@react-aria/i18n": "^3.12.5", "@react-aria/interactions": "^3.23.0", "@react-aria/label": "^3.7.14", "@react-aria/link": "^3.7.8", "@react-aria/listbox": "^3.14.0", "@react-aria/menu": "^3.17.0", "@react-aria/meter": "^3.4.19", "@react-aria/numberfield": "^3.11.10", "@react-aria/overlays": "^3.25.0", "@react-aria/progress": "^3.4.19", "@react-aria/radio": "^3.10.11", "@react-aria/searchfield": "^3.8.0", "@react-aria/select": "^3.15.1", "@react-aria/selection": "^3.22.0", "@react-aria/separator": "^3.4.5", "@react-aria/slider": "^3.7.15", "@react-aria/ssr": "^3.9.7", "@react-aria/switch": "^3.6.11", "@react-aria/table": "^3.16.1", "@react-aria/tabs": "^3.9.9", "@react-aria/tag": "^3.4.9", "@react-aria/textfield": "^3.16.0", "@react-aria/tooltip": "^3.7.11", "@react-aria/utils": "^3.27.0", "@react-aria/visually-hidden": "^3.8.19", "@react-types/shared": "^3.27.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "sha512-u3WUEMTcbQFaoHauHO3KhPaBYzEv1o42EdPcLAs05GBw9Q6Axlqwo73UFgMrsc2ElwLAZ4EKpSdWHLo1R5gfiw=="],

"react-dom": ["[email protected]d85cf3e5-20250205", "", { "dependencies": { "scheduler": "0.26.0-canary-d85cf3e5-20250205" }, "peerDependencies": { "react": "19.1.0-canary-d85cf3e5-20250205" } }, "sha512-AxrNK5Kt4Cb9007Cvt6WOKnrIDWQGHQfN1C/HR3k+UA0h8oAJNGDrsHxOalx9Fu/Iwdh55Zk5FbUJMjCw+CSMg=="],
"react-dom": ["[email protected]ff628334-20250205", "", { "dependencies": { "scheduler": "0.26.0-canary-ff628334-20250205" }, "peerDependencies": { "react": "19.1.0-canary-ff628334-20250205" } }, "sha512-O/FFWzQNHqKLavROUliPXDPAwJcjwDcFbZmg2YfsWtSDJj1pRFTNzYvOUChC/hgBQiIM5rAiznQjBw2D9naH1g=="],

"react-is": ["[email protected]", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],

Expand All @@ -548,7 +548,7 @@

"saxes": ["[email protected]", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="],

"scheduler": ["[email protected]d85cf3e5-20250205", "", {}, "sha512-ivuko9JqWNVtK/Gw17V54bRdMZNNr55RsjUJtUJY2LNL4Wvt7P4EVD9GQRq5K2PvMBSYXYJ/2of2J6Btdekxcg=="],
"scheduler": ["[email protected]ff628334-20250205", "", {}, "sha512-U0tZuylPZVLsLMHfoqXdURMPdHXd8nBqqJXIQCiT0NQqY5wxc4I+Wsg1XFAY2WY0WRh6U0c3WMljp2JvRjXKow=="],

"set-cookie-parser": ["[email protected]", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],

Expand Down Expand Up @@ -582,7 +582,7 @@

"turbo-stream": ["[email protected]", "", {}, "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g=="],

"typescript": ["[email protected].20250205", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-ElowVOyGLZ8RSwHA7UZF8M3n4iT/QaU6jCF9N9z2vT/lTjvM3K2eFliQsmF6Iaz9vOhFVUNfe1Mr8aXnpMXiHA=="],
"typescript": ["[email protected].20250206", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-lnf72PhBy8HHFElX7VbfSwtG86LdWnE+p7h5KjlK459t6WYtW4RL/icVhebS4GM++AmJMGpcZLCyWSrF8NCXHg=="],

"undici-types": ["[email protected]", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],

Expand Down
11 changes: 8 additions & 3 deletions src/feature/chat/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { deepEqual } from "../../utils";
import { useHandlers } from "../../utils/keyboard";
import { useScrollToTop } from "../../utils/scroll";
import { View, collapsedAtom } from "../ui/view";
import type { _Message, Experiment, ExperimentWithMeta, Message } from "../../types";
import type { _Message, Experiment, ExperimentWithMeta, Message, Role } from "../../types";

const baseHeight = bs(6);
export const ChatContainer = styled.div<WithDarkMode>`
Expand All @@ -22,7 +22,7 @@ export const ChatContainer = styled.div<WithDarkMode>`
code {
background-color: ${(p) => (p.isDarkMode ? Palette.white + "50" : Palette.black + "20")};
border-radius: ${bs(1 / 8)};
border-radius: ${bs(Palette.borderSpan)};
}
*:not(pre) > code {
Expand Down Expand Up @@ -59,7 +59,7 @@ const getAlign = (fromServer: boolean, experimentLayout: Store["experimentLayout
};

export const MessageComponent = styled.article<{
role: "assistant" | "developer" | "info" | "error" | "system" | "tool" | "user";
role: Role;
contentType?: string;
ioType?: "input" | "output";
isSelected?: boolean;
Expand Down Expand Up @@ -161,6 +161,11 @@ export const MessageComponent = styled.article<{
border-color: ${Palette.red};
`);
}
if (role === "context") {
styles.push(css`
border-color: ${Palette.teal};
`);
}
if (isSelected) {
if (isDarkMode) {
styles.push(css`
Expand Down
13 changes: 9 additions & 4 deletions src/feature/inference/adapters/adapter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, it } from "bun:test";
import { experimentToAnthropic } from "./anthropic";
import templates from "../../../../fixtures/templates.json";
import anthropicTool from "../../../../fixtures/tools/stockPrice.json";
import { experimentToOpenai } from "./openai";
import { experimentToMistral } from "./mistral";

Expand All @@ -10,13 +11,17 @@ for (const [provider, adapter] of [
["openai", experimentToOpenai],
] as const) {
describe(`inference/${provider}`, () => {
it("tool use experiment", () => {
const result = adapter(templates["Tool use"].messages);
it("tool use experiment", async () => {
const result = await adapter(templates["Tool use"].messages);
expect(result).toMatchSnapshot();
});
it("sample", () => {
const result = adapter(templates["Sample chat"].messages);
it("sample", async () => {
const result = await adapter(templates["Sample chat"].messages);
expect(result).toMatchSnapshot();
});
// it("anthropic tool format", async () => {
// const result = await adapter([{ role: "tool", content: anthropicTool }]);
// expect(result).toMatchSnapshot();
// });
});
}
15 changes: 12 additions & 3 deletions src/feature/inference/adapters/anthropic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import type {
} from "@anthropic-ai/sdk/resources/index.mjs";
import type { Message } from "../../../types";
import { tokenLimit } from "../../../const";
import { createContextFromFiles, iterateDir } from "../../router/Explore";

export const experimentToAnthropic = (
export async function experimentToAnthropic(
experiment: Message[],
{ max_tokens = tokenLimit }: { max_tokens?: number } = {},
): MessageCreateParams | MessageCreateParamsNonStreaming => {
): Promise<MessageCreateParams | MessageCreateParamsNonStreaming> {
let system = "";
const messages: MessageParam[] = [];
const tools: Tool[] = [];
for (const { role, content, fromServer } of experiment) {
if (role === "system") {
system += `${content}
`;
continue;
}
if (role === "user" || role === "assistant") {
if (typeof content === "object") {
Expand All @@ -26,6 +28,13 @@ export const experimentToAnthropic = (
if (typeof content === "string") {
messages.push({ role, content });
}
continue;
}
if (role === "context") {
const directory = content.directory as string;
const files = await iterateDir(directory);
const context = await createContextFromFiles(files, directory);
messages.push({ role: "user", content: context });
}
if (role === "tool" && !fromServer) {
if (typeof content === "object") {
Expand All @@ -49,4 +58,4 @@ export const experimentToAnthropic = (
max_tokens,
stream: true,
};
};
}
2 changes: 1 addition & 1 deletion src/feature/inference/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export const runExperimentAsAnthropic = entangledAtom(
return;
}

const { stream, ...experimentAsAnthropic } = experimentToAnthropic(experiment);
const { stream, ...experimentAsAnthropic } = await experimentToAnthropic(experiment);

const anthropic = new Anthropic({
apiKey: resolvedToken,
Expand Down
95 changes: 62 additions & 33 deletions src/feature/router/Explore.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,33 @@
import { type Setter, atom, useAtom } from "jotai";
import { useEffect } from "react";
import { atom, useAtom } from "jotai";
import { readFile, readdir } from "node:fs/promises";
import path from "node:path";
import { readdir, readFile } from "node:fs/promises";
import { useEffect } from "react";

import { navigateAtom, titleOverrideAtom } from ".";
import templates from "../../../fixtures/templates.json";
import { filenames, importsRegistry, selectedChat } from "../../atoms/client";
import { experimentAtom, isNavPanelOpenAtom, layoutAtom, templatesAtom } from "../../atoms/common";
import { type Config, ConfigRenderer } from "../ui/ConfigRenderer";
import { collapsedAtom, View } from "../ui/view";
import type { ExperimentWithMeta } from "../../types";
import { ExperimentPreview } from "../chat/ExperimentPreview";
import { selectionAtom } from "../chat/chat";
import { Actions } from "../ui/Actions";
import { DesktopOnly } from "../ui/Mobile";
import { Maybe } from "true-myth";
import { titleOverrideAtom } from ".";
import { nopeAtom } from "../../atoms/util";
import { store } from "../../store";
import { entangledAtom } from "../../utils/entanglement";
import { getRealm } from "../../utils/realm";
import { SidebarInput } from "../ui/Navigation";
import { Page } from "../ui/Page";
import { getRealm } from "../../utils/realm";
import { entangledAtom } from "../../utils/entanglement";
import { nopeAtom } from "../../atoms/util";
import { Maybe } from "true-myth";
import { View, collapsedAtom } from "../ui/view";

const pwdAtom = getRealm() === "server" ? atom(Bun.env.PWD) : nopeAtom;
export const pwdAtom = getRealm() === "server" ? atom(Bun.env.PWD) : nopeAtom;

const dirOverrideAtom = atom<string | null>(null);

const currentDirAtom = atom((get) => {
export const currentDirAtom = entangledAtom("cwd", atom((get) => {
const override = get(dirOverrideAtom);
return override ?? get(pwdAtom);
});
}));

const goToAtom = entangledAtom(
"gotodir",
atom(null, (get, set, dir: string) => {
if (getRealm() !== "server") return;
const currentDir = Maybe.of(get(currentDirAtom));
const newPath = currentDir.map(currentDir => path.join(currentDir, dir));
const newPath = currentDir.map((currentDir) => path.join(currentDir, dir));
if (newPath.isJust) {
set(dirOverrideAtom, newPath.value);
}
Expand Down Expand Up @@ -64,6 +56,7 @@ export async function filesInDir(thisPath: string) {
return files;
}

const includeExtensions = ["ts", "tsx", "md", "json", "yml"];
export async function iterateDir(dir: string, ignore: string[] = [".git"]) {
const thisIgnores = [...ignore];
const entries = await readdir(dir, { withFileTypes: true });
Expand All @@ -82,38 +75,74 @@ export async function iterateDir(dir: string, ignore: string[] = [".git"]) {
for (const entry of entries) {
if (thisIgnores.some((ignore) => entry.name === ignore)) continue;
if (entry.isDirectory()) {
if (entry.name === "fixtures") continue;
directories.push(entry.name);
} else {
files.push(`${entry.parentPath}${path.sep}${entry.name}`);
const parts = entry.name.split(".");
const ext = parts[parts.length - 1];
if (entry.isFile() && includeExtensions.includes(ext)) {
files.push(`${entry.parentPath}${path.sep}${entry.name}`);
}
}
}
directories.sort();
files.sort();
for (const directory of directories) {
files = [...(await iterateDir(path.join(dir, directory), thisIgnores)), ...files];
}
files.sort();
return files;
}

const currentDirNameAtom = entangledAtom(
"cwd",
const currentDirContentAtom = entangledAtom(
"cwd-content",
atom(async (get) => {
const currentDir = get(currentDirAtom);
if (currentDir) {
const foo = await iterateDir(currentDir);
for (const url of foo) {
console.log(url.slice(currentDir.length));
try {
const files = await filesInDir(currentDir);
const entry = path.parse(currentDir);
return { [entry.name]: Object.fromEntries(files.map((file) => [file.name, {}])) };
} catch {
store.set(dirOverrideAtom, null);
}
const files = await filesInDir(currentDir);
const entry = path.parse(currentDir);
return { [entry.name]: Object.fromEntries(files.map((file) => [file.name, {}])) };
}
return null;
}),
);

export const createContextFromFiles = async (files: string[], basePath: string) => {
let context = "";
let index = 1;
for (const url of files) {
const relUrl = url.slice(basePath.length);
const content = await readFile(url, "utf-8");
const thisDoc = `
<document index="${index}">
<source>${relUrl}</source>
<document_content>
${content}
</document_content>
</document>
`;
context += thisDoc;
index += 1;
}
return `<documents>\n${context}\n</documents>`;
};

export const currentDirContextAtom = entangledAtom(
"currentdircontext",
atom(async (get) => {
const currentDir = Maybe.of(get(currentDirAtom)).map(async (currentDir) => {
const files = await iterateDir(currentDir);
return await createContextFromFiles(files, currentDir);
});
return await currentDir.unwrapOr(async () => null);
}),
);

const SidebarContents = () => {
const [currentDir] = useAtom(currentDirNameAtom);
const [currentDir] = useAtom(currentDirContentAtom);
const [_, goToDir] = useAtom(goToAtom);
const [collapsed, setCollapsed] = useAtom(collapsedAtom);
if (!currentDir) {
Expand Down
33 changes: 25 additions & 8 deletions src/feature/router/NewExperiment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,16 @@ import { modelOptions } from "../inference/types";
import { Actions } from "../ui/Actions";
import { Page } from "../ui/Page";
import { TextArea } from "../ui/TextArea";
import { currentDirAtom } from "./Explore";
import { hasBackend } from "../../utils/realm";

const baseRadius = 3 / 4;
const baseMargin = 1 / 2;

export const Block = styled.div<WithDarkMode>`
display: flex;
flex-direction: column;
border-radius: ${bs(baseRadius)};
border-radius: ${bs(Palette.baseRadius)};
position: sticky;
bottom: 0;
overflow: clip;
Expand All @@ -64,8 +65,8 @@ export const Block = styled.div<WithDarkMode>`
textarea {
padding: 0 ${bs(baseMargin)} ${bs(baseMargin)};
resize: none;
border-bottom-left-radius: ${bs(baseRadius)};
border-bottom-right-radius: ${bs(baseRadius)};
border-bottom-left-radius: ${bs(Palette.baseRadius)};
border-bottom-right-radius: ${bs(Palette.baseRadius)};
&:focus {
outline: none;
}
Expand Down Expand Up @@ -112,13 +113,13 @@ export const Block = styled.div<WithDarkMode>`

const ActionRow = styled.div`
display: flex;
border-top-left-radius: ${bs(baseRadius)};
border-top-right-radius: ${bs(baseRadius)};
border-top-left-radius: ${bs(Palette.baseRadius)};
border-top-right-radius: ${bs(Palette.baseRadius)};
select {
border-top-left-radius: ${bs(baseRadius)};
border-top-left-radius: ${bs(Palette.baseRadius)};
}
button {
border-top-right-radius: ${bs(baseRadius)};
border-top-right-radius: ${bs(Palette.baseRadius)};
}
`;

Expand Down Expand Up @@ -227,6 +228,22 @@ export const actionsAtom = atom((get) => {
counter++;
}
}
if (hasBackend()){
config.Actions.push({
Special: {
buttons: [
{
label: "Add Context",
action: (set: Setter) => {
const dir = get(currentDirAtom);
set(experimentAtom, [...experiment, { role: "context", content: {directory: dir} }])
},
},
],
},
});
counter++;
}
return { config, counter };
});

Expand Down
1 change: 0 additions & 1 deletion src/feature/ui/ListBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const ListItem = styled.li<ListItemProps>`
props.isFocused ? "white"
: props.isSelected ? Palette.black
: "#333"};
font-size: 14px;
font-weight: ${(props) => (props.isSelected ? "600" : "normal")};
padding: 8px;
display: flex;
Expand Down
Loading

0 comments on commit c1ca66e

Please sign in to comment.