@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.
Files changed (78) hide show
  1. package/.prettierrc +9 -0
  2. package/CHANGELOG.md +8 -0
  3. package/eslint.config.mjs +28 -0
  4. package/package.json +53 -0
  5. package/src/engine/agent.ts +478 -0
  6. package/src/engine/llm-provider.test.ts +275 -0
  7. package/src/engine/llm-provider.ts +330 -0
  8. package/src/engine/stream-parser.ts +170 -0
  9. package/src/index.ts +142 -0
  10. package/src/mounts/mount-manager.test.ts +516 -0
  11. package/src/mounts/mount-manager.ts +327 -0
  12. package/src/mounts/mount-registry.ts +196 -0
  13. package/src/mounts/zod-to-string.test.ts +154 -0
  14. package/src/mounts/zod-to-string.ts +213 -0
  15. package/src/presets/agent-tools.ts +57 -0
  16. package/src/presets/index.ts +5 -0
  17. package/src/sandbox/README.md +1321 -0
  18. package/src/sandbox/bridges/README.md +571 -0
  19. package/src/sandbox/bridges/actor.test.ts +229 -0
  20. package/src/sandbox/bridges/actor.ts +195 -0
  21. package/src/sandbox/bridges/bridge-fixes.test.ts +614 -0
  22. package/src/sandbox/bridges/bucket.test.ts +300 -0
  23. package/src/sandbox/bridges/cleanup-reproduction.test.ts +225 -0
  24. package/src/sandbox/bridges/console-multiple.test.ts +187 -0
  25. package/src/sandbox/bridges/console.test.ts +157 -0
  26. package/src/sandbox/bridges/console.ts +122 -0
  27. package/src/sandbox/bridges/fetch.ts +93 -0
  28. package/src/sandbox/bridges/index.ts +78 -0
  29. package/src/sandbox/bridges/readable-stream.ts +323 -0
  30. package/src/sandbox/bridges/response.test.ts +154 -0
  31. package/src/sandbox/bridges/response.ts +123 -0
  32. package/src/sandbox/bridges/review-fixes.test.ts +331 -0
  33. package/src/sandbox/bridges/search.test.ts +475 -0
  34. package/src/sandbox/bridges/search.ts +264 -0
  35. package/src/sandbox/bridges/shared/body-methods.ts +93 -0
  36. package/src/sandbox/bridges/shared/cleanup.ts +112 -0
  37. package/src/sandbox/bridges/shared/convert.ts +76 -0
  38. package/src/sandbox/bridges/shared/headers.ts +181 -0
  39. package/src/sandbox/bridges/shared/index.ts +36 -0
  40. package/src/sandbox/bridges/shared/json-helpers.ts +77 -0
  41. package/src/sandbox/bridges/shared/path-parser.ts +109 -0
  42. package/src/sandbox/bridges/shared/promise-helper.ts +108 -0
  43. package/src/sandbox/bridges/shared/registry-setup.ts +84 -0
  44. package/src/sandbox/bridges/shared/response-object.ts +280 -0
  45. package/src/sandbox/bridges/shared/result-builder.ts +130 -0
  46. package/src/sandbox/bridges/shared/scope-helpers.ts +44 -0
  47. package/src/sandbox/bridges/shared/stream-reader.ts +90 -0
  48. package/src/sandbox/bridges/storage-bridge.test.ts +893 -0
  49. package/src/sandbox/bridges/storage.ts +421 -0
  50. package/src/sandbox/bridges/text-decoder.ts +190 -0
  51. package/src/sandbox/bridges/text-encoder.ts +102 -0
  52. package/src/sandbox/bridges/types.ts +39 -0
  53. package/src/sandbox/bridges/utils.ts +123 -0
  54. package/src/sandbox/index.ts +6 -0
  55. package/src/sandbox/quickjs-wasm.d.ts +9 -0
  56. package/src/sandbox/sandbox.test.ts +191 -0
  57. package/src/sandbox/sandbox.ts +831 -0
  58. package/src/sandbox/test-helper.ts +43 -0
  59. package/src/sandbox/test-mocks.ts +154 -0
  60. package/src/sandbox/user-stream.test.ts +77 -0
  61. package/src/skills/frontmatter.test.ts +305 -0
  62. package/src/skills/frontmatter.ts +200 -0
  63. package/src/skills/index.ts +9 -0
  64. package/src/skills/skills-loader.test.ts +237 -0
  65. package/src/skills/skills-loader.ts +200 -0
  66. package/src/tools/actor-storage-tools.ts +250 -0
  67. package/src/tools/code-tools.test.ts +199 -0
  68. package/src/tools/code-tools.ts +444 -0
  69. package/src/tools/file-tools.ts +206 -0
  70. package/src/tools/registry.ts +125 -0
  71. package/src/tools/script-tools.ts +145 -0
  72. package/src/tools/smartbucket-tools.ts +203 -0
  73. package/src/tools/sql-tools.ts +213 -0
  74. package/src/tools/tool-factory.ts +119 -0
  75. package/src/types.ts +512 -0
  76. package/tsconfig.eslint.json +5 -0
  77. package/tsconfig.json +15 -0
  78. 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
+ }