@webiny/app-admin 6.6.0-alpha.4 → 6.6.0-alpha.6
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/base/Admin.js +2 -2
- package/base/Admin.js.map +1 -1
- package/features/{aiChat/AiChatGateway.d.ts → adminAssistant/AdminAssistantGateway.d.ts} +7 -7
- package/features/{aiChat/AiChatGateway.js → adminAssistant/AdminAssistantGateway.js} +8 -8
- package/features/adminAssistant/AdminAssistantGateway.js.map +1 -0
- package/features/{aiChat/AiChatPresenter.d.ts → adminAssistant/AdminAssistantPresenter.d.ts} +7 -7
- package/features/{aiChat/AiChatPresenter.js → adminAssistant/AdminAssistantPresenter.js} +7 -7
- package/features/adminAssistant/AdminAssistantPresenter.js.map +1 -0
- package/features/{aiChat → adminAssistant}/abstractions.d.ts +30 -30
- package/features/adminAssistant/abstractions.js +6 -0
- package/features/adminAssistant/abstractions.js.map +1 -0
- package/features/adminAssistant/feature.d.ts +3 -0
- package/features/adminAssistant/feature.js +19 -0
- package/features/adminAssistant/feature.js.map +1 -0
- package/features/adminAssistant/index.d.ts +6 -0
- package/features/adminAssistant/index.js +3 -0
- package/features/formModel/Field.d.ts +6 -0
- package/features/formModel/Field.js +11 -0
- package/features/formModel/Field.js.map +1 -1
- package/features/formModel/Rules.test.js +55 -0
- package/features/formModel/Rules.test.js.map +1 -1
- package/features/wcp/ReactLicense.d.ts +5 -0
- package/features/wcp/ReactLicense.js +15 -0
- package/features/wcp/ReactLicense.js.map +1 -1
- package/features/wcp/WcpGateway.js +4 -0
- package/features/wcp/WcpGateway.js.map +1 -1
- package/hooks/useHotkeys.js +2 -2
- package/hooks/useHotkeys.js.map +1 -1
- package/index.d.ts +2 -2
- package/index.js +1 -1
- package/package.json +20 -20
- package/presentation/commandPalette/CommandPalettePresenter.js +2 -1
- package/presentation/commandPalette/CommandPalettePresenter.js.map +1 -1
- package/presentation/commandPalette/abstractions.d.ts +2 -0
- package/presentation/commandPalette/abstractions.js.map +1 -1
- package/presentation/commandPalette/commands/AskAiCommand.js +1 -1
- package/presentation/commandPalette/commands/AskAiCommand.js.map +1 -1
- package/features/aiChat/AiChatGateway.js.map +0 -1
- package/features/aiChat/AiChatPresenter.js.map +0 -1
- package/features/aiChat/abstractions.js +0 -6
- package/features/aiChat/abstractions.js.map +0 -1
- package/features/aiChat/feature.d.ts +0 -3
- package/features/aiChat/feature.js +0 -19
- package/features/aiChat/feature.js.map +0 -1
- package/features/aiChat/index.d.ts +0 -6
- package/features/aiChat/index.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/commandPalette/CommandPalettePresenter.js","sources":["../../../src/presentation/commandPalette/CommandPalettePresenter.ts"],"sourcesContent":["import { makeAutoObservable } from \"mobx\";\nimport {\n Command,\n CommandPalettePresenter as Abstraction,\n type CommandPaletteViewModel\n} from \"./abstractions.js\";\n\nexport class CommandPalettePresenter implements Abstraction.Interface {\n private isOpen = false;\n private activeCommandName: string | null = null;\n private aiModeActive = false;\n private query = \"\";\n private resolvedCommands: Command.Interface[] = [];\n\n constructor(private getCommands: () => Command.Interface[]) {\n makeAutoObservable(this);\n }\n\n init(): void {\n this.resolvedCommands = this.getCommands();\n }\n\n get shortcutKeys(): Record<string, (e: KeyboardEvent) => void> {\n const keys: Record<string, (e: KeyboardEvent) => void> = {};\n for (const cmd of this.resolvedCommands) {\n if (cmd.shortcut) {\n keys[cmd.shortcut] = (e: KeyboardEvent) => {\n e.preventDefault();\n this.useCommand(cmd.name);\n };\n }\n }\n return keys;\n }\n\n get vm(): CommandPaletteViewModel {\n const activeCmd =\n this.activeCommandName !== null\n ? this.resolvedCommands.find(c => c.name === this.activeCommandName)\n : null;\n\n return {\n isOpen: this.isOpen,\n aiModeActive: this.aiModeActive,\n query: this.query,\n commands: this.resolvedCommands.map(cmd => ({\n name: cmd.name,\n label: cmd.label,\n description: cmd.description,\n icon: cmd.icon,\n category: cmd.category,\n keywords: cmd.keywords,\n shortcut: cmd.shortcut,\n hasDetailView: Boolean(cmd.detailView)\n })),\n activeCommand:\n activeCmd && activeCmd.detailView\n ? {\n command: activeCmd,\n DetailView: activeCmd.detailView\n }\n : null\n };\n }\n\n open(): void {\n this.resolvedCommands = this.getCommands();\n this.activeCommandName = null;\n this.aiModeActive = false;\n this.query = \"\";\n this.isOpen = true;\n }\n\n close(): void {\n this.isOpen = false;\n this.activeCommandName = null;\n this.aiModeActive = false;\n this.query = \"\";\n }\n\n enterAiMode(): void {\n this.aiModeActive = true;\n this.query = \"\";\n }\n\n exitAiMode(): void {\n this.aiModeActive = false;\n this.query = \"\";\n }\n\n setQuery(query: string): void {\n this.query = query;\n }\n\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n useCommand(name: string): void {\n const cmd = this.resolvedCommands.find(c => c.name === name);\n if (!cmd) {\n return;\n }\n\n if (cmd.entersAiMode) {\n // A mode replaces the command list and keeps the input row, so the palette stays open.\n this.enterAiMode();\n return;\n }\n\n if (cmd.detailView) {\n this.activeCommandName = name;\n this.isOpen = true;\n return;\n }\n\n cmd.execute?.();\n this.close();\n }\n\n cancelCommand(): void {\n this.activeCommandName = null;\n }\n}\n"],"names":["CommandPalettePresenter","getCommands","makeAutoObservable","keys","cmd","e","activeCmd","c","Boolean","query","name"],"mappings":";AAOO,MAAMA;IAOT,YAAoBC,WAAsC,CAAE;aAAxCA,WAAW,GAAXA;aANZ,MAAM,GAAG;aACT,iBAAiB,GAAkB;aACnC,YAAY,GAAG;aACf,KAAK,GAAG;aACR,gBAAgB,GAAwB,EAAE;QAG9CC,mBAAmB,IAAI;IAC3B;IAEA,OAAa;QACT,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW;IAC5C;IAEA,IAAI,eAA2D;QAC3D,MAAMC,OAAmD,CAAC;QAC1D,KAAK,MAAMC,OAAO,IAAI,CAAC,gBAAgB,CACnC,IAAIA,IAAI,QAAQ,EACZD,IAAI,CAACC,IAAI,QAAQ,CAAC,GAAG,CAACC;YAClBA,EAAE,cAAc;YAChB,IAAI,CAAC,UAAU,CAACD,IAAI,IAAI;QAC5B;QAGR,OAAOD;IACX;IAEA,IAAI,KAA8B;QAC9B,MAAMG,YACF,AAA2B,SAA3B,IAAI,CAAC,iBAAiB,GAChB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAACC,CAAAA,IAAKA,EAAE,IAAI,KAAK,IAAI,CAAC,iBAAiB,IACjE;QAEV,OAAO;YACH,QAAQ,IAAI,CAAC,MAAM;YACnB,cAAc,IAAI,CAAC,YAAY;YAC/B,OAAO,IAAI,CAAC,KAAK;YACjB,UAAU,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAACH,CAAAA,MAAQ;oBACxC,MAAMA,IAAI,IAAI;oBACd,OAAOA,IAAI,KAAK;oBAChB,aAAaA,IAAI,WAAW;oBAC5B,MAAMA,IAAI,IAAI;oBACd,UAAUA,IAAI,QAAQ;oBACtB,UAAUA,IAAI,QAAQ;oBACtB,UAAUA,IAAI,QAAQ;oBACtB,eAAeI,QAAQJ,IAAI,UAAU;
|
|
1
|
+
{"version":3,"file":"presentation/commandPalette/CommandPalettePresenter.js","sources":["../../../src/presentation/commandPalette/CommandPalettePresenter.ts"],"sourcesContent":["import { makeAutoObservable } from \"mobx\";\nimport {\n Command,\n CommandPalettePresenter as Abstraction,\n type CommandPaletteViewModel\n} from \"./abstractions.js\";\n\nexport class CommandPalettePresenter implements Abstraction.Interface {\n private isOpen = false;\n private activeCommandName: string | null = null;\n private aiModeActive = false;\n private query = \"\";\n private resolvedCommands: Command.Interface[] = [];\n\n constructor(private getCommands: () => Command.Interface[]) {\n makeAutoObservable(this);\n }\n\n init(): void {\n this.resolvedCommands = this.getCommands();\n }\n\n get shortcutKeys(): Record<string, (e: KeyboardEvent) => void> {\n const keys: Record<string, (e: KeyboardEvent) => void> = {};\n for (const cmd of this.resolvedCommands) {\n if (cmd.shortcut) {\n keys[cmd.shortcut] = (e: KeyboardEvent) => {\n e.preventDefault();\n this.useCommand(cmd.name);\n };\n }\n }\n return keys;\n }\n\n get vm(): CommandPaletteViewModel {\n const activeCmd =\n this.activeCommandName !== null\n ? this.resolvedCommands.find(c => c.name === this.activeCommandName)\n : null;\n\n return {\n isOpen: this.isOpen,\n aiModeActive: this.aiModeActive,\n query: this.query,\n commands: this.resolvedCommands.map(cmd => ({\n name: cmd.name,\n label: cmd.label,\n description: cmd.description,\n icon: cmd.icon,\n category: cmd.category,\n keywords: cmd.keywords,\n shortcut: cmd.shortcut,\n hasDetailView: Boolean(cmd.detailView),\n entersAiMode: Boolean(cmd.entersAiMode)\n })),\n activeCommand:\n activeCmd && activeCmd.detailView\n ? {\n command: activeCmd,\n DetailView: activeCmd.detailView\n }\n : null\n };\n }\n\n open(): void {\n this.resolvedCommands = this.getCommands();\n this.activeCommandName = null;\n this.aiModeActive = false;\n this.query = \"\";\n this.isOpen = true;\n }\n\n close(): void {\n this.isOpen = false;\n this.activeCommandName = null;\n this.aiModeActive = false;\n this.query = \"\";\n }\n\n enterAiMode(): void {\n this.aiModeActive = true;\n this.query = \"\";\n }\n\n exitAiMode(): void {\n this.aiModeActive = false;\n this.query = \"\";\n }\n\n setQuery(query: string): void {\n this.query = query;\n }\n\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n useCommand(name: string): void {\n const cmd = this.resolvedCommands.find(c => c.name === name);\n if (!cmd) {\n return;\n }\n\n if (cmd.entersAiMode) {\n // A mode replaces the command list and keeps the input row, so the palette stays open.\n this.enterAiMode();\n return;\n }\n\n if (cmd.detailView) {\n this.activeCommandName = name;\n this.isOpen = true;\n return;\n }\n\n cmd.execute?.();\n this.close();\n }\n\n cancelCommand(): void {\n this.activeCommandName = null;\n }\n}\n"],"names":["CommandPalettePresenter","getCommands","makeAutoObservable","keys","cmd","e","activeCmd","c","Boolean","query","name"],"mappings":";AAOO,MAAMA;IAOT,YAAoBC,WAAsC,CAAE;aAAxCA,WAAW,GAAXA;aANZ,MAAM,GAAG;aACT,iBAAiB,GAAkB;aACnC,YAAY,GAAG;aACf,KAAK,GAAG;aACR,gBAAgB,GAAwB,EAAE;QAG9CC,mBAAmB,IAAI;IAC3B;IAEA,OAAa;QACT,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW;IAC5C;IAEA,IAAI,eAA2D;QAC3D,MAAMC,OAAmD,CAAC;QAC1D,KAAK,MAAMC,OAAO,IAAI,CAAC,gBAAgB,CACnC,IAAIA,IAAI,QAAQ,EACZD,IAAI,CAACC,IAAI,QAAQ,CAAC,GAAG,CAACC;YAClBA,EAAE,cAAc;YAChB,IAAI,CAAC,UAAU,CAACD,IAAI,IAAI;QAC5B;QAGR,OAAOD;IACX;IAEA,IAAI,KAA8B;QAC9B,MAAMG,YACF,AAA2B,SAA3B,IAAI,CAAC,iBAAiB,GAChB,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAACC,CAAAA,IAAKA,EAAE,IAAI,KAAK,IAAI,CAAC,iBAAiB,IACjE;QAEV,OAAO;YACH,QAAQ,IAAI,CAAC,MAAM;YACnB,cAAc,IAAI,CAAC,YAAY;YAC/B,OAAO,IAAI,CAAC,KAAK;YACjB,UAAU,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAACH,CAAAA,MAAQ;oBACxC,MAAMA,IAAI,IAAI;oBACd,OAAOA,IAAI,KAAK;oBAChB,aAAaA,IAAI,WAAW;oBAC5B,MAAMA,IAAI,IAAI;oBACd,UAAUA,IAAI,QAAQ;oBACtB,UAAUA,IAAI,QAAQ;oBACtB,UAAUA,IAAI,QAAQ;oBACtB,eAAeI,QAAQJ,IAAI,UAAU;oBACrC,cAAcI,QAAQJ,IAAI,YAAY;gBAC1C;YACA,eACIE,aAAaA,UAAU,UAAU,GAC3B;gBACI,SAASA;gBACT,YAAYA,UAAU,UAAU;YACpC,IACA;QACd;IACJ;IAEA,OAAa;QACT,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW;QACxC,IAAI,CAAC,iBAAiB,GAAG;QACzB,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI,CAAC,KAAK,GAAG;QACb,IAAI,CAAC,MAAM,GAAG;IAClB;IAEA,QAAc;QACV,IAAI,CAAC,MAAM,GAAG;QACd,IAAI,CAAC,iBAAiB,GAAG;QACzB,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI,CAAC,KAAK,GAAG;IACjB;IAEA,cAAoB;QAChB,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI,CAAC,KAAK,GAAG;IACjB;IAEA,aAAmB;QACf,IAAI,CAAC,YAAY,GAAG;QACpB,IAAI,CAAC,KAAK,GAAG;IACjB;IAEA,SAASG,KAAa,EAAQ;QAC1B,IAAI,CAAC,KAAK,GAAGA;IACjB;IAEA,SAAe;QACX,IAAI,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK;aAEV,IAAI,CAAC,IAAI;IAEjB;IAEA,WAAWC,IAAY,EAAQ;QAC3B,MAAMN,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAACG,CAAAA,IAAKA,EAAE,IAAI,KAAKG;QACvD,IAAI,CAACN,KACD;QAGJ,IAAIA,IAAI,YAAY,EAAE,YAElB,IAAI,CAAC,WAAW;QAIpB,IAAIA,IAAI,UAAU,EAAE;YAChB,IAAI,CAAC,iBAAiB,GAAGM;YACzB,IAAI,CAAC,MAAM,GAAG;YACd;QACJ;QAEAN,IAAI,OAAO;QACX,IAAI,CAAC,KAAK;IACd;IAEA,gBAAsB;QAClB,IAAI,CAAC,iBAAiB,GAAG;IAC7B;AACJ"}
|
|
@@ -36,6 +36,8 @@ export interface CommandItemVm {
|
|
|
36
36
|
keywords?: string[];
|
|
37
37
|
shortcut?: string;
|
|
38
38
|
hasDetailView: boolean;
|
|
39
|
+
/** Selecting this switches the palette into AI mode. Lets a caller hide it when AI is off. */
|
|
40
|
+
entersAiMode: boolean;
|
|
39
41
|
}
|
|
40
42
|
export interface ActiveCommandVm {
|
|
41
43
|
command: ICommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/commandPalette/abstractions.js","sources":["../../../src/presentation/commandPalette/abstractions.ts"],"sourcesContent":["import type React from \"react\";\nimport { createAbstraction } from \"@webiny/feature/admin\";\nimport { Abstraction } from \"@webiny/di\";\n\nexport interface CommandDetailProps {\n command: ICommand;\n onClose: () => void;\n onBack: () => void;\n}\n\n/**\n * A command registered with the command palette via dependency injection. Register an\n * implementation with `Command.createImplementation(...)` and add it to the container;\n * the palette resolves all of them with `container.resolveAll(Command)`.\n */\nexport interface ICommand {\n name: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n category?: string;\n keywords?: string[];\n /* Global hotkey (is-hotkey syntax, e.g. \"cmd+shift+m\") that runs this command. */\n shortcut?: string;\n /* Omitted by a command that only selects a mode; there is no action to run. */\n execute?(params?: unknown): void | Promise<void>;\n /* Optional React view rendered inside the palette when the command is selected. */\n detailView?: React.ComponentType<CommandDetailProps>;\n /*\n * Selecting this command switches the palette into AI mode rather than doing something. A mode\n * needs the shared input row, so the palette stays open and `execute` is never called.\n *\n * Named after the one mode that exists. If a second one ever arrives, this becomes\n * `entersMode: \"
|
|
1
|
+
{"version":3,"file":"presentation/commandPalette/abstractions.js","sources":["../../../src/presentation/commandPalette/abstractions.ts"],"sourcesContent":["import type React from \"react\";\nimport { createAbstraction } from \"@webiny/feature/admin\";\nimport { Abstraction } from \"@webiny/di\";\n\nexport interface CommandDetailProps {\n command: ICommand;\n onClose: () => void;\n onBack: () => void;\n}\n\n/**\n * A command registered with the command palette via dependency injection. Register an\n * implementation with `Command.createImplementation(...)` and add it to the container;\n * the palette resolves all of them with `container.resolveAll(Command)`.\n */\nexport interface ICommand {\n name: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n category?: string;\n keywords?: string[];\n /* Global hotkey (is-hotkey syntax, e.g. \"cmd+shift+m\") that runs this command. */\n shortcut?: string;\n /* Omitted by a command that only selects a mode; there is no action to run. */\n execute?(params?: unknown): void | Promise<void>;\n /* Optional React view rendered inside the palette when the command is selected. */\n detailView?: React.ComponentType<CommandDetailProps>;\n /*\n * Selecting this command switches the palette into AI mode rather than doing something. A mode\n * needs the shared input row, so the palette stays open and `execute` is never called.\n *\n * Named after the one mode that exists. If a second one ever arrives, this becomes\n * `entersMode: \"adminAssistant\"` and the palette looks the mode up by name instead of hardcoding it.\n */\n entersAiMode?: boolean;\n}\n\nexport const Command = createAbstraction<ICommand>(\"Command\");\n\nexport namespace Command {\n export type Interface = ICommand;\n export type DetailProps = CommandDetailProps;\n}\n\nexport interface CommandItemVm {\n name: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n category?: string;\n keywords?: string[];\n shortcut?: string;\n hasDetailView: boolean;\n /** Selecting this switches the palette into AI mode. Lets a caller hide it when AI is off. */\n entersAiMode: boolean;\n}\n\nexport interface ActiveCommandVm {\n command: ICommand;\n DetailView: React.ComponentType<CommandDetailProps>;\n}\n\nexport interface CommandPaletteViewModel {\n isOpen: boolean;\n /**\n * A mode is showing instead of the command list. The palette keeps ONE input row across every\n * mode, so this is the palette's state rather than the mode's.\n */\n aiModeActive: boolean;\n /**\n * What the user has typed. Owned here rather than by the component because it is cleared\n * whenever the palette opens, closes, or enters or leaves a mode.\n */\n query: string;\n commands: CommandItemVm[];\n activeCommand: ActiveCommandVm | null;\n}\n\nexport interface ICommandPalettePresenter {\n vm: CommandPaletteViewModel;\n shortcutKeys: Record<string, (e: KeyboardEvent) => void>;\n init(): void;\n open(): void;\n close(): void;\n toggle(): void;\n useCommand(name: string): void;\n cancelCommand(): void;\n enterAiMode(): void;\n exitAiMode(): void;\n setQuery(query: string): void;\n}\n\nexport const CommandPalettePresenter = new Abstraction<ICommandPalettePresenter>(\n \"CommandPalettePresenter\"\n);\n\nexport namespace CommandPalettePresenter {\n export type Interface = ICommandPalettePresenter;\n export type ViewModel = CommandPaletteViewModel;\n}\n"],"names":["Command","createAbstraction","CommandPalettePresenter","Abstraction"],"mappings":";;AAsCO,MAAMA,UAAUC,kBAA4B;AAuD5C,MAAMC,0BAA0B,IAAIC,YACvC"}
|
|
@@ -6,7 +6,7 @@ class AskAiCommandImpl {
|
|
|
6
6
|
constructor(){
|
|
7
7
|
this.name = "admin.ai.ask";
|
|
8
8
|
this.label = "Ask AI";
|
|
9
|
-
this.description = "Ask about
|
|
9
|
+
this.description = "Ask about this project, or ask for a change, in plain language";
|
|
10
10
|
this.category = "Assistant";
|
|
11
11
|
this.keywords = [
|
|
12
12
|
"ai",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presentation/commandPalette/commands/AskAiCommand.js","sources":["../../../../src/presentation/commandPalette/commands/AskAiCommand.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { ReactComponent as AiIcon } from \"@webiny/icons/auto_awesome.svg\";\nimport { Command } from \"../abstractions.js\";\n\n/**\n * Discoverable entry point for the palette's AI mode.\n *\n * `entersAiMode` rather than `execute`: the design keeps one input row across every mode, so selecting\n * this switches the palette instead of running an action, and the palette stays open. A command\n * without a `detailView` is otherwise executed and then closed, which a mode cannot survive.\n *\n * It exists as a command at all so it stays searchable (\"ai\", \"ask\", \"assistant\") for people who\n * never learn the space shortcut.\n */\nclass AskAiCommandImpl implements Command.Interface {\n name = \"admin.ai.ask\";\n label = \"Ask AI\";\n description = \"Ask about
|
|
1
|
+
{"version":3,"file":"presentation/commandPalette/commands/AskAiCommand.js","sources":["../../../../src/presentation/commandPalette/commands/AskAiCommand.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon } from \"@webiny/admin-ui\";\nimport { ReactComponent as AiIcon } from \"@webiny/icons/auto_awesome.svg\";\nimport { Command } from \"../abstractions.js\";\n\n/**\n * Discoverable entry point for the palette's AI mode.\n *\n * `entersAiMode` rather than `execute`: the design keeps one input row across every mode, so selecting\n * this switches the palette instead of running an action, and the palette stays open. A command\n * without a `detailView` is otherwise executed and then closed, which a mode cannot survive.\n *\n * It exists as a command at all so it stays searchable (\"ai\", \"ask\", \"assistant\") for people who\n * never learn the space shortcut.\n */\nclass AskAiCommandImpl implements Command.Interface {\n name = \"admin.ai.ask\";\n label = \"Ask AI\";\n description = \"Ask about this project, or ask for a change, in plain language\";\n category = \"Assistant\";\n keywords = [\"ai\", \"ask\", \"assistant\", \"chat\", \"search\"];\n icon = <Icon icon={<AiIcon />} size=\"sm\" color=\"neutral-strong\" label=\"\" />;\n entersAiMode = true;\n}\n\nexport const AskAiCommand = Command.createImplementation({\n implementation: AskAiCommandImpl,\n dependencies: []\n});\n"],"names":["AskAiCommandImpl","Icon","AiIcon","AskAiCommand","Command"],"mappings":";;;;AAeA,MAAMA;;aACF,IAAI,GAAG;aACP,KAAK,GAAG;aACR,WAAW,GAAG;aACd,QAAQ,GAAG;aACX,QAAQ,GAAG;YAAC;YAAM;YAAO;YAAa;YAAQ;SAAS;aACvD,IAAI,GAAG,WAAP,GAAO,oBAACC,MAAIA;YAAC,oBAAM,oBAACC,gBAAMA;YAAK,MAAK;YAAK,OAAM;YAAiB,OAAM;;aACtE,YAAY,GAAG;;AACnB;AAEO,MAAMC,eAAeC,QAAQ,oBAAoB,CAAC;IACrD,gBAAgBJ;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/aiChat/AiChatGateway.js","sources":["../../../src/features/aiChat/AiChatGateway.ts"],"sourcesContent":["import { ApiStreamClient } from \"@webiny/app/features/apiStreamClient\";\nimport { readServerSentEvents } from \"@webiny/app/features/apiStreamClient\";\nimport { EnvConfig } from \"@webiny/app/features/envConfig\";\nimport { AiChatGateway as Abstraction } from \"./abstractions.js\";\nimport type { AiChatRequest } from \"./abstractions.js\";\nimport type { AiChatStreamEvent } from \"./abstractions.js\";\nimport { AuthenticationContext } from \"~/features/security/AuthenticationContext/index.js\";\nimport { TenantContext } from \"~/features/tenancy/abstractions.js\";\n\n/*\n * The `/stream/` prefix is required, not cosmetic: it is the CloudFront behavior that targets the\n * Lambda Function URL. Any other path lands on API Gateway and gets buffered.\n */\nconst CHAT_STREAM_PATH = \"/stream/ai/chat\";\n\nconst toBody = (request: AiChatRequest): Record<string, unknown> => {\n const body: Record<string, unknown> = { messages: request.messages };\n\n if (request.approvals?.length) {\n body[\"approvals\"] = request.approvals;\n }\n\n return body;\n};\n\n/**\n * Talks to the API app's chat routes.\n *\n * Streaming goes through `ApiStreamClient`, so auth and tenant headers come from the platform's own\n * decorators — including `x-webiny-authorization`, which the streaming path needs because on AWS\n * SigV4 occupies `Authorization`. Getting that wrong would silently make every streamed request\n * anonymous.\n *\n * The buffered call still uses `fetch`: `ApiStreamClient` hands back an unread `Response` for a caller\n * that owns a read loop, which is the wrong shape for a single JSON answer.\n */\nclass AiChatGatewayImpl implements Abstraction.Interface {\n constructor(\n private authContext: AuthenticationContext.Interface,\n private envConfig: EnvConfig.Interface,\n private tenantContext: TenantContext.Interface,\n private streamClient: ApiStreamClient.Interface\n ) {}\n\n async *stream(request: AiChatRequest, signal?: AbortSignal): AsyncIterable<AiChatStreamEvent> {\n const response = await this.streamClient.execute({\n path: CHAT_STREAM_PATH,\n body: toBody(request),\n signal\n });\n\n yield* readServerSentEvents<AiChatStreamEvent>(response);\n }\n}\n\nexport const AiChatGateway = Abstraction.createImplementation({\n implementation: AiChatGatewayImpl,\n dependencies: [AuthenticationContext, EnvConfig, TenantContext, ApiStreamClient]\n});\n"],"names":["CHAT_STREAM_PATH","toBody","request","body","AiChatGatewayImpl","authContext","envConfig","tenantContext","streamClient","signal","response","readServerSentEvents","AiChatGateway","Abstraction","AuthenticationContext","EnvConfig","TenantContext","ApiStreamClient"],"mappings":";;;;;AAaA,MAAMA,mBAAmB;AAEzB,MAAMC,SAAS,CAACC;IACZ,MAAMC,OAAgC;QAAE,UAAUD,QAAQ,QAAQ;IAAC;IAEnE,IAAIA,QAAQ,SAAS,EAAE,QACnBC,IAAI,CAAC,YAAY,GAAGD,QAAQ,SAAS;IAGzC,OAAOC;AACX;AAaA,MAAMC;IACF,YACYC,WAA4C,EAC5CC,SAA8B,EAC9BC,aAAsC,EACtCC,YAAuC,CACjD;aAJUH,WAAW,GAAXA;aACAC,SAAS,GAATA;aACAC,aAAa,GAAbA;aACAC,YAAY,GAAZA;IACT;IAEH,OAAO,OAAON,OAAsB,EAAEO,MAAoB,EAAoC;QAC1F,MAAMC,WAAW,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAC7C,MAAMV;YACN,MAAMC,OAAOC;YACbO;QACJ;QAEA,OAAOE,qBAAwCD;IACnD;AACJ;AAEO,MAAME,8BAAgBC,cAAAA,oBAAgC,CAAC;IAC1D,gBAAgBT;IAChB,cAAc;QAACU;QAAuBC;QAAWC;QAAeC;KAAgB;AACpF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/aiChat/AiChatPresenter.js","sources":["../../../src/features/aiChat/AiChatPresenter.ts"],"sourcesContent":["import { makeAutoObservable } from \"mobx\";\nimport { AiChatGateway } from \"./abstractions.js\";\nimport type { AiChatMessage, AiChatRequest } from \"./abstractions.js\";\nimport {\n AiChatPresenter as Abstraction,\n type AiTurnViewModel,\n type IAiChatViewModel\n} from \"./abstractions.js\";\n\n/** A turn plus the conversation state the view never sees. */\ninterface Turn extends AiTurnViewModel {\n /** Server messages replayed to continue this conversation or resume its approval. */\n messages: AiChatMessage[];\n}\n\nconst emptyTurn = (question: string): Turn => ({\n question,\n text: \"\",\n tools: [],\n completed: [],\n failed: [],\n running: false,\n pendingApprovals: [],\n messages: [],\n settled: false\n});\n\n/**\n * Owns the palette's AI conversation.\n *\n * A presenter rather than component state: several pieces change together, a network stream drives\n * them, and an abort has to outlive any one render.\n *\n * Registered as a singleton, so `reset` genuinely clears rather than relying on unmount.\n */\nclass AiChatPresenterImpl implements Abstraction.Interface {\n private turns: Turn[] = [];\n private busy = false;\n private controller: AbortController | null = null;\n\n constructor(private gateway: AiChatGateway.Interface) {\n // The controller is machinery, not state anything renders, so keep it out of the map.\n makeAutoObservable<AiChatPresenterImpl, \"controller\">(this, { controller: false });\n }\n\n get vm(): IAiChatViewModel {\n return {\n busy: this.busy,\n turns: this.turns.map(turn => ({\n question: turn.question,\n text: turn.text,\n tools: turn.tools,\n completed: turn.completed,\n failed: turn.failed,\n running: turn.running,\n pendingApprovals: turn.pendingApprovals,\n settled: turn.settled,\n ...(turn.error === undefined ? {} : { error: turn.error })\n }))\n };\n }\n\n ask(question: string): void {\n const trimmed = question.trim();\n\n if (!trimmed || this.busy) {\n return;\n }\n\n const index = this.turns.length;\n this.addTurn(trimmed);\n\n void this.run(index, {\n messages: [...this.historyBefore(index), { role: \"user\", content: trimmed }]\n });\n }\n\n decide(turnIndex: number, approved: boolean): void {\n const turn = this.turns[turnIndex];\n\n if (!turn?.pendingApprovals.length || this.busy) {\n return;\n }\n\n const approvals = turn.pendingApprovals.map(approval => ({\n approvalId: approval.approvalId,\n approved\n }));\n\n /*\n * The paused assistant message must be replayed unchanged: the approval request lives only in\n * the server's messages, so resuming means sending the same history back plus the decision.\n */\n const messages: AiChatMessage[] = [\n ...this.historyBefore(turnIndex),\n { role: \"user\", content: turn.question },\n ...turn.messages\n ];\n\n // Clear the block immediately so the plan cannot be submitted twice.\n this.patch(turnIndex, { pendingApprovals: [], settled: false, running: true });\n\n void this.run(turnIndex, { messages, approvals }, true);\n }\n\n reset(): void {\n this.controller?.abort();\n this.controller = null;\n this.clear();\n }\n\n /** Replays settled turns so a follow-up (\"and which of those is cheapest?\") has context. */\n private historyBefore(upTo: number): AiChatMessage[] {\n const history: AiChatMessage[] = [];\n\n for (const turn of this.turns.slice(0, upTo)) {\n if (!turn.settled || turn.error) {\n continue;\n }\n history.push({ role: \"user\", content: turn.question });\n history.push(...turn.messages);\n }\n\n return history;\n }\n\n private async run(index: number, request: AiChatRequest, resuming = false): Promise<void> {\n this.controller?.abort();\n const controller = new AbortController();\n this.controller = controller;\n\n this.setBusy(true);\n\n try {\n /*\n * Resuming continues the same turn: the tools already called, the text already shown and\n * the messages already collected all still belong to it. Starting from empty would strand\n * earlier chips as running and, worse, drop the assistant message carrying the `tool_use`\n * that the replayed `tool_result` refers to.\n */\n const existing = resuming ? this.turns[index] : undefined;\n let text = existing?.text ?? \"\";\n const tools: string[] = existing ? [...existing.tools] : [];\n const completed: string[] = existing ? [...existing.completed] : [];\n const failed: string[] = existing ? [...existing.failed] : [];\n const priorMessages: AiChatMessage[] = existing ? [...existing.messages] : [];\n\n for await (const event of this.gateway.stream(request, controller.signal)) {\n if (event.type === \"text\") {\n text += event.text;\n this.patch(index, { text, running: false });\n continue;\n }\n\n if (event.type === \"tool-call\") {\n tools.push(event.name);\n this.patch(index, { tools: [...tools], running: true });\n continue;\n }\n\n if (event.type === \"tool-result\") {\n completed.push(event.name);\n this.patch(index, { completed: [...completed] });\n continue;\n }\n\n if (event.type === \"tool-error\") {\n failed.push(event.name);\n this.patch(index, { failed: [...failed] });\n continue;\n }\n\n if (event.type === \"approval\") {\n this.patch(index, { pendingApprovals: event.approvals, running: false });\n continue;\n }\n\n if (event.type === \"done\") {\n this.patch(index, {\n messages: [...priorMessages, ...event.messages],\n settled: true,\n running: false\n });\n continue;\n }\n\n if (event.type === \"error\") {\n this.patch(index, { error: event.message, settled: true, running: false });\n return;\n }\n }\n } catch (error) {\n // An abort is the palette closing, not a failure worth showing.\n if (!controller.signal.aborted) {\n this.patch(index, {\n error: error instanceof Error ? error.message : String(error),\n settled: true,\n running: false\n });\n }\n } finally {\n this.setBusy(false);\n }\n }\n\n /*\n * Every mutation below is its own method on purpose. `run` awaits, and a mutation after an await\n * has escaped the action it started in; `makeAutoObservable` makes these methods actions, so\n * calling them from there is correct.\n */\n private addTurn(question: string): void {\n this.turns = [...this.turns, { ...emptyTurn(question), running: true }];\n }\n\n private patch(index: number, change: Partial<Turn>): void {\n this.turns = this.turns.map((turn, i) => (i === index ? { ...turn, ...change } : turn));\n }\n\n private setBusy(busy: boolean): void {\n this.busy = busy;\n }\n\n private clear(): void {\n this.turns = [];\n this.busy = false;\n }\n}\n\nexport const AiChatPresenter = Abstraction.createImplementation({\n implementation: AiChatPresenterImpl,\n dependencies: [AiChatGateway]\n});\n"],"names":["emptyTurn","question","AiChatPresenterImpl","gateway","makeAutoObservable","turn","undefined","trimmed","index","turnIndex","approved","approvals","approval","messages","upTo","history","request","resuming","controller","AbortController","existing","text","tools","completed","failed","priorMessages","event","error","Error","String","change","i","busy","AiChatPresenter","Abstraction","AiChatGateway"],"mappings":"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"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { createAbstraction } from "@webiny/feature/admin";
|
|
2
|
-
const AiChatGateway = createAbstraction("AiChatGateway");
|
|
3
|
-
const AiChatPresenter = createAbstraction("AiChatPresenter");
|
|
4
|
-
export { AiChatGateway, AiChatPresenter };
|
|
5
|
-
|
|
6
|
-
//# sourceMappingURL=abstractions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/aiChat/abstractions.js","sources":["../../../src/features/aiChat/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\n\n/**\n * Messages are opaque here on purpose. Beyond plain user/assistant turns the server also returns\n * assistant and tool messages carrying approval requests, which must be replayed VERBATIM for the\n * agent loop to resume — the request exists nowhere else, since the server keeps no session.\n */\nexport type AiChatMessage = { role: string; content: unknown };\n\n/** A tool the assistant invoked, so the UI can show its work rather than just an answer. */\nexport interface AiChatToolCall {\n name: string;\n input: unknown;\n}\n\n/** A tool call the assistant wants to make but has not made, because it changes something. */\nexport interface AiChatPendingApproval {\n approvalId: string;\n toolName: string;\n title?: string;\n input: unknown;\n /** The tool declared itself destructive — the UI should say so more loudly. */\n destructive: boolean;\n}\n\nexport interface AiChatDecision {\n approvalId: string;\n approved: boolean;\n reason?: string;\n}\n\nexport interface AiChatRequest {\n messages: AiChatMessage[];\n /** Approve or reject calls the server paused on. */\n approvals?: AiChatDecision[];\n}\n\n/**\n * What the assistant emits while it works. Mirrors the server's `AiChatEvent`; declared here so the\n * admin bundle carries no server or AI SDK code.\n */\nexport type AiChatStreamEvent =\n | { type: \"text\"; text: string }\n | { type: \"tool-call\"; name: string }\n | { type: \"tool-result\"; name: string }\n // A tool threw. Pairs with `tool-call` by name, and does not end the run.\n | { type: \"tool-error\"; name: string; message: string }\n | { type: \"approval\"; approvals: AiChatPendingApproval[] }\n | { type: \"done\"; messages: AiChatMessage[]; steps: number }\n | { type: \"error\"; message: string };\n\nexport interface IAiChatGateway {\n /**\n * Run and yield progress as it arrives. Preferred in the UI: a multi-tool question takes tens of\n * seconds, and an approval request is worth showing the moment it appears.\n */\n stream(request: AiChatRequest, signal?: AbortSignal): AsyncIterable<AiChatStreamEvent>;\n}\n\n/** Sends a question to the server-side AI assistant (`POST /ai/chat`). */\nexport const AiChatGateway = createAbstraction<IAiChatGateway>(\"AiChatGateway\");\n\nexport namespace AiChatGateway {\n export type Interface = IAiChatGateway;\n export type Message = AiChatMessage;\n export type ToolCall = AiChatToolCall;\n export type PendingApproval = AiChatPendingApproval;\n export type Decision = AiChatDecision;\n export type Request = AiChatRequest;\n export type StreamEvent = AiChatStreamEvent;\n}\n\n/**\n * One question and the answer to it, as the view needs it.\n *\n * The server messages that make a follow-up or a resumed approval work are deliberately absent: they\n * are conversation state, not something rendered, so they stay inside the presenter.\n */\nexport interface AiTurnViewModel {\n question: string;\n /** Answer text so far. Grows as the stream arrives. */\n text: string;\n /** Tools called this turn, in call order. */\n tools: string[];\n /**\n * Tools that returned. A call pending approval still emits `tool-call`, so this is the only way\n * to tell a completed tool from one merely proposed.\n */\n completed: string[];\n /** Tools that threw. Settles the chip as a failure; the run continues. */\n failed: string[];\n /** Set while a tool is running and no answer text has arrived yet. */\n running: boolean;\n pendingApprovals: AiChatPendingApproval[];\n settled: boolean;\n error?: string;\n}\n\nexport interface IAiChatViewModel {\n turns: AiTurnViewModel[];\n /** A run is in flight. Asking again or deciding again is refused while true. */\n busy: boolean;\n}\n\nexport interface IAiChatPresenter {\n readonly vm: IAiChatViewModel;\n /** Ask a question, carrying the settled turns before it as context. */\n ask(question: string): void;\n /** Approve or reject the calls a turn paused on, then resume it. */\n decide(turnIndex: number, approved: boolean): void;\n /** Drop the conversation and stop anything in flight. */\n reset(): void;\n}\n\nexport const AiChatPresenter = createAbstraction<IAiChatPresenter>(\"AiChatPresenter\");\n\nexport namespace AiChatPresenter {\n export type Interface = IAiChatPresenter;\n export type ViewModel = IAiChatViewModel;\n export type Turn = AiTurnViewModel;\n}\n"],"names":["AiChatGateway","createAbstraction","AiChatPresenter"],"mappings":";AA4DO,MAAMA,gBAAgBC,kBAAkC;AAsDxD,MAAMC,kBAAkBD,kBAAoC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { createFeature } from "@webiny/feature/admin";
|
|
2
|
-
import { AiChatGateway } from "./AiChatGateway.js";
|
|
3
|
-
import { AiChatPresenter } from "./AiChatPresenter.js";
|
|
4
|
-
import { AiChatPresenter as external_abstractions_js_AiChatPresenter } from "./abstractions.js";
|
|
5
|
-
const AiChatFeature = createFeature({
|
|
6
|
-
name: "AiChat",
|
|
7
|
-
register (container) {
|
|
8
|
-
container.register(AiChatGateway);
|
|
9
|
-
container.register(AiChatPresenter).inSingletonScope();
|
|
10
|
-
},
|
|
11
|
-
resolve (container) {
|
|
12
|
-
return {
|
|
13
|
-
presenter: container.resolve(external_abstractions_js_AiChatPresenter)
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
export { AiChatFeature };
|
|
18
|
-
|
|
19
|
-
//# sourceMappingURL=feature.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"features/aiChat/feature.js","sources":["../../../src/features/aiChat/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/admin\";\nimport { AiChatGateway } from \"./AiChatGateway.js\";\nimport { AiChatPresenter } from \"./AiChatPresenter.js\";\nimport { AiChatPresenter as Abstraction } from \"./abstractions.js\";\n\nexport const AiChatFeature = createFeature({\n name: \"AiChat\",\n register(container) {\n container.register(AiChatGateway);\n // Singleton so the conversation survives re-renders of the palette that reads it.\n container.register(AiChatPresenter).inSingletonScope();\n },\n resolve(container) {\n return { presenter: container.resolve(Abstraction) };\n }\n});\n"],"names":["AiChatFeature","createFeature","container","AiChatGateway","AiChatPresenter","Abstraction"],"mappings":";;;;AAKO,MAAMA,gBAAgBC,cAAc;IACvC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;QAEnBD,UAAU,QAAQ,CAACE,iBAAiB,gBAAgB;IACxD;IACA,SAAQF,SAAS;QACb,OAAO;YAAE,WAAWA,UAAU,OAAO,CAACG;QAAa;IACvD;AACJ"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { AiChatGateway } from "./abstractions.js";
|
|
2
|
-
export type { IAiChatGateway, AiChatMessage, AiChatToolCall, AiChatPendingApproval, AiChatDecision, AiChatRequest, AiChatStreamEvent } from "./abstractions.js";
|
|
3
|
-
export { AiChatGateway as AiChatGatewayImplementation } from "./AiChatGateway.js";
|
|
4
|
-
export { AiChatFeature } from "./feature.js";
|
|
5
|
-
export { AiChatPresenter } from "./abstractions.js";
|
|
6
|
-
export type { AiTurnViewModel, IAiChatPresenter, IAiChatViewModel } from "./abstractions.js";
|
package/features/aiChat/index.js
DELETED