ethagent 0.1.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/README.md +43 -0
- package/bin/ethagent.js +9 -0
- package/package.json +34 -0
- package/src/cli.tsx +147 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<img src="preview/cli.png" alt="ethagent" width="600" />
|
|
2
|
+
|
|
3
|
+
A local-first AI agent with a permanent Ethereum identity. Runs entirely on your machine.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g ethagent
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
When you use cloud AI, every prompt you send, every codebase you share, every reasoning chain you build becomes training data. Your workflows, your thinking, your decision patterns. That data is worth far more than the $20/mo subscription you're paying. It trains the next generation of models, informs product roadmaps, and builds competitive moats for companies that don't share the upside with you.
|
|
12
|
+
|
|
13
|
+
ethagent runs inference entirely on your hardware. Your prompts never leave your machine. Your knowledge base is yours.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Your agent
|
|
17
|
+
|
|
18
|
+
Think of it like a tamagotchi you raise on your own machine. You feed it knowledge. Every conversation you have, every document you give it, every correction you make compounds. ethagent builds a knowledge base that's specific to you, your domain, your way of thinking. It doesn't reset between sessions. It doesn't flatten your context into a generic system prompt. It accumulates.
|
|
19
|
+
|
|
20
|
+
Your inference runs on your hardware, your agent lives on your identity, and everything it learns stays with you. No usage limits. No rate caps. Just your machine, working for you.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
ethagent bootstraps a local LLM on your machine and builds a knowledge base from sources you define. Your agent gets a permanent onchain identity using [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004), the token standard for registering autonomous agents on Ethereum. Identity is tied to an Ethereum address or ENS name, so it can be restored on any machine.
|
|
26
|
+
|
|
27
|
+
All inference runs locally. Your data never leaves your hardware. The knowledge base is pinned to IPFS so it's portable and verifiable.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
## Portability
|
|
31
|
+
|
|
32
|
+
Your agent is tied to your Ethereum identity, not your machine. Knowledge lives on IPFS. Identity lives onchain. Wipe your laptop, restore from your address, and you're back exactly where you left off.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx ethagent init --from bairon.eth
|
|
36
|
+
npx ethagent init --from 0xA1E977e700bF82019beb381F1582575303A389CE
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
As long as Ethereum exists, so does your agent.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
MIT License
|
package/bin/ethagent.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from 'node:child_process'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { dirname, join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const cli = join(__dirname, '..', 'src', 'cli.tsx')
|
|
8
|
+
|
|
9
|
+
execFileSync('node', ['--import', 'tsx/esm', cli], { stdio: 'inherit' })
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ethagent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A local-first AI agent with an Ethereum identity",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ethagent": "./bin/ethagent.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "node bin/ethagent.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ethereum",
|
|
18
|
+
"agent",
|
|
19
|
+
"ai",
|
|
20
|
+
"local-first",
|
|
21
|
+
"ERC-8004",
|
|
22
|
+
"onchain"
|
|
23
|
+
],
|
|
24
|
+
"author": "bairon.eth",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"ink": "^6.8.0",
|
|
28
|
+
"react": "^19.2.4",
|
|
29
|
+
"tsx": "^4.21.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"ansi-to-svg": "^1.4.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/cli.tsx
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import {render, Text, Box} from 'ink'
|
|
4
|
+
|
|
5
|
+
const eth = `░░░░░░░╗░░░░░░░░╗░░╗ ░░╗
|
|
6
|
+
░░╔════╝╚══░░╔══╝░░║ ░░║
|
|
7
|
+
░░░░░╗ ░░║ ░░░░░░░║
|
|
8
|
+
░░╔══╝ ░░║ ░░╔══░░║
|
|
9
|
+
░░░░░░░╗ ░░║ ░░║ ░░║
|
|
10
|
+
╚══════╝ ╚═╝ ╚═╝ ╚═╝`
|
|
11
|
+
|
|
12
|
+
const A = [
|
|
13
|
+
` █████╗ `,
|
|
14
|
+
`██╔══██╗`,
|
|
15
|
+
`███████║`,
|
|
16
|
+
`██╔══██║`,
|
|
17
|
+
`██║ ██║`,
|
|
18
|
+
`╚═╝ ╚═╝`,
|
|
19
|
+
].join('\n')
|
|
20
|
+
|
|
21
|
+
const G = [
|
|
22
|
+
` ██████╗ `,
|
|
23
|
+
`██╔════╝ `,
|
|
24
|
+
`██║ ███╗`,
|
|
25
|
+
`██║ ██║`,
|
|
26
|
+
`╚██████╔╝`,
|
|
27
|
+
` ╚═════╝ `,
|
|
28
|
+
].join('\n')
|
|
29
|
+
|
|
30
|
+
const E = [
|
|
31
|
+
`███████╗`,
|
|
32
|
+
`██╔════╝`,
|
|
33
|
+
`█████╗ `,
|
|
34
|
+
`██╔══╝ `,
|
|
35
|
+
`███████╗`,
|
|
36
|
+
`╚══════╝`,
|
|
37
|
+
].join('\n')
|
|
38
|
+
|
|
39
|
+
const N = [
|
|
40
|
+
`███╗ ██╗`,
|
|
41
|
+
`████╗ ██║`,
|
|
42
|
+
`██╔██╗ ██║`,
|
|
43
|
+
`██║╚██╗██║`,
|
|
44
|
+
`██║ ╚████║`,
|
|
45
|
+
`╚═╝ ╚═══╝`,
|
|
46
|
+
].join('\n')
|
|
47
|
+
|
|
48
|
+
const T = [
|
|
49
|
+
`████████╗`,
|
|
50
|
+
`╚══██╔══╝`,
|
|
51
|
+
` ██║ `,
|
|
52
|
+
` ██║ `,
|
|
53
|
+
` ██║ `,
|
|
54
|
+
` ╚═╝ `,
|
|
55
|
+
].join('\n')
|
|
56
|
+
|
|
57
|
+
const eyes = `
|
|
58
|
+
-+:
|
|
59
|
+
:=- -%@@@%.
|
|
60
|
+
*@@@@@#- *@@-
|
|
61
|
+
+@@. +@
|
|
62
|
+
@@= -#=-+++=+:
|
|
63
|
+
#% .:===-: -@* +@@@@%
|
|
64
|
+
*@-+@@@@@: %@@+ @@@=#@
|
|
65
|
+
*@= @@@@@@@- .@.@@@@@@@ :
|
|
66
|
+
@@+=@@@@@@@@@@@@: .% *@@@@@*-=
|
|
67
|
+
#:-@ -@@@@@@@@@-+% @ -@@@- #
|
|
68
|
+
: #+ @@@@@@@- -% =# =
|
|
69
|
+
-@: *@ .+%%
|
|
70
|
+
:%#: --
|
|
71
|
+
.-:
|
|
72
|
+
`
|
|
73
|
+
|
|
74
|
+
const palette = [
|
|
75
|
+
[0xe8, 0xa0, 0xa0],
|
|
76
|
+
[0xe8, 0xbe, 0x8f],
|
|
77
|
+
[0xe8, 0xdf, 0x9a],
|
|
78
|
+
[0x96, 0xd4, 0xa8],
|
|
79
|
+
[0x90, 0xb8, 0xe8],
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
function gradientColor(t) {
|
|
83
|
+
const s = Math.max(0, Math.min(1, t)) * (palette.length - 1)
|
|
84
|
+
const i = Math.min(Math.floor(s), palette.length - 2)
|
|
85
|
+
const f = s - i
|
|
86
|
+
const [r1, g1, b1] = palette[i]
|
|
87
|
+
const [r2, g2, b2] = palette[i + 1]
|
|
88
|
+
const r = Math.round(r1 + (r2 - r1) * f)
|
|
89
|
+
const g = Math.round(g1 + (g2 - g1) * f)
|
|
90
|
+
const b = Math.round(b1 + (b2 - b1) * f)
|
|
91
|
+
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const Eyes = () => {
|
|
95
|
+
const lines = eyes.split('\n')
|
|
96
|
+
const maxLen = Math.max(...lines.map(l => l.trimEnd().length))
|
|
97
|
+
return (
|
|
98
|
+
<Box flexDirection="column">
|
|
99
|
+
{lines.map((line, li) => (
|
|
100
|
+
<Text key={li}>
|
|
101
|
+
{line.split('').map((char, ci) => (
|
|
102
|
+
<Text key={ci} color={gradientColor(ci / Math.max(maxLen - 1, 1))}>{char}</Text>
|
|
103
|
+
))}
|
|
104
|
+
</Text>
|
|
105
|
+
))}
|
|
106
|
+
</Box>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const App = () => {
|
|
111
|
+
const ethLines = eth.split('\n')
|
|
112
|
+
const aLines = A.split('\n')
|
|
113
|
+
const gLines = G.split('\n')
|
|
114
|
+
const eLines = E.split('\n')
|
|
115
|
+
const nLines = N.split('\n')
|
|
116
|
+
const tLines = T.split('\n')
|
|
117
|
+
|
|
118
|
+
const w = 69
|
|
119
|
+
const topLabel = ' local AI agent with a portable ethereum identity '
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<Box flexDirection="column" alignSelf="flex-start" padding={1}>
|
|
123
|
+
<Eyes />
|
|
124
|
+
<Text>
|
|
125
|
+
<Text color="#555555">╔═</Text>
|
|
126
|
+
<Text color="#777777">{topLabel}</Text>
|
|
127
|
+
<Text color="#555555">{'═'.repeat(w - topLabel.length - 1)}╗</Text>
|
|
128
|
+
</Text>
|
|
129
|
+
{ethLines.map((line, i) => (
|
|
130
|
+
<Box key={i}>
|
|
131
|
+
<Text color="#555555">║</Text>
|
|
132
|
+
<Text color="#555555">{ethLines[i]}</Text>
|
|
133
|
+
<Text color="#555555">{aLines[i]}</Text>
|
|
134
|
+
<Text color="#555555">{gLines[i]}</Text>
|
|
135
|
+
<Text color="#555555">{eLines[i]}</Text>
|
|
136
|
+
<Text color="#555555">{nLines[i]}</Text>
|
|
137
|
+
<Text color="#555555">{tLines[i]}</Text>
|
|
138
|
+
<Text color="#555555">║</Text>
|
|
139
|
+
</Box>
|
|
140
|
+
))}
|
|
141
|
+
<Text color="#555555">{'╚' + '═'.repeat(w) + '╝'}</Text>
|
|
142
|
+
<Text color="#777777">{'\n coming soon...\n'}</Text>
|
|
143
|
+
</Box>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
render(<App />)
|