ff1-cli 1.0.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/LICENSE +21 -0
- package/README.md +65 -0
- package/config.json.example +78 -0
- package/dist/index.js +627 -0
- package/dist/src/ai-orchestrator/index.js +870 -0
- package/dist/src/ai-orchestrator/registry.js +96 -0
- package/dist/src/config.js +352 -0
- package/dist/src/intent-parser/index.js +1342 -0
- package/dist/src/intent-parser/utils.js +108 -0
- package/dist/src/logger.js +72 -0
- package/dist/src/main.js +393 -0
- package/dist/src/types.js +5 -0
- package/dist/src/utilities/address-validator.js +242 -0
- package/dist/src/utilities/domain-resolver.js +291 -0
- package/dist/src/utilities/feed-fetcher.js +387 -0
- package/dist/src/utilities/ff1-device.js +176 -0
- package/dist/src/utilities/functions.js +325 -0
- package/dist/src/utilities/index.js +372 -0
- package/dist/src/utilities/nft-indexer.js +1013 -0
- package/dist/src/utilities/playlist-builder.js +522 -0
- package/dist/src/utilities/playlist-publisher.js +131 -0
- package/dist/src/utilities/playlist-send.js +241 -0
- package/dist/src/utilities/playlist-signer.js +171 -0
- package/dist/src/utilities/playlist-verifier.js +156 -0
- package/dist/src/utils.js +48 -0
- package/docs/CONFIGURATION.md +178 -0
- package/docs/EXAMPLES.md +331 -0
- package/docs/FUNCTION_CALLING.md +92 -0
- package/docs/README.md +267 -0
- package/docs/RELEASING.md +22 -0
- package/package.json +75 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Configuration Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to configure FF1‑CLI, field by field. Configuration priority is:
|
|
4
|
+
|
|
5
|
+
- `config.json` (highest)
|
|
6
|
+
- `.env`
|
|
7
|
+
- built‑in defaults (lowest)
|
|
8
|
+
|
|
9
|
+
## Getting started
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Create example config and edit it
|
|
13
|
+
npm run dev -- config init
|
|
14
|
+
|
|
15
|
+
# Validate your configuration
|
|
16
|
+
npm run dev -- config validate
|
|
17
|
+
|
|
18
|
+
# Show current config summary
|
|
19
|
+
npm run dev -- config show
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Top‑level fields
|
|
23
|
+
|
|
24
|
+
- **defaultModel** (string)
|
|
25
|
+
- The default AI model key to use. Must match a key under `models`.
|
|
26
|
+
- Used by orchestration to pick API, timeouts, and model identifier.
|
|
27
|
+
|
|
28
|
+
- **defaultDuration** (number, seconds)
|
|
29
|
+
- Intended default per‑item display duration. Some flows pass an explicit duration; when omitted, utilities fall back to 10s.
|
|
30
|
+
|
|
31
|
+
## models
|
|
32
|
+
|
|
33
|
+
Each key under `models` defines a model configuration used by the AI orchestrator.
|
|
34
|
+
|
|
35
|
+
- `<modelName>.apiKey` (string): API key for the provider.
|
|
36
|
+
- `<modelName>.baseURL` (string): Base API URL.
|
|
37
|
+
- `<modelName>.model` (string): Model identifier (e.g., `grok-beta`, `gpt-4o`).
|
|
38
|
+
- `<modelName>.availableModels` (string[], optional): Display/help only.
|
|
39
|
+
- `<modelName>.timeout` (number, ms): HTTP timeout for requests.
|
|
40
|
+
- `<modelName>.maxRetries` (number): Retry count for requests.
|
|
41
|
+
- `<modelName>.temperature` (number): Generation temperature.
|
|
42
|
+
- `<modelName>.maxTokens` (number): Token cap.
|
|
43
|
+
- `<modelName>.supportsFunctionCalling` (boolean): Must be true; otherwise the CLI rejects the model.
|
|
44
|
+
|
|
45
|
+
Environment variable helpers:
|
|
46
|
+
|
|
47
|
+
- Grok: `GROK_API_KEY`, `GROK_MODEL`, `GROK_API_BASE_URL`
|
|
48
|
+
- OpenAI: `OPENAI_API_KEY`
|
|
49
|
+
- Gemini: `GEMINI_API_KEY`
|
|
50
|
+
|
|
51
|
+
## browser
|
|
52
|
+
|
|
53
|
+
Optional settings used where headless/browser‑like behavior is needed.
|
|
54
|
+
|
|
55
|
+
- `browser.timeout` (number, ms): Operation timeout (default 90000).
|
|
56
|
+
- `browser.sanitizationLevel` ("none" | "low" | "medium" | "high" | 0‑3): Converted to numeric via `sanitizationLevelToNumber()`; invalid values are flagged during validation.
|
|
57
|
+
|
|
58
|
+
## playlist
|
|
59
|
+
|
|
60
|
+
Used for signing DP‑1 playlists.
|
|
61
|
+
|
|
62
|
+
- `playlist.privateKey` (string, Ed25519 private key in hex or base64): Used by the `sign` command. Hex may include or omit the `0x` prefix. You can also set this via `PLAYLIST_PRIVATE_KEY` in `.env`.
|
|
63
|
+
|
|
64
|
+
### Generate an Ed25519 private key
|
|
65
|
+
|
|
66
|
+
You can generate a key locally. The CLI accepts either base64 (preferred) or hex
|
|
67
|
+
|
|
68
|
+
OpenSSL (recommended):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Base64 (preferred)
|
|
72
|
+
openssl genpkey -algorithm ED25519 -outform DER | base64 | tr -d '\n'
|
|
73
|
+
|
|
74
|
+
# Hex (alternative)
|
|
75
|
+
openssl genpkey -algorithm ED25519 -outform DER | xxd -p -c 256
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Paste either value into `playlist.privateKey`:
|
|
79
|
+
|
|
80
|
+
- Hex example (either is valid):
|
|
81
|
+
- `0xabc123...` (with prefix)
|
|
82
|
+
- `abc123...` (without prefix)
|
|
83
|
+
- Base64 example: `uQd9m8S...==`
|
|
84
|
+
|
|
85
|
+
If you already have a base64 key and want hex, convert it:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
echo -n "<BASE64_KEY>" | base64 -d | xxd -p -c 256
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## feed
|
|
92
|
+
|
|
93
|
+
DP‑1 Feed API configuration.
|
|
94
|
+
|
|
95
|
+
- `feed.baseURLs` (string[]): Array of DP‑1 Feed Operator API v1 base URLs. The CLI queries all feeds in parallel.
|
|
96
|
+
- Legacy support: `feed.baseURL` (string) is still accepted and normalized to an array.
|
|
97
|
+
- Default: `https://feed.feralfile.com/api/v1` if not set.
|
|
98
|
+
- Compatibility: API v1 of the DP‑1 Feed Operator server. See the repository for endpoints and behavior: [dp1-feed](https://github.com/display-protocol/dp1-feed).
|
|
99
|
+
|
|
100
|
+
Endpoints used by the CLI:
|
|
101
|
+
|
|
102
|
+
- `GET /api/v1/playlists` (supports `limit`, `offset`, and sorting)
|
|
103
|
+
- `GET /api/v1/playlists/{id}`
|
|
104
|
+
|
|
105
|
+
Environment variable alternative:
|
|
106
|
+
|
|
107
|
+
```env
|
|
108
|
+
FEED_BASE_URLS=https://feed.feralfile.com/api/v1,https://dp1-feed-operator-api-prod.autonomy-system.workers.dev/api/v1
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## ff1Devices
|
|
112
|
+
|
|
113
|
+
Configure devices you want to send playlists to.
|
|
114
|
+
|
|
115
|
+
- `ff1Devices.devices` (array of objects):
|
|
116
|
+
- `name` (string): Friendly device label. Free‑form; pick anything memorable.
|
|
117
|
+
- `host` (string): Device base URL. For LAN devices, use `http://<ip>:1111`. The device typically listens on port `1111`.
|
|
118
|
+
|
|
119
|
+
Selection rules when sending:
|
|
120
|
+
|
|
121
|
+
- If you omit `-d`, the first configured device is used.
|
|
122
|
+
- If you pass `-d <name>`, the CLI matches the device by `name` (exact match). If not found, you’ll see an error listing available devices.
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Send to first device
|
|
128
|
+
npm run dev -- send playlist.json
|
|
129
|
+
|
|
130
|
+
# Send to a specific device by exact name
|
|
131
|
+
npm run dev -- send playlist.json -d "Living Room Display"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Minimal `config.json` example (selected fields):
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"defaultModel": "grok",
|
|
139
|
+
"models": {
|
|
140
|
+
"grok": {
|
|
141
|
+
"apiKey": "xai-your-api-key-here",
|
|
142
|
+
"baseURL": "https://api.x.ai/v1",
|
|
143
|
+
"model": "grok-beta",
|
|
144
|
+
"supportsFunctionCalling": true
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"defaultDuration": 10,
|
|
148
|
+
"playlist": {
|
|
149
|
+
"privateKey": "your_ed25519_private_key_hex_or_base64_here"
|
|
150
|
+
},
|
|
151
|
+
"feed": {
|
|
152
|
+
"baseURLs": [
|
|
153
|
+
"https://feed.feralfile.com/api/v1"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
"ff1Devices": {
|
|
157
|
+
"devices": [
|
|
158
|
+
{
|
|
159
|
+
"name": "Living Room Display",
|
|
160
|
+
"host": "http://192.168.1.100:1111"
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Security and validation
|
|
168
|
+
|
|
169
|
+
- Do not commit secrets. Keep `config.json`, `.env`, and keys out of version control.
|
|
170
|
+
- Validate changes regularly:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
npm run dev -- config validate
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
If configuration is invalid, the CLI prints actionable errors and a non‑zero exit code.
|
|
177
|
+
|
|
178
|
+
|
package/docs/EXAMPLES.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
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 -- config init
|
|
10
|
+
npm run dev -- config validate
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Natural Language
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Interactive chat
|
|
17
|
+
npm run dev chat
|
|
18
|
+
|
|
19
|
+
# One-shot requests
|
|
20
|
+
npm run dev -- chat "Get tokens 1,2,3 from Ethereum contract 0xabc" -o playlist.json
|
|
21
|
+
npm run dev -- chat "Get token 42 from Tezos contract KT1abc"
|
|
22
|
+
npm run dev -- chat "Get 3 items from Social Codes and 2 from 0xdef" -v
|
|
23
|
+
|
|
24
|
+
# Switch model
|
|
25
|
+
npm run dev -- chat "your request" --model grok
|
|
26
|
+
npm run dev -- chat "your request" --model chatgpt
|
|
27
|
+
npm run dev -- chat "your request" --model gemini
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Deterministic Build (no AI)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# From file
|
|
34
|
+
npm run dev -- build examples/params-example.json -o playlist.json
|
|
35
|
+
|
|
36
|
+
# From stdin
|
|
37
|
+
cat examples/params-example.json | npm run dev -- build -o playlist.json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## AI‑Orchestrated Deterministic Flow (prompts)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Show tool‑call progress and validation
|
|
44
|
+
npm run dev -- chat "Build a playlist of my Tezos works from address tz1... plus 3 from Social Codes" -v -o playlist.json
|
|
45
|
+
|
|
46
|
+
# Switch model if desired
|
|
47
|
+
npm run dev -- chat "Build playlist from Ethereum address 0x... and 2 from Social Codes" --model chatgpt -v
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### One‑shot complex prompt
|
|
51
|
+
|
|
52
|
+
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.
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Example: combine sources, shuffle, set 6s per item, and send to device
|
|
56
|
+
npm run dev -- chat "Get tokens 1,2 from contract 0xabc and token 42 from KT1xyz; shuffle; 6 seconds each; send to 'Living Room Display'." -o playlist.json -v
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Natural Language: Display and Publish
|
|
60
|
+
|
|
61
|
+
The CLI recognizes publishing keywords like "publish", "publish to my feed", "push to feed", "send to feed" and automatically publishes after building.
|
|
62
|
+
|
|
63
|
+
### Basic Publishing
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Build and publish
|
|
67
|
+
npm run dev -- chat "Build playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; publish to my feed" -o playlist.json -v
|
|
68
|
+
|
|
69
|
+
# With feed selection (if multiple servers configured)
|
|
70
|
+
# The CLI will ask: "Which feed server? 1) https://feed.feralfile.com/api/v1 2) http://localhost:8787"
|
|
71
|
+
npm run dev -- chat "Get 3 from Social Codes and publish to feed" -v
|
|
72
|
+
|
|
73
|
+
# Publish existing playlist (defaults to ./playlist.json)
|
|
74
|
+
npm run dev chat
|
|
75
|
+
# Then type: "publish playlist"
|
|
76
|
+
|
|
77
|
+
# Publish specific playlist file
|
|
78
|
+
npm run dev chat
|
|
79
|
+
# Then type: "publish the playlist ./playlist-temp.json"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Combined: Display + Publish
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Display on FF1 AND publish to feed
|
|
86
|
+
npm run dev -- chat "Build playlist from contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; mix them up; send to my FF1 and publish to my feed" -o playlist.json -v
|
|
87
|
+
|
|
88
|
+
# With explicit device name
|
|
89
|
+
npm run dev -- chat "Get 5 from Social Codes, shuffle, display on 'Living Room', and publish to feed" -v
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### How It Works
|
|
93
|
+
|
|
94
|
+
**Mode 1: Build and Publish** (when sources are mentioned)
|
|
95
|
+
1. Intent parser detects "publish" keywords with sources/requirements
|
|
96
|
+
2. Calls `get_feed_servers` to retrieve configured servers
|
|
97
|
+
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
98
|
+
4. Builds playlist → verifies → publishes automatically
|
|
99
|
+
|
|
100
|
+
**Mode 2: Publish Existing File** (e.g., "publish playlist")
|
|
101
|
+
1. Intent parser detects "publish playlist" or similar phrases
|
|
102
|
+
2. Calls `get_feed_servers` to retrieve configured servers
|
|
103
|
+
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
104
|
+
4. Publishes the playlist from `./playlist.json` (or specified path)
|
|
105
|
+
|
|
106
|
+
Output shows:
|
|
107
|
+
- Playlist build progress (Mode 1 only)
|
|
108
|
+
- Device sending (if requested): `✓ Sent to device: Living Room`
|
|
109
|
+
- Publishing status: `✓ Published to feed server`
|
|
110
|
+
- Playlist ID: `Playlist ID: 84e028f8-...`
|
|
111
|
+
|
|
112
|
+
## Validate / Sign / Send
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Validate playlist
|
|
116
|
+
npm run dev -- validate playlist.json
|
|
117
|
+
|
|
118
|
+
# Sign playlist
|
|
119
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
120
|
+
|
|
121
|
+
# Send to device
|
|
122
|
+
npm run dev -- send playlist.json -d "Living Room Display"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Publish to Feed Server
|
|
126
|
+
|
|
127
|
+
Publish validated playlists to a DP-1 feed server for sharing and discovery.
|
|
128
|
+
|
|
129
|
+
### Configuration
|
|
130
|
+
|
|
131
|
+
Add feed servers to `config.json`:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"feedServers": [
|
|
136
|
+
{
|
|
137
|
+
"baseUrl": "http://localhost:8787/api/v1",
|
|
138
|
+
"apiKey": "your-api-key"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"baseUrl": "https://feed.example.com/api/v1",
|
|
142
|
+
"apiKey": "your-api-key"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Publish Commands
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Interactive: list servers and ask which to use
|
|
152
|
+
npm run dev -- publish playlist.json
|
|
153
|
+
|
|
154
|
+
# Direct: publish to specific server (server index 0)
|
|
155
|
+
npm run dev -- publish playlist.json -s 0
|
|
156
|
+
|
|
157
|
+
# Show help
|
|
158
|
+
npm run dev -- publish --help
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Flow
|
|
162
|
+
|
|
163
|
+
1. **Validate** - Playlist verified against DP-1 specification
|
|
164
|
+
2. **Select Server** - If multiple servers, choose which one (interactive or via `-s` flag)
|
|
165
|
+
3. **Publish** - Send validated playlist to selected feed server
|
|
166
|
+
4. **Confirm** - Returns playlist ID and server details
|
|
167
|
+
|
|
168
|
+
### Example Output
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
$ npm run dev -- publish playlist.json
|
|
172
|
+
|
|
173
|
+
📡 Publishing playlist to feed server...
|
|
174
|
+
|
|
175
|
+
Multiple feed servers found. Select one:
|
|
176
|
+
0: http://localhost:8787/api/v1
|
|
177
|
+
1: https://feed.example.com/api/v1
|
|
178
|
+
|
|
179
|
+
Select server (0-based index): 0
|
|
180
|
+
|
|
181
|
+
✅ Playlist published successfully!
|
|
182
|
+
Playlist ID: 84e028f8-ea12-4779-a496-64f95f0486cd
|
|
183
|
+
Server: http://localhost:8787/api/v1
|
|
184
|
+
Status: Published to feed server (created)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Error Handling
|
|
188
|
+
|
|
189
|
+
**Validation failed:**
|
|
190
|
+
```
|
|
191
|
+
❌ Failed to publish playlist
|
|
192
|
+
Playlist validation failed: dpVersion: Required; id: Required
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**File not found:**
|
|
196
|
+
```
|
|
197
|
+
❌ Failed to publish playlist
|
|
198
|
+
Playlist file not found: /path/to/playlist.json
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**API error:**
|
|
202
|
+
```
|
|
203
|
+
❌ Failed to publish playlist
|
|
204
|
+
Failed to publish: {"error":"unauthorized","message":"Invalid API key"}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Validate / Sign / Send / Publish (Complete Flow)
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# 1. Create a playlist (via chat or build)
|
|
211
|
+
npm run dev -- chat "Get tokens 1,2,3 from contract 0xabc" -o playlist.json
|
|
212
|
+
|
|
213
|
+
# 2. Validate it
|
|
214
|
+
npm run dev -- validate playlist.json
|
|
215
|
+
|
|
216
|
+
# 3. Sign it
|
|
217
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
218
|
+
|
|
219
|
+
# 4. Send to device
|
|
220
|
+
npm run dev -- send signed.json -d "My Display"
|
|
221
|
+
|
|
222
|
+
# 5. Publish to feed server
|
|
223
|
+
npm run dev -- publish signed.json -s 0
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Troubleshooting
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# Show current configuration
|
|
230
|
+
npm run dev -- config show
|
|
231
|
+
|
|
232
|
+
# Reinitialize config
|
|
233
|
+
npm run dev -- config init
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
### Natural‑language one‑shot examples (proven)
|
|
238
|
+
|
|
239
|
+
- **ETH contract + token IDs (shuffle/mix, generic device)**
|
|
240
|
+
- Format:
|
|
241
|
+
```bash
|
|
242
|
+
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
|
|
243
|
+
```
|
|
244
|
+
- Example:
|
|
245
|
+
```bash
|
|
246
|
+
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
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
- **TEZ contract + token IDs (shuffle, named device)**
|
|
250
|
+
- Format:
|
|
251
|
+
```bash
|
|
252
|
+
npm run dev -- chat "Build a playlist from Tezos contract <KT1...> with tokens <id> and <id>; shuffle; send to '<device>'" -o <output.json> -v
|
|
253
|
+
```
|
|
254
|
+
- Example:
|
|
255
|
+
```bash
|
|
256
|
+
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
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
- **Owner address (ENS → ETH), shuffled**
|
|
260
|
+
- Format:
|
|
261
|
+
```bash
|
|
262
|
+
npm run dev -- chat "Create a playlist from address <ens> (<n> items); [shuffle|mix]; [send/push to my device]" -o <output.json> -v
|
|
263
|
+
```
|
|
264
|
+
- Example:
|
|
265
|
+
```bash
|
|
266
|
+
npm run dev -- chat "Create a playlist from address reas.eth (5 items); shuffle; push to my device" -o playlist-ens.json -v
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
- **Owner address (Tezos tz1), shuffled**
|
|
270
|
+
- Format:
|
|
271
|
+
```bash
|
|
272
|
+
npm run dev -- chat "Create a playlist from Tezos address <tz1...> (<n> items); [shuffle|mix]; [send to device]" -o <output.json> -v
|
|
273
|
+
```
|
|
274
|
+
- Example:
|
|
275
|
+
```bash
|
|
276
|
+
npm run dev -- chat "Create a playlist from Tezos address tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb (3 items); mix them up; send to device" -o playlist-tz1.json -v
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
- **Feed playlists (named), shuffled**
|
|
280
|
+
- Format:
|
|
281
|
+
```bash
|
|
282
|
+
npm run dev -- chat "[Create|Build] a playlist from feed '<name>' (<n> items); shuffle; [send to device]" -o <output.json> -v
|
|
283
|
+
```
|
|
284
|
+
- Examples:
|
|
285
|
+
```bash
|
|
286
|
+
npm run dev -- chat "Create a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed1.json -v
|
|
287
|
+
npm run dev -- chat "Build a playlist from feed 'Social Codes' (3 items); shuffle; send to device" -o playlist-feed2.json -v
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
- **Mixed in one prompt (ETH + TEZ + feed + ENS), shuffled, named device**
|
|
291
|
+
- Format:
|
|
292
|
+
```bash
|
|
293
|
+
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
|
|
294
|
+
```
|
|
295
|
+
- Example:
|
|
296
|
+
```bash
|
|
297
|
+
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
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
- **Multiple instructions in one prompt (incremental), shuffled**
|
|
301
|
+
- Format:
|
|
302
|
+
```bash
|
|
303
|
+
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
|
|
304
|
+
```
|
|
305
|
+
- Example:
|
|
306
|
+
```bash
|
|
307
|
+
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932, 52457; then add 2 from 'Social Codes'; then add 1 from reas.eth; shuffle; push to my device" -o playlist-multi.json -v
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
- **Synonym variants for the same ETH case**
|
|
311
|
+
- Format:
|
|
312
|
+
```bash
|
|
313
|
+
npm run dev -- chat "[Build|Create|Compose] a playlist from Ethereum contract <0x...> tokens <id> and <id>; send to device" -o <output.json> -v
|
|
314
|
+
```
|
|
315
|
+
- Examples:
|
|
316
|
+
```bash
|
|
317
|
+
npm run dev -- chat "Build a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-build.json -v
|
|
318
|
+
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-create.json -v
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
- **Device targeting: generic vs named**
|
|
322
|
+
- Format:
|
|
323
|
+
```bash
|
|
324
|
+
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to device" -o <output.json> -v
|
|
325
|
+
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to '<device>'" -o <output.json> -v
|
|
326
|
+
```
|
|
327
|
+
- Examples:
|
|
328
|
+
```bash
|
|
329
|
+
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to device" -o playlist-generic-device.json -v
|
|
330
|
+
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to 'Living Room'" -o playlist-named-device.json -v
|
|
331
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Function Calling Architecture
|
|
2
|
+
|
|
3
|
+
How FF1‑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, verify it, 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)` → validates DP-1 compliance (must precede send)
|
|
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 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 })` → `src/utilities/playlist-verifier.ts`
|
|
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
|
+
{ "type": "build_playlist", "blockchain": "ethereum", "contractAddress": "0x...", "tokenIds": ["1","2"], "quantity": 2 }
|
|
69
|
+
],
|
|
70
|
+
"playlistSettings": { "durationPerItem": 10, "preserveOrder": true, "title": "My Mix" }
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This path bypasses the intent parser/orchestrator and calls utilities directly. Validation and sensible defaults are applied in `src/main.ts`.
|
|
75
|
+
|
|
76
|
+
2) AI‑orchestrated deterministic build (recommended for prompts): Use `chat` with `--verbose` to see tool calls. The orchestrator enforces complete requirement objects, then validates the result with `verify_playlist` before sending.
|
|
77
|
+
|
|
78
|
+
## Extending Functionality (OSS‑first)
|
|
79
|
+
|
|
80
|
+
1. Add a new function in `src/utilities/` (prefer OSS libs: `viem` for Ethereum, `@taquito/taquito` for Tezos; add local caching where it helps)
|
|
81
|
+
2. Export and wire it in `src/utilities/index.js`
|
|
82
|
+
3. Add a corresponding schema in `src/ai-orchestrator/index.js`
|
|
83
|
+
4. Update this doc if user‑facing behavior changes
|
|
84
|
+
5. Run `npm run lint:fix`
|
|
85
|
+
|
|
86
|
+
## Validation & Constraints
|
|
87
|
+
|
|
88
|
+
- Verify via `dp1-js` for DP-1 conformance (canonical JSON + Ed25519 signing supported)
|
|
89
|
+
- Enforce max item counts and ordering/shuffle rules during build
|
|
90
|
+
- Batch domain resolution; report failures without crashing the flow
|
|
91
|
+
|
|
92
|
+
|