chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:48 +08:00
commit 77bb5bf71f
3762 changed files with 353249 additions and 0 deletions
@@ -0,0 +1,45 @@
import { type Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import { Tool } from 'llmz'
/** Extract the full content & the metadata of the specified pages as markdown. */
export const browsePages = (client: Client) =>
new Tool({
name: 'browser_browsePages',
description: 'Extract the full content & the metadata of the specified pages as markdown.',
input: z
.object({
urls: z.array(z.string()),
waitFor: z
.default(
z
.number()
.describe(
'Time to wait before extracting the content (in milliseconds). Set this value higher for dynamic pages.'
),
350
)
.describe(
'Time to wait before extracting the content (in milliseconds). Set this value higher for dynamic pages.'
),
})
.catchall(z.never()),
output: z
.object({
results: z.array(
z
.object({
url: z.string(),
content: z.string(),
favicon: z.optional(z.string()),
title: z.optional(z.string()),
description: z.optional(z.string()),
})
.catchall(z.never())
),
})
.catchall(z.never()),
handler: async (input) => {
return client.callAction({ type: 'browser:browsePages', input }).then(({ output }) => output) as any
},
})
@@ -0,0 +1,23 @@
import { type Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import { Tool } from 'llmz'
/** Capture a screenshot of the specified page. */
export const captureScreenshot = (client: Client) =>
new Tool({
name: 'browser_captureScreenshot',
description: 'Capture a screenshot of the specified page.',
input: z
.object({
url: z.string(),
})
.catchall(z.never()),
output: z
.object({
imageUrl: z.string(),
})
.catchall(z.never()),
handler: async (input) => {
return client.callAction({ type: 'browser:captureScreenshot', input }).then(({ output }) => output) as any
},
})
@@ -0,0 +1,3 @@
export * from './browsePages'
export * from './captureScreenshot'
export * from './webSearch'
@@ -0,0 +1,102 @@
import { type Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import { Tool } from 'llmz'
/** Search information on the web. You need to browse to that page to get the full content of the page. */
export const webSearch = (client: Client) =>
new Tool({
name: 'browser_webSearch',
description: 'Search information on the web. You need to browse to that page to get the full content of the page.',
input: z
.object({
query: z.string().min(1, undefined).max(1000, undefined).describe('What are we searching for?'),
includeSites: z
.optional(
z
.array(
z
.string()
.regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/, undefined)
.min(3, undefined)
.max(50, undefined)
)
.max(20, undefined)
.describe('Include only these domains in the search (max 20)')
)
.describe('Include only these domains in the search (max 20)'),
excludeSites: z
.optional(
z
.array(
z
.string()
.regex(/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/, undefined)
.min(3, undefined)
.max(50, undefined)
)
.max(20, undefined)
.describe('Exclude these domains from the search (max 20)')
)
.describe('Exclude these domains from the search (max 20)'),
count: z
.default(
z
.number()
.min(1, undefined)
.max(20, undefined)
.describe('Number of search results to return (default: 10)'),
10
)
.describe('Number of search results to return (default: 10)'),
freshness: z
.optional(z.enum(['Day', 'Week', 'Month']).describe('Only consider results from the last day, week or month'))
.describe('Only consider results from the last day, week or month'),
browsePages: z
.boolean()
// .default(false)
.describe('Whether to browse to the pages to get the full content'),
})
.catchall(z.never()),
output: z
.object({
results: z.array(
z
.object({
name: z.string().describe('Title of the page'),
url: z.string().describe('URL of the page'),
snippet: z.string().describe('A short summary of the page'),
links: z
.optional(
z
.array(
z
.object({
name: z.string(),
url: z.string(),
})
.catchall(z.never())
)
.describe('Useful links on the page')
)
.describe('Useful links on the page'),
page: z.optional(
z
.object({
url: z.string(),
content: z.string(),
favicon: z.optional(z.string()),
title: z.optional(z.string()),
description: z.optional(z.string()),
})
.catchall(z.never())
),
})
.catchall(z.never())
),
})
.catchall(z.never()),
handler: async (input) => {
return client.callAction({ type: 'browser:webSearch', input }).then(({ output }) => output) as any
},
})
@@ -0,0 +1,193 @@
import { Client } from '@botpress/client'
import { z } from '@bpinternal/zui'
import { ObjectInstance, Tool } from 'llmz'
const sanitizePath = (path: string) => {
// Remove leading/trailing slashes and replace multiple slashes with a single slash
path = path.replace(/(^\/+|\/+$)/g, '').replace(/\/{2,}/g, '/')
// Allow only alphanumeric, underscore, hyphen, and slashes
path = path.replace(/[^a-zA-Z0-9_\-\\/\\.]/g, '')
// Ensure the path does not start with a slash
path = path.startsWith('/') ? path : `/${path}`
// Ensure the path does not end with a slash
path = path.endsWith('/') ? path.slice(0, -1) : path
// Ensure the path does not contain consecutive slashes
path = path.replace(/\/{2,}/g, '/')
// Ensure the path does not contain a leading dot
path = path.replace(/^\.\//, '')
// Ensure the path does not contain a trailing dot
path = path.replace(/\/\.$/, '')
return path.toLowerCase().trim()
}
const getPathFolder = (path: string) => {
const parts = path.split('/')
parts.pop() // Remove the last part (file name)
return parts.join('/') || '/'
}
const parseFilePath = (path: string) => {
if (!path || typeof path !== 'string') {
throw new Error(`Invalid file path: "${path}". Path must be a non-empty string.`)
}
if (path.length > 255) {
throw new Error(`Invalid file path: "${path}". Path length exceeds 255 characters.`)
}
const sanitizedPath = sanitizePath(path)
if (!sanitizedPath.length) {
throw new Error(`Invalid file path: "${path}". Path cannot be empty.`)
}
const folder = getPathFolder(sanitizedPath)
const fileName = sanitizedPath.split('/').pop()?.trim() || ''
if (!fileName.length) {
throw new Error(`Invalid file path: "${path}". File name cannot be empty.`)
}
if (fileName.length && !fileName.includes('.')) {
throw new Error(`Invalid file path: "${fileName}". File name must contain an extension.`)
}
return {
path: sanitizedPath,
folder,
file: fileName,
}
}
export const makeFileSystem = (client: Client) =>
new ObjectInstance({
name: 'fs',
description: 'File system operations',
tools: [
new Tool({
name: 'readFile',
description: 'Read a file from the file system',
input: z.string().describe('File path to read'),
output: z.string().describe('File content'),
handler: async (path) => {
const { path: key } = parseFilePath(path)
const { file } = await client.getFile({
id: key,
})
return await fetch(file.url).then((res) => res.text())
},
}),
new Tool({
name: 'writeFile',
description: 'Write a file to the file system',
input: z.object({
path: z.string().describe('File path to write'),
content: z.string().describe('File content to write'),
}),
handler: async (input) => {
const { path, file, folder } = parseFilePath(input.path)
await client.uploadFile({
key: path,
content: input.content,
accessPolicies: ['public_content'],
publicContentImmediatelyAccessible: true,
tags: {
purpose: 'file-system',
folder: folder || '/',
name: file,
},
})
},
}),
new Tool({
name: 'listFiles',
description: 'Write a file to the file system',
input: z.string().describe('Folder path to list files from').default('/'),
output: z
.array(
z.object({
folder: z.string().describe('Folder path'),
file: z.string().describe('File name'),
createdAt: z.string().describe('File creation date'),
updatedAt: z.string().describe('File last update date'),
size: z.number().describe('File size in bytes'),
url: z.string().url().describe('File URL'),
contentType: z.string().describe('File content type'),
})
)
.describe('List of files in the folder'),
handler: async (path) => {
const folder = sanitizePath(path || '/')
const files = await client.list
.files({
sortDirection: 'desc',
sortField: 'updatedAt',
tags: {
purpose: 'file-system',
folder,
},
})
.collect({ limit: 1000 })
return files.map((file) => ({
folder: file.tags?.folder || '/',
file: file.tags?.name || file.key,
createdAt: file.createdAt,
updatedAt: file.updatedAt,
size: file.size,
url: file.url,
contentType: file.contentType,
}))
},
}),
new Tool({
name: 'deleteFile',
description: 'Delete a file from the file system',
input: z.string().describe('File path to delete'),
output: z.boolean().describe('True if file was deleted successfully'),
handler: async (path) => {
const { path: key } = parseFilePath(path)
await client.deleteFile({ id: key })
return true
},
}),
new Tool({
name: 'moveFile',
description: 'Rename a file in the file system',
input: z.object({
before: z.string().describe('Current file path'),
after: z.string().describe('New file path'),
}),
handler: async ({ before, after }) => {
const { path: oldKey } = parseFilePath(before)
const { path: newKey, file, folder } = parseFilePath(after)
await client.copyFile({
idOrKey: oldKey,
destinationKey: newKey,
overwrite: true,
})
await client.deleteFile({ id: oldKey })
await client.updateFileMetadata({
id: newKey,
tags: {
purpose: 'file-system',
folder: folder || '/',
name: file,
},
})
},
}),
],
})