lyra-ai-agent 0.1.3 → 0.1.4
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/package.json +1 -1
- package/src/commands/init.ts +6 -74
- package/src/commands/login.ts +16 -0
- package/src/config/setup.ts +83 -0
- package/src/index.ts +1 -1
package/package.json
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
2
|
import { cancel, intro, isCancel, outro, password, select } from '@clack/prompts'
|
|
5
3
|
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'
|
|
6
|
-
import {
|
|
7
|
-
type LyraNetwork,
|
|
8
|
-
agentPaths,
|
|
9
|
-
defineConfig,
|
|
10
|
-
placeholderAgentId,
|
|
11
|
-
suiRpcUrl,
|
|
12
|
-
} from 'lyra-core'
|
|
4
|
+
import { type LyraNetwork, agentPaths, suiRpcUrl } from 'lyra-core'
|
|
13
5
|
import { keypairFromSecret } from 'lyra-plugin-onchain'
|
|
14
|
-
import { DEFAULT_NETWORK
|
|
15
|
-
import {
|
|
6
|
+
import { DEFAULT_NETWORK } from '../config/defaults'
|
|
7
|
+
import { finalizeSetup } from '../config/setup'
|
|
16
8
|
import { setDotenvVar } from '../util/dotenv'
|
|
17
9
|
import { type SuiAgent, loadAgent, writeAgentKey } from '../util/sui-runtime'
|
|
18
10
|
import { pickBrainModel } from './init/model-picker'
|
|
@@ -156,43 +148,15 @@ export async function runInit(opts?: InitOpts): Promise<void> {
|
|
|
156
148
|
}
|
|
157
149
|
|
|
158
150
|
const modelPick = await pickBrainModel()
|
|
159
|
-
|
|
160
|
-
const agentId = placeholderAgentId(agent.address)
|
|
161
|
-
const paths = agentPaths.agent(agentId)
|
|
162
|
-
await mkdir(paths.dir, { recursive: true })
|
|
163
|
-
|
|
164
|
-
// Telegram is env-driven on Sui (TELEGRAM_BOT_TOKEN). Auto-enable the plugin
|
|
165
|
-
// when the token is present so `lyra` brings the DM gateway online.
|
|
166
151
|
const telegramEnabled = !!process.env.TELEGRAM_BOT_TOKEN
|
|
167
152
|
|
|
168
|
-
await
|
|
169
|
-
paths,
|
|
170
|
-
network,
|
|
153
|
+
const { agentId, packageId } = await finalizeSetup({
|
|
171
154
|
agentAddress: agent.address,
|
|
155
|
+
linkedOwner,
|
|
156
|
+
network,
|
|
172
157
|
brainProvider: modelPick?.provider ?? null,
|
|
173
158
|
brainModel: modelPick?.model ?? null,
|
|
174
159
|
})
|
|
175
|
-
|
|
176
|
-
const cfg = defineConfig({
|
|
177
|
-
identity: {
|
|
178
|
-
operator: linkedOwner,
|
|
179
|
-
agent: agent.address,
|
|
180
|
-
},
|
|
181
|
-
network,
|
|
182
|
-
storage: { network },
|
|
183
|
-
brain: {
|
|
184
|
-
provider: modelPick?.provider ?? null,
|
|
185
|
-
model: modelPick?.model ?? null,
|
|
186
|
-
},
|
|
187
|
-
plugins: telegramEnabled ? ['onchain', 'system', 'telegram'] : ['onchain', 'system'],
|
|
188
|
-
tools: {},
|
|
189
|
-
imports: { claudeCode: true },
|
|
190
|
-
})
|
|
191
|
-
await writeConfigTs(configPath, cfg, {
|
|
192
|
-
header: '// Regenerated by `lyra init`. Edit freely; type-safe.',
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
const packageId = resolvePackageId()
|
|
196
160
|
const lines = [
|
|
197
161
|
'',
|
|
198
162
|
` agent id ${agentId}`,
|
|
@@ -211,35 +175,3 @@ export async function runInit(opts?: InitOpts): Promise<void> {
|
|
|
211
175
|
)
|
|
212
176
|
outro(lines.join('\n'))
|
|
213
177
|
}
|
|
214
|
-
|
|
215
|
-
interface SeedStarterOpts {
|
|
216
|
-
paths: ReturnType<typeof agentPaths.agent>
|
|
217
|
-
network: LyraNetwork
|
|
218
|
-
agentAddress: string
|
|
219
|
-
brainProvider: string | null
|
|
220
|
-
brainModel: string | null
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Seed `MEMORY.md`, `/agent/identity.md`, and `/agent/persona.md` so the
|
|
225
|
-
* brain's first turn sees a parseable memory index and introduces itself.
|
|
226
|
-
*/
|
|
227
|
-
async function seedStarterMemoryFiles(opts: SeedStarterOpts): Promise<void> {
|
|
228
|
-
const memDir = opts.paths.memoryDir
|
|
229
|
-
const agentMem = `${memDir}/agent`
|
|
230
|
-
const userMem = `${memDir}/user`
|
|
231
|
-
await mkdir(agentMem, { recursive: true })
|
|
232
|
-
await mkdir(userMem, { recursive: true })
|
|
233
|
-
|
|
234
|
-
const now = new Date().toISOString().slice(0, 10)
|
|
235
|
-
const identity = `---\nname: identity\ndescription: Auto-written agent identity facts.\ntype: agent-identity\n---\n# Lyra identity\n\n- Name: Lyra\n- Agent address: ${opts.agentAddress} (${opts.network})\n- Created: ${now}\n${opts.brainProvider ? `- Brain provider: ${opts.brainProvider}\n` : ''}${opts.brainModel ? `- Brain model: ${opts.brainModel}\n` : ''}`
|
|
236
|
-
const persona =
|
|
237
|
-
'---\nname: persona\ndescription: Voice + behavior style.\ntype: agent-persona\n---\n# Persona\n\nI am Lyra, a Sui-native autonomous finance agent. I convert goals into policy-checked PTBs, execute only within my approved protocol scope, and store auditable memory and receipts with Walrus. Every value-moving action is checked by a deterministic policy (mirrored on-chain by lyra::policy) before it runs. I am direct, concise, and factual.\n'
|
|
238
|
-
const profile =
|
|
239
|
-
'---\nname: profile\ndescription: User profile (local only).\ntype: user\n---\n# User profile\n\n(empty, fills as we chat)\n'
|
|
240
|
-
|
|
241
|
-
await writeFile(join(agentMem, 'identity.md'), identity, 'utf8')
|
|
242
|
-
await writeFile(join(agentMem, 'persona.md'), persona, 'utf8')
|
|
243
|
-
await writeFile(join(userMem, 'profile.md'), profile, 'utf8')
|
|
244
|
-
await writeFile(opts.paths.memoryIndex, '# Lyra Memory Index\n\n', 'utf8')
|
|
245
|
-
}
|
package/src/commands/login.ts
CHANGED
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
* derives for that owner — so the CLI and the web operate one identical agent.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { existsSync } from 'node:fs'
|
|
18
|
+
import { agentPaths } from 'lyra-core'
|
|
17
19
|
import { keypairFromSecret } from 'lyra-plugin-onchain'
|
|
20
|
+
import { DEFAULT_NETWORK } from '../config/defaults'
|
|
21
|
+
import { finalizeSetup } from '../config/setup'
|
|
18
22
|
import { writeAgentKey } from '../util/sui-runtime'
|
|
19
23
|
|
|
20
24
|
/** Default web origin; override with LYRA_WEB_URL for local/staging testing. */
|
|
@@ -150,6 +154,18 @@ export async function runLogin(): Promise<void> {
|
|
|
150
154
|
console.log(`✓ Linked agent ${result.address} (same as your web wallet)`)
|
|
151
155
|
console.log(` owner ${result.owner}`)
|
|
152
156
|
console.log(` key ${result.keyPath}`)
|
|
157
|
+
|
|
158
|
+
// Login used to write ONLY the agent key, leaving `lyra` (chat) with no config
|
|
159
|
+
// to load. Write a runnable config (defaults) when one doesn't exist yet so the
|
|
160
|
+
// device-link is a complete setup; never clobber an existing config.
|
|
161
|
+
if (!existsSync(agentPaths.config)) {
|
|
162
|
+
await finalizeSetup({
|
|
163
|
+
agentAddress: result.address,
|
|
164
|
+
linkedOwner: result.owner,
|
|
165
|
+
network: DEFAULT_NETWORK,
|
|
166
|
+
})
|
|
167
|
+
console.log(` config ${agentPaths.config}`)
|
|
168
|
+
}
|
|
153
169
|
console.log('')
|
|
154
170
|
console.log('Next: `lyra` to chat · `lyra status` for health')
|
|
155
171
|
} catch (e) {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { type LyraNetwork, agentPaths, defineConfig, placeholderAgentId } from 'lyra-core'
|
|
4
|
+
import { resolvePackageId } from './defaults'
|
|
5
|
+
import { writeConfigTs } from './render'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Write `~/.lyra/config.ts` + seed starter memory for an agent we already have
|
|
9
|
+
* (a fresh key, or one linked from the web). Shared by `lyra init` and
|
|
10
|
+
* `lyra login` so BOTH produce a complete, runnable setup — `lyra login` used to
|
|
11
|
+
* write only the agent key, leaving `lyra` (chat) without a config to load.
|
|
12
|
+
*/
|
|
13
|
+
export async function finalizeSetup(opts: {
|
|
14
|
+
agentAddress: string
|
|
15
|
+
linkedOwner: string | null
|
|
16
|
+
network: LyraNetwork
|
|
17
|
+
brainProvider?: string | null
|
|
18
|
+
brainModel?: string | null
|
|
19
|
+
}): Promise<{ agentId: string; configPath: string; packageId: string }> {
|
|
20
|
+
const configPath = agentPaths.config
|
|
21
|
+
const agentId = placeholderAgentId(opts.agentAddress)
|
|
22
|
+
const paths = agentPaths.agent(agentId)
|
|
23
|
+
await mkdir(paths.dir, { recursive: true })
|
|
24
|
+
|
|
25
|
+
// Telegram is env-driven on Sui (TELEGRAM_BOT_TOKEN). Auto-enable the plugin
|
|
26
|
+
// when the token is present so `lyra` brings the DM gateway online.
|
|
27
|
+
const telegramEnabled = !!process.env.TELEGRAM_BOT_TOKEN
|
|
28
|
+
|
|
29
|
+
await seedStarterMemoryFiles({
|
|
30
|
+
paths,
|
|
31
|
+
network: opts.network,
|
|
32
|
+
agentAddress: opts.agentAddress,
|
|
33
|
+
brainProvider: opts.brainProvider ?? null,
|
|
34
|
+
brainModel: opts.brainModel ?? null,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const cfg = defineConfig({
|
|
38
|
+
identity: { operator: opts.linkedOwner, agent: opts.agentAddress },
|
|
39
|
+
network: opts.network,
|
|
40
|
+
storage: { network: opts.network },
|
|
41
|
+
brain: { provider: opts.brainProvider ?? null, model: opts.brainModel ?? null },
|
|
42
|
+
plugins: telegramEnabled ? ['onchain', 'system', 'telegram'] : ['onchain', 'system'],
|
|
43
|
+
tools: {},
|
|
44
|
+
imports: { claudeCode: true },
|
|
45
|
+
})
|
|
46
|
+
await writeConfigTs(configPath, cfg, {
|
|
47
|
+
header: '// Written by lyra (init / login). Edit freely; type-safe.',
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return { agentId, configPath, packageId: resolvePackageId() }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface SeedStarterOpts {
|
|
54
|
+
paths: ReturnType<typeof agentPaths.agent>
|
|
55
|
+
network: LyraNetwork
|
|
56
|
+
agentAddress: string
|
|
57
|
+
brainProvider: string | null
|
|
58
|
+
brainModel: string | null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Seed `MEMORY.md`, `/agent/identity.md`, and `/agent/persona.md` so the brain's
|
|
63
|
+
* first turn sees a parseable memory index and introduces itself.
|
|
64
|
+
*/
|
|
65
|
+
export async function seedStarterMemoryFiles(opts: SeedStarterOpts): Promise<void> {
|
|
66
|
+
const memDir = opts.paths.memoryDir
|
|
67
|
+
const agentMem = `${memDir}/agent`
|
|
68
|
+
const userMem = `${memDir}/user`
|
|
69
|
+
await mkdir(agentMem, { recursive: true })
|
|
70
|
+
await mkdir(userMem, { recursive: true })
|
|
71
|
+
|
|
72
|
+
const now = new Date().toISOString().slice(0, 10)
|
|
73
|
+
const identity = `---\nname: identity\ndescription: Auto-written agent identity facts.\ntype: agent-identity\n---\n# Lyra identity\n\n- Name: Lyra\n- Agent address: ${opts.agentAddress} (${opts.network})\n- Created: ${now}\n${opts.brainProvider ? `- Brain provider: ${opts.brainProvider}\n` : ''}${opts.brainModel ? `- Brain model: ${opts.brainModel}\n` : ''}`
|
|
74
|
+
const persona =
|
|
75
|
+
'---\nname: persona\ndescription: Voice + behavior style.\ntype: agent-persona\n---\n# Persona\n\nI am Lyra, a Sui-native autonomous finance agent. I convert goals into policy-checked PTBs, execute only within my approved protocol scope, and store auditable memory and receipts with Walrus. Every value-moving action is checked by a deterministic policy (mirrored on-chain by lyra::policy) before it runs. I am direct, concise, and factual.\n'
|
|
76
|
+
const profile =
|
|
77
|
+
'---\nname: profile\ndescription: User profile (local only).\ntype: user\n---\n# User profile\n\n(empty, fills as we chat)\n'
|
|
78
|
+
|
|
79
|
+
await writeFile(join(agentMem, 'identity.md'), identity, 'utf8')
|
|
80
|
+
await writeFile(join(agentMem, 'persona.md'), persona, 'utf8')
|
|
81
|
+
await writeFile(join(userMem, 'profile.md'), profile, 'utf8')
|
|
82
|
+
await writeFile(opts.paths.memoryIndex, '# Lyra Memory Index\n\n', 'utf8')
|
|
83
|
+
}
|