Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fc31391
initial setup of mastra + bump of packages to beta + codemods
lunelson Dec 4, 2025
103ca30
align config w hash monorepo
lunelson Dec 4, 2025
fc1e50e
rename app to hash-ai-agent, for alignment
lunelson Dec 5, 2025
ed5d03b
complete part 1 of mastra course
lunelson Dec 5, 2025
53bb97c
complete part 2 of mastra course
lunelson Dec 5, 2025
83a6957
configure mastra mcp at root
lunelson Dec 5, 2025
b97e3fa
create claude plan for ner optimization
lunelson Dec 5, 2025
111fbfe
phase 1 porting from ai-worker w claude 1m
lunelson Dec 5, 2025
004b01d
post porting clean up pass 1
lunelson Dec 8, 2025
3ba3cdb
entity extraction as workflow
lunelson Dec 8, 2025
7eb51a8
add more required stuff to package
lunelson Dec 9, 2025
d1eaf40
fix static issues; annotate z schemas
lunelson Dec 9, 2025
29cfac7
clean up dereferencing tool
lunelson Dec 9, 2025
943d115
pick apart the mess
lunelson Dec 9, 2025
ca1991d
remove the stuff that was in _holding
lunelson Dec 10, 2025
9c33088
remove docs
lunelson Dec 10, 2025
dc5757d
make the test for entity summaries use test.for API and test data $name
lunelson Dec 10, 2025
7a07b46
port the static parts of the claims extraction tests
lunelson Dec 10, 2025
f9fdc8c
struggling to get the dynamic parts working
lunelson Dec 10, 2025
b75775b
OK maybe some reasonable resolutions
lunelson Dec 10, 2025
e4651f9
delete temp PLANNING doc
lunelson Dec 10, 2025
06a25b9
fixes from cursor bot
lunelson Dec 10, 2025
f3647e9
fix two more cursor bot bugs
lunelson Dec 10, 2025
5dd102d
one more issue
lunelson Dec 10, 2025
24376d3
another cursor bot fix
lunelson Dec 10, 2025
df9cd72
delete useless code and run fix: scripts
lunelson Dec 10, 2025
aaae219
remove demo code
lunelson Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .cursor/mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"mastra": {
"command": "npx",
"args": ["-y", "@mastra/mcp-docs-server@beta"]
}
}
}
8 changes: 8 additions & 0 deletions apps/hash-ai-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
output.txt
node_modules
dist
.mastra
.env.development
.env
*.db
*.db-*
152 changes: 152 additions & 0 deletions apps/hash-ai-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# HASH AI Agent (Mastra-based)

Mastra-based implementation of HASH's AI inference capabilities, focusing on Named Entity Recognition (NER) and entity extraction optimization.

## Project Structure

```
src/mastra/
├── agents/
│ └── entity-summary-agent.ts # NER agent (baseline)
├── evals/
│ ├── test-data/
│ │ └── ner-test-cases.ts # Test dataset with scoring logic
│ ├── test-entity-extraction.ts # Simple smoke test
│ └── run-entity-extraction-eval.ts # Full evaluation runner
├── scorers/
│ └── entity-recall-scorer.ts # Entity recall/precision scorer
├── shared/
│ ├── dereference-entity-type.ts # Entity type schema utilities
│ └── generate-simplified-type-id.ts # Helper for type dereferencing
├── types/
│ └── entities.ts # Core entity type definitions
└── index.ts # Mastra instance registration
```

## Quick Start

### 1. Simple Test

Run a single test case to verify the agent works:

```bash
pnpm tsx src/mastra/evals/test-entity-extraction.ts
```

This will:

- Load the first test case from `ner-test-cases.ts`
- Run the entity summary agent
- Display extracted entities vs. expected entities

### 2. Full Evaluation

Run all test cases with scoring:

```bash
pnpm tsx src/mastra/evals/run-entity-extraction-eval.ts
```

This will:

- Run all NER test cases
- Calculate entity recall, precision, and type accuracy
- Display average scores and detailed breakdowns

## Architecture

### Agents

**Entity Summary Agent** (`agents/entity-summary-agent.ts`)

- **Purpose**: Named Entity Recognition (NER) - identify entities in text
- **Model**: `google/gemini-2.0-flash-exp:free` (via OpenRouter)
- **Tool**: `registerEntitySummaries` for reporting found entities
- **Input**: Text + research goal + entity types
- **Output**: Array of entity summaries (name, summary, type)

### Scorers

**Entity Recall Scorer** (`scorers/entity-recall-scorer.ts`)

- **Purpose**: Measure extraction quality (recall, precision, type accuracy)
- **Methodology**: Ported from hash-ai-worker-ts optimization tests
- **Metrics**:
- Gold entities found vs. missed (recall)
- Irrelevant entities identified (false positives)
- Wrong-type entities (type confusion)
- **Score**: 0-1 (1 = perfect extraction)

### Test Data

**NER Test Cases** (`evals/test-data/ner-test-cases.ts`)

- **Source**: Ported from hash-ai-worker-ts
- **Format**: Stable fixtures (no external dependencies)
- **Coverage**: AI companies, people, organizations, edge cases
- **Ground Truth**: Gold entities, irrelevant entities, wrong-type entities

### Type Definitions

**Entity Types** (`types/entities.ts`)

- `LocalEntitySummary` - Step 1: Entity name + summary + types
- `Claim` - Step 2: Facts about entities (for future phases)
- `ProposedEntity` - Step 3: Full entity with properties (for future phases)
- `SourceProvenance` - Provenance tracking

## Migration from hash-ai-worker-ts

This project migrates AI inference capabilities from `hash-ai-worker-ts` (Temporal-based) to Mastra architecture:

- **Workflows** (Temporal) → **Mastra Workflows** (structured steps)
- **Activities** (LLM-based) → **Mastra Agents** (with tools)
- **Activities** (deterministic) → **Mastra Tools**
- **AI Tests** → **Mastra Evals** (scorers)

See `docs/mastra-migration-plan.md` for complete architectural mapping.

## Next Steps (Future Phases)

- [ ] Create claim extraction agent
- [ ] Create entity proposal agent
- [ ] Build three-step workflow (summaries → claims → entities)
- [ ] Create additional scorers (property accuracy, claim accuracy)
- [ ] Add entity matching/deduplication agent
- [ ] Integrate with HASH Graph API (currently using fixtures)

## Development

### Prerequisites

- Node.js 22+
- pnpm
- OpenRouter API key (for Google models)

### Environment Variables

```bash
OPENROUTER_API_KEY=your_api_key_here
```

### Running Tests

```bash
# Quick smoke test
pnpm tsx src/mastra/evals/test-entity-extraction.ts

# Full evaluation suite
pnpm tsx src/mastra/evals/run-entity-extraction-eval.ts
```

### Type Checking

```bash
pnpm tsc --noEmit
```

## References

- [Mastra Documentation](https://mastra.ai/docs)
- [Original Plan](docs/ner-optimization-plan.md) - Original NER optimization plan
- [Migration Plan](docs/mastra-migration-plan.md) - Detailed migration architecture
18 changes: 18 additions & 0 deletions apps/hash-ai-agent/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createBase, defineConfig } from "@local/eslint/deprecated";

export default [
{
ignores: ["_temp/**", ".mastra/**", "node_modules/**"],
},
...createBase(import.meta.dirname),
...defineConfig([
{
rules: {
/**
* @todo we should have separate browser/node configs
*/
"react-hooks/rules-of-hooks": "off",
},
},
]),
];
66 changes: 66 additions & 0 deletions apps/hash-ai-agent/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "@apps/hash-ai-agent",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "vitest",
"dev": "mastra dev",
"build": "mastra build",
"start": "mastra start",
"fix:eslint": "eslint --fix .",
"lint:eslint": "eslint --report-unused-disable-directives .",
"lint:tsc": "tsc --noEmit",
"ugi": "yarn upgrade-interactive"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.24.0",
"type": "module",
"engines": {
"node": ">=22.13.0"
},
"dependencies": {
"@ai-sdk/openai": "2.0.80",
"@blockprotocol/graph": "0.4.0-canary.2",
"@blockprotocol/type-system": "0.1.2-canary.1",
"@local/advanced-types": "0.0.0-private",
"@local/hash-backend-utils": "0.0.0-private",
"@local/hash-graph-client": "0.0.0-private",
"@local/hash-graph-sdk": "0.0.0-private",
"@local/hash-isomorphic-utils": "0.0.0-private",
"@local/status": "0.0.0-private",
"@mastra/core": "1.0.0-beta.10",
"@mastra/evals": "1.0.0-beta.2",
"@mastra/libsql": "1.0.0-beta.7",
"@mastra/loggers": "1.0.0-beta.3",
"@mastra/mcp": "1.0.0-beta.6",
"@mastra/memory": "1.0.0-beta.4",
"dedent": "1.7.0",
"es-toolkit": "1.42.0",
"zod": "^4.1.13"
},
"devDependencies": {
"@local/eslint": "0.0.0-private",
"@local/tsconfig": "0.0.0-private",
"@types/dedent": "0.7.2",
"@types/dotenv-flow": "3.3.3",
"@types/jsdom": "21.1.7",
"@types/lodash": "4.17.20",
"@types/md5": "2.3.6",
"@types/mime-types": "2.1.4",
"@types/node": "22.18.13",
"@types/papaparse": "5.3.16",
"@types/sanitize-html": "2.16.0",
"@vitest/coverage-istanbul": "3.2.4",
"eslint": "9.38.0",
"jsdom": "27.3.0",
"mastra": "1.0.0-beta.5",
"rimraf": "6.1.2",
"sanitize-html": "2.17.0",
"tsx": "4.21.0",
"typescript": "^5.9.3",
"vitest": "3.2.4",
"wait-on": "9.0.1"
}
}
Loading
Loading