diff --git a/apps/agentstack-sdk-ts/package.json b/apps/agentstack-sdk-ts/package.json index 67d13bdf1..286a4ccac 100644 --- a/apps/agentstack-sdk-ts/package.json +++ b/apps/agentstack-sdk-ts/package.json @@ -4,8 +4,8 @@ "version": "0.4.4", "type": "module", "scripts": { - "build": "rimraf dist && microbundle --format modern,cjs,umd", - "dev": "microbundle watch" + "build": "rimraf dist && microbundle --format modern,cjs,umd src/*.ts", + "dev": "microbundle watch src/*.ts" }, "source": "src/index.ts", "repository": { @@ -25,13 +25,53 @@ "types": "./dist/index.d.ts", "default": "./dist/index.js" }, - "./types": { + "./api": { "require": { - "types": "./dist/types/index.d.cts" + "types": "./dist/api.d.cts", + "default": "./dist/api.cjs" }, "import": { - "types": "./dist/types/index.d.ts" - } + "types": "./dist/api.d.ts", + "default": "./dist/api.js" + }, + "types": "./dist/api.d.ts", + "default": "./dist/api.js" + }, + "./client": { + "require": { + "types": "./dist/client.d.cts", + "default": "./dist/client.cjs" + }, + "import": { + "types": "./dist/client.d.ts", + "default": "./dist/client.js" + }, + "types": "./dist/client.d.ts", + "default": "./dist/client.js" + }, + "./errors": { + "require": { + "types": "./dist/errors.d.cts", + "default": "./dist/errors.cjs" + }, + "import": { + "types": "./dist/errors.d.ts", + "default": "./dist/errors.js" + }, + "types": "./dist/errors.d.ts", + "default": "./dist/errors.js" + }, + "./extensions": { + "require": { + "types": "./dist/extensions.d.cts", + "default": "./dist/extensions.cjs" + }, + "import": { + "types": "./dist/extensions.d.ts", + "default": "./dist/extensions.js" + }, + "types": "./dist/extensions.d.ts", + "default": "./dist/extensions.js" }, "./package.json": "./package.json" }, diff --git a/apps/agentstack-sdk-ts/src/api.ts b/apps/agentstack-sdk-ts/src/api.ts new file mode 100644 index 000000000..2a85d562e --- /dev/null +++ b/apps/agentstack-sdk-ts/src/api.ts @@ -0,0 +1,7 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './client/api/schemas'; +export * from './client/api/types'; diff --git a/apps/agentstack-sdk-ts/src/client.ts b/apps/agentstack-sdk-ts/src/client.ts new file mode 100644 index 000000000..32b4d265c --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client.ts @@ -0,0 +1,7 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './client/client'; +export * from './client/client/types'; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/index.ts new file mode 100644 index 000000000..5c2046e76 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/index.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AServiceExtension, A2AUiExtension } from '../../../runtime/types'; +import { oAuthDemandsSchema, oAuthFulfillmentsSchema, oAuthRequestSchema } from './schemas'; +import type { OAuthDemands, OAuthFulfillments, OAuthRequest } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/auth/oauth/v1'; + +export const oAuthExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => oAuthDemandsSchema, + getFulfillmentsSchema: () => oAuthFulfillmentsSchema, +}; + +export const oAuthRequestExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: oAuthRequestSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/schemas.ts new file mode 100644 index 000000000..40aea9c14 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/schemas.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const oAuthDemandSchema = z.object({ + redirect_uri: z.boolean(), +}); + +export const oAuthDemandsSchema = z.object({ + oauth_demands: z.record(z.string(), oAuthDemandSchema), +}); + +export const oAuthFulfillmentSchema = z.object({ + redirect_uri: z.string(), +}); + +export const oAuthFulfillmentsSchema = z.object({ + oauth_fulfillments: z.record(z.string(), oAuthFulfillmentSchema), +}); + +export const oAuthRequestSchema = z.object({ + authorization_endpoint_url: z.string(), +}); + +export const oAuthResponseSchema = z.object({ + redirect_uri: z.string(), +}); + +export const oAuthMessageSchema = z.object({ + data: oAuthResponseSchema, +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/types.ts new file mode 100644 index 000000000..ba1c1f63c --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/oauth/types.ts @@ -0,0 +1,27 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + oAuthDemandSchema, + oAuthDemandsSchema, + oAuthFulfillmentSchema, + oAuthFulfillmentsSchema, + oAuthMessageSchema, + oAuthRequestSchema, + oAuthResponseSchema, +} from './schemas'; + +export type OAuthDemand = z.infer; +export type OAuthDemands = z.infer; + +export type OAuthFulfillment = z.infer; +export type OAuthFulfillments = z.infer; + +export type OAuthRequest = z.infer; +export type OAuthResponse = z.infer; + +export type OAuthMessage = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/index.ts new file mode 100644 index 000000000..e3d0888a6 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/index.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AServiceExtension, A2AUiExtension } from '../../../runtime/types'; +import { secretDemandsSchema, secretFulfillmentsSchema } from './schemas'; +import type { SecretDemands, SecretFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/auth/secrets/v1'; + +export const secretsExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => secretDemandsSchema, + getFulfillmentsSchema: () => secretFulfillmentsSchema, +}; + +export const secretsRequestExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: secretDemandsSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/schemas.ts new file mode 100644 index 000000000..bb6b0e6a1 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/schemas.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const secretDemandSchema = z.object({ + name: z.string(), + description: z.string().nullish(), +}); + +export const secretDemandsSchema = z.object({ + secret_demands: z.record(z.string(), secretDemandSchema), +}); + +export const secretFulfillmentSchema = z.object({ + secret: z.string(), +}); + +export const secretFulfillmentsSchema = z.object({ + secret_fulfillments: z.record(z.string(), secretFulfillmentSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/types.ts new file mode 100644 index 000000000..4299ab59a --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/auth/secrets/types.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + secretDemandSchema, + secretDemandsSchema, + secretFulfillmentSchema, + secretFulfillmentsSchema, +} from './schemas'; + +export type SecretDemand = z.infer; +export type SecretDemands = z.infer; + +export type SecretFulfillment = z.infer; +export type SecretFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/schemas.ts similarity index 50% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form.ts rename to apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/schemas.ts index 039447792..747789bc9 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/schemas.ts @@ -5,55 +5,32 @@ import z from 'zod'; -const baseField = z.object({ +export const baseFieldSchema = z.object({ id: z.string().nonempty(), label: z.string().nonempty(), required: z.boolean(), col_span: z.int().min(1).max(4).nullish(), }); -const textField = baseField.extend({ +export const textFieldSchema = baseFieldSchema.extend({ type: z.literal('text'), placeholder: z.string().nullish(), default_value: z.string().nullish(), auto_resize: z.boolean().default(true).nullish(), }); -export const textFieldValue = z.object({ - type: textField.shape.type, - value: z.string().nullish(), -}); - -const dateField = baseField.extend({ +export const dateFieldSchema = baseFieldSchema.extend({ type: z.literal('date'), placeholder: z.string().nullish(), default_value: z.string().nullish(), }); -export const dateFieldValue = z.object({ - type: dateField.shape.type, - value: z.string().nullish(), -}); - -const fileField = baseField.extend({ +export const fileFieldSchema = baseFieldSchema.extend({ type: z.literal('file'), accept: z.array(z.string()), }); -export const fileFieldValue = z.object({ - type: fileField.shape.type, - value: z - .array( - z.object({ - uri: z.string(), - name: z.string().nullish(), - mime_type: z.string().nullish(), - }), - ) - .nullish(), -}); - -export const singleSelectField = baseField.extend({ +export const singleSelectFieldSchema = baseFieldSchema.extend({ type: z.literal('singleselect'), options: z .array( @@ -66,12 +43,7 @@ export const singleSelectField = baseField.extend({ default_value: z.string().nullish(), }); -export const singleSelectFieldValue = z.object({ - type: singleSelectField.shape.type, - value: z.string().nullish(), -}); - -export const multiSelectField = baseField.extend({ +export const multiSelectFieldSchema = baseFieldSchema.extend({ type: z.literal('multiselect'), options: z .array( @@ -84,29 +56,66 @@ export const multiSelectField = baseField.extend({ default_value: z.array(z.string()).nullish(), }); -export const multiSelectFieldValue = z.object({ - type: multiSelectField.shape.type, - value: z.array(z.string()).nullish(), -}); - -export const checkboxField = baseField.extend({ +export const checkboxFieldSchema = baseFieldSchema.extend({ type: z.literal('checkbox'), content: z.string(), default_value: z.boolean(), }); -export const checkboxFieldValue = z.object({ - type: checkboxField.shape.type, +export const formFieldSchema = z.discriminatedUnion('type', [ + textFieldSchema, + dateFieldSchema, + fileFieldSchema, + singleSelectFieldSchema, + multiSelectFieldSchema, + checkboxFieldSchema, +]); + +export const textFieldValueSchema = z.object({ + type: textFieldSchema.shape.type, + value: z.string().nullish(), +}); + +export const dateFieldValueSchema = z.object({ + type: dateFieldSchema.shape.type, + value: z.string().nullish(), +}); + +export const fileFieldValueSchema = z.object({ + type: fileFieldSchema.shape.type, + value: z + .array( + z.object({ + uri: z.string(), + name: z.string().nullish(), + mime_type: z.string().nullish(), + }), + ) + .nullish(), +}); + +export const singleSelectFieldValueSchema = z.object({ + type: singleSelectFieldSchema.shape.type, + value: z.string().nullish(), +}); + +export const multiSelectFieldValueSchema = z.object({ + type: multiSelectFieldSchema.shape.type, + value: z.array(z.string()).nullish(), +}); + +export const checkboxFieldValueSchema = z.object({ + type: checkboxFieldSchema.shape.type, value: z.boolean().nullish(), }); -const fieldSchema = z.discriminatedUnion('type', [ - textField, - dateField, - fileField, - singleSelectField, - multiSelectField, - checkboxField, +export const formFieldValueSchema = z.discriminatedUnion('type', [ + textFieldValueSchema, + dateFieldValueSchema, + fileFieldValueSchema, + singleSelectFieldValueSchema, + multiSelectFieldValueSchema, + checkboxFieldValueSchema, ]); export const formRenderSchema = z.object({ @@ -114,31 +123,11 @@ export const formRenderSchema = z.object({ description: z.string().nullish(), columns: z.int().min(1).max(4).nullish(), submit_label: z.string().nullish(), - fields: z.array(fieldSchema).nonempty(), + fields: z.array(formFieldSchema).nonempty(), }); +export const formValuesSchema = z.record(z.string(), formFieldValueSchema); + export const formResponseSchema = z.object({ - values: z.record( - z.string(), - z.discriminatedUnion('type', [ - textFieldValue, - dateFieldValue, - fileFieldValue, - singleSelectFieldValue, - multiSelectFieldValue, - checkboxFieldValue, - ]), - ), + values: formValuesSchema, }); - -export type FormRender = z.infer; - -export type TextField = z.infer; -export type DateField = z.infer; -export type FileField = z.infer; -export type SingleSelectField = z.infer; -export type MultiSelectField = z.infer; -export type CheckboxField = z.infer; - -export type FormField = z.infer; -export type FormResponseValue = z.infer['values'][string]; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/types.ts new file mode 100644 index 000000000..ef80600eb --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/common/form/types.ts @@ -0,0 +1,48 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + checkboxFieldSchema, + checkboxFieldValueSchema, + dateFieldSchema, + dateFieldValueSchema, + fileFieldSchema, + fileFieldValueSchema, + formFieldSchema, + formFieldValueSchema, + formRenderSchema, + formResponseSchema, + formValuesSchema, + multiSelectFieldSchema, + multiSelectFieldValueSchema, + singleSelectFieldSchema, + singleSelectFieldValueSchema, + textFieldSchema, + textFieldValueSchema, +} from './schemas'; + +export type TextField = z.infer; +export type DateField = z.infer; +export type FileField = z.infer; +export type SingleSelectField = z.infer; +export type MultiSelectField = z.infer; +export type CheckboxField = z.infer; + +export type FormField = z.infer; + +export type TextFieldValue = z.infer; +export type DateFieldValue = z.infer; +export type FileFieldValue = z.infer; +export type SingleSelectFieldValue = z.infer; +export type MultiSelectFieldValue = z.infer; +export type CheckboxFieldValue = z.infer; + +export type FormFieldValue = z.infer; + +export type FormRender = z.infer; +export type FormValues = z.infer; +export type FormResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-task-status-update.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-task-status-update.ts deleted file mode 100644 index 3b4b438f6..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-task-status-update.ts +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type { TaskStatusUpdateEvent } from '@a2a-js/sdk'; - -import type { FormRender } from './common/form'; -import type { SecretDemands } from './services/secrets'; -import { secretsMessageExtension } from './services/secrets'; -import { FormRequestExtension } from './ui/form-request'; -import { oauthRequestExtension } from './ui/oauth'; -import { extractUiExtensionData } from './utils'; - -const secretsMessageExtensionExtractor = extractUiExtensionData(secretsMessageExtension); -const oauthRequestExtensionExtractor = extractUiExtensionData(oauthRequestExtension); -const FormRequestExtensionExtractor = extractUiExtensionData(FormRequestExtension); - -export enum TaskStatusUpdateType { - SecretRequired = 'secret-required', - FormRequired = 'form-required', - OAuthRequired = 'oauth-required', -} - -export interface SecretRequiredResult { - type: TaskStatusUpdateType.SecretRequired; - demands: SecretDemands; -} - -export interface FormRequiredResult { - type: TaskStatusUpdateType.FormRequired; - form: FormRender; -} - -export interface OAuthRequiredResult { - type: TaskStatusUpdateType.OAuthRequired; - url: string; -} - -export type TaskStatusUpdateResult = SecretRequiredResult | FormRequiredResult | OAuthRequiredResult; - -export const handleTaskStatusUpdate = (event: TaskStatusUpdateEvent): TaskStatusUpdateResult[] => { - const results: TaskStatusUpdateResult[] = []; - - if (event.status.state === 'auth-required') { - const secretRequired = secretsMessageExtensionExtractor(event.status.message?.metadata); - const oauthRequired = oauthRequestExtensionExtractor(event.status.message?.metadata); - - if (oauthRequired) { - results.push({ - type: TaskStatusUpdateType.OAuthRequired, - url: oauthRequired.authorization_endpoint_url, - }); - } - - if (secretRequired) { - results.push({ - type: TaskStatusUpdateType.SecretRequired, - demands: secretRequired, - }); - } - } else if (event.status.state === 'input-required') { - const formRequired = FormRequestExtensionExtractor(event.status.message?.metadata); - - if (formRequired) { - results.push({ - type: TaskStatusUpdateType.FormRequired, - form: formRequired, - }); - } - } - - return results; -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/index.ts new file mode 100644 index 000000000..9c576b043 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/index.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './auth/oauth'; +export * from './auth/secrets'; +export * from './services/embedding'; +export * from './services/form'; +export * from './services/llm'; +export * from './services/mcp'; +export * from './services/platform-api'; +export * from './ui/agent-detail'; +export * from './ui/canvas'; +export * from './ui/citation'; +export * from './ui/error'; +export * from './ui/form-request'; +export * from './ui/settings'; +export * from './ui/trajectory'; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/resolve-user-metadata.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/resolve-user-metadata.ts deleted file mode 100644 index eb52edac6..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/resolve-user-metadata.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type { FormResponseValue } from './common/form'; -import { type CanvasEditRequest, CanvasExtension } from './ui/canvas'; -import { FormRequestExtension } from './ui/form-request'; - -export type UserMetadataInputs = Partial<{ - form: Record; - canvasEditRequest: CanvasEditRequest; -}>; - -export const resolveUserMetadata = async (inputs: UserMetadataInputs) => { - const metadata: Record = {}; - - const { form, canvasEditRequest } = inputs; - - if (form) { - metadata[FormRequestExtension.getUri()] = { - values: form, - }; - } - if (canvasEditRequest) { - metadata[CanvasExtension.getUri()] = canvasEditRequest; - } - - return metadata; -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/schemas.ts new file mode 100644 index 000000000..4b7d7bb9a --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/schemas.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './auth/oauth/schemas'; +export * from './auth/secrets/schemas'; +export * from './common/form/schemas'; +export * from './services/embedding/schemas'; +export * from './services/form/schemas'; +export * from './services/llm/schemas'; +export * from './services/mcp/schemas'; +export * from './services/platform-api/schemas'; +export * from './ui/agent-detail/schemas'; +export * from './ui/canvas/schemas'; +export * from './ui/citation/schemas'; +export * from './ui/error/schemas'; +export * from './ui/settings/schemas'; +export * from './ui/trajectory/schemas'; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding.ts deleted file mode 100644 index 5f1387995..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/embedding/v1'; - -const embeddingDemandSchema = z.object({ - description: z.string().nullish(), - suggested: z.array(z.string()).nullish(), -}); - -const embeddingDemandsSchema = z.object({ - embedding_demands: z.record(z.string(), embeddingDemandSchema), -}); -export type EmbeddingDemands = z.infer; - -const embeddingFulfillmentsSchema = z.object({ - embedding_fulfillments: z.record( - z.string(), - z.object({ - identifier: z.string().nullish(), - api_base: z.string(), - api_key: z.string(), - api_model: z.string(), - }), - ), -}); -export type EmbeddingFulfillments = z.infer; - -export const embeddingExtension: A2AServiceExtension< - typeof URI, - z.infer, - EmbeddingFulfillments -> = { - getUri: () => URI, - getDemandsSchema: () => embeddingDemandsSchema, - getFulfillmentSchema: () => embeddingFulfillmentsSchema, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/index.ts new file mode 100644 index 000000000..75a009e70 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from '../../../runtime/types'; +import { embeddingDemandsSchema, embeddingFulfillmentsSchema } from './schemas'; +import type { EmbeddingDemands, EmbeddingFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/embedding/v1'; + +export const embeddingExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => embeddingDemandsSchema, + getFulfillmentsSchema: () => embeddingFulfillmentsSchema, +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/schemas.ts new file mode 100644 index 000000000..27d36737f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/schemas.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const embeddingDemandSchema = z.object({ + description: z.string().nullish(), + suggested: z.array(z.string()).nullish(), +}); + +export const embeddingDemandsSchema = z.object({ + embedding_demands: z.record(z.string(), embeddingDemandSchema), +}); + +export const embeddingFulfillmentSchema = z.object({ + identifier: z.string().nullish(), + api_base: z.string(), + api_key: z.string(), + api_model: z.string(), +}); + +export const embeddingFulfillmentsSchema = z.object({ + embedding_fulfillments: z.record(z.string(), embeddingFulfillmentSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/types.ts new file mode 100644 index 000000000..287267501 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/embedding/types.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + embeddingDemandSchema, + embeddingDemandsSchema, + embeddingFulfillmentSchema, + embeddingFulfillmentsSchema, +} from './schemas'; + +export type EmbeddingDemand = z.infer; +export type EmbeddingDemands = z.infer; + +export type EmbeddingFulfillment = z.infer; +export type EmbeddingFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form.ts deleted file mode 100644 index 04db23cd1..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import { formRenderSchema, formResponseSchema } from '../common/form'; -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/form/v1'; - -const formDemandSchema = z.object({ - form_demands: z - .object({ - initial_form: formRenderSchema, - }) - .partial(), -}); -export type FormDemands = z.infer; - -const formFulfillmentSchema = z.object({ - form_fulfillments: z.record(z.string(), formResponseSchema), -}); -export type FormFulfillments = z.infer; - -export const formExtension: A2AServiceExtension = { - getDemandsSchema: () => formDemandSchema, - getFulfillmentSchema: () => formFulfillmentSchema, - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/index.ts new file mode 100644 index 000000000..b2f5eeafd --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from '../../../runtime/types'; +import { formDemandsSchema, formFulfillmentsSchema } from './schemas'; +import type { FormDemands, FormFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/form/v1'; + +export const formExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => formDemandsSchema, + getFulfillmentsSchema: () => formFulfillmentsSchema, +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/schemas.ts new file mode 100644 index 000000000..b21cd8a34 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/schemas.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { formRenderSchema, formResponseSchema } from '../../common/form/schemas'; + +export const formDemandsSchema = z.object({ + form_demands: z + .object({ + initial_form: formRenderSchema, + }) + .partial(), +}); + +export const formFulfillmentsSchema = z.object({ + form_fulfillments: z.record(z.string(), formResponseSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/types.ts new file mode 100644 index 000000000..2c35a0f2f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/form/types.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { formDemandsSchema, formFulfillmentsSchema } from './schemas'; + +export type FormDemands = z.infer; + +export type FormFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm.ts deleted file mode 100644 index ce6c383b7..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/llm/v1'; - -const llmDemandSchema = z.object({ - description: z.string().nullish(), - suggested: z.array(z.string()).nullish(), -}); - -const llmDemandsSchema = z.object({ - llm_demands: z.record(z.string(), llmDemandSchema), -}); -export type LLMDemands = z.infer; - -const llmFulfillmentSchema = z.object({ - llm_fulfillments: z.record( - z.string(), - z.object({ - identifier: z.string().nullish(), - api_base: z.string(), - api_key: z.string(), - api_model: z.string(), - }), - ), -}); -export type LLMFulfillments = z.infer; - -export const llmExtension: A2AServiceExtension, LLMFulfillments> = { - getUri: () => URI, - getDemandsSchema: () => llmDemandsSchema, - getFulfillmentSchema: () => llmFulfillmentSchema, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/index.ts new file mode 100644 index 000000000..7a69246a9 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from '../../../runtime/types'; +import { llmDemandsSchema, llmFulfillmentsSchema } from './schemas'; +import type { LLMDemands, LLMFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/llm/v1'; + +export const llmExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => llmDemandsSchema, + getFulfillmentsSchema: () => llmFulfillmentsSchema, +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/schemas.ts new file mode 100644 index 000000000..8dacb6670 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/schemas.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const llmDemandSchema = z.object({ + description: z.string().nullish(), + suggested: z.array(z.string()).nullish(), +}); + +export const llmDemandsSchema = z.object({ + llm_demands: z.record(z.string(), llmDemandSchema), +}); + +export const llmFulfillmentSchema = z.object({ + identifier: z.string().nullish(), + api_base: z.string(), + api_key: z.string(), + api_model: z.string(), +}); + +export const llmFulfillmentsSchema = z.object({ + llm_fulfillments: z.record(z.string(), llmFulfillmentSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/types.ts new file mode 100644 index 000000000..96f24d843 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/llm/types.ts @@ -0,0 +1,14 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { llmDemandSchema, llmDemandsSchema, llmFulfillmentSchema, llmFulfillmentsSchema } from './schemas'; + +export type LLMDemand = z.infer; +export type LLMDemands = z.infer; + +export type LLMFulfillment = z.infer; +export type LLMFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp.ts deleted file mode 100644 index a8d885b2c..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/mcp/v1'; - -const mcpTransportTypesEnum = z.enum(['streamable_http', 'stdio']); -type MCPTransportType = z.infer; - -const mcpDemandSchema = z.object({ - description: z.string().nullish(), - suggested: z.array(z.string()).nullish(), - allowed_transports: z.array(mcpTransportTypesEnum).nullish(), -}); - -const mcpDemandsSchema = z.object({ - mcp_demands: z.record(z.string(), mcpDemandSchema), -}); -export type MCPDemands = z.infer; - -const mcpFulfillmentSchema = z.object({ - mcp_fulfillments: z.record( - z.string(), - z.object({ - transport: z.object({ - type: mcpTransportTypesEnum, - url: z.string(), - headers: z.record(z.string(), z.string()).optional(), - }), - }), - ), -}); -export type MCPFulfillments = z.infer; - -export const mcpExtension: A2AServiceExtension< - typeof URI, - z.infer, - { - mcp_fulfillments: Record< - string, - { - transport: { - type: MCPTransportType; - url: string; - headers?: Record; - }; - } - >; - } -> = { - getUri: () => URI, - getDemandsSchema: () => mcpDemandsSchema, - getFulfillmentSchema: () => mcpFulfillmentSchema, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/index.ts new file mode 100644 index 000000000..3c7c19128 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from '../../../runtime/types'; +import { mcpDemandsSchema, mcpFulfillmentsSchema } from './schemas'; +import type { MCPDemands, MCPFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/mcp/v1'; + +export const mcpExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => mcpDemandsSchema, + getFulfillmentsSchema: () => mcpFulfillmentsSchema, +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/schemas.ts new file mode 100644 index 000000000..7bece6b5e --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/schemas.ts @@ -0,0 +1,32 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { MCPTransportType } from './types'; + +export const mcpTransportTypeSchema = z.enum(MCPTransportType); + +export const mcpDemandSchema = z.object({ + description: z.string().nullish(), + suggested: z.array(z.string()).nullish(), + allowed_transports: z.array(mcpTransportTypeSchema).nullish(), +}); + +export const mcpDemandsSchema = z.object({ + mcp_demands: z.record(z.string(), mcpDemandSchema), +}); + +export const mcpFulfillmentSchema = z.object({ + transport: z.object({ + type: mcpTransportTypeSchema, + url: z.string(), + headers: z.record(z.string(), z.string()).optional(), + }), +}); + +export const mcpFulfillmentsSchema = z.object({ + mcp_fulfillments: z.record(z.string(), mcpFulfillmentSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/types.ts new file mode 100644 index 000000000..3f0e69f38 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/mcp/types.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { mcpDemandSchema, mcpDemandsSchema, mcpFulfillmentSchema, mcpFulfillmentsSchema } from './schemas'; + +export enum MCPTransportType { + StreamableHttp = 'streamable_http', + Stdio = 'stdio', +} + +export type MCPDemand = z.infer; +export type MCPDemands = z.infer; + +export type MCPFulfillment = z.infer; +export type MCPFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/oauth-provider.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/oauth-provider.ts deleted file mode 100644 index c8201f1f6..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/oauth-provider.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/auth/oauth/v1'; - -const oauthDemandSchema = z.object({ - redirect_uri: z.boolean(), -}); - -const oauthDemandsSchema = z.object({ - oauth_demands: z.record(z.string(), oauthDemandSchema), -}); -export type OAuthDemands = z.infer; - -const oauthFulfillmentSchema = z.object({ - oauth_fulfillments: z.record( - z.string(), - z.object({ - redirect_uri: z.string(), - }), - ), -}); -export type OAuthFulfillments = z.infer; - -export const oauthProviderExtension: A2AServiceExtension< - typeof URI, - z.infer, - { - oauth_fulfillments: Record< - string, - { - redirect_uri: string; - } - >; - } -> = { - getUri: () => URI, - getDemandsSchema: () => oauthDemandsSchema, - getFulfillmentSchema: () => oauthFulfillmentSchema, -}; - -export const oauthMessageSchema = z.object({ - data: z.object({ - redirect_uri: z.string(), - }), -}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/index.ts similarity index 57% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform.ts rename to apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/index.ts index a9b77635f..e0097d884 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/index.ts @@ -3,20 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ContextToken } from '../../../api/types'; +import type { ContextToken } from '../../../../api/contexts/types'; const URI = 'https://a2a-extensions.agentstack.beeai.dev/services/platform_api/v1'; -const getMetadata = (contextToken: ContextToken) => { - return { - auth_token: contextToken.token, - expires_at: contextToken.expires_at, - }; -}; - export const platformApiExtension = (metadata: Record, contextToken: ContextToken) => { return { ...metadata, - [URI]: getMetadata(contextToken), + [URI]: { + auth_token: contextToken.token, + expires_at: contextToken.expires_at, + }, }; }; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/schemas.ts new file mode 100644 index 000000000..57cd19212 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/schemas.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const platformApiMetadataSchema = z.object({ + base_url: z.string().nullish(), + auth_token: z.string(), + expires_at: z.string().nullish(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/types.ts new file mode 100644 index 000000000..39258596f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/platform-api/types.ts @@ -0,0 +1,10 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { platformApiMetadataSchema } from './schemas'; + +export type PlatformApiMetadata = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/secrets.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/secrets.ts deleted file mode 100644 index 6e83cf17c..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/services/secrets.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension, A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/auth/secrets/v1'; - -const secretDemandSchema = z.object({ - name: z.string(), - description: z.string().nullish(), -}); -export type SecretDemand = z.infer; - -const secretDemandsSchema = z.object({ - secret_demands: z.record(z.string(), secretDemandSchema), -}); -export type SecretDemands = z.infer; - -const secretFulfillmentSchema = z.object({ - secret_fulfillments: z.record( - z.string(), - z.object({ - secret: z.string(), - }), - ), -}); -export type SecretFulfillments = z.infer; - -export const secretsExtension: A2AServiceExtension< - typeof URI, - z.infer, - SecretFulfillments -> = { - getUri: () => URI, - getDemandsSchema: () => secretDemandsSchema, - getFulfillmentSchema: () => secretFulfillmentSchema, -}; - -export const secretsMessageExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: secretDemandsSchema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/types.ts index a5181cd11..af7d1bb66 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/types.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/types.ts @@ -3,18 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { z } from 'zod'; - -export interface A2AExtension { - getUri: () => U; -} - -export interface A2AUiExtension extends A2AExtension { - getMessageMetadataSchema: () => z.ZodSchema>>; -} - -export interface A2AServiceExtension extends A2AExtension { - getUri: () => U; - getDemandsSchema: () => z.ZodSchema; - getFulfillmentSchema: () => z.ZodSchema; -} +export * from './auth/oauth/types'; +export * from './auth/secrets/types'; +export * from './common/form/types'; +export * from './services/embedding/types'; +export * from './services/form/types'; +export * from './services/llm/types'; +export * from './services/mcp/types'; +export * from './services/platform-api/types'; +export * from './ui/agent-detail/types'; +export * from './ui/canvas/types'; +export * from './ui/citation/types'; +export * from './ui/error/types'; +export * from './ui/settings/types'; +export * from './ui/trajectory/types'; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail.ts deleted file mode 100644 index da0b9b04a..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import { interactionModeSchema } from '../../../../types'; -import type { A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/agent-detail/v1'; - -const contributorSchema = z.object({ - name: z.string(), - email: z.string().nullish(), - url: z.string().nullish(), -}); - -const toolSchema = z.object({ - name: z.string(), - description: z.string(), -}); - -const schema = z.object({ - interaction_mode: z.union([interactionModeSchema, z.string()]).nullish(), - user_greeting: z.string().nullish(), - input_placeholder: z.string().nullish(), - tools: z.array(toolSchema).nullish(), - framework: z.string().nullish(), - license: z.string().nullish(), - programming_language: z.string().nullish(), - homepage_url: z.string().nullish(), - source_code_url: z.string().nullish(), - container_image_url: z.string().nullish(), - author: contributorSchema.nullish(), - contributors: z.array(contributorSchema).nullish(), -}); - -export type AgentDetailTool = z.infer; -export type AgentDetailContributor = z.infer; -export type AgentDetail = z.infer; - -export const agentDetailExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/index.ts new file mode 100644 index 000000000..465b396ff --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AUiExtension } from '../../../runtime/types'; +import { agentDetailSchema } from './schemas'; +import type { AgentDetail } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/agent-detail/v1'; + +export const agentDetailExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: agentDetailSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/schemas.ts new file mode 100644 index 000000000..3d4227774 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/schemas.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { InteractionMode } from './types'; + +export const interactionModeSchema = z.enum(InteractionMode); + +export const agentDetailToolSchema = z.object({ + name: z.string(), + description: z.string(), +}); + +export const agentDetailContributorSchema = z.object({ + name: z.string(), + email: z.string().nullish(), + url: z.string().nullish(), +}); + +export const agentDetailSchema = z.object({ + interaction_mode: z.union([interactionModeSchema, z.string()]).nullish(), + user_greeting: z.string().nullish(), + input_placeholder: z.string().nullish(), + tools: z.array(agentDetailToolSchema).nullish(), + framework: z.string().nullish(), + license: z.string().nullish(), + programming_language: z.string().nullish(), + homepage_url: z.string().nullish(), + source_code_url: z.string().nullish(), + container_image_url: z.string().nullish(), + author: agentDetailContributorSchema.nullish(), + contributors: z.array(agentDetailContributorSchema).nullish(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/types.ts new file mode 100644 index 000000000..6ae206be8 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/agent-detail/types.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { agentDetailContributorSchema, agentDetailSchema, agentDetailToolSchema } from './schemas'; + +export enum InteractionMode { + SingleTurn = 'single-turn', + MultiTurn = 'multi-turn', +} + +export type AgentDetailTool = z.infer; + +export type AgentDetailContributor = z.infer; + +export type AgentDetail = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas.ts deleted file mode 100644 index 4ae047491..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { z } from 'zod'; - -import type { A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/canvas/v1'; - -const schema = z.object({ - start_index: z.int(), - end_index: z.int(), - description: z.string().nullish(), - artifact_id: z.string(), -}); - -export type CanvasEditRequest = z.infer; - -export const CanvasExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/index.ts new file mode 100644 index 000000000..eb28bd7f0 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AUiExtension } from '../../../runtime/types'; +import { canvasEditRequestSchema } from './schemas'; +import type { CanvasEditRequest } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/canvas/v1'; + +export const canvasExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: canvasEditRequestSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/schemas.ts new file mode 100644 index 000000000..a01163dc4 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/schemas.ts @@ -0,0 +1,13 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const canvasEditRequestSchema = z.object({ + start_index: z.int(), + end_index: z.int(), + description: z.string().nullish(), + artifact_id: z.string(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/types.ts new file mode 100644 index 000000000..919f92b1a --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/canvas/types.ts @@ -0,0 +1,10 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { canvasEditRequestSchema } from './schemas'; + +export type CanvasEditRequest = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation.ts deleted file mode 100644 index e5d711d64..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/citation/v1'; - -const citationSchema = z.object({ - url: z.string().nullish(), - start_index: z.number().nullish(), - end_index: z.number().nullish(), - title: z.string().nullish(), - description: z.string().nullish(), -}); - -const schema = z.object({ - citations: z.array(citationSchema), -}); - -export type CitationMetadata = z.infer; -export type Citation = z.infer; - -export const citationExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/index.ts new file mode 100644 index 000000000..d02d9ffb8 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AUiExtension } from '../../../runtime/types'; +import { citationMetadataSchema } from './schemas'; +import type { CitationMetadata } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/citation/v1'; + +export const citationExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: citationMetadataSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/schemas.ts new file mode 100644 index 000000000..127926f27 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/schemas.ts @@ -0,0 +1,18 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const citationSchema = z.object({ + url: z.string().nullish(), + start_index: z.number().nullish(), + end_index: z.number().nullish(), + title: z.string().nullish(), + description: z.string().nullish(), +}); + +export const citationMetadataSchema = z.object({ + citations: z.array(citationSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/types.ts new file mode 100644 index 000000000..c3e57c1b4 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/citation/types.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { citationMetadataSchema, citationSchema } from './schemas'; + +export type Citation = z.infer; + +export type CitationMetadata = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error.ts deleted file mode 100644 index db97442eb..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/error/v1'; - -const errorSchema = z.object({ - title: z.string(), - message: z.string(), -}); - -const errorGroupSchema = z.object({ - message: z.string(), - errors: z.array(errorSchema), -}); - -const schema = z.object({ - error: z.union([errorSchema, errorGroupSchema]), - context: z.record(z.string(), z.unknown()).nullish(), - stack_trace: z.string().nullish(), -}); - -export type ErrorMetadata = z.infer; - -export const errorExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/index.ts new file mode 100644 index 000000000..dcc1f2e7e --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import type { A2AUiExtension } from '../../../runtime/types'; +import { errorMetadataSchema } from './schemas'; +import type { ErrorMetadata } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/error/v1'; + +export const errorExtension: A2AUiExtension = { + getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: errorMetadataSchema }).partial(), +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/schemas.ts new file mode 100644 index 000000000..a8f57f6f4 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/schemas.ts @@ -0,0 +1,22 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const errorSchema = z.object({ + title: z.string(), + message: z.string(), +}); + +export const errorGroupSchema = z.object({ + message: z.string(), + errors: z.array(errorSchema), +}); + +export const errorMetadataSchema = z.object({ + error: z.union([errorSchema, errorGroupSchema]), + context: z.record(z.string(), z.unknown()).nullish(), + stack_trace: z.string().nullish(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/types.ts new file mode 100644 index 000000000..acde3bb5f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/error/types.ts @@ -0,0 +1,14 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { errorGroupSchema, errorMetadataSchema, errorSchema } from './schemas'; + +export type Error = z.infer; + +export type ErrorGroup = z.infer; + +export type ErrorMetadata = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request/index.ts similarity index 56% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request.ts rename to apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request/index.ts index f3eeb192e..210433e16 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/form-request/index.ts @@ -5,14 +5,13 @@ import z from 'zod'; -import { formRenderSchema } from '../common/form'; -import type { A2AUiExtension } from '../types'; +import type { A2AUiExtension } from '../../../runtime/types'; +import { formRenderSchema } from '../../schemas'; +import type { FormRender } from '../../types'; const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/form_request/v1'; -export type FormRequest = z.infer; - -export const FormRequestExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: formRenderSchema }).partial(), +export const formRequestExtension: A2AUiExtension = { getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: formRenderSchema }).partial(), }; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/oauth.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/oauth.ts deleted file mode 100644 index 4ed94da94..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/oauth.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AUiExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/auth/oauth/v1'; - -const schema = z.object({ - authorization_endpoint_url: z.string(), -}); - -export type OAuthRequest = z.infer; - -export const oauthRequestExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings.ts deleted file mode 100644 index 71b6d04c5..000000000 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings.ts +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -import type { A2AServiceExtension } from '../types'; - -const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/settings/v1'; - -const checkboxField = z.object({ - id: z.string().nonempty(), - label: z.string().nonempty(), - default_value: z.boolean(), -}); - -const checkboxGroupField = z.object({ - id: z.string().nonempty(), - type: z.literal('checkbox_group'), - fields: z.array(checkboxField), -}); - -const optionItem = z.object({ - label: z.string().nonempty(), - value: z.string().nonempty(), -}); - -const singleSelectField = z.object({ - type: z.literal('single_select'), - id: z.string().nonempty(), - label: z.string().nonempty(), - options: z.array(optionItem).nonempty(), - default_value: z.string().nonempty(), -}); - -const settingsRenderSchema = z.object({ - fields: z.array(z.discriminatedUnion('type', [checkboxGroupField, singleSelectField])), -}); - -const checkboxFieldValue = z.object({ - value: z.boolean(), -}); - -const checkboxGroupFieldValue = z.object({ - type: z.literal('checkbox_group'), - values: z.record(z.string(), checkboxFieldValue), -}); - -const singleSelectFieldValue = z.object({ - type: z.literal('single_select'), - value: z.string(), -}); - -const settingsFieldValue = z.discriminatedUnion('type', [checkboxGroupFieldValue, singleSelectFieldValue]); - -export const agentSettings = z.record(z.string(), settingsFieldValue); -export type AgentSettings = z.infer; - -const agentRunSettingsSchema = z.object({ - values: agentSettings, -}); - -export type SettingsCheckboxField = z.infer; -export type SettingsCheckboxGroupField = z.infer; -export type SettingsOptionItem = z.infer; -export type SettingsSingleSelectField = z.infer; -export type SettingsCheckboxFieldValue = z.infer; -export type SettingsCheckboxGroupFieldValue = z.infer; -export type SettingsSingleSelectFieldValue = z.infer; -export type SettingsFieldValue = z.infer; - -export type SettingsDemands = z.infer; -export type SettingsFulfillments = z.infer; - -export const settingsExtension: A2AServiceExtension< - typeof URI, - z.infer, - SettingsFulfillments -> = { - getDemandsSchema: () => settingsRenderSchema, - getFulfillmentSchema: () => agentRunSettingsSchema, - getUri: () => URI, -}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/index.ts new file mode 100644 index 000000000..f241b017a --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/index.ts @@ -0,0 +1,16 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from '../../../runtime/types'; +import { settingsDemandsSchema, settingsFulfillmentsSchema } from './schemas'; +import type { SettingsDemands, SettingsFulfillments } from './types'; + +const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/settings/v1'; + +export const settingsExtension: A2AServiceExtension = { + getUri: () => URI, + getDemandsSchema: () => settingsDemandsSchema, + getFulfillmentsSchema: () => settingsFulfillmentsSchema, +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/schemas.ts new file mode 100644 index 000000000..ff3e4951b --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/schemas.ts @@ -0,0 +1,65 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const settingsCheckboxFieldSchema = z.object({ + id: z.string().nonempty(), + label: z.string().nonempty(), + default_value: z.boolean(), +}); + +export const settingsCheckboxGroupFieldSchema = z.object({ + id: z.string().nonempty(), + type: z.literal('checkbox_group'), + fields: z.array(settingsCheckboxFieldSchema), +}); + +export const settingsOptionItemSchema = z.object({ + label: z.string().nonempty(), + value: z.string().nonempty(), +}); + +export const settingsSingleSelectFieldSchema = z.object({ + type: z.literal('single_select'), + id: z.string().nonempty(), + label: z.string().nonempty(), + options: z.array(settingsOptionItemSchema).nonempty(), + default_value: z.string().nonempty(), +}); + +export const settingsFieldSchema = z.discriminatedUnion('type', [ + settingsCheckboxGroupFieldSchema, + settingsSingleSelectFieldSchema, +]); + +export const settingsCheckboxFieldValueSchema = z.object({ + value: z.boolean(), +}); + +export const settingsCheckboxGroupFieldValueSchema = z.object({ + type: z.literal('checkbox_group'), + values: z.record(z.string(), settingsCheckboxFieldValueSchema), +}); + +export const settingsSingleSelectFieldValueSchema = z.object({ + type: z.literal('single_select'), + value: z.string(), +}); + +export const settingsFieldValueSchema = z.discriminatedUnion('type', [ + settingsCheckboxGroupFieldValueSchema, + settingsSingleSelectFieldValueSchema, +]); + +export const settingsDemandsSchema = z.object({ + fields: z.array(settingsFieldSchema), +}); + +export const settingsValuesSchema = z.record(z.string(), settingsFieldValueSchema); + +export const settingsFulfillmentsSchema = z.object({ + values: settingsValuesSchema, +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/types.ts new file mode 100644 index 000000000..7085df8f7 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/settings/types.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + settingsCheckboxFieldSchema, + settingsCheckboxFieldValueSchema, + settingsCheckboxGroupFieldSchema, + settingsCheckboxGroupFieldValueSchema, + settingsDemandsSchema, + settingsFieldSchema, + settingsFieldValueSchema, + settingsFulfillmentsSchema, + settingsOptionItemSchema, + settingsSingleSelectFieldSchema, + settingsSingleSelectFieldValueSchema, + settingsValuesSchema, +} from './schemas'; + +export type SettingsCheckboxField = z.infer; +export type SettingsCheckboxGroupField = z.infer; +export type SettingsOptionItem = z.infer; +export type SettingsSingleSelectField = z.infer; + +export type SettingsField = z.infer; + +export type SettingsCheckboxFieldValue = z.infer; +export type SettingsCheckboxGroupFieldValue = z.infer; +export type SettingsSingleSelectFieldValue = z.infer; + +export type SettingsFieldValue = z.infer; + +export type SettingsDemands = z.infer; +export type SettingsValues = z.infer; +export type SettingsFulfillments = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/index.ts similarity index 50% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory.ts rename to apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/index.ts index 2881e9303..4701af5a8 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/index.ts @@ -5,19 +5,13 @@ import z from 'zod'; -import type { A2AUiExtension } from '../types'; +import type { A2AUiExtension } from '../../../runtime/types'; +import { trajectoryMetadataSchema } from './schemas'; +import type { TrajectoryMetadata } from './types'; const URI = 'https://a2a-extensions.agentstack.beeai.dev/ui/trajectory/v1'; -const schema = z.object({ - title: z.string().nullish(), - content: z.string().nullish(), - group_id: z.string().nullish(), -}); - -export type TrajectoryMetadata = z.infer; - export const trajectoryExtension: A2AUiExtension = { - getMessageMetadataSchema: () => z.object({ [URI]: schema }).partial(), getUri: () => URI, + getMessageMetadataSchema: () => z.object({ [URI]: trajectoryMetadataSchema }).partial(), }; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/schemas.ts new file mode 100644 index 000000000..54e9ca16c --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/schemas.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const trajectoryMetadataSchema = z.object({ + title: z.string().nullish(), + content: z.string().nullish(), + group_id: z.string().nullish(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/types.ts new file mode 100644 index 000000000..4d6361de2 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/extensions/ui/trajectory/types.ts @@ -0,0 +1,10 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { trajectoryMetadataSchema } from './schemas'; + +export type TrajectoryMetadata = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/protocol/schemas.ts b/apps/agentstack-sdk-ts/src/client/a2a/protocol/schemas.ts new file mode 100644 index 000000000..d1bd5f362 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/protocol/schemas.ts @@ -0,0 +1,63 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { MessageRole } from './types'; + +export const textPartSchema = z.object({ + kind: z.literal('text'), + text: z.string(), + metadata: z.record(z.string(), z.unknown()).nullish(), +}); + +export const fileWithBytesSchema = z.object({ + bytes: z.string(), + mimeType: z.string().nullish(), + name: z.string().nullish(), +}); + +export const fileWithUriSchema = z.object({ + uri: z.string(), + mimeType: z.string().nullish(), + name: z.string().nullish(), +}); + +export const filePartSchema = z.object({ + kind: z.literal('file'), + file: z.union([fileWithBytesSchema, fileWithUriSchema]), + metadata: z.record(z.string(), z.unknown()).nullish(), +}); + +export const dataPartSchema = z.object({ + kind: z.literal('data'), + data: z.record(z.string(), z.unknown()), + metadata: z.record(z.string(), z.unknown()).nullish(), +}); + +export const partSchema = z.union([textPartSchema, filePartSchema, dataPartSchema]); + +export const artifactSchema = z.object({ + artifactId: z.string(), + parts: z.array(partSchema), + description: z.string().nullish(), + extensions: z.array(z.string()).nullish(), + metadata: z.record(z.string(), z.unknown()).nullish(), + name: z.string().nullish(), +}); + +export const messageRoleSchema = z.enum(MessageRole); + +export const messageSchema = z.object({ + kind: z.literal('message'), + messageId: z.string(), + parts: z.array(partSchema), + role: messageRoleSchema, + contextId: z.string().nullish(), + extensions: z.array(z.string()).nullish(), + metadata: z.record(z.string(), z.unknown()).nullish(), + referenceTaskIds: z.array(z.string()).nullish(), + taskId: z.string().nullish(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/a2a/protocol/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/protocol/types.ts new file mode 100644 index 000000000..4a71a8712 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/protocol/types.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + artifactSchema, + dataPartSchema, + filePartSchema, + fileWithBytesSchema, + fileWithUriSchema, + messageSchema, + partSchema, + textPartSchema, +} from './schemas'; + +export type TextPart = z.infer; + +export type FileWithBytes = z.infer; + +export type FileWithUri = z.infer; + +export type FilePart = z.infer; + +export type DataPart = z.infer; + +export type Part = z.infer; + +export type Artifact = z.infer; + +export enum MessageRole { + Agent = 'agent', + User = 'user', +} + +export type Message = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/fulfillment-resolvers/build-llm-extension-fulfillment-resolver.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/buildLLMExtensionFulfillmentResolver.ts similarity index 64% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/fulfillment-resolvers/build-llm-extension-fulfillment-resolver.ts rename to apps/agentstack-sdk-ts/src/client/a2a/runtime/buildLLMExtensionFulfillmentResolver.ts index d6f740be5..dc4c5193d 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/fulfillment-resolvers/build-llm-extension-fulfillment-resolver.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/buildLLMExtensionFulfillmentResolver.ts @@ -3,23 +3,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { AgentstackClient } from '../../../api/build-api-client'; -import type { ContextToken } from '../../../api/types'; -import { ModelCapability } from '../../../api/types'; -import type { LLMDemands, LLMFulfillments } from '../services/llm'; +import type { ContextToken } from '../../api/types'; +import { ModelCapability } from '../../api/types'; +import { unwrapResult } from '../../client'; +import type { AgentStackClient } from '../../client/types'; +import type { LLMDemands, LLMFulfillments } from '../extensions/types'; const DEFAULT_SCORE_CUTOFF = 0.4; -export const buildLLMExtensionFulfillmentResolver = (api: AgentstackClient, token: ContextToken) => { +export const buildLLMExtensionFulfillmentResolver = (api: AgentStackClient, token: ContextToken) => { return async ({ llm_demands }: LLMDemands): Promise => { const allDemands = Object.keys(llm_demands); const fulfillmentPromises = allDemands.map(async (demandKey) => { const demand = llm_demands[demandKey]; - const resolvedModels = await api.matchProviders({ - suggestedModels: demand.suggested ?? [], - capability: ModelCapability.Llm, - scoreCutoff: DEFAULT_SCORE_CUTOFF, - }); + const resolvedModels = unwrapResult( + await api.matchModelProviders({ + suggested_models: demand.suggested ?? [], + capability: ModelCapability.Llm, + score_cutoff: DEFAULT_SCORE_CUTOFF, + }), + ); if (resolvedModels.items.length === 0) { throw new Error(`No models found for demand ${demandKey}. Demand details: ${JSON.stringify(demand)}`); @@ -38,6 +41,7 @@ export const buildLLMExtensionFulfillmentResolver = (api: AgentstackClient, toke }); const fulfilledEntries = await Promise.all(fulfillmentPromises); + return { llm_fulfillments: Object.fromEntries(fulfilledEntries) }; }; }; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/utils/build-message-builder.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/buildMessageBuilder.ts similarity index 85% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/utils/build-message-builder.ts rename to apps/agentstack-sdk-ts/src/client/a2a/runtime/buildMessageBuilder.ts index e6aa08429..338b93a17 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/utils/build-message-builder.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/buildMessageBuilder.ts @@ -5,8 +5,8 @@ import type { AgentCapabilities, Message } from '@a2a-js/sdk'; -import type { Fulfillments } from '../handle-agent-card'; -import { handleAgentCard } from '../handle-agent-card'; +import { handleAgentCard } from './handleAgentCard'; +import type { Fulfillments } from './types'; export const buildMessageBuilder = (agent: { capabilities: AgentCapabilities }) => diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/utils.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/extract.ts similarity index 72% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/utils.ts rename to apps/agentstack-sdk-ts/src/client/a2a/runtime/extract.ts index 8597956c4..e549df850 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/utils.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/extract.ts @@ -11,7 +11,7 @@ export function extractUiExtensionData(extension: A2AUiExte const schema = extension.getMessageMetadataSchema(); const uri = extension.getUri(); - return function (metadata: Record | undefined) { + return function (metadata: Record | undefined | null) { const { success, data: parsed, error } = schema.safeParse(metadata ?? {}); if (!success) { @@ -46,21 +46,3 @@ export function extractServiceExtensionDemands(extension return parsed; }; } - -export function fulfillServiceExtensionDemand(extension: A2AServiceExtension) { - const schema = extension.getFulfillmentSchema(); - const uri = extension.getUri(); - - return function (metadata: Record, fulfillment: F) { - const { success, data: parsed, error } = schema.safeParse(fulfillment); - - if (!success) { - console.warn(error); - } - - return { - ...metadata, - [uri]: success ? parsed : {}, - }; - }; -} diff --git a/apps/agentstack-sdk-ts/src/client/a2a/runtime/fulfill.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/fulfill.ts new file mode 100644 index 000000000..94d4d3e06 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/fulfill.ts @@ -0,0 +1,24 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { A2AServiceExtension } from './types'; + +export function fulfillServiceExtensionDemand(extension: A2AServiceExtension) { + const schema = extension.getFulfillmentsSchema(); + const uri = extension.getUri(); + + return function (metadata: Record, fulfillment: F) { + const { success, data: parsed, error } = schema.safeParse(fulfillment); + + if (!success) { + console.warn(error); + } + + return { + ...metadata, + [uri]: success ? parsed : {}, + }; + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-agent-card.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/handleAgentCard.ts similarity index 61% rename from apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-agent-card.ts rename to apps/agentstack-sdk-ts/src/client/a2a/runtime/handleAgentCard.ts index 940610394..b24b9e860 100644 --- a/apps/agentstack-sdk-ts/src/client/a2a/extensions/handle-agent-card.ts +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/handleAgentCard.ts @@ -5,41 +5,22 @@ import type { AgentCapabilities } from '@a2a-js/sdk'; -import type { ContextToken } from '../../api/types'; -import type { EmbeddingDemands, EmbeddingFulfillments } from './services/embedding'; -import { embeddingExtension } from './services/embedding'; -import type { FormDemands, FormFulfillments } from './services/form'; -import { formExtension } from './services/form'; -import type { LLMDemands, LLMFulfillments } from './services/llm'; -import { llmExtension } from './services/llm'; -import type { MCPDemands, MCPFulfillments } from './services/mcp'; -import { mcpExtension } from './services/mcp'; -import type { OAuthDemands, OAuthFulfillments } from './services/oauth-provider'; -import { oauthProviderExtension } from './services/oauth-provider'; -import { platformApiExtension } from './services/platform'; -import type { SecretDemands, SecretFulfillments } from './services/secrets'; -import { secretsExtension } from './services/secrets'; -import { oauthRequestExtension } from './ui/oauth'; -import type { SettingsDemands, SettingsFulfillments } from './ui/settings'; -import { settingsExtension } from './ui/settings'; -import { extractServiceExtensionDemands, fulfillServiceExtensionDemand } from './utils'; - -export interface Fulfillments { - llm: (demand: LLMDemands) => Promise; - embedding: (demand: EmbeddingDemands) => Promise; - mcp: (demand: MCPDemands) => Promise; - oauth: (demand: OAuthDemands) => Promise; - settings: (demand: SettingsDemands) => Promise; - secrets: (demand: SecretDemands) => Promise; - form: (demand: FormDemands) => Promise; - oauthRedirectUri: () => string | null; - getContextToken: () => ContextToken; -} +import { oAuthExtension, oAuthRequestExtension } from '../extensions/auth/oauth'; +import { secretsExtension } from '../extensions/auth/secrets'; +import { embeddingExtension } from '../extensions/services/embedding'; +import { formExtension } from '../extensions/services/form'; +import { llmExtension } from '../extensions/services/llm'; +import { mcpExtension } from '../extensions/services/mcp'; +import { platformApiExtension } from '../extensions/services/platform-api'; +import { settingsExtension } from '../extensions/ui/settings'; +import { extractServiceExtensionDemands } from './extract'; +import { fulfillServiceExtensionDemand } from './fulfill'; +import type { Fulfillments } from './types'; const mcpExtensionExtractor = extractServiceExtensionDemands(mcpExtension); const llmExtensionExtractor = extractServiceExtensionDemands(llmExtension); const embeddingExtensionExtractor = extractServiceExtensionDemands(embeddingExtension); -const oauthExtensionExtractor = extractServiceExtensionDemands(oauthProviderExtension); +const oAuthExtensionExtractor = extractServiceExtensionDemands(oAuthExtension); const settingsExtensionExtractor = extractServiceExtensionDemands(settingsExtension); const secretExtensionExtractor = extractServiceExtensionDemands(secretsExtension); const formExtensionExtractor = extractServiceExtensionDemands(formExtension); @@ -47,7 +28,7 @@ const formExtensionExtractor = extractServiceExtensionDemands(formExtension); const fulfillMcpDemand = fulfillServiceExtensionDemand(mcpExtension); const fulfillLlmDemand = fulfillServiceExtensionDemand(llmExtension); const fulfillEmbeddingDemand = fulfillServiceExtensionDemand(embeddingExtension); -const fulfillOAuthDemand = fulfillServiceExtensionDemand(oauthProviderExtension); +const fulfillOAuthDemand = fulfillServiceExtensionDemand(oAuthExtension); const fulfillSettingsDemand = fulfillServiceExtensionDemand(settingsExtension); const fulfillSecretDemand = fulfillServiceExtensionDemand(secretsExtension); const fulfillFormDemand = fulfillServiceExtensionDemand(formExtension); @@ -58,7 +39,7 @@ export const handleAgentCard = (agentCard: { capabilities: AgentCapabilities }) const llmDemands = llmExtensionExtractor(extensions); const embeddingDemands = embeddingExtensionExtractor(extensions); const mcpDemands = mcpExtensionExtractor(extensions); - const oauthDemands = oauthExtensionExtractor(extensions); + const oauthDemands = oAuthExtensionExtractor(extensions); const settingsDemands = settingsExtensionExtractor(extensions); const secretDemands = secretExtensionExtractor(extensions); const formDemands = formExtensionExtractor(extensions); @@ -100,7 +81,7 @@ export const handleAgentCard = (agentCard: { capabilities: AgentCapabilities }) if (oauthRedirectUri) { fulfilledMetadata = { ...fulfilledMetadata, - [oauthRequestExtension.getUri()]: { + [oAuthRequestExtension.getUri()]: { redirect_uri: oauthRedirectUri, }, }; @@ -115,7 +96,7 @@ export const handleAgentCard = (agentCard: { capabilities: AgentCapabilities }) llmDemands, embeddingDemands, mcpDemands, - oauthDemands, + oAuthDemands: oauthDemands, settingsDemands, secretDemands, formDemands, diff --git a/apps/agentstack-sdk-ts/src/client/a2a/runtime/handleTaskStatusUpdate.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/handleTaskStatusUpdate.ts new file mode 100644 index 000000000..fbc08d019 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/handleTaskStatusUpdate.ts @@ -0,0 +1,51 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { TaskStatusUpdateEvent } from '@a2a-js/sdk'; + +import { oAuthRequestExtension } from '../extensions/auth/oauth'; +import { secretsRequestExtension } from '../extensions/auth/secrets'; +import { formRequestExtension } from '../extensions/ui/form-request'; +import { extractUiExtensionData } from './extract'; +import type { TaskStatusUpdateResult } from './types'; +import { TaskStatusUpdateType } from './types'; + +const secretsRequestExtensionExtractor = extractUiExtensionData(secretsRequestExtension); +const oauthRequestExtensionExtractor = extractUiExtensionData(oAuthRequestExtension); +const formRequestExtensionExtractor = extractUiExtensionData(formRequestExtension); + +export const handleTaskStatusUpdate = (event: TaskStatusUpdateEvent): TaskStatusUpdateResult[] => { + const results: TaskStatusUpdateResult[] = []; + + if (event.status.state === 'auth-required') { + const secretRequired = secretsRequestExtensionExtractor(event.status.message?.metadata); + const oauthRequired = oauthRequestExtensionExtractor(event.status.message?.metadata); + + if (oauthRequired) { + results.push({ + type: TaskStatusUpdateType.OAuthRequired, + url: oauthRequired.authorization_endpoint_url, + }); + } + + if (secretRequired) { + results.push({ + type: TaskStatusUpdateType.SecretRequired, + demands: secretRequired, + }); + } + } else if (event.status.state === 'input-required') { + const formRequired = formRequestExtensionExtractor(event.status.message?.metadata); + + if (formRequired) { + results.push({ + type: TaskStatusUpdateType.FormRequired, + form: formRequired, + }); + } + } + + return results; +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/runtime/index.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/index.ts new file mode 100644 index 000000000..2c340bd07 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/index.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './buildLLMExtensionFulfillmentResolver'; +export * from './buildMessageBuilder'; +export * from './extract'; +export * from './fulfill'; +export * from './handleAgentCard'; +export * from './handleTaskStatusUpdate'; +export * from './resolveUserMetadata'; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/runtime/resolveUserMetadata.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/resolveUserMetadata.ts new file mode 100644 index 000000000..c8b6ed158 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/resolveUserMetadata.ts @@ -0,0 +1,25 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { canvasExtension } from '../extensions/ui/canvas'; +import { formRequestExtension } from '../extensions/ui/form-request'; +import type { UserMetadataInputs } from './types'; + +export const resolveUserMetadata = async (inputs: UserMetadataInputs) => { + const metadata: Record = {}; + + const { form, canvasEditRequest } = inputs; + + if (form) { + metadata[formRequestExtension.getUri()] = { + values: form, + }; + } + if (canvasEditRequest) { + metadata[canvasExtension.getUri()] = canvasEditRequest; + } + + return metadata; +}; diff --git a/apps/agentstack-sdk-ts/src/client/a2a/runtime/types.ts b/apps/agentstack-sdk-ts/src/client/a2a/runtime/types.ts new file mode 100644 index 000000000..e547ce8a2 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/a2a/runtime/types.ts @@ -0,0 +1,70 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { z } from 'zod'; + +import type { ContextToken } from '../../api/contexts/types'; +import type { OAuthDemands, OAuthFulfillments } from '../extensions/auth/oauth/types'; +import type { SecretDemands, SecretFulfillments } from '../extensions/auth/secrets/types'; +import type { FormRender, FormValues } from '../extensions/common/form/types'; +import type { EmbeddingDemands, EmbeddingFulfillments } from '../extensions/services/embedding/types'; +import type { FormDemands, FormFulfillments } from '../extensions/services/form/types'; +import type { LLMDemands, LLMFulfillments } from '../extensions/services/llm/types'; +import type { MCPDemands, MCPFulfillments } from '../extensions/services/mcp/types'; +import type { CanvasEditRequest } from '../extensions/ui/canvas/types'; +import type { SettingsDemands, SettingsFulfillments } from '../extensions/ui/settings/types'; + +export interface A2AExtension { + getUri: () => U; +} + +export interface A2AUiExtension extends A2AExtension { + getMessageMetadataSchema: () => z.ZodSchema>>; +} + +export interface A2AServiceExtension extends A2AExtension { + getDemandsSchema: () => z.ZodSchema; + getFulfillmentsSchema: () => z.ZodSchema; +} + +export interface Fulfillments { + llm: (demand: LLMDemands) => Promise; + embedding: (demand: EmbeddingDemands) => Promise; + mcp: (demand: MCPDemands) => Promise; + oauth: (demand: OAuthDemands) => Promise; + settings: (demand: SettingsDemands) => Promise; + secrets: (demand: SecretDemands) => Promise; + form: (demand: FormDemands) => Promise; + oauthRedirectUri: () => string | null; + getContextToken: () => ContextToken; +} + +export type UserMetadataInputs = Partial<{ + form: FormValues; + canvasEditRequest: CanvasEditRequest; +}>; + +export enum TaskStatusUpdateType { + SecretRequired = 'secret-required', + FormRequired = 'form-required', + OAuthRequired = 'oauth-required', +} + +export interface SecretRequiredResult { + type: TaskStatusUpdateType.SecretRequired; + demands: SecretDemands; +} + +export interface FormRequiredResult { + type: TaskStatusUpdateType.FormRequired; + form: FormRender; +} + +export interface OAuthRequiredResult { + type: TaskStatusUpdateType.OAuthRequired; + url: string; +} + +export type TaskStatusUpdateResult = SecretRequiredResult | FormRequiredResult | OAuthRequiredResult; diff --git a/apps/agentstack-sdk-ts/src/client/api/build-api-client.ts b/apps/agentstack-sdk-ts/src/client/api/build-api-client.ts deleted file mode 100644 index 5601d4255..000000000 --- a/apps/agentstack-sdk-ts/src/client/api/build-api-client.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type { z } from 'zod'; - -import type { ContextPermissionsGrant, GlobalPermissionsGrant, ModelCapability } from './types'; -import { contextSchema, contextTokenSchema, listConnectorsResponseSchema, modelProviderMatchSchema } from './types'; - -export interface MatchProvidersParams { - suggestedModels: string[] | null; - capability: ModelCapability; - scoreCutoff: number; -} - -export interface CreateContextTokenParams { - contextId: string; - globalPermissions: GlobalPermissionsGrant; - contextPermissions: ContextPermissionsGrant; -} - -export const buildApiClient = ( - { - baseUrl, - fetch: customFetchImpl, - }: { - baseUrl: string; - fetch?: typeof globalThis.fetch; - } = { baseUrl: '' }, -) => { - const maybeFetchFn = customFetchImpl ?? (typeof globalThis.fetch !== 'undefined' ? globalThis.fetch : undefined); - - if (!maybeFetchFn) { - throw new Error( - 'fetch is not available. In Node.js < 18 or environments without global fetch, ' + - 'provide a fetch implementation via the fetch option.', - ); - } - - const fetchFn = maybeFetchFn; - - async function callApi( - method: 'POST' | 'GET', - url: string, - data: Record | null, - resultSchema: z.ZodSchema, - ) { - let requestUrl = `${baseUrl}${url}`; - const options: RequestInit = { - method, - headers: { - 'Content-Type': 'application/json', - }, - }; - - if (method === 'GET' && data) { - const params = new URLSearchParams(); - Object.entries(data).forEach(([key, value]) => { - if (value !== null && value !== undefined) { - params.append(key, String(value)); - } - }); - requestUrl = `${requestUrl}?${params.toString()}`; - } else if (method === 'POST' && data) { - options.body = JSON.stringify(data); - } - - const response = await fetchFn(requestUrl, options); - if (!response.ok) { - throw new Error(`Failed to call Agent Stackk API - ${url}`); - } - - const json = await response.json(); - return resultSchema.parse(json); - } - - const createContext = async (providerId: string) => - await callApi('POST', '/api/v1/contexts', { metadata: {}, provider_id: providerId }, contextSchema); - - const createContextToken = async ({ contextId, globalPermissions, contextPermissions }: CreateContextTokenParams) => { - const token = await callApi( - 'POST', - `/api/v1/contexts/${contextId}/token`, - { - grant_global_permissions: globalPermissions, - grant_context_permissions: contextPermissions, - }, - contextTokenSchema, - ); - - return { token, contextId }; - }; - - const matchProviders = async ({ suggestedModels, capability, scoreCutoff }: MatchProvidersParams) => { - return await callApi( - 'POST', - '/api/v1/model_providers/match', - { - capability, - score_cutoff: scoreCutoff, - suggested_models: suggestedModels, - }, - modelProviderMatchSchema, - ); - }; - - const listConnectors = async () => { - return await callApi('GET', '/api/v1/connectors', null, listConnectorsResponseSchema); - }; - - return { createContextToken, createContext, matchProviders, listConnectors }; -}; - -export type AgentstackClient = ReturnType; diff --git a/apps/agentstack-sdk-ts/src/client/api/configuration/api.ts b/apps/agentstack-sdk-ts/src/client/api/configuration/api.ts new file mode 100644 index 000000000..0219c18ba --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/configuration/api.ts @@ -0,0 +1,31 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { readSystemConfigurationResponseSchema, updateSystemConfigurationResponseSchema } from './schemas'; +import type { UpdateSystemConfigurationRequest } from './types'; + +export function createConfigurationApi(callApi: CallApi) { + const readSystemConfiguration = () => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/configurations/system', + schema: readSystemConfigurationResponseSchema, + }); + + const updateSystemConfiguration = ({ ...body }: UpdateSystemConfigurationRequest) => + callApi({ + method: ApiMethod.Put, + path: '/api/v1/configurations/system', + schema: updateSystemConfigurationResponseSchema, + body, + }); + + return { + readSystemConfiguration, + updateSystemConfiguration, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/configuration/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/configuration/schemas.ts new file mode 100644 index 000000000..b2656a04f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/configuration/schemas.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const systemConfigurationSchema = z.object({ + id: z.string(), + created_by: z.string(), + updated_at: z.string(), + default_embedding_model: z.string().nullish(), + default_llm_model: z.string().nullish(), +}); + +export const readSystemConfigurationResponseSchema = systemConfigurationSchema; + +export const updateSystemConfigurationRequestSchema = z.object({ + default_embedding_model: z.string().nullish(), + default_llm_model: z.string().nullish(), +}); + +export const updateSystemConfigurationResponseSchema = systemConfigurationSchema; diff --git a/apps/agentstack-sdk-ts/src/client/api/configuration/types.ts b/apps/agentstack-sdk-ts/src/client/api/configuration/types.ts new file mode 100644 index 000000000..fb9354629 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/configuration/types.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + readSystemConfigurationResponseSchema, + systemConfigurationSchema, + updateSystemConfigurationRequestSchema, + updateSystemConfigurationResponseSchema, +} from './schemas'; + +export type SystemConfiguration = z.infer; + +export type ReadSystemConfigurationResponse = z.infer; + +export type UpdateSystemConfigurationRequest = z.infer; +export type UpdateSystemConfigurationResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/connectors/api.ts b/apps/agentstack-sdk-ts/src/client/api/connectors/api.ts new file mode 100644 index 000000000..8c0c1460f --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/connectors/api.ts @@ -0,0 +1,86 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { + connectConnectorResponseSchema, + createConnectorResponseSchema, + deleteConnectorResponseSchema, + disconnectConnectorResponseSchema, + listConnectorPresetsResponseSchema, + listConnectorsResponseSchema, + readConnectorResponseSchema, +} from './schemas'; +import type { + ConnectConnectorRequest, + CreateConnectorRequest, + DeleteConnectorRequest, + DisconnectConnectorRequest, + ReadConnectorRequest, +} from './types'; + +export function createConnectorsApi(callApi: CallApi) { + const listConnectors = () => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/connectors', + schema: listConnectorsResponseSchema, + }); + + const createConnector = ({ ...body }: CreateConnectorRequest) => + callApi({ + method: ApiMethod.Post, + path: '/api/v1/connectors', + schema: createConnectorResponseSchema, + body, + }); + + const readConnector = ({ connector_id }: ReadConnectorRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/connectors/${connector_id}`, + schema: readConnectorResponseSchema, + }); + + const deleteConnector = ({ connector_id }: DeleteConnectorRequest) => + callApi({ + method: ApiMethod.Delete, + path: `/api/v1/connectors/${connector_id}`, + schema: deleteConnectorResponseSchema, + }); + + const connectConnector = ({ connector_id, ...body }: ConnectConnectorRequest) => + callApi({ + method: ApiMethod.Post, + path: `/api/v1/connectors/${connector_id}/connect`, + schema: connectConnectorResponseSchema, + body, + }); + + const disconnectConnector = ({ connector_id }: DisconnectConnectorRequest) => + callApi({ + method: ApiMethod.Post, + path: `/api/v1/connectors/${connector_id}/disconnect`, + schema: disconnectConnectorResponseSchema, + }); + + const listConnectorPresets = () => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/connectors/presets', + schema: listConnectorPresetsResponseSchema, + }); + + return { + listConnectors, + createConnector, + readConnector, + deleteConnector, + connectConnector, + disconnectConnector, + listConnectorPresets, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/connectors/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/connectors/schemas.ts new file mode 100644 index 000000000..12643a6c0 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/connectors/schemas.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { paginatedResponseSchema } from '../../client/schemas'; +import { ConnectorState } from './types'; + +export const connectorStateSchema = z.enum(ConnectorState); + +export const connectorSchema = z.object({ + id: z.string(), + url: z.string(), + state: connectorStateSchema, + auth_request: z + .object({ + type: z.literal('code'), + authorization_endpoint: z.string(), + }) + .nullable(), + disconnect_reason: z.string().nullable(), + metadata: z.record(z.string(), z.string()).nullable(), +}); + +export const listConnectorsResponseSchema = paginatedResponseSchema.extend({ + items: z.array(connectorSchema), +}); + +export const createConnectorRequestSchema = z.object({ + match_preset: z.boolean(), + url: z.string(), + client_id: z.string().nullish(), + client_secret: z.string().nullish(), + metadata: z.record(z.string(), z.string()).nullish(), +}); + +export const createConnectorResponseSchema = connectorSchema; + +export const readConnectorRequestSchema = z.object({ + connector_id: z.string(), +}); + +export const readConnectorResponseSchema = connectorSchema; + +export const deleteConnectorRequestSchema = z.object({ + connector_id: z.string(), +}); + +export const deleteConnectorResponseSchema = z.null(); + +export const connectConnectorRequestSchema = z.object({ + connector_id: z.string(), + redirect_url: z.string().nullish(), +}); + +export const connectConnectorResponseSchema = connectorSchema; + +export const disconnectConnectorRequestSchema = z.object({ + connector_id: z.string(), +}); + +export const disconnectConnectorResponseSchema = connectorSchema; + +export const connectorPresetSchema = z.object({ + url: z.string(), + metadata: z.record(z.string(), z.string()).nullable(), +}); + +export const listConnectorPresetsResponseSchema = paginatedResponseSchema.extend({ + items: z.array(connectorPresetSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/api/connectors/types.ts b/apps/agentstack-sdk-ts/src/client/api/connectors/types.ts new file mode 100644 index 000000000..fa33d3f0b --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/connectors/types.ts @@ -0,0 +1,53 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + connectConnectorRequestSchema, + connectConnectorResponseSchema, + connectorPresetSchema, + connectorSchema, + createConnectorRequestSchema, + createConnectorResponseSchema, + deleteConnectorRequestSchema, + deleteConnectorResponseSchema, + disconnectConnectorRequestSchema, + disconnectConnectorResponseSchema, + listConnectorPresetsResponseSchema, + listConnectorsResponseSchema, + readConnectorRequestSchema, + readConnectorResponseSchema, +} from './schemas'; + +export enum ConnectorState { + Created = 'created', + AuthRequired = 'auth_required', + Connected = 'connected', + Disconnected = 'disconnected', +} + +export type Connector = z.infer; + +export type ListConnectorsResponse = z.infer; + +export type CreateConnectorRequest = z.infer; +export type CreateConnectorResponse = z.infer; + +export type ReadConnectorRequest = z.infer; +export type ReadConnectorResponse = z.infer; + +export type DeleteConnectorRequest = z.infer; +export type DeleteConnectorResponse = z.infer; + +export type ConnectConnectorRequest = z.infer; +export type ConnectConnectorResponse = z.infer; + +export type DisconnectConnectorRequest = z.infer; +export type DisconnectConnectorResponse = z.infer; + +export type ConnectorPreset = z.infer; + +export type ListConnectorPresetsResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/contexts/api.ts b/apps/agentstack-sdk-ts/src/client/api/contexts/api.ts new file mode 100644 index 000000000..14c7158b2 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/contexts/api.ts @@ -0,0 +1,113 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { + createContextHistoryResponseSchema, + createContextResponseSchema, + createContextTokenResponseSchema, + deleteContextResponseSchema, + listContextHistoryResponseSchema, + listContextsResponseSchema, + patchContextMetadataResponseSchema, + readContextResponseSchema, + updateContextResponseSchema, +} from './schemas'; +import type { + CreateContextHistoryRequest, + CreateContextRequest, + CreateContextTokenRequest, + DeleteContextRequest, + ListContextHistoryRequest, + ListContextsRequest, + PatchContextMetadataRequest, + ReadContextRequest, + UpdateContextRequest, +} from './types'; + +export function createContextsApi(callApi: CallApi) { + const listContexts = ({ query }: ListContextsRequest) => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/contexts', + schema: listContextsResponseSchema, + query, + }); + + const createContext = ({ ...body }: CreateContextRequest) => + callApi({ + method: ApiMethod.Post, + path: '/api/v1/contexts', + schema: createContextResponseSchema, + body, + }); + + const readContext = ({ context_id }: ReadContextRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/contexts/${context_id}`, + schema: readContextResponseSchema, + }); + + const updateContext = ({ context_id, ...body }: UpdateContextRequest) => + callApi({ + method: ApiMethod.Put, + path: `/api/v1/contexts/${context_id}`, + schema: updateContextResponseSchema, + body, + }); + + const deleteContext = ({ context_id }: DeleteContextRequest) => + callApi({ + method: ApiMethod.Delete, + path: `/api/v1/contexts/${context_id}`, + schema: deleteContextResponseSchema, + }); + + const listContextHistory = ({ context_id, query }: ListContextHistoryRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/contexts/${context_id}/history`, + schema: listContextHistoryResponseSchema, + query, + }); + + const createContextHistory = ({ context_id, ...body }: CreateContextHistoryRequest) => + callApi({ + method: ApiMethod.Post, + path: `/api/v1/contexts/${context_id}/history`, + schema: createContextHistoryResponseSchema, + body, + }); + + const patchContextMetadata = ({ context_id, ...body }: PatchContextMetadataRequest) => + callApi({ + method: ApiMethod.Patch, + path: `/api/v1/contexts/${context_id}/metadata`, + schema: patchContextMetadataResponseSchema, + body, + }); + + const createContextToken = ({ context_id, ...body }: CreateContextTokenRequest) => + callApi({ + method: ApiMethod.Post, + path: `/api/v1/contexts/${context_id}/token`, + schema: createContextTokenResponseSchema, + body, + }); + + return { + listContexts, + createContext, + readContext, + updateContext, + deleteContext, + listContextHistory, + createContextHistory, + patchContextMetadata, + createContextToken, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/contexts/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/contexts/schemas.ts new file mode 100644 index 000000000..02d3e3f0c --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/contexts/schemas.ts @@ -0,0 +1,136 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { artifactSchema, messageSchema } from '../../a2a/protocol/schemas'; +import { paginatedResponseSchema, paginationQuerySchema } from '../../client/schemas'; +import { ContextHistoryKind } from './types'; + +export const contextSchema = z.object({ + id: z.string(), + created_at: z.string(), + updated_at: z.string(), + last_active_at: z.string(), + created_by: z.string(), + provider_id: z.string().nullable(), + metadata: z.record(z.string(), z.unknown()).nullable(), +}); + +export const listContextsRequestSchema = z.object({ + query: paginationQuerySchema + .extend({ + provider_id: z.string().nullish(), + include_empty: z.boolean().optional(), + }) + .optional(), +}); + +export const listContextsResponseSchema = paginatedResponseSchema.extend({ + items: z.array(contextSchema), +}); + +export const createContextRequestSchema = z.object({ + provider_id: z.string().nullish(), + metadata: z.record(z.string(), z.string()).nullish(), +}); + +export const createContextResponseSchema = contextSchema; + +export const readContextRequestSchema = z.object({ + context_id: z.string(), +}); + +export const readContextResponseSchema = contextSchema; + +export const updateContextRequestSchema = z.object({ + context_id: z.string(), + metadata: z.record(z.string(), z.string()).nullish(), +}); + +export const updateContextResponseSchema = contextSchema; + +export const deleteContextRequestSchema = z.object({ + context_id: z.string(), +}); + +export const deleteContextResponseSchema = z.null(); + +export const contextHistoryKind = z.enum(ContextHistoryKind); + +export const contextHistorySchema = z.object({ + id: z.string(), + context_id: z.string(), + created_at: z.string(), + kind: contextHistoryKind, + data: z.union([artifactSchema, messageSchema]), +}); + +export const listContextHistoryRequestSchema = z.object({ + context_id: z.string(), + query: paginationQuerySchema.optional(), +}); + +export const listContextHistoryResponseSchema = paginatedResponseSchema.extend({ + items: z.array(contextHistorySchema), +}); + +export const createContextHistoryRequestSchema = z.object({ + context_id: z.string(), + data: z.union([artifactSchema, messageSchema]), +}); + +export const createContextHistoryResponseSchema = z.null(); + +export const patchContextMetadataRequestSchema = z.object({ + context_id: z.string(), + metadata: z.record(z.string(), z.union([z.string(), z.null()])), +}); + +export const patchContextMetadataResponseSchema = contextSchema; + +export const contextTokenSchema = z.object({ + token: z.string(), + expires_at: z.string().nullable(), +}); + +export const resourceIdPermissionSchema = z.object({ + id: z.string(), +}); + +export const contextPermissionsGrantSchema = z.object({ + files: z.array(z.literal(['read', 'write', 'extract', '*'])).optional(), + vector_stores: z.array(z.literal(['read', 'write', '*'])).optional(), + context_data: z.array(z.literal(['read', 'write', '*'])).optional(), +}); + +export const globalPermissionsGrantSchema = contextPermissionsGrantSchema.extend({ + feedback: z.array(z.literal('write')).optional(), + + llm: z.array(z.union([z.literal('*'), resourceIdPermissionSchema])).optional(), + embeddings: z.array(z.union([z.literal('*'), resourceIdPermissionSchema])).optional(), + model_providers: z.array(z.literal(['read', 'write', '*'])).optional(), + + a2a_proxy: z.array(z.literal('*')).optional(), + + providers: z.array(z.literal(['read', 'write', '*'])).optional(), + provider_variables: z.array(z.literal(['read', 'write', '*'])).optional(), + + contexts: z.array(z.literal(['read', 'write', '*'])).optional(), + + mcp_providers: z.array(z.literal(['read', 'write', '*'])).optional(), + mcp_tools: z.array(z.literal(['read', '*'])).optional(), + mcp_proxy: z.array(z.literal('*')).optional(), + + connectors: z.array(z.literal(['read', 'write', 'proxy', '*'])).optional(), +}); + +export const createContextTokenRequestSchema = z.object({ + context_id: z.string(), + grant_context_permissions: contextPermissionsGrantSchema.optional(), + grant_global_permissions: globalPermissionsGrantSchema.optional(), +}); + +export const createContextTokenResponseSchema = contextTokenSchema; diff --git a/apps/agentstack-sdk-ts/src/client/api/contexts/types.ts b/apps/agentstack-sdk-ts/src/client/api/contexts/types.ts new file mode 100644 index 000000000..86f2087d3 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/contexts/types.ts @@ -0,0 +1,74 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + contextHistorySchema, + contextPermissionsGrantSchema, + contextSchema, + contextTokenSchema, + createContextHistoryRequestSchema, + createContextHistoryResponseSchema, + createContextRequestSchema, + createContextResponseSchema, + createContextTokenRequestSchema, + createContextTokenResponseSchema, + deleteContextRequestSchema, + deleteContextResponseSchema, + globalPermissionsGrantSchema, + listContextHistoryRequestSchema, + listContextHistoryResponseSchema, + listContextsRequestSchema, + listContextsResponseSchema, + patchContextMetadataRequestSchema, + patchContextMetadataResponseSchema, + readContextRequestSchema, + readContextResponseSchema, + resourceIdPermissionSchema, + updateContextRequestSchema, + updateContextResponseSchema, +} from './schemas'; + +export type Context = z.infer; + +export type ListContextsRequest = z.infer; +export type ListContextsResponse = z.infer; + +export type CreateContextRequest = z.infer; +export type CreateContextResponse = z.infer; + +export type ReadContextRequest = z.infer; +export type ReadContextResponse = z.infer; + +export type UpdateContextRequest = z.infer; +export type UpdateContextResponse = z.infer; + +export type DeleteContextRequest = z.infer; +export type DeleteContextResponse = z.infer; + +export enum ContextHistoryKind { + Artifact = 'artifact', + Message = 'message', +} +export type ContextHistory = z.infer; + +export type ListContextHistoryRequest = z.infer; +export type ListContextHistoryResponse = z.infer; + +export type CreateContextHistoryRequest = z.infer; +export type CreateContextHistoryResponse = z.infer; + +export type PatchContextMetadataRequest = z.infer; +export type PatchContextMetadataResponse = z.infer; + +export type ContextToken = z.infer; + +export type ResourceIdPermission = z.infer; +export type ContextPermissionsGrant = z.infer; +export type GlobalPermissionsGrant = z.infer; + +export type CreateContextTokenRequest = z.infer; +export type CreateContextTokenResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/files/api.ts b/apps/agentstack-sdk-ts/src/client/api/files/api.ts new file mode 100644 index 000000000..9217f8c91 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/files/api.ts @@ -0,0 +1,65 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { + createFileResponseSchema, + deleteFileResponseSchema, + readFileContentResponseSchema, + readFileResponseSchema, +} from './schemas'; +import type { CreateFileRequest, DeleteFileRequest, ReadFileContentRequest, ReadFileRequest } from './types'; + +export function createFilesApi(callApi: CallApi) { + const createFile = ({ context_id, file }: CreateFileRequest) => { + const body = new FormData(); + + if (file instanceof File) { + body.append('file', file); + } else { + body.append('file', file.blob, file.filename); + } + + return callApi({ + method: ApiMethod.Post, + path: '/api/v1/files', + schema: createFileResponseSchema, + query: { context_id }, + body, + }); + }; + + const readFile = ({ context_id, file_id }: ReadFileRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/files/${file_id}`, + schema: readFileResponseSchema, + query: { context_id }, + }); + + const deleteFile = ({ context_id, file_id }: DeleteFileRequest) => + callApi({ + method: ApiMethod.Delete, + path: `/api/v1/files/${file_id}`, + schema: deleteFileResponseSchema, + query: { context_id }, + }); + + const readFileContent = ({ context_id, file_id }: ReadFileContentRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/files/${file_id}/content`, + schema: readFileContentResponseSchema, + query: { context_id }, + }); + + return { + createFile, + readFile, + deleteFile, + readFileContent, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/files/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/files/schemas.ts new file mode 100644 index 000000000..f7e5bad7d --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/files/schemas.ts @@ -0,0 +1,56 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { FileType } from './types'; + +export const fileTypeSchema = z.enum(FileType); + +export const fileSchema = z.object({ + id: z.string(), + filename: z.string(), + content_type: z.string(), + file_type: fileTypeSchema, + created_by: z.string(), + created_at: z.string(), + context_id: z.string().nullish(), + file_size_bytes: z.number().nullish(), + parent_file_id: z.string().nullish(), +}); + +export const createFileRequestSchema = z.object({ + context_id: z.string().nullable(), + file: z.union([ + z.file(), + z.object({ + blob: z.instanceof(Blob), + filename: z.string(), + }), + ]), +}); + +export const createFileResponseSchema = fileSchema; + +export const readFileRequestSchema = z.object({ + context_id: z.string().nullable(), + file_id: z.string(), +}); + +export const readFileResponseSchema = fileSchema; + +export const deleteFileRequestSchema = z.object({ + context_id: z.string().nullable(), + file_id: z.string(), +}); + +export const deleteFileResponseSchema = z.null(); + +export const readFileContentRequestSchema = z.object({ + context_id: z.string().nullable(), + file_id: z.string(), +}); + +export const readFileContentResponseSchema = z.unknown(); diff --git a/apps/agentstack-sdk-ts/src/client/api/files/types.ts b/apps/agentstack-sdk-ts/src/client/api/files/types.ts new file mode 100644 index 000000000..75b699245 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/files/types.ts @@ -0,0 +1,37 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + createFileRequestSchema, + createFileResponseSchema, + deleteFileRequestSchema, + deleteFileResponseSchema, + fileSchema, + readFileContentRequestSchema, + readFileContentResponseSchema, + readFileRequestSchema, + readFileResponseSchema, +} from './schemas'; + +export enum FileType { + UserUpload = 'user_upload', + ExtractedText = 'extracted_text', +} + +export type File = z.infer; + +export type CreateFileRequest = z.infer; +export type CreateFileResponse = z.infer; + +export type ReadFileRequest = z.infer; +export type ReadFileResponse = z.infer; + +export type DeleteFileRequest = z.infer; +export type DeleteFileResponse = z.infer; + +export type ReadFileContentRequest = z.infer; +export type ReadFileContentResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/model-providers/api.ts b/apps/agentstack-sdk-ts/src/client/api/model-providers/api.ts new file mode 100644 index 000000000..333c5a16b --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/model-providers/api.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { + createModelProviderResponseSchema, + deleteModelProviderResponseSchema, + listModelProvidersResponseSchema, + matchModelProvidersResponseSchema, + readModelProviderResponseSchema, +} from './schemas'; +import type { + CreateModelProviderRequest, + DeleteModelProviderRequest, + MatchModelProvidersRequest, + ReadModelProviderRequest, +} from './types'; + +export function createModelProvidersApi(callApi: CallApi) { + const listModelProviders = () => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/model_providers', + schema: listModelProvidersResponseSchema, + }); + + const createModelProvider = ({ ...body }: CreateModelProviderRequest) => + callApi({ + method: ApiMethod.Post, + path: '/api/v1/model_providers', + schema: createModelProviderResponseSchema, + body, + }); + + const readModelProvider = ({ model_provider_id }: ReadModelProviderRequest) => + callApi({ + method: ApiMethod.Get, + path: `/api/v1/model_providers/${model_provider_id}`, + schema: readModelProviderResponseSchema, + }); + + const deleteModelProvider = ({ model_provider_id }: DeleteModelProviderRequest) => + callApi({ + method: ApiMethod.Delete, + path: `/api/v1/model_providers/${model_provider_id}`, + schema: deleteModelProviderResponseSchema, + }); + + const matchModelProviders = ({ ...body }: MatchModelProvidersRequest) => + callApi({ + method: ApiMethod.Post, + path: '/api/v1/model_providers/match', + schema: matchModelProvidersResponseSchema, + body, + }); + + return { + listModelProviders, + createModelProvider, + readModelProvider, + deleteModelProvider, + matchModelProviders, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/model-providers/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/model-providers/schemas.ts new file mode 100644 index 000000000..3194cc345 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/model-providers/schemas.ts @@ -0,0 +1,66 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { paginatedResponseSchema } from '../../client/schemas'; +import { ModelCapability, ModelProviderType } from './types'; + +export const modelCapabilitySchema = z.enum(ModelCapability); + +export const modelProviderTypeSchema = z.enum(ModelProviderType); + +export const modelProviderSchema = z.object({ + id: z.string(), + base_url: z.string(), + created_at: z.string(), + capabilities: z.array(modelCapabilitySchema), + name: z.string().nullish(), + description: z.string().nullish(), + type: modelProviderTypeSchema, +}); + +export const listModelProvidersResponseSchema = paginatedResponseSchema.extend({ + items: z.array(modelProviderSchema), +}); + +export const createModelProviderRequestSchema = z.object({ + api_key: z.string(), + base_url: z.string(), + type: modelProviderTypeSchema, + name: z.string().nullish(), + description: z.string().nullish(), + watsonx_project_id: z.string().nullish(), + watsonx_space_id: z.string().nullish(), +}); + +export const createModelProviderResponseSchema = modelProviderSchema; + +export const readModelProviderRequestSchema = z.object({ + model_provider_id: z.string(), +}); + +export const readModelProviderResponseSchema = modelProviderSchema; + +export const deleteModelProviderRequestSchema = z.object({ + model_provider_id: z.string(), +}); + +export const deleteModelProviderResponseSchema = z.null(); + +export const matchModelProvidersRequestSchema = z.object({ + suggested_models: z.array(z.string()).nullable(), + capability: modelCapabilitySchema, + score_cutoff: z.number(), +}); + +export const matchModelProvidersResponseSchema = paginatedResponseSchema.extend({ + items: z.array( + z.object({ + model_id: z.string(), + score: z.number(), + }), + ), +}); diff --git a/apps/agentstack-sdk-ts/src/client/api/model-providers/types.ts b/apps/agentstack-sdk-ts/src/client/api/model-providers/types.ts new file mode 100644 index 000000000..0110d2796 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/model-providers/types.ts @@ -0,0 +1,64 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { + createModelProviderRequestSchema, + createModelProviderResponseSchema, + deleteModelProviderRequestSchema, + deleteModelProviderResponseSchema, + listModelProvidersResponseSchema, + matchModelProvidersRequestSchema, + matchModelProvidersResponseSchema, + modelProviderSchema, + readModelProviderRequestSchema, + readModelProviderResponseSchema, +} from './schemas'; + +export enum ModelCapability { + Llm = 'llm', + Embedding = 'embedding', +} + +export enum ModelProviderType { + Anthropic = 'anthropic', + Cerebras = 'cerebras', + Chutes = 'chutes', + Cohere = 'cohere', + DeepSeek = 'deepseek', + Gemini = 'gemini', + GitHub = 'github', + Groq = 'groq', + Watsonx = 'watsonx', + Jan = 'jan', + Mistral = 'mistral', + Moonshot = 'moonshot', + Nvidia = 'nvidia', + Ollama = 'ollama', + OpenAI = 'openai', + OpenRouter = 'openrouter', + Perplexity = 'perplexity', + Together = 'together', + Voyage = 'voyage', + Rits = 'rits', + Other = 'other', +} + +export type ModelProvider = z.infer; + +export type ListModelProvidersResponse = z.infer; + +export type CreateModelProviderRequest = z.infer; +export type CreateModelProviderResponse = z.infer; + +export type ReadModelProviderRequest = z.infer; +export type ReadModelProviderResponse = z.infer; + +export type DeleteModelProviderRequest = z.infer; +export type DeleteModelProviderResponse = z.infer; + +export type MatchModelProvidersRequest = z.infer; +export type MatchModelProvidersResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/provider-builds/api.ts b/apps/agentstack-sdk-ts/src/client/api/provider-builds/api.ts new file mode 100644 index 000000000..2f65b7dfd --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/provider-builds/api.ts @@ -0,0 +1,22 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ApiMethod, type CallApi } from '../../client/types'; +import { listProviderBuildsResponseSchema } from './schemas'; +import type { ListProviderBuildsRequest } from './types'; + +export function createProviderBuildsApi(callApi: CallApi) { + const listProviderBuilds = ({ query }: ListProviderBuildsRequest) => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/provider_builds', + schema: listProviderBuildsResponseSchema, + query, + }); + + return { + listProviderBuilds, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/provider-builds/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/provider-builds/schemas.ts new file mode 100644 index 000000000..10942bc64 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/provider-builds/schemas.ts @@ -0,0 +1,24 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { paginatedResponseSchema, paginationQuerySchema } from '../../client/schemas'; +import { ProviderBuildState } from './types'; + +export const providerBuildStateSchema = z.enum(ProviderBuildState); + +export const providerBuildSchema = z.object({}); + +export const listProviderBuildsRequestSchema = z.object({ + query: paginationQuerySchema.extend({ + status: providerBuildStateSchema.nullish(), + user_owned: z.boolean().nullish(), + }), +}); + +export const listProviderBuildsResponseSchema = paginatedResponseSchema.extend({ + items: z.array(providerBuildSchema), +}); diff --git a/apps/agentstack-sdk-ts/src/client/api/provider-builds/types.ts b/apps/agentstack-sdk-ts/src/client/api/provider-builds/types.ts new file mode 100644 index 000000000..26bf3bc81 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/provider-builds/types.ts @@ -0,0 +1,21 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { listProviderBuildsRequestSchema, listProviderBuildsResponseSchema, providerBuildSchema } from './schemas'; + +export enum ProviderBuildState { + Missing = 'missing', + InProgress = 'in_progress', + BuildCompleted = 'build_completed', + Completed = 'completed', + Failed = 'failed', +} + +export type ProviderBuild = z.infer; + +export type ListProviderBuildsRequest = z.infer; +export type ListProviderBuildsResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/api/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/schemas.ts new file mode 100644 index 000000000..5d4ddebb4 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/schemas.ts @@ -0,0 +1,12 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './configuration/schemas'; +export * from './connectors/schemas'; +export * from './contexts/schemas'; +export * from './files/schemas'; +export * from './model-providers/schemas'; +export * from './provider-builds/schemas'; +export * from './users/schemas'; diff --git a/apps/agentstack-sdk-ts/src/client/api/types.ts b/apps/agentstack-sdk-ts/src/client/api/types.ts index d678b2a5f..8090e7148 100644 --- a/apps/agentstack-sdk-ts/src/client/api/types.ts +++ b/apps/agentstack-sdk-ts/src/client/api/types.ts @@ -3,109 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import z from 'zod'; - -export const contextSchema = z.object({ - id: z.string(), - created_at: z.string(), - updated_at: z.string(), - last_active_at: z.string(), - created_by: z.string(), - provider_id: z.string().nullable(), - metadata: z.record(z.string(), z.unknown()).nullable(), -}); -export type CreateContextResponse = z.infer; - -export const contextTokenSchema = z.object({ - token: z.string(), - expires_at: z.string().nullable(), -}); -export type ContextToken = z.infer; - -export enum ModelCapability { - Llm = 'llm', - Embedding = 'embedding', -} - -const paginatedResultSchema = z.object({ - items: z.array(z.unknown()), - total_count: z.number(), - has_more: z.boolean(), - next_page_token: z.string().nullable(), -}); - -export const modelProviderMatchSchema = paginatedResultSchema.extend({ - items: z.array( - z.object({ - model_id: z.string(), - score: z.number(), - }), - ), -}); -export type ModelProviderMatch = z.infer; - -export const resourceIdPermissionSchema = z.object({ - id: z.string(), -}); - -export type ResourceIdPermission = z.infer; - -export const contextPermissionsGrantSchema = z.object({ - files: z.array(z.literal(['read', 'write', 'extract', '*'])).optional(), - vector_stores: z.array(z.literal(['read', 'write', '*'])).optional(), - context_data: z.array(z.literal(['read', 'write', '*'])).optional(), -}); - -export type ContextPermissionsGrant = z.infer; - -export const globalPermissionsGrantSchema = contextPermissionsGrantSchema.extend({ - feedback: z.array(z.literal('write')).optional(), - - llm: z.array(z.union([z.literal('*'), resourceIdPermissionSchema])).optional(), - embeddings: z.array(z.union([z.literal('*'), resourceIdPermissionSchema])).optional(), - model_providers: z.array(z.literal(['read', 'write', '*'])).optional(), - - a2a_proxy: z.array(z.literal('*')).optional(), - - providers: z.array(z.literal(['read', 'write', '*'])).optional(), - provider_variables: z.array(z.literal(['read', 'write', '*'])).optional(), - - contexts: z.array(z.literal(['read', 'write', '*'])).optional(), - - mcp_providers: z.array(z.literal(['read', 'write', '*'])).optional(), - mcp_tools: z.array(z.literal(['read', '*'])).optional(), - mcp_proxy: z.array(z.literal('*')).optional(), - - connectors: z.array(z.literal(['read', 'write', 'proxy', '*'])).optional(), -}); - -export type GlobalPermissionsGrant = z.infer; - -export enum ConnectorState { - Created = 'created', - AuthRequired = 'auth_required', - Connected = 'connected', - Disconnected = 'disconnected', -} - -export const connectorSchema = z.object({ - id: z.string(), - url: z.string(), - state: z.enum(ConnectorState), - auth_request: z - .object({ - type: z.literal('code'), - authorization_endpoint: z.string(), - }) - .nullable(), - disconnect_reason: z.string().nullable(), - metadata: z.record(z.string(), z.string()).nullable(), -}); - -export type Connector = z.infer; - -export const listConnectorsResponseSchema = paginatedResultSchema.extend({ - items: z.array(connectorSchema), -}); - -export type ListConnectorsResponse = z.infer; +export * from './configuration/types'; +export * from './connectors/types'; +export * from './contexts/types'; +export * from './files/types'; +export * from './model-providers/types'; +export * from './provider-builds/types'; +export * from './users/types'; diff --git a/apps/agentstack-sdk-ts/src/client/api/users/api.ts b/apps/agentstack-sdk-ts/src/client/api/users/api.ts new file mode 100644 index 000000000..76abff313 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/users/api.ts @@ -0,0 +1,21 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { CallApi } from '../../client/types'; +import { ApiMethod } from '../../client/types'; +import { readUserResponseSchema } from './schemas'; + +export function createUsersApi(callApi: CallApi) { + const readUser = () => + callApi({ + method: ApiMethod.Get, + path: '/api/v1/user', + schema: readUserResponseSchema, + }); + + return { + readUser, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/api/users/schemas.ts b/apps/agentstack-sdk-ts/src/client/api/users/schemas.ts new file mode 100644 index 000000000..9995157da --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/users/schemas.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +import { UserRole } from './types'; + +export const userRoleSchema = z.enum(UserRole); + +export const userSchema = z.object({ + id: z.string(), + role: userRoleSchema, + email: z.string(), + created_at: z.string(), +}); + +export const readUserResponseSchema = userSchema; diff --git a/apps/agentstack-sdk-ts/src/client/api/users/types.ts b/apps/agentstack-sdk-ts/src/client/api/users/types.ts new file mode 100644 index 000000000..cf6ff4f07 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/api/users/types.ts @@ -0,0 +1,18 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { readUserResponseSchema, userSchema } from './schemas'; + +export enum UserRole { + Admin = 'admin', + Developer = 'developer', + User = 'user', +} + +export type User = z.infer; + +export type ReadUserResponse = z.infer; diff --git a/apps/agentstack-sdk-ts/src/client/client/index.ts b/apps/agentstack-sdk-ts/src/client/client/index.ts new file mode 100644 index 000000000..392129544 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/client/index.ts @@ -0,0 +1,147 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import { createConfigurationApi } from '../api/configuration/api'; +import { createConnectorsApi } from '../api/connectors/api'; +import { createContextsApi } from '../api/contexts/api'; +import { createFilesApi } from '../api/files/api'; +import { createModelProvidersApi } from '../api/model-providers/api'; +import { createProviderBuildsApi } from '../api/provider-builds/api'; +import { createUsersApi } from '../api/users/api'; +import { ApiErrorException } from '../errors'; +import type { HttpError, NetworkError, ParseError, ValidationError } from '../errors/types'; +import { ApiErrorType } from '../errors/types'; +import type { ApiFailure, ApiRequest, ApiResult, CallApi } from './types'; +import { buildRequestInit, buildRequestUrl, parseBodyText, safeReadText } from './utils'; + +function createCallApi({ baseUrl, fetch: fetchFn }: { baseUrl: string; fetch: typeof globalThis.fetch }): CallApi { + return async function callApi({ method, path, schema, query, body }) { + const requestUrl = buildRequestUrl({ baseUrl, path, query }); + const requestInit = buildRequestInit({ method, body }); + + const request: ApiRequest = { + method, + url: requestUrl, + }; + + try { + const rawResponse = await fetchFn(requestUrl, requestInit); + const bodyText = await safeReadText(rawResponse); + + const { ok, status, statusText, headers } = rawResponse; + const response = { status, statusText, bodyText }; + + if (!ok) { + return { + ok: false, + error: { + type: ApiErrorType.Http, + message: 'API Http Error', + request, + response, + } satisfies HttpError, + } satisfies ApiFailure; + } + + const { data: parsedBody, error: parseError } = parseBodyText(bodyText, headers); + + if (parseError) { + return { + ok: false, + error: { + type: ApiErrorType.Parse, + message: 'API Parse Error', + request, + response, + details: parseError, + } satisfies ParseError, + } satisfies ApiFailure; + } + + const { data: result, success, error } = schema.safeParse(parsedBody); + + if (!success) { + return { + ok: false, + error: { + type: ApiErrorType.Validation, + message: 'API Validation Error', + request, + response, + details: error, + } satisfies ValidationError, + } satisfies ApiFailure; + } + + return { + ok: true, + data: result, + response, + }; + } catch (details) { + return { + ok: false, + error: { + type: ApiErrorType.Network, + message: 'API Network Error', + request, + details, + } satisfies NetworkError, + } satisfies ApiFailure; + } + }; +} + +export const buildApiClient = ( + { + baseUrl, + fetch: fetchFn, + }: { + baseUrl: string; + fetch?: typeof globalThis.fetch; + } = { baseUrl: '' }, +) => { + const maybeFetch = fetchFn ?? (typeof globalThis.fetch !== 'undefined' ? globalThis.fetch : undefined); + + if (!maybeFetch) { + throw new Error( + 'fetch is not available. In Node.js < 18 or environments without global fetch, provide a fetch implementation via the fetch option.', + ); + } + + const callApi = createCallApi({ baseUrl, fetch: maybeFetch }); + + const configurationApi = createConfigurationApi(callApi); + const connectorsApi = createConnectorsApi(callApi); + const contextsApi = createContextsApi(callApi); + const filesApi = createFilesApi(callApi); + const modelProvidersApi = createModelProvidersApi(callApi); + const providerBuildsApi = createProviderBuildsApi(callApi); + const usersApi = createUsersApi(callApi); + + return { + ...configurationApi, + ...connectorsApi, + ...contextsApi, + ...filesApi, + ...modelProvidersApi, + ...providerBuildsApi, + ...usersApi, + }; +}; + +export function unwrapResult(result: ApiResult): T; +export function unwrapResult(result: ApiResult, schema: z.ZodType): Out; +export function unwrapResult(result: ApiResult, schema?: z.ZodType): T | Out { + if (result.ok) { + const { data } = result; + + return schema ? schema.parse(data) : data; + } + + throw new ApiErrorException(result.error); +} diff --git a/apps/agentstack-sdk-ts/src/client/client/schemas.ts b/apps/agentstack-sdk-ts/src/client/client/schemas.ts new file mode 100644 index 000000000..10294ba10 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/client/schemas.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import z from 'zod'; + +export const paginationQuerySchema = z.object({ + limit: z.number().optional(), + order: z.string().optional(), + order_by: z.string().optional(), + page_token: z.string().nullish(), +}); + +export const paginatedResponseSchema = z.object({ + items: z.array(z.unknown()), + total_count: z.number(), + has_more: z.boolean(), + next_page_token: z.string().nullable(), +}); diff --git a/apps/agentstack-sdk-ts/src/client/client/types.ts b/apps/agentstack-sdk-ts/src/client/client/types.ts new file mode 100644 index 000000000..760d285ca --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/client/types.ts @@ -0,0 +1,56 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type z from 'zod'; + +import type { ApiError } from '../errors/types'; +import type { buildApiClient } from '.'; + +export enum ApiMethod { + Get = 'GET', + Post = 'POST', + Put = 'PUT', + Delete = 'DELETE', + Patch = 'PATCH', +} + +export type ApiQueryParams = Record; +export type ApiRequestBody = Record | FormData; + +export interface ApiParams { + method: ApiMethod; + path: string; + schema: z.ZodSchema; + query?: ApiQueryParams; + body?: ApiRequestBody; +} + +export interface ApiRequest { + method: ApiMethod; + url: string; +} + +export interface ApiResponse { + status: number; + statusText: string; + bodyText: string | null; +} + +export interface ApiSuccess { + ok: true; + data: T; + response: ApiResponse; +} + +export interface ApiFailure { + ok: false; + error: ApiError; +} + +export type ApiResult = ApiSuccess | ApiFailure; + +export type CallApi = (params: ApiParams) => Promise>; + +export type AgentStackClient = ReturnType; diff --git a/apps/agentstack-sdk-ts/src/client/client/utils.ts b/apps/agentstack-sdk-ts/src/client/client/utils.ts new file mode 100644 index 000000000..f8e067d4d --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/client/utils.ts @@ -0,0 +1,90 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { ApiMethod, ApiQueryParams, ApiRequestBody } from './types'; + +export function buildRequestUrl({ baseUrl, path, query }: { baseUrl: string; path: string; query?: ApiQueryParams }) { + const url = `${baseUrl.replace(/\/+$/, '')}${path}`; + + if (query) { + const searchParams = new URLSearchParams(); + + Object.entries(query).forEach(([key, value]) => { + if (value != null) { + searchParams.append(key, String(value)); + } + }); + + const requestUrl = `${url}?${searchParams.toString()}`; + + return requestUrl; + } + + return url; +} + +export function buildRequestInit({ method, body }: { method: ApiMethod; body?: ApiRequestBody }) { + const headers = new Headers(); + + let requestBody: FormData | string | undefined; + + if (body) { + if (body instanceof FormData) { + requestBody = body; + } else { + headers.set('Content-Type', 'application/json'); + + requestBody = JSON.stringify(body); + } + } + + return { + method, + headers, + body: requestBody, + }; +} + +export async function safeReadText(response: Response) { + try { + return await response.text(); + } catch { + return null; + } +} + +export function parseBodyText( + bodyText: string | null, + headers: Headers, +): { + data: unknown; + error?: Error; +} { + if (bodyText == null || bodyText.trim() === '') { + return { + data: null, + }; + } + + const contentType = headers.get('content-type') ?? ''; + const isJsonResponse = contentType.includes('application/json'); + + if (isJsonResponse) { + try { + return { + data: JSON.parse(bodyText), + }; + } catch (error) { + return { + data: null, + error: error instanceof Error ? error : new Error('Failed to parse body text.'), + }; + } + } + + return { + data: bodyText, + }; +} diff --git a/apps/agentstack-sdk-ts/src/client/errors/index.ts b/apps/agentstack-sdk-ts/src/client/errors/index.ts new file mode 100644 index 000000000..024b3f25e --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/errors/index.ts @@ -0,0 +1,41 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { HttpError, NetworkError, ParseError, ValidationError } from './types'; +import { type ApiError, ApiErrorType } from './types'; + +export class ApiErrorException extends Error { + apiError: ApiError; + + constructor(apiError: ApiError) { + super(apiError.message); + + this.apiError = apiError; + } +} + +export function isHttpError(error: ApiError, status?: number): error is HttpError { + if (error.type !== ApiErrorType.Http) { + return false; + } + + if (typeof status === 'number') { + return error.response.status === status; + } + + return true; +} + +export function isNetworkError(error: ApiError): error is NetworkError { + return error.type === ApiErrorType.Network; +} + +export function isParseError(error: ApiError): error is ParseError { + return error.type === ApiErrorType.Parse; +} + +export function isValidationError(error: ApiError): error is ValidationError { + return error.type === ApiErrorType.Validation; +} diff --git a/apps/agentstack-sdk-ts/src/client/errors/types.ts b/apps/agentstack-sdk-ts/src/client/errors/types.ts new file mode 100644 index 000000000..f362b7943 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/client/errors/types.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { ZodError } from 'zod'; + +import type { ApiRequest, ApiResponse } from '../client/types'; + +export enum ApiErrorType { + Http = 'http', + Network = 'network', + Parse = 'parse', + Unknown = 'unknown', + Validation = 'validation', +} + +export interface ApiErrorBase { + message: string; + request: ApiRequest; +} + +export interface HttpError extends ApiErrorBase { + type: ApiErrorType.Http; + response: ApiResponse; +} + +export interface NetworkError extends ApiErrorBase { + type: ApiErrorType.Network; + details: unknown; +} + +export interface ParseError extends ApiErrorBase { + type: ApiErrorType.Parse; + response: ApiResponse; + details: Error; +} + +export interface ValidationError extends ApiErrorBase { + type: ApiErrorType.Validation; + response: ApiResponse; + details: ZodError; +} + +export type ApiError = HttpError | NetworkError | ParseError | ValidationError; diff --git a/apps/agentstack-sdk-ts/src/errors.ts b/apps/agentstack-sdk-ts/src/errors.ts new file mode 100644 index 000000000..37e7037e7 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/errors.ts @@ -0,0 +1,7 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './client/errors'; +export * from './client/errors/types'; diff --git a/apps/agentstack-sdk-ts/src/extensions.ts b/apps/agentstack-sdk-ts/src/extensions.ts new file mode 100644 index 000000000..27bf37aa0 --- /dev/null +++ b/apps/agentstack-sdk-ts/src/extensions.ts @@ -0,0 +1,8 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './client/a2a/extensions'; +export * from './client/a2a/extensions/schemas'; +export * from './client/a2a/extensions/types'; diff --git a/apps/agentstack-sdk-ts/src/index.ts b/apps/agentstack-sdk-ts/src/index.ts index 1ef9a528d..bc0cc66f9 100644 --- a/apps/agentstack-sdk-ts/src/index.ts +++ b/apps/agentstack-sdk-ts/src/index.ts @@ -3,32 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -export * from './client/a2a/extensions/common/form'; -export * from './client/a2a/extensions/fulfillment-resolvers/build-llm-extension-fulfillment-resolver'; -export { type Fulfillments, handleAgentCard } from './client/a2a/extensions/handle-agent-card'; -export { - handleTaskStatusUpdate, - type TaskStatusUpdateResult, - TaskStatusUpdateType, -} from './client/a2a/extensions/handle-task-status-update'; -export { resolveUserMetadata, type UserMetadataInputs } from './client/a2a/extensions/resolve-user-metadata'; -export * from './client/a2a/extensions/services/embedding'; -export * from './client/a2a/extensions/services/form'; -export * from './client/a2a/extensions/services/llm'; -export * from './client/a2a/extensions/services/mcp'; -export * from './client/a2a/extensions/services/oauth-provider'; -export * from './client/a2a/extensions/services/platform'; -export * from './client/a2a/extensions/services/secrets'; +export * from './client/a2a/extensions'; +export * from './client/a2a/extensions/schemas'; export * from './client/a2a/extensions/types'; -export * from './client/a2a/extensions/ui/agent-detail'; -export * from './client/a2a/extensions/ui/canvas'; -export * from './client/a2a/extensions/ui/citation'; -export * from './client/a2a/extensions/ui/error'; -export * from './client/a2a/extensions/ui/form-request'; -export * from './client/a2a/extensions/ui/oauth'; -export * from './client/a2a/extensions/ui/settings'; -export * from './client/a2a/extensions/ui/trajectory'; -export * from './client/a2a/extensions/utils'; -export * from './client/a2a/extensions/utils/build-message-builder'; -export * from './client/api/build-api-client'; +export * from './client/a2a/protocol/schemas'; +export * from './client/a2a/protocol/types'; +export * from './client/a2a/runtime'; +export * from './client/a2a/runtime/types'; +export * from './client/api/schemas'; export * from './client/api/types'; +export * from './client/client'; +export * from './client/client/types'; +export * from './client/errors'; +export * from './client/errors/types'; diff --git a/apps/agentstack-sdk-ts/src/types.ts b/apps/agentstack-sdk-ts/src/types.ts deleted file mode 100644 index 619fab567..000000000 --- a/apps/agentstack-sdk-ts/src/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import z from 'zod'; - -export const interactionModeSchema = z.enum(['single-turn', 'multi-turn']); -export type InteractionMode = z.infer; diff --git a/apps/agentstack-ui/src/api/a2a/client.ts b/apps/agentstack-ui/src/api/a2a/client.ts index 845041b7f..27239b9a0 100644 --- a/apps/agentstack-ui/src/api/a2a/client.ts +++ b/apps/agentstack-ui/src/api/a2a/client.ts @@ -4,6 +4,7 @@ */ import type { TaskArtifactUpdateEvent, TaskStatusUpdateEvent } from '@a2a-js/sdk'; +import type { Message } from 'agentstack-sdk'; import { handleAgentCard, handleTaskStatusUpdate, resolveUserMetadata } from 'agentstack-sdk'; import { defaultIfEmpty, filter, lastValueFrom, Subject } from 'rxjs'; import { match } from 'ts-pattern'; @@ -41,7 +42,8 @@ function handleStatusUpdate( return []; } - const metadataParts = processMessageMetadata(message); + // TODO: Resolve so that we don't have to use typecasting + const metadataParts = processMessageMetadata(message as Message); const contentParts = processParts(message.parts); const genericParts = onStatusUpdate?.(event) || []; diff --git a/apps/agentstack-ui/src/api/a2a/part-processors.ts b/apps/agentstack-ui/src/api/a2a/part-processors.ts index 1b466627f..bb90539e4 100644 --- a/apps/agentstack-ui/src/api/a2a/part-processors.ts +++ b/apps/agentstack-ui/src/api/a2a/part-processors.ts @@ -3,7 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { FilePart, Message, Part, TextPart } from '@a2a-js/sdk'; +import type { FilePart, TextPart } from '@a2a-js/sdk'; +import type { Message, Part } from 'agentstack-sdk'; import { match } from 'ts-pattern'; import { v4 as uuid } from 'uuid'; diff --git a/apps/agentstack-ui/src/api/a2a/utils.ts b/apps/agentstack-ui/src/api/a2a/utils.ts index 28e08890f..6e406d015 100644 --- a/apps/agentstack-ui/src/api/a2a/utils.ts +++ b/apps/agentstack-ui/src/api/a2a/utils.ts @@ -116,7 +116,7 @@ export function getFileUrl(file: FilePart['file']): string { return `data:${mimeType};base64,${bytes}`; } -export function createSourcePart(citation: Citation, taskId: string | undefined): UISourcePart | null { +export function createSourcePart(citation: Citation, taskId: string | undefined | null): UISourcePart | null { const { url, start_index, end_index, title, description } = citation; if (!url || !taskId) { diff --git a/apps/agentstack-ui/src/api/agentstack-client.ts b/apps/agentstack-ui/src/api/agentstack-client.ts index dde68b642..ba9e17c72 100644 --- a/apps/agentstack-ui/src/api/agentstack-client.ts +++ b/apps/agentstack-ui/src/api/agentstack-client.ts @@ -7,12 +7,11 @@ import { buildApiClient } from 'agentstack-sdk'; import { ensureToken } from '#app/(auth)/rsc.tsx'; import { runtimeConfig } from '#contexts/App/runtime-config.ts'; -import { listConnectorsResponseSchema } from '#modules/connectors/api/types.ts'; import { getBaseUrl } from '#utils/api/getBaseUrl.ts'; -import { getProxyHeaders, handleFailedResponse } from './utils'; +import { getProxyHeaders } from './utils'; -function buildAuthenticatedAgentstackClient() { +function buildAuthenticatedAgentStackClient() { const { isAuthEnabled } = runtimeConfig; const baseUrl = getBaseUrl(); @@ -28,10 +27,13 @@ function buildAuthenticatedAgentstackClient() { } const isServer = typeof window === 'undefined'; + if (isServer) { const { headers } = await import('next/headers'); const { forwarded, forwardedHost, forwardedFor, forwardedProto } = await getProxyHeaders(await headers()); + request.headers.set('forwarded', forwarded); + if (forwardedHost) request.headers.set('x-forwarded-host', forwardedHost); if (forwardedProto) request.headers.set('x-forwarded-proto', forwardedProto); if (forwardedFor) request.headers.set('x-forwarded-for', forwardedFor); @@ -39,25 +41,12 @@ function buildAuthenticatedAgentstackClient() { const response = await fetch(request); - if (!response.ok) { - const error = await response.json(); - handleFailedResponse({ response, error }); - } - return response; }; const client = buildApiClient({ baseUrl, fetch: authenticatedFetch }); + return client; } -const baseAgentstackClient = buildAuthenticatedAgentstackClient(); - -export const agentstackClient = { - ...baseAgentstackClient, - listConnectors: async () => { - const response = await baseAgentstackClient.listConnectors(); - - return listConnectorsResponseSchema.parse(response); - }, -}; +export const agentStackClient = buildAuthenticatedAgentStackClient(); diff --git a/apps/agentstack-ui/src/api/index.ts b/apps/agentstack-ui/src/api/index.ts index bea54feb7..802232169 100644 --- a/apps/agentstack-ui/src/api/index.ts +++ b/apps/agentstack-ui/src/api/index.ts @@ -51,7 +51,7 @@ const proxyMiddleware: Middleware = { /** * @deprecated - * Use agentstackClient instead + * Use agentStackClient instead */ export const api = createClient({ baseUrl: getBaseUrl(), diff --git a/apps/agentstack-ui/src/app/(main)/run/[providerId]/c/[contextId]/page.tsx b/apps/agentstack-ui/src/app/(main)/run/[providerId]/c/[contextId]/page.tsx index b55fefa77..cb795e6a4 100644 --- a/apps/agentstack-ui/src/app/(main)/run/[providerId]/c/[contextId]/page.tsx +++ b/apps/agentstack-ui/src/app/(main)/run/[providerId]/c/[contextId]/page.tsx @@ -32,7 +32,7 @@ export default async function AgentRunPage({ params }: Props) { const [agent, initialData] = await Promise.all([ fetchAgent(providerId), fetchContextHistory({ - contextId, + context_id: contextId, query: LIST_CONTEXT_HISTORY_DEFAULT_QUERY, }), ]); diff --git a/apps/agentstack-ui/src/app/(main)/run/[providerId]/ensure-model-selected.tsx b/apps/agentstack-ui/src/app/(main)/run/[providerId]/ensure-model-selected.tsx index 528fdc2df..b945c028d 100644 --- a/apps/agentstack-ui/src/app/(main)/run/[providerId]/ensure-model-selected.tsx +++ b/apps/agentstack-ui/src/app/(main)/run/[providerId]/ensure-model-selected.tsx @@ -9,7 +9,7 @@ import type { ReactElement } from 'react'; import { getAgentClient } from '#api/a2a/agent-card.ts'; import { handleApiError } from '#app/(auth)/rsc.tsx'; import { ErrorPage } from '#components/ErrorPage/ErrorPage.tsx'; -import { readConfigurationsSystem } from '#modules/configurations/api/index.ts'; +import { readSystemConfiguration } from '#modules/configuration/api/index.ts'; import { ModelType, NoModelSelectedErrorPage } from '#modules/runs/components/NoModelSelectedErrorPage.tsx'; export async function ensureModelSelected(providerId: string) { @@ -23,7 +23,7 @@ export async function ensureModelSelected(providerId: string) { let ErrorComponent: ReactElement | null = null; if (llmDemands || embeddingDemands) { try { - const config = await readConfigurationsSystem(); + const config = await readSystemConfiguration(); if (llmDemands && !config?.default_llm_model) { ErrorComponent = ; } else if (embeddingDemands && !config?.default_embedding_model) { diff --git a/apps/agentstack-ui/src/modules/agents/api/types.ts b/apps/agentstack-ui/src/modules/agents/api/types.ts index 892824550..dbd347a42 100644 --- a/apps/agentstack-ui/src/modules/agents/api/types.ts +++ b/apps/agentstack-ui/src/modules/agents/api/types.ts @@ -19,11 +19,6 @@ export interface Agent extends Omit { export type AgentExtension = NonNullable[number]; -export enum InteractionMode { - MultiTurn = 'multi-turn', - SingleTurn = 'single-turn', -} - export enum ListAgentsOrderBy { Name = 'name', CreatedAt = 'created_at', diff --git a/apps/agentstack-ui/src/modules/agents/components/detail/AgentHeading.tsx b/apps/agentstack-ui/src/modules/agents/components/detail/AgentHeading.tsx index add35b055..f2a6876b4 100644 --- a/apps/agentstack-ui/src/modules/agents/components/detail/AgentHeading.tsx +++ b/apps/agentstack-ui/src/modules/agents/components/detail/AgentHeading.tsx @@ -3,11 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { InteractionMode } from 'agentstack-sdk'; import clsx from 'clsx'; import { AgentIcon } from '#modules/runs/components/AgentIcon.tsx'; -import { type Agent, InteractionMode } from '../../api/types'; +import type { Agent } from '../../api/types'; import classes from './AgentHeading.module.scss'; interface Props { diff --git a/apps/agentstack-ui/src/modules/agents/components/detail/AgentRunGreeting.tsx b/apps/agentstack-ui/src/modules/agents/components/detail/AgentRunGreeting.tsx index e0164e7da..c286680a7 100644 --- a/apps/agentstack-ui/src/modules/agents/components/detail/AgentRunGreeting.tsx +++ b/apps/agentstack-ui/src/modules/agents/components/detail/AgentRunGreeting.tsx @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { InteractionMode } from 'agentstack-sdk'; import { memo } from 'react'; -import { type Agent, InteractionMode } from '../../api/types'; +import type { Agent } from '../../api/types'; import { AgentWelcomeMessage } from './AgentWelcomeMessage'; interface Props { diff --git a/apps/agentstack-ui/src/modules/configuration/api/index.ts b/apps/agentstack-ui/src/modules/configuration/api/index.ts new file mode 100644 index 000000000..3f3820c32 --- /dev/null +++ b/apps/agentstack-ui/src/modules/configuration/api/index.ts @@ -0,0 +1,15 @@ +/** + * Copyright 2025 © BeeAI a Series of LF Projects, LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { unwrapResult } from 'agentstack-sdk'; + +import { agentStackClient } from '#api/agentstack-client.ts'; + +export async function readSystemConfiguration() { + const response = await agentStackClient.readSystemConfiguration(); + const result = unwrapResult(response); + + return result; +} diff --git a/apps/agentstack-ui/src/modules/configurations/api/index.ts b/apps/agentstack-ui/src/modules/configurations/api/index.ts deleted file mode 100644 index d2efbe32e..000000000 --- a/apps/agentstack-ui/src/modules/configurations/api/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { api } from '#api/index.ts'; -import { ensureData } from '#api/utils.ts'; - -export async function readConfigurationsSystem() { - const response = await api.GET('/api/v1/configurations/system'); - - return ensureData(response); -} diff --git a/apps/agentstack-ui/src/modules/connectors/api/index.ts b/apps/agentstack-ui/src/modules/connectors/api/index.ts index 1104a364a..a92505414 100644 --- a/apps/agentstack-ui/src/modules/connectors/api/index.ts +++ b/apps/agentstack-ui/src/modules/connectors/api/index.ts @@ -3,46 +3,60 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { api } from '#api/index.ts'; -import { ensureData } from '#api/utils.ts'; -import { BASE_URL } from '#utils/constants.ts'; - import type { - ConnectConnectorPath, + ConnectConnectorRequest, CreateConnectorRequest, - DeleteConnectorPath, - DisconnectConnectorPath, -} from './types'; + DeleteConnectorRequest, + DisconnectConnectorRequest, +} from 'agentstack-sdk'; +import { unwrapResult } from 'agentstack-sdk'; + +import { agentStackClient } from '#api/agentstack-client.ts'; +import { BASE_URL } from '#utils/constants.ts'; + +import { connectorSchema, listConnectorPresetsResponseSchema, listConnectorsResponseSchema } from './types'; + +export async function listConnectors() { + const response = await agentStackClient.listConnectors(); + const result = unwrapResult(response, listConnectorsResponseSchema); + + return result; +} -export async function createConnector(body: CreateConnectorRequest) { - const response = await api.POST('/api/v1/connectors', { body }); +export async function createConnector(request: CreateConnectorRequest) { + const response = await agentStackClient.createConnector(request); + const result = unwrapResult(response, connectorSchema); - return ensureData(response); + return result; } -export async function deleteConnector(path: DeleteConnectorPath) { - const response = await api.DELETE('/api/v1/connectors/{connector_id}', { params: { path } }); +export async function deleteConnector(request: DeleteConnectorRequest) { + const response = await agentStackClient.deleteConnector(request); + const result = unwrapResult(response); - return ensureData(response); + return result; } -export async function connectConnector(path: ConnectConnectorPath) { - const response = await api.POST('/api/v1/connectors/{connector_id}/connect', { - params: { path }, - body: { redirect_url: `${BASE_URL}/oauth-callback` }, +export async function connectConnector(request: ConnectConnectorRequest) { + const response = await agentStackClient.connectConnector({ + redirect_url: `${BASE_URL}/oauth-callback`, + ...request, }); + const result = unwrapResult(response, connectorSchema); - return ensureData(response); + return result; } -export async function disconnectConnector(path: DisconnectConnectorPath) { - const response = await api.POST('/api/v1/connectors/{connector_id}/disconnect', { params: { path } }); +export async function disconnectConnector(request: DisconnectConnectorRequest) { + const response = await agentStackClient.disconnectConnector(request); + const result = unwrapResult(response, connectorSchema); - return ensureData(response); + return result; } export async function listConnectorPresets() { - const response = await api.GET('/api/v1/connectors/presets'); + const response = await agentStackClient.listConnectorPresets(); + const result = unwrapResult(response, listConnectorPresetsResponseSchema); - return ensureData(response); + return result; } diff --git a/apps/agentstack-ui/src/modules/connectors/api/mutations/useCreateConnector.ts b/apps/agentstack-ui/src/modules/connectors/api/mutations/useCreateConnector.ts index 4f1da969e..9a949f53f 100644 --- a/apps/agentstack-ui/src/modules/connectors/api/mutations/useCreateConnector.ts +++ b/apps/agentstack-ui/src/modules/connectors/api/mutations/useCreateConnector.ts @@ -10,7 +10,7 @@ import { connectorKeys } from '../keys'; import type { Connector } from '../types'; interface Props { - onSuccess?: (connector: Connector | undefined) => void; + onSuccess?: (connector: Connector) => void; } export function useCreateConnector({ onSuccess }: Props = {}) { diff --git a/apps/agentstack-ui/src/modules/connectors/api/queries/useListConnectors.ts b/apps/agentstack-ui/src/modules/connectors/api/queries/useListConnectors.ts index fd06f1ab2..b00b7b64e 100644 --- a/apps/agentstack-ui/src/modules/connectors/api/queries/useListConnectors.ts +++ b/apps/agentstack-ui/src/modules/connectors/api/queries/useListConnectors.ts @@ -5,14 +5,13 @@ import { useQuery } from '@tanstack/react-query'; -import { agentstackClient } from '#api/agentstack-client.ts'; - +import { listConnectors } from '..'; import { connectorKeys } from '../keys'; export function useListConnectors() { const query = useQuery({ queryKey: connectorKeys.list(), - queryFn: agentstackClient.listConnectors, + queryFn: listConnectors, }); return query; diff --git a/apps/agentstack-ui/src/modules/connectors/api/types.ts b/apps/agentstack-ui/src/modules/connectors/api/types.ts index 15c07fbc2..48b100d00 100644 --- a/apps/agentstack-ui/src/modules/connectors/api/types.ts +++ b/apps/agentstack-ui/src/modules/connectors/api/types.ts @@ -4,14 +4,14 @@ */ import { + connectorPresetSchema as sdkConnectorPresetSchema, connectorSchema as sdkConnectorSchema, + listConnectorPresetsResponseSchema as sdkListConnectorPresetsResponseSchema, listConnectorsResponseSchema as sdkListConnectorsResponseSchema, } from 'agentstack-sdk'; import z from 'zod'; -import type { ApiPath, ApiRequest, ApiResponse } from '#@types/utils.ts'; - -const connectorMetadataSchema = z +export const connectorMetadataSchema = z .object({ name: z.string().optional(), }) @@ -20,28 +20,24 @@ const connectorMetadataSchema = z export const connectorSchema = sdkConnectorSchema.extend({ metadata: connectorMetadataSchema, }); +export type Connector = z.infer; export const listConnectorsResponseSchema = sdkListConnectorsResponseSchema.extend({ items: z.array(connectorSchema), }); - -export type Connector = z.infer; - export type ListConnectorsResponse = z.infer; -export type CreateConnectorRequest = ApiRequest<'/api/v1/connectors'>; - -export type ConnectConnectorPath = ApiPath<'/api/v1/connectors/{connector_id}/connect', 'post'>; - -export type DisconnectConnectorPath = ApiPath<'/api/v1/connectors/{connector_id}/disconnect', 'post'>; - -export type DeleteConnectorPath = ApiPath<'/api/v1/connectors/{connector_id}', 'delete'>; +export const connectorPresetMetadataSchema = z.object({ + name: z.string().optional(), + description: z.string().optional(), +}); -export type ListConnectorPresetsResponse = ApiResponse<'/api/v1/connectors/presets'>; +export const connectorPresetSchema = sdkConnectorPresetSchema.extend({ + metadata: connectorPresetMetadataSchema.nullable(), +}); +export type ConnectorPreset = z.infer; -export type ConnectorPreset = Omit & { - metadata: { - name?: string; - description?: string; - } | null; -}; +export const listConnectorPresetsResponseSchema = sdkListConnectorPresetsResponseSchema.extend({ + items: z.array(connectorPresetSchema), +}); +export type ListConnectorPresetsResponse = z.infer; diff --git a/apps/agentstack-ui/src/modules/connectors/components/ConnectPresetButton.tsx b/apps/agentstack-ui/src/modules/connectors/components/ConnectPresetButton.tsx index 33bf6c76d..6399032f9 100644 --- a/apps/agentstack-ui/src/modules/connectors/components/ConnectPresetButton.tsx +++ b/apps/agentstack-ui/src/modules/connectors/components/ConnectPresetButton.tsx @@ -23,13 +23,7 @@ export function ConnectPresetButton({ preset, className }: Props) { const { data: connectors, isPending: isConnectorsPending } = useListConnectors(); const { mutate: createConnector, isPending: isCreatePending } = useCreateConnector({ - onSuccess: (connector) => { - if (!connector) { - return; - } - - connect(connector.id); - }, + onSuccess: ({ id }) => connect(id), }); const { connect, isPending: isConnectPending } = useConnect(); const { disconnect, isPending: isDisconnectPending } = useDisconnect(); diff --git a/apps/agentstack-ui/src/modules/files/api/index.ts b/apps/agentstack-ui/src/modules/files/api/index.ts index 84b8a332b..128aea598 100644 --- a/apps/agentstack-ui/src/modules/files/api/index.ts +++ b/apps/agentstack-ui/src/modules/files/api/index.ts @@ -3,31 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { api } from '#api/index.ts'; -import { ensureData } from '#api/utils.ts'; +import type { DeleteFileRequest } from 'agentstack-sdk'; +import { unwrapResult } from 'agentstack-sdk'; -import type { DeleteFileParams, UploadFileParams, UploadFileRequest } from './types'; +import { agentStackClient } from '#api/agentstack-client.ts'; -export async function uploadFile({ context_id, file }: UploadFileParams) { - const response = await api.POST('/api/v1/files', { - params: { query: { context_id } }, - body: { file: file.originalFile } as unknown as UploadFileRequest, - bodySerializer: (body) => { - const formData = new FormData(); +import type { UploadFileParams } from './types'; - formData.append('file', body.file); +export async function uploadFile({ file, ...request }: UploadFileParams) { + const response = await agentStackClient.createFile({ ...request, file: file.originalFile }); + const result = unwrapResult(response); - return formData; - }, - }); - - return ensureData(response); + return result; } -export async function deleteFile({ file_id, context_id }: DeleteFileParams) { - const response = await api.DELETE('/api/v1/files/{file_id}', { - params: { path: { file_id }, query: { context_id } }, - }); +export async function deleteFile(request: DeleteFileRequest) { + const response = await agentStackClient.deleteFile(request); + const result = unwrapResult(response); - return ensureData(response); + return result; } diff --git a/apps/agentstack-ui/src/modules/files/api/mutations/useUploadFile.ts b/apps/agentstack-ui/src/modules/files/api/mutations/useUploadFile.ts index 07fa07940..8603f763e 100644 --- a/apps/agentstack-ui/src/modules/files/api/mutations/useUploadFile.ts +++ b/apps/agentstack-ui/src/modules/files/api/mutations/useUploadFile.ts @@ -4,13 +4,14 @@ */ import { useMutation } from '@tanstack/react-query'; +import type { CreateFileResponse } from 'agentstack-sdk'; import { uploadFile } from '..'; -import type { UploadFileParams, UploadFileResponse } from '../types'; +import type { UploadFileParams } from '../types'; interface Props { onMutate?: (variables: UploadFileParams) => void; - onSuccess?: (data: UploadFileResponse | undefined, variables: UploadFileParams) => void; + onSuccess?: (data: CreateFileResponse, variables: UploadFileParams) => void; onError?: (error: Error, variables: UploadFileParams) => void; } diff --git a/apps/agentstack-ui/src/modules/files/api/types.ts b/apps/agentstack-ui/src/modules/files/api/types.ts index a356ccd69..0df7d1eaf 100644 --- a/apps/agentstack-ui/src/modules/files/api/types.ts +++ b/apps/agentstack-ui/src/modules/files/api/types.ts @@ -3,15 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ApiPath, ApiQuery, ApiRequest, ApiResponse } from '#@types/utils.ts'; +import type { CreateFileRequest } from 'agentstack-sdk'; import type { FileEntity } from '../types'; -export type UploadFileQuery = ApiQuery<'/api/v1/files', 'post'>; -export type UploadFileRequest = ApiRequest<'/api/v1/files', 'post', 'multipart/form-data'>; -export type UploadFileParams = UploadFileQuery & Omit & { file: FileEntity }; -export type UploadFileResponse = ApiResponse<'/api/v1/files', 'post', 'application/json', 201>; - -export type DeleteFileQuery = ApiQuery<'/api/v1/files/{file_id}', 'delete'>; -export type DeleteFilePath = ApiPath<'/api/v1/files/{file_id}', 'delete'>; -export type DeleteFileParams = DeleteFilePath & DeleteFileQuery; +export type UploadFileParams = Omit & { file: FileEntity }; diff --git a/apps/agentstack-ui/src/modules/files/types.ts b/apps/agentstack-ui/src/modules/files/types.ts index f9f8fc780..6ea380517 100644 --- a/apps/agentstack-ui/src/modules/files/types.ts +++ b/apps/agentstack-ui/src/modules/files/types.ts @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { UploadFileResponse } from './api/types'; +import type { CreateFileResponse } from 'agentstack-sdk'; export interface FileEntity { id: string; originalFile: File; status: FileStatus; - uploadFile?: UploadFileResponse; + uploadFile?: CreateFileResponse; error?: string; } diff --git a/apps/agentstack-ui/src/modules/form/components/FormField.tsx b/apps/agentstack-ui/src/modules/form/components/FormField.tsx index 567b032ee..bcc1c599a 100644 --- a/apps/agentstack-ui/src/modules/form/components/FormField.tsx +++ b/apps/agentstack-ui/src/modules/form/components/FormField.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { FormField, FormResponseValue } from 'agentstack-sdk'; +import type { FormField, FormFieldValue } from 'agentstack-sdk'; import type { CSSProperties } from 'react'; import { match, P } from 'ts-pattern'; @@ -18,7 +18,7 @@ import classes from './FormField.module.scss'; interface Props { field: FormField; - value?: FormResponseValue; + value?: FormFieldValue; } export function FormField({ field, value }: Props) { diff --git a/apps/agentstack-ui/src/modules/form/components/fields/FileFieldValue.tsx b/apps/agentstack-ui/src/modules/form/components/fields/FileFieldValue.tsx index e3e95cf07..f8102fa03 100644 --- a/apps/agentstack-ui/src/modules/form/components/fields/FileFieldValue.tsx +++ b/apps/agentstack-ui/src/modules/form/components/fields/FileFieldValue.tsx @@ -4,7 +4,7 @@ */ import { FormGroup } from '@carbon/react'; -import type { FileField, FormResponseValue } from 'agentstack-sdk'; +import type { FileField, FormFieldValue } from 'agentstack-sdk'; import { getFileIdFromFilePlatformUrl } from '#api/a2a/utils.ts'; import { FileCard } from '#modules/files/components/FileCard.tsx'; @@ -15,7 +15,7 @@ import classes from './FielFieldValue.module.scss'; interface Props { field: FileField; - value: NonNullable['value']>; + value: NonNullable['value']>; } export function FileFieldValue({ field, value }: Props) { diff --git a/apps/agentstack-ui/src/modules/form/types.ts b/apps/agentstack-ui/src/modules/form/types.ts index cc1c43511..e88bf2416 100644 --- a/apps/agentstack-ui/src/modules/form/types.ts +++ b/apps/agentstack-ui/src/modules/form/types.ts @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { FormField, FormResponseValue } from 'agentstack-sdk'; +import type { FormField, FormFieldValue } from 'agentstack-sdk'; -export type RunFormValues = Record; +export type RunFormValues = Record; -export type ValueOfField = Extract; +export type ValueOfField = Extract; export type ValuesOfField = Record>; diff --git a/apps/agentstack-ui/src/modules/history/utils.ts b/apps/agentstack-ui/src/modules/history/utils.ts index 0d2fa29a0..fcf642ca2 100644 --- a/apps/agentstack-ui/src/modules/history/utils.ts +++ b/apps/agentstack-ui/src/modules/history/utils.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { Artifact, Message } from '@a2a-js/sdk'; +import { type ContextHistory, MessageRole } from 'agentstack-sdk'; import { match } from 'ts-pattern'; import { v4 as uuid } from 'uuid'; @@ -12,25 +12,24 @@ import { Role } from '#modules/messages/api/types.ts'; import type { UIAgentMessage, UIUserMessage } from '#modules/messages/types.ts'; import { type UIMessage, UIMessageStatus } from '#modules/messages/types.ts'; import { addMessagePart } from '#modules/messages/utils.ts'; -import type { ContextHistoryItem } from '#modules/platform-context/api/types.ts'; import type { TaskId } from '#modules/tasks/api/types.ts'; -export function convertHistoryToUIMessages(history: ContextHistoryItem[]): UIMessage[] { +export function convertHistoryToUIMessages(history: ContextHistory[]): UIMessage[] { const { messages } = history.reduce<{ messages: UIMessage[]; taskId?: TaskId }>( ({ messages, taskId }, { data }) => { let lastTaskId = taskId; const message = match(data) - .with({ kind: 'message' }, (message: Message) => { + .with({ kind: 'message' }, (message) => { const metadataParts = processMessageMetadata(message); const contentParts = processParts(message.parts); const parts = [...metadataParts, ...contentParts]; - lastTaskId = message.taskId; + lastTaskId = message.taskId ?? undefined; const { messageId } = message; return match(message) - .with({ role: 'agent' }, (): UIAgentMessage => { + .with({ role: MessageRole.Agent }, (): UIAgentMessage => { const uiMessage: UIAgentMessage = { id: messageId, role: Role.Agent, @@ -48,7 +47,7 @@ export function convertHistoryToUIMessages(history: ContextHistoryItem[]): UIMes return uiMessage; }) .with( - { role: 'user' }, + { role: MessageRole.User }, (): UIUserMessage => ({ id: messageId, role: Role.User, @@ -58,7 +57,7 @@ export function convertHistoryToUIMessages(history: ContextHistoryItem[]): UIMes ) .exhaustive(); }) - .otherwise((artifact: Artifact): UIAgentMessage => { + .otherwise((artifact): UIAgentMessage => { const contentParts = processParts(artifact.parts); return { diff --git a/apps/agentstack-ui/src/modules/messages/contexts/Messages/MessagesProvider.tsx b/apps/agentstack-ui/src/modules/messages/contexts/Messages/MessagesProvider.tsx index d6b2886f8..10fcfdef5 100644 --- a/apps/agentstack-ui/src/modules/messages/contexts/Messages/MessagesProvider.tsx +++ b/apps/agentstack-ui/src/modules/messages/contexts/Messages/MessagesProvider.tsx @@ -21,7 +21,7 @@ export function MessagesProvider({ children }: PropsWithChildren) { const { contextId, history: initialHistory } = usePlatformContext(); const { data: history, ...queryRest } = useListContextHistory({ - contextId: contextId ?? undefined, + context_id: contextId ?? undefined, query: LIST_CONTEXT_HISTORY_DEFAULT_QUERY, initialData: initialHistory, // Ensures newly created messages are not fetched from history diff --git a/apps/agentstack-ui/src/modules/platform-context/api/constants.ts b/apps/agentstack-ui/src/modules/platform-context/api/constants.ts index fa05d7b8f..760e6ef9e 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/constants.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/constants.ts @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ListContextHistoryQuery, ListContextsQuery } from './types'; +import type { ListContextHistoryRequest, ListContextsRequest } from 'agentstack-sdk'; -export const LIST_CONTEXTS_DEFAULT_QUERY: ListContextsQuery = { limit: 10, include_empty: false }; +export const LIST_CONTEXTS_DEFAULT_QUERY: ListContextsRequest['query'] = { limit: 10, include_empty: false }; -export const LIST_CONTEXT_HISTORY_DEFAULT_QUERY: ListContextHistoryQuery = { limit: 10 }; +export const LIST_CONTEXT_HISTORY_DEFAULT_QUERY: ListContextHistoryRequest['query'] = { limit: 10 }; diff --git a/apps/agentstack-ui/src/modules/platform-context/api/index.ts b/apps/agentstack-ui/src/modules/platform-context/api/index.ts index 6294acd0d..974282c40 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/index.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/index.ts @@ -3,61 +3,70 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { CreateContextResponse, CreateContextTokenParams, MatchProvidersParams } from 'agentstack-sdk'; +import type { + CreateContextRequest, + CreateContextTokenRequest, + DeleteContextRequest, + ListContextHistoryRequest, + ListContextsRequest, +} from 'agentstack-sdk'; +import { type MatchModelProvidersRequest, unwrapResult } from 'agentstack-sdk'; -import { agentstackClient } from '#api/agentstack-client.ts'; -import { api } from '#api/index.ts'; -import { ensureData, fetchEntity } from '#api/utils.ts'; +import { agentStackClient } from '#api/agentstack-client.ts'; +import { fetchEntity } from '#api/utils.ts'; -import type { - DeleteContextParams, - ListContextHistoryParams, - ListContextsParams, - UpdateContextMetadataParams, -} from './types'; +import type { PatchContextMetadataRequest } from './types'; +import { contextSchema, listContextsResponseSchema } from './types'; + +export async function listContexts(request: ListContextsRequest) { + const response = await agentStackClient.listContexts(request); + const result = unwrapResult(response, listContextsResponseSchema); -export async function createContext(providerId: string): Promise { - return await agentstackClient.createContext(providerId); + return result; } -export async function listContexts(params: ListContextsParams) { - const response = await api.GET('/api/v1/contexts', { params }); +export async function createContext(request: CreateContextRequest) { + const response = await agentStackClient.createContext(request); + const result = unwrapResult(response, contextSchema); - return ensureData(response); + return result; } -export async function updateContextMetadata({ context_id, metadata }: UpdateContextMetadataParams) { - const response = await api.PATCH('/api/v1/contexts/{context_id}/metadata', { - body: { metadata }, - params: { path: { context_id } }, - }); +export async function deleteContext(request: DeleteContextRequest) { + const response = await agentStackClient.deleteContext(request); + const result = unwrapResult(response); - return ensureData(response); + return result; } -export async function deleteContext(path: DeleteContextParams) { - const response = await api.DELETE('/api/v1/contexts/{context_id}', { params: { path } }); +export async function listContextHistory(request: ListContextHistoryRequest) { + const response = await agentStackClient.listContextHistory(request); + const result = unwrapResult(response); - return ensureData(response); + return result; } -export async function listContextHistory({ contextId, query }: ListContextHistoryParams) { - const response = await api.GET('/api/v1/contexts/{context_id}/history', { - params: { path: { context_id: contextId }, query }, - }); +export async function patchContextMetadata(request: PatchContextMetadataRequest) { + const response = await agentStackClient.patchContextMetadata(request); + const result = unwrapResult(response, contextSchema); - return ensureData(response); + return result; } -export async function matchProviders(matchProvidersParams: MatchProvidersParams) { - return await agentstackClient.matchProviders(matchProvidersParams); +export async function matchModelProviders(request: MatchModelProvidersRequest) { + const response = await agentStackClient.matchModelProviders(request); + const result = unwrapResult(response); + + return result; } -export async function createContextToken(createContextTokenParams: CreateContextTokenParams) { - const result = await agentstackClient.createContextToken(createContextTokenParams); - return result.token; +export async function createContextToken(request: CreateContextTokenRequest) { + const response = await agentStackClient.createContextToken(request); + const result = unwrapResult(response); + + return result; } -export async function fetchContextHistory(params: ListContextHistoryParams) { - return await fetchEntity(() => listContextHistory(params)); +export async function fetchContextHistory(request: ListContextHistoryRequest) { + return await fetchEntity(() => listContextHistory(request)); } diff --git a/apps/agentstack-ui/src/modules/platform-context/api/keys.ts b/apps/agentstack-ui/src/modules/platform-context/api/keys.ts index 04ae83372..f8efb795c 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/keys.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/keys.ts @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ListContextHistoryParams, ListContextsParams } from './types'; +import type { ListContextHistoryRequest, ListContextsRequest } from 'agentstack-sdk'; export const contextKeys = { all: () => ['contexts'] as const, lists: () => [...contextKeys.all(), 'list'] as const, - list: ({ query = {} }: ListContextsParams) => [...contextKeys.lists(), query] as const, + list: ({ query = {} }: ListContextsRequest) => [...contextKeys.lists(), query] as const, histories: () => [...contextKeys.all(), 'history'] as const, - history: ({ contextId, query = {} }: ListContextHistoryParams) => - [...contextKeys.histories(), contextId, query] as const, + history: ({ context_id, query = {} }: ListContextHistoryRequest) => + [...contextKeys.histories(), context_id, query] as const, }; diff --git a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useCreateContext.ts b/apps/agentstack-ui/src/modules/platform-context/api/mutations/useCreateContext.ts index bc0968999..bdb084983 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useCreateContext.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/mutations/useCreateContext.ts @@ -4,12 +4,16 @@ */ import { useMutation } from '@tanstack/react-query'; -import type { CreateContextResponse } from 'agentstack-sdk'; +import type { Context } from 'agentstack-sdk'; import { createContext } from '..'; import { contextKeys } from '../keys'; -export function useCreateContext({ onSuccess }: { onSuccess?: (data: CreateContextResponse) => void } = {}) { +interface Props { + onSuccess?: (data: Context) => void; +} + +export function useCreateContext({ onSuccess }: Props = {}) { const mutation = useMutation({ mutationFn: createContext, onSuccess, diff --git a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchProviders.ts b/apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchModelProviders.ts similarity index 79% rename from apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchProviders.ts rename to apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchModelProviders.ts index 7429d9cdd..d426b84e2 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchProviders.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/mutations/useMatchModelProviders.ts @@ -11,19 +11,19 @@ import { useEffect } from 'react'; import { useApp } from '#contexts/App/index.ts'; import { MODEL_SETUP_COMMAND } from '#utils/constants.ts'; -import { matchProviders } from '..'; +import { matchModelProviders } from '..'; const MAX_PROVIDERS = 5; -type MatchProvidersResult = Record; +type MatchModelProvidersResult = Record; interface Props { demands: EmbeddingDemands['embedding_demands'] | LLMDemands['llm_demands']; - onSuccess: (data: MatchProvidersResult) => void; + onSuccess: (data: MatchModelProvidersResult) => void; capability: ModelCapability; } -export function useMatchProviders({ demands, onSuccess, capability }: Props) { +export function useMatchModelProviders({ demands, onSuccess, capability }: Props) { const { config: { featureFlags }, } = useApp(); @@ -40,9 +40,9 @@ export function useMatchProviders({ demands, onSuccess, capability }: Props) { queryFn: async () => { const allProviders = await Promise.all( demandKeys.map(async (demandKey) => { - const result = await matchProviders({ - scoreCutoff: 0.4, - suggestedModels: demands[demandKey].suggested ?? [], + const result = await matchModelProviders({ + score_cutoff: 0.4, + suggested_models: demands[demandKey].suggested ?? [], capability, }); return { @@ -52,7 +52,7 @@ export function useMatchProviders({ demands, onSuccess, capability }: Props) { }), ); - return allProviders.reduce((acc, { key, providers }) => { + return allProviders.reduce((acc, { key, providers }) => { acc[key] = providers; return acc; }, {}); diff --git a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useUpdateContextMetadata.ts b/apps/agentstack-ui/src/modules/platform-context/api/mutations/usePatchContextMetadata.ts similarity index 71% rename from apps/agentstack-ui/src/modules/platform-context/api/mutations/useUpdateContextMetadata.ts rename to apps/agentstack-ui/src/modules/platform-context/api/mutations/usePatchContextMetadata.ts index 8587b75f2..3ecb13963 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/mutations/useUpdateContextMetadata.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/mutations/usePatchContextMetadata.ts @@ -5,12 +5,12 @@ import { useMutation } from '@tanstack/react-query'; -import { updateContextMetadata } from '..'; +import { patchContextMetadata } from '..'; import { contextKeys } from '../keys'; -export function useUpdateContextMetadata() { +export function usePatchContextMetadata() { const mutation = useMutation({ - mutationFn: updateContextMetadata, + mutationFn: patchContextMetadata, meta: { invalidates: [contextKeys.lists()], }, diff --git a/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContextHistory.ts b/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContextHistory.ts index 59532457a..015e4bb34 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContextHistory.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContextHistory.ts @@ -4,22 +4,22 @@ */ import { useInfiniteQuery } from '@tanstack/react-query'; +import type { ListContextHistoryRequest, ListContextHistoryResponse } from 'agentstack-sdk'; import type { PartialBy } from '#@types/utils.ts'; import { isNotNull } from '#utils/helpers.ts'; import { listContextHistory } from '..'; import { contextKeys } from '../keys'; -import type { ListContextHistoryParams, ListContextHistoryResponse } from '../types'; -type Params = PartialBy & { +type Params = PartialBy & { initialData?: ListContextHistoryResponse; enabled?: boolean; initialPageParam?: string; }; export function useListContextHistory({ - contextId, + context_id, query: queryParams, initialData, initialPageParam, @@ -27,12 +27,12 @@ export function useListContextHistory({ }: Params) { const query = useInfiniteQuery({ queryKey: contextKeys.history({ - contextId: contextId!, + context_id: context_id!, query: queryParams, }), queryFn: ({ pageParam }: { pageParam?: string }) => { return listContextHistory({ - contextId: contextId!, + context_id: context_id!, query: { ...queryParams, page_token: pageParam, @@ -52,7 +52,7 @@ export function useListContextHistory({ return items; }, - enabled: Boolean(contextId) && enabled, + enabled: Boolean(context_id) && enabled, initialData: initialData ? { pages: [initialData], pageParams: [undefined] } : undefined, }); diff --git a/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContexts.ts b/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContexts.ts index ed3eb215c..ec71e9d36 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContexts.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/queries/useListContexts.ts @@ -4,15 +4,14 @@ */ import { useInfiniteQuery } from '@tanstack/react-query'; +import type { ListContextsRequest } from 'agentstack-sdk'; -import type { ContextWithMetadata } from '#modules/platform-context/types.ts'; import { isNotNull } from '#utils/helpers.ts'; import { listContexts } from '..'; import { contextKeys } from '../keys'; -import type { ListContextsParams } from '../types'; -export function useListContexts(params: ListContextsParams = {}) { +export function useListContexts(params: ListContextsRequest = {}) { const query = useInfiniteQuery({ queryKey: contextKeys.list(params), queryFn: ({ pageParam }: { pageParam?: string }) => { @@ -31,7 +30,7 @@ export function useListContexts(params: ListContextsParams = {}) { select: (data) => { const items = data.pages.flatMap((page) => page?.items).filter(isNotNull); - return items as ContextWithMetadata[]; + return items; }, }); diff --git a/apps/agentstack-ui/src/modules/platform-context/api/types.ts b/apps/agentstack-ui/src/modules/platform-context/api/types.ts index 63f005c53..b4c517cbf 100644 --- a/apps/agentstack-ui/src/modules/platform-context/api/types.ts +++ b/apps/agentstack-ui/src/modules/platform-context/api/types.ts @@ -3,30 +3,46 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { ApiPath, ApiQuery, ApiRequest, ApiResponse } from '#@types/utils.ts'; - -import type { ContextMetadata } from '../types'; - -export type { CreateContextResponse } from 'agentstack-sdk'; - -export type ListContextsQuery = ApiQuery<'/api/v1/contexts'>; -export type ListContextsResponse = ApiResponse<'/api/v1/contexts'>; -export type ListContextsParams = { query?: ListContextsQuery }; - -export type DeleteContextPath = ApiPath<'/api/v1/contexts/{context_id}'>; -export type DeleteContextParams = DeleteContextPath; - -export type UpdateContextMetadataPath = ApiPath<'/api/v1/contexts/{context_id}/metadata', 'patch'>; -export type UpdateContextMetadataRequest = ApiRequest<'/api/v1/contexts/{context_id}/metadata', 'patch'> & { - metadata: Pick; -}; -export type UpdateContextMetadataParams = UpdateContextMetadataPath & UpdateContextMetadataRequest; - -export type ListContextHistoryQuery = ApiQuery<'/api/v1/contexts/{context_id}/history'>; -export type ListContextHistoryResponse = ApiResponse<'/api/v1/contexts/{context_id}/history'>; -export type ListContextHistoryParams = { contextId: string; query?: ListContextHistoryQuery }; - -export type ContextHistoryItem = ListContextHistoryResponse['items'][number]; +import { + contextSchema as sdkContextSchema, + listContextsResponseSchema as sdkListContextsResponseSchema, + patchContextMetadataRequestSchema as sdkPatchContextMetadataRequestSchema, +} from 'agentstack-sdk'; +import z from 'zod'; + +import type { ApiResponse } from '#@types/utils.ts'; + +export enum TitleGenerationState { + Pending = 'pending', + Completed = 'completed', + Failed = 'failed', +} + +export const contextMetadataSchema = z.object({ + agent_name: z.string().optional(), + provider_id: z.string().optional(), + title_generation_state: z.enum(TitleGenerationState).optional(), + title: z.string().optional(), +}); + +export type ContextMetadata = z.infer; + +export const contextSchema = sdkContextSchema.extend({ + metadata: contextMetadataSchema.nullable(), +}); +export type Context = z.infer; + +export const listContextsResponseSchema = sdkListContextsResponseSchema.extend({ + items: z.array(contextSchema), +}); +export type ListContextsResponse = z.infer; + +export const patchContextMetadataRequestSchema = sdkPatchContextMetadataRequestSchema.extend({ + metadata: contextMetadataSchema, +}); +export type PatchContextMetadataRequest = z.infer; + +// export type HistoryItem = ApiResponse<'/api/v1/contexts/{context_id}/history'>['items'][number]['data']; export type HistoryMessage = Extract; diff --git a/apps/agentstack-ui/src/modules/platform-context/contexts/PlatformContextProvider.tsx b/apps/agentstack-ui/src/modules/platform-context/contexts/PlatformContextProvider.tsx index 055550dc0..5a79cf3b8 100644 --- a/apps/agentstack-ui/src/modules/platform-context/contexts/PlatformContextProvider.tsx +++ b/apps/agentstack-ui/src/modules/platform-context/contexts/PlatformContextProvider.tsx @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ 'use client'; +import type { ListContextHistoryResponse } from 'agentstack-sdk'; import { type PropsWithChildren, useCallback, useState } from 'react'; import type { Agent } from '#modules/agents/api/types.ts'; import { useCreateContext } from '../api/mutations/useCreateContext'; -import { useUpdateContextMetadata } from '../api/mutations/useUpdateContextMetadata'; -import type { ListContextHistoryResponse } from '../api/types'; +import { usePatchContextMetadata } from '../api/mutations/usePatchContextMetadata'; import { PlatformContext } from './platform-context'; interface Props { @@ -21,16 +21,12 @@ export function PlatformContextProvider({ history, contextId: contextIdProp, chi const [contextId, setContextId] = useState(contextIdProp ?? null); const { mutateAsync: createContext } = useCreateContext({ - onSuccess: (context) => { - if (!context) { - throw new Error(`Context has not been created`); - } - - setContextId(context.id); + onSuccess: ({ id }) => { + setContextId(id); }, }); - const { mutateAsync: updateContextMetadata } = useUpdateContextMetadata(); + const { mutateAsync: patchContextMetadata } = usePatchContextMetadata(); const resetContext = useCallback(() => { setContextId(null); @@ -42,7 +38,7 @@ export function PlatformContextProvider({ history, contextId: contextIdProp, chi return; } - await updateContextMetadata({ + await patchContextMetadata({ context_id: contextId, metadata: { agent_name: agent.name, @@ -50,7 +46,7 @@ export function PlatformContextProvider({ history, contextId: contextIdProp, chi }, }); }, - [contextId, updateContextMetadata], + [contextId, patchContextMetadata], ); const getContextId = useCallback(() => { diff --git a/apps/agentstack-ui/src/modules/platform-context/contexts/platform-context.ts b/apps/agentstack-ui/src/modules/platform-context/contexts/platform-context.ts index 874f55496..0fda7e0e7 100644 --- a/apps/agentstack-ui/src/modules/platform-context/contexts/platform-context.ts +++ b/apps/agentstack-ui/src/modules/platform-context/contexts/platform-context.ts @@ -4,13 +4,12 @@ */ import type { UseMutateAsyncFunction } from '@tanstack/react-query'; +import type { Context, CreateContextRequest, ListContextHistoryResponse } from 'agentstack-sdk'; import { createContext } from 'react'; import type { Agent } from '#modules/agents/api/types.ts'; import type { ContextId } from '#modules/tasks/api/types.ts'; -import type { CreateContextResponse, ListContextHistoryResponse } from '../api/types'; - export type ContextToken = { token: string; expires_at: string | null; @@ -22,7 +21,7 @@ interface PlatformContextValue { getContextId: () => ContextId; resetContext: () => void; - createContext: UseMutateAsyncFunction; + createContext: UseMutateAsyncFunction; updateContextWithAgentMetadata: (agent: Agent) => Promise; } diff --git a/apps/agentstack-ui/src/modules/platform-context/hooks/useEnsurePlatformContext.ts b/apps/agentstack-ui/src/modules/platform-context/hooks/useEnsurePlatformContext.ts index 6078d8108..a58e2aa43 100644 --- a/apps/agentstack-ui/src/modules/platform-context/hooks/useEnsurePlatformContext.ts +++ b/apps/agentstack-ui/src/modules/platform-context/hooks/useEnsurePlatformContext.ts @@ -22,7 +22,7 @@ export function useEnsurePlatformContext(agent?: Agent) { const ensureContext = async () => { if (!contextId) { - await createContext(agent.provider.id); + await createContext({ provider_id: agent.provider.id }); } }; diff --git a/apps/agentstack-ui/src/modules/platform-context/types.ts b/apps/agentstack-ui/src/modules/platform-context/types.ts index bcc4b5fe3..1d0840d63 100644 --- a/apps/agentstack-ui/src/modules/platform-context/types.ts +++ b/apps/agentstack-ui/src/modules/platform-context/types.ts @@ -6,23 +6,6 @@ import { contextPermissionsGrantSchema, globalPermissionsGrantSchema } from 'agentstack-sdk'; import z from 'zod'; -import type { ListContextsResponse } from './api/types'; - -enum TitleGenerationState { - Pending = 'pending', - Completed = 'completed', - Failed = 'failed', -} - -export type ContextMetadata = { - agent_name?: string; - provider_id?: string; - title_generation_state?: TitleGenerationState; - title?: string; -}; - -export type ContextWithMetadata = ListContextsResponse['items'][number] & { metadata?: ContextMetadata }; - export const contextTokenPermissionsSchema = z.object({ grant_global_permissions: globalPermissionsGrantSchema.optional(), grant_context_permissions: contextPermissionsGrantSchema.optional(), diff --git a/apps/agentstack-ui/src/modules/runs/components/RunInput.tsx b/apps/agentstack-ui/src/modules/runs/components/RunInput.tsx index 172f7901f..13eb2eb41 100644 --- a/apps/agentstack-ui/src/modules/runs/components/RunInput.tsx +++ b/apps/agentstack-ui/src/modules/runs/components/RunInput.tsx @@ -5,12 +5,12 @@ import { InlineLoading } from '@carbon/react'; import { useMergeRefs } from '@floating-ui/react'; +import { InteractionMode } from 'agentstack-sdk'; import { useCallback, useRef, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { mergeRefs } from 'react-merge-refs'; import { TextAreaAutoHeight } from '#components/TextAreaAutoHeight/TextAreaAutoHeight.tsx'; -import { InteractionMode } from '#modules/agents/api/types.ts'; import { FileUploadButton } from '#modules/files/components/FileUploadButton.tsx'; import { useFileUpload } from '#modules/files/contexts/index.ts'; import { dispatchInputEventOnTextarea, submitFormOnEnter } from '#utils/form-utils.ts'; diff --git a/apps/agentstack-ui/src/modules/runs/components/RunView.tsx b/apps/agentstack-ui/src/modules/runs/components/RunView.tsx index ed461a847..226c03496 100644 --- a/apps/agentstack-ui/src/modules/runs/components/RunView.tsx +++ b/apps/agentstack-ui/src/modules/runs/components/RunView.tsx @@ -4,7 +4,10 @@ */ 'use client'; -import { type Agent, InteractionMode } from '#modules/agents/api/types.ts'; + +import { InteractionMode } from 'agentstack-sdk'; + +import type { Agent } from '#modules/agents/api/types.ts'; import { usePlatformContext } from '#modules/platform-context/contexts/index.ts'; import { ChatView } from '../chat/ChatView'; diff --git a/apps/agentstack-ui/src/modules/runs/constants.ts b/apps/agentstack-ui/src/modules/runs/constants.ts index cf895a985..ae5adae15 100644 --- a/apps/agentstack-ui/src/modules/runs/constants.ts +++ b/apps/agentstack-ui/src/modules/runs/constants.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { InteractionMode } from '#modules/agents/api/types.ts'; +import { InteractionMode } from 'agentstack-sdk'; export const SupportedUis: string[] = [InteractionMode.MultiTurn, InteractionMode.SingleTurn]; diff --git a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/AgentDemandsProvider.tsx b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/AgentDemandsProvider.tsx index cba967840..3e4b3f5e6 100644 --- a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/AgentDemandsProvider.tsx +++ b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/AgentDemandsProvider.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { type AgentSettings, type FormFulfillments, ModelCapability } from 'agentstack-sdk'; +import { type FormFulfillments, ModelCapability, type SettingsValues } from 'agentstack-sdk'; import { type PropsWithChildren, useCallback, useRef, useState } from 'react'; import type { AgentA2AClient } from '#api/a2a/types.ts'; @@ -11,7 +11,7 @@ import { useApp } from '#contexts/App/index.ts'; import { useListConnectors } from '#modules/connectors/api/queries/useListConnectors.ts'; import type { RunFormValues } from '#modules/form/types.ts'; import { useCreateContextToken } from '#modules/platform-context/api/mutations/useCreateContextToken.ts'; -import { useMatchProviders } from '#modules/platform-context/api/mutations/useMatchProviders.ts'; +import { useMatchModelProviders } from '#modules/platform-context/api/mutations/useMatchModelProviders.ts'; import { usePlatformContext } from '#modules/platform-context/contexts/index.ts'; import { getSettingsDemandsDefaultValues } from '#modules/runs/settings/utils.ts'; @@ -34,7 +34,7 @@ export function AgentDemandsProvider({ const [selectedLLMProviders, setSelectedLLMProviders] = useState>({}); const formFulfillmentsRef = useRef({ form_fulfillments: {} }); - const [selectedSettings, setSelectedSettings] = useState( + const [selectedSettings, setSelectedSettings] = useState( getSettingsDemandsDefaultValues(agentClient.demands.settingsDemands ?? { fields: [] }), ); @@ -45,7 +45,7 @@ export function AgentDemandsProvider({ const { mutateAsync: createContextToken } = useCreateContextToken(); - const onUpdateSettings = useCallback((value: AgentSettings) => { + const onUpdateSettings = useCallback((value: SettingsValues) => { setSelectedSettings(value); }, []); @@ -66,7 +66,7 @@ export function AgentDemandsProvider({ [setSelectedLLMProviders], ); - const { data: matchedLLMProviders } = useMatchProviders({ + const { data: matchedLLMProviders } = useMatchModelProviders({ demands: agentClient?.demands.llmDemands?.llm_demands ?? {}, onSuccess: setDefaultSelectedLLMProviders, capability: ModelCapability.Llm, @@ -89,7 +89,7 @@ export function AgentDemandsProvider({ [setSelectedEmbeddingProviders], ); - const { data: matchedEmbeddingProviders } = useMatchProviders({ + const { data: matchedEmbeddingProviders } = useMatchModelProviders({ demands: agentClient?.demands.embeddingDemands?.embedding_demands ?? {}, onSuccess: setDefaultSelectedEmbeddingProviders, capability: ModelCapability.Embedding, @@ -121,9 +121,9 @@ export function AgentDemandsProvider({ } const contextToken = await createContextToken({ - contextId, - contextPermissions: contextTokenPermissions.grant_context_permissions ?? {}, - globalPermissions: contextTokenPermissions.grant_global_permissions ?? {}, + context_id: contextId, + grant_context_permissions: contextTokenPermissions.grant_context_permissions ?? {}, + grant_global_permissions: contextTokenPermissions.grant_global_permissions ?? {}, }); if (!contextToken) { diff --git a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/agent-demands-context.ts b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/agent-demands-context.ts index dbd8ebc8d..7df19f624 100644 --- a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/agent-demands-context.ts +++ b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/agent-demands-context.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { AgentSettings, FormDemands, Fulfillments, SettingsDemands } from 'agentstack-sdk'; +import type { FormDemands, Fulfillments, SettingsDemands, SettingsValues } from 'agentstack-sdk'; import { createContext } from 'react'; import type { RunFormValues } from '#modules/form/types.ts'; @@ -26,8 +26,8 @@ interface AgentDemandsContextValue { selectLLMProvider: (key: string, value: string) => void; selectEmbeddingProvider: (key: string, value: string) => void; provideFormValues: (values: RunFormValues) => void; - onUpdateSettings: (settings: AgentSettings) => void; - selectedSettings: AgentSettings | undefined; + onUpdateSettings: (settings: SettingsValues) => void; + selectedSettings: SettingsValues | undefined; settingsDemands: SettingsDemands | null; formDemands: FormDemands | null; } diff --git a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/build-fulfillments.ts b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/build-fulfillments.ts index 46aeb231a..083aec202 100644 --- a/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/build-fulfillments.ts +++ b/apps/agentstack-ui/src/modules/runs/contexts/agent-demands/build-fulfillments.ts @@ -4,15 +4,15 @@ */ import type { - AgentSettings, Connector, ContextToken, EmbeddingDemands, FormFulfillments, Fulfillments, MCPFulfillments, + SettingsValues, } from 'agentstack-sdk'; -import { ConnectorState } from 'agentstack-sdk'; +import { ConnectorState, MCPTransportType } from 'agentstack-sdk'; import { BASE_URL } from '#utils/constants.ts'; @@ -21,7 +21,7 @@ interface BuildFulfillmentsParams { selectedLLMProviders: Record; selectedEmbeddingProviders: Record; providedSecrets: Record; - selectedSettings: AgentSettings; + selectedSettings: SettingsValues; formFulfillments: FormFulfillments; oauthRedirectUri: string | null; connectors: Connector[]; @@ -132,7 +132,7 @@ export const buildFulfillments = ({ mcp_fulfillments[demandKey] = { transport: { - type: 'streamable_http', + type: MCPTransportType.StreamableHttp, url: `{platform_url}/api/v1/connectors/${latestConnector.id}/mcp`, }, }; diff --git a/apps/agentstack-ui/src/modules/runs/contexts/agent-run/AgentRunProvider.tsx b/apps/agentstack-ui/src/modules/runs/contexts/agent-run/AgentRunProvider.tsx index 0bfbfdda5..655658e75 100644 --- a/apps/agentstack-ui/src/modules/runs/contexts/agent-run/AgentRunProvider.tsx +++ b/apps/agentstack-ui/src/modules/runs/contexts/agent-run/AgentRunProvider.tsx @@ -276,7 +276,7 @@ function AgentRunProvider({ agent, agentClient, children }: PropsWithChildren({ + const form = useForm({ defaultValues: selectedSettings, }); useEffect(() => { - const subscription = form.watch((values: AgentSettings) => { + const subscription = form.watch((values: SettingsValues) => { onUpdateSettings(values); }); diff --git a/apps/agentstack-ui/src/modules/runs/settings/utils.ts b/apps/agentstack-ui/src/modules/runs/settings/utils.ts index 7ca60a215..3d75811fa 100644 --- a/apps/agentstack-ui/src/modules/runs/settings/utils.ts +++ b/apps/agentstack-ui/src/modules/runs/settings/utils.ts @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { AgentSettings, SettingsCheckboxFieldValue, SettingsDemands } from 'agentstack-sdk'; +import type { SettingsCheckboxFieldValue, SettingsDemands, SettingsValues } from 'agentstack-sdk'; import { match } from 'ts-pattern'; export function getSettingsDemandsDefaultValues(settingsDemands: SettingsDemands) { - const defaults = settingsDemands?.fields.reduce((valuesAcc, field) => { + const defaults = settingsDemands?.fields.reduce((valuesAcc, field) => { valuesAcc[field.id] = match(field) .with({ type: 'checkbox_group' }, ({ fields }) => { const values = fields.reduce>((acc, field) => { diff --git a/apps/agentstack-ui/src/modules/users/api/index.ts b/apps/agentstack-ui/src/modules/users/api/index.ts index c39692270..88b2142ed 100644 --- a/apps/agentstack-ui/src/modules/users/api/index.ts +++ b/apps/agentstack-ui/src/modules/users/api/index.ts @@ -3,11 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { api } from '#api/index.ts'; -import { ensureData } from '#api/utils.ts'; +import { unwrapResult } from 'agentstack-sdk'; + +import { agentStackClient } from '#api/agentstack-client.ts'; export async function readUser() { - const response = await api.GET('/api/v1/user'); + const response = await agentStackClient.readUser(); + const result = unwrapResult(response); - return ensureData(response); + return result; } diff --git a/apps/agentstack-ui/src/modules/users/api/types.ts b/apps/agentstack-ui/src/modules/users/api/types.ts deleted file mode 100644 index ae8a3c9ef..000000000 --- a/apps/agentstack-ui/src/modules/users/api/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright 2025 © BeeAI a Series of LF Projects, LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import type { ApiPath, ApiResponse } from '#@types/utils.ts'; - -export type ReadUserPath = ApiPath<'/api/v1/user'>; -export type User = ApiResponse<'/api/v1/user'>; diff --git a/apps/agentstack-ui/src/modules/users/utils.ts b/apps/agentstack-ui/src/modules/users/utils.ts index b75ec6885..caa5fa9dd 100644 --- a/apps/agentstack-ui/src/modules/users/utils.ts +++ b/apps/agentstack-ui/src/modules/users/utils.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { User } from './api/types'; +import { type User, UserRole } from 'agentstack-sdk'; export function isUserAdminOrDev(user: User | undefined) { if (!user) { @@ -12,5 +12,5 @@ export function isUserAdminOrDev(user: User | undefined) { const { role } = user; - return role === 'admin' || role === 'developer'; + return role === UserRole.Admin || role === UserRole.Developer; }