@burdenoff/microfe-botmanor 2026.1101.2 → 2026.1106.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/botlit/hooks/internal/mutationInput.js.map +1 -1
- package/dist/botlit/hooks/internal/workspaceGateway.js +8 -5
- package/dist/botlit/hooks/internal/workspaceGateway.js.map +1 -1
- package/dist/botlit/hooks/useAgents.js +3 -3
- package/dist/botlit/hooks/useAgents.js.map +1 -1
- package/dist/botlit/hooks/useLLMProviders.js +4 -4
- package/dist/botlit/hooks/useLLMProviders.js.map +1 -1
- package/dist/botlit/pages/AgentBuilderPage.js.map +1 -1
- package/dist/botlit/permissions/botmanorPermissions.js.map +1 -1
- package/dist/generated/global-types.js.map +1 -1
- package/dist/generated/wspace-operations.js +11 -11
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutationInput.js","names":[],"sources":["../../../../src/botlit/hooks/internal/mutationInput.ts"],"sourcesContent":["/**\n * Mutation input primitives\n * @module botlit/hooks/internal\n *\n * GraphQL rejects an input object that carries a field its input type does not\n * declare, so a mutation payload must NEVER be assembled by spreading whatever\n * value the UI happens to be holding. An Apollo result carries `__typename`,\n * `id`, `revision` and the audit columns — no `Update*Input` on\n * wspace-botlit-svc accepts any of them, and sending one fails the whole write.\n *\n * `fieldsOf` records the allow-list once per input type and `buildMutationInput`\n * projects an arbitrary caller payload onto it. The `Record<keyof TInput, true>`\n * shape is what makes this safe over time: when the schema grows a field, the\n * allow-list stops compiling until it is declared here too.\n */\n\n/**\n * Widens one generated input field to the values the gateway really accepts.\n *\n * Two codegen artefacts are corrected here:\n * - Enums are emitted as real TypeScript enums (`Visibility.Private`), which a\n * plain `'PRIVATE'` is not assignable to. Widening them to their string\n * literals lets pages pass the values they already render in `<select>`\n * options without a cast.\n * - The `JSON` scalar is mapped to `Record<string, unknown>`, but a GraphQL\n * JSON scalar accepts arrays just as happily (`variables`, `entitlements`\n * and `exampleInputs` are all JSON arrays in practice).\n *\n * Arrays are widened element-wise, so an enum list such as\n * `Array<
|
|
1
|
+
{"version":3,"file":"mutationInput.js","names":[],"sources":["../../../../src/botlit/hooks/internal/mutationInput.ts"],"sourcesContent":["/**\n * Mutation input primitives\n * @module botlit/hooks/internal\n *\n * GraphQL rejects an input object that carries a field its input type does not\n * declare, so a mutation payload must NEVER be assembled by spreading whatever\n * value the UI happens to be holding. An Apollo result carries `__typename`,\n * `id`, `revision` and the audit columns — no `Update*Input` on\n * wspace-botlit-svc accepts any of them, and sending one fails the whole write.\n *\n * `fieldsOf` records the allow-list once per input type and `buildMutationInput`\n * projects an arbitrary caller payload onto it. The `Record<keyof TInput, true>`\n * shape is what makes this safe over time: when the schema grows a field, the\n * allow-list stops compiling until it is declared here too.\n */\n\n/**\n * Widens one generated input field to the values the gateway really accepts.\n *\n * Two codegen artefacts are corrected here:\n * - Enums are emitted as real TypeScript enums (`Visibility.Private`), which a\n * plain `'PRIVATE'` is not assignable to. Widening them to their string\n * literals lets pages pass the values they already render in `<select>`\n * options without a cast.\n * - The `JSON` scalar is mapped to `Record<string, unknown>`, but a GraphQL\n * JSON scalar accepts arrays just as happily (`variables`, `entitlements`\n * and `exampleInputs` are all JSON arrays in practice).\n *\n * Arrays are widened element-wise, so an enum list such as\n * `Array<BotmanorAgentCapability>` accepts `['MCP_TOOLS']`.\n */\ntype WidenValue<TValue> = TValue extends string\n ? `${TValue}`\n : TValue extends readonly (infer TItem)[]\n ? WidenValue<TItem>[]\n : TValue extends Record<string, unknown>\n ? TValue | unknown[]\n : TValue;\n\n/** Generated `*Input` type with its enum and JSON fields widened. */\nexport type GraphQLInput<TInput> = {\n [TKey in keyof TInput]: WidenValue<TInput[TKey]>;\n};\n\n/** The complete, compiler-checked field list of one GraphQL input type. */\nexport interface MutationInputFields<TInput> {\n readonly keys: readonly (keyof TInput)[];\n}\n\n/**\n * Declares the complete field list of a GraphQL input type.\n *\n * Every key of `TInput` must be present, so a schema field added upstream\n * surfaces as a compile error here instead of being silently dropped from\n * every mutation the hook sends.\n */\nexport function fieldsOf<TInput>(shape: Record<keyof TInput, true>): MutationInputFields<TInput> {\n return { keys: Object.keys(shape) as (keyof TInput)[] };\n}\n\n/**\n * Projects `input` onto the declared fields, dropping every key the input type\n * does not declare.\n *\n * `undefined` values are dropped (the caller left the field alone); `null` is\n * preserved because GraphQL treats it as an explicit \"clear this field\".\n */\nexport function buildMutationInput<TInput>(\n input: Partial<GraphQLInput<TInput>>,\n fields: MutationInputFields<TInput>\n): Partial<GraphQLInput<TInput>> {\n // Erased views: `TInput` is unresolved here, so the compiler cannot relate\n // `keyof TInput` to an index of the mapped type. The keys come from\n // `fieldsOf`, so every one of them is a real field of the input type.\n const source = input as Record<string, unknown>;\n const payload: Record<string, unknown> = {};\n\n for (const field of fields.keys) {\n const key = field as string;\n const value = source[key];\n if (value !== undefined) {\n payload[key] = value;\n }\n }\n\n return payload as Partial<GraphQLInput<TInput>>;\n}\n"],"mappings":";AAwDA,SAAgB,EAAiB,GAAgE;AAC/F,QAAO,EAAE,MAAM,OAAO,KAAK,EAAM,EAAsB;;AAUzD,SAAgB,EACd,GACA,GAC+B;CAI/B,IAAM,IAAS,GACT,IAAmC,EAAE;AAE3C,MAAK,IAAM,KAAS,EAAO,MAAM;EAC/B,IAAM,IAAM,GACN,IAAQ,EAAO;AACrB,EAAI,MAAU,KAAA,MACZ,EAAQ,KAAO;;AAInB,QAAO"}
|
|
@@ -31,7 +31,8 @@ function f(e) {
|
|
|
31
31
|
query: t,
|
|
32
32
|
variables: i,
|
|
33
33
|
fetchPolicy: "network-only"
|
|
34
|
-
});
|
|
34
|
+
}), n = e.error;
|
|
35
|
+
if (n != null) throw u(n, s);
|
|
35
36
|
h(f.current(e.data ?? void 0));
|
|
36
37
|
} catch (e) {
|
|
37
38
|
h(p.current), y(u(e, s));
|
|
@@ -72,13 +73,15 @@ function p(e) {
|
|
|
72
73
|
let n = await i.mutate({
|
|
73
74
|
mutation: t,
|
|
74
75
|
variables: a.current(e)
|
|
75
|
-
}), o =
|
|
76
|
-
if (o
|
|
76
|
+
}), o = n.error;
|
|
77
|
+
if (o != null) throw u(o, r);
|
|
78
|
+
let c = s.current(n.data ?? void 0);
|
|
79
|
+
if (c === void 0) throw Error(r);
|
|
77
80
|
return f({
|
|
78
|
-
data:
|
|
81
|
+
data: c,
|
|
79
82
|
loading: !1,
|
|
80
83
|
error: void 0
|
|
81
|
-
}),
|
|
84
|
+
}), c;
|
|
82
85
|
} catch (e) {
|
|
83
86
|
let t = u(e, r);
|
|
84
87
|
throw f({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaceGateway.js","names":[],"sources":["../../../../src/botlit/hooks/internal/workspaceGateway.ts"],"sourcesContent":["/**\n * Workspace gateway hook primitives\n * @module botlit/hooks/internal\n *\n * Every BotManor hook talks to the workspace public gateway through the Apollo\n * client the shell installs (`useGatewayClient('workspace')`) — never through a\n * client of its own. These primitives capture the exact shape used by the\n * reference hooks (`useAgents`, `useBots`): `network-only` reads, an explicit\n * `Error` in state rather than a thrown promise, and a `refetch` the caller can\n * run after a mutation.\n */\n\nimport type { ApolloClient, DocumentNode } from '@apollo/client';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBotlit } from '../../providers/BotlitProvider';\nimport { extractGraphqlFailureMessage } from '../../utils/errors';\n\nexport type WorkspaceClient = ApolloClient;\n\n/** Apollo client for the workspace gateway, provided by the host shell. */\nexport function useWorkspaceClient(): WorkspaceClient {\n return useGatewayClient('workspace');\n}\n\n/** Current workspace id from the BotManor context (undefined until the shell resolves it). */\nexport function useWorkspaceId(): string | undefined {\n return useBotlit().workspaceId;\n}\n\nexport interface QueryResult<T> {\n data: T;\n loading: boolean;\n /** Set only when the request FAILED. An empty `data` with no `error` means \"no records yet\". */\n error: Error | undefined;\n refetch: () => Promise<void>;\n}\n\nexport interface MutationState<T> {\n data: T | undefined;\n loading: boolean;\n error: Error | undefined;\n}\n\n/**\n * Normalises any mutation failure to an Error with the server's\n * user-actionable message where one exists.\n *\n * Apollo Client v4 does not reject with a plain Error: failures arrive as\n * `{ networkError }` / `{ graphQLErrors }` objects, and the batched fetch\n * layer attaches the structured GraphQL errors as `.errors` on the\n * networkError. `extractGraphqlFailureMessage` unwraps all of those; only\n * when nothing user-actionable is present do we fall back to the hook's\n * generic `errorMessage`.\n */\nfunction toError(cause: unknown, fallbackMessage: string): Error {\n const message = extractGraphqlFailureMessage(cause);\n if (message) {\n // Preserve the original rejection on the chain so error monitoring can\n // still reach the structured GraphQL errors (extensions.code, requestId…).\n return new Error(message, { cause });\n }\n if (cause instanceof Error) return cause;\n return new Error(fallbackMessage, { cause });\n}\n\n/** Keeps a mutable ref pointing at the latest value without re-running effects. */\nfunction useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useLayoutEffect(() => {\n ref.current = value;\n }, [value]);\n return ref;\n}\n\nexport interface WorkspaceQueryOptions<TData, TResult> {\n /** Generated GraphQL document (see `src/generated/wspace-operations.ts`). */\n document: DocumentNode;\n /** Must be referentially stable — memoize at the call site. */\n variables: Record<string, unknown> | undefined;\n /** Projects the raw payload onto the record shape the UI consumes. */\n select: (data: TData | undefined) => TResult;\n /** Value held while disabled or before the first successful read. */\n fallback: TResult;\n /** When false the request is skipped (e.g. no workspace id / no entity id yet). */\n enabled: boolean;\n /** Used when the thrown value is not an Error. */\n errorMessage: string;\n}\n\n/**\n * Reads from the workspace gateway and keeps `{ data, loading, error, refetch }`\n * in sync. `error` is reserved for real failures so callers can tell an empty\n * collection apart from a failed request.\n */\nexport function useWorkspaceQuery<TData, TResult>(\n options: WorkspaceQueryOptions<TData, TResult>\n): QueryResult<TResult> {\n const { document, variables, enabled, errorMessage } = options;\n const client = useWorkspaceClient();\n const selectRef = useLatest(options.select);\n const fallbackRef = useLatest(options.fallback);\n\n const [data, setData] = useState<TResult>(options.fallback);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!enabled) {\n setData(fallbackRef.current);\n setError(undefined);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<TData>({\n query: document,\n variables,\n fetchPolicy: 'network-only',\n });\n setData(selectRef.current(result.data ?? undefined));\n } catch (queryError) {\n setData(fallbackRef.current);\n setError(toError(queryError, errorMessage));\n } finally {\n setLoading(false);\n }\n // fallbackRef/selectRef are stable refs by construction\n }, [client, document, variables, enabled, errorMessage, fallbackRef, selectRef]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport interface WorkspaceMutationOptions<TData, TInput, TResult> {\n /** Generated GraphQL document (see `src/generated/wspace-operations.ts`). */\n document: DocumentNode;\n /** Maps the caller's input onto GraphQL variables. */\n variables: (input: TInput) => Record<string, unknown>;\n /** Projects the raw payload onto the record shape the UI consumes. */\n select: (data: TData | undefined) => TResult | undefined;\n /** Thrown (and stored) when the payload is missing or the request fails. */\n errorMessage: string;\n}\n\n/**\n * Writes to the workspace gateway. Returns the `[mutate, state]` tuple used by\n * the reference hooks. `mutate` REJECTS on failure so callers cannot mistake a\n * failed write for a successful one.\n */\nexport function useWorkspaceMutation<TData, TInput, TResult>(\n options: WorkspaceMutationOptions<TData, TInput, TResult>\n): readonly [(input: TInput) => Promise<TResult>, MutationState<TResult>] {\n const { document, errorMessage } = options;\n const client = useWorkspaceClient();\n const variablesRef = useLatest(options.variables);\n const selectRef = useLatest(options.select);\n\n const [state, setState] = useState<MutationState<TResult>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const mutate = useCallback(\n async (input: TInput): Promise<TResult> => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<TData>({\n mutation: document,\n variables: variablesRef.current(input),\n });\n const selected = selectRef.current(result.data ?? undefined);\n if (selected === undefined) {\n throw new Error(errorMessage);\n }\n setState({ data: selected, loading: false, error: undefined });\n return selected;\n } catch (mutationError) {\n const failure = toError(mutationError, errorMessage);\n setState({ data: undefined, loading: false, error: failure });\n throw failure;\n }\n },\n [client, document, errorMessage, selectRef, variablesRef]\n );\n\n return [mutate, state] as const;\n}\n"],"mappings":";;;;;AAsBA,SAAgB,IAAsC;AACpD,QAAO,EAAiB,YAAY;;AAItC,SAAgB,IAAqC;AACnD,QAAO,GAAW,CAAC;;AA4BrB,SAAS,EAAQ,GAAgB,GAAgC;CAC/D,IAAM,IAAU,EAA6B,EAAM;AAOnD,QANI,IAGS,MAAM,GAAS,EAAE,UAAO,CAAC,GAElC,aAAiB,QAAc,IACxB,MAAM,GAAiB,EAAE,UAAO,CAAC;;AAI9C,SAAS,EAAa,GAAmC;CACvD,IAAM,IAAM,EAAO,EAAM;AAIzB,QAHA,QAAsB;AACpB,IAAI,UAAU;IACb,CAAC,EAAM,CAAC,EACJ;;AAuBT,SAAgB,EACd,GACsB;CACtB,IAAM,EAAE,aAAU,cAAW,YAAS,oBAAiB,GACjD,IAAS,GAAoB,EAC7B,IAAY,EAAU,EAAQ,OAAO,EACrC,IAAc,EAAU,EAAQ,SAAS,EAEzC,CAAC,GAAM,KAAW,EAAkB,EAAQ,SAAS,EACrD,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,GAA6B,EAEjD,IAAU,EAAY,YAAY;AACtC,MAAI,CAAC,GAAS;AAEZ,GADA,EAAQ,EAAY,QAAQ,EAC5B,EAAS,KAAA,EAAU;AACnB;;AAIF,EADA,EAAW,GAAK,EAChB,EAAS,KAAA,EAAU;AACnB,MAAI;GACF,IAAM,IAAS,MAAM,EAAO,MAAa;IACvC,OAAO;IACP;IACA,aAAa;IACd,CAAC;AACF,KAAQ,EAAU,QAAQ,EAAO,QAAQ,KAAA,EAAU,CAAC;WAC7C,GAAY;AAEnB,GADA,EAAQ,EAAY,QAAQ,EAC5B,EAAS,EAAQ,GAAY,EAAa,CAAC;YACnC;AACR,KAAW,GAAM;;IAGlB;EAAC;EAAQ;EAAU;EAAW;EAAS;EAAc;EAAa;EAAU,CAAC;AAMhF,QAJA,QAAgB;AACT,KAAS;IACb,CAAC,EAAQ,CAAC,EAEN;EAAE;EAAM;EAAS;EAAO;EAAS;;AAmB1C,SAAgB,EACd,GACwE;CACxE,IAAM,EAAE,aAAU,oBAAiB,GAC7B,IAAS,GAAoB,EAC7B,IAAe,EAAU,EAAQ,UAAU,EAC3C,IAAY,EAAU,EAAQ,OAAO,EAErC,CAAC,GAAO,KAAY,EAAiC;EACzD,MAAM,KAAA;EACN,SAAS;EACT,OAAO,KAAA;EACR,CAAC;AAyBF,QAAO,CAvBQ,EACb,OAAO,MAAoC;AACzC,IAAS;GAAE,MAAM,KAAA;GAAW,SAAS;GAAM,OAAO,KAAA;GAAW,CAAC;AAC9D,MAAI;GACF,IAAM,IAAS,MAAM,EAAO,OAAc;IACxC,UAAU;IACV,WAAW,EAAa,QAAQ,EAAM;IACvC,CAAC,EACI,IAAW,EAAU,QAAQ,EAAO,QAAQ,KAAA,EAAU;AAC5D,OAAI,MAAa,KAAA,EACf,OAAU,MAAM,EAAa;AAG/B,UADA,EAAS;IAAE,MAAM;IAAU,SAAS;IAAO,OAAO,KAAA;IAAW,CAAC,EACvD;WACA,GAAe;GACtB,IAAM,IAAU,EAAQ,GAAe,EAAa;AAEpD,SADA,EAAS;IAAE,MAAM,KAAA;IAAW,SAAS;IAAO,OAAO;IAAS,CAAC,EACvD;;IAGV;EAAC;EAAQ;EAAU;EAAc;EAAW;EAAa,CAC1D,EAEe,EAAM"}
|
|
1
|
+
{"version":3,"file":"workspaceGateway.js","names":[],"sources":["../../../../src/botlit/hooks/internal/workspaceGateway.ts"],"sourcesContent":["/**\n * Workspace gateway hook primitives\n * @module botlit/hooks/internal\n *\n * Every BotManor hook talks to the workspace public gateway through the Apollo\n * client the shell installs (`useGatewayClient('workspace')`) — never through a\n * client of its own. These primitives capture the exact shape used by the\n * reference hooks (`useAgents`, `useBots`): `network-only` reads, an explicit\n * `Error` in state rather than a thrown promise, and a `refetch` the caller can\n * run after a mutation.\n */\n\nimport type { ApolloClient, DocumentNode } from '@apollo/client';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useBotlit } from '../../providers/BotlitProvider';\nimport { extractGraphqlFailureMessage } from '../../utils/errors';\n\nexport type WorkspaceClient = ApolloClient;\n\n/** Apollo client for the workspace gateway, provided by the host shell. */\nexport function useWorkspaceClient(): WorkspaceClient {\n return useGatewayClient('workspace');\n}\n\n/** Current workspace id from the BotManor context (undefined until the shell resolves it). */\nexport function useWorkspaceId(): string | undefined {\n return useBotlit().workspaceId;\n}\n\nexport interface QueryResult<T> {\n data: T;\n loading: boolean;\n /** Set only when the request FAILED. An empty `data` with no `error` means \"no records yet\". */\n error: Error | undefined;\n refetch: () => Promise<void>;\n}\n\nexport interface MutationState<T> {\n data: T | undefined;\n loading: boolean;\n error: Error | undefined;\n}\n\n/**\n * Normalises any mutation failure to an Error with the server's\n * user-actionable message where one exists.\n *\n * Apollo Client v4 does not reject with a plain Error: failures arrive as\n * `{ networkError }` / `{ graphQLErrors }` objects, and the batched fetch\n * layer attaches the structured GraphQL errors as `.errors` on the\n * networkError. `extractGraphqlFailureMessage` unwraps all of those; only\n * when nothing user-actionable is present do we fall back to the hook's\n * generic `errorMessage`.\n */\nfunction toError(cause: unknown, fallbackMessage: string): Error {\n const message = extractGraphqlFailureMessage(cause);\n if (message) {\n // Preserve the original rejection on the chain so error monitoring can\n // still reach the structured GraphQL errors (extensions.code, requestId…).\n return new Error(message, { cause });\n }\n if (cause instanceof Error) return cause;\n return new Error(fallbackMessage, { cause });\n}\n\n/** Keeps a mutable ref pointing at the latest value without re-running effects. */\nfunction useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useLayoutEffect(() => {\n ref.current = value;\n }, [value]);\n return ref;\n}\n\nexport interface WorkspaceQueryOptions<TData, TResult> {\n /** Generated GraphQL document (see `src/generated/wspace-operations.ts`). */\n document: DocumentNode;\n /** Must be referentially stable — memoize at the call site. */\n variables: Record<string, unknown> | undefined;\n /** Projects the raw payload onto the record shape the UI consumes. */\n select: (data: TData | undefined) => TResult;\n /** Value held while disabled or before the first successful read. */\n fallback: TResult;\n /** When false the request is skipped (e.g. no workspace id / no entity id yet). */\n enabled: boolean;\n /** Used when the thrown value is not an Error. */\n errorMessage: string;\n}\n\n/**\n * Reads from the workspace gateway and keeps `{ data, loading, error, refetch }`\n * in sync. `error` is reserved for real failures so callers can tell an empty\n * collection apart from a failed request.\n */\nexport function useWorkspaceQuery<TData, TResult>(\n options: WorkspaceQueryOptions<TData, TResult>\n): QueryResult<TResult> {\n const { document, variables, enabled, errorMessage } = options;\n const client = useWorkspaceClient();\n const selectRef = useLatest(options.select);\n const fallbackRef = useLatest(options.fallback);\n\n const [data, setData] = useState<TResult>(options.fallback);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!enabled) {\n setData(fallbackRef.current);\n setError(undefined);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<TData>({\n query: document,\n variables,\n fetchPolicy: 'network-only',\n });\n // Apollo v4 resolves (not rejects) with `result.error` set on GraphQL\n // errors — same handling as useWorkspaceMutation.\n const operationError = (result as { error?: unknown }).error;\n if (operationError != null) {\n throw toError(operationError, errorMessage);\n }\n setData(selectRef.current(result.data ?? undefined));\n } catch (queryError) {\n setData(fallbackRef.current);\n setError(toError(queryError, errorMessage));\n } finally {\n setLoading(false);\n }\n // fallbackRef/selectRef are stable refs by construction\n }, [client, document, variables, enabled, errorMessage, fallbackRef, selectRef]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport interface WorkspaceMutationOptions<TData, TInput, TResult> {\n /** Generated GraphQL document (see `src/generated/wspace-operations.ts`). */\n document: DocumentNode;\n /** Maps the caller's input onto GraphQL variables. */\n variables: (input: TInput) => Record<string, unknown>;\n /** Projects the raw payload onto the record shape the UI consumes. */\n select: (data: TData | undefined) => TResult | undefined;\n /** Thrown (and stored) when the payload is missing or the request fails. */\n errorMessage: string;\n}\n\n/**\n * Writes to the workspace gateway. Returns the `[mutate, state]` tuple used by\n * the reference hooks. `mutate` REJECTS on failure so callers cannot mistake a\n * failed write for a successful one.\n */\nexport function useWorkspaceMutation<TData, TInput, TResult>(\n options: WorkspaceMutationOptions<TData, TInput, TResult>\n): readonly [(input: TInput) => Promise<TResult>, MutationState<TResult>] {\n const { document, errorMessage } = options;\n const client = useWorkspaceClient();\n const variablesRef = useLatest(options.variables);\n const selectRef = useLatest(options.select);\n\n const [state, setState] = useState<MutationState<TResult>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const mutate = useCallback(\n async (input: TInput): Promise<TResult> => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<TData>({\n mutation: document,\n variables: variablesRef.current(input),\n });\n // Apollo v4 does not reject on GraphQL errors by default: the mutation\n // RESOLVES with `data` undefined and the failure on `result.error`\n // (CombinedGraphQLErrors / networkError). Surface it like a rejection\n // so callers see the server's field-level message, not the fallback.\n const operationError = (result as { error?: unknown }).error;\n if (operationError != null) {\n throw toError(operationError, errorMessage);\n }\n const selected = selectRef.current(result.data ?? undefined);\n if (selected === undefined) {\n throw new Error(errorMessage);\n }\n setState({ data: selected, loading: false, error: undefined });\n return selected;\n } catch (mutationError) {\n const failure = toError(mutationError, errorMessage);\n setState({ data: undefined, loading: false, error: failure });\n throw failure;\n }\n },\n [client, document, errorMessage, selectRef, variablesRef]\n );\n\n return [mutate, state] as const;\n}\n"],"mappings":";;;;;AAsBA,SAAgB,IAAsC;AACpD,QAAO,EAAiB,YAAY;;AAItC,SAAgB,IAAqC;AACnD,QAAO,GAAW,CAAC;;AA4BrB,SAAS,EAAQ,GAAgB,GAAgC;CAC/D,IAAM,IAAU,EAA6B,EAAM;AAOnD,QANI,IAGS,MAAM,GAAS,EAAE,UAAO,CAAC,GAElC,aAAiB,QAAc,IACxB,MAAM,GAAiB,EAAE,UAAO,CAAC;;AAI9C,SAAS,EAAa,GAAmC;CACvD,IAAM,IAAM,EAAO,EAAM;AAIzB,QAHA,QAAsB;AACpB,IAAI,UAAU;IACb,CAAC,EAAM,CAAC,EACJ;;AAuBT,SAAgB,EACd,GACsB;CACtB,IAAM,EAAE,aAAU,cAAW,YAAS,oBAAiB,GACjD,IAAS,GAAoB,EAC7B,IAAY,EAAU,EAAQ,OAAO,EACrC,IAAc,EAAU,EAAQ,SAAS,EAEzC,CAAC,GAAM,KAAW,EAAkB,EAAQ,SAAS,EACrD,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,GAA6B,EAEjD,IAAU,EAAY,YAAY;AACtC,MAAI,CAAC,GAAS;AAEZ,GADA,EAAQ,EAAY,QAAQ,EAC5B,EAAS,KAAA,EAAU;AACnB;;AAIF,EADA,EAAW,GAAK,EAChB,EAAS,KAAA,EAAU;AACnB,MAAI;GACF,IAAM,IAAS,MAAM,EAAO,MAAa;IACvC,OAAO;IACP;IACA,aAAa;IACd,CAAC,EAGI,IAAkB,EAA+B;AACvD,OAAI,KAAkB,KACpB,OAAM,EAAQ,GAAgB,EAAa;AAE7C,KAAQ,EAAU,QAAQ,EAAO,QAAQ,KAAA,EAAU,CAAC;WAC7C,GAAY;AAEnB,GADA,EAAQ,EAAY,QAAQ,EAC5B,EAAS,EAAQ,GAAY,EAAa,CAAC;YACnC;AACR,KAAW,GAAM;;IAGlB;EAAC;EAAQ;EAAU;EAAW;EAAS;EAAc;EAAa;EAAU,CAAC;AAMhF,QAJA,QAAgB;AACT,KAAS;IACb,CAAC,EAAQ,CAAC,EAEN;EAAE;EAAM;EAAS;EAAO;EAAS;;AAmB1C,SAAgB,EACd,GACwE;CACxE,IAAM,EAAE,aAAU,oBAAiB,GAC7B,IAAS,GAAoB,EAC7B,IAAe,EAAU,EAAQ,UAAU,EAC3C,IAAY,EAAU,EAAQ,OAAO,EAErC,CAAC,GAAO,KAAY,EAAiC;EACzD,MAAM,KAAA;EACN,SAAS;EACT,OAAO,KAAA;EACR,CAAC;AAiCF,QAAO,CA/BQ,EACb,OAAO,MAAoC;AACzC,IAAS;GAAE,MAAM,KAAA;GAAW,SAAS;GAAM,OAAO,KAAA;GAAW,CAAC;AAC9D,MAAI;GACF,IAAM,IAAS,MAAM,EAAO,OAAc;IACxC,UAAU;IACV,WAAW,EAAa,QAAQ,EAAM;IACvC,CAAC,EAKI,IAAkB,EAA+B;AACvD,OAAI,KAAkB,KACpB,OAAM,EAAQ,GAAgB,EAAa;GAE7C,IAAM,IAAW,EAAU,QAAQ,EAAO,QAAQ,KAAA,EAAU;AAC5D,OAAI,MAAa,KAAA,EACf,OAAU,MAAM,EAAa;AAG/B,UADA,EAAS;IAAE,MAAM;IAAU,SAAS;IAAO,OAAO,KAAA;IAAW,CAAC,EACvD;WACA,GAAe;GACtB,IAAM,IAAU,EAAQ,GAAe,EAAa;AAEpD,SADA,EAAS;IAAE,MAAM,KAAA;IAAW,SAAS;IAAO,OAAO;IAAS,CAAC,EACvD;;IAGV;EAAC;EAAQ;EAAU;EAAc;EAAW;EAAa,CAC1D,EAEe,EAAM"}
|
|
@@ -5,8 +5,8 @@ import { gql as s } from "@apollo/client";
|
|
|
5
5
|
import { useGatewayClient as c } from "@burdenoff/fe-libs/shared/graphql";
|
|
6
6
|
//#region src/botlit/hooks/useAgents.ts
|
|
7
7
|
var l = s`
|
|
8
|
-
query
|
|
9
|
-
|
|
8
|
+
query ListBotmanorAgents($filters: BotmanorAgentFilterInput, $pagination: PaginationInput) {
|
|
9
|
+
listBotmanorAgents(filters: $filters, pagination: $pagination) {
|
|
10
10
|
id
|
|
11
11
|
name
|
|
12
12
|
slug
|
|
@@ -207,7 +207,7 @@ function b(t) {
|
|
|
207
207
|
query: l,
|
|
208
208
|
variables: g,
|
|
209
209
|
fetchPolicy: "network-only"
|
|
210
|
-
})).data?.
|
|
210
|
+
})).data?.listBotmanorAgents ?? []);
|
|
211
211
|
} catch (e) {
|
|
212
212
|
h(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load agents"));
|
|
213
213
|
} finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAgents.js","names":[],"sources":["../../../src/botlit/hooks/useAgents.ts"],"sourcesContent":["import { gql, type ApolloClient } from '@apollo/client';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\n\nimport type { UpdateBotmanorAgentInput } from '../../generated/wspace-types';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport type { BaseFilter } from '../types';\nimport { buildMutationInput, fieldsOf, type GraphQLInput } from './internal/mutationInput';\n\nconst LIST_AGENTS_DOCUMENT = gql`\n query ListAgents($filters: AgentFilterInput, $pagination: PaginationInput) {\n listAgents(filters: $filters, pagination: $pagination) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n bucketId\n executionCount\n lastExecutedAt\n specialization\n tagIds\n createdAt\n updatedAt\n createdById\n updatedById\n workspaceId\n }\n }\n`;\n\nconst GET_AGENT_DOCUMENT = gql`\n query GetBotmanorAgent($id: ID!) {\n getBotmanorAgent(id: $id) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n bucketId\n currentVersionId\n draftVersionId\n executionCount\n lastExecutedAt\n specialization\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n knowledgeBaseIds\n mcpConnectionIds\n workflowIds\n tagIds\n metadata\n createdAt\n updatedAt\n createdById\n updatedById\n workspaceId\n }\n }\n`;\n\nconst CREATE_AGENT_DOCUMENT = gql`\n mutation CreateBotmanorAgent($input: CreateBotmanorAgentInput!) {\n createBotmanorAgent(input: $input) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n tagIds\n createdAt\n updatedAt\n workspaceId\n }\n }\n`;\n\nconst UPDATE_AGENT_DOCUMENT = gql`\n mutation UpdateBotmanorAgent($id: ID!, $input: UpdateBotmanorAgentInput!) {\n updateBotmanorAgent(id: $id, input: $input) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n knowledgeBaseIds\n mcpConnectionIds\n workflowIds\n tagIds\n metadata\n createdAt\n updatedAt\n updatedById\n workspaceId\n }\n }\n`;\n\nconst DELETE_AGENT_DOCUMENT = gql`\n mutation DeleteBotmanorAgent($id: ID!) {\n deleteBotmanorAgent(id: $id)\n }\n`;\n\n// BOFF-4381: agent version history, publish, and rollback.\nconst LIST_AGENT_VERSIONS_DOCUMENT = gql`\n query ListAgentVersions($agentId: ID!, $pagination: PaginationInput) {\n listAgentVersions(agentId: $agentId, pagination: $pagination) {\n id\n agentId\n version\n status\n changelog\n config\n createdById\n createdAt\n publishedById\n publishedAt\n }\n }\n`;\n\nconst PUBLISH_AGENT_VERSION_DOCUMENT = gql`\n mutation PublishAgentVersion($agentId: ID!, $versionId: ID!, $changelog: String) {\n publishAgentVersion(agentId: $agentId, versionId: $versionId, changelog: $changelog) {\n id\n agentId\n version\n status\n changelog\n publishedById\n publishedAt\n }\n }\n`;\n\nconst ROLLBACK_AGENT_VERSION_DOCUMENT = gql`\n mutation RollbackAgentVersion($agentId: ID!, $targetVersionId: ID!) {\n rollbackAgentVersion(agentId: $agentId, targetVersionId: $targetVersionId) {\n id\n agentId\n version\n status\n changelog\n publishedById\n publishedAt\n }\n }\n`;\n\ntype WorkspaceClient = ApolloClient;\n\nexport interface AgentRecord {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n type: string;\n status: string;\n visibility?: string | null;\n capabilities?: string[] | null;\n llmModelId?: string | null;\n bucketId?: string | null;\n currentVersionId?: string | null;\n draftVersionId?: string | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n specialization?: string | null;\n systemPrompt?: string | null;\n temperature?: number | null;\n maxTokens?: number | null;\n maxConcurrentExecutions?: number | null;\n knowledgeBaseIds?: string[] | null;\n mcpConnectionIds?: string[] | null;\n workflowIds?: string[] | null;\n tagIds?: string[] | null;\n metadata?: Record<string, unknown> | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n createdById?: string | null;\n updatedById?: string | null;\n workspaceId?: string | null;\n}\n\ninterface ListAgentsData {\n listAgents: AgentRecord[];\n}\n\ninterface GetAgentData {\n getBotmanorAgent: AgentRecord | null;\n}\n\ninterface CreateAgentData {\n createBotmanorAgent: AgentRecord;\n}\n\ninterface UpdateAgentData {\n updateBotmanorAgent: AgentRecord;\n}\n\ninterface DeleteAgentData {\n deleteBotmanorAgent: boolean;\n}\n\nexport interface AgentVersionRecord {\n id: string;\n agentId: string;\n version: string;\n status: 'DRAFT' | 'PUBLISHED' | 'HISTORICAL';\n changelog?: string | null;\n config?: Record<string, unknown> | null;\n createdById?: string | null;\n createdAt?: string | null;\n publishedById?: string | null;\n publishedAt?: string | null;\n}\n\ninterface ListAgentVersionsData {\n listAgentVersions: AgentVersionRecord[];\n}\n\ninterface PublishAgentVersionData {\n publishAgentVersion: AgentVersionRecord;\n}\n\ninterface RollbackAgentVersionData {\n rollbackAgentVersion: AgentVersionRecord;\n}\n\ninterface AgentMutationState<T> {\n data: T | undefined;\n loading: boolean;\n error: Error | undefined;\n}\n\ninterface CreateAgentInput {\n workspaceId: string;\n name: string;\n slug?: string;\n description?: string;\n type: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n capabilities?: string[];\n llmModelId?: string;\n}\n\ninterface UpdateAgentInput {\n agentId: string;\n input: GraphQLInput<UpdateBotmanorAgentInput>;\n}\n\nconst UPDATE_AGENT_FIELDS = fieldsOf<UpdateBotmanorAgentInput>({\n bucketId: true,\n capabilities: true,\n context: true,\n description: true,\n knowledgeBaseIds: true,\n llmModelId: true,\n maxConcurrentExecutions: true,\n maxTokens: true,\n mcpConnectionIds: true,\n metadata: true,\n name: true,\n slug: true,\n specialization: true,\n status: true,\n systemPrompt: true,\n tagIds: true,\n tags: true,\n temperature: true,\n type: true,\n visibility: true,\n workflowIds: true,\n});\n\nfunction getWorkspaceClient(client: unknown): WorkspaceClient {\n return client as WorkspaceClient;\n}\n\nfunction buildAgentFilter(\n workspaceId: string | undefined,\n filter?: BaseFilter\n): Record<string, unknown> | undefined {\n if (!workspaceId && !filter) return undefined;\n\n return {\n workspaceId,\n search: filter?.search,\n status: filter?.status?.[0],\n visibility: filter?.visibility?.[0],\n bucketId: filter?.bucketId,\n };\n}\n\nexport const agentKeys = {\n all: ['agents'] as const,\n lists: () => [...agentKeys.all, 'list'] as const,\n list: (filter?: BaseFilter) => [...agentKeys.lists(), filter] as const,\n details: () => [...agentKeys.all, 'detail'] as const,\n detail: (id: string) => [...agentKeys.details(), id] as const,\n};\n\nexport function useAgents(filter?: BaseFilter) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const { workspaceId } = useBotlit();\n const [data, setData] = useState<AgentRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const variables = useMemo(\n () => ({\n filters: buildAgentFilter(workspaceId, filter),\n pagination: { limit: 100, offset: 0 },\n }),\n [filter, workspaceId]\n );\n\n const refetch = useCallback(async () => {\n if (!workspaceId) {\n setData([]);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<ListAgentsData>({\n query: LIST_AGENTS_DOCUMENT,\n variables,\n fetchPolicy: 'network-only',\n });\n setData(result.data?.listAgents ?? []);\n } catch (queryError) {\n setError(queryError instanceof Error ? queryError : new Error('Failed to load agents'));\n } finally {\n setLoading(false);\n }\n }, [client, variables, workspaceId]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function useAgent(agentId: string | undefined) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [data, setData] = useState<AgentRecord | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!agentId) {\n setData(null);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<GetAgentData>({\n query: GET_AGENT_DOCUMENT,\n variables: { id: agentId },\n fetchPolicy: 'network-only',\n });\n setData(result.data?.getBotmanorAgent ?? null);\n } catch (queryError) {\n setError(queryError instanceof Error ? queryError : new Error('Failed to load agent'));\n } finally {\n setLoading(false);\n }\n }, [agentId, client]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function useCreateAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const createAgent = useCallback(\n async (input: CreateAgentInput) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<CreateAgentData>({\n mutation: CREATE_AGENT_DOCUMENT,\n variables: { input },\n });\n\n const createdAgent = result.data?.createBotmanorAgent;\n if (!createdAgent) {\n throw new Error('Failed to create agent');\n }\n\n setState({ data: createdAgent, loading: false, error: undefined });\n return createdAgent;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to create agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [createAgent, state] as const;\n}\n\nexport function useUpdateAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const updateAgent = useCallback(\n async ({ agentId, input }: UpdateAgentInput) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<UpdateAgentData>({\n mutation: UPDATE_AGENT_DOCUMENT,\n variables: { id: agentId, input: buildMutationInput(input, UPDATE_AGENT_FIELDS) },\n });\n\n const updatedAgent = result.data?.updateBotmanorAgent;\n if (!updatedAgent) {\n throw new Error('Failed to update agent');\n }\n\n setState({ data: updatedAgent, loading: false, error: undefined });\n return updatedAgent;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to update agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [updateAgent, state] as const;\n}\n\nexport function useDeleteAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<boolean>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const deleteAgent = useCallback(\n async (agentId: string) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<DeleteAgentData>({\n mutation: DELETE_AGENT_DOCUMENT,\n variables: { id: agentId },\n });\n\n const deleted = result.data?.deleteBotmanorAgent ?? false;\n setState({ data: deleted, loading: false, error: undefined });\n return deleted;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to delete agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [deleteAgent, state] as const;\n}\n\n// ============================================================================\n// VERSIONING (BOFF-4381) — version history, publish, rollback\n// ============================================================================\n\nexport function useAgentVersions(agentId: string | undefined) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [data, setData] = useState<AgentVersionRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!agentId) {\n setData([]);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<ListAgentVersionsData>({\n query: LIST_AGENT_VERSIONS_DOCUMENT,\n variables: { agentId, pagination: { limit: 50, offset: 0 } },\n fetchPolicy: 'network-only',\n });\n const versions = result.data?.listAgentVersions ?? [];\n // Newest first, regardless of what the server returned.\n setData(\n [...versions].sort((a, b) =>\n a.createdAt && b.createdAt ? b.createdAt.localeCompare(a.createdAt) : 0\n )\n );\n } catch (queryError) {\n setError(\n queryError instanceof Error ? queryError : new Error('Failed to load agent versions')\n );\n } finally {\n setLoading(false);\n }\n }, [agentId, client]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function usePublishAgentVersion() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentVersionRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const publishAgentVersion = useCallback(\n async ({\n agentId,\n versionId,\n changelog,\n }: {\n agentId: string;\n versionId: string;\n changelog?: string;\n }) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<PublishAgentVersionData>({\n mutation: PUBLISH_AGENT_VERSION_DOCUMENT,\n variables: { agentId, versionId, changelog: changelog?.trim() || undefined },\n });\n\n const published = result.data?.publishAgentVersion;\n if (!published) {\n throw new Error('Failed to publish agent version');\n }\n\n setState({ data: published, loading: false, error: undefined });\n return published;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error\n ? mutationError\n : new Error('Failed to publish agent version');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [publishAgentVersion, state] as const;\n}\n\nexport function useRollbackAgentVersion() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentVersionRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const rollbackAgentVersion = useCallback(\n async ({ agentId, targetVersionId }: { agentId: string; targetVersionId: string }) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<RollbackAgentVersionData>({\n mutation: ROLLBACK_AGENT_VERSION_DOCUMENT,\n variables: { agentId, targetVersionId },\n });\n\n const rolledBack = result.data?.rollbackAgentVersion;\n if (!rolledBack) {\n throw new Error('Failed to roll back agent version');\n }\n\n setState({ data: rolledBack, loading: false, error: undefined });\n return rolledBack;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error\n ? mutationError\n : new Error('Failed to roll back agent version');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [rollbackAgentVersion, state] as const;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAgents.js","names":[],"sources":["../../../src/botlit/hooks/useAgents.ts"],"sourcesContent":["import { gql, type ApolloClient } from '@apollo/client';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\n\nimport type { UpdateBotmanorAgentInput } from '../../generated/wspace-types';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport type { BaseFilter } from '../types';\nimport { buildMutationInput, fieldsOf, type GraphQLInput } from './internal/mutationInput';\n\nconst LIST_AGENTS_DOCUMENT = gql`\n query ListBotmanorAgents($filters: BotmanorAgentFilterInput, $pagination: PaginationInput) {\n listBotmanorAgents(filters: $filters, pagination: $pagination) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n bucketId\n executionCount\n lastExecutedAt\n specialization\n tagIds\n createdAt\n updatedAt\n createdById\n updatedById\n workspaceId\n }\n }\n`;\n\nconst GET_AGENT_DOCUMENT = gql`\n query GetBotmanorAgent($id: ID!) {\n getBotmanorAgent(id: $id) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n bucketId\n currentVersionId\n draftVersionId\n executionCount\n lastExecutedAt\n specialization\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n knowledgeBaseIds\n mcpConnectionIds\n workflowIds\n tagIds\n metadata\n createdAt\n updatedAt\n createdById\n updatedById\n workspaceId\n }\n }\n`;\n\nconst CREATE_AGENT_DOCUMENT = gql`\n mutation CreateBotmanorAgent($input: CreateBotmanorAgentInput!) {\n createBotmanorAgent(input: $input) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n tagIds\n createdAt\n updatedAt\n workspaceId\n }\n }\n`;\n\nconst UPDATE_AGENT_DOCUMENT = gql`\n mutation UpdateBotmanorAgent($id: ID!, $input: UpdateBotmanorAgentInput!) {\n updateBotmanorAgent(id: $id, input: $input) {\n id\n name\n slug\n description\n type\n status\n visibility\n capabilities\n llmModelId\n systemPrompt\n temperature\n maxTokens\n maxConcurrentExecutions\n knowledgeBaseIds\n mcpConnectionIds\n workflowIds\n tagIds\n metadata\n createdAt\n updatedAt\n updatedById\n workspaceId\n }\n }\n`;\n\nconst DELETE_AGENT_DOCUMENT = gql`\n mutation DeleteBotmanorAgent($id: ID!) {\n deleteBotmanorAgent(id: $id)\n }\n`;\n\n// BOFF-4381: agent version history, publish, and rollback.\nconst LIST_AGENT_VERSIONS_DOCUMENT = gql`\n query ListAgentVersions($agentId: ID!, $pagination: PaginationInput) {\n listAgentVersions(agentId: $agentId, pagination: $pagination) {\n id\n agentId\n version\n status\n changelog\n config\n createdById\n createdAt\n publishedById\n publishedAt\n }\n }\n`;\n\nconst PUBLISH_AGENT_VERSION_DOCUMENT = gql`\n mutation PublishAgentVersion($agentId: ID!, $versionId: ID!, $changelog: String) {\n publishAgentVersion(agentId: $agentId, versionId: $versionId, changelog: $changelog) {\n id\n agentId\n version\n status\n changelog\n publishedById\n publishedAt\n }\n }\n`;\n\nconst ROLLBACK_AGENT_VERSION_DOCUMENT = gql`\n mutation RollbackAgentVersion($agentId: ID!, $targetVersionId: ID!) {\n rollbackAgentVersion(agentId: $agentId, targetVersionId: $targetVersionId) {\n id\n agentId\n version\n status\n changelog\n publishedById\n publishedAt\n }\n }\n`;\n\ntype WorkspaceClient = ApolloClient;\n\nexport interface AgentRecord {\n id: string;\n name: string;\n slug: string;\n description?: string | null;\n type: string;\n status: string;\n visibility?: string | null;\n capabilities?: string[] | null;\n llmModelId?: string | null;\n bucketId?: string | null;\n currentVersionId?: string | null;\n draftVersionId?: string | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n specialization?: string | null;\n systemPrompt?: string | null;\n temperature?: number | null;\n maxTokens?: number | null;\n maxConcurrentExecutions?: number | null;\n knowledgeBaseIds?: string[] | null;\n mcpConnectionIds?: string[] | null;\n workflowIds?: string[] | null;\n tagIds?: string[] | null;\n metadata?: Record<string, unknown> | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n createdById?: string | null;\n updatedById?: string | null;\n workspaceId?: string | null;\n}\n\ninterface ListBotmanorAgentsData {\n listBotmanorAgents: AgentRecord[];\n}\n\ninterface GetAgentData {\n getBotmanorAgent: AgentRecord | null;\n}\n\ninterface CreateAgentData {\n createBotmanorAgent: AgentRecord;\n}\n\ninterface UpdateAgentData {\n updateBotmanorAgent: AgentRecord;\n}\n\ninterface DeleteAgentData {\n deleteBotmanorAgent: boolean;\n}\n\nexport interface AgentVersionRecord {\n id: string;\n agentId: string;\n version: string;\n status: 'DRAFT' | 'PUBLISHED' | 'HISTORICAL';\n changelog?: string | null;\n config?: Record<string, unknown> | null;\n createdById?: string | null;\n createdAt?: string | null;\n publishedById?: string | null;\n publishedAt?: string | null;\n}\n\ninterface ListAgentVersionsData {\n listAgentVersions: AgentVersionRecord[];\n}\n\ninterface PublishAgentVersionData {\n publishAgentVersion: AgentVersionRecord;\n}\n\ninterface RollbackAgentVersionData {\n rollbackAgentVersion: AgentVersionRecord;\n}\n\ninterface AgentMutationState<T> {\n data: T | undefined;\n loading: boolean;\n error: Error | undefined;\n}\n\ninterface CreateAgentInput {\n workspaceId: string;\n name: string;\n slug?: string;\n description?: string;\n type: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n capabilities?: string[];\n llmModelId?: string;\n}\n\ninterface UpdateAgentInput {\n agentId: string;\n input: GraphQLInput<UpdateBotmanorAgentInput>;\n}\n\nconst UPDATE_AGENT_FIELDS = fieldsOf<UpdateBotmanorAgentInput>({\n bucketId: true,\n capabilities: true,\n context: true,\n description: true,\n knowledgeBaseIds: true,\n llmModelId: true,\n maxConcurrentExecutions: true,\n maxTokens: true,\n mcpConnectionIds: true,\n metadata: true,\n name: true,\n slug: true,\n specialization: true,\n status: true,\n systemPrompt: true,\n tagIds: true,\n tags: true,\n temperature: true,\n type: true,\n visibility: true,\n workflowIds: true,\n});\n\nfunction getWorkspaceClient(client: unknown): WorkspaceClient {\n return client as WorkspaceClient;\n}\n\nfunction buildAgentFilter(\n workspaceId: string | undefined,\n filter?: BaseFilter\n): Record<string, unknown> | undefined {\n if (!workspaceId && !filter) return undefined;\n\n return {\n workspaceId,\n search: filter?.search,\n status: filter?.status?.[0],\n visibility: filter?.visibility?.[0],\n bucketId: filter?.bucketId,\n };\n}\n\nexport const agentKeys = {\n all: ['agents'] as const,\n lists: () => [...agentKeys.all, 'list'] as const,\n list: (filter?: BaseFilter) => [...agentKeys.lists(), filter] as const,\n details: () => [...agentKeys.all, 'detail'] as const,\n detail: (id: string) => [...agentKeys.details(), id] as const,\n};\n\nexport function useAgents(filter?: BaseFilter) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const { workspaceId } = useBotlit();\n const [data, setData] = useState<AgentRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const variables = useMemo(\n () => ({\n filters: buildAgentFilter(workspaceId, filter),\n pagination: { limit: 100, offset: 0 },\n }),\n [filter, workspaceId]\n );\n\n const refetch = useCallback(async () => {\n if (!workspaceId) {\n setData([]);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<ListBotmanorAgentsData>({\n query: LIST_AGENTS_DOCUMENT,\n variables,\n fetchPolicy: 'network-only',\n });\n setData(result.data?.listBotmanorAgents ?? []);\n } catch (queryError) {\n setError(queryError instanceof Error ? queryError : new Error('Failed to load agents'));\n } finally {\n setLoading(false);\n }\n }, [client, variables, workspaceId]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function useAgent(agentId: string | undefined) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [data, setData] = useState<AgentRecord | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!agentId) {\n setData(null);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<GetAgentData>({\n query: GET_AGENT_DOCUMENT,\n variables: { id: agentId },\n fetchPolicy: 'network-only',\n });\n setData(result.data?.getBotmanorAgent ?? null);\n } catch (queryError) {\n setError(queryError instanceof Error ? queryError : new Error('Failed to load agent'));\n } finally {\n setLoading(false);\n }\n }, [agentId, client]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function useCreateAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const createAgent = useCallback(\n async (input: CreateAgentInput) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<CreateAgentData>({\n mutation: CREATE_AGENT_DOCUMENT,\n variables: { input },\n });\n\n const createdAgent = result.data?.createBotmanorAgent;\n if (!createdAgent) {\n throw new Error('Failed to create agent');\n }\n\n setState({ data: createdAgent, loading: false, error: undefined });\n return createdAgent;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to create agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [createAgent, state] as const;\n}\n\nexport function useUpdateAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const updateAgent = useCallback(\n async ({ agentId, input }: UpdateAgentInput) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<UpdateAgentData>({\n mutation: UPDATE_AGENT_DOCUMENT,\n variables: { id: agentId, input: buildMutationInput(input, UPDATE_AGENT_FIELDS) },\n });\n\n const updatedAgent = result.data?.updateBotmanorAgent;\n if (!updatedAgent) {\n throw new Error('Failed to update agent');\n }\n\n setState({ data: updatedAgent, loading: false, error: undefined });\n return updatedAgent;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to update agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [updateAgent, state] as const;\n}\n\nexport function useDeleteAgent() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<boolean>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const deleteAgent = useCallback(\n async (agentId: string) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<DeleteAgentData>({\n mutation: DELETE_AGENT_DOCUMENT,\n variables: { id: agentId },\n });\n\n const deleted = result.data?.deleteBotmanorAgent ?? false;\n setState({ data: deleted, loading: false, error: undefined });\n return deleted;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error ? mutationError : new Error('Failed to delete agent');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [deleteAgent, state] as const;\n}\n\n// ============================================================================\n// VERSIONING (BOFF-4381) — version history, publish, rollback\n// ============================================================================\n\nexport function useAgentVersions(agentId: string | undefined) {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [data, setData] = useState<AgentVersionRecord[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | undefined>();\n\n const refetch = useCallback(async () => {\n if (!agentId) {\n setData([]);\n return;\n }\n\n setLoading(true);\n setError(undefined);\n try {\n const result = await client.query<ListAgentVersionsData>({\n query: LIST_AGENT_VERSIONS_DOCUMENT,\n variables: { agentId, pagination: { limit: 50, offset: 0 } },\n fetchPolicy: 'network-only',\n });\n const versions = result.data?.listAgentVersions ?? [];\n // Newest first, regardless of what the server returned.\n setData(\n [...versions].sort((a, b) =>\n a.createdAt && b.createdAt ? b.createdAt.localeCompare(a.createdAt) : 0\n )\n );\n } catch (queryError) {\n setError(\n queryError instanceof Error ? queryError : new Error('Failed to load agent versions')\n );\n } finally {\n setLoading(false);\n }\n }, [agentId, client]);\n\n useEffect(() => {\n void refetch();\n }, [refetch]);\n\n return { data, loading, error, refetch };\n}\n\nexport function usePublishAgentVersion() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentVersionRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const publishAgentVersion = useCallback(\n async ({\n agentId,\n versionId,\n changelog,\n }: {\n agentId: string;\n versionId: string;\n changelog?: string;\n }) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<PublishAgentVersionData>({\n mutation: PUBLISH_AGENT_VERSION_DOCUMENT,\n variables: { agentId, versionId, changelog: changelog?.trim() || undefined },\n });\n\n const published = result.data?.publishAgentVersion;\n if (!published) {\n throw new Error('Failed to publish agent version');\n }\n\n setState({ data: published, loading: false, error: undefined });\n return published;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error\n ? mutationError\n : new Error('Failed to publish agent version');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [publishAgentVersion, state] as const;\n}\n\nexport function useRollbackAgentVersion() {\n const client = getWorkspaceClient(useGatewayClient('workspace'));\n const [state, setState] = useState<AgentMutationState<AgentVersionRecord>>({\n data: undefined,\n loading: false,\n error: undefined,\n });\n\n const rollbackAgentVersion = useCallback(\n async ({ agentId, targetVersionId }: { agentId: string; targetVersionId: string }) => {\n setState({ data: undefined, loading: true, error: undefined });\n try {\n const result = await client.mutate<RollbackAgentVersionData>({\n mutation: ROLLBACK_AGENT_VERSION_DOCUMENT,\n variables: { agentId, targetVersionId },\n });\n\n const rolledBack = result.data?.rollbackAgentVersion;\n if (!rolledBack) {\n throw new Error('Failed to roll back agent version');\n }\n\n setState({ data: rolledBack, loading: false, error: undefined });\n return rolledBack;\n } catch (mutationError) {\n const error =\n mutationError instanceof Error\n ? mutationError\n : new Error('Failed to roll back agent version');\n setState({ data: undefined, loading: false, error });\n throw error;\n }\n },\n [client]\n );\n\n return [rollbackAgentVersion, state] as const;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useBotlit as e } from "../providers/BotlitProvider.js";
|
|
2
2
|
import { buildMutationInput as t, fieldsOf as n } from "./internal/mutationInput.js";
|
|
3
|
-
import { CreateBotmanorLlmModelDocument as r, CreateBotmanorLlmProviderDocument as i,
|
|
3
|
+
import { CreateBotmanorLlmModelDocument as r, CreateBotmanorLlmProviderDocument as i, ListBotmanorLlmModelsDocument as a, ListBotmanorLlmProvidersDocument as o, UpdateBotmanorLlmProviderDocument as s } from "../../generated/wspace-operations.js";
|
|
4
4
|
import { useWorkspaceClient as c, useWorkspaceId as l, useWorkspaceMutation as u } from "./internal/workspaceGateway.js";
|
|
5
5
|
import { useCallback as d } from "react";
|
|
6
6
|
import { useQuery as f } from "@tanstack/react-query";
|
|
@@ -64,10 +64,10 @@ function v(t, n, r, i, a) {
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
function y() {
|
|
67
|
-
return v(o, "providers", (e) => e?.
|
|
67
|
+
return v(o, "providers", (e) => e?.listBotmanorLLMProviders ?? m, m);
|
|
68
68
|
}
|
|
69
69
|
function b(e) {
|
|
70
|
-
return v(a, "models", (e) => e?.
|
|
70
|
+
return v(a, "models", (e) => e?.listBotmanorLLMModels ?? h, h, e?.providerId);
|
|
71
71
|
}
|
|
72
72
|
function x() {
|
|
73
73
|
let e = l(), [n, r] = u({
|
|
@@ -84,7 +84,7 @@ function x() {
|
|
|
84
84
|
id: e,
|
|
85
85
|
input: t(n, _)
|
|
86
86
|
}),
|
|
87
|
-
select: (e) => e?.
|
|
87
|
+
select: (e) => e?.updateBotmanorLLMProvider,
|
|
88
88
|
errorMessage: "Failed to update the LLM provider"
|
|
89
89
|
});
|
|
90
90
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLLMProviders.js","names":[],"sources":["../../../src/botlit/hooks/useLLMProviders.ts"],"sourcesContent":["/**\n * LLM Providers Hooks\n * @module botlit/hooks\n *\n * These go through the shell's workspace gateway client like every other BotManor\n * hook. They deliberately do NOT use the generated `useQuery`/`useMutation`\n * wrappers: `BotmanorRoot` only mounts an `<ApolloProvider>` in standalone mode,\n * so an Apollo React hook throws \"Could not find client in the context\" the\n * moment the MFE is mounted by an app shell — which is every production route.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport type { DocumentNode } from 'graphql';\nimport { useQuery } from '@tanstack/react-query';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n CreateBotmanorLlmProviderDocument,\n CreateBotmanorLlmModelDocument,\n DeleteLlmProviderDocument,\n GetLlmProviderDocument,\n ListLlmModelsDocument,\n ListLlmProvidersDocument,\n TestLlmConnectionDocument,\n UpdateLlmProviderDocument,\n type CreateBotmanorLlmProviderMutation,\n type CreateBotmanorLlmModelMutation,\n type DeleteLlmProviderMutation,\n type GetLlmProviderQuery,\n type ListLlmModelsQuery,\n type ListLlmProvidersQuery,\n type TestLlmConnectionMutation,\n type UpdateLlmProviderMutation,\n} from '../../generated/wspace-operations';\nimport type {\n CreateBotmanorLlmModelInput,\n CreateBotmanorLlmProviderInput,\n UpdateBotlitLlmProviderInput,\n} from '../../generated/wspace-types';\nimport { buildMutationInput, fieldsOf, type GraphQLInput } from './internal/mutationInput';\nimport {\n useWorkspaceId,\n useWorkspaceClient,\n useWorkspaceMutation,\n useWorkspaceQuery,\n type QueryResult,\n} from './internal/workspaceGateway';\n\nconst LIST_LIMIT = 50;\n\nexport interface LLMProviderRecord {\n id: string;\n name: string;\n type: string;\n isActive: boolean;\n apiEndpoint?: string | null;\n credentialsHash?: string | null;\n connectionId?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n workspaceId: string;\n}\n\nexport interface LLMModelRecord {\n id: string;\n name: string;\n modelId: string;\n providerId: string;\n contextWindow: number;\n maxOutputTokens: number;\n inputPricePerMToken: number;\n outputPricePerMToken: number;\n isActive: boolean;\n supportsStreaming: boolean;\n supportsFunctionCalling: boolean;\n supportsVision: boolean;\n metadata?: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** `CreateBotmanorLLMProviderInput` minus the `workspaceId` the hook supplies. */\nexport type ConfigureLLMProviderVariables = Omit<\n GraphQLInput<CreateBotmanorLlmProviderInput>,\n 'workspaceId'\n> & { isActive?: boolean };\n\nconst NO_PROVIDERS: LLMProviderRecord[] = [];\nconst NO_MODELS: LLMModelRecord[] = [];\n\nconst CREATE_PROVIDER_FIELDS = fieldsOf<CreateBotmanorLlmProviderInput>({\n apiEndpoint: true,\n connectionId: true,\n credentials: true,\n metadata: true,\n name: true,\n type: true,\n workspaceId: true,\n});\n\nconst UPDATE_PROVIDER_FIELDS = fieldsOf<UpdateBotlitLlmProviderInput>({\n apiEndpoint: true,\n connectionId: true,\n credentials: true,\n isActive: true,\n metadata: true,\n name: true,\n});\n\nexport const llmProviderKeys = {\n all: ['llmProviders'] as const,\n lists: () => [...llmProviderKeys.all, 'list'] as const,\n details: () => [...llmProviderKeys.all, 'detail'] as const,\n detail: (id: string) => [...llmProviderKeys.details(), id] as const,\n};\n\nfunction useLLMList<TData, TRecord>(\n document: DocumentNode,\n kind: string,\n select: (data: TData | undefined) => TRecord[],\n fallback: TRecord[],\n providerId?: string\n): QueryResult<TRecord[]> {\n const client = useWorkspaceClient();\n const { workspaceId, currentUser } = useBotlit();\n const query = useQuery({\n queryKey: ['botmanor-llm-catalog', workspaceId, currentUser?.id, kind, providerId],\n enabled: Boolean(workspaceId),\n retry: false,\n queryFn: async () => {\n const records: TRecord[] = [];\n for (let offset = 0; offset < 10000; offset += LIST_LIMIT) {\n const result = await client.query<TData>({\n query: document,\n fetchPolicy: 'network-only',\n variables: {\n filters: providerId ? { providerId } : undefined,\n pagination: { limit: LIST_LIMIT, offset },\n },\n });\n if (!result.data) throw new Error('Model catalog unavailable');\n const page = select(result.data);\n if (!Array.isArray(page) || page.length > LIST_LIMIT)\n throw new Error('Model catalog unavailable');\n records.push(...page);\n if (page.length < LIST_LIMIT) return records;\n }\n throw new Error('Model catalog exceeds the supported limit');\n },\n });\n return {\n data: query.data ?? fallback,\n loading: query.isFetching,\n error: query.error ?? undefined,\n refetch: async () => {\n await query.refetch();\n },\n };\n}\n\nexport function useLLMProviders(): QueryResult<LLMProviderRecord[]> {\n return useLLMList<ListLlmProvidersQuery, LLMProviderRecord>(\n ListLlmProvidersDocument,\n 'providers',\n (data) => data?.listLLMProviders ?? NO_PROVIDERS,\n NO_PROVIDERS\n );\n}\n\nexport function useLLMProvider(\n providerId: string | undefined\n): QueryResult<LLMProviderRecord | null> {\n const variables = useMemo(() => ({ id: providerId ?? '' }), [providerId]);\n\n return useWorkspaceQuery<GetLlmProviderQuery, LLMProviderRecord | null>({\n document: GetLlmProviderDocument,\n variables,\n select: (data) => data?.getLLMProvider ?? null,\n fallback: null,\n enabled: Boolean(providerId),\n errorMessage: 'Failed to load LLM provider',\n });\n}\n\nexport function useLLMModels(filters?: { providerId?: string }): QueryResult<LLMModelRecord[]> {\n return useLLMList<ListLlmModelsQuery, LLMModelRecord>(\n ListLlmModelsDocument,\n 'models',\n (data) => data?.listLLMModels ?? NO_MODELS,\n NO_MODELS,\n filters?.providerId\n );\n}\n\n/**\n * Creates a provider, or updates the one whose id the caller passes.\n * `UpdateBotlitLLMProviderInput` has no `type`/`workspaceId`, so the update\n * payload is projected onto the fields that input actually declares.\n */\nexport function useConfigureLLMProvider() {\n const workspaceId = useWorkspaceId();\n\n const [create, createState] = useWorkspaceMutation<\n CreateBotmanorLlmProviderMutation,\n ConfigureLLMProviderVariables,\n LLMProviderRecord\n >({\n document: CreateBotmanorLlmProviderDocument,\n variables: (input) => ({\n input: buildMutationInput({ ...input, workspaceId }, CREATE_PROVIDER_FIELDS),\n }),\n select: (data) => data?.createBotmanorLLMProvider,\n errorMessage: 'Failed to create the LLM provider',\n });\n\n const [update, updateState] = useWorkspaceMutation<\n UpdateLlmProviderMutation,\n { providerId: string; input: ConfigureLLMProviderVariables },\n LLMProviderRecord\n >({\n document: UpdateLlmProviderDocument,\n variables: ({ providerId, input }) => ({\n id: providerId,\n input: buildMutationInput(input, UPDATE_PROVIDER_FIELDS),\n }),\n select: (data) => data?.updateLLMProvider,\n errorMessage: 'Failed to update the LLM provider',\n });\n\n const configureProvider = useCallback(\n async (input: ConfigureLLMProviderVariables, existingId?: string) =>\n existingId ? update({ providerId: existingId, input }) : create(input),\n [create, update]\n );\n\n return {\n configureProvider,\n isConfiguring: createState.loading || updateState.loading,\n error: createState.error ?? updateState.error,\n };\n}\n\nexport function useDeleteLLMProvider() {\n return useWorkspaceMutation<DeleteLlmProviderMutation, string, boolean>({\n document: DeleteLlmProviderDocument,\n variables: (providerId) => ({ id: providerId }),\n select: (data) => data?.deleteLLMProvider,\n errorMessage: 'Failed to delete the LLM provider',\n });\n}\n\nexport function useTestLLMConnection() {\n return useWorkspaceMutation<TestLlmConnectionMutation, string, boolean>({\n document: TestLlmConnectionDocument,\n variables: (providerId) => ({ id: providerId }),\n select: (data) => data?.testLlmConnection,\n errorMessage: 'Failed to test the LLM connection',\n });\n}\n\n/** Register models through the same authenticated workspace gateway as providers. */\nexport function useCreateLLMModel() {\n const [createModel, state] = useWorkspaceMutation<\n CreateBotmanorLlmModelMutation,\n CreateBotmanorLlmModelInput,\n LLMModelRecord\n >({\n document: CreateBotmanorLlmModelDocument,\n variables: (input) => ({\n input: buildMutationInput(\n input,\n fieldsOf<CreateBotmanorLlmModelInput>({\n providerId: true,\n name: true,\n modelId: true,\n contextWindow: true,\n maxOutputTokens: true,\n inputPricePerMToken: true,\n outputPricePerMToken: true,\n supportsStreaming: true,\n supportsFunctionCalling: true,\n supportsVision: true,\n metadata: true,\n })\n ),\n }),\n select: (data) => data?.createBotmanorLLMModel,\n errorMessage: 'Failed to register the model',\n });\n return { createModel, isCreating: state.loading, error: state.error };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useLLMProviders.js","names":[],"sources":["../../../src/botlit/hooks/useLLMProviders.ts"],"sourcesContent":["/**\n * LLM Providers Hooks\n * @module botlit/hooks\n *\n * These go through the shell's workspace gateway client like every other BotManor\n * hook. They deliberately do NOT use the generated `useQuery`/`useMutation`\n * wrappers: `BotmanorRoot` only mounts an `<ApolloProvider>` in standalone mode,\n * so an Apollo React hook throws \"Could not find client in the context\" the\n * moment the MFE is mounted by an app shell — which is every production route.\n */\n\nimport { useCallback, useMemo } from 'react';\nimport type { DocumentNode } from 'graphql';\nimport { useQuery } from '@tanstack/react-query';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport {\n CreateBotmanorLlmProviderDocument,\n CreateBotmanorLlmModelDocument,\n DeleteLlmProviderDocument,\n GetBotmanorLlmProviderDocument,\n ListBotmanorLlmModelsDocument,\n ListBotmanorLlmProvidersDocument,\n TestLlmConnectionDocument,\n UpdateBotmanorLlmProviderDocument,\n type CreateBotmanorLlmProviderMutation,\n type CreateBotmanorLlmModelMutation,\n type DeleteLlmProviderMutation,\n type GetBotmanorLlmProviderQuery,\n type ListBotmanorLlmModelsQuery,\n type ListBotmanorLlmProvidersQuery,\n type TestLlmConnectionMutation,\n type UpdateBotmanorLlmProviderMutation,\n} from '../../generated/wspace-operations';\nimport type {\n CreateBotmanorLlmModelInput,\n CreateBotmanorLlmProviderInput,\n UpdateBotmanorLlmProviderInput,\n} from '../../generated/wspace-types';\nimport { buildMutationInput, fieldsOf, type GraphQLInput } from './internal/mutationInput';\nimport {\n useWorkspaceId,\n useWorkspaceClient,\n useWorkspaceMutation,\n useWorkspaceQuery,\n type QueryResult,\n} from './internal/workspaceGateway';\n\nconst LIST_LIMIT = 50;\n\nexport interface LLMProviderRecord {\n id: string;\n name: string;\n type: string;\n isActive: boolean;\n apiEndpoint?: string | null;\n credentialsHash?: string | null;\n connectionId?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n workspaceId: string;\n}\n\nexport interface LLMModelRecord {\n id: string;\n name: string;\n modelId: string;\n providerId: string;\n contextWindow: number;\n maxOutputTokens: number;\n inputPricePerMToken: number;\n outputPricePerMToken: number;\n isActive: boolean;\n supportsStreaming: boolean;\n supportsFunctionCalling: boolean;\n supportsVision: boolean;\n metadata?: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/** `CreateBotmanorLLMProviderInput` minus the `workspaceId` the hook supplies. */\nexport type ConfigureLLMProviderVariables = Omit<\n GraphQLInput<CreateBotmanorLlmProviderInput>,\n 'workspaceId'\n> & { isActive?: boolean };\n\nconst NO_PROVIDERS: LLMProviderRecord[] = [];\nconst NO_MODELS: LLMModelRecord[] = [];\n\nconst CREATE_PROVIDER_FIELDS = fieldsOf<CreateBotmanorLlmProviderInput>({\n apiEndpoint: true,\n connectionId: true,\n credentials: true,\n metadata: true,\n name: true,\n type: true,\n workspaceId: true,\n});\n\nconst UPDATE_PROVIDER_FIELDS = fieldsOf<UpdateBotmanorLlmProviderInput>({\n apiEndpoint: true,\n connectionId: true,\n credentials: true,\n isActive: true,\n metadata: true,\n name: true,\n});\n\nexport const llmProviderKeys = {\n all: ['llmProviders'] as const,\n lists: () => [...llmProviderKeys.all, 'list'] as const,\n details: () => [...llmProviderKeys.all, 'detail'] as const,\n detail: (id: string) => [...llmProviderKeys.details(), id] as const,\n};\n\nfunction useLLMList<TData, TRecord>(\n document: DocumentNode,\n kind: string,\n select: (data: TData | undefined) => TRecord[],\n fallback: TRecord[],\n providerId?: string\n): QueryResult<TRecord[]> {\n const client = useWorkspaceClient();\n const { workspaceId, currentUser } = useBotlit();\n const query = useQuery({\n queryKey: ['botmanor-llm-catalog', workspaceId, currentUser?.id, kind, providerId],\n enabled: Boolean(workspaceId),\n retry: false,\n queryFn: async () => {\n const records: TRecord[] = [];\n for (let offset = 0; offset < 10000; offset += LIST_LIMIT) {\n const result = await client.query<TData>({\n query: document,\n fetchPolicy: 'network-only',\n variables: {\n filters: providerId ? { providerId } : undefined,\n pagination: { limit: LIST_LIMIT, offset },\n },\n });\n if (!result.data) throw new Error('Model catalog unavailable');\n const page = select(result.data);\n if (!Array.isArray(page) || page.length > LIST_LIMIT)\n throw new Error('Model catalog unavailable');\n records.push(...page);\n if (page.length < LIST_LIMIT) return records;\n }\n throw new Error('Model catalog exceeds the supported limit');\n },\n });\n return {\n data: query.data ?? fallback,\n loading: query.isFetching,\n error: query.error ?? undefined,\n refetch: async () => {\n await query.refetch();\n },\n };\n}\n\nexport function useLLMProviders(): QueryResult<LLMProviderRecord[]> {\n return useLLMList<ListBotmanorLlmProvidersQuery, LLMProviderRecord>(\n ListBotmanorLlmProvidersDocument,\n 'providers',\n (data) => data?.listBotmanorLLMProviders ?? NO_PROVIDERS,\n NO_PROVIDERS\n );\n}\n\nexport function useLLMProvider(\n providerId: string | undefined\n): QueryResult<LLMProviderRecord | null> {\n const variables = useMemo(() => ({ id: providerId ?? '' }), [providerId]);\n\n return useWorkspaceQuery<GetBotmanorLlmProviderQuery, LLMProviderRecord | null>({\n document: GetBotmanorLlmProviderDocument,\n variables,\n select: (data) => data?.getBotmanorLLMProvider ?? null,\n fallback: null,\n enabled: Boolean(providerId),\n errorMessage: 'Failed to load LLM provider',\n });\n}\n\nexport function useLLMModels(filters?: { providerId?: string }): QueryResult<LLMModelRecord[]> {\n return useLLMList<ListBotmanorLlmModelsQuery, LLMModelRecord>(\n ListBotmanorLlmModelsDocument,\n 'models',\n (data) => data?.listBotmanorLLMModels ?? NO_MODELS,\n NO_MODELS,\n filters?.providerId\n );\n}\n\n/**\n * Creates a provider, or updates the one whose id the caller passes.\n * `UpdateBotmanorLLMProviderInput` has no `type`/`workspaceId`, so the update\n * payload is projected onto the fields that input actually declares.\n */\nexport function useConfigureLLMProvider() {\n const workspaceId = useWorkspaceId();\n\n const [create, createState] = useWorkspaceMutation<\n CreateBotmanorLlmProviderMutation,\n ConfigureLLMProviderVariables,\n LLMProviderRecord\n >({\n document: CreateBotmanorLlmProviderDocument,\n variables: (input) => ({\n input: buildMutationInput({ ...input, workspaceId }, CREATE_PROVIDER_FIELDS),\n }),\n select: (data) => data?.createBotmanorLLMProvider,\n errorMessage: 'Failed to create the LLM provider',\n });\n\n const [update, updateState] = useWorkspaceMutation<\n UpdateBotmanorLlmProviderMutation,\n { providerId: string; input: ConfigureLLMProviderVariables },\n LLMProviderRecord\n >({\n document: UpdateBotmanorLlmProviderDocument,\n variables: ({ providerId, input }) => ({\n id: providerId,\n input: buildMutationInput(input, UPDATE_PROVIDER_FIELDS),\n }),\n select: (data) => data?.updateBotmanorLLMProvider,\n errorMessage: 'Failed to update the LLM provider',\n });\n\n const configureProvider = useCallback(\n async (input: ConfigureLLMProviderVariables, existingId?: string) =>\n existingId ? update({ providerId: existingId, input }) : create(input),\n [create, update]\n );\n\n return {\n configureProvider,\n isConfiguring: createState.loading || updateState.loading,\n error: createState.error ?? updateState.error,\n };\n}\n\nexport function useDeleteLLMProvider() {\n return useWorkspaceMutation<DeleteLlmProviderMutation, string, boolean>({\n document: DeleteLlmProviderDocument,\n variables: (providerId) => ({ id: providerId }),\n select: (data) => data?.deleteLLMProvider,\n errorMessage: 'Failed to delete the LLM provider',\n });\n}\n\nexport function useTestLLMConnection() {\n return useWorkspaceMutation<TestLlmConnectionMutation, string, boolean>({\n document: TestLlmConnectionDocument,\n variables: (providerId) => ({ id: providerId }),\n select: (data) => data?.testLlmConnection,\n errorMessage: 'Failed to test the LLM connection',\n });\n}\n\n/** Register models through the same authenticated workspace gateway as providers. */\nexport function useCreateLLMModel() {\n const [createModel, state] = useWorkspaceMutation<\n CreateBotmanorLlmModelMutation,\n CreateBotmanorLlmModelInput,\n LLMModelRecord\n >({\n document: CreateBotmanorLlmModelDocument,\n variables: (input) => ({\n input: buildMutationInput(\n input,\n fieldsOf<CreateBotmanorLlmModelInput>({\n providerId: true,\n name: true,\n modelId: true,\n contextWindow: true,\n maxOutputTokens: true,\n inputPricePerMToken: true,\n outputPricePerMToken: true,\n supportsStreaming: true,\n supportsFunctionCalling: true,\n supportsVision: true,\n metadata: true,\n })\n ),\n }),\n select: (data) => data?.createBotmanorLLMModel,\n errorMessage: 'Failed to register the model',\n });\n return { createModel, isCreating: state.loading, error: state.error };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentBuilderPage.js","names":[],"sources":["../../../src/botlit/pages/AgentBuilderPage.tsx"],"sourcesContent":["/**\n * Agent Builder Page\n * @module botlit/pages\n *\n * Creates/edits agents with real GraphQL BotlitAgent type:\n * - systemPrompt (string), temperature, maxTokens\n * - capabilities (enum array: MCP_TOOLS, RAG, REASONING, etc.)\n * - llmModelId (reference to LLM model)\n * - type (ASSISTANT, ANALYST, AUTOMATION, SPECIALIST)\n */\n\nimport type { FC } from 'react';\nimport { useState, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { ArrowLeft, Save, Brain, Wrench, Settings, Sparkles } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { useAgent, useCreateAgent, useUpdateAgent } from '../hooks/useAgents';\nimport { useBots } from '../hooks/useBots';\nimport { useLLMProviders, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\nimport { configuredAnswerModels } from '../utils/embedding-models';\n\n/** `BotlitAgentCapability` values the builder offers. */\nconst AGENT_CAPABILITIES = [\n 'MCP_TOOLS',\n 'RAG',\n 'REASONING',\n 'MULTIMODAL',\n 'MEMORY',\n 'CODE_EXECUTION',\n 'A2A',\n 'WEB_BROWSING',\n] as const;\ntype AgentCapability = (typeof AGENT_CAPABILITIES)[number];\n\n/** `BotlitAgentType` values the builder offers. */\nconst AGENT_TYPES = ['ASSISTANT', 'ANALYST', 'AUTOMATION', 'SPECIALIST'] as const;\n\n/** Drops any capability the schema does not declare rather than guessing one. */\nfunction toCapabilities(values: string[]): AgentCapability[] {\n return values.flatMap((value) => {\n const match = AGENT_CAPABILITIES.find((capability) => capability === value);\n return match ? [match] : [];\n });\n}\n\nfunction toAgentType(value: string): (typeof AGENT_TYPES)[number] {\n return toUnion(value, AGENT_TYPES, 'ASSISTANT');\n}\n\ninterface FormDataType {\n name: string;\n slug: string;\n description: string;\n avatar: string;\n tags: string[];\n // Flat fields matching real GraphQL API\n systemPrompt: string;\n temperature: string;\n maxTokens: string;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId: string;\n}\n\nexport const AgentBuilderPage: FC = () => {\n const { agentId } = useParams();\n const { navigateTo, workspaceId } = useBotlit();\n const { data: existingAgent } = useAgent(agentId);\n const { data: bots } = useBots();\n const {\n data: providers,\n loading: providersLoading,\n error: providersError,\n refetch: refetchProviders,\n } = useLLMProviders();\n const {\n data: llmModels,\n loading: modelsLoading,\n error: modelsError,\n refetch: refetchModels,\n } = useLLMModels();\n const catalogLoading = providersLoading || modelsLoading;\n const catalogError = providersError || modelsError;\n const answerModels = configuredAnswerModels(llmModels ?? [], providers ?? []);\n const [createAgent, createAgentResult] = useCreateAgent();\n const [updateAgent, updateAgentResult] = useUpdateAgent();\n\n const isEditing = !!agentId;\n const [activeStep, setActiveStep] = useState(0);\n\n const [formData, setFormData] = useState<FormDataType>({\n name: '',\n slug: '',\n description: '',\n avatar: '🤖',\n tags: [],\n systemPrompt: 'You are a helpful AI assistant. Be concise, accurate, and friendly.',\n temperature: '0.7',\n maxTokens: '2048',\n type: 'ASSISTANT',\n status: 'DRAFT',\n capabilities: ['MCP_TOOLS', 'REASONING'],\n llmModelId: '',\n });\n\n // Update form when existing agent loads\n useEffect(() => {\n if (existingAgent) {\n const agent = existingAgent as {\n name: string;\n slug: string;\n description?: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId?: string;\n tagIds?: string[];\n };\n setFormData({\n name: agent.name,\n slug: agent.slug,\n description: agent.description || '',\n avatar: '🤖',\n tags: agent.tagIds || [],\n systemPrompt: agent.systemPrompt || '',\n temperature: String(agent.temperature ?? 0.7),\n maxTokens: String(agent.maxTokens ?? 2048),\n type: agent.type || 'ASSISTANT',\n status: agent.status || 'DRAFT',\n capabilities: agent.capabilities || [],\n llmModelId: agent.llmModelId || '',\n });\n }\n }, [existingAgent]);\n\n const steps = [\n { id: 0, label: 'Basic Info', icon: <Sparkles size={18} /> },\n { id: 1, label: 'Prompt', icon: <Brain size={18} /> },\n { id: 2, label: 'LLM Model', icon: <Settings size={18} /> },\n { id: 3, label: 'Tools & Knowledge', icon: <Wrench size={18} /> },\n ];\n\n const avatars = ['🤖', '🧠', '💡', '🎯', '🔧', '📊', '🎧', '💼', '🔍', '⚡', '🌟', '🚀'];\n\n const allCapabilities: { key: AgentCapability; label: string; description: string }[] = [\n { key: 'MCP_TOOLS', label: 'MCP Tools', description: 'Can use MCP tool servers' },\n { key: 'RAG', label: 'RAG', description: 'Retrieval-augmented generation' },\n { key: 'REASONING', label: 'Reasoning', description: 'Advanced reasoning' },\n { key: 'MULTIMODAL', label: 'Multimodal', description: 'Process images & media' },\n { key: 'MEMORY', label: 'Memory', description: 'Conversation memory' },\n { key: 'CODE_EXECUTION', label: 'Code Execution', description: 'Execute code' },\n { key: 'A2A', label: 'A2A', description: 'Agent-to-agent protocol' },\n { key: 'WEB_BROWSING', label: 'Web Browsing', description: 'Browse the web' },\n ];\n\n const toggleCapability = (cap: string) => {\n setFormData((prev) => ({\n ...prev,\n capabilities: prev.capabilities.includes(cap)\n ? prev.capabilities.filter((c) => c !== cap)\n : [...prev.capabilities, cap],\n }));\n };\n\n const handleSave = async () => {\n if (\n formData.llmModelId &&\n (catalogLoading ||\n catalogError ||\n !answerModels.some((model) => model.id === formData.llmModelId))\n ) {\n toast.error('Choose an active answer model from the available catalog.');\n return;\n }\n const slug = formData.slug || formData.name.toLowerCase().replace(/\\s+/g, '-');\n\n try {\n if (isEditing && agentId) {\n await updateAgent({\n agentId,\n input: {\n name: formData.name,\n slug,\n description: formData.description || undefined,\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n type: toAgentType(formData.type),\n },\n });\n toast.success(`Agent \"${formData.name}\" updated successfully`);\n navigateTo(`agents/${agentId}`);\n } else {\n if (!workspaceId) return;\n const agent = await createAgent({\n workspaceId,\n name: formData.name,\n slug,\n type: toAgentType(formData.type),\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n description: formData.description || undefined,\n });\n toast.success(`Agent \"${formData.name}\" created successfully`);\n if (agent?.id) navigateTo(`agents/${agent.id}`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save agent';\n toast.error(message);\n }\n };\n\n const isCreating = createAgentResult.loading;\n const isUpdating = updateAgentResult.loading;\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n <ArrowLeft size={20} />\n </Button>\n <span>{isEditing ? 'Edit Agent' : 'Create New Agent'}</span>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n </div>\n }\n >\n <div className=\"max-w-4xl mx-auto\">\n <PagePurpose className=\"mb-6\" icon={<Sparkles size={18} />}>\n This guided builder walks you through everything an agent needs — its identity and system\n prompt, the model and parameters it runs on, and the tools and knowledge it can reach.\n Work through the steps, then create the agent and test it in chat. You can come back and\n edit any step later.\n </PagePurpose>\n\n {/* Steps */}\n <div className=\"flex items-center justify-between mb-8\">\n {steps.map((step) => (\n <button\n key={step.id}\n onClick={() => setActiveStep(step.id)}\n className={cn(\n 'flex items-center gap-2 px-4 py-2 rounded-lg transition-colors',\n activeStep === step.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:bg-accent'\n )}\n >\n {step.icon}\n <span className=\"font-medium\">{step.label}</span>\n </button>\n ))}\n </div>\n\n {/* Step Content */}\n <div className=\"space-y-6\">\n {activeStep === 0 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n <CardDescription>Set up the agent's identity and purpose</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Avatar Selection */}\n <div>\n <label className=\"text-sm font-medium\">Avatar</label>\n <div className=\"flex gap-2 mt-2 flex-wrap\">\n {avatars.map((avatar) => (\n <button\n key={avatar}\n onClick={() => setFormData({ ...formData, avatar })}\n className={cn(\n 'text-3xl p-2 rounded-lg border-2 transition-colors',\n formData.avatar === avatar\n ? 'border-primary bg-action-primary-bg/10'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n {avatar}\n </button>\n ))}\n </div>\n </div>\n\n <FormField label=\"Agent Name\" required>\n <Input\n placeholder=\"e.g., Customer Support Agent\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Slug\" description=\"URL-friendly identifier\">\n <Input\n placeholder=\"customer-support-agent\"\n value={formData.slug}\n onChange={(e) => setFormData({ ...formData, slug: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"Describe what this agent does...\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n />\n </FormField>\n\n {/* Capabilities */}\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Capabilities</label>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {allCapabilities.map((cap) => (\n <label\n key={cap.key}\n className=\"flex items-start gap-3 p-3 border border-border-subtle rounded-lg cursor-pointer hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-border-default mt-0.5\"\n checked={formData.capabilities.includes(cap.key)}\n onChange={() => toggleCapability(cap.key)}\n />\n <div>\n <p className=\"font-medium text-sm\">{cap.label}</p>\n <p className=\"text-xs text-text-secondary\">{cap.description}</p>\n </div>\n </label>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 1 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Prompt Configuration</CardTitle>\n <CardDescription>Define how the agent communicates and behaves</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField\n label=\"System Prompt\"\n required\n description=\"The core instructions that define the agent's behavior\"\n >\n <Textarea\n placeholder=\"You are a helpful assistant...\"\n value={formData.systemPrompt}\n onChange={(e) => setFormData({ ...formData, systemPrompt: e.target.value })}\n rows={8}\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Temperature\" description=\"Controls randomness (0-2)\">\n <Input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={formData.temperature}\n onChange={(e) => setFormData({ ...formData, temperature: e.target.value })}\n />\n </FormField>\n <FormField label=\"Max Tokens\" description=\"Maximum response length\">\n <Input\n type=\"number\"\n step=\"256\"\n min=\"1\"\n value={formData.maxTokens}\n onChange={(e) => setFormData({ ...formData, maxTokens: e.target.value })}\n />\n </FormField>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 2 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>LLM Configuration</CardTitle>\n <CardDescription>Select the LLM model for this agent</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField label=\"LLM Model\" description=\"Select a model for this agent\">\n {catalogLoading && <p role=\"status\">Loading answer models…</p>}\n {catalogError && (\n <div role=\"alert\">\n <p>Could not load answer models.</p>\n <Button\n variant=\"secondary\"\n onClick={() => {\n void refetchModels();\n void refetchProviders();\n }}\n >\n Retry model catalog\n </Button>\n </div>\n )}\n <select\n aria-label=\"LLM Model\"\n disabled={catalogLoading || Boolean(catalogError)}\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.llmModelId}\n onChange={(e) => setFormData({ ...formData, llmModelId: e.target.value })}\n >\n <option value=\"\">Select a model...</option>\n {answerModels.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.modelId})\n </option>\n ))}\n </select>\n </FormField>\n\n <div className=\"p-4 bg-bg-sunken rounded-lg\">\n <h4 className=\"text-sm font-medium mb-2\">Available Providers</h4>\n <div className=\"grid grid-cols-2 gap-2\">\n {providers?.map((provider: { id: string; name: string; type: string }) => (\n <div key={provider.id} className=\"text-sm\">\n <span className=\"font-medium\">{provider.name}</span>\n <span className=\"text-text-secondary ml-2\">({provider.type})</span>\n </div>\n ))}\n {!catalogLoading && !catalogError && !providers?.length && (\n <p className=\"text-sm text-text-secondary\">No providers configured</p>\n )}\n </div>\n </div>\n\n {!catalogLoading && !catalogError && !answerModels.length && (\n <p className=\"text-sm text-text-secondary\">\n No models available. Configure a provider and add models in Settings.\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n {activeStep === 3 && (\n <div className=\"space-y-6\">\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench size={18} />\n Tools & Knowledge\n </CardTitle>\n <CardDescription>\n Configure tools and knowledge bases for this agent\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"text-center py-12 text-text-secondary\">\n <Wrench className=\"h-10 w-10 mx-auto mb-3 opacity-50\" />\n <p className=\"font-medium\">Tools & Knowledge coming soon</p>\n <p className=\"text-sm mt-2\">\n MCP tool connections and knowledge base bindings will be configurable here in\n a future update.\n </p>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between pt-6\">\n <Button\n variant=\"outline\"\n onClick={() => setActiveStep(Math.max(0, activeStep - 1))}\n disabled={activeStep === 0}\n >\n Previous\n </Button>\n {activeStep < steps.length - 1 ? (\n <Button onClick={() => setActiveStep(activeStep + 1)}>Next</Button>\n ) : (\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n )}\n </div>\n </div>\n </div>\n\n {/* Show bots dropdown if needed */}\n {bots && bots.length > 0 && null}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentBuilderPage.js","names":[],"sources":["../../../src/botlit/pages/AgentBuilderPage.tsx"],"sourcesContent":["/**\n * Agent Builder Page\n * @module botlit/pages\n *\n * Creates/edits agents with real GraphQL BotmanorAgent type:\n * - systemPrompt (string), temperature, maxTokens\n * - capabilities (enum array: MCP_TOOLS, RAG, REASONING, etc.)\n * - llmModelId (reference to LLM model)\n * - type (ASSISTANT, ANALYST, AUTOMATION, SPECIALIST)\n */\n\nimport type { FC } from 'react';\nimport { useState, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { ArrowLeft, Save, Brain, Wrench, Settings, Sparkles } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { useAgent, useCreateAgent, useUpdateAgent } from '../hooks/useAgents';\nimport { useBots } from '../hooks/useBots';\nimport { useLLMProviders, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\nimport { configuredAnswerModels } from '../utils/embedding-models';\n\n/** `BotmanorAgentCapability` values the builder offers. */\nconst AGENT_CAPABILITIES = [\n 'MCP_TOOLS',\n 'RAG',\n 'REASONING',\n 'MULTIMODAL',\n 'MEMORY',\n 'CODE_EXECUTION',\n 'A2A',\n 'WEB_BROWSING',\n] as const;\ntype AgentCapability = (typeof AGENT_CAPABILITIES)[number];\n\n/** `BotmanorAgentType` values the builder offers. */\nconst AGENT_TYPES = ['ASSISTANT', 'ANALYST', 'AUTOMATION', 'SPECIALIST'] as const;\n\n/** Drops any capability the schema does not declare rather than guessing one. */\nfunction toCapabilities(values: string[]): AgentCapability[] {\n return values.flatMap((value) => {\n const match = AGENT_CAPABILITIES.find((capability) => capability === value);\n return match ? [match] : [];\n });\n}\n\nfunction toAgentType(value: string): (typeof AGENT_TYPES)[number] {\n return toUnion(value, AGENT_TYPES, 'ASSISTANT');\n}\n\ninterface FormDataType {\n name: string;\n slug: string;\n description: string;\n avatar: string;\n tags: string[];\n // Flat fields matching real GraphQL API\n systemPrompt: string;\n temperature: string;\n maxTokens: string;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId: string;\n}\n\nexport const AgentBuilderPage: FC = () => {\n const { agentId } = useParams();\n const { navigateTo, workspaceId } = useBotlit();\n const { data: existingAgent } = useAgent(agentId);\n const { data: bots } = useBots();\n const {\n data: providers,\n loading: providersLoading,\n error: providersError,\n refetch: refetchProviders,\n } = useLLMProviders();\n const {\n data: llmModels,\n loading: modelsLoading,\n error: modelsError,\n refetch: refetchModels,\n } = useLLMModels();\n const catalogLoading = providersLoading || modelsLoading;\n const catalogError = providersError || modelsError;\n const answerModels = configuredAnswerModels(llmModels ?? [], providers ?? []);\n const [createAgent, createAgentResult] = useCreateAgent();\n const [updateAgent, updateAgentResult] = useUpdateAgent();\n\n const isEditing = !!agentId;\n const [activeStep, setActiveStep] = useState(0);\n\n const [formData, setFormData] = useState<FormDataType>({\n name: '',\n slug: '',\n description: '',\n avatar: '🤖',\n tags: [],\n systemPrompt: 'You are a helpful AI assistant. Be concise, accurate, and friendly.',\n temperature: '0.7',\n maxTokens: '2048',\n type: 'ASSISTANT',\n status: 'DRAFT',\n capabilities: ['MCP_TOOLS', 'REASONING'],\n llmModelId: '',\n });\n\n // Update form when existing agent loads\n useEffect(() => {\n if (existingAgent) {\n const agent = existingAgent as {\n name: string;\n slug: string;\n description?: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId?: string;\n tagIds?: string[];\n };\n setFormData({\n name: agent.name,\n slug: agent.slug,\n description: agent.description || '',\n avatar: '🤖',\n tags: agent.tagIds || [],\n systemPrompt: agent.systemPrompt || '',\n temperature: String(agent.temperature ?? 0.7),\n maxTokens: String(agent.maxTokens ?? 2048),\n type: agent.type || 'ASSISTANT',\n status: agent.status || 'DRAFT',\n capabilities: agent.capabilities || [],\n llmModelId: agent.llmModelId || '',\n });\n }\n }, [existingAgent]);\n\n const steps = [\n { id: 0, label: 'Basic Info', icon: <Sparkles size={18} /> },\n { id: 1, label: 'Prompt', icon: <Brain size={18} /> },\n { id: 2, label: 'LLM Model', icon: <Settings size={18} /> },\n { id: 3, label: 'Tools & Knowledge', icon: <Wrench size={18} /> },\n ];\n\n const avatars = ['🤖', '🧠', '💡', '🎯', '🔧', '📊', '🎧', '💼', '🔍', '⚡', '🌟', '🚀'];\n\n const allCapabilities: { key: AgentCapability; label: string; description: string }[] = [\n { key: 'MCP_TOOLS', label: 'MCP Tools', description: 'Can use MCP tool servers' },\n { key: 'RAG', label: 'RAG', description: 'Retrieval-augmented generation' },\n { key: 'REASONING', label: 'Reasoning', description: 'Advanced reasoning' },\n { key: 'MULTIMODAL', label: 'Multimodal', description: 'Process images & media' },\n { key: 'MEMORY', label: 'Memory', description: 'Conversation memory' },\n { key: 'CODE_EXECUTION', label: 'Code Execution', description: 'Execute code' },\n { key: 'A2A', label: 'A2A', description: 'Agent-to-agent protocol' },\n { key: 'WEB_BROWSING', label: 'Web Browsing', description: 'Browse the web' },\n ];\n\n const toggleCapability = (cap: string) => {\n setFormData((prev) => ({\n ...prev,\n capabilities: prev.capabilities.includes(cap)\n ? prev.capabilities.filter((c) => c !== cap)\n : [...prev.capabilities, cap],\n }));\n };\n\n const handleSave = async () => {\n if (\n formData.llmModelId &&\n (catalogLoading ||\n catalogError ||\n !answerModels.some((model) => model.id === formData.llmModelId))\n ) {\n toast.error('Choose an active answer model from the available catalog.');\n return;\n }\n const slug = formData.slug || formData.name.toLowerCase().replace(/\\s+/g, '-');\n\n try {\n if (isEditing && agentId) {\n await updateAgent({\n agentId,\n input: {\n name: formData.name,\n slug,\n description: formData.description || undefined,\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n type: toAgentType(formData.type),\n },\n });\n toast.success(`Agent \"${formData.name}\" updated successfully`);\n navigateTo(`agents/${agentId}`);\n } else {\n if (!workspaceId) return;\n const agent = await createAgent({\n workspaceId,\n name: formData.name,\n slug,\n type: toAgentType(formData.type),\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n description: formData.description || undefined,\n });\n toast.success(`Agent \"${formData.name}\" created successfully`);\n if (agent?.id) navigateTo(`agents/${agent.id}`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save agent';\n toast.error(message);\n }\n };\n\n const isCreating = createAgentResult.loading;\n const isUpdating = updateAgentResult.loading;\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n <ArrowLeft size={20} />\n </Button>\n <span>{isEditing ? 'Edit Agent' : 'Create New Agent'}</span>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n </div>\n }\n >\n <div className=\"max-w-4xl mx-auto\">\n <PagePurpose className=\"mb-6\" icon={<Sparkles size={18} />}>\n This guided builder walks you through everything an agent needs — its identity and system\n prompt, the model and parameters it runs on, and the tools and knowledge it can reach.\n Work through the steps, then create the agent and test it in chat. You can come back and\n edit any step later.\n </PagePurpose>\n\n {/* Steps */}\n <div className=\"flex items-center justify-between mb-8\">\n {steps.map((step) => (\n <button\n key={step.id}\n onClick={() => setActiveStep(step.id)}\n className={cn(\n 'flex items-center gap-2 px-4 py-2 rounded-lg transition-colors',\n activeStep === step.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:bg-accent'\n )}\n >\n {step.icon}\n <span className=\"font-medium\">{step.label}</span>\n </button>\n ))}\n </div>\n\n {/* Step Content */}\n <div className=\"space-y-6\">\n {activeStep === 0 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n <CardDescription>Set up the agent's identity and purpose</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Avatar Selection */}\n <div>\n <label className=\"text-sm font-medium\">Avatar</label>\n <div className=\"flex gap-2 mt-2 flex-wrap\">\n {avatars.map((avatar) => (\n <button\n key={avatar}\n onClick={() => setFormData({ ...formData, avatar })}\n className={cn(\n 'text-3xl p-2 rounded-lg border-2 transition-colors',\n formData.avatar === avatar\n ? 'border-primary bg-action-primary-bg/10'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n {avatar}\n </button>\n ))}\n </div>\n </div>\n\n <FormField label=\"Agent Name\" required>\n <Input\n placeholder=\"e.g., Customer Support Agent\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Slug\" description=\"URL-friendly identifier\">\n <Input\n placeholder=\"customer-support-agent\"\n value={formData.slug}\n onChange={(e) => setFormData({ ...formData, slug: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"Describe what this agent does...\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n />\n </FormField>\n\n {/* Capabilities */}\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Capabilities</label>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {allCapabilities.map((cap) => (\n <label\n key={cap.key}\n className=\"flex items-start gap-3 p-3 border border-border-subtle rounded-lg cursor-pointer hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-border-default mt-0.5\"\n checked={formData.capabilities.includes(cap.key)}\n onChange={() => toggleCapability(cap.key)}\n />\n <div>\n <p className=\"font-medium text-sm\">{cap.label}</p>\n <p className=\"text-xs text-text-secondary\">{cap.description}</p>\n </div>\n </label>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 1 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Prompt Configuration</CardTitle>\n <CardDescription>Define how the agent communicates and behaves</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField\n label=\"System Prompt\"\n required\n description=\"The core instructions that define the agent's behavior\"\n >\n <Textarea\n placeholder=\"You are a helpful assistant...\"\n value={formData.systemPrompt}\n onChange={(e) => setFormData({ ...formData, systemPrompt: e.target.value })}\n rows={8}\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Temperature\" description=\"Controls randomness (0-2)\">\n <Input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={formData.temperature}\n onChange={(e) => setFormData({ ...formData, temperature: e.target.value })}\n />\n </FormField>\n <FormField label=\"Max Tokens\" description=\"Maximum response length\">\n <Input\n type=\"number\"\n step=\"256\"\n min=\"1\"\n value={formData.maxTokens}\n onChange={(e) => setFormData({ ...formData, maxTokens: e.target.value })}\n />\n </FormField>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 2 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>LLM Configuration</CardTitle>\n <CardDescription>Select the LLM model for this agent</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField label=\"LLM Model\" description=\"Select a model for this agent\">\n {catalogLoading && <p role=\"status\">Loading answer models…</p>}\n {catalogError && (\n <div role=\"alert\">\n <p>Could not load answer models.</p>\n <Button\n variant=\"secondary\"\n onClick={() => {\n void refetchModels();\n void refetchProviders();\n }}\n >\n Retry model catalog\n </Button>\n </div>\n )}\n <select\n aria-label=\"LLM Model\"\n disabled={catalogLoading || Boolean(catalogError)}\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.llmModelId}\n onChange={(e) => setFormData({ ...formData, llmModelId: e.target.value })}\n >\n <option value=\"\">Select a model...</option>\n {answerModels.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.modelId})\n </option>\n ))}\n </select>\n </FormField>\n\n <div className=\"p-4 bg-bg-sunken rounded-lg\">\n <h4 className=\"text-sm font-medium mb-2\">Available Providers</h4>\n <div className=\"grid grid-cols-2 gap-2\">\n {providers?.map((provider: { id: string; name: string; type: string }) => (\n <div key={provider.id} className=\"text-sm\">\n <span className=\"font-medium\">{provider.name}</span>\n <span className=\"text-text-secondary ml-2\">({provider.type})</span>\n </div>\n ))}\n {!catalogLoading && !catalogError && !providers?.length && (\n <p className=\"text-sm text-text-secondary\">No providers configured</p>\n )}\n </div>\n </div>\n\n {!catalogLoading && !catalogError && !answerModels.length && (\n <p className=\"text-sm text-text-secondary\">\n No models available. Configure a provider and add models in Settings.\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n {activeStep === 3 && (\n <div className=\"space-y-6\">\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench size={18} />\n Tools & Knowledge\n </CardTitle>\n <CardDescription>\n Configure tools and knowledge bases for this agent\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"text-center py-12 text-text-secondary\">\n <Wrench className=\"h-10 w-10 mx-auto mb-3 opacity-50\" />\n <p className=\"font-medium\">Tools & Knowledge coming soon</p>\n <p className=\"text-sm mt-2\">\n MCP tool connections and knowledge base bindings will be configurable here in\n a future update.\n </p>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between pt-6\">\n <Button\n variant=\"outline\"\n onClick={() => setActiveStep(Math.max(0, activeStep - 1))}\n disabled={activeStep === 0}\n >\n Previous\n </Button>\n {activeStep < steps.length - 1 ? (\n <Button onClick={() => setActiveStep(activeStep + 1)}>Next</Button>\n ) : (\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n )}\n </div>\n </div>\n </div>\n\n {/* Show bots dropdown if needed */}\n {bots && bots.length > 0 && null}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"botmanorPermissions.js","names":[],"sources":["../../../src/botlit/permissions/botmanorPermissions.ts"],"sourcesContent":["/**\n * BotManor permission catalogue\n * @module botlit/permissions\n *\n * The `resource:action` pairs the BotManor UI checks before it offers a write\n * control. Every pair mirrors the `@rbac(resource, action)` directive on the\n * wspace-botmanor-svc mutation that the control calls, so the UI hides exactly\n * what the gateway would refuse. The gateway stays the only enforcement point:\n * hiding a button never grants or denies anything, it only stops a member from\n * attempting an action the gateway will answer with FORBIDDEN.\n *\n * Keep this file in step with the service schema. When a mutation's directive\n * changes, change the pair here and the control that calls it.\n */\n\nexport const BOTMANOR_PERMISSIONS = {\n // Bot apps — createBotApp / updateBotApp / deleteBotApp / publishBotAppVersion /\n // rollbackBotAppVersion\n APP_CREATE: 'botmanor-app:create',\n APP_UPDATE: 'botmanor-app:update',\n APP_DELETE: 'botmanor-app:delete',\n APP_PUBLISH: 'botmanor-app:publish',\n APP_ROLLBACK: 'botmanor-app:rollback',\n\n // Agents behind an app — createAppAgent / updateAppAgent / deleteAppAgent\n APP_AGENT_CREATE: 'botmanor-app-agent:create',\n APP_AGENT_UPDATE: 'botmanor-app-agent:update',\n APP_AGENT_DELETE: 'botmanor-app-agent:delete',\n\n // Agents — createBotmanorAgent / updateBotmanorAgent / deleteBotmanorAgent /\n // publishAgentVersion / rollbackAgentVersion / chatWithAgent /\n // approve|rejectBotmanorAgentActivation / updateBotmanorAgentApprovalSettings /\n // configureAssistantRuntime / publishAssistantWebsite / configureAssistantChannel\n AGENT_CREATE: 'botmanor-agent:create',\n AGENT_UPDATE: 'botmanor-agent:update',\n AGENT_DELETE: 'botmanor-agent:delete',\n AGENT_PUBLISH: 'botmanor-agent:publish',\n AGENT_ROLLBACK: 'botmanor-agent:rollback',\n AGENT_EXECUTE: 'botmanor-agent:execute',\n AGENT_APPROVE: 'botmanor-agent:approve',\n\n // Knowledge bases — createKnowledgeBase / addKnowledgeDocument /\n // updateKnowledgeBase / deleteKnowledgeBase / removeKnowledgeDocument /\n // rebuildKnowledgeBaseIndex / queueKnowledgeSource / retry*\n KNOWLEDGE_CREATE: 'botmanor-knowledge-base:create',\n KNOWLEDGE_UPDATE: 'botmanor-knowledge-base:update',\n KNOWLEDGE_DELETE: 'botmanor-knowledge-base:delete',\n KNOWLEDGE_MANAGE: 'botmanor-knowledge-base:manage',\n\n // Retrieval profiles\n RETRIEVAL_PROFILE_CREATE: 'botmanor-retrieval-profile:create',\n RETRIEVAL_PROFILE_UPDATE: 'botmanor-retrieval-profile:update',\n RETRIEVAL_PROFILE_DELETE: 'botmanor-retrieval-profile:delete',\n\n // MCP servers — create/update/deleteMCPConnection, updateMCPTool,\n // testMCPConnection, refreshMCPTools / refreshMCPResources / callMCPTool\n MCP_CREATE: 'botmanor-mcp:create',\n MCP_UPDATE: 'botmanor-mcp:update',\n MCP_DELETE: 'botmanor-mcp:delete',\n MCP_TEST: 'botmanor-mcp:test',\n MCP_EXECUTE: 'botmanor-mcp:execute',\n\n // LLM providers and models — create/update/delete*, testLlmConnection\n LLM_CREATE: 'botmanor-llm:create',\n LLM_UPDATE: 'botmanor-llm:update',\n LLM_DELETE: 'botmanor-llm:delete',\n LLM_TEST: 'botmanor-llm:test',\n\n // A2A — create/update/deleteA2AConnection, sendA2AMessage, delegateA2ATask\n A2A_CREATE: 'botmanor-a2a:create',\n A2A_UPDATE: 'botmanor-a2a:update',\n A2A_DELETE: 'botmanor-a2a:delete',\n A2A_SEND: 'botmanor-a2a:send',\n A2A_EXECUTE: 'botmanor-a2a:execute',\n\n // A2A registry (the external agents the Registry page lists) —\n // create/update/deleteA2ARegistryEntry\n A2A_REGISTRY_CREATE: 'botmanor-a2a-registry:create',\n A2A_REGISTRY_UPDATE: 'botmanor-a2a-registry:update',\n A2A_REGISTRY_DELETE: 'botmanor-a2a-registry:delete',\n\n // Channels — connectors and routes\n CHANNEL_CREATE: 'botmanor-channel:create',\n CHANNEL_UPDATE: 'botmanor-channel:update',\n CHANNEL_DELETE: 'botmanor-channel:delete',\n // sendChannelMessage is :create, handleChannelMessage is :execute\n CHANNEL_MESSAGE_CREATE: 'botmanor-channel-message:create',\n CHANNEL_MESSAGE_EXECUTE: 'botmanor-channel-message:execute',\n\n // Policies\n POLICY_CREATE: 'botmanor-policy:create',\n POLICY_UPDATE: 'botmanor-policy:update',\n POLICY_DELETE: 'botmanor-policy:delete',\n\n // Skills\n SKILL_CREATE: 'botmanor-skill:create',\n SKILL_UPDATE: 'botmanor-skill:update',\n SKILL_DELETE: 'botmanor-skill:delete',\n\n // Prompt templates — create/duplicate share :create; renderPromptTemplate is :execute\n PROMPT_TEMPLATE_CREATE: 'botmanor-prompt-template:create',\n PROMPT_TEMPLATE_UPDATE: 'botmanor-prompt-template:update',\n PROMPT_TEMPLATE_DELETE: 'botmanor-prompt-template:delete',\n PROMPT_TEMPLATE_EXECUTE: 'botmanor-prompt-template:execute',\n\n // Executions — createExecution /
|
|
1
|
+
{"version":3,"file":"botmanorPermissions.js","names":[],"sources":["../../../src/botlit/permissions/botmanorPermissions.ts"],"sourcesContent":["/**\n * BotManor permission catalogue\n * @module botlit/permissions\n *\n * The `resource:action` pairs the BotManor UI checks before it offers a write\n * control. Every pair mirrors the `@rbac(resource, action)` directive on the\n * wspace-botmanor-svc mutation that the control calls, so the UI hides exactly\n * what the gateway would refuse. The gateway stays the only enforcement point:\n * hiding a button never grants or denies anything, it only stops a member from\n * attempting an action the gateway will answer with FORBIDDEN.\n *\n * Keep this file in step with the service schema. When a mutation's directive\n * changes, change the pair here and the control that calls it.\n */\n\nexport const BOTMANOR_PERMISSIONS = {\n // Bot apps — createBotApp / updateBotApp / deleteBotApp / publishBotAppVersion /\n // rollbackBotAppVersion\n APP_CREATE: 'botmanor-app:create',\n APP_UPDATE: 'botmanor-app:update',\n APP_DELETE: 'botmanor-app:delete',\n APP_PUBLISH: 'botmanor-app:publish',\n APP_ROLLBACK: 'botmanor-app:rollback',\n\n // Agents behind an app — createAppAgent / updateAppAgent / deleteAppAgent\n APP_AGENT_CREATE: 'botmanor-app-agent:create',\n APP_AGENT_UPDATE: 'botmanor-app-agent:update',\n APP_AGENT_DELETE: 'botmanor-app-agent:delete',\n\n // Agents — createBotmanorAgent / updateBotmanorAgent / deleteBotmanorAgent /\n // publishAgentVersion / rollbackAgentVersion / chatWithAgent /\n // approve|rejectBotmanorAgentActivation / updateBotmanorAgentApprovalSettings /\n // configureAssistantRuntime / publishAssistantWebsite / configureAssistantChannel\n AGENT_CREATE: 'botmanor-agent:create',\n AGENT_UPDATE: 'botmanor-agent:update',\n AGENT_DELETE: 'botmanor-agent:delete',\n AGENT_PUBLISH: 'botmanor-agent:publish',\n AGENT_ROLLBACK: 'botmanor-agent:rollback',\n AGENT_EXECUTE: 'botmanor-agent:execute',\n AGENT_APPROVE: 'botmanor-agent:approve',\n\n // Knowledge bases — createKnowledgeBase / addKnowledgeDocument /\n // updateKnowledgeBase / deleteKnowledgeBase / removeKnowledgeDocument /\n // rebuildKnowledgeBaseIndex / queueKnowledgeSource / retry*\n KNOWLEDGE_CREATE: 'botmanor-knowledge-base:create',\n KNOWLEDGE_UPDATE: 'botmanor-knowledge-base:update',\n KNOWLEDGE_DELETE: 'botmanor-knowledge-base:delete',\n KNOWLEDGE_MANAGE: 'botmanor-knowledge-base:manage',\n\n // Retrieval profiles\n RETRIEVAL_PROFILE_CREATE: 'botmanor-retrieval-profile:create',\n RETRIEVAL_PROFILE_UPDATE: 'botmanor-retrieval-profile:update',\n RETRIEVAL_PROFILE_DELETE: 'botmanor-retrieval-profile:delete',\n\n // MCP servers — create/update/deleteMCPConnection, updateMCPTool,\n // testMCPConnection, refreshMCPTools / refreshMCPResources / callMCPTool\n MCP_CREATE: 'botmanor-mcp:create',\n MCP_UPDATE: 'botmanor-mcp:update',\n MCP_DELETE: 'botmanor-mcp:delete',\n MCP_TEST: 'botmanor-mcp:test',\n MCP_EXECUTE: 'botmanor-mcp:execute',\n\n // LLM providers and models — create/update/delete*, testLlmConnection\n LLM_CREATE: 'botmanor-llm:create',\n LLM_UPDATE: 'botmanor-llm:update',\n LLM_DELETE: 'botmanor-llm:delete',\n LLM_TEST: 'botmanor-llm:test',\n\n // A2A — create/update/deleteA2AConnection, sendA2AMessage, delegateA2ATask\n A2A_CREATE: 'botmanor-a2a:create',\n A2A_UPDATE: 'botmanor-a2a:update',\n A2A_DELETE: 'botmanor-a2a:delete',\n A2A_SEND: 'botmanor-a2a:send',\n A2A_EXECUTE: 'botmanor-a2a:execute',\n\n // A2A registry (the external agents the Registry page lists) —\n // create/update/deleteA2ARegistryEntry\n A2A_REGISTRY_CREATE: 'botmanor-a2a-registry:create',\n A2A_REGISTRY_UPDATE: 'botmanor-a2a-registry:update',\n A2A_REGISTRY_DELETE: 'botmanor-a2a-registry:delete',\n\n // Channels — connectors and routes\n CHANNEL_CREATE: 'botmanor-channel:create',\n CHANNEL_UPDATE: 'botmanor-channel:update',\n CHANNEL_DELETE: 'botmanor-channel:delete',\n // sendChannelMessage is :create, handleChannelMessage is :execute\n CHANNEL_MESSAGE_CREATE: 'botmanor-channel-message:create',\n CHANNEL_MESSAGE_EXECUTE: 'botmanor-channel-message:execute',\n\n // Policies\n POLICY_CREATE: 'botmanor-policy:create',\n POLICY_UPDATE: 'botmanor-policy:update',\n POLICY_DELETE: 'botmanor-policy:delete',\n\n // Skills\n SKILL_CREATE: 'botmanor-skill:create',\n SKILL_UPDATE: 'botmanor-skill:update',\n SKILL_DELETE: 'botmanor-skill:delete',\n\n // Prompt templates — create/duplicate share :create; renderPromptTemplate is :execute\n PROMPT_TEMPLATE_CREATE: 'botmanor-prompt-template:create',\n PROMPT_TEMPLATE_UPDATE: 'botmanor-prompt-template:update',\n PROMPT_TEMPLATE_DELETE: 'botmanor-prompt-template:delete',\n PROMPT_TEMPLATE_EXECUTE: 'botmanor-prompt-template:execute',\n\n // Executions — createExecution / triggerBotmanorBoundWorkflow are :create,\n // runExecution / updateExecutionStatus are :update\n EXECUTION_CREATE: 'botmanor-execution:create',\n EXECUTION_UPDATE: 'botmanor-execution:update',\n\n // Buckets\n BUCKET_CREATE: 'botmanor-bucket:create',\n BUCKET_UPDATE: 'botmanor-bucket:update',\n BUCKET_DELETE: 'botmanor-bucket:delete',\n\n // Store — installPackage / forkInstalledPackage are :create,\n // updateInstalledPackage :update, uninstallPackage :delete\n STORE_CREATE: 'botmanor-store:create',\n STORE_UPDATE: 'botmanor-store:update',\n STORE_DELETE: 'botmanor-store:delete',\n\n // Agent and app templates\n TEMPLATE_CREATE: 'botmanor-template:create',\n TEMPLATE_UPDATE: 'botmanor-template:update',\n TEMPLATE_DELETE: 'botmanor-template:delete',\n} as const;\n\nexport type BotmanorPermission = (typeof BOTMANOR_PERMISSIONS)[keyof typeof BOTMANOR_PERMISSIONS];\n"],"mappings":";AAeA,IAAa,IAAuB;CAGlC,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,cAAc;CAGd,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAMlB,cAAc;CACd,cAAc;CACd,cAAc;CACd,eAAe;CACf,gBAAgB;CAChB,eAAe;CACf,eAAe;CAKf,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAGlB,0BAA0B;CAC1B,0BAA0B;CAC1B,0BAA0B;CAI1B,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,UAAU;CACV,aAAa;CAGb,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,UAAU;CAGV,YAAY;CACZ,YAAY;CACZ,YAAY;CACZ,UAAU;CACV,aAAa;CAIb,qBAAqB;CACrB,qBAAqB;CACrB,qBAAqB;CAGrB,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAEhB,wBAAwB;CACxB,yBAAyB;CAGzB,eAAe;CACf,eAAe;CACf,eAAe;CAGf,cAAc;CACd,cAAc;CACd,cAAc;CAGd,wBAAwB;CACxB,wBAAwB;CACxB,wBAAwB;CACxB,yBAAyB;CAIzB,kBAAkB;CAClB,kBAAkB;CAGlB,eAAe;CACf,eAAe;CACf,eAAe;CAIf,cAAc;CACd,cAAc;CACd,cAAc;CAGd,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAClB"}
|