@positronic/template-new-project 0.0.2
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/.claude/settings.local.json +8 -0
- package/CLAUDE.md +215 -0
- package/index.js +180 -0
- package/package.json +18 -0
- package/template/.positronic/package.json +17 -0
- package/template/.positronic/src/index.ts +35 -0
- package/template/.positronic/tsconfig.json +19 -0
- package/template/.positronic/wrangler.jsonc +53 -0
- package/template/CLAUDE.md +120 -0
- package/template/_env +32 -0
- package/template/_gitignore +24 -0
- package/template/brain.ts +59 -0
- package/template/brains/example.ts +13 -0
- package/template/docs/brain-dsl-guide.md +601 -0
- package/template/docs/brain-testing-guide.md +307 -0
- package/template/docs/positronic-guide.md +236 -0
- package/template/docs/tips-for-agents.md +425 -0
- package/template/jest.config.js +24 -0
- package/template/package.json +29 -0
- package/template/positronic.config.json +8 -0
- package/template/resources/example.md +0 -0
- package/template/runner.ts +9 -0
- package/template/tests/example.test.ts +20 -0
- package/template/tsconfig.json +16 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Tips for AI Agents
|
|
2
|
+
|
|
3
|
+
This document contains helpful tips and patterns for AI agents working with Positronic projects.
|
|
4
|
+
|
|
5
|
+
## TypeScript Compilation
|
|
6
|
+
|
|
7
|
+
Run `npm run typecheck` frequently as you make changes to ensure your TypeScript code compiles correctly. This will catch type errors early and help maintain code quality.
|
|
8
|
+
|
|
9
|
+
## Running the Development Server
|
|
10
|
+
|
|
11
|
+
When you need to run a development server, use the `--log-file` option to capture server output. **Important**: Always place the server log file in the `/tmp` directory so it gets cleaned up automatically by the operating system.
|
|
12
|
+
|
|
13
|
+
### 1. Start the server with logging
|
|
14
|
+
|
|
15
|
+
**Default mode (recommended for most cases):**
|
|
16
|
+
```bash
|
|
17
|
+
px server -d
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This starts the server on the default port (3000) with logs written to `.positronic-server.log`.
|
|
21
|
+
|
|
22
|
+
**Custom port mode (when you need a specific port):**
|
|
23
|
+
|
|
24
|
+
First, generate a random port between 30000 and 50000:
|
|
25
|
+
```bash
|
|
26
|
+
echo $((30000 + RANDOM % 20000))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Remember this port number** and use it for all subsequent commands. For example, if the port is 38291:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
px server --port 38291 --log-file /tmp/server-38291.log -d
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Note: When using `--port` with `-d`, you MUST also specify `--log-file`.
|
|
36
|
+
|
|
37
|
+
The `-d` flag runs the server in detached/background mode. The server will output its process ID (PID) which you can use to stop it later.
|
|
38
|
+
|
|
39
|
+
### 2. Run commands using your server
|
|
40
|
+
|
|
41
|
+
**If using default port (3000):**
|
|
42
|
+
```bash
|
|
43
|
+
# No need to set POSITRONIC_PORT
|
|
44
|
+
px brain list
|
|
45
|
+
px brain run my-brain
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**If using custom port:**
|
|
49
|
+
```bash
|
|
50
|
+
# Set the port environment variable for subsequent commands (using your remembered port)
|
|
51
|
+
export POSITRONIC_PORT=38291
|
|
52
|
+
|
|
53
|
+
# Now all px commands will use your server
|
|
54
|
+
px brain list
|
|
55
|
+
px brain run my-brain
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Check server logs when needed
|
|
59
|
+
|
|
60
|
+
**Default server:**
|
|
61
|
+
```bash
|
|
62
|
+
# View the entire log file
|
|
63
|
+
cat .positronic-server.log
|
|
64
|
+
|
|
65
|
+
# View the last 50 lines of the log file
|
|
66
|
+
tail -n 50 .positronic-server.log
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Custom port server:**
|
|
70
|
+
```bash
|
|
71
|
+
# View the entire log file (using your remembered port)
|
|
72
|
+
cat /tmp/server-38291.log
|
|
73
|
+
|
|
74
|
+
# View the last 50 lines of the log file
|
|
75
|
+
tail -n 50 /tmp/server-38291.log
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. Stop the server when done
|
|
79
|
+
|
|
80
|
+
**Using the built-in kill option (recommended for default server):**
|
|
81
|
+
```bash
|
|
82
|
+
# Kill default server
|
|
83
|
+
px server -k
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Manual methods:**
|
|
87
|
+
```bash
|
|
88
|
+
# Default server
|
|
89
|
+
kill $(cat .positronic-server.pid)
|
|
90
|
+
|
|
91
|
+
# Custom port server (PID file includes port number)
|
|
92
|
+
kill $(cat .positronic-server-38291.pid)
|
|
93
|
+
|
|
94
|
+
# Or find and kill the server process by port
|
|
95
|
+
kill $(lsof -ti:38291)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Important Notes
|
|
99
|
+
- The `-d` flag runs the server in detached/background mode (similar to Docker's -d)
|
|
100
|
+
- Default server: PID stored in `.positronic-server.pid`, logs in `.positronic-server.log`
|
|
101
|
+
- Custom port servers: PID stored in `.positronic-server-{port}.pid`
|
|
102
|
+
- When using `--port` with `-d`, you MUST also specify `--log-file`
|
|
103
|
+
- Log files are always appended to (never overwritten)
|
|
104
|
+
- The server will error if another server is already running on the same port
|
|
105
|
+
- Always clean up by killing the server process when done
|
|
106
|
+
- The log file contains timestamped entries with [INFO], [ERROR], and [WARN] prefixes
|
|
107
|
+
|
|
108
|
+
## Brain DSL Type Inference
|
|
109
|
+
|
|
110
|
+
The Brain DSL has very strong type inference capabilities. **Important**: You should NOT explicitly specify types on the state object as it flows through steps. The types are automatically inferred from the previous step.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// ❌ DON'T DO THIS - unnecessary type annotations
|
|
114
|
+
brain('example')
|
|
115
|
+
.step('init', ({ state }: { state: {} }) => ({
|
|
116
|
+
count: 0,
|
|
117
|
+
name: 'test'
|
|
118
|
+
}))
|
|
119
|
+
.step('process', ({ state }: { state: { count: number; name: string } }) => ({
|
|
120
|
+
...state,
|
|
121
|
+
processed: true
|
|
122
|
+
}))
|
|
123
|
+
|
|
124
|
+
// ✅ DO THIS - let TypeScript infer the types
|
|
125
|
+
brain('example')
|
|
126
|
+
.step('init', ({ state }) => ({
|
|
127
|
+
count: 0,
|
|
128
|
+
name: 'test'
|
|
129
|
+
}))
|
|
130
|
+
.step('process', ({ state }) => ({
|
|
131
|
+
...state, // TypeScript knows state has count: number and name: string
|
|
132
|
+
processed: true
|
|
133
|
+
}))
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The type inference flows through the entire chain, making the code cleaner and more maintainable.
|
|
137
|
+
|
|
138
|
+
## Error Handling in Brains
|
|
139
|
+
|
|
140
|
+
**Important**: Do NOT catch errors in brain steps unless error handling is specifically part of the brain's workflow logic. The brain runner handles all errors automatically.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// ❌ DON'T DO THIS - unnecessary error catching
|
|
144
|
+
brain('example')
|
|
145
|
+
.step('fetch data', async ({ state }) => {
|
|
146
|
+
try {
|
|
147
|
+
const data = await fetchSomeData();
|
|
148
|
+
return { ...state, data };
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error('Error:', error);
|
|
151
|
+
return { ...state, error: error.message };
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// ✅ DO THIS - let errors propagate
|
|
156
|
+
brain('example')
|
|
157
|
+
.step('fetch data', async ({ state }) => {
|
|
158
|
+
const data = await fetchSomeData(); // If this throws, the runner handles it
|
|
159
|
+
return { ...state, data };
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// ✅ ONLY catch errors when it's part of the workflow logic
|
|
163
|
+
brain('validation-example')
|
|
164
|
+
.step('validate input', async ({ state }) => {
|
|
165
|
+
try {
|
|
166
|
+
const result = await validateData(state.input);
|
|
167
|
+
return { ...state, valid: true, result };
|
|
168
|
+
} catch (validationError) {
|
|
169
|
+
// Only if the next step needs to know about validation failures
|
|
170
|
+
return { ...state, valid: false, validationError: validationError.message };
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
.step('process based on validation', ({ state }) => {
|
|
174
|
+
if (!state.valid) {
|
|
175
|
+
// Handle validation failure as part of the workflow
|
|
176
|
+
return { ...state, status: 'validation-failed' };
|
|
177
|
+
}
|
|
178
|
+
// Continue with valid data
|
|
179
|
+
return { ...state, status: 'processing' };
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Most generated brains should not have try-catch blocks. Only use them when the error state is meaningful to subsequent steps in the workflow.
|
|
184
|
+
|
|
185
|
+
## Service Organization
|
|
186
|
+
|
|
187
|
+
When implementing services for the project brain, consider creating a `services/` directory at the root of your project to keep service implementations organized and reusable:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
services/
|
|
191
|
+
├── gmail.js # Gmail API integration
|
|
192
|
+
├── slack.js # Slack notifications
|
|
193
|
+
├── database.js # Database client
|
|
194
|
+
└── analytics.js # Analytics tracking
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Then in your `brain.ts` (at the project root):
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import gmail from './services/gmail.js';
|
|
201
|
+
import slack from './services/slack.js';
|
|
202
|
+
import database from './services/database.js';
|
|
203
|
+
import analytics from './services/analytics.js';
|
|
204
|
+
|
|
205
|
+
export function brain<
|
|
206
|
+
TOptions extends object = object,
|
|
207
|
+
TState extends object = object
|
|
208
|
+
>(
|
|
209
|
+
brainConfig: string | { title: string; description?: string }
|
|
210
|
+
) {
|
|
211
|
+
return coreBrain(brainConfig)
|
|
212
|
+
.withServices({
|
|
213
|
+
gmail,
|
|
214
|
+
slack,
|
|
215
|
+
database,
|
|
216
|
+
analytics
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This keeps your service implementations separate from your brain logic and makes them easier to test and maintain.
|
|
222
|
+
|
|
223
|
+
## Important: ESM Module Imports
|
|
224
|
+
|
|
225
|
+
This project uses ES modules (ESM). **Always include the `.js` extension in your imports**, even when importing TypeScript files:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// ✅ CORRECT - Include .js extension
|
|
229
|
+
import { brain } from '../brain.js'; // From a file in brains/ directory
|
|
230
|
+
import { analyzeData } from '../utils/analyzer.js';
|
|
231
|
+
import gmail from '../services/gmail.js';
|
|
232
|
+
|
|
233
|
+
// ❌ WRONG - Missing .js extension
|
|
234
|
+
import { brain } from '../brain';
|
|
235
|
+
import { analyzeData } from '../utils/analyzer';
|
|
236
|
+
import gmail from '../services/gmail';
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
This applies to all imports in:
|
|
240
|
+
- Brain files
|
|
241
|
+
- Service files
|
|
242
|
+
- Test files
|
|
243
|
+
- Any other TypeScript/JavaScript files
|
|
244
|
+
|
|
245
|
+
The `.js` extension is required for ESM compatibility, even though the source files are `.ts`.
|
|
246
|
+
|
|
247
|
+
## Creating New Brains - Test-Driven Development
|
|
248
|
+
|
|
249
|
+
**IMPORTANT**: When asked to generate or create a new brain, you should ALWAYS follow this test-driven development approach. This ensures the brain works correctly and helps catch issues early.
|
|
250
|
+
|
|
251
|
+
### 1. Write a Failing Test First
|
|
252
|
+
|
|
253
|
+
Start by following the brain testing guide (`/docs/brain-testing-guide.md`) and write a failing test that describes the expected behavior of the brain.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// tests/my-new-brain.test.ts
|
|
257
|
+
import { describe, it, expect } from '@jest/globals';
|
|
258
|
+
import { createMockClient, runBrainTest } from '@positronic/core/testing';
|
|
259
|
+
import myNewBrain from '../brains/my-new-brain';
|
|
260
|
+
|
|
261
|
+
describe('MyNewBrain', () => {
|
|
262
|
+
it('should process data and return expected result', async () => {
|
|
263
|
+
const mockClient = createMockClient();
|
|
264
|
+
|
|
265
|
+
// Mock any AI responses if the brain uses prompts
|
|
266
|
+
mockClient.mockResponses(
|
|
267
|
+
{ processedData: 'expected output' }
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const result = await runBrainTest(myNewBrain, {
|
|
271
|
+
client: mockClient,
|
|
272
|
+
initialState: { input: 'test data' }
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(result.completed).toBe(true);
|
|
276
|
+
expect(result.finalState.output).toBe('expected output');
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### 2. Review Documentation
|
|
282
|
+
|
|
283
|
+
Before implementing the brain:
|
|
284
|
+
- Re-read the **Brain DSL guide** (`/docs/brain-dsl-guide.md`) to understand the DSL patterns
|
|
285
|
+
- Re-read this **Tips for Agents** document if you haven't already
|
|
286
|
+
- Pay special attention to type inference and error handling guidelines
|
|
287
|
+
|
|
288
|
+
### 3. Start the Development Server
|
|
289
|
+
|
|
290
|
+
Before implementing, start the development server in detached mode so you can actually run and test your brain:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# For most cases, just use the default:
|
|
294
|
+
px server -d
|
|
295
|
+
|
|
296
|
+
# Verify the server is running
|
|
297
|
+
px brain list
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
If you need a custom port (e.g., when running multiple servers):
|
|
301
|
+
```bash
|
|
302
|
+
# 1. Generate a random port
|
|
303
|
+
PORT=$(echo $((30000 + RANDOM % 20000)))
|
|
304
|
+
echo "Using port: $PORT"
|
|
305
|
+
|
|
306
|
+
# 2. Start the server in detached mode (--log-file is required with --port)
|
|
307
|
+
px server --port $PORT --log-file /tmp/server-$PORT.log -d
|
|
308
|
+
|
|
309
|
+
# 3. Set environment variable for all subsequent px commands
|
|
310
|
+
export POSITRONIC_PORT=$PORT
|
|
311
|
+
|
|
312
|
+
# 4. Verify the server is running
|
|
313
|
+
px brain list
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### 4. Implement Incrementally
|
|
317
|
+
|
|
318
|
+
Build the brain one step at a time, testing as you go. **Actually run the brain after each change** to see if it works:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# 1. Create the brain with just the first step
|
|
322
|
+
# Write minimal implementation in brains/my-new-brain.ts
|
|
323
|
+
|
|
324
|
+
# 2. Run the brain to test the first step
|
|
325
|
+
px brain run my-new-brain
|
|
326
|
+
|
|
327
|
+
# 3. Check the server log to see execution details
|
|
328
|
+
# For default server:
|
|
329
|
+
tail -f .positronic-server.log
|
|
330
|
+
# For custom port server:
|
|
331
|
+
# tail -f /tmp/server-$PORT.log
|
|
332
|
+
|
|
333
|
+
# 4. Run the test to see if it's getting closer to passing
|
|
334
|
+
npm test tests/my-new-brain.test.ts
|
|
335
|
+
|
|
336
|
+
# 5. Add the next step, run again, check logs
|
|
337
|
+
# Repeat until the test passes
|
|
338
|
+
|
|
339
|
+
# 6. When done, stop the server
|
|
340
|
+
px server -k # (for default server) or: kill $(cat .positronic-server.pid)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 5. Example Workflow
|
|
344
|
+
|
|
345
|
+
Here's a complete example of creating a brain that processes user feedback:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
// Step 1: Write the test first
|
|
349
|
+
describe('FeedbackProcessor', () => {
|
|
350
|
+
it('should analyze feedback and generate response', async () => {
|
|
351
|
+
const mockClient = createMockClient();
|
|
352
|
+
mockClient.mockResponses(
|
|
353
|
+
{ sentiment: 'positive', score: 0.8 },
|
|
354
|
+
{ response: 'Thank you for your feedback!' }
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
const result = await runBrainTest(feedbackBrain, {
|
|
358
|
+
client: mockClient,
|
|
359
|
+
initialState: { feedback: 'Great product!' }
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
expect(result.completed).toBe(true);
|
|
363
|
+
expect(result.finalState.sentiment).toBe('positive');
|
|
364
|
+
expect(result.finalState.response).toBeTruthy();
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Step 2: Create minimal brain implementation
|
|
369
|
+
import { brain } from '@positronic/core';
|
|
370
|
+
import { z } from 'zod';
|
|
371
|
+
|
|
372
|
+
const feedbackBrain = brain('feedback-processor')
|
|
373
|
+
.step('Initialize', ({ state }) => ({
|
|
374
|
+
...state,
|
|
375
|
+
timestamp: Date.now()
|
|
376
|
+
}));
|
|
377
|
+
|
|
378
|
+
export default feedbackBrain;
|
|
379
|
+
|
|
380
|
+
// Step 3: Run and check logs, see it doesn't analyze yet
|
|
381
|
+
// Step 4: Add sentiment analysis step
|
|
382
|
+
.prompt('Analyze sentiment', {
|
|
383
|
+
template: ({ feedback }) =>
|
|
384
|
+
<%= "`Analyze the sentiment of this feedback: \"${feedback}\"`" %>,
|
|
385
|
+
outputSchema: {
|
|
386
|
+
schema: z.object({
|
|
387
|
+
sentiment: z.enum(['positive', 'neutral', 'negative']),
|
|
388
|
+
score: z.number().min(0).max(1)
|
|
389
|
+
}),
|
|
390
|
+
name: 'sentimentAnalysis' as const
|
|
391
|
+
}
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
// Step 5: Run again, check logs, test still fails (no response)
|
|
395
|
+
// Step 6: Add response generation
|
|
396
|
+
.prompt('Generate response', {
|
|
397
|
+
template: ({ sentimentAnalysis, feedback }) =>
|
|
398
|
+
<%= "`Generate a brief response to this ${sentimentAnalysis.sentiment} feedback: \"${feedback}\"`" %>,
|
|
399
|
+
outputSchema: {
|
|
400
|
+
schema: z.object({
|
|
401
|
+
response: z.string()
|
|
402
|
+
}),
|
|
403
|
+
name: 'responseData' as const
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
.step('Format output', ({ state }) => ({
|
|
407
|
+
...state,
|
|
408
|
+
sentiment: state.sentimentAnalysis.sentiment,
|
|
409
|
+
response: state.responseData.response
|
|
410
|
+
}));
|
|
411
|
+
|
|
412
|
+
// Step 7: Run test - it should pass now!
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### 6. Important Reminders
|
|
416
|
+
|
|
417
|
+
- Always start with a test that describes what the brain should do
|
|
418
|
+
- Start the development server in detached mode (`-d`) before implementing
|
|
419
|
+
- **Actually run the brain** after each change to verify it works
|
|
420
|
+
- Build incrementally - one step at a time
|
|
421
|
+
- Use the server logs to debug and understand execution
|
|
422
|
+
- Let TypeScript infer types - don't add explicit type annotations
|
|
423
|
+
- Don't catch errors unless it's part of the workflow logic
|
|
424
|
+
- Run `npm run typecheck` frequently to catch type errors early
|
|
425
|
+
- Stop the server when done: `px server -k` (default server) or `kill $(cat .positronic-server.pid)`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
preset: 'ts-jest/presets/default-esm',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
extensionsToTreatAsEsm: ['.ts'],
|
|
5
|
+
moduleNameMapper: {
|
|
6
|
+
'^(\\.{1,2}/.*)\\.js$': '$1',
|
|
7
|
+
},
|
|
8
|
+
transform: {
|
|
9
|
+
'^.+\\.tsx?$': [
|
|
10
|
+
'ts-jest',
|
|
11
|
+
{
|
|
12
|
+
useESM: true,
|
|
13
|
+
tsconfig: {
|
|
14
|
+
moduleResolution: 'NodeNext',
|
|
15
|
+
isolatedModules: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
transformIgnorePatterns: [],
|
|
21
|
+
testMatch: ['<rootDir>/tests/**/*.test.ts'],
|
|
22
|
+
moduleFileExtensions: ['ts', 'js', 'json'],
|
|
23
|
+
collectCoverageFrom: ['brains/**/*.ts'],
|
|
24
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "<%= name %>",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"zod": "^3.24.1",
|
|
16
|
+
"@positronic/client-vercel": "<%= positronicClientVercelVersion %>",
|
|
17
|
+
"@ai-sdk/openai": "^1.3.22",
|
|
18
|
+
"@positronic/core": "<%= positronicCoreVersion %>"<% if (backend === 'cloudflare') { %>,
|
|
19
|
+
"@positronic/cloudflare": "<%= positronicCloudflareVersion %>"<% } %>
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {<% if (backend === 'cloudflare') { %>
|
|
22
|
+
"wrangler": "^4.0.0",<% } %>
|
|
23
|
+
"typescript": "^5.0.0",
|
|
24
|
+
"jest": "^30.0.4",
|
|
25
|
+
"@jest/globals": "^30.0.4",
|
|
26
|
+
"ts-jest": "^29.2.6",
|
|
27
|
+
"@types/jest": "^30.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BrainRunner } from '@positronic/core';
|
|
2
|
+
import { VercelClient } from '@positronic/client-vercel';
|
|
3
|
+
import { openai } from '@ai-sdk/openai';
|
|
4
|
+
|
|
5
|
+
export const runner = new BrainRunner({
|
|
6
|
+
adapters: [],
|
|
7
|
+
client: new VercelClient(openai('gpt-4o-mini')),
|
|
8
|
+
resources: {},
|
|
9
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createMockClient, runBrainTest } from '@positronic/core/testing';
|
|
2
|
+
import exampleBrain from '../brains/example.js';
|
|
3
|
+
|
|
4
|
+
describe('example brain', () => {
|
|
5
|
+
it('should complete successfully with welcome messages', async () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
const mockClient = createMockClient();
|
|
8
|
+
|
|
9
|
+
// Act
|
|
10
|
+
const result = await runBrainTest(exampleBrain, { client: mockClient });
|
|
11
|
+
|
|
12
|
+
// Assert
|
|
13
|
+
expect(result.completed).toBe(true);
|
|
14
|
+
expect(result.error).toBeNull();
|
|
15
|
+
expect(result.finalState).toMatchObject({
|
|
16
|
+
message: 'Welcome to Positronic!',
|
|
17
|
+
finalMessage: 'Welcome to Positronic! Your project is set up.'
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"lib": ["ESNext", "WebWorker"],
|
|
6
|
+
"strict": true,
|
|
7
|
+
"moduleResolution": "nodenext",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./"
|
|
13
|
+
},
|
|
14
|
+
"include": ["brains/**/*.ts", "resources.d.ts"],
|
|
15
|
+
"exclude": ["node_modules", ".positronic"]
|
|
16
|
+
}
|