@archetypeai/ds-cli 0.5.7 → 0.5.9
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/files/AGENTS.md +0 -15
- package/files/CLAUDE.md +0 -15
- package/files/rules/frontend-architecture.md +0 -1
- package/package.json +1 -1
- package/files/skills/embedding-from-file/SKILL.md +0 -428
- package/files/skills/embedding-from-sensor/SKILL.md +0 -419
- package/files/skills/embedding-upload/SKILL.md +0 -427
- package/files/skills/newton-activity-monitor-lens-on-video/SKILL.md +0 -817
- package/files/skills/newton-camera-frame-analysis/SKILL.md +0 -624
- package/files/skills/newton-camera-frame-analysis/scripts/activity-monitor-frame.py +0 -165
- package/files/skills/newton-camera-frame-analysis/scripts/captures/logs/api_responses_20260206_105610.json +0 -62
- package/files/skills/newton-camera-frame-analysis/scripts/continuous_monitor.py +0 -119
- package/files/skills/newton-direct-query/SKILL.md +0 -221
- package/files/skills/newton-direct-query/scripts/direct_query.py +0 -129
- package/files/skills/newton-machine-state-from-file/SKILL.md +0 -559
- package/files/skills/newton-machine-state-from-sensor/SKILL.md +0 -721
- package/files/skills/newton-machine-state-upload/SKILL.md +0 -986
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: embedding-upload
|
|
3
|
-
description: Run an Embedding Lens by uploading a CSV file for server-side processing. Use when you want to upload a file and get embeddings without local streaming.
|
|
4
|
-
argument-hint: [csv-file-path]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Embedding Lens — Upload File (Server-Side Processing)
|
|
8
|
-
|
|
9
|
-
Generate a script that uploads a CSV file to the Archetype AI platform and extracts embeddings server-side. The server reads the file directly — no local streaming loop required. Supports both Python and JavaScript/Web.
|
|
10
|
-
|
|
11
|
-
## Frontend Architecture
|
|
12
|
-
|
|
13
|
-
Decompose the UI into components. See `@rules/frontend-architecture` for conventions.
|
|
14
|
-
|
|
15
|
-
### Recommended decomposition
|
|
16
|
-
|
|
17
|
-
| UI Area | Component | Pattern/Primitives | Key Props |
|
|
18
|
-
|---------|-----------|-------------------|-----------|
|
|
19
|
-
| File upload | `DataInput.svelte` | BackgroundCard, Button, Input | `onselect`, `status` |
|
|
20
|
-
| Scatter plot | Reuse ScatterChart pattern | BackgroundCard, Chart | `data[]`, `categories` |
|
|
21
|
-
| Progress | `StreamProgress.svelte` | BackgroundCard, Progress | `current`, `total` |
|
|
22
|
-
|
|
23
|
-
- Use `@skills/create-dashboard` for the page layout
|
|
24
|
-
- Extract upload and session logic into `$lib/api/embeddings.js`
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## Python Implementation
|
|
29
|
-
|
|
30
|
-
### Requirements
|
|
31
|
-
|
|
32
|
-
- `archetypeai` Python package
|
|
33
|
-
- Environment variables: `ATAI_API_KEY`, optionally `ATAI_API_ENDPOINT`
|
|
34
|
-
|
|
35
|
-
### Architecture
|
|
36
|
-
|
|
37
|
-
Uses `create_and_run_lens` with YAML config. After the session is created, upload the data CSV and configure a `csv_file_reader` input stream for server-side reading.
|
|
38
|
-
|
|
39
|
-
#### 1. API Client Setup
|
|
40
|
-
|
|
41
|
-
```python
|
|
42
|
-
from archetypeai.api_client import ArchetypeAI
|
|
43
|
-
import os
|
|
44
|
-
|
|
45
|
-
api_key = os.getenv("ATAI_API_KEY")
|
|
46
|
-
api_endpoint = os.getenv("ATAI_API_ENDPOINT", ArchetypeAI.get_default_endpoint())
|
|
47
|
-
client = ArchetypeAI(api_key, api_endpoint=api_endpoint)
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
#### 2. Lens YAML Configuration
|
|
51
|
-
|
|
52
|
-
```yaml
|
|
53
|
-
lens_name: Embedding Lens
|
|
54
|
-
lens_config:
|
|
55
|
-
model_pipeline:
|
|
56
|
-
- processor_name: lens_timeseries_embedding_processor
|
|
57
|
-
processor_config: {}
|
|
58
|
-
model_parameters:
|
|
59
|
-
model_name: OmegaEncoder
|
|
60
|
-
model_version: OmegaEncoder::omega_embeddings_01
|
|
61
|
-
normalize_input: true
|
|
62
|
-
buffer_size: {window_size}
|
|
63
|
-
csv_configs:
|
|
64
|
-
timestamp_column: timestamp
|
|
65
|
-
data_columns: ['a1', 'a2', 'a3', 'a4']
|
|
66
|
-
window_size: {window_size}
|
|
67
|
-
step_size: {step_size}
|
|
68
|
-
output_streams:
|
|
69
|
-
- stream_type: server_sent_events_writer
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
#### 3. Event Builders
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
def build_input_event(file_id, window_size, step_size):
|
|
76
|
-
return {
|
|
77
|
-
"type": "input_stream.set",
|
|
78
|
-
"event_data": {
|
|
79
|
-
"stream_type": "csv_file_reader",
|
|
80
|
-
"stream_config": {
|
|
81
|
-
"file_id": file_id,
|
|
82
|
-
"window_size": window_size,
|
|
83
|
-
"step_size": step_size,
|
|
84
|
-
"loop_recording": False,
|
|
85
|
-
"output_format": ""
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
def build_output_event():
|
|
91
|
-
return {
|
|
92
|
-
"type": "output_stream.set",
|
|
93
|
-
"event_data": {
|
|
94
|
-
"stream_type": "server_side_events_writer",
|
|
95
|
-
"stream_config": {}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
#### 4. Session Callback
|
|
101
|
-
|
|
102
|
-
```python
|
|
103
|
-
def session_callback(session_id, session_endpoint, client, args):
|
|
104
|
-
print(f"Session created: {session_id}")
|
|
105
|
-
|
|
106
|
-
# Upload the data CSV
|
|
107
|
-
data_resp = client.files.local.upload(args["data_file_path"])
|
|
108
|
-
data_file_id = data_resp["file_id"]
|
|
109
|
-
|
|
110
|
-
# Tell server to read the uploaded CSV
|
|
111
|
-
client.lens.sessions.process_event(
|
|
112
|
-
session_id,
|
|
113
|
-
build_input_event(data_file_id, args["window_size"], args["step_size"])
|
|
114
|
-
)
|
|
115
|
-
client.lens.sessions.process_event(
|
|
116
|
-
session_id,
|
|
117
|
-
build_output_event()
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
# Collect embeddings via SSE
|
|
121
|
-
sse_reader = client.lens.sessions.create_sse_consumer(
|
|
122
|
-
session_id, max_read_time_sec=args["max_run_time_sec"]
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
embeddings = []
|
|
126
|
-
try:
|
|
127
|
-
for event in sse_reader.read(block=True):
|
|
128
|
-
if stop_flag:
|
|
129
|
-
break
|
|
130
|
-
if isinstance(event, dict) and event.get("type") == "inference.result":
|
|
131
|
-
ed = event.get("event_data", {})
|
|
132
|
-
embedding = ed.get("response")
|
|
133
|
-
meta = ed.get("query_metadata", {})
|
|
134
|
-
|
|
135
|
-
# Flatten 4×768 → 3072D
|
|
136
|
-
if isinstance(embedding, list) and len(embedding) > 0:
|
|
137
|
-
if isinstance(embedding[0], list):
|
|
138
|
-
flat = [val for row in embedding for val in row]
|
|
139
|
-
else:
|
|
140
|
-
flat = embedding
|
|
141
|
-
|
|
142
|
-
embeddings.append({
|
|
143
|
-
"window_index": len(embeddings),
|
|
144
|
-
"query_timestamp": meta.get("query_timestamp", "N/A"),
|
|
145
|
-
"read_index": meta.get("query_metadata", {}).get("read_index", "N/A"),
|
|
146
|
-
"embedding": flat,
|
|
147
|
-
})
|
|
148
|
-
print(f"[{len(embeddings)}] Embedding: {len(flat)}D")
|
|
149
|
-
finally:
|
|
150
|
-
sse_reader.close()
|
|
151
|
-
print(f"Collected {len(embeddings)} embeddings. Stopped.")
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
#### 5. Create and Run Lens
|
|
155
|
-
|
|
156
|
-
```python
|
|
157
|
-
client.lens.create_and_run_lens(
|
|
158
|
-
yaml_config, session_callback,
|
|
159
|
-
client=client, args=args
|
|
160
|
-
)
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### CLI Arguments
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
--api-key API key (fallback to ATAI_API_KEY env var)
|
|
167
|
-
--api-endpoint API endpoint (default from SDK)
|
|
168
|
-
--data-file Path to CSV file to analyze (required)
|
|
169
|
-
--window-size Window size in samples (default: 100)
|
|
170
|
-
--step-size Step size in samples (default: 100)
|
|
171
|
-
--max-run-time-sec Max runtime (default: 600)
|
|
172
|
-
--output-file Path to save embeddings CSV (optional)
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## Web / JavaScript Implementation
|
|
178
|
-
|
|
179
|
-
Uses direct `fetch` calls to the Archetype AI REST API. The simplest embedding approach on web — just upload and collect results.
|
|
180
|
-
|
|
181
|
-
### API Reference
|
|
182
|
-
|
|
183
|
-
| Operation | Method | Endpoint | Body |
|
|
184
|
-
|-----------|--------|----------|------|
|
|
185
|
-
| Upload file | POST | `/files` | `FormData` |
|
|
186
|
-
| Register lens | POST | `/lens/register` | `{ lens_config: config }` |
|
|
187
|
-
| Create session | POST | `/lens/sessions/create` | `{ lens_id }` |
|
|
188
|
-
| Process event | POST | `/lens/sessions/events/process` | `{ session_id, event }` |
|
|
189
|
-
| Delete lens | POST | `/lens/delete` | `{ lens_id }` |
|
|
190
|
-
| Destroy session | POST | `/lens/sessions/destroy` | `{ session_id }` |
|
|
191
|
-
| SSE consumer | GET | `/lens/sessions/consumer/{sessionId}` | — |
|
|
192
|
-
|
|
193
|
-
### Helper: API fetch wrapper
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
const API_ENDPOINT = 'https://api.u1.archetypeai.app/v0.5'
|
|
197
|
-
|
|
198
|
-
async function apiPost<T>(path: string, apiKey: string, body: unknown, timeoutMs = 5000): Promise<T> {
|
|
199
|
-
const controller = new AbortController()
|
|
200
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
const response = await fetch(`${API_ENDPOINT}${path}`, {
|
|
204
|
-
method: 'POST',
|
|
205
|
-
headers: {
|
|
206
|
-
Authorization: `Bearer ${apiKey}`,
|
|
207
|
-
'Content-Type': 'application/json',
|
|
208
|
-
},
|
|
209
|
-
body: JSON.stringify(body),
|
|
210
|
-
signal: controller.signal,
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
if (!response.ok) {
|
|
214
|
-
const errorBody = await response.json().catch(() => ({}))
|
|
215
|
-
throw new Error(`API POST ${path} failed: ${response.status} - ${JSON.stringify(errorBody)}`)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return response.json()
|
|
219
|
-
} finally {
|
|
220
|
-
clearTimeout(timeoutId)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Step 1: Upload the data CSV
|
|
226
|
-
|
|
227
|
-
```typescript
|
|
228
|
-
const dataFormData = new FormData()
|
|
229
|
-
dataFormData.append('file', dataFile) // File from <input type="file">
|
|
230
|
-
|
|
231
|
-
const dataResponse = await fetch(`${API_ENDPOINT}/files`, {
|
|
232
|
-
method: 'POST',
|
|
233
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
234
|
-
body: dataFormData,
|
|
235
|
-
})
|
|
236
|
-
const dataUpload = await dataResponse.json()
|
|
237
|
-
const dataFileId = dataUpload.file_id
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Step 2: Register embedding lens and create session
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
const windowSize = 100
|
|
244
|
-
const stepSize = 100
|
|
245
|
-
|
|
246
|
-
const lensConfig = {
|
|
247
|
-
lens_name: 'embedding_lens',
|
|
248
|
-
lens_config: {
|
|
249
|
-
model_pipeline: [
|
|
250
|
-
{ processor_name: 'lens_timeseries_embedding_processor', processor_config: {} },
|
|
251
|
-
],
|
|
252
|
-
model_parameters: {
|
|
253
|
-
model_name: 'OmegaEncoder',
|
|
254
|
-
model_version: 'OmegaEncoder::omega_embeddings_01',
|
|
255
|
-
normalize_input: true,
|
|
256
|
-
buffer_size: windowSize,
|
|
257
|
-
csv_configs: {
|
|
258
|
-
timestamp_column: 'timestamp',
|
|
259
|
-
data_columns: ['a1', 'a2', 'a3', 'a4'],
|
|
260
|
-
window_size: windowSize,
|
|
261
|
-
step_size: stepSize,
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
output_streams: [
|
|
265
|
-
{ stream_type: 'server_sent_events_writer' },
|
|
266
|
-
],
|
|
267
|
-
},
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const registeredLens = await apiPost<{ lens_id: string }>(
|
|
271
|
-
'/lens/register', apiKey, { lens_config: lensConfig }
|
|
272
|
-
)
|
|
273
|
-
const lensId = registeredLens.lens_id
|
|
274
|
-
|
|
275
|
-
const session = await apiPost<{ session_id: string }>(
|
|
276
|
-
'/lens/sessions/create', apiKey, { lens_id: lensId }
|
|
277
|
-
)
|
|
278
|
-
const sessionId = session.session_id
|
|
279
|
-
|
|
280
|
-
await apiPost('/lens/delete', apiKey, { lens_id: lensId })
|
|
281
|
-
|
|
282
|
-
// Wait for session ready (same waitForSessionReady pattern)
|
|
283
|
-
async function waitForSessionReady(sessionId: string, maxWaitMs = 30000): Promise<boolean> {
|
|
284
|
-
const start = Date.now()
|
|
285
|
-
while (Date.now() - start < maxWaitMs) {
|
|
286
|
-
const status = await apiPost<{ session_status: string }>(
|
|
287
|
-
'/lens/sessions/events/process', apiKey,
|
|
288
|
-
{ session_id: sessionId, event: { type: 'session.status' } },
|
|
289
|
-
10000
|
|
290
|
-
)
|
|
291
|
-
if (status.session_status === 'LensSessionStatus.SESSION_STATUS_RUNNING' ||
|
|
292
|
-
status.session_status === '3') return true
|
|
293
|
-
if (status.session_status === 'LensSessionStatus.SESSION_STATUS_FAILED' ||
|
|
294
|
-
status.session_status === '6') return false
|
|
295
|
-
await new Promise(r => setTimeout(r, 500))
|
|
296
|
-
}
|
|
297
|
-
return false
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
await waitForSessionReady(sessionId)
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Step 3: Tell server to read the uploaded CSV
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
// Set input stream to CSV file reader
|
|
307
|
-
await apiPost('/lens/sessions/events/process', apiKey, {
|
|
308
|
-
session_id: sessionId,
|
|
309
|
-
event: {
|
|
310
|
-
type: 'input_stream.set',
|
|
311
|
-
event_data: {
|
|
312
|
-
stream_type: 'csv_file_reader',
|
|
313
|
-
stream_config: {
|
|
314
|
-
file_id: dataFileId,
|
|
315
|
-
window_size: windowSize,
|
|
316
|
-
step_size: stepSize,
|
|
317
|
-
loop_recording: false,
|
|
318
|
-
output_format: '',
|
|
319
|
-
},
|
|
320
|
-
},
|
|
321
|
-
},
|
|
322
|
-
}, 10000)
|
|
323
|
-
|
|
324
|
-
// Enable SSE output
|
|
325
|
-
await apiPost('/lens/sessions/events/process', apiKey, {
|
|
326
|
-
session_id: sessionId,
|
|
327
|
-
event: {
|
|
328
|
-
type: 'output_stream.set',
|
|
329
|
-
event_data: {
|
|
330
|
-
stream_type: 'server_side_events_writer',
|
|
331
|
-
stream_config: {},
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
}, 10000)
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Step 4: Consume SSE embedding results
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|
341
|
-
|
|
342
|
-
interface EmbeddingResult {
|
|
343
|
-
windowIndex: number
|
|
344
|
-
queryTimestamp: string
|
|
345
|
-
readIndex: number | string
|
|
346
|
-
embedding: number[] // 3072D flattened
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const embeddings: EmbeddingResult[] = []
|
|
350
|
-
const abortController = new AbortController()
|
|
351
|
-
|
|
352
|
-
fetchEventSource(`${API_ENDPOINT}/lens/sessions/consumer/${sessionId}`, {
|
|
353
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
354
|
-
signal: abortController.signal,
|
|
355
|
-
onmessage(event) {
|
|
356
|
-
const parsed = JSON.parse(event.data)
|
|
357
|
-
|
|
358
|
-
if (parsed.type === 'inference.result') {
|
|
359
|
-
const response = parsed.event_data.response
|
|
360
|
-
const meta = parsed.event_data.query_metadata
|
|
361
|
-
const queryMeta = meta?.query_metadata ?? {}
|
|
362
|
-
|
|
363
|
-
const flat = Array.isArray(response[0]) ? response.flat() : response
|
|
364
|
-
|
|
365
|
-
embeddings.push({
|
|
366
|
-
windowIndex: embeddings.length,
|
|
367
|
-
queryTimestamp: meta?.query_timestamp ?? 'N/A',
|
|
368
|
-
readIndex: queryMeta.read_index ?? 'N/A',
|
|
369
|
-
embedding: flat,
|
|
370
|
-
})
|
|
371
|
-
console.log(`[${embeddings.length}] Embedding: ${flat.length}D`)
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (parsed.type === 'sse.stream.end') {
|
|
375
|
-
console.log(`Complete. ${embeddings.length} embeddings collected.`)
|
|
376
|
-
abortController.abort()
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
})
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
### Step 5: Cleanup
|
|
383
|
-
|
|
384
|
-
```typescript
|
|
385
|
-
abortController.abort()
|
|
386
|
-
await apiPost('/lens/sessions/destroy', apiKey, { session_id: sessionId })
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
### Web Lifecycle Summary
|
|
390
|
-
|
|
391
|
-
```
|
|
392
|
-
1. Upload data CSV -> POST /files (FormData)
|
|
393
|
-
2. Register lens -> POST /lens/register { lens_config: config }
|
|
394
|
-
3. Create session -> POST /lens/sessions/create { lens_id }
|
|
395
|
-
4. Wait for ready -> POST /lens/sessions/events/process (poll)
|
|
396
|
-
5. Set input stream -> POST /lens/sessions/events/process { session_id, event: input_stream.set }
|
|
397
|
-
6. Set output stream -> POST /lens/sessions/events/process { session_id, event: output_stream.set }
|
|
398
|
-
7. Consume SSE results -> GET /lens/sessions/consumer/{sessionId}
|
|
399
|
-
8. Destroy session -> POST /lens/sessions/destroy { session_id }
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
---
|
|
403
|
-
|
|
404
|
-
## Embedding Response Structure
|
|
405
|
-
|
|
406
|
-
The `inference.result` response contains:
|
|
407
|
-
- `response`: nested list `(4, 768)` — one 768D embedding per input channel
|
|
408
|
-
- Flatten to `3072D` by concatenating: `[a1_768D, a2_768D, a3_768D, a4_768D]`
|
|
409
|
-
- `query_metadata.query_timestamp`: timestamp
|
|
410
|
-
- `query_metadata.query_metadata.read_index`: window position in file
|
|
411
|
-
- `query_metadata.query_metadata.file_id`: the file being analyzed
|
|
412
|
-
|
|
413
|
-
## Key Differences from Streaming Approaches
|
|
414
|
-
|
|
415
|
-
| | Upload (this skill) | Stream from File | Stream from Sensor |
|
|
416
|
-
|---|---|---|---|
|
|
417
|
-
| Data reading | Server-side `csv_file_reader` | Local pandas/JS + windowed push | Local sensor + buffered push |
|
|
418
|
-
| Local processing | None (just upload) | Window slicing | Sensor acquisition + buffering |
|
|
419
|
-
| Best for | Batch embedding extraction | Controlled local streaming | Real-time from hardware |
|
|
420
|
-
|
|
421
|
-
## Key Implementation Notes
|
|
422
|
-
|
|
423
|
-
- Default `window_size` and `step_size`: **100**
|
|
424
|
-
- No n-shot files or KNN config — this is pure embedding extraction
|
|
425
|
-
- Embeddings are `(4, 768)` per window — flatten to `3072D` for downstream use
|
|
426
|
-
- Use UMAP/t-SNE for 2D/3D visualization
|
|
427
|
-
- Combine with machine state lens results for labeled embedding plots
|