@feralfile/cli 1.6.0 → 2.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.
@@ -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
- }
@@ -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