veryfront 0.1.565 → 0.1.567
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/cli/shared/project-source-context.d.ts +1 -0
- package/esm/cli/shared/project-source-context.d.ts.map +1 -1
- package/esm/cli/shared/project-source-context.js +3 -2
- package/esm/cli/templates/manifest.js +2 -2
- package/esm/deno.js +1 -1
- package/esm/src/agent/runtime/text-generation-runtime-message-converter.d.ts.map +1 -1
- package/esm/src/agent/runtime/text-generation-runtime-message-converter.js +1 -9
- package/esm/src/chat/message-prep.d.ts.map +1 -1
- package/esm/src/chat/message-prep.js +54 -1
- package/esm/src/chat/types.js +1 -1
- package/esm/src/embedding/upload-handler.d.ts.map +1 -1
- package/esm/src/embedding/upload-handler.js +4 -4
- package/esm/src/security/input-validation/parsers.d.ts.map +1 -1
- package/esm/src/security/input-validation/parsers.js +4 -4
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ export interface ProjectSourceExecutionContext {
|
|
|
13
13
|
projectId?: string;
|
|
14
14
|
proxyContext?: ProxyProjectSourceContext;
|
|
15
15
|
}
|
|
16
|
+
export declare function getProxyProjectSourceContext(): ProxyProjectSourceContext | null;
|
|
16
17
|
export declare function withProjectSourceContext<T>(projectDir: string, run: (context: ProjectSourceExecutionContext) => Promise<T>): Promise<T>;
|
|
17
18
|
export {};
|
|
18
19
|
//# sourceMappingURL=project-source-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-source-context.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/project-source-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,6BAA6B,CAAC;AAErC,UAAU,yBAAyB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,yBAAyB,CAAC;CAC1C;
|
|
1
|
+
{"version":3,"file":"project-source-context.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/project-source-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,6BAA6B,CAAC;AAErC,UAAU,yBAAyB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,yBAAyB,CAAC;CAC1C;AAED,wBAAgB,4BAA4B,IAAI,yBAAyB,GAAG,IAAI,CAkB/E;AAWD,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,OAAO,CAAC,CAAC,CAAC,GAC1D,OAAO,CAAC,CAAC,CAAC,CAwCZ"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { getConfig } from "../../src/config/index.js";
|
|
2
2
|
import { enhanceAdapterWithFS, getEnv, isExtendedFSAdapter, runtime, } from "../../src/platform/index.js";
|
|
3
|
-
function getProxyProjectSourceContext() {
|
|
3
|
+
export function getProxyProjectSourceContext() {
|
|
4
4
|
const projectSlug = getEnv("VERYFRONT_PROJECT_SLUG")?.trim();
|
|
5
5
|
const token = getEnv("VERYFRONT_API_TOKEN")?.trim();
|
|
6
6
|
if (!projectSlug || !token) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
9
9
|
const projectId = getEnv("VERYFRONT_PROJECT_ID")?.trim();
|
|
10
|
-
const branchRef = getEnv("VERYFRONT_BRANCH_REF")?.trim()
|
|
10
|
+
const branchRef = getEnv("VERYFRONT_BRANCH_REF")?.trim() ||
|
|
11
|
+
getEnv("TENANT_BRANCH_ID")?.trim();
|
|
11
12
|
return {
|
|
12
13
|
projectSlug,
|
|
13
14
|
token,
|
|
@@ -197,12 +197,12 @@ export default {
|
|
|
197
197
|
".env.example": "# Atlassian OAuth credentials\n# Get these from: https://developer.atlassian.com/console/myapps/\nATLASSIAN_CLIENT_ID=your_client_id_here\nATLASSIAN_CLIENT_SECRET=your_client_secret_here\n",
|
|
198
198
|
"app/api/auth/confluence/callback/route.ts": "import { confluenceConfig, createOAuthCallbackHandler } from \"veryfront/oauth\";\nimport { tokenStore } from \"../../../../../lib/token-store.ts\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\n\nconst hybridTokenStore = {\n getTokens(serviceId: string, userId: string) {\n return tokenStore.getToken(userId, serviceId);\n },\n async setTokens(\n serviceId: string,\n userId: string,\n tokens: { accessToken: string; refreshToken?: string; expiresAt?: number },\n ) {\n await tokenStore.setToken(userId, serviceId, tokens);\n },\n async clearTokens(serviceId: string, userId: string) {\n await tokenStore.revokeToken(userId, serviceId);\n },\n setState(\n state: string,\n meta: {\n userId: string;\n serviceId: string;\n codeVerifier?: string;\n redirectUri?: string;\n scopes?: string[];\n createdAt: number;\n },\n ) {\n return oauthMemoryTokenStore.setState(state, meta);\n },\n consumeState(state: string) {\n return oauthMemoryTokenStore.consumeState(state);\n },\n};\n\nexport const GET = createOAuthCallbackHandler(confluenceConfig, { tokenStore: hybridTokenStore });\n",
|
|
199
199
|
"app/api/auth/confluence/route.ts": "import { confluenceConfig, createOAuthInitHandler } from \"veryfront/oauth\";\nimport { oauthMemoryTokenStore } from \"../../../../../lib/oauth-memory-store.ts\";\nimport { requireUserIdFromRequest } from \"../../../../../lib/user-id.ts\";\n\nfunction getUserId(request: Request): string {\n return requireUserIdFromRequest(request);\n}\n\nexport const GET = createOAuthInitHandler(confluenceConfig, {\n tokenStore: oauthMemoryTokenStore,\n getUserId,\n});",
|
|
200
|
-
"lib/confluence-client.ts": "import { getAccessToken, getCloudId } from \"./token-store.ts\";\n\nconst CONFLUENCE_API_BASE = \"https://api.atlassian.com/ex/confluence\";\n\ninterface ConfluenceResponse<T> {\n results: T[];\n size
|
|
200
|
+
"lib/confluence-client.ts": "import { getAccessToken, getCloudId } from \"./token-store.ts\";\n\nconst CONFLUENCE_API_BASE = \"https://api.atlassian.com/ex/confluence\";\n\ninterface ConfluenceResponse<T> {\n results: T[];\n size?: number;\n start?: number;\n limit?: number;\n _links?: {\n next?: string;\n base?: string;\n };\n}\n\nexport interface ConfluenceSpace {\n id: string;\n key: string;\n name: string;\n type: string;\n status: string;\n _links: {\n webui: string;\n };\n}\n\nexport type ConfluencePageType = \"page\" | \"blogpost\";\n\nexport interface ConfluencePage {\n id: string;\n type?: ConfluencePageType;\n status: string;\n title: string;\n spaceId?: string;\n parentId?: string;\n version: {\n number: number;\n message?: string;\n };\n body?: {\n storage?: {\n value: string;\n representation: \"storage\";\n };\n view?: {\n value: string;\n representation: \"view\";\n };\n };\n _links: {\n webui: string;\n tinyui?: string;\n };\n}\n\nexport interface ConfluenceSearchResult {\n content: {\n id: string;\n type: string;\n status: string;\n title: string;\n space?: {\n id: string;\n key: string;\n name: string;\n };\n history?: {\n lastUpdated: {\n when: string;\n };\n };\n _links: {\n webui: string;\n };\n };\n excerpt?: string;\n url: string;\n resultGlobalContainer?: {\n title: string;\n };\n}\n\nexport class ConfluenceApiError extends Error {\n constructor(public readonly status: number, message: string) {\n super(message);\n this.name = \"ConfluenceApiError\";\n }\n}\n\nasync function confluenceFetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n const [token, cloudId] = await Promise.all([getAccessToken(), getCloudId()]);\n\n if (!token || !cloudId) {\n throw new Error(\"Not authenticated with Confluence. Please connect your Atlassian account.\");\n }\n\n const url = `${CONFLUENCE_API_BASE}/${cloudId}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = (await response.json().catch(() => ({}))) as { message?: string };\n throw new ConfluenceApiError(\n response.status,\n `Confluence API error: ${response.status} ${error.message ?? response.statusText}`,\n );\n }\n\n return response.json() as Promise<T>;\n}\n\nfunction buildEndpoint(path: string, params?: URLSearchParams): string {\n const query = params?.toString();\n return `${path}${query ? `?${query}` : \"\"}`;\n}\n\n// Uses Confluence v2 — v1 /wiki/rest/api/space is deprecated alongside /content.\nexport async function listSpaces(options?: {\n limit?: number;\n type?: \"global\" | \"personal\";\n}): Promise<ConfluenceSpace[]> {\n const params = new URLSearchParams();\n\n if (options?.limit) params.set(\"limit\", options.limit.toString());\n if (options?.type) params.set(\"type\", options.type);\n\n const response = await confluenceFetch<ConfluenceResponse<ConfluenceSpace>>(\n buildEndpoint(\"/wiki/api/v2/spaces\", params),\n );\n\n return response.results ?? [];\n}\n\n// Direct key lookup via v2 — avoids the v1 enumeration trap that capped at 250 spaces\n// and silently failed on enterprise tenancies with hundreds of spaces.\nasync function getSpaceIdByKey(spaceKey: string): Promise<string> {\n const params = new URLSearchParams();\n params.set(\"keys\", spaceKey);\n params.set(\"limit\", \"1\");\n\n const response = await confluenceFetch<ConfluenceResponse<ConfluenceSpace>>(\n buildEndpoint(\"/wiki/api/v2/spaces\", params),\n );\n\n const space = response.results?.[0];\n if (!space) {\n throw new Error(`Confluence space not found: ${spaceKey}`);\n }\n return space.id;\n}\n\nexport async function searchContent(\n query: string,\n options?: {\n cql?: string;\n limit?: number;\n spaceKey?: string;\n },\n): Promise<ConfluenceSearchResult[]> {\n const params = new URLSearchParams();\n\n let cqlQuery = options?.cql ?? `title ~ \"${query}\" OR text ~ \"${query}\"`;\n if (options?.spaceKey) cqlQuery += ` AND space = \"${options.spaceKey}\"`;\n\n params.set(\"cql\", cqlQuery);\n if (options?.limit) params.set(\"limit\", options.limit.toString());\n\n const response = await confluenceFetch<ConfluenceResponse<ConfluenceSearchResult>>(\n buildEndpoint(\"/wiki/rest/api/search\", params),\n );\n\n return response.results ?? [];\n}\n\n// v2 splits pages and blogposts into separate resources. Try /pages first;\n// fall back to /blogposts on 404 so search-content → get-page works for both\n// (searchContent returns mixed results and tools/get-page.ts has no type discriminator).\nexport async function getPage(pageId: string): Promise<ConfluencePage> {\n try {\n return await confluenceFetch<ConfluencePage>(\n `/wiki/api/v2/pages/${pageId}?body-format=storage`,\n );\n } catch (error) {\n if (error instanceof ConfluenceApiError && error.status === 404) {\n return await confluenceFetch<ConfluencePage>(\n `/wiki/api/v2/blogposts/${pageId}?body-format=storage`,\n );\n }\n throw error;\n }\n}\n\nexport function getPageContent(pageId: string): Promise<ConfluencePage> {\n return getPage(pageId);\n}\n\nexport async function createPage(options: {\n spaceKey: string;\n title: string;\n content: string;\n parentId?: string;\n type?: ConfluencePageType;\n}): Promise<ConfluencePage> {\n const spaceId = await getSpaceIdByKey(options.spaceKey);\n const type: ConfluencePageType = options.type ?? \"page\";\n\n const body: Record<string, unknown> = {\n spaceId,\n title: options.title,\n status: \"current\",\n body: {\n representation: \"storage\",\n value: options.content,\n },\n };\n\n if (type === \"blogpost\") {\n // v2 blogposts cannot have a parent — surface the user error instead of dropping it silently.\n if (options.parentId) {\n throw new Error(\"Confluence blogposts cannot have a parentId\");\n }\n return confluenceFetch<ConfluencePage>(\"/wiki/api/v2/blogposts\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n }\n\n if (options.parentId) body.parentId = options.parentId;\n\n return confluenceFetch<ConfluencePage>(\"/wiki/api/v2/pages\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n}\n\n// v2 PUT /pages/{id} is a full replace, not PATCH — title and body are both required.\n// Callers must resolve fallbacks (e.g. from a prior getPage) before invoking this.\n// Mirrors getPage's pages-then-blogposts fallback so update-page works on either resource\n// (createPage with type='blogpost' returns a blogpost id that this must accept).\nexport async function updatePage(\n pageId: string,\n options: {\n title: string;\n content: string;\n version: number;\n versionMessage?: string;\n },\n): Promise<ConfluencePage> {\n const body = {\n id: pageId,\n status: \"current\",\n title: options.title,\n body: {\n representation: \"storage\",\n value: options.content,\n },\n version: {\n number: options.version,\n message: options.versionMessage,\n },\n };\n\n const init: RequestInit = {\n method: \"PUT\",\n body: JSON.stringify(body),\n };\n\n try {\n return await confluenceFetch<ConfluencePage>(`/wiki/api/v2/pages/${pageId}`, init);\n } catch (error) {\n if (error instanceof ConfluenceApiError && error.status === 404) {\n return await confluenceFetch<ConfluencePage>(`/wiki/api/v2/blogposts/${pageId}`, init);\n }\n throw error;\n }\n}\n\nexport function extractPlainText(storageHtml: string): string {\n return storageHtml\n .replace(/<[^>]*>/g, \" \")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nexport function formatAsStorage(text: string): string {\n const paragraphs = text.split(\"\\n\\n\").filter((p) => p.trim());\n return paragraphs.map((p) => `<p>${escapeHtml(p.trim())}</p>`).join(\"\\n\");\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n",
|
|
201
201
|
"tools/create-page.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { createPage, formatAsStorage } from \"../../lib/confluence-client.ts\";\n\nexport default tool({\n id: \"create-page\",\n description:\n \"Create a new page in a Confluence space. Can optionally be created as a child of an existing page.\",\n inputSchema: defineSchema((v) => v.object({\n spaceKey: v\n .string()\n .describe('The key of the space to create the page in (e.g., \"TEAM\", \"DEV\")'),\n title: v.string().describe(\"Title of the new page\"),\n content: v\n .string()\n .describe(\n \"Content for the page (can be plain text or Confluence storage format HTML)\",\n ),\n parentId: v\n .string()\n .optional()\n .describe(\"Optional ID of the parent page to create this as a child page\"),\n type: v\n .enum([\"page\", \"blogpost\"])\n .default(\"page\")\n .describe(\"Type of content to create\"),\n }))(),\n async execute({ spaceKey, title, content, parentId, type }) {\n const trimmedContent = content.trim();\n const storageContent = trimmedContent.startsWith(\"<\")\n ? trimmedContent\n : formatAsStorage(trimmedContent);\n\n const page = await createPage({\n spaceKey,\n title,\n content: storageContent,\n parentId,\n type,\n });\n\n return {\n id: page.id,\n title: page.title,\n type: page.type ?? \"page\",\n url: page._links.webui,\n version: page.version.number,\n spaceId: page.spaceId,\n };\n },\n});\n",
|
|
202
202
|
"tools/get-page.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { extractPlainText, getPageContent } from \"../../lib/confluence-client.ts\";\n\nexport default tool({\n id: \"get-page\",\n description:\n \"Get the content of a specific Confluence page. Returns the page title, content, and metadata.\",\n inputSchema: defineSchema((v) => v.object({\n pageId: v.string().describe(\"The ID of the Confluence page to retrieve\"),\n }))(),\n async execute({ pageId }) {\n const page = await getPageContent(pageId);\n\n const htmlContent = page.body?.storage?.value ?? page.body?.view?.value ?? \"\";\n const content = extractPlainText(htmlContent);\n\n return {\n id: page.id,\n type: page.type ?? \"page\",\n title: page.title,\n content,\n htmlContent,\n version: page.version.number,\n url: page._links.webui,\n spaceId: page.spaceId,\n parentId: page.parentId,\n };\n },\n});\n",
|
|
203
203
|
"tools/list-spaces.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { listSpaces } from \"../../lib/confluence-client.ts\";\n\nexport default tool({\n id: \"list-spaces\",\n description: \"List all accessible Confluence spaces. Returns space keys, names, and links.\",\n inputSchema: defineSchema((v) => v.object({\n type: v\n .enum([\"global\", \"personal\", \"all\"])\n .default(\"all\")\n .describe(\"Type of spaces to list (global, personal, or all)\"),\n limit: v\n .number()\n .min(1)\n .max(100)\n .default(25)\n .describe(\"Maximum number of spaces to return\"),\n }))(),\n async execute({ type, limit }) {\n const spaces = await listSpaces({\n type: type === \"all\" ? undefined : type,\n limit,\n });\n\n return spaces.map(({ id, key, name, type, status, _links }) => ({\n id,\n key,\n name,\n type,\n status,\n url: _links.webui,\n }));\n },\n});\n",
|
|
204
204
|
"tools/search-content.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { searchContent } from \"../../lib/confluence-client.ts\";\n\nexport default tool({\n id: \"search-content\",\n description:\n \"Search for pages and blog posts in Confluence. Returns matching content with titles, excerpts, and links.\",\n inputSchema: defineSchema((v) => v.object({\n query: v.string().describe(\"Search query to find pages or blog posts\"),\n spaceKey: v\n .string()\n .optional()\n .describe(\"Optional space key to limit search to a specific space\"),\n limit: v\n .number()\n .min(1)\n .max(50)\n .default(10)\n .describe(\"Maximum number of results to return\"),\n }))(),\n async execute({ query, spaceKey, limit }) {\n const results = await searchContent(query, { spaceKey, limit });\n\n return results.map((result) => {\n const { content, excerpt, url } = result;\n const space = content.space;\n\n return {\n id: content.id,\n type: content.type,\n title: content.title,\n excerpt,\n url,\n space: space\n ? {\n id: space.id,\n key: space.key,\n name: space.name,\n }\n : undefined,\n lastUpdated: content.history?.lastUpdated.when,\n };\n });\n },\n});\n",
|
|
205
|
-
"tools/update-page.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { formatAsStorage, getPage, updatePage } from \"../../lib/confluence-client.ts\";\n\nfunction toStorageContent(content?: string): string | undefined {\n if (!content) return undefined;\n\n const trimmed = content.trim();\n if (trimmed.startsWith(\"<\")) return content;\n\n return formatAsStorage(content);\n}\n\nexport default tool({\n id: \"update-page\",\n description:\n \"Update the content or title of an existing Confluence page. Requires the current version number.\",\n inputSchema: defineSchema((v) => v.object({\n pageId: v.string().describe(\"The ID of the page to update\"),\n title: v\n .string()\n .optional()\n .describe(\"New title for the page (leave empty to keep current title)\"),\n content: v\n .string()\n .optional()\n .describe(\"New content for the page (can be plain text or Confluence storage format HTML)\"),\n versionMessage: v\n .string()\n .optional()\n .describe(\"Optional message describing the changes made\"),\n }))(),\n async execute({ pageId, title, content, versionMessage }) {\n const currentPage = await getPage(pageId
|
|
205
|
+
"tools/update-page.ts": "import { tool } from \"veryfront/tool\";\nimport { defineSchema } from \"veryfront/schemas\";\nimport { formatAsStorage, getPage, updatePage } from \"../../lib/confluence-client.ts\";\n\nfunction toStorageContent(content?: string): string | undefined {\n if (!content || !content.trim()) return undefined;\n\n const trimmed = content.trim();\n if (trimmed.startsWith(\"<\")) return content;\n\n return formatAsStorage(content);\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n return value && value.trim() ? value : undefined;\n}\n\nexport default tool({\n id: \"update-page\",\n description:\n \"Update the content or title of an existing Confluence page. Requires the current version number.\",\n inputSchema: defineSchema((v) => v.object({\n pageId: v.string().describe(\"The ID of the page to update\"),\n title: v\n .string()\n .optional()\n .describe(\"New title for the page (leave empty to keep current title)\"),\n content: v\n .string()\n .optional()\n .describe(\"New content for the page (can be plain text or Confluence storage format HTML)\"),\n versionMessage: v\n .string()\n .optional()\n .describe(\"Optional message describing the changes made\"),\n }))(),\n async execute({ pageId, title, content, versionMessage }) {\n // v2 PUT /pages/{id} is a full replace — both title and body must be sent on every\n // update. Resolve missing fields from the current page so partial updates work.\n // The schema describes empty values as \"keep current\", so treat empty/whitespace\n // strings as unset (??-fallback would otherwise let \"\" overwrite a real title).\n const currentPage = await getPage(pageId);\n const storageContent = toStorageContent(content);\n const currentBody = currentPage.body?.storage?.value ?? \"\";\n\n const updatedPage = await updatePage(pageId, {\n title: nonEmpty(title) ?? currentPage.title,\n content: storageContent ?? currentBody,\n version: currentPage.version.number + 1,\n versionMessage,\n });\n\n return {\n id: updatedPage.id,\n title: updatedPage.title,\n type: updatedPage.type ?? \"page\",\n url: updatedPage._links.webui,\n version: updatedPage.version.number,\n versionMessage: updatedPage.version.message,\n };\n },\n});\n"
|
|
206
206
|
}
|
|
207
207
|
},
|
|
208
208
|
"integration:discord": {
|
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-generation-runtime-message-converter.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/text-generation-runtime-message-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAGV,4BAA4B,EAI7B,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAGL,KAAK,OAAO,EAGb,MAAM,aAAa,CAAC;AA0ErB;;GAEG;AACH,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,OAAO,GAAG,4BAA4B,CA2FhG;AA8BD;;GAEG;AACH,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,OAAO,EAAE,GAClB,4BAA4B,EAAE,
|
|
1
|
+
{"version":3,"file":"text-generation-runtime-message-converter.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/text-generation-runtime-message-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAGV,4BAA4B,EAI7B,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAGL,KAAK,OAAO,EAGb,MAAM,aAAa,CAAC;AA0ErB;;GAEG;AACH,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,OAAO,GAAG,4BAA4B,CA2FhG;AA8BD;;GAEG;AACH,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,OAAO,EAAE,GAClB,4BAA4B,EAAE,CA4BhC"}
|
|
@@ -181,7 +181,6 @@ function hasProviderSendableAssistantContent(message) {
|
|
|
181
181
|
*/
|
|
182
182
|
export function convertToTextGenerationRuntimeMessages(messages) {
|
|
183
183
|
const textGenerationRuntimeMessages = [];
|
|
184
|
-
const toolResultMessageIndexes = new Map();
|
|
185
184
|
for (const message of messages) {
|
|
186
185
|
if (!hasProviderSendableAssistantContent(message)) {
|
|
187
186
|
continue;
|
|
@@ -196,14 +195,7 @@ export function convertToTextGenerationRuntimeMessages(messages) {
|
|
|
196
195
|
continue;
|
|
197
196
|
}
|
|
198
197
|
for (const toolResultPart of toolResultParts) {
|
|
199
|
-
|
|
200
|
-
const existingIndex = toolResultMessageIndexes.get(toolResultPart.toolCallId);
|
|
201
|
-
if (existingIndex === undefined) {
|
|
202
|
-
toolResultMessageIndexes.set(toolResultPart.toolCallId, textGenerationRuntimeMessages.length);
|
|
203
|
-
textGenerationRuntimeMessages.push(toolResultMessage);
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
textGenerationRuntimeMessages[existingIndex] = toolResultMessage;
|
|
198
|
+
textGenerationRuntimeMessages.push(convertToolResultPart(toolResultPart));
|
|
207
199
|
}
|
|
208
200
|
}
|
|
209
201
|
return textGenerationRuntimeMessages;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-prep.d.ts","sourceRoot":"","sources":["../../../src/src/chat/message-prep.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAC;AAQjC,OAAO,EAKL,KAAK,aAAa,EAGlB,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAIpB,uBAAuB;AACvB,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAErD;AAOD,qBAAqB;AACrB,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,oBAAoB,EAAE,EAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,oBAAoB,EAAE,CAiCxB;AAqCD,kDAAkD;AAClD,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,oBAAoB,EAAE,EAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,oBAAoB,EAAE,CAiExB;AA+BD,4DAA4D;AAC5D,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED,gDAAgD;AAChD,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAwB7F;AAED,qDAAqD;AACrD,wBAAgB,wCAAwC,CACtD,QAAQ,EAAE,aAAa,EAAE,GACxB,aAAa,EAAE,CAmDjB;
|
|
1
|
+
{"version":3,"file":"message-prep.d.ts","sourceRoot":"","sources":["../../../src/src/chat/message-prep.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAC;AAQjC,OAAO,EAKL,KAAK,aAAa,EAGlB,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAIpB,uBAAuB;AACvB,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAErD;AAOD,qBAAqB;AACrB,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,oBAAoB,EAAE,EAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,oBAAoB,EAAE,CAiCxB;AAqCD,kDAAkD;AAClD,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,oBAAoB,EAAE,EAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,oBAAoB,EAAE,CAiExB;AA+BD,4DAA4D;AAC5D,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED,gDAAgD;AAChD,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAwB7F;AAED,qDAAqD;AACrD,wBAAgB,wCAAwC,CACtD,QAAQ,EAAE,aAAa,EAAE,GACxB,aAAa,EAAE,CAmDjB;AAyCD,gCAAgC;AAChC,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE,CAiBhF;AAsFD,wCAAwC;AACxC,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,oBAAoB,EAAE,GAC/B,oBAAoB,EAAE,CAwBxB;AAED;;GAEG;AACH,4CAA4C;AAC5C,eAAO,MAAM,qBAAqB,sCAAgC,CAAC;AAYnE,wDAAwD;AACxD,wBAAgB,0CAA0C,CACxD,QAAQ,EAAE,aAAa,EAAE,GACxB,oBAAoB,EAAE,CAiBxB;AA4FD,6BAA6B;AAC7B,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CAsE3F;AAWD,yBAAyB;AACzB,wBAAgB,eAAe,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CA4IxF;AAED,yBAAyB;AACzB,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGjF;AAED,sCAAsC;AACtC,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CA4B7F;AAED,wBAAwB;AACxB,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,oBAAoB,EAAE,EAChC,QAAQ,GAAE,MAAU,GACnB,oBAAoB,EAAE,CAexB;AAED,2BAA2B;AAC3B,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CA0D1F;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,oBAAoB,EAAE,EAChC,MAAM,GAAE,MAA6B,EACrC,QAAQ,GAAE,MAAU,GACnB,oBAAoB,EAAE,CAMxB;AAED;;GAEG;AACH,4DAA4D;AAC5D,eAAO,MAAM,kCAAkC,mDAA6C,CAAC"}
|
|
@@ -237,6 +237,25 @@ function isPendingToolPart(part) {
|
|
|
237
237
|
}
|
|
238
238
|
return part.type === "dynamic-tool" || part.type === "tool_call" || part.type.startsWith("tool-");
|
|
239
239
|
}
|
|
240
|
+
function getToolPartCallId(part) {
|
|
241
|
+
if (!isRecord(part)) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const toolCallId = part.toolCallId;
|
|
245
|
+
return typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : null;
|
|
246
|
+
}
|
|
247
|
+
function isToolLikePart(part) {
|
|
248
|
+
return isRecord(part) && typeof part.type === "string" &&
|
|
249
|
+
(part.type === "dynamic-tool" || part.type === "tool_call" || part.type.startsWith("tool-"));
|
|
250
|
+
}
|
|
251
|
+
function hasToolState(part, state) {
|
|
252
|
+
return isRecord(part) && part.state === state && isToolLikePart(part);
|
|
253
|
+
}
|
|
254
|
+
function isToolErrorState(part) {
|
|
255
|
+
return isRecord(part) &&
|
|
256
|
+
(part.state === "output-error" || part.state === "output-denied" || part.state === "error") &&
|
|
257
|
+
isToolLikePart(part);
|
|
258
|
+
}
|
|
240
259
|
/** Strip pending tool parts. */
|
|
241
260
|
export function stripPendingToolParts(messages) {
|
|
242
261
|
return messages.flatMap((message) => {
|
|
@@ -253,6 +272,39 @@ export function stripPendingToolParts(messages) {
|
|
|
253
272
|
return [{ ...message, parts }];
|
|
254
273
|
});
|
|
255
274
|
}
|
|
275
|
+
function stripSupersededToolErrorParts(messages) {
|
|
276
|
+
return messages.flatMap((message) => {
|
|
277
|
+
if (message.role !== "assistant" || message.parts.length === 0) {
|
|
278
|
+
return [message];
|
|
279
|
+
}
|
|
280
|
+
const completedToolCallIds = new Set();
|
|
281
|
+
for (const part of message.parts) {
|
|
282
|
+
if (hasToolState(part, "output-available")) {
|
|
283
|
+
const toolCallId = getToolPartCallId(part);
|
|
284
|
+
if (toolCallId) {
|
|
285
|
+
completedToolCallIds.add(toolCallId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (completedToolCallIds.size === 0) {
|
|
290
|
+
return [message];
|
|
291
|
+
}
|
|
292
|
+
const parts = message.parts.filter((part) => {
|
|
293
|
+
if (!isToolErrorState(part)) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
const toolCallId = getToolPartCallId(part);
|
|
297
|
+
return !toolCallId || !completedToolCallIds.has(toolCallId);
|
|
298
|
+
});
|
|
299
|
+
if (parts.length === message.parts.length) {
|
|
300
|
+
return [message];
|
|
301
|
+
}
|
|
302
|
+
if (parts.length === 0) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
return [{ ...message, parts }];
|
|
306
|
+
});
|
|
307
|
+
}
|
|
256
308
|
function isKeepableModelPart(part, includeReasoning) {
|
|
257
309
|
if (!isRecord(part) || typeof part.type !== "string")
|
|
258
310
|
return false;
|
|
@@ -344,7 +396,8 @@ export function prepareProviderModelMessagesFromUiMessages(messages) {
|
|
|
344
396
|
const validMessages = messages.filter((message) => message && typeof message === "object" && "role" in message);
|
|
345
397
|
const normalizedMessages = normalizeMessageFilePartMediaTypes(validMessages);
|
|
346
398
|
const strippedPendingToolMessages = stripPendingToolParts(normalizedMessages);
|
|
347
|
-
const
|
|
399
|
+
const strippedSupersededToolMessages = stripSupersededToolErrorParts(strippedPendingToolMessages);
|
|
400
|
+
const rewrittenMessages = rewriteUnsupportedFilePartsAsAnnotations(strippedSupersededToolMessages);
|
|
348
401
|
const providerModelMessages = convertUiMessagesToProviderModelMessages(rewrittenMessages);
|
|
349
402
|
const patchedMessages = ensureToolCallInputs(dedupeToolHistory(providerModelMessages));
|
|
350
403
|
const sanitized = sanitizeProviderModelMessages(patchedMessages);
|
package/esm/src/chat/types.js
CHANGED
|
@@ -111,7 +111,7 @@ export const getMessageMetadataSchema = defineSchema((v) => v.object({
|
|
|
111
111
|
*/
|
|
112
112
|
export const messageMetadataSchema = lazySchema(getMessageMetadataSchema);
|
|
113
113
|
/** Zod schema for get chat UI message role. */
|
|
114
|
-
export const getChatUiMessageRoleSchema = defineSchema((v) => v.enum(["system", "user", "assistant"]));
|
|
114
|
+
export const getChatUiMessageRoleSchema = defineSchema((v) => v.enum(["system", "user", "assistant", "tool"]));
|
|
115
115
|
/** Schema for chat ui message role.
|
|
116
116
|
* @deprecated Use getChatUiMessageRoleSchema()
|
|
117
117
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"upload-handler.d.ts","sourceRoot":"","sources":["../../../src/src/embedding/upload-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqF3C,UAAU,mBAAmB;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA2CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,EACf,MAAM,CAAC,EAAE,mBAAmB;oBAIC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;eA8ElC,OAAO,CAAC,QAAQ,CAAC;uBAW3B,OAAO,WACR;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,KAC1C,OAAO,CAAC,QAAQ,CAAC;EA0BrB"}
|
|
@@ -2,9 +2,9 @@ import { isVeryfrontCloudEnabled } from "../platform/cloud/resolver.js";
|
|
|
2
2
|
import { VeryfrontCloudBlobStorage } from "../workflow/blob/veryfront-cloud-storage.js";
|
|
3
3
|
import { serverLogger } from "../utils/index.js";
|
|
4
4
|
import { loadUpload } from "./upload-loader.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import * as nodeBuffer from "node:buffer";
|
|
6
|
+
const FileCtor = globalThis.File ??
|
|
7
|
+
nodeBuffer.File;
|
|
8
8
|
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
|
|
9
9
|
const MAX_FILE_NAME_LENGTH = 200;
|
|
10
10
|
const CLOUD_UPLOAD_PREFIX = ".veryfront/rag/uploads/";
|
|
@@ -145,7 +145,7 @@ export function createUploadHandler(store, config) {
|
|
|
145
145
|
try {
|
|
146
146
|
const formData = await request.formData();
|
|
147
147
|
const file = formData.get("file");
|
|
148
|
-
if (!file || !(file instanceof
|
|
148
|
+
if (!file || !(file instanceof FileCtor)) {
|
|
149
149
|
return Response.json({ error: "No file provided" }, { status: 400 });
|
|
150
150
|
}
|
|
151
151
|
if (file.size > maxSize) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parsers.d.ts","sourceRoot":"","sources":["../../../../src/src/security/input-validation/parsers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAI/D,OAAO,EAAkB,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"parsers.d.ts","sourceRoot":"","sources":["../../../../src/src/security/input-validation/parsers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAI/D,OAAO,EAAkB,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAM1F,8CAA8C;AAC9C,wBAAsB,aAAa,CAAC,CAAC,EACnC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,CAAC,CAAC,CA6BZ;AAED,6DAA6D;AAC7D,wBAAsB,aAAa,CAAC,CAAC,EACnC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,CAAC,CAAC,CA0BZ;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CA2B1E"}
|
|
@@ -2,9 +2,9 @@ import { createValidationError, VeryfrontError } from "./errors.js";
|
|
|
2
2
|
import { readBodyWithLimit, validateContentType, validateRequestLimits } from "./limits.js";
|
|
3
3
|
import { sanitizeData } from "./sanitizers.js";
|
|
4
4
|
import { DEFAULT_LIMITS } from "./types.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import * as nodeBuffer from "node:buffer";
|
|
6
|
+
const FileCtor = globalThis.File ??
|
|
7
|
+
nodeBuffer.File;
|
|
8
8
|
/** Parse and validate a JSON request body. */
|
|
9
9
|
export async function parseJsonBody(request, schema, options) {
|
|
10
10
|
validateRequestLimits(request, options?.limits);
|
|
@@ -42,7 +42,7 @@ export async function parseFormData(request, schema, options) {
|
|
|
42
42
|
const data = {};
|
|
43
43
|
const maxFileSize = options?.limits?.maxFileSize ?? DEFAULT_LIMITS.maxFileSize;
|
|
44
44
|
for (const [key, value] of formData.entries()) {
|
|
45
|
-
if (value instanceof
|
|
45
|
+
if (value instanceof FileCtor && value.size > maxFileSize) {
|
|
46
46
|
throw createValidationError(`File ${key} too large`, {
|
|
47
47
|
maxSize: maxFileSize,
|
|
48
48
|
actualSize: value.size,
|