-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #672 from JigsawStack/narcisse/jigsawstack-tools
- Loading branch information
Showing
6 changed files
with
446 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{ | ||
"name": "@agentic/jigsawstack", | ||
"version": "1.0.0", | ||
"description": "Agentic adapter for the Jigsawstack AI SDK.", | ||
"author": "Narcisse Egonu", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/transitive-bullshit/agentic.git" | ||
}, | ||
"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", | ||
"test:unit": "vitest run" | ||
}, | ||
"peerDependencies": { | ||
"@agentic/core": "workspace:*" | ||
}, | ||
"devDependencies": { | ||
"@agentic/core": "workspace:*", | ||
"@agentic/tsconfig": "workspace:*" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"dependencies": { | ||
"ky": "^1.5.0", | ||
"p-throttle": "^6.1.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './jigsawstack-client' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// eslint-disable-next-line simple-import-sort/imports | ||
import { openai } from '@ai-sdk/openai' | ||
import { generateText } from 'ai' | ||
import { expect, test } from 'vitest' | ||
import { createAISDKTools } from '../../ai-sdk' | ||
import { JigsawStackClient } from './jigsawstack-client' | ||
|
||
// Do ensure to set your JIGSAWSTACK_API_KEY environment variable. | ||
|
||
const jigsaw = new JigsawStackClient({ timeoutMs: 30_000 }) | ||
|
||
test.skip('should run successfully and return search result', async () => { | ||
const { toolResults } = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: createAISDKTools(jigsaw), | ||
toolChoice: 'required', | ||
prompt: 'Tell me about "Santorini"' | ||
}) | ||
|
||
// console.log(toolResults, 'toolResults') | ||
expect(toolResults[0]).toBeTruthy() | ||
}) | ||
|
||
test.skip('should scrape url successfully and return result', async () => { | ||
const { toolResults } = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: createAISDKTools(jigsaw), | ||
toolChoice: 'required', | ||
prompt: 'Scrape https://jigsawstack.com and tell me their title' | ||
}) | ||
|
||
// console.log(toolResults[0], 'toolResults') | ||
expect(toolResults[0]).toBeTruthy() | ||
}) | ||
|
||
test.skip('should perform vision based OCR and return result', async () => { | ||
const { toolResults } = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: createAISDKTools(jigsaw), | ||
toolChoice: 'required', | ||
prompt: | ||
'Tell me about this image : https://rogilvkqloanxtvjfrkm.supabase.co/storage/v1/object/public/demo/Collabo%201080x842.jpg?t=2024-03-22T09%3A22%3A48.442Z' | ||
}) | ||
// console.log(toolResults[0], 'toolResults') | ||
expect(toolResults[0]).toBeTruthy() | ||
}) | ||
|
||
test.skip('should perform speech to text and return result', async () => { | ||
const { toolResults } = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: createAISDKTools(jigsaw), | ||
toolChoice: 'required', | ||
prompt: | ||
'Get the transcription from this video url : https://rogilvkqloanxtvjfrkm.supabase.co/storage/v1/object/public/demo/Video%201737458382653833217.mp4?t=2024-03-22T09%3A50%3A49.894Z' | ||
}) | ||
// console.log(toolResults[0], 'toolResults') | ||
expect(toolResults[0]).toBeTruthy() | ||
}) | ||
|
||
test('should perform text to sql and return result', async () => { | ||
const prompt = ` | ||
Generate a query to get transactions that amount exceed 10000 and sort by when created. Given this schema: | ||
"CREATE TABLE Transactions (transaction_id INT PRIMARY KEY, user_id INT NOT NULL,total_amount DECIMAL(10, 2 NOT NULL, transaction_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,status VARCHAR(20) DEFAULT 'pending',FOREIGN KEY(user_id) REFERENCES Users(user_id))"` | ||
const { toolResults } = await generateText({ | ||
model: openai('gpt-4o-mini'), | ||
tools: createAISDKTools(jigsaw), | ||
toolChoice: 'required', | ||
prompt | ||
}) | ||
expect(toolResults[0]).toBeTruthy() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
import { aiFunction,AIFunctionsProvider, assert, getEnv } from '@agentic/core' | ||
import ky, { type KyInstance } from 'ky' | ||
import { z } from 'zod' | ||
|
||
export namespace jigsawstack { | ||
export interface BaseResponse { | ||
success: boolean | ||
} | ||
|
||
export const API_BASE_URL = 'https://api.jigsawstack.com/v1/' | ||
|
||
export interface SearchParams { | ||
query: string | ||
ai_overview?: boolean | ||
safe_search?: 'moderate' | 'strict' | 'off' | ||
spell_check?: boolean | ||
} | ||
|
||
export interface SearchResponse extends BaseResponse { | ||
query: string | ||
spell_fixed: string | ||
is_safe: boolean | ||
ai_overview: string | ||
results: { | ||
title: string | ||
url: string | ||
description: string | ||
content: string | ||
is_safe: boolean | ||
site_name: string | ||
site_long_name: string | ||
age: string | ||
language: string | ||
favicon: string | ||
snippets: string[] | ||
related_index: [] | ||
}[] | ||
} | ||
|
||
export interface CookieParameter { | ||
name: string | ||
value: string | ||
url?: string | ||
domain?: string | ||
path?: string | ||
secure?: boolean | ||
httpOnly?: boolean | ||
sameSite?: 'Strict' | 'Lax' | 'None' | ||
expires?: boolean | ||
priority?: string | ||
sameParty?: boolean | ||
} | ||
|
||
export interface ScrapeParams { | ||
url: string | ||
element_prompts: string[] | ||
http_headers?: object | ||
reject_request_pattern?: string[] | ||
goto_options?: { | ||
timeout: number | ||
wait_until: string | ||
} | ||
wait_for?: { | ||
mode: string | ||
value: string | number | ||
} | ||
advance_config?: { | ||
console: boolean | ||
network: boolean | ||
cookies: boolean | ||
} | ||
size_preset?: string | ||
is_mobile?: boolean | ||
scale?: number | ||
width?: number | ||
height?: number | ||
cookies?: Array<CookieParameter> | ||
} | ||
|
||
export interface ScrapeResponse extends BaseResponse { | ||
data: any | ||
} | ||
|
||
export interface VOCRParams { | ||
prompt: string | string[] | ||
url?: string | ||
file_store_key?: string | ||
} | ||
|
||
export interface VOCRResponse extends BaseResponse { | ||
context: string | ||
width: number | ||
height: number | ||
tags: string[] | ||
has_text: boolean | ||
sections: Array<any> | ||
} | ||
|
||
export interface TextToSqlParams { | ||
prompt: string | ||
sql_schema?: string | ||
file_store_key?: string | ||
} | ||
|
||
export interface TextToSqlResponse extends BaseResponse { | ||
sql: string | ||
} | ||
|
||
export interface SpeechToTextParams { | ||
url?: string | ||
file_store_key?: string | ||
language?: string | ||
translate?: boolean | ||
by_speaker?: boolean | ||
webhook_url?: string | ||
} | ||
|
||
export interface SpeechToTextResponse extends BaseResponse { | ||
text: string | ||
chunks: Array<{ | ||
timestamp: number[] | ||
text: string | ||
}> | ||
status?: 'processing' | 'error' | ||
id?: string | ||
} | ||
} | ||
|
||
/** | ||
* Basic JigsawStack API wrapper. | ||
*/ | ||
export class JigsawStackClient extends AIFunctionsProvider { | ||
protected readonly apiKey: string | ||
protected readonly ky: KyInstance | ||
constructor({ | ||
apiKey = getEnv('JIGSAWSTACK_API_KEY'), | ||
timeoutMs = 60_000 | ||
}: { | ||
apiKey?: string | ||
throttle?: boolean | ||
timeoutMs?: number | ||
} = {}) { | ||
assert( | ||
apiKey, | ||
'Please set the JIGSAWSTACK_API_KEY environment variable or pass it to the constructor as the apiKey field.' | ||
) | ||
super() | ||
this.apiKey = apiKey | ||
this.ky = ky.extend({ | ||
prefixUrl: jigsawstack.API_BASE_URL, | ||
timeout: timeoutMs, | ||
headers: { | ||
'x-api-key': this.apiKey | ||
} | ||
}) | ||
} | ||
|
||
@aiFunction({ | ||
name: 'jigsawstack_ai_search', | ||
description: | ||
'Perform web searches and retrieve high-quality results of the given query', | ||
inputSchema: z.object({ | ||
query: z.string().describe('The search query') | ||
}) | ||
}) | ||
async aiSearch(params: jigsawstack.SearchParams) { | ||
return this.ky | ||
.get('web/search', { | ||
searchParams: { | ||
...params | ||
} | ||
}) | ||
.json<jigsawstack.SearchResponse>() | ||
} | ||
|
||
@aiFunction({ | ||
name: 'jigsawstack_ai_scrape', | ||
description: 'Scrape any website', | ||
inputSchema: z.object({ | ||
url: z.string().describe('The url to scrape its content'), | ||
element_prompts: z | ||
.array(z.string()) | ||
.describe( | ||
'The items to scrape (retrieve) from the given url. eg. Page title, price, etc' | ||
) | ||
}) | ||
}) | ||
async aiScrape(params: jigsawstack.ScrapeParams) { | ||
return this.ky | ||
.post('ai/scrape', { | ||
json: { | ||
...params | ||
} | ||
}) | ||
.json<jigsawstack.ScrapeResponse>() | ||
} | ||
|
||
@aiFunction({ | ||
name: 'jigsawstack_vocr', | ||
description: | ||
'Recognise, describe and retrieve data within an image with great accuracy.', | ||
inputSchema: z.object({ | ||
url: z.string().describe('The image url to OCR'), | ||
prompt: z | ||
.string() | ||
.default('Describe the image in detail.') | ||
.describe('What you want to know or retrieve from the image') | ||
}) | ||
}) | ||
async vocr(params: jigsawstack.VOCRParams) { | ||
return this.ky | ||
.post('vocr', { | ||
json: { | ||
...params | ||
} | ||
}) | ||
.json<jigsawstack.VOCRResponse>() | ||
} | ||
|
||
@aiFunction({ | ||
name: 'jigsawstack_text_to_sql', | ||
description: 'Generate semantically correct SQL queries from text.', | ||
inputSchema: z.object({ | ||
prompt: z | ||
.string() | ||
.describe('The text that will be translated to an SQL query.'), | ||
sql_schema: z | ||
.string() | ||
.describe('The valid sql schema where the query will be run') | ||
}) | ||
}) | ||
async textToSql( | ||
params: jigsawstack.TextToSqlParams | ||
): Promise<jigsawstack.TextToSqlResponse> { | ||
return this.ky | ||
.post('ai/sql', { | ||
json: { | ||
...params | ||
} | ||
}) | ||
.json<jigsawstack.TextToSqlResponse>() | ||
} | ||
|
||
@aiFunction({ | ||
name: 'jigsawstack_speech_to_text', | ||
description: | ||
'Convert audio/video files into accurate text transcriptions instantly.', | ||
inputSchema: z.object({ | ||
url: z.string().describe('The audio or video url') | ||
}) | ||
}) | ||
async speechToText( | ||
params: jigsawstack.SpeechToTextParams | ||
): Promise<jigsawstack.SpeechToTextResponse> { | ||
return this.ky | ||
.post('ai/transcribe', { | ||
json: { | ||
...params | ||
} | ||
}) | ||
.json<jigsawstack.SpeechToTextResponse>() | ||
} | ||
} |
Oops, something went wrong.