@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,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming Response Parser - Shared logic for parsing OpenAI-format streams
|
|
3
|
+
*
|
|
4
|
+
* Both OpenAIProvider and LiquidmetalProvider use OpenAI-compatible streaming formats.
|
|
5
|
+
* This shared parser eliminates ~100 lines of duplication.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { LLMResponse, LLMToolCall, Logger } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parse an OpenAI-compatible streaming response
|
|
12
|
+
*
|
|
13
|
+
* Handles:
|
|
14
|
+
* - Standard OpenAI format: { choices: [{ delta: { content }, tool_calls: [...] }] }
|
|
15
|
+
* - DeepSeek-R1 format: { response: "..." }
|
|
16
|
+
* - Tool call accumulation across multiple chunks
|
|
17
|
+
*/
|
|
18
|
+
export async function parseOpenAIStream(
|
|
19
|
+
stream: ReadableStream,
|
|
20
|
+
logger?: Logger,
|
|
21
|
+
deepSeekMode = false
|
|
22
|
+
): Promise<LLMResponse> {
|
|
23
|
+
const reader = stream.getReader();
|
|
24
|
+
const decoder = new TextDecoder();
|
|
25
|
+
let buffer = '';
|
|
26
|
+
|
|
27
|
+
const toolCallsMap = new Map<number, LLMToolCall>();
|
|
28
|
+
let content = '';
|
|
29
|
+
let finishReason: string | null = null;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
while (true) {
|
|
33
|
+
const { done, value } = await reader.read();
|
|
34
|
+
if (done) break;
|
|
35
|
+
|
|
36
|
+
buffer += decoder.decode(value, { stream: true });
|
|
37
|
+
const lines = buffer.split('\n\n');
|
|
38
|
+
buffer = lines.pop() || '';
|
|
39
|
+
|
|
40
|
+
for (const line of lines) {
|
|
41
|
+
if (!line.trim() || line.trim() === 'data: [DONE]') continue;
|
|
42
|
+
|
|
43
|
+
const jsonStr = line.replace(/^data: /, '').trim();
|
|
44
|
+
if (!jsonStr) continue;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const chunk = JSON.parse(jsonStr);
|
|
48
|
+
|
|
49
|
+
// Check for error responses from the AI service
|
|
50
|
+
if (chunk.error) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`AI service error: ${chunk.error.message || JSON.stringify(chunk.error)}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Handle DeepSeek-R1 streaming format: {"response": "..."}
|
|
57
|
+
if (deepSeekMode && chunk.response !== undefined) {
|
|
58
|
+
content += chunk.response;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle OpenAI-compatible format: {"choices": [...]}
|
|
63
|
+
const choice = chunk.choices?.[0];
|
|
64
|
+
if (!choice) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Accumulate content
|
|
69
|
+
if (choice.delta?.content) {
|
|
70
|
+
content += choice.delta.content;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Accumulate tool calls
|
|
74
|
+
if (choice.delta?.tool_calls) {
|
|
75
|
+
for (const toolCallDelta of choice.delta.tool_calls) {
|
|
76
|
+
const index = toolCallDelta.index;
|
|
77
|
+
|
|
78
|
+
if (!toolCallsMap.has(index)) {
|
|
79
|
+
toolCallsMap.set(index, {
|
|
80
|
+
id: toolCallDelta.id || '',
|
|
81
|
+
type: 'function',
|
|
82
|
+
function: {
|
|
83
|
+
name: toolCallDelta.function?.name || '',
|
|
84
|
+
arguments: toolCallDelta.function?.arguments || ''
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
const existing = toolCallsMap.get(index)!;
|
|
89
|
+
if (toolCallDelta.function?.arguments) {
|
|
90
|
+
existing.function.arguments += toolCallDelta.function?.arguments;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (choice.finish_reason) {
|
|
97
|
+
finishReason = choice.finish_reason;
|
|
98
|
+
}
|
|
99
|
+
} catch (e) {
|
|
100
|
+
logger?.warn?.('Failed to parse streaming chunk', {
|
|
101
|
+
error: (e as Error).message,
|
|
102
|
+
jsonStr: jsonStr.substring(0, 200)
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} finally {
|
|
108
|
+
reader.releaseLock();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Validate accumulated tool call arguments are valid JSON
|
|
112
|
+
if (toolCallsMap.size > 0) {
|
|
113
|
+
for (const [index, toolCall] of toolCallsMap.entries()) {
|
|
114
|
+
if (toolCall.function.arguments) {
|
|
115
|
+
try {
|
|
116
|
+
JSON.parse(toolCall.function.arguments);
|
|
117
|
+
} catch (_e) {
|
|
118
|
+
logger?.error?.(
|
|
119
|
+
`Invalid JSON in tool call ${index} (${toolCall.function.name}): ${toolCall.function.arguments.substring(0, 200)}`
|
|
120
|
+
);
|
|
121
|
+
// Remove the invalid tool call to prevent downstream errors
|
|
122
|
+
toolCallsMap.delete(index);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
content: content || null,
|
|
130
|
+
toolCalls: Array.from(toolCallsMap.values()),
|
|
131
|
+
finishReason
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse a non-streaming OpenAI-compatible response
|
|
137
|
+
*/
|
|
138
|
+
export function parseOpenAIResponse(data: any): LLMResponse {
|
|
139
|
+
if (!data) {
|
|
140
|
+
return {
|
|
141
|
+
content: null,
|
|
142
|
+
toolCalls: [],
|
|
143
|
+
finishReason: 'error'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!data.choices || data.choices.length === 0) {
|
|
148
|
+
return {
|
|
149
|
+
content: null,
|
|
150
|
+
toolCalls: [],
|
|
151
|
+
finishReason: 'error'
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const choice = data.choices[0];
|
|
156
|
+
const message = choice?.message;
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
content: message?.content || null,
|
|
160
|
+
toolCalls: message?.tool_calls || [],
|
|
161
|
+
finishReason: choice?.finish_reason || null,
|
|
162
|
+
usage: data.usage
|
|
163
|
+
? {
|
|
164
|
+
promptTokens: data.usage.prompt_tokens,
|
|
165
|
+
completionTokens: data.usage.completion_tokens,
|
|
166
|
+
totalTokens: data.usage.total_tokens
|
|
167
|
+
}
|
|
168
|
+
: undefined
|
|
169
|
+
};
|
|
170
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precip - Agent SDK for Raindrop
|
|
3
|
+
*
|
|
4
|
+
* Build sophisticated LLM-powered agents with tool calling and sandboxed code execution
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Core Agent
|
|
8
|
+
export { PrecipAgent } from './engine/agent.js';
|
|
9
|
+
|
|
10
|
+
// LLM Provider
|
|
11
|
+
export { createLLMProvider } from './engine/llm-provider.js';
|
|
12
|
+
|
|
13
|
+
// Mounts
|
|
14
|
+
export { MountManager } from './mounts/mount-manager.js';
|
|
15
|
+
|
|
16
|
+
// Tools
|
|
17
|
+
export { ToolRegistry } from './tools/registry.js';
|
|
18
|
+
export {
|
|
19
|
+
FileTools,
|
|
20
|
+
ReadFileTool,
|
|
21
|
+
WriteFileTool,
|
|
22
|
+
ListFilesTool,
|
|
23
|
+
DeleteFileTool
|
|
24
|
+
} from './tools/file-tools.js';
|
|
25
|
+
export { SqlTools, SqlQueryTool, SqlExecuteTool, SqlBatchTool } from './tools/sql-tools.js';
|
|
26
|
+
export { CodeTools, CodeExecutionTool, createCodeExecutionTool, createMountGlobals } from './tools/code-tools.js';
|
|
27
|
+
export type { CodeToolOptions } from './tools/code-tools.js';
|
|
28
|
+
export {
|
|
29
|
+
ScriptTools,
|
|
30
|
+
ScriptExecutionTool,
|
|
31
|
+
createScriptExecutionTool
|
|
32
|
+
} from './tools/script-tools.js';
|
|
33
|
+
export type { ScriptToolOptions } from './tools/script-tools.js';
|
|
34
|
+
export {
|
|
35
|
+
SmartBucketTools,
|
|
36
|
+
SemanticSearchTool,
|
|
37
|
+
ChunkSearchTool,
|
|
38
|
+
GetSearchPageTool
|
|
39
|
+
} from './tools/smartbucket-tools.js';
|
|
40
|
+
export {
|
|
41
|
+
ActorStorageTools,
|
|
42
|
+
ReadStateTool,
|
|
43
|
+
WriteStateTool,
|
|
44
|
+
ListStateTool,
|
|
45
|
+
DeleteStateTool
|
|
46
|
+
} from './tools/actor-storage-tools.js';
|
|
47
|
+
|
|
48
|
+
// Sandbox
|
|
49
|
+
export { Sandbox } from './sandbox/index.js';
|
|
50
|
+
|
|
51
|
+
// Skills
|
|
52
|
+
export { discoverSkills, generateSkillsPrompt, parseFrontmatter } from './skills/index.js';
|
|
53
|
+
export type { SkillMetadata, SkillsConfig, SkillFrontmatter } from './skills/index.js';
|
|
54
|
+
|
|
55
|
+
// Presets
|
|
56
|
+
export { ScriptAgentTools, ToolAgentTools } from './presets/index.js';
|
|
57
|
+
|
|
58
|
+
// Types
|
|
59
|
+
export type {
|
|
60
|
+
// LLM Types
|
|
61
|
+
LLMProvider,
|
|
62
|
+
LLMConfig,
|
|
63
|
+
LLMMessage,
|
|
64
|
+
LLMResponse,
|
|
65
|
+
LLMToolCall,
|
|
66
|
+
|
|
67
|
+
// Mount Types
|
|
68
|
+
MountConfig,
|
|
69
|
+
MountConfigType,
|
|
70
|
+
MountInfo,
|
|
71
|
+
MountType,
|
|
72
|
+
MountMode,
|
|
73
|
+
ParsedPath,
|
|
74
|
+
|
|
75
|
+
// Mount Config Types
|
|
76
|
+
BucketMountConfig,
|
|
77
|
+
SmartBucketMountConfig,
|
|
78
|
+
KvMountConfig,
|
|
79
|
+
SqlMountConfig,
|
|
80
|
+
ActorMountConfig,
|
|
81
|
+
ActorStorageMountConfig,
|
|
82
|
+
ActorMethodSchema,
|
|
83
|
+
BucketMountInfo,
|
|
84
|
+
SmartBucketMountInfo,
|
|
85
|
+
KvMountInfo,
|
|
86
|
+
SqlMountInfo,
|
|
87
|
+
ActorMountInfo,
|
|
88
|
+
ActorStorageMountInfo,
|
|
89
|
+
|
|
90
|
+
// Tool Types
|
|
91
|
+
Tool,
|
|
92
|
+
ToolDefinition,
|
|
93
|
+
ToolParameter,
|
|
94
|
+
ToolContext,
|
|
95
|
+
ToolResult,
|
|
96
|
+
ToolClass,
|
|
97
|
+
|
|
98
|
+
// Agent Types
|
|
99
|
+
AgentConfig,
|
|
100
|
+
AgentResponse,
|
|
101
|
+
AgentEvent,
|
|
102
|
+
AgentEventType,
|
|
103
|
+
ToolCallResult,
|
|
104
|
+
ConversationState,
|
|
105
|
+
RetryConfig,
|
|
106
|
+
|
|
107
|
+
// Sandbox Types
|
|
108
|
+
SandboxResult,
|
|
109
|
+
SandboxOptions,
|
|
110
|
+
SandboxGlobals,
|
|
111
|
+
SandboxGlobal,
|
|
112
|
+
AsyncSandboxGlobal,
|
|
113
|
+
SyncSandboxGlobal,
|
|
114
|
+
ObjectSandboxGlobal,
|
|
115
|
+
|
|
116
|
+
// Logger
|
|
117
|
+
Logger
|
|
118
|
+
} from './types.js';
|
|
119
|
+
// Sandbox global helpers
|
|
120
|
+
export { sandboxAsync, sandboxSync, sandboxObject } from './types.js';
|
|
121
|
+
export type { BridgeInstaller } from './sandbox/bridges/types.js';
|
|
122
|
+
// Utilities
|
|
123
|
+
export { zodToTypeString } from './mounts/zod-to-string.js';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Helper to create a custom tool
|
|
127
|
+
*/
|
|
128
|
+
export function createTool(config: {
|
|
129
|
+
name: string;
|
|
130
|
+
description: string;
|
|
131
|
+
parameters: Record<string, any>;
|
|
132
|
+
execute: (params: any, context: any) => Promise<any>;
|
|
133
|
+
}): any {
|
|
134
|
+
return {
|
|
135
|
+
definition: {
|
|
136
|
+
name: config.name,
|
|
137
|
+
description: config.description,
|
|
138
|
+
parameters: config.parameters
|
|
139
|
+
},
|
|
140
|
+
execute: config.execute
|
|
141
|
+
};
|
|
142
|
+
}
|