Skip to content

Commit

Permalink
workspace cache (#632)
Browse files Browse the repository at this point in the history
* explose cache support

* docs

* added test
  • Loading branch information
pelikhan authored Aug 20, 2024
1 parent b605f8c commit 0a5e182
Show file tree
Hide file tree
Showing 18 changed files with 478 additions and 2 deletions.
31 changes: 31 additions & 0 deletions docs/genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion docs/src/content/docs/reference/scripts/cache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,18 @@ npx genaiscript run .... --cache-name summary
- cache
- summary.jsonl

</FileTree>
</FileTree>

## Programmatic cache

You can instantiate a custom cache object to manage the cache programmatically.

```js
const cache = await workspace.cache("summary")
// write entries
await cache.set("file.txt", "...")
// read entries
const content = await cache.get("file.txt")
// list entries
const entries = await cache.values()
```
31 changes: 31 additions & 0 deletions genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions packages/core/src/filesystem.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { JSONLineCache } from "./cache"
import { DOT_ENV_REGEX } from "./constants"
import { NotSupportedError, errorMessage } from "./error"
import { resolveFileContent } from "./file"
Expand Down Expand Up @@ -67,6 +68,16 @@ export function createFileSystem(): Omit<WorkspaceFileSystem, "grep"> {
const res = XMLParse(file.content)
return res
},
cache: async (name: string) => {
if (!name) throw new NotSupportedError("missing cache name")
const res = JSONLineCache.byName<any, any>(name)
return <WorkspaceFileCache<any, any>>{
get: async (key: any) => res.get(key),
set: async (key: any, val: any) => res.set(key, val),
values: async () =>
res.entries().then((es) => es.map((e) => e.val)),
}
},
}
;(fs as any).readFile = readText
return Object.freeze(fs)
Expand Down
31 changes: 31 additions & 0 deletions packages/core/src/genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/core/src/promptcontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { YAMLParse, YAMLStringify } from "./yaml"
import { createParsers } from "./parsers"
import { readText } from "./fs"
import {
PromptImage,
PromptNode,
appendChild,
createFileMergeNode,
Expand Down Expand Up @@ -105,6 +104,7 @@ export async function createPromptContext(
readJSON: (f) => runtimeHost.workspace.readJSON(f),
readXML: (f) => runtimeHost.workspace.readXML(f),
writeText: (f, c) => runtimeHost.workspace.writeText(f, c),
cache: (n) => runtimeHost.workspace.cache(n),
findFiles: async (pattern, options) => {
const res = await runtimeHost.workspace.findFiles(pattern, options)
trace.files(res, {
Expand Down
31 changes: 31 additions & 0 deletions packages/core/src/types/prompt_template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,25 @@ interface ToolCallContent {

type ToolCallOutput = string | ToolCallContent | ShellOutput | WorkspaceFile

interface WorkspaceFileCache<K, V> {
/**
* Gets the value associated with the key, or undefined if there is none.
* @param key
*/
get(key: K): Promise<V | undefined>
/**
* Sets the value associated with the key.
* @param key
* @param value
*/
set(key: K, value: V): Promise<void>

/**
* List the values in the cache.
*/
values(): Promise<V[]>
}

interface WorkspaceFileSystem {
/**
* Searches for files using the glob pattern and returns a list of files.
Expand Down Expand Up @@ -524,6 +543,15 @@ interface WorkspaceFileSystem {
* @param content
*/
writeText(path: string, content: string): Promise<void>

/**
* Opens a key-value cache for the given cache name.
* The cache is persisted accross runs of the script. Entries are dropped when the cache grows too large.
* @param cacheName
*/
cache<K = any, V = any>(
cacheName: string
): Promise<WorkspaceFileCache<K, V>>
}

interface ToolCallContext {
Expand Down Expand Up @@ -1641,6 +1669,9 @@ interface PromptContext extends ChatGenerationContext {
path: Path
parsers: Parsers
retrieval: Retrieval
/**
* @deprecated Use `workspace` instead
*/
fs: WorkspaceFileSystem
workspace: WorkspaceFileSystem
YAML: YAML
Expand Down
17 changes: 17 additions & 0 deletions packages/sample/genaisrc/cache.genai.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
script({
model: "openai:gpt-3.5-turbo",
tests: {},
})

const cache = await workspace.cache<number, number>("test-cache")
const key = Math.random()
const value = Math.random()

await cache.set(key, value)
const result = await cache.get(key)
if (result !== value) throw new Error(`unexpected value: ${result}`)

const values = await cache.values()
if (!values.includes(value)) throw new Error(`unexpected values: ${values}`)

console.log(`cache test passed`)
31 changes: 31 additions & 0 deletions packages/sample/genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions packages/sample/genaisrc/node/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0a5e182

Please sign in to comment.