feat: add 5 research tools and blocks framework setup
- Add @tpmjs/tools-page-brief for URL content extraction - Add @tpmjs/tools-compare-pages for cross-source validation - Add @tpmjs/tools-source-credibility for credibility scoring - Add @tpmjs/tools-claim-checklist for factual claim extraction - Add @tpmjs/tools-timeline-from-text for timeline generation - Move createBlogPost to packages/tools/official/ - Add blocks.yml for Blocks framework validation - Update pnpm-workspace.yaml to include official tools
This commit is contained in:
parent
409d1232a6
commit
36a0735ab1
34 changed files with 2458 additions and 61 deletions
21
.changeset/add-research-tools.md
Normal file
21
.changeset/add-research-tools.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
"@tpmjs/tools-page-brief": minor
|
||||
"@tpmjs/tools-compare-pages": minor
|
||||
"@tpmjs/tools-source-credibility": minor
|
||||
"@tpmjs/tools-claim-checklist": minor
|
||||
"@tpmjs/tools-timeline-from-text": minor
|
||||
---
|
||||
|
||||
Add 5 new research tools for AI-powered content analysis
|
||||
|
||||
New tools using AI SDK v6 beta (tool() + jsonSchema() pattern):
|
||||
|
||||
- **@tpmjs/tools-page-brief**: Fetch URL and extract summary with key points and claims needing citations
|
||||
- **@tpmjs/tools-compare-pages**: Compare two URLs for agreements, conflicts, and unique points
|
||||
- **@tpmjs/tools-source-credibility**: Calculate heuristic credibility score based on domain signals
|
||||
- **@tpmjs/tools-claim-checklist**: Extract checkable factual claims from text
|
||||
- **@tpmjs/tools-timeline-from-text**: Extract dated events and return normalized timeline
|
||||
|
||||
All tools are stub implementations ready for full logic implementation.
|
||||
|
||||
Also moved @tpmjs/createblogpost to packages/tools/official/ directory and set up blocks.yml for Blocks framework validation.
|
||||
21
docs/TODO.md
21
docs/TODO.md
|
|
@ -130,6 +130,27 @@ GET /api/users/[username]/collections - Get user's public collections
|
|||
|
||||
---
|
||||
|
||||
## Benchmark Comparison Page
|
||||
|
||||
### Overview
|
||||
- [ ] Create `/benchmarks` page to compare tool performance
|
||||
- [ ] Display execution time comparisons across similar tools
|
||||
- [ ] Show token usage efficiency metrics
|
||||
- [ ] Compare success rates and reliability
|
||||
|
||||
### Features
|
||||
- [ ] Side-by-side tool comparison UI
|
||||
- [ ] Historical performance trends (charts)
|
||||
- [ ] Filter by category to compare relevant tools
|
||||
- [ ] Export benchmark data as JSON/CSV
|
||||
|
||||
### Data Collection
|
||||
- [ ] Track execution metrics from playground simulations
|
||||
- [ ] Aggregate anonymous performance data
|
||||
- [ ] Calculate percentile rankings within categories
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Consider rate limiting on ratings to prevent abuse
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@blocksai/cli": "^0.2.1",
|
||||
"@blocksai/validators": "^1.1.1",
|
||||
"@changesets/cli": "^2.27.10",
|
||||
"@total-typescript/ts-reset": "^0.6.1",
|
||||
"@types/node": "^22.10.2",
|
||||
|
|
|
|||
3
packages/tools/official/.gitignore
vendored
Normal file
3
packages/tools/official/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Blocks CLI runtime files
|
||||
.blocks/
|
||||
.env
|
||||
168
packages/tools/official/BLOCKS_DOMAIN_VALIDATOR_BUG.md
Normal file
168
packages/tools/official/BLOCKS_DOMAIN_VALIDATOR_BUG.md
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# Blocks Domain Validator Bug Report
|
||||
|
||||
## Status: FIXED
|
||||
|
||||
The fix has been applied to `/Users/ajaxdavis/repos/blocks/packages/ai/src/provider.ts`.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The domain validator in `@blocksai/validators` was failing with an OpenAI structured output schema error when validating any block. The schema and shape.ts validators worked correctly.
|
||||
|
||||
## Error Message
|
||||
|
||||
```
|
||||
⚠ [domain] AI validation failed: Invalid schema for response_format 'response':
|
||||
In context=('properties', 'issues', 'items'), 'required' is required to be supplied
|
||||
and to be an array including every key in properties. Missing 'file'.
|
||||
```
|
||||
|
||||
## Environment
|
||||
|
||||
- `@blocksai/cli`: latest (installed via npx)
|
||||
- `@blocksai/validators`: latest
|
||||
- OpenAI API: Using `OPENAI_API_KEY` from .env
|
||||
- Node.js: v22.x
|
||||
- OS: macOS
|
||||
|
||||
## Reproduction Steps
|
||||
|
||||
1. Create a valid `blocks.yml` with any block definition
|
||||
2. Create the corresponding TypeScript file with proper exports
|
||||
3. Run `npx blocks run --all`
|
||||
|
||||
## Example blocks.yml
|
||||
|
||||
```yaml
|
||||
name: "tpmjs-official-tools"
|
||||
root: "."
|
||||
|
||||
philosophy:
|
||||
- "Tools must be pure functions with no side effects"
|
||||
|
||||
domain:
|
||||
entities:
|
||||
url:
|
||||
fields: [href, domain, protocol, path]
|
||||
|
||||
signals:
|
||||
credibility:
|
||||
description: "Trustworthiness of a source"
|
||||
|
||||
measures:
|
||||
valid_output:
|
||||
constraints:
|
||||
- "Must return structured object matching interface"
|
||||
|
||||
blocks:
|
||||
domain_rules:
|
||||
- id: pure_function
|
||||
description: "Tool must be deterministic with no side effects"
|
||||
|
||||
research.pageBrief:
|
||||
description: "Fetch URL and extract content"
|
||||
path: "page-brief"
|
||||
inputs:
|
||||
- name: url
|
||||
type: string
|
||||
outputs:
|
||||
- name: brief
|
||||
type: PageBrief
|
||||
measures: [valid_output]
|
||||
|
||||
validators:
|
||||
- schema
|
||||
- shape.ts
|
||||
- domain
|
||||
```
|
||||
|
||||
## Observed Behavior
|
||||
|
||||
```
|
||||
📦 Validating: research.pageBrief
|
||||
✓ schema ok
|
||||
✓ shape.ts ok
|
||||
- Running domain...
|
||||
⚠ [domain] AI validation failed: Invalid schema for response_format 'response':
|
||||
In context=('properties', 'issues', 'items'), 'required' is required to be
|
||||
supplied and to be an array including every key in properties. Missing 'file'.
|
||||
|
||||
⚠️ Block "research.pageBrief" has warnings
|
||||
```
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
The error message indicates that the domain validator is constructing an OpenAI structured output request with a JSON schema that's missing required fields. Specifically:
|
||||
|
||||
1. OpenAI's structured output feature requires that all properties in an object schema must be listed in the `required` array
|
||||
2. The domain validator's internal response schema has a `file` property in the `issues.items` object
|
||||
3. This `file` property is not included in the corresponding `required` array
|
||||
|
||||
This is an internal schema construction issue within the domain validator, not related to user-provided blocks.yml configuration.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
The domain validator should:
|
||||
1. Construct a valid JSON schema for OpenAI's structured output API
|
||||
2. Ensure all properties are listed in `required` arrays
|
||||
3. Successfully analyze the block against the domain rules and philosophy
|
||||
|
||||
## Workaround
|
||||
|
||||
Currently, the schema and shape.ts validators work correctly. The domain validator can be skipped by removing `domain` from the validators list in blocks.yml:
|
||||
|
||||
```yaml
|
||||
validators:
|
||||
- schema
|
||||
- shape.ts
|
||||
# - domain # Disabled due to bug
|
||||
```
|
||||
|
||||
## Fix Applied
|
||||
|
||||
**File:** `/Users/ajaxdavis/repos/blocks/packages/ai/src/provider.ts` (lines 163-173)
|
||||
|
||||
**Before (broken):**
|
||||
```typescript
|
||||
const schema = z.object({
|
||||
isValid: z.boolean(),
|
||||
issues: z.array(
|
||||
z.object({
|
||||
message: z.string(),
|
||||
severity: z.enum(["error", "warning"]),
|
||||
file: z.string().optional(), // ← Problem: .optional() excludes from required
|
||||
})
|
||||
),
|
||||
summary: z.string().optional().describe("..."),
|
||||
});
|
||||
```
|
||||
|
||||
**After (fixed):**
|
||||
```typescript
|
||||
const schema = z.object({
|
||||
isValid: z.boolean(),
|
||||
issues: z.array(
|
||||
z.object({
|
||||
message: z.string().describe("Description of the issue found"),
|
||||
severity: z.enum(["error", "warning"]).describe("Severity of the issue"),
|
||||
file: z.string().describe("File path where the issue was found, or empty string if not file-specific"),
|
||||
})
|
||||
),
|
||||
summary: z.string().describe("Brief summary of why the block passed or failed validation"),
|
||||
});
|
||||
```
|
||||
|
||||
**Root Cause:** OpenAI's structured output requires ALL properties to be in the JSON schema's `required` array. When Zod converts `.optional()` to JSON schema, it omits that property from `required`, causing OpenAI to reject the schema.
|
||||
|
||||
**Solution:** Remove `.optional()` and `.default()` modifiers. Make all fields required strings. The AI will return an empty string for file-agnostic issues.
|
||||
|
||||
## Impact
|
||||
|
||||
- **Severity**: Medium - domain validation is non-functional
|
||||
- **Affected**: All blocks using the domain validator
|
||||
- **Workaround available**: Yes - disable domain validator
|
||||
|
||||
## Additional Context
|
||||
|
||||
This was tested with 6 different blocks, all showing the same error. The error is consistent and reproducible regardless of block configuration.
|
||||
132
packages/tools/official/blocks.yml
Normal file
132
packages/tools/official/blocks.yml
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
name: "tpmjs-official-tools"
|
||||
root: "."
|
||||
|
||||
philosophy:
|
||||
- "Tools must be pure functions with no side effects"
|
||||
- "Each tool solves one specific problem well"
|
||||
- "Tools are publishable to npm as @tpmjs/* packages"
|
||||
- "Use AI SDK v6 tool() + jsonSchema() pattern"
|
||||
|
||||
domain:
|
||||
entities:
|
||||
url:
|
||||
fields: [href, domain, protocol, path]
|
||||
text:
|
||||
fields: [content, sentences, wordCount]
|
||||
claim:
|
||||
fields: [statement, needsCitation, evidence]
|
||||
timeline_event:
|
||||
fields: [date, description, confidence]
|
||||
|
||||
signals:
|
||||
credibility:
|
||||
description: "Trustworthiness of a source"
|
||||
extraction_hint: "Look for author, date, citations, HTTPS"
|
||||
readability:
|
||||
description: "How easy content is to understand"
|
||||
extraction_hint: "Check sentence length, jargon, structure"
|
||||
|
||||
measures:
|
||||
valid_output:
|
||||
constraints:
|
||||
- "Must return structured object matching interface"
|
||||
- "Must not throw unhandled errors"
|
||||
npm_publishable:
|
||||
constraints:
|
||||
- "Must have valid package.json with tpmjs field"
|
||||
- "Must export tool as named and default export"
|
||||
|
||||
blocks:
|
||||
domain_rules:
|
||||
- id: pure_function
|
||||
description: "Tool must be deterministic with no side effects"
|
||||
- id: ai_sdk_pattern
|
||||
description: "Must use AI SDK v6 tool() + jsonSchema()"
|
||||
- id: npm_ready
|
||||
description: "Must be publishable to npm with complete metadata"
|
||||
|
||||
adapter.createBlogPost:
|
||||
description: "Creates structured blog posts with frontmatter and metadata"
|
||||
path: "createBlogPost"
|
||||
inputs:
|
||||
- name: title
|
||||
type: string
|
||||
- name: author
|
||||
type: string
|
||||
- name: content
|
||||
type: string
|
||||
- name: tags
|
||||
type: string[]
|
||||
optional: true
|
||||
- name: format
|
||||
type: "'markdown' | 'mdx'"
|
||||
optional: true
|
||||
outputs:
|
||||
- name: blogPost
|
||||
type: BlogPost
|
||||
measures: [valid_output, npm_publishable]
|
||||
|
||||
research.pageBrief:
|
||||
description: "Fetch URL, extract main content, return summary with key points and claims needing citations"
|
||||
path: "page-brief"
|
||||
inputs:
|
||||
- name: url
|
||||
type: string
|
||||
outputs:
|
||||
- name: brief
|
||||
type: PageBrief
|
||||
measures: [valid_output]
|
||||
|
||||
research.comparePages:
|
||||
description: "Compare two URLs for agreements, conflicts, and unique points"
|
||||
path: "compare-pages"
|
||||
inputs:
|
||||
- name: urlA
|
||||
type: string
|
||||
- name: urlB
|
||||
type: string
|
||||
outputs:
|
||||
- name: comparison
|
||||
type: PageComparison
|
||||
measures: [valid_output]
|
||||
|
||||
research.sourceCredibility:
|
||||
description: "Heuristic credibility score based on domain signals, author presence, citations"
|
||||
path: "source-credibility"
|
||||
inputs:
|
||||
- name: url
|
||||
type: string
|
||||
- name: html
|
||||
type: string
|
||||
optional: true
|
||||
outputs:
|
||||
- name: credibility
|
||||
type: CredibilityScore
|
||||
measures: [valid_output]
|
||||
|
||||
research.claimChecklist:
|
||||
description: "Extract checkable factual claims from text, mark what needs citations"
|
||||
path: "claim-checklist"
|
||||
inputs:
|
||||
- name: text
|
||||
type: string
|
||||
outputs:
|
||||
- name: checklist
|
||||
type: ClaimChecklist
|
||||
measures: [valid_output]
|
||||
|
||||
research.timelineFromText:
|
||||
description: "Extract dated events from text, return normalized timeline with confidence"
|
||||
path: "timeline-from-text"
|
||||
inputs:
|
||||
- name: text
|
||||
type: string
|
||||
outputs:
|
||||
- name: timeline
|
||||
type: Timeline
|
||||
measures: [valid_output]
|
||||
|
||||
validators:
|
||||
- schema
|
||||
- shape.ts
|
||||
- domain
|
||||
61
packages/tools/official/claim-checklist/package.json
Normal file
61
packages/tools/official/claim-checklist/package.json
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-claim-checklist",
|
||||
"version": "0.1.0",
|
||||
"description": "Extract checkable factual claims from text and identify what needs citations",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "research", "ai", "claims", "fact-checking", "citations"],
|
||||
"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:*",
|
||||
"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/claim-checklist"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "research",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "claimChecklistTool",
|
||||
"description": "Extract checkable factual claims from text and mark what needs citations",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
"type": "string",
|
||||
"description": "The text to analyze for factual claims",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "ClaimChecklist",
|
||||
"description": "Object with claims array and summary statistics"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"sbd": "^1.0.19"
|
||||
}
|
||||
}
|
||||
56
packages/tools/official/claim-checklist/src/index.ts
Normal file
56
packages/tools/official/claim-checklist/src/index.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface ClaimChecklist {
|
||||
originalText: string;
|
||||
claims: Array<{
|
||||
claim: string;
|
||||
needsCitation: boolean;
|
||||
evidenceType: 'statistic' | 'fact' | 'quote' | 'opinion' | 'common-knowledge';
|
||||
suggestedEvidence: string;
|
||||
sentenceIndex: number;
|
||||
}>;
|
||||
summary: {
|
||||
totalClaims: number;
|
||||
needingCitation: number;
|
||||
verified: number;
|
||||
};
|
||||
}
|
||||
|
||||
type ClaimChecklistInput = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export const claimChecklistTool = tool({
|
||||
description:
|
||||
'Extract checkable factual claims from text, mark what needs citations, and suggest what evidence would support each claim',
|
||||
inputSchema: jsonSchema<ClaimChecklistInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
text: {
|
||||
type: 'string',
|
||||
description: 'The text to analyze for factual claims',
|
||||
},
|
||||
},
|
||||
required: ['text'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ text }): Promise<ClaimChecklist> {
|
||||
// TODO: Implement with:
|
||||
// 1. Split text into sentences with sbd
|
||||
// 2. Rule-based claim extraction (numbers, dates, proper nouns)
|
||||
// 3. Classify claim types
|
||||
// 4. Determine if citation needed based on type
|
||||
|
||||
return {
|
||||
originalText: text,
|
||||
claims: [],
|
||||
summary: {
|
||||
totalClaims: 0,
|
||||
needingCitation: 0,
|
||||
verified: 0,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default claimChecklistTool;
|
||||
67
packages/tools/official/compare-pages/package.json
Normal file
67
packages/tools/official/compare-pages/package.json
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-compare-pages",
|
||||
"version": "0.1.0",
|
||||
"description": "Compare two URLs for agreements, conflicts, and unique points for cross-source validation",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "research", "ai", "comparison", "fact-checking"],
|
||||
"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:*",
|
||||
"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/compare-pages"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "research",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "comparePagesTool",
|
||||
"description": "Compare two URLs for agreements, conflicts, and unique points",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "urlA",
|
||||
"type": "string",
|
||||
"description": "First URL to compare",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "urlB",
|
||||
"type": "string",
|
||||
"description": "Second URL to compare",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "PageComparison",
|
||||
"description": "Object with agreements, conflicts, uniqueToA, and uniqueToB arrays"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"natural": "^8.0.0"
|
||||
}
|
||||
}
|
||||
57
packages/tools/official/compare-pages/src/index.ts
Normal file
57
packages/tools/official/compare-pages/src/index.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface PageComparison {
|
||||
urlA: string;
|
||||
urlB: string;
|
||||
agreements: string[];
|
||||
conflicts: Array<{
|
||||
topic: string;
|
||||
pageAPosition: string;
|
||||
pageBPosition: string;
|
||||
}>;
|
||||
uniqueToA: string[];
|
||||
uniqueToB: string[];
|
||||
}
|
||||
|
||||
type ComparePagesInput = {
|
||||
urlA: string;
|
||||
urlB: string;
|
||||
};
|
||||
|
||||
export const comparePagesTool = tool({
|
||||
description:
|
||||
'Compare two URLs for agreements, conflicts, and unique points to help with cross-source validation',
|
||||
inputSchema: jsonSchema<ComparePagesInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
urlA: {
|
||||
type: 'string',
|
||||
description: 'First URL to compare',
|
||||
},
|
||||
urlB: {
|
||||
type: 'string',
|
||||
description: 'Second URL to compare',
|
||||
},
|
||||
},
|
||||
required: ['urlA', 'urlB'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ urlA, urlB }): Promise<PageComparison> {
|
||||
// TODO: Implement with:
|
||||
// 1. Call pageBriefTool on both URLs
|
||||
// 2. Extract key points from both
|
||||
// 3. Use TF-IDF (natural) for semantic matching
|
||||
// 4. Identify agreements, conflicts, and unique points
|
||||
|
||||
return {
|
||||
urlA,
|
||||
urlB,
|
||||
agreements: [],
|
||||
conflicts: [],
|
||||
uniqueToA: [],
|
||||
uniqueToB: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default comparePagesTool;
|
||||
11
packages/tools/official/compare-pages/tsconfig.json
Normal file
11
packages/tools/official/compare-pages/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/compare-pages/tsup.config.ts
Normal file
10
packages/tools/official/compare-pages/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,
|
||||
});
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ajaxdavis/tpmjs.git",
|
||||
"directory": "packages/tools/createBlogPost"
|
||||
"directory": "packages/tools/official/createBlogPost"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
11
packages/tools/official/createBlogPost/tsconfig.json
Normal file
11
packages/tools/official/createBlogPost/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/createBlogPost/tsup.config.ts
Normal file
10
packages/tools/official/createBlogPost/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,
|
||||
});
|
||||
63
packages/tools/official/page-brief/package.json
Normal file
63
packages/tools/official/page-brief/package.json
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-page-brief",
|
||||
"version": "0.1.0",
|
||||
"description": "Fetch a URL, extract main content, and return a brief with summary, key points, and claims needing citations",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "research", "ai", "readability", "web-scraping"],
|
||||
"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:*",
|
||||
"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/page-brief"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "research",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "pageBriefTool",
|
||||
"description": "Fetch a URL, extract main content, and return a brief with summary, key points, and claims needing citations",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"description": "The URL to fetch and analyze",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "PageBrief",
|
||||
"description": "Object with url, title, summary, keyPoints array, and claimsNeedingCitation array"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"sbd": "^1.0.19"
|
||||
}
|
||||
}
|
||||
50
packages/tools/official/page-brief/src/index.ts
Normal file
50
packages/tools/official/page-brief/src/index.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface PageBrief {
|
||||
url: string;
|
||||
title: string;
|
||||
summary: string;
|
||||
keyPoints: string[];
|
||||
claimsNeedingCitation: Array<{
|
||||
claim: string;
|
||||
suggestedEvidence: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
type PageBriefInput = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const pageBriefTool = tool({
|
||||
description:
|
||||
'Fetch a URL, extract main content using readability, and return a brief with summary, key points, and claims that need citations',
|
||||
inputSchema: jsonSchema<PageBriefInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'The URL to fetch and analyze',
|
||||
},
|
||||
},
|
||||
required: ['url'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ url }): Promise<PageBrief> {
|
||||
// TODO: Implement with fetch + @mozilla/readability + jsdom + sbd
|
||||
// 1. Fetch the URL
|
||||
// 2. Parse HTML with jsdom
|
||||
// 3. Extract main content with Readability
|
||||
// 4. Split into sentences with sbd
|
||||
// 5. Identify claims that need citations
|
||||
|
||||
return {
|
||||
url,
|
||||
title: 'Not implemented',
|
||||
summary: 'This is a stub implementation. Real implementation will use @mozilla/readability.',
|
||||
keyPoints: [],
|
||||
claimsNeedingCitation: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default pageBriefTool;
|
||||
11
packages/tools/official/page-brief/tsconfig.json
Normal file
11
packages/tools/official/page-brief/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/page-brief/tsup.config.ts
Normal file
10
packages/tools/official/page-brief/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,
|
||||
});
|
||||
68
packages/tools/official/source-credibility/package.json
Normal file
68
packages/tools/official/source-credibility/package.json
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-source-credibility",
|
||||
"version": "0.1.0",
|
||||
"description": "Calculate heuristic credibility score based on domain signals, author presence, and citations",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "research", "ai", "credibility", "fact-checking"],
|
||||
"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:*",
|
||||
"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/source-credibility"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "research",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "sourceCredibilityTool",
|
||||
"description": "Calculate heuristic credibility score based on domain signals",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"type": "string",
|
||||
"description": "URL to analyze for credibility",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "html",
|
||||
"type": "string",
|
||||
"description": "Optional pre-fetched HTML content",
|
||||
"required": false
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "CredibilityScore",
|
||||
"description": "Object with score (0-1), signals breakdown, and detailed analysis"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"tldts": "^6.1.0",
|
||||
"cheerio": "^1.0.0"
|
||||
}
|
||||
}
|
||||
75
packages/tools/official/source-credibility/src/index.ts
Normal file
75
packages/tools/official/source-credibility/src/index.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface CredibilityScore {
|
||||
url: string;
|
||||
score: number; // 0.0 to 1.0
|
||||
signals: {
|
||||
hasHttps: boolean;
|
||||
hasAuthor: boolean;
|
||||
hasPublishDate: boolean;
|
||||
hasCitations: boolean;
|
||||
domainAge?: string;
|
||||
isKnownSource: boolean;
|
||||
};
|
||||
breakdown: Array<{
|
||||
signal: string;
|
||||
weight: number;
|
||||
present: boolean;
|
||||
}>;
|
||||
}
|
||||
|
||||
type SourceCredibilityInput = {
|
||||
url: string;
|
||||
html?: string;
|
||||
};
|
||||
|
||||
export const sourceCredibilityTool = tool({
|
||||
description:
|
||||
'Calculate a heuristic credibility score based on domain signals, author presence, date, citations density, and HTTPS',
|
||||
inputSchema: jsonSchema<SourceCredibilityInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'URL to analyze for credibility',
|
||||
},
|
||||
html: {
|
||||
type: 'string',
|
||||
description: 'Optional: pre-fetched HTML content to analyze',
|
||||
},
|
||||
},
|
||||
required: ['url'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ url, html: _html }): Promise<CredibilityScore> {
|
||||
// TODO: Implement with:
|
||||
// 1. Parse URL with tldts for domain info
|
||||
// 2. If no HTML provided, fetch the page
|
||||
// 3. Parse HTML with cheerio for meta signals
|
||||
// 4. Check for author, date, citations
|
||||
// 5. Calculate weighted score
|
||||
|
||||
const isHttps = url.startsWith('https://');
|
||||
|
||||
return {
|
||||
url,
|
||||
score: 0.5, // Stub score
|
||||
signals: {
|
||||
hasHttps: isHttps,
|
||||
hasAuthor: false,
|
||||
hasPublishDate: false,
|
||||
hasCitations: false,
|
||||
isKnownSource: false,
|
||||
},
|
||||
breakdown: [
|
||||
{ signal: 'https', weight: 0.1, present: isHttps },
|
||||
{ signal: 'author', weight: 0.2, present: false },
|
||||
{ signal: 'publishDate', weight: 0.2, present: false },
|
||||
{ signal: 'citations', weight: 0.3, present: false },
|
||||
{ signal: 'knownSource', weight: 0.2, present: false },
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default sourceCredibilityTool;
|
||||
11
packages/tools/official/source-credibility/tsconfig.json
Normal file
11
packages/tools/official/source-credibility/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/source-credibility/tsup.config.ts
Normal file
10
packages/tools/official/source-credibility/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,
|
||||
});
|
||||
62
packages/tools/official/timeline-from-text/package.json
Normal file
62
packages/tools/official/timeline-from-text/package.json
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"name": "@tpmjs/tools-timeline-from-text",
|
||||
"version": "0.1.0",
|
||||
"description": "Extract dated events from text and return a normalized timeline with confidence scores",
|
||||
"type": "module",
|
||||
"keywords": ["tpmjs", "research", "ai", "timeline", "dates", "events"],
|
||||
"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:*",
|
||||
"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/timeline-from-text"
|
||||
},
|
||||
"homepage": "https://tpmjs.com",
|
||||
"license": "MIT",
|
||||
"tpmjs": {
|
||||
"category": "research",
|
||||
"frameworks": ["vercel-ai"],
|
||||
"tools": [
|
||||
{
|
||||
"name": "timelineFromTextTool",
|
||||
"description": "Extract dated events from text and return normalized timeline",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "text",
|
||||
"type": "string",
|
||||
"description": "The text to extract timeline events from",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"returns": {
|
||||
"type": "Timeline",
|
||||
"description": "Object with events array and optional date range"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "6.0.0-beta.124",
|
||||
"chrono-node": "^2.7.0",
|
||||
"sbd": "^1.0.19"
|
||||
}
|
||||
}
|
||||
50
packages/tools/official/timeline-from-text/src/index.ts
Normal file
50
packages/tools/official/timeline-from-text/src/index.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { jsonSchema, tool } from 'ai';
|
||||
|
||||
export interface Timeline {
|
||||
originalText: string;
|
||||
events: Array<{
|
||||
date: string; // ISO format
|
||||
description: string;
|
||||
confidence: number; // 0.0 to 1.0
|
||||
originalMention: string;
|
||||
}>;
|
||||
dateRange?: {
|
||||
earliest: string;
|
||||
latest: string;
|
||||
};
|
||||
}
|
||||
|
||||
type TimelineFromTextInput = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
export const timelineFromTextTool = tool({
|
||||
description:
|
||||
'Extract dated events from text and return a normalized timeline with confidence scores per event',
|
||||
inputSchema: jsonSchema<TimelineFromTextInput>({
|
||||
type: 'object',
|
||||
properties: {
|
||||
text: {
|
||||
type: 'string',
|
||||
description: 'The text to extract timeline events from',
|
||||
},
|
||||
},
|
||||
required: ['text'],
|
||||
additionalProperties: false,
|
||||
}),
|
||||
async execute({ text }): Promise<Timeline> {
|
||||
// TODO: Implement with:
|
||||
// 1. Use chrono-node to parse dates from text
|
||||
// 2. Extract sentence context around each date
|
||||
// 3. Normalize dates to ISO format
|
||||
// 4. Assign confidence based on date specificity
|
||||
|
||||
return {
|
||||
originalText: text,
|
||||
events: [],
|
||||
dateRange: undefined,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default timelineFromTextTool;
|
||||
11
packages/tools/official/timeline-from-text/tsconfig.json
Normal file
11
packages/tools/official/timeline-from-text/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/timeline-from-text/tsup.config.ts
Normal file
10
packages/tools/official/timeline-from-text/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,
|
||||
});
|
||||
1455
pnpm-lock.yaml
generated
1455
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,3 +5,4 @@ packages:
|
|||
- 'packages/config/tailwind'
|
||||
- 'packages/config/tsconfig'
|
||||
- 'packages/tools/*'
|
||||
- 'packages/tools/official/*'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue