@mku1tra/que-pasa 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/dist/define/index.d.ts +1 -0
- package/dist/define/index.js +1 -0
- package/dist/define/resource.d.ts +15 -0
- package/dist/define/resource.js +8 -0
- package/dist/define/runtime.d.ts +6 -3
- package/dist/define/tool.d.ts +3 -2
- package/dist/define/tool.js +8 -3
- package/dist/loop/extension.d.ts +2 -1
- package/dist/loop/extension.js +17 -7
- package/dist/loop/index.d.ts +1 -0
- package/dist/loop/index.js +1 -0
- package/dist/loop/resources.d.ts +34 -0
- package/dist/loop/resources.js +57 -0
- package/dist/loop/runtime.d.ts +7 -1
- package/dist/loop/runtime.js +10 -2
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ que-v2's harness, on pi-durable: a workspace defines its agents with `@mku1tra/q
|
|
|
4
4
|
|
|
5
5
|
## Run and check
|
|
6
6
|
|
|
7
|
-
Node runs in the dev container (`.devcontainer/devcontainer.json`), never on the host. You need `just`, `podman` and `npx
|
|
7
|
+
Node runs in the dev container (`.devcontainer/devcontainer.json`), never on the host. The container starts from the dev image, `ghcr.io/matta-kelly/que-pasa-dev:main`, which `.devcontainer/Containerfile` builds with the npm cache of `package-lock.json`, and the `dev-image` workflow on main builds and pushes it. You need `just`, `podman` and `npx`; once per machine, log in with `podman login ghcr.io`, and the first `just up` pulls the dev image, then installs from its cache in seconds.
|
|
8
8
|
|
|
9
9
|
- `just up`: make or start this checkout's dev container
|
|
10
10
|
- `just check`: the check set, `scripts/check.sh`: notes, then types, lint, format, tests and the build. The pre-push hook and the pipeline run the same file
|
|
@@ -24,6 +24,25 @@ await runtime.close();
|
|
|
24
24
|
|
|
25
25
|
One runtime per process owns its SQLite file. After a crash, open it again with the same agents: unfinished runs go on, and `run` with the same `runId` gives back the result.
|
|
26
26
|
|
|
27
|
+
A tool gets what it acts on from its run, as a resource the host provides. The file and command tools of `@mku1tra/que-pasa/sandbox` act in the `Sandbox` the host gives each run:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { provide } from "@mku1tra/que-pasa/loop";
|
|
31
|
+
import { Sandbox, execute, fileTools, podman, view } from "@mku1tra/que-pasa/sandbox";
|
|
32
|
+
|
|
33
|
+
const coder = defineAgent({ name: "coder", model, instructions, tools: [...fileTools, execute] });
|
|
34
|
+
const runtime = await openRuntime({
|
|
35
|
+
storage, models, agents: [coder],
|
|
36
|
+
resources: [
|
|
37
|
+
provide(Sandbox, ({ runId }) =>
|
|
38
|
+
podman({ name: `run-${runId}`, image: "node:22", mounts: [{ source: worktree, target: "/work" }] }),
|
|
39
|
+
),
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A provider resolves from the run as it was started, so a run that resumes after a crash gets the same sandbox. `view(backend, { read, write })` limits a run to some files. What each backend's wall stops: `sandbox/que-pasa-sandbox.md`.
|
|
45
|
+
|
|
27
46
|
Each run is traced as OpenTelemetry GenAI spans through `@opentelemetry/api`. To keep them, register an SDK (a tracer provider, an exporter, and an async context manager). To add what only the host knows, call `runtime.run()` inside a span of its own. `captureContent: true` on `openRuntime` adds message content.
|
|
28
47
|
|
|
29
48
|
## Use it from another project
|
package/dist/define/index.d.ts
CHANGED
package/dist/define/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare const valueType: unique symbol;
|
|
2
|
+
/**
|
|
3
|
+
* Something a tool needs that the host gives each run: a sandbox, and later a connection. It holds no value, only its
|
|
4
|
+
* name and the type of its value: the host provides the value per run (`openRuntime({ resources })`), and a tool asks
|
|
5
|
+
* for it with `runtime.use(resource)`.
|
|
6
|
+
*/
|
|
7
|
+
export type Resource<T = unknown> = {
|
|
8
|
+
/** kebab-case: the host provides it by this name. */
|
|
9
|
+
readonly name: string;
|
|
10
|
+
/** The type of its value; never set. */
|
|
11
|
+
readonly [valueType]?: T;
|
|
12
|
+
};
|
|
13
|
+
/** A resource, checked: its name is kebab-case. */
|
|
14
|
+
export declare function defineResource<T>(name: string): Resource<T>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const resourceName = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
2
|
+
/** A resource, checked: its name is kebab-case. */
|
|
3
|
+
export function defineResource(name) {
|
|
4
|
+
if (!resourceName.test(name)) {
|
|
5
|
+
throw new Error(`resource "${name}": the name must be kebab-case`);
|
|
6
|
+
}
|
|
7
|
+
return Object.freeze({ name });
|
|
8
|
+
}
|
package/dist/define/runtime.d.ts
CHANGED
|
@@ -2,16 +2,19 @@
|
|
|
2
2
|
export type Caller = {
|
|
3
3
|
id: string;
|
|
4
4
|
};
|
|
5
|
+
import type { Resource } from "./resource.ts";
|
|
5
6
|
/** A JSON value: what a run keeps in storage, so it survives a restart. */
|
|
6
7
|
export type Json = string | number | boolean | null | Json[] | {
|
|
7
8
|
[key: string]: Json;
|
|
8
9
|
};
|
|
9
10
|
/**
|
|
10
|
-
* What a tool gets from its run, besides its input: the caller,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* What a tool gets from its run, besides its input: the caller, the context the run was given (LangChain's runtime
|
|
12
|
+
* context), and the resources the host provides for the run. The context is JSON, because the run keeps it, and a run
|
|
13
|
+
* that resumes after a restart gives its tools the same one, so they get the same resources.
|
|
13
14
|
*/
|
|
14
15
|
export type Runtime<C extends Json | undefined = undefined> = {
|
|
15
16
|
caller: Caller;
|
|
16
17
|
context: C;
|
|
18
|
+
/** The run's value of a resource the tool declares in `uses`. Any other resource throws. */
|
|
19
|
+
use<T>(resource: Resource<T>): Promise<T>;
|
|
17
20
|
};
|
package/dist/define/tool.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
+
import type { Resource } from "./resource.ts";
|
|
2
3
|
import type { Json, Runtime } from "./runtime.ts";
|
|
3
4
|
/** A function an agent can call: written once in a workspace, so any agent in it can be given it. */
|
|
4
5
|
export type Tool<S extends z.ZodObject = z.ZodObject, C extends Json | undefined = undefined> = {
|
|
@@ -8,8 +9,8 @@ export type Tool<S extends z.ZodObject = z.ZodObject, C extends Json | undefined
|
|
|
8
9
|
description: string;
|
|
9
10
|
/** The input the model must give. */
|
|
10
11
|
schema: S;
|
|
11
|
-
/** The
|
|
12
|
-
|
|
12
|
+
/** The resources it asks its run for, with `runtime.use`: a sandbox, a connection. It never holds one. */
|
|
13
|
+
uses?: readonly Resource[];
|
|
13
14
|
/**
|
|
14
15
|
* "safe": a call a crash cut off runs again when the run resumes. Left out, it never runs twice: the model gets an
|
|
15
16
|
* `interrupted` result and decides what to do. pi's own term.
|
package/dist/define/tool.js
CHANGED
|
@@ -7,8 +7,13 @@ export function defineTool(tool) {
|
|
|
7
7
|
if (tool.description.trim() === "") {
|
|
8
8
|
throw new Error(`tool "${tool.name}": the description is empty`);
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
const uses = tool.uses ?? [];
|
|
11
|
+
const named = new Set(uses.map((resource) => resource.name));
|
|
12
|
+
if (named.size !== uses.length) {
|
|
13
|
+
throw new Error(`tool "${tool.name}": a resource is in uses twice`);
|
|
12
14
|
}
|
|
13
|
-
return Object.freeze({
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
...tool,
|
|
17
|
+
...(tool.uses ? { uses: Object.freeze([...tool.uses]) } : {}),
|
|
18
|
+
});
|
|
14
19
|
}
|
package/dist/loop/extension.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Extension } from "@earendil-works/pi-durable";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { Agent, Json } from "../define/index.ts";
|
|
4
|
+
import type { Resources } from "./resources.ts";
|
|
4
5
|
/** Any agent, as the runtime holds it. */
|
|
5
6
|
export type AnyAgent = Agent<z.ZodObject | undefined, Json | undefined>;
|
|
6
7
|
/** The tool an agent with an output calls to give its result. No agent tool may take its name. */
|
|
@@ -14,7 +15,7 @@ export declare const extensionName: (agent: AnyAgent) => string;
|
|
|
14
15
|
* no run's state: each call reads its run's document and transcript, so it serves every run of the agent, also one that
|
|
15
16
|
* resumes in a new process.
|
|
16
17
|
*/
|
|
17
|
-
export declare function agentExtension(agent: AnyAgent): Extension;
|
|
18
|
+
export declare function agentExtension(agent: AnyAgent, resources: Resources): Extension;
|
|
18
19
|
/**
|
|
19
20
|
* The JSON Schema of what the model must give: the input shape, so a field with a default is not required. Without the
|
|
20
21
|
* `$schema` key a tool's parameters do not take.
|
package/dist/loop/extension.js
CHANGED
|
@@ -15,12 +15,12 @@ export const extensionName = (agent) => `agent-${agent.name}`;
|
|
|
15
15
|
* no run's state: each call reads its run's document and transcript, so it serves every run of the agent, also one that
|
|
16
16
|
* resumes in a new process.
|
|
17
17
|
*/
|
|
18
|
-
export function agentExtension(agent) {
|
|
18
|
+
export function agentExtension(agent, resources) {
|
|
19
19
|
const { output } = agent;
|
|
20
20
|
if (output && agent.tools.some((tool) => tool.name === submitTool)) {
|
|
21
21
|
throw new Error(`agent "${agent.name}": a tool is named "${submitTool}", which its output needs`);
|
|
22
22
|
}
|
|
23
|
-
const tools = agent.tools.map(toPiTool);
|
|
23
|
+
const tools = agent.tools.map((tool) => toPiTool(tool, resources));
|
|
24
24
|
if (output)
|
|
25
25
|
tools.push(submit(output));
|
|
26
26
|
return defineExtension({
|
|
@@ -30,14 +30,14 @@ export function agentExtension(agent) {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
/** A que-pasa tool as a pi tool: pi checks the arguments against the JSON Schema, zod parses them, and the run's runtime goes in. */
|
|
33
|
-
function toPiTool(tool) {
|
|
33
|
+
function toPiTool(tool, resources) {
|
|
34
34
|
return definePiTool({
|
|
35
35
|
name: tool.name,
|
|
36
36
|
description: tool.description,
|
|
37
37
|
parameters: jsonSchema(tool.schema),
|
|
38
38
|
...(tool.replay ? { replay: tool.replay } : {}),
|
|
39
39
|
execute: async (args, api, context) => {
|
|
40
|
-
const result = await tool.run(tool.schema.parse(args), await runtimeOf(api, context));
|
|
40
|
+
const result = await tool.run(tool.schema.parse(args), await runtimeOf(tool, resources, api, context));
|
|
41
41
|
return {
|
|
42
42
|
output: [
|
|
43
43
|
{
|
|
@@ -73,12 +73,22 @@ const remind = hook(GenerationTask, {
|
|
|
73
73
|
return sent < reminders ? { continue: reminder } : undefined;
|
|
74
74
|
},
|
|
75
75
|
});
|
|
76
|
-
/** The runtime of the call's run, from its run document. */
|
|
77
|
-
async function runtimeOf(api, context) {
|
|
76
|
+
/** The runtime of the call's run, from its run document: its caller, its context, and the resources the tool uses. */
|
|
77
|
+
async function runtimeOf(tool, resources, api, context) {
|
|
78
78
|
const run = await api.snapshot(RunDoc, api.conversationId, context);
|
|
79
79
|
if (!run)
|
|
80
80
|
throw new Error("the run has no run document");
|
|
81
|
-
|
|
81
|
+
const uses = new Set((tool.uses ?? []).map((resource) => resource.name));
|
|
82
|
+
return {
|
|
83
|
+
caller: run.caller,
|
|
84
|
+
context: run.context,
|
|
85
|
+
use: async (resource) => {
|
|
86
|
+
if (!uses.has(resource.name)) {
|
|
87
|
+
throw new Error(`tool "${tool.name}" uses resource "${resource.name}", which it does not declare in uses`);
|
|
88
|
+
}
|
|
89
|
+
return resources.use(run, resource);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
82
92
|
}
|
|
83
93
|
/**
|
|
84
94
|
* The JSON Schema of what the model must give: the input shape, so a field with a default is not required. Without the
|
package/dist/loop/index.d.ts
CHANGED
package/dist/loop/index.js
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Caller, Json, Resource } from "../define/index.ts";
|
|
2
|
+
import type { RunState } from "./state.ts";
|
|
3
|
+
/** What a provider resolves a resource from: the run as it was started, read from its run document. */
|
|
4
|
+
export type RunOf = {
|
|
5
|
+
runId: string;
|
|
6
|
+
caller: Caller;
|
|
7
|
+
/** Absent when the run was given none. */
|
|
8
|
+
context?: Json;
|
|
9
|
+
};
|
|
10
|
+
/** The host's value of one resource, per run. */
|
|
11
|
+
export type Provider<T = unknown> = {
|
|
12
|
+
readonly resource: Resource<T>;
|
|
13
|
+
resolve(run: RunOf): T | Promise<T>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The host's value of a resource for each run, resolved from the run as it was started: a run that resumes in a new
|
|
17
|
+
* process gets the same one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function provide<T>(resource: Resource<T>, resolve: (run: RunOf) => T | Promise<T>): Provider<T>;
|
|
20
|
+
/** The host's providers, and each run's resolved values: resolved once per run while it goes on in this process. */
|
|
21
|
+
export declare function createResources(providers: readonly Provider[]): {
|
|
22
|
+
/** Throws when a resource a tool uses has no provider: at open, never in a run. */
|
|
23
|
+
check(uses: readonly {
|
|
24
|
+
tool: string;
|
|
25
|
+
resource: Resource;
|
|
26
|
+
}[]): void;
|
|
27
|
+
/** The run's value of a resource. */
|
|
28
|
+
use<T>(run: RunState, resource: Resource<T>): Promise<T>;
|
|
29
|
+
/** Drop a run's values, when it ends. */
|
|
30
|
+
forget(runId: string): void;
|
|
31
|
+
/** Drop every run's values, when the runtime closes. */
|
|
32
|
+
clear(): void;
|
|
33
|
+
};
|
|
34
|
+
export type Resources = ReturnType<typeof createResources>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's value of a resource for each run, resolved from the run as it was started: a run that resumes in a new
|
|
3
|
+
* process gets the same one.
|
|
4
|
+
*/
|
|
5
|
+
export function provide(resource, resolve) {
|
|
6
|
+
return Object.freeze({ resource, resolve });
|
|
7
|
+
}
|
|
8
|
+
/** The host's providers, and each run's resolved values: resolved once per run while it goes on in this process. */
|
|
9
|
+
export function createResources(providers) {
|
|
10
|
+
const byName = new Map();
|
|
11
|
+
for (const provider of providers) {
|
|
12
|
+
const { name } = provider.resource;
|
|
13
|
+
if (byName.has(name))
|
|
14
|
+
throw new Error(`resource "${name}" is provided twice`);
|
|
15
|
+
byName.set(name, provider);
|
|
16
|
+
}
|
|
17
|
+
const resolved = new Map();
|
|
18
|
+
return {
|
|
19
|
+
/** Throws when a resource a tool uses has no provider: at open, never in a run. */
|
|
20
|
+
check(uses) {
|
|
21
|
+
for (const { tool, resource } of uses) {
|
|
22
|
+
if (!byName.has(resource.name)) {
|
|
23
|
+
throw new Error(`tool "${tool}" uses resource "${resource.name}", which is not provided`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
/** The run's value of a resource. */
|
|
28
|
+
use(run, resource) {
|
|
29
|
+
const provider = byName.get(resource.name);
|
|
30
|
+
if (!provider)
|
|
31
|
+
throw new Error(`resource "${resource.name}" is not provided`);
|
|
32
|
+
const values = resolved.get(run.runId) ??
|
|
33
|
+
resolved.set(run.runId, new Map()).get(run.runId);
|
|
34
|
+
let value = values.get(resource.name);
|
|
35
|
+
if (!value) {
|
|
36
|
+
const { runId, caller, context } = run;
|
|
37
|
+
value = Promise.resolve(provider.resolve({
|
|
38
|
+
runId,
|
|
39
|
+
caller,
|
|
40
|
+
...(context === undefined ? {} : { context }),
|
|
41
|
+
}));
|
|
42
|
+
// A failed resolve is not kept: the next call tries again.
|
|
43
|
+
value.catch(() => values.delete(resource.name));
|
|
44
|
+
values.set(resource.name, value);
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
},
|
|
48
|
+
/** Drop a run's values, when it ends. */
|
|
49
|
+
forget(runId) {
|
|
50
|
+
resolved.delete(runId);
|
|
51
|
+
},
|
|
52
|
+
/** Drop every run's values, when the runtime closes. */
|
|
53
|
+
clear() {
|
|
54
|
+
resolved.clear();
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
package/dist/loop/runtime.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type Storage, type UsageState } from "@earendil-works/pi-durable";
|
|
|
3
3
|
import type { z } from "zod";
|
|
4
4
|
import { type Agent, type Caller, type Json } from "../define/index.ts";
|
|
5
5
|
import { type AnyAgent } from "./extension.ts";
|
|
6
|
+
import { type Provider } from "./resources.ts";
|
|
6
7
|
/** The tokens and cost a run spent: per `provider/model-id` for model calls, and per tool for tools that report it. */
|
|
7
8
|
export type RunUsage = UsageState;
|
|
8
9
|
/** What a run gives back: the agent's output, checked against its schema, or its answer as text. */
|
|
@@ -15,6 +16,11 @@ export type RuntimeOptions = {
|
|
|
15
16
|
models: Models;
|
|
16
17
|
/** Every agent the host can run. A run that resumes after a restart finds its agent here, by name. */
|
|
17
18
|
agents: readonly AnyAgent[];
|
|
19
|
+
/**
|
|
20
|
+
* The host's value of each resource the agents' tools use, per run: `provide(resource, (run) => value)`. A provider
|
|
21
|
+
* resolves from the run as it was started, so a run that resumes after a restart gets the same one.
|
|
22
|
+
*/
|
|
23
|
+
resources?: readonly Provider[];
|
|
18
24
|
/**
|
|
19
25
|
* Record message content in the trace: instructions, tool definitions, messages, tool arguments and results. Off by
|
|
20
26
|
* default, as the GenAI conventions say: content can hold sensitive data.
|
|
@@ -58,4 +64,4 @@ export type Runtime = {
|
|
|
58
64
|
* Open a runtime: one pi harness on `storage`, with each agent installed as its own extension. Runs a crash left
|
|
59
65
|
* unfinished go on at once.
|
|
60
66
|
*/
|
|
61
|
-
export declare function openRuntime({ storage, models, agents, captureContent, }: RuntimeOptions): Promise<Runtime>;
|
|
67
|
+
export declare function openRuntime({ storage, models, agents, resources: providers, captureContent, }: RuntimeOptions): Promise<Runtime>;
|
package/dist/loop/runtime.js
CHANGED
|
@@ -2,6 +2,7 @@ import { BACKGROUND_CONTEXT, withAbortSignal, } from "@earendil-works/chord/cont
|
|
|
2
2
|
import { configure, createRegistry, Harness, UsageDoc, } from "@earendil-works/pi-durable";
|
|
3
3
|
import { parseModel, } from "../define/index.js";
|
|
4
4
|
import { agentExtension, submitTool } from "./extension.js";
|
|
5
|
+
import { createResources } from "./resources.js";
|
|
5
6
|
import { RunDoc, RunIndex } from "./state.js";
|
|
6
7
|
import { activeParent, createTracing } from "./trace.js";
|
|
7
8
|
import { answerOf, messagesOf, resultOf } from "./transcript.js";
|
|
@@ -10,12 +11,17 @@ const context = BACKGROUND_CONTEXT;
|
|
|
10
11
|
* Open a runtime: one pi harness on `storage`, with each agent installed as its own extension. Runs a crash left
|
|
11
12
|
* unfinished go on at once.
|
|
12
13
|
*/
|
|
13
|
-
export async function openRuntime({ storage, models, agents, captureContent = false, }) {
|
|
14
|
+
export async function openRuntime({ storage, models, agents, resources: providers = [], captureContent = false, }) {
|
|
15
|
+
const resources = createResources(providers);
|
|
16
|
+
resources.check(agents.flatMap((agent) => agent.tools.flatMap((tool) => (tool.uses ?? []).map((resource) => ({ tool: tool.name, resource })))));
|
|
14
17
|
const installed = new Map();
|
|
15
18
|
for (const agent of agents) {
|
|
16
19
|
if (installed.has(agent.name))
|
|
17
20
|
throw new Error(`two agents are named "${agent.name}"`);
|
|
18
|
-
installed.set(agent.name, {
|
|
21
|
+
installed.set(agent.name, {
|
|
22
|
+
agent,
|
|
23
|
+
extension: agentExtension(agent, resources),
|
|
24
|
+
});
|
|
19
25
|
}
|
|
20
26
|
const tracing = createTracing({
|
|
21
27
|
agents: new Map([...installed].map(([name, { agent }]) => [name, agent])),
|
|
@@ -103,6 +109,7 @@ export async function openRuntime({ storage, models, agents, captureContent = fa
|
|
|
103
109
|
tools: {},
|
|
104
110
|
});
|
|
105
111
|
onMessages?.(await transcript());
|
|
112
|
+
resources.forget(runId);
|
|
106
113
|
}
|
|
107
114
|
}
|
|
108
115
|
return {
|
|
@@ -110,6 +117,7 @@ export async function openRuntime({ storage, models, agents, captureContent = fa
|
|
|
110
117
|
async close() {
|
|
111
118
|
await tracing.closeAll();
|
|
112
119
|
await harness.close(context);
|
|
120
|
+
resources.clear();
|
|
113
121
|
},
|
|
114
122
|
};
|
|
115
123
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mku1tra/que-pasa",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "An agent harness on pi-durable: define agents and tools with define/, and run them durably and traced with loop/.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"./loop": {
|
|
21
21
|
"types": "./dist/loop/index.d.ts",
|
|
22
22
|
"default": "./dist/loop/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./sandbox": {
|
|
25
|
+
"types": "./dist/sandbox/index.d.ts",
|
|
26
|
+
"default": "./dist/sandbox/index.js"
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
"files": [
|