@electric-ax/agents 0.1.4 → 0.2.1
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/dist/entrypoint.js +650 -407
- package/dist/index.cjs +668 -418
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +653 -410
- package/package.json +7 -10
- package/skills/init.md +71 -0
- package/skills/quickstart/scaffold/entities/.gitkeep +0 -0
- package/skills/quickstart/scaffold/lib/electric-tools.ts +80 -0
- package/skills/quickstart/scaffold/package.json +17 -0
- package/skills/quickstart/scaffold/server.ts +51 -0
- package/skills/quickstart/scaffold/tsconfig.json +15 -0
- package/skills/quickstart.md +672 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@electric-ax/agents",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Built-in Electric Agents runtimes such as Horton and worker",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,33 +29,30 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
32
|
-
"@durable-streams/state": "npm:@electric-ax/durable-streams-state-beta@^0.3.
|
|
32
|
+
"@durable-streams/state": "npm:@electric-ax/durable-streams-state-beta@^0.3.1",
|
|
33
33
|
"@mariozechner/pi-agent-core": "^0.70.2",
|
|
34
34
|
"@mariozechner/pi-ai": "^0.70.2",
|
|
35
|
-
"@mozilla/readability": "^0.6.0",
|
|
36
35
|
"@sinclair/typebox": "^0.34.48",
|
|
36
|
+
"agent-session-protocol": "^0.0.2",
|
|
37
37
|
"better-sqlite3": "^11.10.0",
|
|
38
|
-
"jsdom": "^28.1.0",
|
|
39
38
|
"nanoid": "^3.3.11",
|
|
40
39
|
"pino": "^10.3.1",
|
|
41
40
|
"pino-pretty": "^13.0.0",
|
|
42
41
|
"sqlite-vec": "^0.1.9",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"@electric-ax/agents-runtime": "0.0.4"
|
|
42
|
+
"zod": "^4.3.6",
|
|
43
|
+
"@electric-ax/agents-runtime": "0.1.1"
|
|
46
44
|
},
|
|
47
45
|
"devDependencies": {
|
|
48
46
|
"@types/better-sqlite3": "^7.6.13",
|
|
49
|
-
"@types/jsdom": "^27.0.0",
|
|
50
47
|
"@types/node": "^22.19.15",
|
|
51
|
-
"@types/turndown": "^5.0.6",
|
|
52
48
|
"@vitest/coverage-v8": "^4.1.0",
|
|
53
49
|
"tsdown": "^0.9.0",
|
|
54
50
|
"typescript": "^5.0.0",
|
|
55
51
|
"vitest": "^4.1.0"
|
|
56
52
|
},
|
|
57
53
|
"files": [
|
|
58
|
-
"dist"
|
|
54
|
+
"dist",
|
|
55
|
+
"skills"
|
|
59
56
|
],
|
|
60
57
|
"sideEffects": false,
|
|
61
58
|
"license": "Apache-2.0",
|
package/skills/init.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Scaffold a new Electric Agents app project and get oriented in the codebase
|
|
3
|
+
whenToUse: User wants to create a new app, start a project, or scaffold an Electric Agents application
|
|
4
|
+
keywords:
|
|
5
|
+
- init
|
|
6
|
+
- scaffold
|
|
7
|
+
- new project
|
|
8
|
+
- create app
|
|
9
|
+
- starter
|
|
10
|
+
- setup
|
|
11
|
+
user-invocable: true
|
|
12
|
+
argument-hint: '[project-name]'
|
|
13
|
+
arguments:
|
|
14
|
+
- project_name
|
|
15
|
+
max: 15000
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Init: Create a New Electric Agents App
|
|
19
|
+
|
|
20
|
+
Help the user scaffold and understand a new Electric Agents project.
|
|
21
|
+
|
|
22
|
+
## Flow
|
|
23
|
+
|
|
24
|
+
### 1. Assess experience
|
|
25
|
+
|
|
26
|
+
Before scaffolding, ask the user:
|
|
27
|
+
|
|
28
|
+
> "Are you familiar with Electric Agents concepts (entities, handlers, spawning workers)? If not, I can walk you through a hands-on quickstart first — or we can dive straight into setting up your project."
|
|
29
|
+
|
|
30
|
+
- If they want the quickstart → load the quickstart skill with `use_skill("quickstart")`
|
|
31
|
+
- If they want to dive in → continue to step 2
|
|
32
|
+
|
|
33
|
+
### 2. Scaffold the project
|
|
34
|
+
|
|
35
|
+
**Ask the user where they want the project.** Suggest a sensible default (e.g., `./$project_name` relative to the working directory) but let them choose. Do not create files or directories until the user confirms the location.
|
|
36
|
+
|
|
37
|
+
If `$project_name` is not provided, ask the user what they'd like to name their project.
|
|
38
|
+
|
|
39
|
+
Run the init command to create the project:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
npx electric-ax agents init $project_name
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After the command completes, read the generated project structure to orient yourself.
|
|
46
|
+
|
|
47
|
+
### 3. Orient the user
|
|
48
|
+
|
|
49
|
+
Walk through what was created. Read the key files and explain:
|
|
50
|
+
|
|
51
|
+
- **Project structure** — what each directory and file is for
|
|
52
|
+
- **Entity definitions** — where entity types are defined (e.g., `src/server/` or `entities/`)
|
|
53
|
+
- **Server setup** — how the HTTP server and webhook handler work
|
|
54
|
+
- **Frontend** — how the UI connects to the agent backend (if applicable)
|
|
55
|
+
- **Running it** — the commands to start the dev server
|
|
56
|
+
|
|
57
|
+
Keep explanations concise. The user can ask follow-up questions.
|
|
58
|
+
|
|
59
|
+
### 4. Customize
|
|
60
|
+
|
|
61
|
+
Ask the user what they want to build:
|
|
62
|
+
|
|
63
|
+
> "What kind of app are you thinking of building? I can help you customize the starter — rename entity types, add new ones, adjust the tools, or modify the UI."
|
|
64
|
+
|
|
65
|
+
Help them make their first changes to the scaffolded project.
|
|
66
|
+
|
|
67
|
+
## Rules
|
|
68
|
+
|
|
69
|
+
- Always read generated files before explaining them — don't assume the scaffold output.
|
|
70
|
+
- If the init command doesn't exist or fails, fall back to manual scaffolding: create the project directory, set up package.json, install dependencies, and create a basic server.ts using the pattern from the quickstart skill's scaffold directory.
|
|
71
|
+
- Don't overwhelm with information. Give a high-level overview first, then go deeper when asked.
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Type } from '@sinclair/typebox'
|
|
2
|
+
import type { AgentTool } from '@electric-ax/agents-runtime'
|
|
3
|
+
|
|
4
|
+
type CreateElectricToolsContext = {
|
|
5
|
+
entityUrl: string
|
|
6
|
+
entityType: string
|
|
7
|
+
args: Readonly<Record<string, unknown>>
|
|
8
|
+
upsertCronSchedule: (opts: {
|
|
9
|
+
id: string
|
|
10
|
+
expression: string
|
|
11
|
+
timezone?: string
|
|
12
|
+
payload?: unknown
|
|
13
|
+
debounceMs?: number
|
|
14
|
+
timeoutMs?: number
|
|
15
|
+
}) => Promise<{ txid: string }>
|
|
16
|
+
upsertFutureSendSchedule: (opts: {
|
|
17
|
+
id: string
|
|
18
|
+
payload: unknown
|
|
19
|
+
targetUrl?: string
|
|
20
|
+
fireAt: string
|
|
21
|
+
from?: string
|
|
22
|
+
messageType?: string
|
|
23
|
+
}) => Promise<{ txid: string }>
|
|
24
|
+
deleteSchedule: (opts: { id: string }) => Promise<{ txid: string }>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createElectricTools(
|
|
28
|
+
ctx: CreateElectricToolsContext
|
|
29
|
+
): Array<AgentTool> {
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
name: `upsert_cron_schedule`,
|
|
33
|
+
label: `Upsert Cron`,
|
|
34
|
+
description: `Create or update a recurring cron wake schedule.`,
|
|
35
|
+
parameters: Type.Object({
|
|
36
|
+
id: Type.String({ description: `Stable schedule identifier` }),
|
|
37
|
+
expression: Type.String({ description: `Cron expression` }),
|
|
38
|
+
timezone: Type.Optional(Type.String({ description: `IANA timezone` })),
|
|
39
|
+
payload: Type.Any({ description: `Instruction for the agent` }),
|
|
40
|
+
}),
|
|
41
|
+
execute: async (_toolCallId, params) => {
|
|
42
|
+
const { id, expression, timezone, payload } = params as any
|
|
43
|
+
const tz = timezone ?? `UTC`
|
|
44
|
+
const { txid } = await ctx.upsertCronSchedule({
|
|
45
|
+
id,
|
|
46
|
+
expression,
|
|
47
|
+
timezone: tz,
|
|
48
|
+
payload,
|
|
49
|
+
})
|
|
50
|
+
return {
|
|
51
|
+
content: [
|
|
52
|
+
{ type: `text` as const, text: `Cron "${id}" set. txid=${txid}` },
|
|
53
|
+
],
|
|
54
|
+
details: { txid },
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: `delete_schedule`,
|
|
60
|
+
label: `Delete Schedule`,
|
|
61
|
+
description: `Delete a schedule by id.`,
|
|
62
|
+
parameters: Type.Object({
|
|
63
|
+
id: Type.String({ description: `Schedule identifier` }),
|
|
64
|
+
}),
|
|
65
|
+
execute: async (_toolCallId, params) => {
|
|
66
|
+
const { id } = params as { id: string }
|
|
67
|
+
const { txid } = await ctx.deleteSchedule({ id })
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: `text` as const,
|
|
72
|
+
text: `Schedule "${id}" deleted. txid=${txid}`,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
details: { txid },
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-electric-agents-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "tsx server.ts",
|
|
7
|
+
"dev": "tsx --watch server.ts"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@electric-ax/agents-runtime": "latest",
|
|
11
|
+
"@sinclair/typebox": "^0.34.49"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"tsx": "^4.19.0",
|
|
15
|
+
"typescript": "^5.7.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import http from 'node:http'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import {
|
|
5
|
+
createEntityRegistry,
|
|
6
|
+
createRuntimeHandler,
|
|
7
|
+
} from '@electric-ax/agents-runtime'
|
|
8
|
+
import { createElectricTools } from './lib/electric-tools'
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const here = path.dirname(fileURLToPath(import.meta.url))
|
|
12
|
+
process.loadEnvFile(path.resolve(here, `.env`))
|
|
13
|
+
} catch {}
|
|
14
|
+
|
|
15
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
16
|
+
console.warn(
|
|
17
|
+
`[app] ANTHROPIC_API_KEY is not set — agent.run() will throw on the first wake.`
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ELECTRIC_AGENTS_URL =
|
|
22
|
+
process.env.ELECTRIC_AGENTS_URL ?? `http://localhost:4437`
|
|
23
|
+
const PORT = Number(process.env.PORT ?? 3000)
|
|
24
|
+
const SERVE_URL = process.env.SERVE_URL ?? `http://localhost:${PORT}`
|
|
25
|
+
|
|
26
|
+
const registry = createEntityRegistry()
|
|
27
|
+
|
|
28
|
+
// Register your entity types here:
|
|
29
|
+
// import { registerMyEntity } from "./entities/my-entity"
|
|
30
|
+
// registerMyEntity(registry)
|
|
31
|
+
|
|
32
|
+
const runtime = createRuntimeHandler({
|
|
33
|
+
baseUrl: ELECTRIC_AGENTS_URL,
|
|
34
|
+
serveEndpoint: `${SERVE_URL}/webhook`,
|
|
35
|
+
registry,
|
|
36
|
+
createElectricTools,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const server = http.createServer(async (req, res) => {
|
|
40
|
+
if (req.url === `/webhook` && req.method === `POST`) {
|
|
41
|
+
await runtime.onEnter(req, res)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
res.writeHead(404)
|
|
45
|
+
res.end()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
server.listen(PORT, async () => {
|
|
49
|
+
await runtime.registerTypes()
|
|
50
|
+
console.log(`App server ready on port ${PORT}`)
|
|
51
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"allowImportingTsExtensions": false,
|
|
11
|
+
"noEmit": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["**/*.ts"],
|
|
14
|
+
"exclude": ["node_modules"]
|
|
15
|
+
}
|