@liquidmetal-ai/precip 1.0.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/.prettierrc +9 -0
- package/CHANGELOG.md +8 -0
- package/eslint.config.mjs +28 -0
- package/package.json +53 -0
- package/src/engine/agent.ts +478 -0
- package/src/engine/llm-provider.test.ts +275 -0
- package/src/engine/llm-provider.ts +330 -0
- package/src/engine/stream-parser.ts +170 -0
- package/src/index.ts +142 -0
- package/src/mounts/mount-manager.test.ts +516 -0
- package/src/mounts/mount-manager.ts +327 -0
- package/src/mounts/mount-registry.ts +196 -0
- package/src/mounts/zod-to-string.test.ts +154 -0
- package/src/mounts/zod-to-string.ts +213 -0
- package/src/presets/agent-tools.ts +57 -0
- package/src/presets/index.ts +5 -0
- package/src/sandbox/README.md +1321 -0
- package/src/sandbox/bridges/README.md +571 -0
- package/src/sandbox/bridges/actor.test.ts +229 -0
- package/src/sandbox/bridges/actor.ts +195 -0
- package/src/sandbox/bridges/bridge-fixes.test.ts +614 -0
- package/src/sandbox/bridges/bucket.test.ts +300 -0
- package/src/sandbox/bridges/cleanup-reproduction.test.ts +225 -0
- package/src/sandbox/bridges/console-multiple.test.ts +187 -0
- package/src/sandbox/bridges/console.test.ts +157 -0
- package/src/sandbox/bridges/console.ts +122 -0
- package/src/sandbox/bridges/fetch.ts +93 -0
- package/src/sandbox/bridges/index.ts +78 -0
- package/src/sandbox/bridges/readable-stream.ts +323 -0
- package/src/sandbox/bridges/response.test.ts +154 -0
- package/src/sandbox/bridges/response.ts +123 -0
- package/src/sandbox/bridges/review-fixes.test.ts +331 -0
- package/src/sandbox/bridges/search.test.ts +475 -0
- package/src/sandbox/bridges/search.ts +264 -0
- package/src/sandbox/bridges/shared/body-methods.ts +93 -0
- package/src/sandbox/bridges/shared/cleanup.ts +112 -0
- package/src/sandbox/bridges/shared/convert.ts +76 -0
- package/src/sandbox/bridges/shared/headers.ts +181 -0
- package/src/sandbox/bridges/shared/index.ts +36 -0
- package/src/sandbox/bridges/shared/json-helpers.ts +77 -0
- package/src/sandbox/bridges/shared/path-parser.ts +109 -0
- package/src/sandbox/bridges/shared/promise-helper.ts +108 -0
- package/src/sandbox/bridges/shared/registry-setup.ts +84 -0
- package/src/sandbox/bridges/shared/response-object.ts +280 -0
- package/src/sandbox/bridges/shared/result-builder.ts +130 -0
- package/src/sandbox/bridges/shared/scope-helpers.ts +44 -0
- package/src/sandbox/bridges/shared/stream-reader.ts +90 -0
- package/src/sandbox/bridges/storage-bridge.test.ts +893 -0
- package/src/sandbox/bridges/storage.ts +421 -0
- package/src/sandbox/bridges/text-decoder.ts +190 -0
- package/src/sandbox/bridges/text-encoder.ts +102 -0
- package/src/sandbox/bridges/types.ts +39 -0
- package/src/sandbox/bridges/utils.ts +123 -0
- package/src/sandbox/index.ts +6 -0
- package/src/sandbox/quickjs-wasm.d.ts +9 -0
- package/src/sandbox/sandbox.test.ts +191 -0
- package/src/sandbox/sandbox.ts +831 -0
- package/src/sandbox/test-helper.ts +43 -0
- package/src/sandbox/test-mocks.ts +154 -0
- package/src/sandbox/user-stream.test.ts +77 -0
- package/src/skills/frontmatter.test.ts +305 -0
- package/src/skills/frontmatter.ts +200 -0
- package/src/skills/index.ts +9 -0
- package/src/skills/skills-loader.test.ts +237 -0
- package/src/skills/skills-loader.ts +200 -0
- package/src/tools/actor-storage-tools.ts +250 -0
- package/src/tools/code-tools.test.ts +199 -0
- package/src/tools/code-tools.ts +444 -0
- package/src/tools/file-tools.ts +206 -0
- package/src/tools/registry.ts +125 -0
- package/src/tools/script-tools.ts +145 -0
- package/src/tools/smartbucket-tools.ts +203 -0
- package/src/tools/sql-tools.ts +213 -0
- package/src/tools/tool-factory.ts +119 -0
- package/src/types.ts +512 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +33 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Factory - Reduces boilerplate for path-based tools
|
|
3
|
+
*
|
|
4
|
+
* This factory handles common patterns:
|
|
5
|
+
* - Mount validation and resolution
|
|
6
|
+
* - Path parsing
|
|
7
|
+
* - Mount type checking
|
|
8
|
+
* - Permission (mode) checking
|
|
9
|
+
* - Consistent error messages
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Tool, ToolContext, ToolParameter } from '../types.js';
|
|
13
|
+
import type { MountInfo, MountProvider, ParsedPath } from '../types.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for creating a path-based tool
|
|
17
|
+
*/
|
|
18
|
+
export interface PathBasedToolConfig<TConfig extends Record<string, any>, TResult> {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
parameters: Record<string, ToolParameter>;
|
|
22
|
+
allowedMountTypes: MountInfo['type'][];
|
|
23
|
+
mode?: 'read' | 'write';
|
|
24
|
+
/** Name of the parameter containing the path (default: 'path', also checks 'database') */
|
|
25
|
+
pathParameterName?: string;
|
|
26
|
+
executor: (mount: MountInfo, parsed: ParsedPath, params: TConfig) => Promise<TResult>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Mount access validation utilities
|
|
31
|
+
*/
|
|
32
|
+
export class MountAccess {
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a mount path with validation
|
|
35
|
+
*/
|
|
36
|
+
static async getWithValidation(
|
|
37
|
+
mountManager: MountProvider,
|
|
38
|
+
path: string,
|
|
39
|
+
allowedTypes: MountInfo['type'][],
|
|
40
|
+
mode?: 'read' | 'write'
|
|
41
|
+
): Promise<{ mount: MountInfo; parsed: ParsedPath }> {
|
|
42
|
+
const parsed = mountManager.parsePath(path);
|
|
43
|
+
const mount = mountManager.getMount(parsed.mountName);
|
|
44
|
+
|
|
45
|
+
if (!mount) {
|
|
46
|
+
throw this.createMountNotFoundError(parsed.mountName, mountManager);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!allowedTypes.includes(mount.type)) {
|
|
50
|
+
throw this.createTypeError(mount, allowedTypes);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (mode === 'write' && mount.mode !== 'rw') {
|
|
54
|
+
throw new Error(`Cannot write to read-only mount: ${mount.name}. Mount must have mode 'rw'.`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { mount, parsed };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a "mount not found" error with helpful message
|
|
62
|
+
*/
|
|
63
|
+
static createMountNotFoundError(name: string, mountManager: MountProvider): Error {
|
|
64
|
+
const available = Array.from(mountManager.getAllMounts().keys()).join(', ');
|
|
65
|
+
return new Error(`Mount not found: ${name}. Available: ${available}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a mount type mismatch error
|
|
70
|
+
*/
|
|
71
|
+
static createTypeError(
|
|
72
|
+
mount: MountInfo,
|
|
73
|
+
allowedTypes: MountInfo['type'][]
|
|
74
|
+
): Error {
|
|
75
|
+
const typeList = allowedTypes.join(' or ');
|
|
76
|
+
return new Error(
|
|
77
|
+
`Mount '${mount.name}' is not ${typeList} (it's ${mount.type})`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a path-based tool with automatic mount validation
|
|
84
|
+
*
|
|
85
|
+
* This eliminates ~80% of boilerplate from tools that operate on mounted resources.
|
|
86
|
+
*/
|
|
87
|
+
export function createPathBasedTool<TConfig extends Record<string, any>, TResult>(
|
|
88
|
+
config: PathBasedToolConfig<TConfig, TResult>
|
|
89
|
+
): Tool {
|
|
90
|
+
return {
|
|
91
|
+
definition: {
|
|
92
|
+
name: config.name,
|
|
93
|
+
description: config.description,
|
|
94
|
+
parameters: config.parameters
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
async execute(params: any, context: ToolContext) {
|
|
98
|
+
const mountManager = context.mounts;
|
|
99
|
+
|
|
100
|
+
// Extract path from params using configured parameter name
|
|
101
|
+
const pathParam = config.pathParameterName || 'path';
|
|
102
|
+
const path = params[pathParam] || (pathParam === 'path' ? params.database : undefined);
|
|
103
|
+
if (!path) {
|
|
104
|
+
throw new Error(`Parameter '${pathParam}' is required`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Validate mount and get resource
|
|
108
|
+
const { mount, parsed } = await MountAccess.getWithValidation(
|
|
109
|
+
mountManager,
|
|
110
|
+
path,
|
|
111
|
+
config.allowedMountTypes,
|
|
112
|
+
config.mode
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// Execute the tool's logic with properly typed params
|
|
116
|
+
return config.executor(mount, parsed, params);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for Precip Agent SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Use Raindrop framework types
|
|
6
|
+
import type {
|
|
7
|
+
Ai,
|
|
8
|
+
Bucket,
|
|
9
|
+
SmartBucket,
|
|
10
|
+
KvCache,
|
|
11
|
+
SqlDatabase,
|
|
12
|
+
Actor,
|
|
13
|
+
ActorNamespace,
|
|
14
|
+
ActorStorage
|
|
15
|
+
} from '@liquidmetal-ai/raindrop-framework';
|
|
16
|
+
import type { BridgeInstaller } from './sandbox/bridges/types.js';
|
|
17
|
+
import type { z } from 'zod';
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// LLM Provider Types
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export type LLMProvider = 'openai' | 'anthropic' | 'liquidmetal';
|
|
24
|
+
|
|
25
|
+
export interface LLMConfig {
|
|
26
|
+
provider: LLMProvider;
|
|
27
|
+
model: string;
|
|
28
|
+
apiKey?: string;
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
temperature?: number;
|
|
31
|
+
maxTokens?: number;
|
|
32
|
+
streaming?: boolean;
|
|
33
|
+
aiBinding?: Ai;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface LLMMessage {
|
|
37
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
38
|
+
content: string | null;
|
|
39
|
+
name?: string;
|
|
40
|
+
tool_call_id?: string;
|
|
41
|
+
tool_calls?: LLMToolCall[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface LLMToolCall {
|
|
45
|
+
id: string;
|
|
46
|
+
type: 'function';
|
|
47
|
+
function: {
|
|
48
|
+
name: string;
|
|
49
|
+
arguments: string; // JSON string
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LLMResponse {
|
|
54
|
+
content: string | null;
|
|
55
|
+
toolCalls: LLMToolCall[];
|
|
56
|
+
finishReason: string | null;
|
|
57
|
+
usage?: {
|
|
58
|
+
promptTokens: number;
|
|
59
|
+
completionTokens: number;
|
|
60
|
+
totalTokens: number;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Mount Types
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
/** Mount types */
|
|
69
|
+
export type MountType = 'bucket' | 'smartbucket' | 'kv' | 'database' | 'actor' | 'actor-storage';
|
|
70
|
+
|
|
71
|
+
// ----------------------------------------------------------------------------
|
|
72
|
+
// Actor Method Schema (Zod-based)
|
|
73
|
+
// ----------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Schema definition for an actor RPC method.
|
|
77
|
+
* Uses Zod for type-safe, self-documenting method signatures.
|
|
78
|
+
*
|
|
79
|
+
* Arguments are represented as a tuple (z.tuple), matching the actual
|
|
80
|
+
* method signature. For example, a method `doSomething(a: string, b: number)`
|
|
81
|
+
* should have `params: z.tuple([z.string().describe("a"), z.number().describe("b")])`.
|
|
82
|
+
* A method with no arguments uses `params: z.tuple([])`.
|
|
83
|
+
*
|
|
84
|
+
* Use `.describe()` on each tuple element to name the parameter — these names
|
|
85
|
+
* appear in generated documentation and system prompts for LLMs.
|
|
86
|
+
*/
|
|
87
|
+
export interface ActorMethodSchema {
|
|
88
|
+
/** Human-readable description of what this method does */
|
|
89
|
+
description: string;
|
|
90
|
+
/**
|
|
91
|
+
* Zod tuple schema for method arguments.
|
|
92
|
+
* Each element in the tuple corresponds to a positional argument.
|
|
93
|
+
* Use `.describe("name")` on each element to provide a parameter name.
|
|
94
|
+
*
|
|
95
|
+
* Examples:
|
|
96
|
+
* - No args: `z.tuple([])`
|
|
97
|
+
* - Single arg: `z.tuple([z.object({ theme: z.string() }).describe("prefs")])`
|
|
98
|
+
* - Multiple args: `z.tuple([z.string().describe("userId"), z.number().describe("limit")])`
|
|
99
|
+
*/
|
|
100
|
+
params: z.ZodTuple<[z.ZodTypeAny, ...z.ZodTypeAny[]] | [], z.ZodTypeAny | null>;
|
|
101
|
+
/** Zod schema for return type */
|
|
102
|
+
returns: z.ZodType;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ----------------------------------------------------------------------------
|
|
106
|
+
// Discriminated Mount Configurations
|
|
107
|
+
// ----------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
/** Mount access mode */
|
|
110
|
+
export type MountMode = 'ro' | 'rw';
|
|
111
|
+
|
|
112
|
+
/** Base config for all mount types */
|
|
113
|
+
interface BaseMountConfig {
|
|
114
|
+
/** Human-readable description of what this resource is for */
|
|
115
|
+
description?: string;
|
|
116
|
+
/** Access mode: 'ro' (read-only) or 'rw' (read-write). Default: 'ro' */
|
|
117
|
+
mode?: MountMode;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Config for Bucket mounts */
|
|
121
|
+
export interface BucketMountConfig extends BaseMountConfig {
|
|
122
|
+
type: 'bucket';
|
|
123
|
+
resource: Bucket;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Config for SmartBucket mounts */
|
|
127
|
+
export interface SmartBucketMountConfig extends BaseMountConfig {
|
|
128
|
+
type: 'smartbucket';
|
|
129
|
+
resource: SmartBucket;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Config for KvCache mounts */
|
|
133
|
+
export interface KvMountConfig extends BaseMountConfig {
|
|
134
|
+
type: 'kv';
|
|
135
|
+
resource: KvCache;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Config for SqlDatabase mounts */
|
|
139
|
+
export interface SqlMountConfig extends BaseMountConfig {
|
|
140
|
+
type: 'database';
|
|
141
|
+
resource: SqlDatabase;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Config for Actor mounts - requires method schemas */
|
|
145
|
+
export interface ActorMountConfig<T extends Actor<unknown> = Actor<unknown>>
|
|
146
|
+
extends BaseMountConfig {
|
|
147
|
+
type: 'actor';
|
|
148
|
+
resource: ActorNamespace<T>;
|
|
149
|
+
/** Zod schemas for each RPC method the actor exposes */
|
|
150
|
+
methods: Record<string, ActorMethodSchema>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Config for ActorStorage mounts - exposes actor's local state.storage as a filesystem-like mount */
|
|
154
|
+
export interface ActorStorageMountConfig extends BaseMountConfig {
|
|
155
|
+
type: 'actor-storage';
|
|
156
|
+
resource: ActorStorage;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Discriminated union of all mount configs */
|
|
160
|
+
export type MountConfigType =
|
|
161
|
+
| BucketMountConfig
|
|
162
|
+
| SmartBucketMountConfig
|
|
163
|
+
| KvMountConfig
|
|
164
|
+
| SqlMountConfig
|
|
165
|
+
| ActorMountConfig
|
|
166
|
+
| ActorStorageMountConfig;
|
|
167
|
+
|
|
168
|
+
/** Mount configuration map - requires explicit type for each mount */
|
|
169
|
+
export interface MountConfig {
|
|
170
|
+
[mountName: string]: MountConfigType;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ----------------------------------------------------------------------------
|
|
174
|
+
// Internal Mount Info (normalized)
|
|
175
|
+
// ----------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
/** Base mount info after normalization */
|
|
178
|
+
interface BaseMountInfo {
|
|
179
|
+
name: string;
|
|
180
|
+
type: MountType;
|
|
181
|
+
description?: string;
|
|
182
|
+
/** Access mode: 'ro' (read-only) or 'rw' (read-write). Default: 'ro' */
|
|
183
|
+
mode?: MountMode;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Normalized info for Bucket mounts */
|
|
187
|
+
export interface BucketMountInfo extends BaseMountInfo {
|
|
188
|
+
type: 'bucket';
|
|
189
|
+
resource: Bucket;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Normalized info for SmartBucket mounts */
|
|
193
|
+
export interface SmartBucketMountInfo extends BaseMountInfo {
|
|
194
|
+
type: 'smartbucket';
|
|
195
|
+
resource: SmartBucket;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Normalized info for KvCache mounts */
|
|
199
|
+
export interface KvMountInfo extends BaseMountInfo {
|
|
200
|
+
type: 'kv';
|
|
201
|
+
resource: KvCache;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Normalized info for SqlDatabase mounts */
|
|
205
|
+
export interface SqlMountInfo extends BaseMountInfo {
|
|
206
|
+
type: 'database';
|
|
207
|
+
resource: SqlDatabase;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Normalized info for Actor mounts */
|
|
211
|
+
export interface ActorMountInfo extends BaseMountInfo {
|
|
212
|
+
type: 'actor';
|
|
213
|
+
resource: ActorNamespace<Actor<unknown>>;
|
|
214
|
+
methods: Record<string, ActorMethodSchema>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Normalized info for ActorStorage mounts */
|
|
218
|
+
export interface ActorStorageMountInfo extends BaseMountInfo {
|
|
219
|
+
type: 'actor-storage';
|
|
220
|
+
resource: ActorStorage;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Union of all normalized mount info types (discriminated by type) */
|
|
224
|
+
export type MountInfo =
|
|
225
|
+
| BucketMountInfo
|
|
226
|
+
| SmartBucketMountInfo
|
|
227
|
+
| KvMountInfo
|
|
228
|
+
| SqlMountInfo
|
|
229
|
+
| ActorMountInfo
|
|
230
|
+
| ActorStorageMountInfo;
|
|
231
|
+
|
|
232
|
+
export interface ParsedPath {
|
|
233
|
+
mountName: string;
|
|
234
|
+
path: string;
|
|
235
|
+
fullPath: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ============================================================================
|
|
239
|
+
// Tool Types
|
|
240
|
+
// ============================================================================
|
|
241
|
+
|
|
242
|
+
export interface ToolParameter {
|
|
243
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
244
|
+
description: string;
|
|
245
|
+
required?: boolean;
|
|
246
|
+
enum?: string[];
|
|
247
|
+
items?: ToolParameter;
|
|
248
|
+
properties?: Record<string, ToolParameter>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface ToolDefinition {
|
|
252
|
+
name: string;
|
|
253
|
+
description: string;
|
|
254
|
+
parameters: Record<string, ToolParameter>;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Interface for mount management in tool contexts.
|
|
259
|
+
* Provides path-based access to mounted resources.
|
|
260
|
+
* Implemented by MountManager.
|
|
261
|
+
*/
|
|
262
|
+
export interface MountProvider {
|
|
263
|
+
/** Get mount by name */
|
|
264
|
+
getMount(name: string): MountInfo | undefined;
|
|
265
|
+
/** Get all mounts as a map */
|
|
266
|
+
getAllMounts(): Map<string, MountInfo>;
|
|
267
|
+
/** Parse a full path into mount name and resource path */
|
|
268
|
+
parsePath(fullPath: string): ParsedPath;
|
|
269
|
+
/** Resolve a path to a mount and resource path */
|
|
270
|
+
resolvePath(fullPath: string): { mount: MountInfo; path: string };
|
|
271
|
+
/** List all mounts of a given type */
|
|
272
|
+
getMountsByType<T extends MountInfo['type']>(type: T): MountInfo[];
|
|
273
|
+
/** Get all actor mounts with their schemas */
|
|
274
|
+
getActorMounts(): Map<string, ActorMountInfo>;
|
|
275
|
+
/** Generate a formatted description of all mounts for system prompts */
|
|
276
|
+
getMountsDescription(): string;
|
|
277
|
+
/** Create sandbox globals from mounts */
|
|
278
|
+
createSandboxGlobals(): Record<string, unknown>;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface ToolContext {
|
|
282
|
+
mounts: MountProvider;
|
|
283
|
+
logger?: Logger;
|
|
284
|
+
env?: unknown;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface Tool {
|
|
288
|
+
definition: ToolDefinition;
|
|
289
|
+
execute: (params: any, context: ToolContext) => Promise<any>;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface ToolResult {
|
|
293
|
+
success: boolean;
|
|
294
|
+
result?: any;
|
|
295
|
+
error?: string;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ============================================================================
|
|
299
|
+
// Agent Types
|
|
300
|
+
// ============================================================================
|
|
301
|
+
|
|
302
|
+
export interface AgentConfig {
|
|
303
|
+
llm: LLMConfig;
|
|
304
|
+
system?: string;
|
|
305
|
+
mounts?: MountConfig;
|
|
306
|
+
tools?: (Tool | ToolClass)[];
|
|
307
|
+
/**
|
|
308
|
+
* Agent Skills configuration.
|
|
309
|
+
* Scans a mount path for skills and injects their metadata into the system prompt.
|
|
310
|
+
* @see https://agentskills.io/specification
|
|
311
|
+
*/
|
|
312
|
+
skills?: {
|
|
313
|
+
/** Mount path where skills are stored, e.g. "/knowledge/skills/" */
|
|
314
|
+
path: string;
|
|
315
|
+
};
|
|
316
|
+
maxTurns?: number;
|
|
317
|
+
/**
|
|
318
|
+
* Retry configuration for transient LLM failures.
|
|
319
|
+
* When set, LLM calls that throw are retried with exponential backoff.
|
|
320
|
+
* By default retries on any error — use `retryOn` to filter.
|
|
321
|
+
*/
|
|
322
|
+
retry?: RetryConfig;
|
|
323
|
+
logger?: Logger;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Configuration for retrying failed LLM calls.
|
|
328
|
+
*
|
|
329
|
+
* Defaults retry on every error. Provide `retryOn` to be selective
|
|
330
|
+
* (e.g. only retry HTTP 5xx but not 4xx auth errors).
|
|
331
|
+
*/
|
|
332
|
+
export interface RetryConfig {
|
|
333
|
+
/**
|
|
334
|
+
* Maximum number of retry attempts after the initial call (default: 2).
|
|
335
|
+
* Total attempts = maxRetries + 1.
|
|
336
|
+
* For example, maxRetries=2 means the initial call plus 2 retries (3 attempts total).
|
|
337
|
+
*/
|
|
338
|
+
maxRetries?: number;
|
|
339
|
+
/** Initial delay in ms before first retry (default: 1000) */
|
|
340
|
+
initialDelayMs?: number;
|
|
341
|
+
/** Backoff multiplier applied after each retry (default: 2) */
|
|
342
|
+
backoffMultiplier?: number;
|
|
343
|
+
/** Maximum delay cap in ms (default: 30000) */
|
|
344
|
+
maxDelayMs?: number;
|
|
345
|
+
/**
|
|
346
|
+
* Predicate to decide whether a given error should be retried.
|
|
347
|
+
* Return true to retry, false to fail immediately.
|
|
348
|
+
* Default: retry on any error.
|
|
349
|
+
*/
|
|
350
|
+
retryOn?: (error: Error) => boolean;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export interface AgentResponse {
|
|
354
|
+
message: string;
|
|
355
|
+
reasoning?: string;
|
|
356
|
+
toolCalls?: ToolCallResult[];
|
|
357
|
+
turns: number;
|
|
358
|
+
finishReason: string | null;
|
|
359
|
+
usage?: {
|
|
360
|
+
promptTokens: number;
|
|
361
|
+
completionTokens: number;
|
|
362
|
+
totalTokens: number;
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface ToolCallResult {
|
|
367
|
+
turn: number;
|
|
368
|
+
toolCallId: string;
|
|
369
|
+
toolName: string;
|
|
370
|
+
arguments: any;
|
|
371
|
+
result: any;
|
|
372
|
+
success: boolean;
|
|
373
|
+
error?: string;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export interface ConversationState {
|
|
377
|
+
messages: LLMMessage[];
|
|
378
|
+
turnCount: number;
|
|
379
|
+
totalTokens: number;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// ============================================================================
|
|
383
|
+
// Sandbox Types
|
|
384
|
+
// ============================================================================
|
|
385
|
+
|
|
386
|
+
export interface SandboxResult {
|
|
387
|
+
success: boolean;
|
|
388
|
+
result?: any;
|
|
389
|
+
error?: string;
|
|
390
|
+
executionTime?: number;
|
|
391
|
+
consoleOutput?: string[];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface SandboxOptions {
|
|
395
|
+
timeoutMs?: number;
|
|
396
|
+
memoryLimitBytes?: number;
|
|
397
|
+
logger?: Logger;
|
|
398
|
+
/** Additional bridge installers to run after standard bridges */
|
|
399
|
+
bridgeInstallers?: BridgeInstaller[];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ----------------------------------------------------------------------------
|
|
403
|
+
// Typed Sandbox Globals
|
|
404
|
+
// ----------------------------------------------------------------------------
|
|
405
|
+
|
|
406
|
+
/** An async function to expose in the sandbox — always returns a promise to sandbox code */
|
|
407
|
+
export interface AsyncSandboxGlobal {
|
|
408
|
+
kind: 'async';
|
|
409
|
+
fn: (...args: any[]) => Promise<any>;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** A sync function to expose in the sandbox — returns the value directly */
|
|
413
|
+
export interface SyncSandboxGlobal {
|
|
414
|
+
kind: 'sync';
|
|
415
|
+
fn: (...args: any[]) => any;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** An object with typed methods and optional static properties */
|
|
419
|
+
export interface ObjectSandboxGlobal {
|
|
420
|
+
kind: 'object';
|
|
421
|
+
methods: Record<string, AsyncSandboxGlobal | SyncSandboxGlobal>;
|
|
422
|
+
properties?: Record<string, any>;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** A single sandbox global entry */
|
|
426
|
+
export type SandboxGlobal =
|
|
427
|
+
| AsyncSandboxGlobal
|
|
428
|
+
| SyncSandboxGlobal
|
|
429
|
+
| ObjectSandboxGlobal
|
|
430
|
+
| number
|
|
431
|
+
| string
|
|
432
|
+
| boolean
|
|
433
|
+
| null
|
|
434
|
+
| undefined
|
|
435
|
+
| any[]
|
|
436
|
+
| Record<string, unknown>;
|
|
437
|
+
|
|
438
|
+
/** Map of named globals to inject into the sandbox */
|
|
439
|
+
export interface SandboxGlobals {
|
|
440
|
+
[key: string]: SandboxGlobal;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Helper constructors for typed globals
|
|
444
|
+
|
|
445
|
+
/** Wrap an async function for sandbox injection */
|
|
446
|
+
export function sandboxAsync(fn: (...args: any[]) => Promise<any>): AsyncSandboxGlobal {
|
|
447
|
+
return { kind: 'async', fn };
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** Wrap a sync function for sandbox injection */
|
|
451
|
+
export function sandboxSync(fn: (...args: any[]) => any): SyncSandboxGlobal {
|
|
452
|
+
return { kind: 'sync', fn };
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** Wrap an object with typed methods for sandbox injection */
|
|
456
|
+
export function sandboxObject(
|
|
457
|
+
methods: Record<string, AsyncSandboxGlobal | SyncSandboxGlobal>,
|
|
458
|
+
properties?: Record<string, any>
|
|
459
|
+
): ObjectSandboxGlobal {
|
|
460
|
+
return { kind: 'object', methods, properties };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// ============================================================================
|
|
464
|
+
// Agent Streaming Event Types
|
|
465
|
+
// ============================================================================
|
|
466
|
+
|
|
467
|
+
export type AgentEventType =
|
|
468
|
+
| 'tool_call_start'
|
|
469
|
+
| 'tool_call_end'
|
|
470
|
+
| 'llm_response'
|
|
471
|
+
| 'turn_complete';
|
|
472
|
+
|
|
473
|
+
export interface AgentEvent {
|
|
474
|
+
type: AgentEventType;
|
|
475
|
+
turn: number;
|
|
476
|
+
toolCall?: {
|
|
477
|
+
id: string;
|
|
478
|
+
name: string;
|
|
479
|
+
arguments: Record<string, unknown>;
|
|
480
|
+
};
|
|
481
|
+
toolResult?: {
|
|
482
|
+
id: string;
|
|
483
|
+
name: string;
|
|
484
|
+
result: unknown;
|
|
485
|
+
success: boolean;
|
|
486
|
+
error?: string;
|
|
487
|
+
};
|
|
488
|
+
message?: string;
|
|
489
|
+
finishReason?: string | null;
|
|
490
|
+
usage?: { promptTokens: number; completionTokens: number; totalTokens: number };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// ============================================================================
|
|
494
|
+
// Logger Types
|
|
495
|
+
// ============================================================================
|
|
496
|
+
|
|
497
|
+
export interface Logger {
|
|
498
|
+
info(message: string, data?: any): void;
|
|
499
|
+
warn(message: string, data?: any): void;
|
|
500
|
+
error(message: string, data?: any): void;
|
|
501
|
+
debug(message: string, data?: any): void;
|
|
502
|
+
with?(data: any): Logger;
|
|
503
|
+
withError?(error: Error): Logger;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ============================================================================
|
|
507
|
+
// Tool Class Interface
|
|
508
|
+
// ============================================================================
|
|
509
|
+
|
|
510
|
+
export interface ToolClass {
|
|
511
|
+
new (context: ToolContext): Tool;
|
|
512
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"extends": "@liquidmetal-ai/typescript-config/base.json",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"lib": ["ESNext", "WebWorker"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"noEmit": false,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"types": ["@liquidmetal-ai/raindrop-framework"]
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"],
|
|
14
|
+
"exclude": ["eslint.config.js", "node_modules", "dist", "examples", "src/**/*.test.ts"]
|
|
15
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
testTimeout: 10000,
|
|
8
|
+
passWithNoTests: true
|
|
9
|
+
},
|
|
10
|
+
plugins: [
|
|
11
|
+
{
|
|
12
|
+
name: 'wasm-stub',
|
|
13
|
+
enforce: 'pre',
|
|
14
|
+
resolveId(id) {
|
|
15
|
+
// Stub the /wasm export from @jitl packages.
|
|
16
|
+
// In Raindrop this resolves to a WebAssembly.Module,
|
|
17
|
+
// but in Node.js tests the quickjs library loads WASM from disk
|
|
18
|
+
// automatically, so we just need to prevent the import from failing.
|
|
19
|
+
if (id.includes('/wasm') && id.includes('@jitl')) {
|
|
20
|
+
return '\0virtual:wasm-stub';
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
load(id) {
|
|
24
|
+
if (id === '\0virtual:wasm-stub') {
|
|
25
|
+
return 'export default undefined;';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
build: {
|
|
31
|
+
target: 'esnext'
|
|
32
|
+
}
|
|
33
|
+
});
|