@feralfile/cli 1.6.0 → 2.0.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/README.md +6 -11
- package/config.json.example +0 -65
- package/dist/index.js +1 -3
- package/dist/package.json +3 -4
- package/dist/src/commands/config.js +15 -13
- package/dist/src/commands/play.js +63 -0
- package/dist/src/commands/setup.js +1 -73
- package/dist/src/commands/status.js +0 -13
- package/dist/src/config.js +3 -126
- package/dist/src/main.js +2 -361
- package/dist/src/utilities/ff1-device.js +55 -0
- package/dist/src/utilities/playlist-builder.js +79 -17
- package/docs/CONFIGURATION.md +1 -35
- package/docs/EXAMPLES.md +206 -215
- package/docs/PROJECT_SPEC.md +20 -18
- package/docs/README.md +51 -104
- package/package.json +3 -4
- package/dist/src/ai-orchestrator/index.js +0 -1040
- package/dist/src/ai-orchestrator/registry.js +0 -96
- package/dist/src/commands/chat.js +0 -189
- package/dist/src/intent-parser/index.js +0 -1393
- package/dist/src/intent-parser/utils.js +0 -116
- package/docs/FUNCTION_CALLING.md +0 -100
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Intent Parser Utilities
|
|
4
|
-
* Validation and constraint enforcement for parsed requirements
|
|
5
|
-
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.applyConstraints = applyConstraints;
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
/**
|
|
13
|
-
* Apply constraints to parsed requirements
|
|
14
|
-
*
|
|
15
|
-
* @param {Object} params - Parsed parameters
|
|
16
|
-
* @param {Array<Object>} params.requirements - Array of requirements
|
|
17
|
-
* @param {Object} [params.playlistSettings] - Playlist settings
|
|
18
|
-
* @param {Object} _config - Application config (kept in the signature for
|
|
19
|
-
* call-site stability; no constraint reads it since durationPerItem
|
|
20
|
-
* pre-filling was removed in favor of DP-1 §4.1 auto timing)
|
|
21
|
-
* @returns {Object} Validated parameters
|
|
22
|
-
*/
|
|
23
|
-
function applyConstraints(params, _config) {
|
|
24
|
-
// Validate requirements array
|
|
25
|
-
if (!params.requirements || !Array.isArray(params.requirements)) {
|
|
26
|
-
throw new Error('Requirements must be an array');
|
|
27
|
-
}
|
|
28
|
-
if (params.requirements.length === 0) {
|
|
29
|
-
throw new Error('At least one requirement is needed');
|
|
30
|
-
}
|
|
31
|
-
// Validate each requirement
|
|
32
|
-
params.requirements = params.requirements.map((req, index) => {
|
|
33
|
-
const r = req;
|
|
34
|
-
if (!r.type) {
|
|
35
|
-
throw new Error(`Requirement ${index + 1}: type is required`);
|
|
36
|
-
}
|
|
37
|
-
// Validate based on type
|
|
38
|
-
if (r.type === 'build_playlist') {
|
|
39
|
-
if (!r.blockchain) {
|
|
40
|
-
throw new Error(`Requirement ${index + 1}: blockchain is required for build_playlist`);
|
|
41
|
-
}
|
|
42
|
-
if (!r.contractAddress) {
|
|
43
|
-
throw new Error(`Requirement ${index + 1}: contractAddress is required for build_playlist`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else if (r.type === 'query_address') {
|
|
47
|
-
if (!r.ownerAddress) {
|
|
48
|
-
throw new Error(`Requirement ${index + 1}: ownerAddress is required for query_address`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else if (r.type === 'fetch_feed') {
|
|
52
|
-
if (!r.playlistName) {
|
|
53
|
-
throw new Error(`Requirement ${index + 1}: playlistName is required for fetch_feed`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else if (r.type === 'feral_file_artwork') {
|
|
57
|
-
if (!r.artworkId) {
|
|
58
|
-
throw new Error(`Requirement ${index + 1}: artworkId is required for feral_file_artwork`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
throw new Error(`Requirement ${index + 1}: invalid type "${r.type}"`);
|
|
63
|
-
}
|
|
64
|
-
// Set default quantity if not provided
|
|
65
|
-
// Allow "all" as a string value for query_address type
|
|
66
|
-
let quantity;
|
|
67
|
-
if (r.quantity === 'all') {
|
|
68
|
-
quantity = 'all';
|
|
69
|
-
}
|
|
70
|
-
else if (r.quantity === null || r.quantity === undefined) {
|
|
71
|
-
quantity = 5;
|
|
72
|
-
}
|
|
73
|
-
else if (typeof r.quantity === 'string') {
|
|
74
|
-
// Try to parse string numbers
|
|
75
|
-
const parsed = parseInt(r.quantity, 10);
|
|
76
|
-
quantity = isNaN(parsed) ? r.quantity : parsed;
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
quantity = r.quantity;
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
...r,
|
|
83
|
-
quantity: quantity, // No cap - registry system handles large playlists efficiently
|
|
84
|
-
tokenIds: r.tokenIds || [],
|
|
85
|
-
};
|
|
86
|
-
});
|
|
87
|
-
// Note: No cap needed - registry system handles large playlists efficiently
|
|
88
|
-
// Full items are stored in memory, only IDs are sent to AI model
|
|
89
|
-
const hasAllQuantity = params.requirements.some((r) => 'quantity' in r && r.quantity === 'all');
|
|
90
|
-
const totalRequested = params.requirements.reduce((sum, r) => {
|
|
91
|
-
if ('quantity' in r && typeof r.quantity === 'number') {
|
|
92
|
-
return sum + r.quantity;
|
|
93
|
-
}
|
|
94
|
-
return sum;
|
|
95
|
-
}, 0);
|
|
96
|
-
if (hasAllQuantity) {
|
|
97
|
-
console.log(chalk_1.default.yellow(`\nRequesting all tokens from one or more addresses. This may take a while to fetch and process.\n`));
|
|
98
|
-
}
|
|
99
|
-
else if (totalRequested > 100) {
|
|
100
|
-
console.log(chalk_1.default.yellow(`\nRequesting ${totalRequested} items. This may take a while to fetch and process.\n`));
|
|
101
|
-
}
|
|
102
|
-
// Set playlist defaults
|
|
103
|
-
if (!params.playlistSettings) {
|
|
104
|
-
params.playlistSettings = {};
|
|
105
|
-
}
|
|
106
|
-
// durationPerItem stays undefined unless the user asked for a per-item
|
|
107
|
-
// time: absence means auto timing downstream (video/audio omit duration
|
|
108
|
-
// and play their natural length per DP-1 §4.1; static media falls back to
|
|
109
|
-
// config.defaultDuration at item-build time). Pre-filling a number here
|
|
110
|
-
// would force-cut every video item.
|
|
111
|
-
// Only set preserveOrder if not already specified
|
|
112
|
-
if (params.playlistSettings.preserveOrder === undefined) {
|
|
113
|
-
params.playlistSettings.preserveOrder = true;
|
|
114
|
-
}
|
|
115
|
-
return params;
|
|
116
|
-
}
|
package/docs/FUNCTION_CALLING.md
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
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`, `feral_file_artwork`, `fetch_feed`, `query_address`
|
|
28
|
-
- For `build_playlist`: requires `blockchain`, `contractAddress`, `tokenIds`, optional `quantity`
|
|
29
|
-
- For `feral_file_artwork`: requires `artworkId`, either a Feral File public artwork id or `/exhibitions/artwork/{id}` URL
|
|
30
|
-
- For `query_address`: requires `ownerAddress`, optional `quantity` (random selection)
|
|
31
|
-
- For `fetch_feed`: requires `playlistName`, `quantity`
|
|
32
|
-
|
|
33
|
-
- `search_feed_playlist(playlistName)` → fuzzy-match across configured feeds
|
|
34
|
-
- `fetch_feed_playlist_items(playlistName, quantity, duration)`
|
|
35
|
-
- `build_playlist(items, title?, slug?, shuffle?)` → returns DP-1 playlist
|
|
36
|
-
- `verify_playlist(playlist)` → DP-1 parse/structure validation only (must precede send; use CLI `verify` for signatures)
|
|
37
|
-
- `verify_addresses(addresses[])` → validates Ethereum (0x...) and Tezos (tz.../KT1) address formats
|
|
38
|
-
- `send_to_device(playlist, deviceName?)`
|
|
39
|
-
- `resolve_domains(domains[], displayResults?)` → ENS/TNS resolution
|
|
40
|
-
|
|
41
|
-
Notes enforced by the orchestrator:
|
|
42
|
-
|
|
43
|
-
- Always pass complete requirement objects (no truncating addresses/token IDs)
|
|
44
|
-
- Resolve domains (`.eth`, `.tez`) before `query_address`
|
|
45
|
-
- Build, then `verify_playlist` (structure) before sending to devices
|
|
46
|
-
- Shuffle is controlled by `playlistSettings.preserveOrder`
|
|
47
|
-
|
|
48
|
-
## Implementations (server‑side)
|
|
49
|
-
|
|
50
|
-
Located in `src/utilities/` and wired in `src/ai-orchestrator/index.js`:
|
|
51
|
-
|
|
52
|
-
- `buildDP1Playlist({ items, title, slug })` → `src/utilities/playlist-builder.js`
|
|
53
|
-
- `sendPlaylistToDevice({ playlist, deviceName })` → `src/utilities/ff1-device.ts`
|
|
54
|
-
- `resolveDomains({ domains, displayResults })` → `src/utilities/domain-resolver.ts`
|
|
55
|
-
- `verifyPlaylist({ playlist })` in `functions.js` → delegates to `validatePlaylist` in `playlist-verifier.ts` (structure/parse only)
|
|
56
|
-
- `verifyAddresses({ addresses })` → `src/utilities/functions.js` (uses `address-validator.ts`)
|
|
57
|
-
- Feed utilities: `feed-fetcher.js`
|
|
58
|
-
|
|
59
|
-
## Deterministic Paths
|
|
60
|
-
|
|
61
|
-
Two options are available:
|
|
62
|
-
|
|
63
|
-
1. No-AI deterministic build (recommended for automation): Use CLI `build` command with a JSON file or stdin containing:
|
|
64
|
-
|
|
65
|
-
```json
|
|
66
|
-
{
|
|
67
|
-
"requirements": [
|
|
68
|
-
{ "type": "fetch_feed", "playlistName": "Social Codes", "quantity": 3 },
|
|
69
|
-
{ "type": "feral_file_artwork", "artworkId": "https://feralfile.com/exhibitions/artwork/..." },
|
|
70
|
-
{
|
|
71
|
-
"type": "build_playlist",
|
|
72
|
-
"blockchain": "ethereum",
|
|
73
|
-
"contractAddress": "0x...",
|
|
74
|
-
"tokenIds": ["1", "2"],
|
|
75
|
-
"quantity": 2
|
|
76
|
-
}
|
|
77
|
-
],
|
|
78
|
-
"playlistSettings": { "preserveOrder": true, "title": "My Mix" }
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
This path bypasses the intent parser/orchestrator and calls utilities directly. Validation and sensible defaults are applied in `src/main.ts`.
|
|
83
|
-
|
|
84
|
-
`playlistSettings.durationPerItem` is optional. Omit it for auto timing: video/audio items are emitted without `duration` and with `display.loop: false`, so a DP-1 player advances at end-of-stream (§4.1) and the media plays its natural length; static items fall back to `defaultDuration`. Set `durationPerItem` only to force a fixed display time on every item.
|
|
85
|
-
|
|
86
|
-
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.
|
|
87
|
-
|
|
88
|
-
## Extending Functionality (OSS‑first)
|
|
89
|
-
|
|
90
|
-
1. Add a new function in `src/utilities/` (prefer OSS libs: `viem` for Ethereum, `@taquito/taquito` for Tezos; add local caching where it helps)
|
|
91
|
-
2. Export and wire it in `src/utilities/index.js`
|
|
92
|
-
3. Add a corresponding schema in `src/ai-orchestrator/index.js`
|
|
93
|
-
4. Update this doc if user‑facing behavior changes
|
|
94
|
-
5. Run `npm run lint:fix`
|
|
95
|
-
|
|
96
|
-
## Validation & Constraints
|
|
97
|
-
|
|
98
|
-
- Verify via `dp1-js` for DP-1 conformance (canonical JSON + Ed25519 signing supported)
|
|
99
|
-
- Enforce max item counts and ordering/shuffle rules during build
|
|
100
|
-
- Batch domain resolution; report failures without crashing the flow
|