Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jw websets #43

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
120 changes: 60 additions & 60 deletions .github/workflows/run-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@ name: Test SDK and Run Examples

on:
push:
branches: [ main ]
branches: [main]
pull_request:

jobs:
test-sdk-and-run-examples:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Build SDK
run: npm run build

- name: Run tests
run: npm test

- name: Run Node.js example
working-directory: ./examples/node
run: |
npm ci
npm run build
node dist/server.js &
sleep 10
curl http://localhost:8000
kill %1
env:
EXASEARCH_API_KEY: ${{ secrets.EXA_API_KEY }}
- uses: actions/checkout@v3

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: "18"

- name: Install dependencies
run: npm ci

- name: Build SDK
run: npm run build

- name: Run tests
run: npm test

- name: Run Node.js example
working-directory: ./examples/node
run: |
npm ci
npm run build
node dist/server.js &
sleep 10
curl -s -o /tmp/curl_output.txt http://localhost:8000 || cat /tmp/curl_output.txt
kill %1
env:
EXASEARCH_API_KEY: ${{ secrets.EXA_API_KEY }}

# Optional: Add steps to publish the package if on main branch
# - name: Publish to npm
Expand All @@ -49,35 +49,35 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Install TypeScript
run: npm install -g typescript

- name: Compile TypeScript files
run: |
cd examples
for file in *.ts; do
echo "Compiling $file"
tsc $file
done

- name: List compiled files
run: ls -R examples/*.js

- name: Run JavaScript files
run: |
for file in examples/*.js; do
echo "Running $file"
node $file || echo "Failed to run $file"
done
env:
EXASEARCH_API_KEY: ${{ secrets.EXA_API_KEY }}
- uses: actions/checkout@v3

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: "18"

- name: Install dependencies
run: npm ci

- name: Install TypeScript
run: npm install -g typescript

- name: Compile TypeScript files
run: |
cd examples
for file in *.ts; do
echo "Compiling $file"
tsc $file
done

- name: List compiled files
run: ls -R examples/*.js

- name: Run JavaScript files
run: |
for file in examples/*.js; do
echo "Running $file"
node $file || echo "Failed to run $file"
done
env:
EXASEARCH_API_KEY: ${{ secrets.EXA_API_KEY }}
38 changes: 38 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Exa-JS Code Assistant Guide

## Build & Test Commands
- Build: `npm run build`
- Fast Build: `npm run build-fast` (only builds index.ts)
- Test All: `npm run test`
- Test Single: `npx vitest run test/path/to/test.ts`
- Generate Docs: `npm run generate-docs`

## Code Style Guidelines
- **TypeScript**: ES2020 target, ESNext modules, strict mode
- **Formatting**: Default Prettier (2.8.4)
- **Imports**: ES imports, built-in modules first
- **Types**:
- Comprehensive TypeScript types with JSDoc comments
- Generic types for API responses
- Interfaces/Types in PascalCase (e.g., `SearchOptions`)
- Optional properties with `?` suffix
- **Naming**:
- Classes: PascalCase (e.g., `Exa`)
- Methods/Variables: camelCase
- Consistent patterns (e.g., `*Options`, `*Response`)
- **Error Handling**:
- Explicit errors with descriptive messages
- API error handling with status codes
- **API Design**:
- Class-based design with clear method signatures
- Private helper methods for common functionality
- Method overloading via optional parameters

## Websets API Implementation
- The Python SDK has a comprehensive Websets API implementation that needs to be mirrored in TypeScript
- Key components include:
- WebsetsClient with methods for create, get, list, update, delete, cancel, wait_until_idle
- Sub-clients for items, searches, enrichments, and webhooks
- Extensive type definitions for all request/response objects
- Proper handling of pagination for list operations
- Support for entity types (company, person, article, research paper, custom)
2 changes: 1 addition & 1 deletion examples/find_similar_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runFindSimilarExamples() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/get_contents_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runGetContentsExample() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/links_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runLinksExample() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/livecrawl_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runLivecrawlExample() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/schema_summary_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa, { JSONSchema } from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runSchemaSummaryExample() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/search_example.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runSearchExamples() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/search_with_contents.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runSearchExamples() {
try {
Expand Down
2 changes: 1 addition & 1 deletion examples/subpages.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Exa from "../src/index";

const exa = new Exa(process.env.EXASEARCH_API_KEY);
const exa = new Exa(process.env.EXA_API_KEY);

async function runExamples() {
try {
Expand Down
126 changes: 126 additions & 0 deletions examples/websets_builder_example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Example demonstrating the builder pattern for the Websets API
*
* This example shows how to use the builder classes to create complex
* Webset objects in a more readable and maintainable way.
*/

import * as dotenv from "dotenv";
import Exa, { EventType, WebsetBuilder, WebsetSearchBuilder } from "../src";

// Load environment variables from .env file
dotenv.config();

async function main() {
// Initialize the client
const exa = new Exa(process.env.EXA_API_KEY);

console.log("Creating a Webset using the builder pattern...");

// 1. Build the search parameters first
const searchBuilder = new WebsetSearchBuilder("AI research labs", 20)
.forCompanies()
.withCriteria([
"Must focus on large language models research",
"Must have published research in the last two years",
]);

// 2. Build the Webset parameters, passing the SearchBuilder
const websetParams = new WebsetBuilder(searchBuilder)
.withNumberEnrichment("Estimate the company's founding year")
.withOptionsEnrichment("Primary focus area", [
"Language models",
"Computer vision",
"Robotics",
"Multi-modal AI",
"Other",
])
.withEmailEnrichment("Extract the contact email for the research lab")
.withPhoneEnrichment("Find the phone number of the main office")
.withMetadata({
purpose: "Market research",
created_by: "builder-example",
category: "AI Research",
})
.build();

console.log(
"Built Webset parameters:",
JSON.stringify(websetParams, null, 2)
);

const webset = await exa.websets.create(websetParams);
console.log(`Created Webset with ID: ${webset.id}`);

// Wait for the Webset to be idle
console.log("Waiting for Webset to be idle...");
await exa.websets.waitUntilIdle(webset.id, {
timeout: 300000,
onPoll: (currentStatus) => console.log(`Current status: ${currentStatus}`),
});

// Add another search using the builder
console.log("Adding another search to the Webset...");
const newSearchBuilder = new WebsetSearchBuilder(
"AI research labs in Europe",
3
)
.forCompanies()
.withCriterion("Must be headquartered in Europe")
.shouldOverride();

const searchParams = newSearchBuilder.build();

console.log(
"Built search parameters:",
JSON.stringify(searchParams, null, 2)
);

const search = await exa.websets.searches.create(webset.id, searchParams);
console.log(`Created search with ID: ${search.id}`);

// Wait for the Webset to be idle again
console.log("Waiting for Webset to be idle again...");
await exa.websets.waitUntilIdle(webset.id, {
timeout: 60000,
onPoll: (currentStatus) => console.log(`Current status: ${currentStatus}`),
});

// Get all items at once
console.log("Getting all items...");
const items = await exa.websets.items.getAll(webset.id);
console.log(`Found ${items.length} items in the Webset`);

// Monitor events related to our Webset
console.log("\nMonitoring events for our Webset...");
const events = await exa.websets.events.list({
limit: 10,
types: [
EventType.webset_created,
EventType.webset_idle,
EventType.webset_item_created,
EventType.webset_search_created,
EventType.webset_search_completed,
],
});

console.log(`Found ${events.data.length} events:`);
for (const event of events.data) {
console.log(`- ${event.type} at ${event.createdAt}`);
if (
event.type === EventType.webset_created ||
event.type === EventType.webset_idle
) {
console.log(` Webset ID: ${event.data.id}`);
} else if (event.type === EventType.webset_item_created) {
console.log(` Item ID: ${event.data.id}`);
} else if (
event.type === EventType.webset_search_created ||
event.type === EventType.webset_search_completed
) {
console.log(` Search ID: ${event.data.id}`);
}
}
}

main();
Loading