Merge pull request #689 from transitive-bullshit/feature/gravatar

pull/691/head
Travis Fischer 2025-02-28 05:54:10 +07:00 zatwierdzone przez GitHub
commit 2df13fb94f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
14 zmienionych plików z 299 dodań i 9 usunięć

Wyświetl plik

@ -23,7 +23,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10.4.1
version: 10.5.2
run_install: false
- name: Install Node.js

Wyświetl plik

@ -63,6 +63,7 @@
"tools/exa",
"tools/firecrawl",
"tools/hacker-news",
"tools/gravatar",
"tools/hunter",
"tools/jina",
"tools/leadmagic",

Wyświetl plik

@ -0,0 +1,36 @@
---
title: Gravatar
description: Gravatar Profile API.
---
- package: `@agentic/gravatar`
- exports: `class GravatarClient`, `namespace gravatar`
- env vars: `GRAVATAR_API_KEY` _(optional)_
- [source](https://github.com/transitive-bullshit/agentic/blob/main/packages/gravatar/src/gravatar-client.ts)
- [Gravatar API docs](https://docs.gravatar.com/api/profiles/rest-api/)
## Install
<CodeGroup>
```bash npm
npm install @agentic/gravatar
```
```bash yarn
yarn add @agentic/gravatar
```
```bash pnpm
pnpm add @agentic/gravatar
```
</CodeGroup>
## Usage
```ts
import { GravatarClient } from '@agentic/gravatar'
const gravatar = new GravatarClient()
const profile = await gravatar.getProfileByIdentifier('my-email@example.com')
```

Wyświetl plik

@ -1,6 +1,6 @@
import 'dotenv/config'
import { ZoomInfoClient } from '@agentic/stdlib'
import * as stdlib from '@agentic/stdlib'
import restoreCursor from 'restore-cursor'
/**
@ -135,15 +135,17 @@ async function main() {
// category: 'linkedin profile'
// })
const zoomInfo = new ZoomInfoClient()
const res = await zoomInfo.enrichContact({
// emailAddress: 'travis@transitivebullsh.it'
fullName: 'Kevin Raheja',
companyName: 'HeyGen'
})
// const zoomInfo = new ZoomInfoClient()
// const res = await zoomInfo.enrichContact({
// // emailAddress: 'travis@transitivebullsh.it'
// fullName: 'Kevin Raheja',
// companyName: 'HeyGen'
// })
// const res = await zoomInfo.searchContacts({
// fullName: 'Kevin Raheja'
// })
const gravatar = new stdlib.GravatarClient()
const res = await gravatar.getProfileByIdentifier('email@example.com')
console.log(JSON.stringify(res, null, 2))
}

Wyświetl plik

@ -7,7 +7,7 @@
"type": "git",
"url": "git+https://github.com/transitive-bullshit/agentic.git"
},
"packageManager": "pnpm@10.4.1",
"packageManager": "pnpm@10.5.2",
"engines": {
"node": ">=18"
},

Wyświetl plik

@ -0,0 +1,48 @@
{
"name": "@agentic/gravatar",
"version": "7.4.1",
"description": "Agentic SDK for Gravatar.",
"author": "Travis Fischer <travis@transitivebullsh.it>",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/transitive-bullshit/agentic.git",
"directory": "packages/gravatar"
},
"type": "module",
"source": "./src/index.ts",
"types": "./dist/index.d.ts",
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsup --config ../../tsup.config.ts",
"dev": "tsup --config ../../tsup.config.ts --watch",
"clean": "del dist",
"test": "run-s test:*",
"test:lint": "eslint .",
"test:typecheck": "tsc --noEmit"
},
"dependencies": {
"@agentic/core": "workspace:*",
"ky": "^1.7.5",
"p-throttle": "^6.2.0"
},
"peerDependencies": {
"zod": "^3.24.2"
},
"devDependencies": {
"@agentic/tsconfig": "workspace:*"
},
"publishConfig": {
"access": "public"
}
}

Wyświetl plik

@ -0,0 +1,24 @@
<p align="center">
<a href="https://agentic.so">
<img alt="Agentic" src="https://raw.githubusercontent.com/transitive-bullshit/agentic/main/docs/media/agentic-header.jpg" width="308">
</a>
</p>
<p align="center">
<em>AI agent stdlib that works with any LLM and TypeScript AI SDK.</em>
</p>
<p align="center">
<a href="https://github.com/transitive-bullshit/agentic/actions/workflows/main.yml"><img alt="Build Status" src="https://github.com/transitive-bullshit/agentic/actions/workflows/main.yml/badge.svg" /></a>
<a href="https://www.npmjs.com/package/@agentic/stdlib"><img alt="NPM" src="https://img.shields.io/npm/v/@agentic/stdlib.svg" /></a>
<a href="https://github.com/transitive-bullshit/agentic/blob/main/license"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-blue" /></a>
<a href="https://prettier.io"><img alt="Prettier Code Formatting" src="https://img.shields.io/badge/code_style-prettier-brightgreen.svg" /></a>
</p>
# Agentic
**See the [github repo](https://github.com/transitive-bullshit/agentic) or [docs](https://agentic.so) for more info.**
## License
MIT © [Travis Fischer](https://x.com/transitive_bs)

Wyświetl plik

@ -0,0 +1,148 @@
import crypto from 'node:crypto'
import {
aiFunction,
AIFunctionsProvider,
getEnv,
throttleKy
} from '@agentic/core'
import defaultKy, { type KyInstance } from 'ky'
import pThrottle from 'p-throttle'
import z from 'zod'
export namespace gravatar {
export const API_BASE_URL = 'https://api.gravatar.com'
// Allow up to 100 unauthenticated requests per hour by default.
export const unauthenticatedThrottle = pThrottle({
limit: 100,
interval: 60 * 60 * 1000
})
// Allow up to 1000 authenticated requests per hour by default.
export const authenticatedThrottle = pThrottle({
limit: 1000,
interval: 60 * 60 * 1000
})
export type GetProfileByIdentifierOptions = {
email: string
}
export interface Profile {
/** The SHA256 hash of the users primary email address. */
hash: string
/** The users display name that appears on their profile. */
display_name: string
/** The full URL to the users Gravatar profile. */
profile_url: string
/** The URL to the users avatar image, if set. */
avatar_url: string
/** Alternative text describing the users avatar. */
avatar_alt_text: string
/** The users geographical location. */
location: string
/** A short biography or description about the user found on their profile. */
description: string
/** The users current job title. */
job_title: string
/** The name of the company where the user is employed. */
company: string
/** An array of verified accounts the user has added to their profile. The number of verified accounts displayed is limited to a maximum of 4 in unauthenticated requests. */
verified_accounts: any[]
/** A phonetic guide to pronouncing the users name. */
pronunciation: string
/** The pronouns the user prefers to use. */
pronouns: string
/** The total number of verified accounts the user has added to their profile, including those not displayed on their profile. This property is only provided in authenticated API requests. */
number_verified_accounts?: number
/** The date and time (UTC) when the user last edited their profile. This property is only provided in authenticated API requests. Example: "2021-10-01T12:00:00Z" */
last_profile_edit?: string
/** The date the user registered their account. This property is only provided in authenticated API requests. Example: "2021-10-01" */
registration_date?: string
}
}
/**
* A client for the Gravatar API.
*
* API key is optional.
*
* @see https://docs.gravatar.com/getting-started/
*/
export class GravatarClient extends AIFunctionsProvider {
protected readonly ky: KyInstance
protected readonly apiKey?: string
protected readonly apiBaseUrl: string
constructor({
apiKey = getEnv('GRAVATAR_API_KEY'),
apiBaseUrl = gravatar.API_BASE_URL,
timeoutMs = 60_000,
throttle = true,
ky = defaultKy
}: {
apiKey?: string
apiBaseUrl?: string
timeoutMs?: number
throttle?: boolean
ky?: KyInstance
} = {}) {
super()
// API key is optional
this.apiKey = apiKey
this.apiBaseUrl = apiBaseUrl
const throttledKy = throttle
? throttleKy(
ky,
apiKey
? gravatar.authenticatedThrottle
: gravatar.unauthenticatedThrottle
)
: ky
this.ky = throttledKy.extend({
prefixUrl: apiBaseUrl,
timeout: timeoutMs,
headers: Object.fromEntries(
apiKey ? [['Authorization', `Bearer ${apiKey}`]] : []
)
})
}
@aiFunction({
name: 'gravatar_get_profile',
description:
'Get Gravatar profile by email. Returns a profile object or `undefined` if not found.',
inputSchema: z.object({
email: z.string()
})
})
async getProfileByIdentifier(
emailOrOpts: string | gravatar.GetProfileByIdentifierOptions
): Promise<gravatar.Profile | undefined> {
const { email } =
typeof emailOrOpts === 'string' ? { email: emailOrOpts } : emailOrOpts
const hashedEmail = crypto
.createHash('SHA256')
.update(email.trim().toLowerCase(), 'utf8')
.digest('hex')
try {
return await this.ky
.get(`v3/profiles/${hashedEmail}`)
.json<gravatar.Profile>()
} catch (err: any) {
if (err.response?.status === 404) {
return
}
throw err
}
}
}

Wyświetl plik

@ -0,0 +1 @@
export * from './gravatar-client'

Wyświetl plik

@ -0,0 +1,5 @@
{
"extends": "@agentic/tsconfig/base.json",
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

Wyświetl plik

@ -45,6 +45,7 @@
"@agentic/firecrawl": "workspace:*",
"@agentic/genkit": "workspace:*",
"@agentic/github": "workspace:*",
"@agentic/gravatar": "workspace:*",
"@agentic/hacker-news": "workspace:*",
"@agentic/hunter": "workspace:*",
"@agentic/jina": "workspace:*",

Wyświetl plik

@ -8,6 +8,7 @@ export * from '@agentic/e2b'
export * from '@agentic/exa'
export * from '@agentic/firecrawl'
export * from '@agentic/github'
export * from '@agentic/gravatar'
export * from '@agentic/hacker-news'
export * from '@agentic/hunter'
export * from '@agentic/jina'

Wyświetl plik

@ -495,6 +495,25 @@ importers:
specifier: workspace:*
version: link:../tsconfig
packages/gravatar:
dependencies:
'@agentic/core':
specifier: workspace:*
version: link:../core
ky:
specifier: ^1.7.5
version: 1.7.5
p-throttle:
specifier: ^6.2.0
version: 6.2.0
zod:
specifier: ^3.24.2
version: 3.24.2
devDependencies:
'@agentic/tsconfig':
specifier: workspace:*
version: link:../tsconfig
packages/hacker-news:
dependencies:
'@agentic/core':
@ -883,6 +902,9 @@ importers:
'@agentic/github':
specifier: workspace:*
version: link:../github
'@agentic/gravatar':
specifier: workspace:*
version: link:../gravatar
'@agentic/hacker-news':
specifier: workspace:*
version: link:../hacker-news

Wyświetl plik

@ -157,6 +157,7 @@ Full docs are available at [agentic.so](https://agentic.so).
| [E2B](https://e2b.dev) | `@agentic/e2b` | [docs](https://agentic.so/tools/e2b) | Hosted Python code interpreter sandbox which is really useful for data analysis, flexible code execution, and advanced reasoning on-the-fly. |
| [Exa](https://docs.exa.ai) | `@agentic/exa` | [docs](https://agentic.so/tools/exa) | Web search tailored for LLMs. |
| [Firecrawl](https://www.firecrawl.dev) | `@agentic/firecrawl` | [docs](https://agentic.so/tools/firecrawl) | Website scraping and structured data extraction. |
| [Gravatar](https://docs.gravatar.com/api/profiles/rest-api/) | `@agentic/gravatar` | [docs](https://agentic.so/tools/gravatar) | Gravatar profile API. |
| [HackerNews](https://github.com/HackerNews/API) | `@agentic/hacker-news` | [docs](https://agentic.so/tools/hacker-news) | Official HackerNews API. |
| [Hunter](https://hunter.io) | `@agentic/hunter` | [docs](https://agentic.so/tools/hunter) | Email finder, verifier, and enrichment. |
| [Jina](https://jina.ai/reader) | `@agentic/jina` | [docs](https://agentic.so/tools/jina) | URL scraper and web search. |