@feralfile/cli 1.1.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/LICENSE +21 -0
- package/README.md +96 -0
- package/config.json.example +96 -0
- package/dist/index.js +54 -0
- package/dist/src/ai-orchestrator/index.js +1019 -0
- package/dist/src/ai-orchestrator/registry.js +96 -0
- package/dist/src/commands/build.js +69 -0
- package/dist/src/commands/chat.js +189 -0
- package/dist/src/commands/config.js +68 -0
- package/dist/src/commands/device.js +278 -0
- package/dist/src/commands/helpers/config-files.js +62 -0
- package/dist/src/commands/helpers/device-discovery.js +111 -0
- package/dist/src/commands/helpers/playlist-display.js +161 -0
- package/dist/src/commands/helpers/prompt.js +65 -0
- package/dist/src/commands/helpers/ssh-helpers.js +44 -0
- package/dist/src/commands/play.js +110 -0
- package/dist/src/commands/publish.js +115 -0
- package/dist/src/commands/setup.js +225 -0
- package/dist/src/commands/sign.js +41 -0
- package/dist/src/commands/ssh.js +108 -0
- package/dist/src/commands/status.js +126 -0
- package/dist/src/commands/validate.js +18 -0
- package/dist/src/config.js +441 -0
- package/dist/src/intent-parser/index.js +1382 -0
- package/dist/src/intent-parser/utils.js +108 -0
- package/dist/src/logger.js +82 -0
- package/dist/src/main.js +459 -0
- package/dist/src/types.js +5 -0
- package/dist/src/utilities/address-validator.js +242 -0
- package/dist/src/utilities/device-default.js +36 -0
- package/dist/src/utilities/device-lookup.js +107 -0
- package/dist/src/utilities/device-normalize.js +62 -0
- package/dist/src/utilities/device-upsert.js +91 -0
- package/dist/src/utilities/domain-resolver.js +291 -0
- package/dist/src/utilities/ed25519-key-derive.js +155 -0
- package/dist/src/utilities/feed-fetcher.js +471 -0
- package/dist/src/utilities/ff1-compatibility.js +269 -0
- package/dist/src/utilities/ff1-device.js +250 -0
- package/dist/src/utilities/ff1-discovery.js +330 -0
- package/dist/src/utilities/functions.js +308 -0
- package/dist/src/utilities/index.js +469 -0
- package/dist/src/utilities/nft-indexer.js +1024 -0
- package/dist/src/utilities/playlist-builder.js +523 -0
- package/dist/src/utilities/playlist-publisher.js +131 -0
- package/dist/src/utilities/playlist-send.js +260 -0
- package/dist/src/utilities/playlist-signer.js +204 -0
- package/dist/src/utilities/playlist-signing-role.js +41 -0
- package/dist/src/utilities/playlist-source.js +128 -0
- package/dist/src/utilities/playlist-verifier.js +274 -0
- package/dist/src/utilities/ssh-access.js +145 -0
- package/dist/src/utils.js +48 -0
- package/docs/CONFIGURATION.md +206 -0
- package/docs/EXAMPLES.md +390 -0
- package/docs/FUNCTION_CALLING.md +96 -0
- package/docs/PROJECT_SPEC.md +228 -0
- package/docs/README.md +348 -0
- package/docs/RELEASING.md +73 -0
- package/package.json +76 -0
package/docs/EXAMPLES.md
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
Copy‑pasteable commands that work with the current CLI.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev -- setup
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Manual config path:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm run dev -- config init
|
|
16
|
+
npm run dev -- config validate
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## OpenClaw skill prompt
|
|
20
|
+
|
|
21
|
+
If you want OpenClaw to run ff-cli end-to-end without confirmation, start from:
|
|
22
|
+
|
|
23
|
+
`skills/ff-control/SKILL.md`
|
|
24
|
+
|
|
25
|
+
Recommended local install path:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mkdir -p ~/.openclaw/skills
|
|
29
|
+
ln -sfn ~/Work/ff-cli/skills/ff-control ~/.openclaw/skills/ff-control
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Compatibility copy (same prompt):
|
|
33
|
+
|
|
34
|
+
`examples/openclaw-ff-skill.md`
|
|
35
|
+
|
|
36
|
+
Paste that prompt into your OpenClaw skill config, then test with plain requests like:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
"Get 3 works from reas.eth and send to Living Room"
|
|
40
|
+
"Get 3 from Unsupervised and publish to my feed"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Natural Language
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Interactive chat
|
|
47
|
+
npm run dev chat
|
|
48
|
+
|
|
49
|
+
# One-shot requests
|
|
50
|
+
npm run dev -- chat "Get 3 works from reas.eth" -o playlist.json
|
|
51
|
+
npm run dev -- chat "Get 3 works from einstein-rosen.tez"
|
|
52
|
+
npm run dev -- chat "Get tokens 52932,52457 from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0" -v
|
|
53
|
+
npm run dev -- chat "Make a playlist of 10 works from 0xaeE022552B539dB18297D7481b6D547C622488B3" -v
|
|
54
|
+
|
|
55
|
+
# Switch model
|
|
56
|
+
npm run dev -- chat "your request" --model grok
|
|
57
|
+
npm run dev -- chat "your request" --model gpt
|
|
58
|
+
npm run dev -- chat "your request" --model gemini
|
|
59
|
+
|
|
60
|
+
# Model names must match keys in config.json under `models`.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Deterministic Build (no AI)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# From file
|
|
67
|
+
npm run dev -- build examples/params-example.json -o playlist.json
|
|
68
|
+
|
|
69
|
+
# From stdin
|
|
70
|
+
cat examples/params-example.json | npm run dev -- build -o playlist.json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## AI‑Orchestrated Deterministic Flow (prompts)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Show tool‑call progress and validation
|
|
77
|
+
npm run dev -- chat "Build a playlist of my works from reas.eth plus 3 from Unsupervised" -v -o playlist.json
|
|
78
|
+
|
|
79
|
+
# Switch model if desired
|
|
80
|
+
npm run dev -- chat "Build playlist from Ethereum address 0xaeE022552B539dB18297D7481b6D547C622488B3 and 2 from Unsupervised" --model gpt -v
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### One‑shot complex prompt
|
|
84
|
+
|
|
85
|
+
The CLI can parse rich requests and do it all in one go: fetch, build a DP‑1 playlist, shuffle, set durations, and send to a named device.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Example: combine sources, shuffle, set 6s per item, and send to device
|
|
89
|
+
npm run dev -- chat "Get tokens 52932,52457 from contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 and 2 from reas.eth; shuffle; 6 seconds each; send to 'Living Room Display'." -o playlist.json -v
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Feral File Built Playlists
|
|
93
|
+
|
|
94
|
+
Use exhibition titles from the official playlist repository:
|
|
95
|
+
`https://github.com/feral-file/dp1-feed/tree/main/playlists`
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Fetch from a built playlist title
|
|
99
|
+
npm run dev -- chat "Get 3 from Unsupervised" -v
|
|
100
|
+
|
|
101
|
+
# Mix a built playlist with wallet/domain sources
|
|
102
|
+
npm run dev -- chat "Get 3 from Unsupervised and 2 from reas.eth" -v -o playlist.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Notes:
|
|
106
|
+
|
|
107
|
+
- Feed playlist queries require reachable feed servers in your config.
|
|
108
|
+
- If no feeds are reachable, feed playlist examples will fail even if the title exists.
|
|
109
|
+
- Bare EVM prompts (`from 0x...`) now fall back from owner lookup to contract lookup when needed.
|
|
110
|
+
|
|
111
|
+
## Natural Language: Display and Publish
|
|
112
|
+
|
|
113
|
+
The CLI recognizes publishing keywords like "publish", "publish to my feed", "push to feed", "send to feed" and automatically publishes after building.
|
|
114
|
+
|
|
115
|
+
### Basic Publishing
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Build and publish
|
|
119
|
+
npm run dev -- chat "Build playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; publish to my feed" -o playlist.json -v
|
|
120
|
+
|
|
121
|
+
# With feed selection (if multiple servers configured)
|
|
122
|
+
# The CLI will ask: "Which feed server? 1) https://dp1-feed-operator-api-prod.autonomy-system.workers.dev/api/v1 2) http://localhost:8787"
|
|
123
|
+
npm run dev -- chat "Get 3 from Unsupervised and publish to feed" -v
|
|
124
|
+
|
|
125
|
+
# Publish existing playlist (defaults to ./playlist.json)
|
|
126
|
+
npm run dev chat
|
|
127
|
+
# Then type: "publish playlist"
|
|
128
|
+
|
|
129
|
+
# Publish specific playlist file
|
|
130
|
+
npm run dev chat
|
|
131
|
+
# Then type: "publish the playlist ./playlist-temp.json"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Combined: Display + Publish
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Display on Art Computer AND publish to feed
|
|
138
|
+
npm run dev -- chat "Build playlist from contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; mix them up; send to my Art Computer and publish to my feed" -o playlist.json -v
|
|
139
|
+
|
|
140
|
+
# With explicit device name
|
|
141
|
+
npm run dev -- chat "Get 5 from Unsupervised, shuffle, display on 'Living Room', and publish to feed" -v
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### How It Works
|
|
145
|
+
|
|
146
|
+
**Mode 1: Build and Publish** (when sources are mentioned)
|
|
147
|
+
|
|
148
|
+
1. Intent parser detects "publish" keywords with sources/requirements
|
|
149
|
+
2. Calls `get_feed_servers` to retrieve configured servers
|
|
150
|
+
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
151
|
+
4. Builds playlist → validates structure → publishes automatically
|
|
152
|
+
|
|
153
|
+
**Mode 2: Publish Existing File** (e.g., "publish playlist")
|
|
154
|
+
|
|
155
|
+
1. Intent parser detects "publish playlist" or similar phrases
|
|
156
|
+
2. Calls `get_feed_servers` to retrieve configured servers
|
|
157
|
+
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
158
|
+
4. Publishes the playlist from `./playlist.json` (or specified path)
|
|
159
|
+
|
|
160
|
+
Output shows:
|
|
161
|
+
|
|
162
|
+
- Playlist build progress (Mode 1 only)
|
|
163
|
+
- Device sending (if requested): `✓ Sent to device: Living Room`
|
|
164
|
+
- Publishing status: `✓ Published to feed server`
|
|
165
|
+
- Playlist ID: `Playlist ID: 84e028f8-...`
|
|
166
|
+
|
|
167
|
+
## Validate / Sign / Send
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Validate playlist
|
|
171
|
+
npm run dev -- validate playlist.json
|
|
172
|
+
npm run dev -- validate "https://cdn.example.com/playlist.json"
|
|
173
|
+
|
|
174
|
+
# Sign playlist
|
|
175
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
176
|
+
|
|
177
|
+
# Send to device
|
|
178
|
+
npm run dev -- send playlist.json -d "Living Room Display"
|
|
179
|
+
npm run dev -- send "https://cdn.example.com/playlist.json" -d "Living Room Display"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Publish to Feed Server
|
|
183
|
+
|
|
184
|
+
Publish validated playlists to a DP-1 feed server for sharing and discovery.
|
|
185
|
+
|
|
186
|
+
### Configuration
|
|
187
|
+
|
|
188
|
+
Add feed servers to `config.json`:
|
|
189
|
+
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"feedServers": [
|
|
193
|
+
{
|
|
194
|
+
"baseUrl": "http://localhost:8787/api/v1",
|
|
195
|
+
"apiKey": "your-api-key"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"baseUrl": "https://feed.example.com/api/v1",
|
|
199
|
+
"apiKey": "your-api-key"
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Publish Commands
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# Interactive: list servers and ask which to use
|
|
209
|
+
npm run dev -- publish playlist.json
|
|
210
|
+
|
|
211
|
+
# Direct: publish to specific server (server index 0)
|
|
212
|
+
npm run dev -- publish playlist.json -s 0
|
|
213
|
+
|
|
214
|
+
# Show help
|
|
215
|
+
npm run dev -- publish --help
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Flow
|
|
219
|
+
|
|
220
|
+
1. **Validate** - Playlist structure checked (`validate`-style parse; use `verify` for signatures)
|
|
221
|
+
2. **Select Server** - If multiple servers, choose which one (interactive or via `-s` flag)
|
|
222
|
+
3. **Publish** - Send validated playlist to selected feed server
|
|
223
|
+
4. **Confirm** - Returns playlist ID and server details
|
|
224
|
+
|
|
225
|
+
### Example Output
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
$ npm run dev -- publish playlist.json
|
|
229
|
+
|
|
230
|
+
📡 Publishing playlist to feed server...
|
|
231
|
+
|
|
232
|
+
Multiple feed servers found. Select one:
|
|
233
|
+
0: http://localhost:8787/api/v1
|
|
234
|
+
1: https://feed.example.com/api/v1
|
|
235
|
+
|
|
236
|
+
Select server (0-based index): 0
|
|
237
|
+
|
|
238
|
+
✅ Playlist published successfully!
|
|
239
|
+
Playlist ID: 84e028f8-ea12-4779-a496-64f95f0486cd
|
|
240
|
+
Server: http://localhost:8787/api/v1
|
|
241
|
+
Status: Published to feed server (created)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Error Handling
|
|
245
|
+
|
|
246
|
+
**Validation failed:**
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
❌ Failed to publish playlist
|
|
250
|
+
Playlist validation failed: dpVersion: Required; id: Required
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**File not found:**
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
❌ Failed to publish playlist
|
|
257
|
+
Playlist file not found: /path/to/playlist.json
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**API error:**
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
❌ Failed to publish playlist
|
|
264
|
+
Failed to publish: {"error":"unauthorized","message":"Invalid API key"}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Validate / Sign / Send / Publish (Complete Flow)
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# 1. Create a playlist (via chat or build)
|
|
271
|
+
npm run dev -- chat "Get 3 works from reas.eth" -o playlist.json
|
|
272
|
+
|
|
273
|
+
# 2. Validate it
|
|
274
|
+
npm run dev -- validate playlist.json
|
|
275
|
+
|
|
276
|
+
# 3. Sign it
|
|
277
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
278
|
+
|
|
279
|
+
# 4. Send to device
|
|
280
|
+
npm run dev -- send signed.json -d "My Display"
|
|
281
|
+
|
|
282
|
+
# 5. Publish to feed server
|
|
283
|
+
npm run dev -- publish signed.json -s 0
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Troubleshooting
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Show current configuration
|
|
290
|
+
npm run dev -- config show
|
|
291
|
+
|
|
292
|
+
# Reinitialize config
|
|
293
|
+
npm run dev -- config init
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Natural‑language one‑shot examples (proven)
|
|
297
|
+
|
|
298
|
+
- **ETH contract + token IDs (shuffle/mix, generic device)**
|
|
299
|
+
- Format:
|
|
300
|
+
```bash
|
|
301
|
+
npm run dev -- chat "Compose a playlist from Ethereum contract <0x...> with tokens <id> and <id>; [shuffle|mix]; [send to device|send to '<device>']" -o <output.json> -v
|
|
302
|
+
```
|
|
303
|
+
- Example:
|
|
304
|
+
```bash
|
|
305
|
+
npm run dev -- chat "Compose a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; mix them up; send to device" -o playlist-eth.json -v
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
- **TEZ contract + token IDs (shuffle, named device)**
|
|
309
|
+
- Format:
|
|
310
|
+
```bash
|
|
311
|
+
npm run dev -- chat "Build a playlist from Tezos contract <KT1...> with tokens <id> and <id>; shuffle; send to '<device>'" -o <output.json> -v
|
|
312
|
+
```
|
|
313
|
+
- Example:
|
|
314
|
+
```bash
|
|
315
|
+
npm run dev -- chat "Build a playlist from Tezos contract KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ with tokens 22 and 8; shuffle; send to 'Living Room'" -o playlist-tez.json -v
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
- **Owner address (ENS → ETH), shuffled**
|
|
319
|
+
- Format:
|
|
320
|
+
```bash
|
|
321
|
+
npm run dev -- chat "Create a playlist from address <ens> (<n> items); [shuffle|mix]; [send/push to my device]" -o <output.json> -v
|
|
322
|
+
```
|
|
323
|
+
- Example:
|
|
324
|
+
```bash
|
|
325
|
+
npm run dev -- chat "Create a playlist from address reas.eth (5 items); shuffle; push to my device" -o playlist-ens.json -v
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
- **Owner address (Tezos tz1), shuffled**
|
|
329
|
+
- Format:
|
|
330
|
+
```bash
|
|
331
|
+
npm run dev -- chat "Create a playlist from Tezos address <tz1...> (<n> items); [shuffle|mix]; [send to device]" -o <output.json> -v
|
|
332
|
+
```
|
|
333
|
+
- Example:
|
|
334
|
+
```bash
|
|
335
|
+
npm run dev -- chat "Create a playlist from Tezos address tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb (3 items); mix them up; send to device" -o playlist-tz1.json -v
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
- **Feed playlists (named), shuffled**
|
|
339
|
+
- Format:
|
|
340
|
+
```bash
|
|
341
|
+
npm run dev -- chat "[Create|Build] a playlist from feed '<name>' (<n> items); shuffle; [send to device]" -o <output.json> -v
|
|
342
|
+
```
|
|
343
|
+
- Examples:
|
|
344
|
+
```bash
|
|
345
|
+
npm run dev -- chat "Create a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed1.json -v
|
|
346
|
+
npm run dev -- chat "Build a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed2.json -v
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
- **Mixed in one prompt (ETH + TEZ + feed + ENS), shuffled, named device**
|
|
350
|
+
- Format:
|
|
351
|
+
```bash
|
|
352
|
+
npm run dev -- chat "Compose a playlist: Tezos <KT1...> tokens <id>, <id>; Ethereum <0x...> tokens <id>, <id>; <n> from '<feed>'; <m> from <ens>; shuffle; send to '<device>'" -o <output.json> -v
|
|
353
|
+
```
|
|
354
|
+
- Example:
|
|
355
|
+
```bash
|
|
356
|
+
npm run dev -- chat "Compose a playlist: Tezos KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ tokens 22, 8; Ethereum 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932, 52457; 3 from 'Unsupervised'; 1 from reas.eth; shuffle; send to 'Living Room'" -o playlist-mixed.json -v
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
- **Multiple instructions in one prompt (incremental), shuffled**
|
|
360
|
+
- Format:
|
|
361
|
+
```bash
|
|
362
|
+
npm run dev -- chat "Create a playlist from Ethereum contract <0x...> tokens <id>, <id>; then add <n> from '<feed>'; then add <m> from <ens>; shuffle; [send/push to my device]" -o <output.json> -v
|
|
363
|
+
```
|
|
364
|
+
- Example:
|
|
365
|
+
```bash
|
|
366
|
+
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932, 52457; then add 2 from 'Unsupervised'; then add 1 from reas.eth; shuffle; push to my device" -o playlist-multi.json -v
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
- **Synonym variants for the same ETH case**
|
|
370
|
+
- Format:
|
|
371
|
+
```bash
|
|
372
|
+
npm run dev -- chat "[Build|Create|Compose] a playlist from Ethereum contract <0x...> tokens <id> and <id>; send to device" -o <output.json> -v
|
|
373
|
+
```
|
|
374
|
+
- Examples:
|
|
375
|
+
```bash
|
|
376
|
+
npm run dev -- chat "Build a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-build.json -v
|
|
377
|
+
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-create.json -v
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
- **Device targeting: generic vs named**
|
|
381
|
+
- Format:
|
|
382
|
+
```bash
|
|
383
|
+
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to device" -o <output.json> -v
|
|
384
|
+
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to '<device>'" -o <output.json> -v
|
|
385
|
+
```
|
|
386
|
+
- Examples:
|
|
387
|
+
```bash
|
|
388
|
+
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to device" -o playlist-generic-device.json -v
|
|
389
|
+
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to 'Living Room'" -o playlist-named-device.json -v
|
|
390
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Function Calling Architecture
|
|
2
|
+
|
|
3
|
+
How ff-cli uses AI function calling to build playlists deterministically. The model orchestrates function calls; tools enforce schema and assemble the DP-1 envelope.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Natural language requests become structured parameters. An AI orchestrator then calls functions to fetch items, build a DP-1 playlist, validate structure (`verify_playlist`), optionally sign, and send to a device.
|
|
8
|
+
|
|
9
|
+
Pipeline:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Intent Parser → Orchestrator (function calls) → Utilities → DP-1 Playlist
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Key files:
|
|
16
|
+
|
|
17
|
+
- `src/intent-parser/` – Parses user text into `requirements` + `playlistSettings`
|
|
18
|
+
- `src/ai-orchestrator/index.js` – Function schemas and orchestration logic
|
|
19
|
+
- `src/utilities/` – Concrete implementations used by the orchestrator
|
|
20
|
+
- `src/main.ts` – Bridges CLI commands to parser/orchestrator/utilities
|
|
21
|
+
|
|
22
|
+
## Function Schemas (AI‑visible)
|
|
23
|
+
|
|
24
|
+
Defined in `src/ai-orchestrator/index.js` as tool schemas for OpenAI‑compatible clients.
|
|
25
|
+
|
|
26
|
+
- `query_requirement(requirement, duration)`
|
|
27
|
+
- Types: `build_playlist`, `fetch_feed`, `query_address`
|
|
28
|
+
- For `build_playlist`: requires `blockchain`, `contractAddress`, `tokenIds`, optional `quantity`
|
|
29
|
+
- For `query_address`: requires `ownerAddress`, optional `quantity` (random selection)
|
|
30
|
+
- For `fetch_feed`: requires `playlistName`, `quantity`
|
|
31
|
+
|
|
32
|
+
- `search_feed_playlist(playlistName)` → fuzzy-match across configured feeds
|
|
33
|
+
- `fetch_feed_playlist_items(playlistName, quantity, duration)`
|
|
34
|
+
- `build_playlist(items, title?, slug?, shuffle?)` → returns DP-1 playlist
|
|
35
|
+
- `verify_playlist(playlist)` → DP-1 parse/structure validation only (must precede send; use CLI `verify` for signatures)
|
|
36
|
+
- `verify_addresses(addresses[])` → validates Ethereum (0x...) and Tezos (tz.../KT1) address formats
|
|
37
|
+
- `send_to_device(playlist, deviceName?)`
|
|
38
|
+
- `resolve_domains(domains[], displayResults?)` → ENS/TNS resolution
|
|
39
|
+
|
|
40
|
+
Notes enforced by the orchestrator:
|
|
41
|
+
|
|
42
|
+
- Always pass complete requirement objects (no truncating addresses/token IDs)
|
|
43
|
+
- Resolve domains (`.eth`, `.tez`) before `query_address`
|
|
44
|
+
- Build, then `verify_playlist` (structure) before sending to devices
|
|
45
|
+
- Shuffle is controlled by `playlistSettings.preserveOrder`
|
|
46
|
+
|
|
47
|
+
## Implementations (server‑side)
|
|
48
|
+
|
|
49
|
+
Located in `src/utilities/` and wired in `src/ai-orchestrator/index.js`:
|
|
50
|
+
|
|
51
|
+
- `buildDP1Playlist({ items, title, slug })` → `src/utilities/playlist-builder.js`
|
|
52
|
+
- `sendPlaylistToDevice({ playlist, deviceName })` → `src/utilities/ff1-device.ts`
|
|
53
|
+
- `resolveDomains({ domains, displayResults })` → `src/utilities/domain-resolver.ts`
|
|
54
|
+
- `verifyPlaylist({ playlist })` in `functions.js` → delegates to `validatePlaylist` in `playlist-verifier.ts` (structure/parse only)
|
|
55
|
+
- `verifyAddresses({ addresses })` → `src/utilities/functions.js` (uses `address-validator.ts`)
|
|
56
|
+
- Feed utilities: `feed-fetcher.js`
|
|
57
|
+
|
|
58
|
+
## Deterministic Paths
|
|
59
|
+
|
|
60
|
+
Two options are available:
|
|
61
|
+
|
|
62
|
+
1. No-AI deterministic build (recommended for automation): Use CLI `build` command with a JSON file or stdin containing:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"requirements": [
|
|
67
|
+
{ "type": "fetch_feed", "playlistName": "Social Codes", "quantity": 3 },
|
|
68
|
+
{
|
|
69
|
+
"type": "build_playlist",
|
|
70
|
+
"blockchain": "ethereum",
|
|
71
|
+
"contractAddress": "0x...",
|
|
72
|
+
"tokenIds": ["1", "2"],
|
|
73
|
+
"quantity": 2
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"playlistSettings": { "durationPerItem": 10, "preserveOrder": true, "title": "My Mix" }
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This path bypasses the intent parser/orchestrator and calls utilities directly. Validation and sensible defaults are applied in `src/main.ts`.
|
|
81
|
+
|
|
82
|
+
2. AI‑orchestrated deterministic build (recommended for prompts): Use `chat` with `--verbose` to see tool calls. The orchestrator enforces complete requirement objects, then runs `verify_playlist` (structure only) before sending.
|
|
83
|
+
|
|
84
|
+
## Extending Functionality (OSS‑first)
|
|
85
|
+
|
|
86
|
+
1. Add a new function in `src/utilities/` (prefer OSS libs: `viem` for Ethereum, `@taquito/taquito` for Tezos; add local caching where it helps)
|
|
87
|
+
2. Export and wire it in `src/utilities/index.js`
|
|
88
|
+
3. Add a corresponding schema in `src/ai-orchestrator/index.js`
|
|
89
|
+
4. Update this doc if user‑facing behavior changes
|
|
90
|
+
5. Run `npm run lint:fix`
|
|
91
|
+
|
|
92
|
+
## Validation & Constraints
|
|
93
|
+
|
|
94
|
+
- Verify via `dp1-js` for DP-1 conformance (canonical JSON + Ed25519 signing supported)
|
|
95
|
+
- Enforce max item counts and ordering/shuffle rules during build
|
|
96
|
+
- Batch domain resolution; report failures without crashing the flow
|