feat: add 100+ official TPMJS tools
Implements a comprehensive suite of AI SDK v6 tools across multiple categories: - Research (5): page-brief, compare-pages, source-credibility, claim-checklist, timeline-from-text - Web (10): fetch-text, links-catalog, extract-meta, extract-json-ld, redirect-trace, sitemap-read, rss-read, table-extract, robots-policy, url-normalize - Data (15): csv-parse, csv-stringify, json-repair, json-schema-validate, yaml-parse, yaml-stringify, text-chunk, normalize-whitespace, dedupe-by-key, pivot, rows-filter, rows-sort, rows-group-aggregate, rows-join, schema-infer - Doc (12): toc-generate, glossary-build, faq-from-text, executive-brief, decision-record-adr, prd-outline, acceptance-criteria, style-rewrite - Eng (12): diff-text-unified, env-var-docs-generate, dependency-audit-lite, conventional-commit-suggest, markdown-lint-basic, test-case-generate, stacktrace-parse, release-notes, changelog-entry, release-checklist - Security (7): redact-secrets, secret-scan-text, url-risk-heuristic, csp-compose, hardening-checklist-web, access-control-matrix, data-classification-heuristic - Stats (9): effect-size-suite, bootstrap-ci, permutation-test, multiple-testing-adjust, linear-regression-ols, logistic-regression, time-series-decompose-lite, anomaly-detect-mad - Ops (7): slo-draft, runbook-draft, postmortem-draft, postmortem-action-extractor, error-log-triage, coverage-tracker, monitoring-gap-analysis - Agent (15): prompt-to-workflow-skeleton, workflow-validate-io, workflow-explain, workflow-cost-estimate, tool-call-accuracy-score, eval-fixture-build, guardrail-policy-draft, workflow-auto-repair, tool-selection-plan, novelty-score-workflow, workflow-variant-generate, config-normalize, recipe-* - Utility (8): base64-encode, base64-decode, hash-text, regex-extract, template-render, date-parse, json-path-query, url-parse - HTML (3): html-sanitize, html-to-markdown, markdown-to-html All tools follow AI SDK v6 pattern with tool() and jsonSchema<T>(). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2d9b06020d
commit
5d2096fb5d
499 changed files with 50782 additions and 238 deletions
196
packages/tools/official/csv-stringify/README.md
Normal file
196
packages/tools/official/csv-stringify/README.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# @tpmjs/tools-csv-stringify
|
||||
|
||||
Convert array of objects to CSV string using [papaparse](https://www.papaparse.com/).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @tpmjs/tools-csv-stringify
|
||||
# or
|
||||
pnpm add @tpmjs/tools-csv-stringify
|
||||
# or
|
||||
yarn add @tpmjs/tools-csv-stringify
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### With Vercel AI SDK
|
||||
|
||||
```typescript
|
||||
import { csvStringifyTool } from '@tpmjs/tools-csv-stringify';
|
||||
import { generateText } from 'ai';
|
||||
|
||||
const result = await generateText({
|
||||
model: yourModel,
|
||||
tools: {
|
||||
csvStringify: csvStringifyTool,
|
||||
},
|
||||
prompt: 'Convert this data to CSV format: [{"name":"Alice","age":25},{"name":"Bob","age":30}]',
|
||||
});
|
||||
```
|
||||
|
||||
### Direct Usage
|
||||
|
||||
```typescript
|
||||
import { csvStringifyTool } from '@tpmjs/tools-csv-stringify';
|
||||
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [
|
||||
{ name: 'Alice', age: 25, city: 'New York' },
|
||||
{ name: 'Bob', age: 30, city: 'San Francisco' },
|
||||
{ name: 'Charlie', age: 35, city: 'Boston' },
|
||||
],
|
||||
});
|
||||
|
||||
console.log(result.csv);
|
||||
// name,age,city
|
||||
// Alice,25,New York
|
||||
// Bob,30,San Francisco
|
||||
// Charlie,35,Boston
|
||||
|
||||
console.log(result);
|
||||
// {
|
||||
// csv: '...',
|
||||
// rowCount: 3,
|
||||
// metadata: {
|
||||
// headers: ['name', 'age', 'city'],
|
||||
// stringifiedAt: '2025-01-15T12:00:00.000Z',
|
||||
// byteSize: 85
|
||||
// }
|
||||
// }
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Header Detection** - Uses object keys from first row if headers not provided
|
||||
- **Custom Headers** - Optionally specify custom header names and order
|
||||
- **Type Preservation** - Properly handles strings, numbers, booleans, and null values
|
||||
- **Standards Compliant** - Follows RFC 4180 CSV specification
|
||||
- **Byte Size Reporting** - Returns UTF-8 byte size for file writing
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| `rows` | `Record<string, unknown>[]` | Yes | - | Array of objects to convert to CSV |
|
||||
| `headers` | `string[]` | No | Object keys from first row | Custom header names |
|
||||
|
||||
## Returns
|
||||
|
||||
```typescript
|
||||
{
|
||||
csv: string;
|
||||
rowCount: number;
|
||||
metadata: {
|
||||
headers: string[];
|
||||
stringifiedAt: string;
|
||||
byteSize: number;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```typescript
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [
|
||||
{ product: 'Laptop', price: 999.99, inStock: true },
|
||||
{ product: 'Mouse', price: 29.99, inStock: false },
|
||||
],
|
||||
});
|
||||
|
||||
console.log(result.csv);
|
||||
// product,price,inStock
|
||||
// Laptop,999.99,true
|
||||
// Mouse,29.99,false
|
||||
```
|
||||
|
||||
### Custom Headers
|
||||
|
||||
```typescript
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [
|
||||
{ name: 'Alice', age: 25, city: 'NYC' },
|
||||
{ name: 'Bob', age: 30, city: 'SF' },
|
||||
],
|
||||
headers: ['name', 'city'], // Only include these columns
|
||||
});
|
||||
|
||||
console.log(result.csv);
|
||||
// name,city
|
||||
// Alice,NYC
|
||||
// Bob,SF
|
||||
```
|
||||
|
||||
### Custom Header Order
|
||||
|
||||
```typescript
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [
|
||||
{ age: 25, name: 'Alice', city: 'NYC' },
|
||||
{ age: 30, name: 'Bob', city: 'SF' },
|
||||
],
|
||||
headers: ['name', 'age', 'city'], // Specify order
|
||||
});
|
||||
|
||||
console.log(result.csv);
|
||||
// name,age,city
|
||||
// Alice,25,NYC
|
||||
// Bob,30,SF
|
||||
```
|
||||
|
||||
### Handling Special Characters
|
||||
|
||||
```typescript
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [
|
||||
{ name: 'Alice, Jr.', message: 'Hello "World"' },
|
||||
{ name: 'Bob\nSmith', message: 'Line\nBreak' },
|
||||
],
|
||||
});
|
||||
|
||||
// Properly escapes commas, quotes, and newlines
|
||||
console.log(result.csv);
|
||||
// name,message
|
||||
// "Alice, Jr.","Hello ""World"""
|
||||
// "Bob\nSmith","Line\nBreak"
|
||||
```
|
||||
|
||||
### Writing to File
|
||||
|
||||
```typescript
|
||||
import { writeFile } from 'fs/promises';
|
||||
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [...],
|
||||
});
|
||||
|
||||
await writeFile('output.csv', result.csv, 'utf-8');
|
||||
console.log(`Wrote ${result.metadata.byteSize} bytes to output.csv`);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: [],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error.message); // "Rows array cannot be empty"
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await csvStringifyTool.execute({
|
||||
rows: ['not', 'objects'], // Invalid
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error.message); // "All rows must be objects"
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
68
packages/tools/official/csv-stringify/package.json
Normal file
68
packages/tools/official/csv-stringify/package.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-csv-stringify",
|
||||
"version": "0.1.0",
|
||||
"description": "Convert array of objects to CSV string using papaparse",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "data", "csv", "stringify"],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": ["dist"],
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"dev": "tsup --watch",
|
||||
"type-check": "tsc --noEmit",
|
||||
"clean": "rm -rf dist .turbo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tpmjs/tsconfig": "workspace:*",
|
||||
"@types/papaparse": "^5.3.15",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/anthropics/tpmjs.git",
|
||||
"directory": "packages/tools/official/csv-stringify"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "data",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "csvStringifyTool",
|
||||
"description": "Convert array of objects to CSV string with optional custom headers",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "rows",
|
||||
"type": "array",
|
||||
"description": "Array of objects to convert to CSV",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "headers",
|
||||
"type": "array",
|
||||
"description": "Optional array of header names (default: uses object keys)",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "CsvStringifyResult",
|
||||
"description": "Object with csv string and rowCount"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"papaparse": "^5.4.1"
|
||||
}
|
||||
}
|
||||
124
packages/tools/official/csv-stringify/src/index.ts
Normal file
124
packages/tools/official/csv-stringify/src/index.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* CSV Stringify Tool for TPMJS
|
||||
* Converts array of objects to CSV string using papaparse
|
||||
*
|
||||
* @requires Node.js 18+
|
||||
*/
|
||||
|
||||
import { jsonSchema, tool } from 'ai';
|
||||
import Papa from 'papaparse';
|
||||
|
||||
/**
|
||||
* Output interface for CSV stringification
|
||||
*/
|
||||
export interface CsvStringifyResult {
|
||||
csv: string;
|
||||
rowCount: number;
|
||||
metadata: {
|
||||
headers: string[];
|
||||
stringifiedAt: string;
|
||||
byteSize: number;
|
||||
};
|
||||
}
|
||||
|
||||
type CsvStringifyInput = {
|
||||
rows: Record<string, unknown>[];
|
||||
headers?: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* CSV Stringify Tool
|
||||
* Converts array of objects to CSV format with optional custom headers
|
||||
*/
|
||||
export const csvStringifyTool = tool({
|
||||
description:
|
||||
'Convert an array of objects to CSV string format. Optionally specify custom headers. Returns the CSV string, row count, and metadata. Useful for exporting data to CSV files or API responses.',
|
||||
inputSchema: jsonSchema<CsvStringifyInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
rows: {
|
||||
type: 'array',
|
||||
description: 'Array of objects to convert to CSV',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
},
|
||||
},
|
||||
headers: {
|
||||
type: 'array',
|
||||
description:
|
||||
'Optional array of header names. If not provided, uses object keys from first row.',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['rows'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ rows, headers }): Promise<CsvStringifyResult> {
|
||||
// Validate input
|
||||
if (!rows || !Array.isArray(rows)) {
|
||||
throw new Error('Rows must be an array');
|
||||
}
|
||||
|
||||
if (rows.length === 0) {
|
||||
throw new Error('Rows array cannot be empty');
|
||||
}
|
||||
|
||||
// Validate that all rows are objects
|
||||
if (!rows.every((row) => typeof row === 'object' && row !== null && !Array.isArray(row))) {
|
||||
throw new Error('All rows must be objects (not arrays or primitives)');
|
||||
}
|
||||
|
||||
// Determine headers
|
||||
let actualHeaders: string[];
|
||||
if (headers && headers.length > 0) {
|
||||
// Validate custom headers
|
||||
if (!Array.isArray(headers)) {
|
||||
throw new Error('Headers must be an array of strings');
|
||||
}
|
||||
if (!headers.every((h) => typeof h === 'string')) {
|
||||
throw new Error('All headers must be strings');
|
||||
}
|
||||
actualHeaders = headers;
|
||||
} else {
|
||||
// Extract headers from first row
|
||||
const firstRow = rows[0];
|
||||
if (!firstRow) {
|
||||
throw new Error('Cannot determine headers from empty first row');
|
||||
}
|
||||
actualHeaders = Object.keys(firstRow);
|
||||
}
|
||||
|
||||
if (actualHeaders.length === 0) {
|
||||
throw new Error('No headers found. Either provide headers or ensure rows have properties.');
|
||||
}
|
||||
|
||||
// Convert to CSV using papaparse
|
||||
const csv = Papa.unparse(rows, {
|
||||
columns: actualHeaders,
|
||||
header: true,
|
||||
skipEmptyLines: false,
|
||||
newline: '\n',
|
||||
});
|
||||
|
||||
// Calculate byte size
|
||||
const byteSize = new TextEncoder().encode(csv).length;
|
||||
|
||||
// Build result
|
||||
const result: CsvStringifyResult = {
|
||||
csv,
|
||||
rowCount: rows.length,
|
||||
metadata: {
|
||||
headers: actualHeaders,
|
||||
stringifiedAt: new Date().toISOString(),
|
||||
byteSize,
|
||||
},
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
});
|
||||
|
||||
export default csvStringifyTool;
|
||||
11
packages/tools/official/csv-stringify/tsconfig.json
Normal file
11
packages/tools/official/csv-stringify/tsconfig.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"extends": "@tpmjs/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"incremental": false,
|
||||
"composite": false
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
10
packages/tools/official/csv-stringify/tsup.config.ts
Normal file
10
packages/tools/official/csv-stringify/tsup.config.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { defineConfig } from 'tsup';
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
format: ['esm'],
|
||||
dts: true,
|
||||
clean: true,
|
||||
treeshake: true,
|
||||
splitting: false,
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue