@xpert-ai/plugin-analytics-files 0.1.0 → 0.1.2

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # File Analytics
2
2
 
3
+ The Live Dashboard Agent generates this provider’s Definition through `analytics_definition_connections` → `analytics_definition_inspect` → `analytics_definition_register`. Existing toolset/Integration credentials stay in their original configuration entries. Settings → Analytics is for viewing, correction and version management; users do not fill internal IDs. See [the authoring guide](../../../../docs/analytics-providers.md#automatic-definition-generation).
3
4
  `@xpert-ai/plugin-analytics-files` provides `file.table`: declarative CSV, JSON and XLSX queries over platform-authorized Workspace files. Standard charts and HTML dashboards consume the same Dataset/Binding results.
4
5
 
5
- Administrators configure a `workspace-files` data source with approved file references, explicit format/read options, column types and business descriptions. Agent discovery returns the exact query contract and a bounded real preview; no new Agent middleware is required. File parsing, aggregation and format dependencies remain in this plugin. The platform owns file permissions, data-source authorization and Artifact lifecycle.
6
6
 
7
7
  - [Overview](docs/index.mdx) / [中文概览](docs/zh-Hans/index.mdx)
8
8
  - [Configuration and query contract](docs/configuration.mdx) / [中文配置](docs/zh-Hans/configuration.mdx)
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ const node_path_1 = require("node:path");
5
5
  const plugin_1 = require("./lib/plugin");
6
6
  const metadata = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, '../package.json'), 'utf8'));
7
7
  const plugin = {
8
- meta: { name: metadata.name, version: metadata.version, category: 'database', displayName: 'File Analytics',
8
+ meta: { name: metadata.name, version: metadata.version, category: 'tools', displayName: 'File Analytics',
9
9
  description: 'Declarative CSV, JSON and XLSX queries over authorized Workspace files', author: 'XpertAI',
10
10
  level: metadata.xpert.plugin.level, artifactNamespace: metadata.xpert.plugin.artifactNamespace },
11
11
  register: () => ({ module: plugin_1.AnalyticsFilesPlugin })
@@ -0,0 +1,2 @@
1
+ import { type AnalyticsDefinitionAuthoring } from '@xpert-ai/plugin-sdk';
2
+ export declare const fileAuthoring: AnalyticsDefinitionAuthoring;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fileAuthoring = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const v3_1 = require("zod/v3");
6
+ const schema_1 = require("./schema");
7
+ const worker_client_1 = require("./worker-client");
8
+ const inspectSchema = v3_1.z.object({ path: v3_1.z.string().min(1).max(1024).optional() }).strict();
9
+ const definitionSchema = schema_1.datasetSchema.innerType().omit({ id: true, revision: true, file: true }).extend({ path: v3_1.z.string().min(1).max(1024) }).strict();
10
+ async function resolve(path, context) {
11
+ if (context.connection.kind !== 'workspace-files')
12
+ throw new Error('ANALYTICS_CONNECTION_INVALID');
13
+ const reference = await context.files.resolveRuntimeReference(path);
14
+ const base = { catalog: reference.catalog, filePath: reference.filePath };
15
+ const file = schema_1.fileSchema.parse(reference.catalog === 'projects' ? { ...base, projectId: reference.projectId }
16
+ : reference.catalog === 'users' ? { ...base, userId: reference.userId }
17
+ : reference.catalog === 'user-xperts' ? { ...base, xpertId: reference.xpertId, userId: reference.userId }
18
+ : { ...base, xpertId: reference.xpertId });
19
+ const metadata = await context.files.resolveFile(reference);
20
+ if (!metadata.size || metadata.size > schema_1.MAX_BYTES)
21
+ throw new Error('FILE_DATASET_SIZE_LIMIT');
22
+ context.signal.throwIfAborted();
23
+ return { reference, file, size: metadata.size };
24
+ }
25
+ exports.fileAuthoring = {
26
+ inspectSchema: (0, schema_1.jsonSchema)(inspectSchema), definitionSchema: (0, schema_1.jsonSchema)(definitionSchema),
27
+ instructions: 'Use SandboxFile tools to list/read the current authorized workspace files. Select the exact runtime path, inspect CSV headers/JSON rows/XLSX sheet and documented business semantics, then generate reader and columns. Do not ask the user for internal file scope or IDs. Register validates the real file and mapping. Do not infer business meanings without evidence.',
28
+ async inspect(original, context) {
29
+ const input = inspectSchema.parse(original);
30
+ if (!input.path)
31
+ return { next: 'List/read authorized files with SandboxFile tools, then inspect with {path}.' };
32
+ const resolved = await resolve(input.path, context);
33
+ return { path: input.path, size: resolved.size, formats: ['csv', 'json', 'xlsx'] };
34
+ },
35
+ async prepare(original, context) {
36
+ const { path, ...input } = definitionSchema.parse(original);
37
+ const resolved = await resolve(path, context);
38
+ const options = schema_1.optionsSchema.parse({ datasets: [{ ...input, id: 'dataset', revision: 'initial', file: resolved.file }] });
39
+ const dataset = options.datasets[0], { buffer } = await context.files.readBuffer(resolved.reference);
40
+ if (!buffer.length || buffer.length > schema_1.MAX_BYTES)
41
+ throw new Error('FILE_DATASET_SIZE_LIMIT');
42
+ const payload = schema_1.payloadSchema.parse({ datasetId: dataset.id, revision: dataset.revision, contractHash: (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(dataset)).digest('hex'), select: dataset.columns.map(column => column.key) });
43
+ await (0, worker_client_1.queryWorker)(buffer, dataset, payload, {}, 5, context.signal, context.deadlineAt);
44
+ await resolve(path, context);
45
+ return options;
46
+ }
47
+ };
@@ -5,6 +5,62 @@ export declare const contractHash: (dataset: FileDataset) => string;
5
5
  export declare class FileAnalyticsProvider implements AnalyticsQueryProvider {
6
6
  private readonly runtime;
7
7
  readonly descriptor: AnalyticsProviderDescriptor;
8
+ readonly authoring: import("@xpert-ai/plugin-sdk").AnalyticsDefinitionAuthoring;
9
+ readonly configuration: {
10
+ kind: "definition";
11
+ connection: "workspace-files";
12
+ schema: Record<string, JSONValue>;
13
+ };
14
+ validateConfiguration(options: Record<string, JSONValue>): {
15
+ datasets: {
16
+ description: string;
17
+ id: string;
18
+ revision: string;
19
+ name: string;
20
+ file: {
21
+ catalog: "xperts";
22
+ xpertId: string;
23
+ filePath: string;
24
+ } | {
25
+ catalog: "user-xperts";
26
+ xpertId: string;
27
+ filePath: string;
28
+ userId: string;
29
+ } | {
30
+ catalog: "users";
31
+ filePath: string;
32
+ userId: string;
33
+ } | {
34
+ catalog: "projects";
35
+ filePath: string;
36
+ projectId: string;
37
+ };
38
+ reader: {
39
+ format: "csv";
40
+ delimiter: "," | ";" | "\t";
41
+ headerRow: number;
42
+ } | {
43
+ format: "json";
44
+ rowsPath: string[];
45
+ } | {
46
+ format: "xlsx";
47
+ headerRow: number;
48
+ sheet: string;
49
+ formulaPolicy: "reject" | "cached";
50
+ };
51
+ columns: {
52
+ path: string[];
53
+ key: string;
54
+ label: string;
55
+ description: string;
56
+ logicalType: "string" | "boolean" | "date" | "int64" | "decimal" | "float64" | "timestamp";
57
+ nullable: boolean;
58
+ role: "dimension" | "measure" | "time" | "identifier";
59
+ nullValues: string[];
60
+ unit?: string | undefined;
61
+ }[];
62
+ }[];
63
+ };
8
64
  constructor(runtime: RuntimeCapabilityRegistry);
9
65
  private check;
10
66
  private file;
@@ -13,6 +13,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.FileAnalyticsProvider = exports.contractHash = void 0;
16
+ const authoring_1 = require("./authoring");
16
17
  const common_1 = require("@nestjs/common");
17
18
  const node_crypto_1 = require("node:crypto");
18
19
  const plugin_sdk_1 = require("@xpert-ai/plugin-sdk");
@@ -26,13 +27,15 @@ const instructions = `Use an inspected dataset's bindingPayload and columns. Nev
26
27
  const queryContract = { operation: 'query', contractVersion: 1,
27
28
  payloadSchema: (0, schema_1.jsonSchema)(schema_1.payloadSchema), instructions: instructions + ' metadata.binding is a complete canonical Binding; bindingPayload alone is only its payload, not a Binding. Start from metadata.binding and preserve its envelope. Raw rows do not promise uniqueness; keep grain:[] unless verified, or group first and declare the grouping field IDs as grain.' };
28
29
  let FileAnalyticsProvider = class FileAnalyticsProvider {
30
+ validateConfiguration(options) { return schema_1.optionsSchema.parse(options); }
29
31
  constructor(runtime) {
30
32
  this.runtime = runtime;
31
33
  this.descriptor = {
32
- id: schema_1.PROVIDER, name: 'Workspace files (CSV / JSON / XLSX)', dataSourceTypes: ['workspace-files'],
33
- operations: [{ name: 'query', contractVersion: 1, readOnly: true }],
34
- connectionType: { type: 'workspace-files', name: 'Workspace files', configuration: (0, schema_1.jsonSchema)(schema_1.optionsSchema) }
34
+ id: schema_1.PROVIDER, name: 'Workspace files (CSV / JSON / XLSX)', sourceKinds: ['definition'],
35
+ operations: [{ name: 'query', contractVersion: 1, readOnly: true }]
35
36
  };
37
+ this.authoring = authoring_1.fileAuthoring;
38
+ this.configuration = { kind: 'definition', connection: 'workspace-files', schema: (0, schema_1.jsonSchema)(schema_1.optionsSchema) };
36
39
  }
37
40
  check(context) {
38
41
  context.signal.throwIfAborted();
@@ -101,7 +104,7 @@ let FileAnalyticsProvider = class FileAnalyticsProvider {
101
104
  const read = await this.read(definition, context);
102
105
  const preview = await (0, worker_client_1.queryWorker)(read.buffer, definition, payload, {}, 5, context.signal, context.deadlineAt);
103
106
  await this.file(definition, context);
104
- const binding = { schemaVersion: 1, id: definition.id, dataSourceId: context.dataSourceId,
107
+ const binding = { source: context.source, id: definition.id,
105
108
  providerId: schema_1.PROVIDER, operation: 'query', contractVersion: 1, payload: JSON.parse(JSON.stringify(payload)), parameters: [],
106
109
  output: { datasetId: definition.id, grain: [], fields: definition.columns.map(({ key, path, description, nullValues, ...field }) => ({ ...field, id: key, sourceField: key })) } };
107
110
  const previewFits = Buffer.byteLength(JSON.stringify(preview.rows)) <= 32000;
@@ -115,7 +118,7 @@ let FileAnalyticsProvider = class FileAnalyticsProvider {
115
118
  }
116
119
  items.push({ id: definition.id, name: definition.name, description: definition.description, kind: 'dataset', inspectRequest: { datasetId: definition.id }, metadata });
117
120
  }
118
- return { schemaVersion: 1, queryContract, items,
121
+ return { queryContract, items,
119
122
  ...(!input.datasetId && input.page * 20 < datasets.length ? { nextRequest: { page: input.page + 1 } } : {}) };
120
123
  });
121
124
  }
@@ -2,7 +2,7 @@ import type { AnalyticsBinding, AnalyticsValue } from '@xpert-ai/contracts';
2
2
  import type { Column, FileDataset, FileQuery } from './schema';
3
3
  export type Row = Record<string, AnalyticsValue>;
4
4
  export declare function outputColumns(definition: FileDataset, query: FileQuery): Column[];
5
- export declare function validateOutput(binding: AnalyticsBinding, columns: Column[]): void;
5
+ export declare function validateOutput(binding: Pick<AnalyticsBinding, 'output'>, columns: Column[]): void;
6
6
  export declare function executeQuery(rows: Row[], definition: FileDataset, query: FileQuery, parameters: Row, maxRows: number): {
7
7
  columns: {
8
8
  key: string;
@@ -45,7 +45,7 @@ exports.datasetSchema = v3_1.z.object({
45
45
  if (Buffer.byteLength(JSON.stringify(dataset)) > 48000)
46
46
  ctx.addIssue({ code: 'custom', message: 'Dataset exceeds discovery metadata budget' });
47
47
  });
48
- exports.optionsSchema = v3_1.z.object({ datasets: v3_1.z.array(exports.datasetSchema).min(1).max(100) }).strict()
48
+ exports.optionsSchema = v3_1.z.object({ datasets: v3_1.z.array(exports.datasetSchema).length(1) }).strict()
49
49
  .refine(value => new Set(value.datasets.map(d => d.id)).size === value.datasets.length, 'Duplicate dataset ID');
50
50
  const operand = v3_1.z.discriminatedUnion('type', [
51
51
  v3_1.z.object({ type: v3_1.z.literal('literal'), value: exports.scalar }).strict(),
@@ -3,7 +3,7 @@ title: 'Configuration and queries'
3
3
  description: 'Approved files, explicit column semantics and declarative queries.'
4
4
  ---
5
5
 
6
- Create a platform data source of type `workspace-files`. Configure `datasets` using the packaged `examples/sales.json` catalog. Replace the example Assistant ID with a published Assistant you can access. Upload the file through the platform Files UI/API. Paths are Volume-relative, never local host paths.
6
+ Open Settings → Analytics → Workspace files and create a Definition with exactly one dataset. Configure `datasets` using the packaged `examples/sales.json` catalog. Replace the example Assistant ID with a published Assistant you can access. Upload the file through the platform Files UI/API. Paths are Volume-relative, never local host paths.
7
7
 
8
8
  Each dataset has `id`, `revision`, `name`, `description`, `file`, `reader` and `columns`.
9
9
 
@@ -3,7 +3,7 @@ title: '配置与查询'
3
3
  description: '受控文件目录、字段口径和声明式查询。'
4
4
  ---
5
5
 
6
- 安装插件后创建类型为 `workspace-files` 的平台数据源,按包内 `examples/sales.json` 配置 `datasets`。示例 Assistant ID 需要替换为有权访问的已发布 Assistant;通过平台 Files 上传源文件。路径为 Volume 内相对路径,不能使用本机绝对路径。
6
+ 安装插件后在「设置 → 分析定义 → Workspace files」创建 Definition,每个定义配置一个数据集,按包内 `examples/sales.json` 配置 `datasets`。示例 Assistant ID 需要替换为有权访问的已发布 Assistant;通过平台 Files 上传源文件。路径为 Volume 内相对路径,不能使用本机绝对路径。
7
7
 
8
8
  每个数据集包含 `id/revision/name/description/file/reader/columns`。`file.catalog` 支持共享 Assistant `xperts`、用户隔离 Assistant `user-xperts`、用户文件 `users` 和项目 `projects`。用户目录必须匹配当前访问者;项目需要有效成员权限,Assistant 文件检查准确的已发布 Assistant 授权。租户和组织由平台提供。
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpert-ai/plugin-analytics-files",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Declarative CSV, JSON and XLSX analytics over authorized Workspace files",
5
5
  "main": "./index.cjs",
6
6
  "types": "./dist/index.d.ts",
@@ -28,15 +28,15 @@
28
28
  }
29
29
  },
30
30
  "peerDependencies": {
31
- "@xpert-ai/plugin-sdk": "^3.25.0",
32
- "@xpert-ai/contracts": "^3.25.0",
31
+ "@xpert-ai/plugin-sdk": "^3.26.1",
32
+ "@xpert-ai/contracts": "^3.26.1",
33
33
  "@nestjs/common": "^11.1.6",
34
34
  "@nestjs/core": "^11.1.6",
35
35
  "zod": "3.25.67"
36
36
  },
37
37
  "devDependencies": {
38
- "@xpert-ai/plugin-sdk": "3.25.0",
39
- "@xpert-ai/contracts": "3.25.0",
38
+ "@xpert-ai/plugin-sdk": "3.26.1",
39
+ "@xpert-ai/contracts": "3.26.1",
40
40
  "@nestjs/common": "^11.1.6",
41
41
  "@nestjs/core": "^11.1.6",
42
42
  "zod": "3.25.67",