@myvillage/cli 2.8.2 → 2.9.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/package.json
CHANGED
|
@@ -22,6 +22,14 @@ export const DATASET_APPEND_DESCRIPTION =
|
|
|
22
22
|
'regression provide a numeric `target`. Data stays local; provenance ' +
|
|
23
23
|
'is recorded automatically.';
|
|
24
24
|
|
|
25
|
+
export const DATASET_READ_DESCRIPTION =
|
|
26
|
+
'Read a LOCAL dataset on this machine: its description, columns, labels, ' +
|
|
27
|
+
'row counts, and a page of its rows (newest working set by default, or a ' +
|
|
28
|
+
'frozen version). Filter by split or label and page with offset/limit. ' +
|
|
29
|
+
'Table rows come back keyed by column name; image and sound rows come back ' +
|
|
30
|
+
'as absolute file paths (which model_predict accepts). Read-only — use ' +
|
|
31
|
+
'dataset_append to add rows.';
|
|
32
|
+
|
|
25
33
|
export const MODEL_PREDICT_DESCRIPTION =
|
|
26
34
|
'Run a prediction with a LOCAL trained model on this machine. `input` is ' +
|
|
27
35
|
'text (words models), the values of one table row as a list in column ' +
|
|
@@ -38,6 +46,12 @@ export const BUILTIN_TOOL_DEFS = [
|
|
|
38
46
|
tier: 'villager',
|
|
39
47
|
builtin: true,
|
|
40
48
|
},
|
|
49
|
+
{
|
|
50
|
+
name: 'dataset_read',
|
|
51
|
+
description: DATASET_READ_DESCRIPTION,
|
|
52
|
+
tier: 'villager',
|
|
53
|
+
builtin: true,
|
|
54
|
+
},
|
|
41
55
|
{
|
|
42
56
|
name: 'model_predict',
|
|
43
57
|
description: MODEL_PREDICT_DESCRIPTION,
|
|
@@ -10,16 +10,63 @@
|
|
|
10
10
|
* `myvillage dataset append` command uses — so agents and humans write
|
|
11
11
|
* identically. Raw data stays local; nothing leaves the machine.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* `dataset_read` is its read side: it wraps readRows() so agents can look at
|
|
14
|
+
* what's been collected (to answer questions about it, avoid duplicate
|
|
15
|
+
* appends, or feed rows to model_predict). Also local-only.
|
|
16
|
+
*
|
|
17
|
+
* Tool contracts mirror @myvillage-studio/dataset-schema DATASET_APPEND_TOOL
|
|
18
|
+
* and DATASET_READ_TOOL.
|
|
14
19
|
*/
|
|
15
20
|
import { tool } from 'ai';
|
|
16
21
|
import { z } from 'zod';
|
|
17
|
-
import {
|
|
18
|
-
|
|
22
|
+
import {
|
|
23
|
+
appendRows,
|
|
24
|
+
datasetExists,
|
|
25
|
+
readManifest,
|
|
26
|
+
readRows,
|
|
27
|
+
ingestAsset,
|
|
28
|
+
getAssetPath,
|
|
29
|
+
listDatasets,
|
|
30
|
+
} from '../utils/dataset-workspace.js';
|
|
31
|
+
import {
|
|
32
|
+
DATASET_APPEND_DESCRIPTION,
|
|
33
|
+
DATASET_READ_DESCRIPTION,
|
|
34
|
+
MODEL_PREDICT_DESCRIPTION,
|
|
35
|
+
} from './builtin-tools-registry.js';
|
|
19
36
|
import { readToolsYaml } from '../utils/local-agent.js';
|
|
20
37
|
|
|
21
38
|
export { BUILTIN_TOOL_DEFS } from './builtin-tools-registry.js';
|
|
22
39
|
|
|
40
|
+
const READ_DEFAULT_LIMIT = 50;
|
|
41
|
+
const READ_MAX_LIMIT = 200;
|
|
42
|
+
// Long text rows are clipped so one page can't blow out the model's context.
|
|
43
|
+
const READ_MAX_TEXT_CHARS = 2000;
|
|
44
|
+
|
|
45
|
+
/** Shape a stored row for the model: readable features, no internal noise. */
|
|
46
|
+
function presentRow(slug, manifest, row) {
|
|
47
|
+
let features = row.features;
|
|
48
|
+
let truncated = false;
|
|
49
|
+
if (features && typeof features === 'object' && !Array.isArray(features) && features.path) {
|
|
50
|
+
// AssetRef → absolute path, the same form model_predict / dataset_append take
|
|
51
|
+
features = getAssetPath(slug, features.path);
|
|
52
|
+
} else if (
|
|
53
|
+
Array.isArray(features) &&
|
|
54
|
+
manifest.featureNames?.length === features.length
|
|
55
|
+
) {
|
|
56
|
+
features = Object.fromEntries(manifest.featureNames.map((name, i) => [name, features[i]]));
|
|
57
|
+
} else if (typeof features === 'string' && features.length > READ_MAX_TEXT_CHARS) {
|
|
58
|
+
features = features.slice(0, READ_MAX_TEXT_CHARS);
|
|
59
|
+
truncated = true;
|
|
60
|
+
}
|
|
61
|
+
const out = { id: row.id, features, split: row.split };
|
|
62
|
+
if (truncated) out.truncated = true;
|
|
63
|
+
if (row.label != null) out.label = row.label;
|
|
64
|
+
if (row.target != null) out.target = row.target;
|
|
65
|
+
if (row.provenance?.source) out.source = row.provenance.source;
|
|
66
|
+
if (row.provenance?.ts) out.addedAt = row.provenance.ts;
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
23
70
|
/**
|
|
24
71
|
* Gate built-ins by the SAME allowlist as the MyVillageOS platform server
|
|
25
72
|
* (`allowed_tools` on whichever tools.yaml server points at a myvillageproject.ai
|
|
@@ -128,6 +175,77 @@ export function getBuiltinTools(agentName, config) {
|
|
|
128
175
|
},
|
|
129
176
|
}),
|
|
130
177
|
|
|
178
|
+
dataset_read: tool({
|
|
179
|
+
description: DATASET_READ_DESCRIPTION,
|
|
180
|
+
inputSchema: z.object({
|
|
181
|
+
datasetId: z.string().describe('Slug of the local dataset to read'),
|
|
182
|
+
version: z
|
|
183
|
+
.number()
|
|
184
|
+
.int()
|
|
185
|
+
.positive()
|
|
186
|
+
.optional()
|
|
187
|
+
.describe('Frozen version number to read; omit for the current working set'),
|
|
188
|
+
split: z.enum(['train', 'val']).optional().describe('Only rows in this split'),
|
|
189
|
+
label: z.string().optional().describe('Only rows with this class label (classification datasets)'),
|
|
190
|
+
offset: z.number().int().min(0).optional().describe('Rows to skip (default 0)'),
|
|
191
|
+
limit: z
|
|
192
|
+
.number()
|
|
193
|
+
.int()
|
|
194
|
+
.min(0)
|
|
195
|
+
.max(READ_MAX_LIMIT)
|
|
196
|
+
.optional()
|
|
197
|
+
.describe(`Rows to return (default ${READ_DEFAULT_LIMIT}, max ${READ_MAX_LIMIT}; 0 = summary only)`),
|
|
198
|
+
}),
|
|
199
|
+
execute: async ({ datasetId, version, split, label, offset = 0, limit = READ_DEFAULT_LIMIT }) => {
|
|
200
|
+
const manifest = readManifest(datasetId);
|
|
201
|
+
if (!manifest) {
|
|
202
|
+
let available = [];
|
|
203
|
+
try {
|
|
204
|
+
available = listDatasets().map((d) => d.slug);
|
|
205
|
+
} catch { /* store unavailable */ }
|
|
206
|
+
return {
|
|
207
|
+
error:
|
|
208
|
+
`Dataset "${datasetId}" not found locally.` +
|
|
209
|
+
(available.length ? ` Available: ${available.join(', ')}.` : ' No local datasets exist yet.'),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (version && !manifest.versions?.some((v) => v.version === version)) {
|
|
213
|
+
const known = (manifest.versions ?? []).map((v) => v.version);
|
|
214
|
+
return {
|
|
215
|
+
error:
|
|
216
|
+
`Dataset "${datasetId}" has no version ${version}.` +
|
|
217
|
+
(known.length ? ` Frozen versions: ${known.join(', ')}.` : ' It has no frozen versions yet.'),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
let rows = readRows(datasetId, { version, split });
|
|
222
|
+
if (label != null) rows = rows.filter((r) => r.label === label);
|
|
223
|
+
const page = rows.slice(offset, offset + limit);
|
|
224
|
+
return {
|
|
225
|
+
ok: true,
|
|
226
|
+
datasetId: manifest.slug,
|
|
227
|
+
name: manifest.name,
|
|
228
|
+
...(manifest.description ? { description: manifest.description } : {}),
|
|
229
|
+
modality: manifest.modality,
|
|
230
|
+
taskType: manifest.taskType,
|
|
231
|
+
labels: manifest.labels ?? [],
|
|
232
|
+
...(manifest.featureNames ? { columns: manifest.featureNames } : {}),
|
|
233
|
+
...(manifest.featureTypes ? { columnTypes: manifest.featureTypes } : {}),
|
|
234
|
+
stats: manifest.stats,
|
|
235
|
+
versions: (manifest.versions ?? []).map((v) => ({ version: v.version, rowCount: v.rowCount, frozenAt: v.frozenAt })),
|
|
236
|
+
reading: version ? `version ${version}` : 'working set',
|
|
237
|
+
matchingRows: rows.length,
|
|
238
|
+
offset,
|
|
239
|
+
returned: page.length,
|
|
240
|
+
hasMore: offset + page.length < rows.length,
|
|
241
|
+
rows: page.map((r) => presentRow(datasetId, manifest, r)),
|
|
242
|
+
};
|
|
243
|
+
} catch (e) {
|
|
244
|
+
return { error: e.message };
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
}),
|
|
248
|
+
|
|
131
249
|
model_predict: tool({
|
|
132
250
|
description: MODEL_PREDICT_DESCRIPTION,
|
|
133
251
|
inputSchema: z.object({
|
|
@@ -34,13 +34,14 @@ export async function gatherContext(agentConfig, lastCheckIn, recentActions = []
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// Local Lab datasets & models, so the agent knows what it can
|
|
38
|
-
// predict with (and the exact slugs to pass to
|
|
37
|
+
// Local Lab datasets & models, so the agent knows what it can read / append
|
|
38
|
+
// to / predict with (and the exact slugs to pass to dataset_read /
|
|
39
|
+
// dataset_append / model_predict).
|
|
39
40
|
// Local-only, synchronous file reads; tfjs is NOT loaded by listing models.
|
|
40
41
|
try {
|
|
41
42
|
const datasets = listDatasets();
|
|
42
43
|
if (datasets.length > 0) {
|
|
43
|
-
parts.push('\nLocal datasets you can add to with dataset_append (use the slug as datasetId):');
|
|
44
|
+
parts.push('\nLocal datasets you can read with dataset_read or add to with dataset_append (use the slug as datasetId):');
|
|
44
45
|
for (const d of datasets.slice(0, 25)) {
|
|
45
46
|
parts.push(`- ${d.slug} — ${d.modality}/${d.taskType}, ${d.stats?.rowCount ?? 0} rows`);
|
|
46
47
|
}
|
|
@@ -25,7 +25,7 @@ const TOOL_GROUPS = {
|
|
|
25
25
|
villages: ['village_search', 'village_view', 'village_create', 'village_update'],
|
|
26
26
|
moments: ['moment_create', 'moment_get', 'pulse_create', 'pulse_list'],
|
|
27
27
|
villagers: ['villager_me', 'villager_search', 'villager_update', 'agent_list'],
|
|
28
|
-
meetings: ['recall_send_bot', 'recall_meeting_attendance'],
|
|
28
|
+
meetings: ['recall_send_bot', 'recall_list_sessions', 'recall_meeting_attendance'],
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
// ─── Agentic App Template (Next.js) ─────────────────────────────────────────
|
|
@@ -756,7 +756,7 @@ const TOOL_GROUPS = {
|
|
|
756
756
|
villages: ['village_search', 'village_view', 'village_create', 'village_update'],
|
|
757
757
|
moments: ['moment_create', 'moment_get', 'pulse_create', 'pulse_list'],
|
|
758
758
|
villagers: ['villager_me', 'villager_search', 'villager_update', 'agent_list'],
|
|
759
|
-
meetings: ['recall_send_bot', 'recall_meeting_attendance'],
|
|
759
|
+
meetings: ['recall_send_bot', 'recall_list_sessions', 'recall_meeting_attendance'],
|
|
760
760
|
};
|
|
761
761
|
|
|
762
762
|
// Tool groups selected during project creation
|