@synergenius/flow-weaver-pack-weaver 0.9.134 → 0.9.136
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/bot/ai-client.d.ts +9 -0
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +59 -0
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/behavior-defaults.d.ts +4 -0
- package/dist/bot/behavior-defaults.d.ts.map +1 -1
- package/dist/bot/behavior-defaults.js +17 -0
- package/dist/bot/behavior-defaults.js.map +1 -1
- package/dist/bot/capability-registry.d.ts +20 -0
- package/dist/bot/capability-registry.d.ts.map +1 -0
- package/dist/bot/capability-registry.js +205 -0
- package/dist/bot/capability-registry.js.map +1 -0
- package/dist/bot/capability-types.d.ts +23 -0
- package/dist/bot/capability-types.d.ts.map +1 -0
- package/dist/bot/capability-types.js +9 -0
- package/dist/bot/capability-types.js.map +1 -0
- package/dist/bot/estimate-tokens.d.ts +12 -0
- package/dist/bot/estimate-tokens.d.ts.map +1 -0
- package/dist/bot/estimate-tokens.js +18 -0
- package/dist/bot/estimate-tokens.js.map +1 -0
- package/dist/bot/profile-types.d.ts +4 -0
- package/dist/bot/profile-types.d.ts.map +1 -1
- package/dist/bot/system-prompt.d.ts +11 -0
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +31 -0
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/types.d.ts +1 -0
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +49 -45
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/ui/capability-editor.js +657 -0
- package/dist/ui/profile-card.js +25 -0
- package/dist/ui/profile-editor.js +615 -316
- package/dist/ui/swarm-dashboard.js +643 -319
- package/flowweaver.manifest.json +1 -1
- package/package.json +2 -2
- package/src/bot/ai-client.ts +75 -0
- package/src/bot/behavior-defaults.ts +20 -0
- package/src/bot/capability-registry.ts +230 -0
- package/src/bot/capability-types.ts +23 -0
- package/src/bot/estimate-tokens.ts +16 -0
- package/src/bot/profile-types.ts +4 -0
- package/src/bot/system-prompt.ts +33 -0
- package/src/bot/types.ts +1 -0
- package/src/node-types/plan-task.ts +51 -44
- package/src/ui/capability-editor.tsx +420 -0
- package/src/ui/profile-card.tsx +20 -0
- package/src/ui/profile-editor.tsx +100 -6
|
@@ -2318,6 +2318,31 @@ function ProfileCard({ profile, activeInstances, onEdit, onDelete }) {
|
|
|
2318
2318
|
)
|
|
2319
2319
|
)
|
|
2320
2320
|
),
|
|
2321
|
+
// Knowledge capabilities (from behavior)
|
|
2322
|
+
behavior?.capabilities && behavior.capabilities.length > 0 && React8.createElement(
|
|
2323
|
+
Field2,
|
|
2324
|
+
{ label: "Knowledge", labelWidth: 90, align: "start" },
|
|
2325
|
+
React8.createElement(
|
|
2326
|
+
Flex7,
|
|
2327
|
+
{ variant: "row-center-start-wrap-4" },
|
|
2328
|
+
...behavior.capabilities.map(
|
|
2329
|
+
(capName) => React8.createElement(
|
|
2330
|
+
"span",
|
|
2331
|
+
{ key: capName },
|
|
2332
|
+
React8.createElement(Chip4, { label: capName, size: "small", color: "color-status-info" })
|
|
2333
|
+
)
|
|
2334
|
+
)
|
|
2335
|
+
)
|
|
2336
|
+
),
|
|
2337
|
+
// Budget (from behavior)
|
|
2338
|
+
behavior?.budget && React8.createElement(
|
|
2339
|
+
Field2,
|
|
2340
|
+
{ label: "Budget", labelWidth: 90, align: "center" },
|
|
2341
|
+
React8.createElement(Typography7, {
|
|
2342
|
+
variant: "smallCaption-regular",
|
|
2343
|
+
color: "color-text-high"
|
|
2344
|
+
}, `$${behavior.budget.toFixed(2)}/task`)
|
|
2345
|
+
),
|
|
2321
2346
|
// Strategy
|
|
2322
2347
|
React8.createElement(
|
|
2323
2348
|
Field2,
|
|
@@ -2637,6 +2662,205 @@ var BOT_COLORS = [
|
|
|
2637
2662
|
{ label: "Info", token: "color-status-info" }
|
|
2638
2663
|
];
|
|
2639
2664
|
|
|
2665
|
+
// src/bot/operations.ts
|
|
2666
|
+
var OP_WRITE_FILE = "write_file";
|
|
2667
|
+
var OP_READ_FILE = "read_file";
|
|
2668
|
+
var OP_PATCH_FILE = "patch_file";
|
|
2669
|
+
var OP_LIST_FILES = "list_files";
|
|
2670
|
+
var OP_RUN_SHELL = "run_shell";
|
|
2671
|
+
var OP_VALIDATE = "validate";
|
|
2672
|
+
var OP_TSC_CHECK = "tsc_check";
|
|
2673
|
+
var OP_RUN_TESTS = "run_tests";
|
|
2674
|
+
var OP_TASK_CREATE = "task_create";
|
|
2675
|
+
|
|
2676
|
+
// src/bot/capability-registry.ts
|
|
2677
|
+
var CAP_CORE = {
|
|
2678
|
+
name: "core",
|
|
2679
|
+
description: "Bot identity, structured plan output format, and safety rules. Always loaded.",
|
|
2680
|
+
prompt: `You are Weaver, an expert AI companion for Flow Weaver workflows.
|
|
2681
|
+
|
|
2682
|
+
## Plan Format
|
|
2683
|
+
Your plans MUST be structured JSON with concrete steps.
|
|
2684
|
+
Each step has: operation (tool name), description (what it does), args (complete arguments).
|
|
2685
|
+
Do NOT describe what you would do \u2014 actually do it by calling tools.
|
|
2686
|
+
|
|
2687
|
+
## Safety Rules
|
|
2688
|
+
- Writes that shrink a file by >50% or write empty content are automatically BLOCKED.
|
|
2689
|
+
- Blocked shell commands: rm -rf, git push, npm publish, sudo, curl|sh.
|
|
2690
|
+
- Always validate BEFORE and AFTER patching.
|
|
2691
|
+
- Always read a file before patching it (you need exact strings for find/replace).
|
|
2692
|
+
- Use patch_file for modifications, write_file only for new files.
|
|
2693
|
+
- Be concise \u2014 let tool results speak.`
|
|
2694
|
+
};
|
|
2695
|
+
var CAP_FILE_OPS = {
|
|
2696
|
+
name: "file-ops",
|
|
2697
|
+
description: "File read/write/patch operations and best practices for file manipulation.",
|
|
2698
|
+
tools: [OP_READ_FILE, OP_WRITE_FILE, OP_PATCH_FILE, OP_LIST_FILES],
|
|
2699
|
+
prompt: `## File Operations
|
|
2700
|
+
- read_file: Read a file and return its content. args: { file }
|
|
2701
|
+
- write_file: Write a file. args: { file, content }. Content must be the COMPLETE file.
|
|
2702
|
+
- patch_file: Surgical find-and-replace edits. args: { file, patches: [{ find: "old text", replace: "new text" }] }. PREFERRED for modifying existing files.
|
|
2703
|
+
- list_files: List files in a directory. args: { directory, pattern? } (pattern is regex)
|
|
2704
|
+
|
|
2705
|
+
## Best Practices
|
|
2706
|
+
PREFER patch_file over write_file for modifying existing files (surgical edits, no truncation risk).
|
|
2707
|
+
Use read_file to understand a file before modifying it.
|
|
2708
|
+
Use list_files to discover project structure.
|
|
2709
|
+
Writes that shrink a file by >50% or write empty content are automatically BLOCKED.`
|
|
2710
|
+
};
|
|
2711
|
+
var CAP_SHELL = {
|
|
2712
|
+
name: "shell",
|
|
2713
|
+
description: "Shell command execution for running tests, builds, and inspecting output.",
|
|
2714
|
+
tools: [OP_RUN_SHELL, OP_VALIDATE, OP_TSC_CHECK, OP_RUN_TESTS],
|
|
2715
|
+
prompt: `## Shell Commands
|
|
2716
|
+
- run_shell: Execute a shell command and return output. args: { command }
|
|
2717
|
+
Use for: npx vitest, git status, grep, find, etc.
|
|
2718
|
+
Examples: { "command": "npx vitest run --reporter verbose" }, { "command": "npx flow-weaver validate src/workflow.ts --json" }
|
|
2719
|
+
Blocked: rm -rf, git push, npm publish, sudo, curl|sh (safety policy).
|
|
2720
|
+
Use run_shell for running tests (npx vitest), validation (flow-weaver validate), and inspecting output.`
|
|
2721
|
+
};
|
|
2722
|
+
var CAP_TASK_MGMT = {
|
|
2723
|
+
name: "task-mgmt",
|
|
2724
|
+
description: "Create and manage swarm subtasks for parallel execution.",
|
|
2725
|
+
tools: [OP_TASK_CREATE],
|
|
2726
|
+
prompt: `## Task Management
|
|
2727
|
+
- task_create: Create swarm subtasks for parallel execution. args: { title, description, complexity, subtasks[] }
|
|
2728
|
+
- task_list, task_get, task_update: Query and update existing tasks
|
|
2729
|
+
|
|
2730
|
+
Use task_create to decompose complex work into smaller, independent subtasks that other bots can execute in parallel.`
|
|
2731
|
+
};
|
|
2732
|
+
var CAP_FW_GRAMMAR = {
|
|
2733
|
+
name: "fw-grammar",
|
|
2734
|
+
description: "Flow Weaver annotation syntax, node types, workflows, patterns, and data flow.",
|
|
2735
|
+
prompt: `## Core Mental Model
|
|
2736
|
+
|
|
2737
|
+
The code IS the workflow. Flow Weaver workflows are plain TypeScript files with JSDoc annotations above functions. The compiler reads annotations and generates deterministic execution code between @flow-weaver-body-start/end markers. Compiled code is standalone with no runtime dependency on flow-weaver.
|
|
2738
|
+
|
|
2739
|
+
Three block types:
|
|
2740
|
+
- @flowWeaver nodeType: A reusable function (node) with typed inputs/outputs
|
|
2741
|
+
- @flowWeaver workflow: A DAG orchestration that wires node instances together
|
|
2742
|
+
- @flowWeaver pattern: A reusable fragment with boundary ports (IN/OUT instead of Start/Exit)
|
|
2743
|
+
|
|
2744
|
+
## Node Execution Model
|
|
2745
|
+
|
|
2746
|
+
Expression nodes (@expression):
|
|
2747
|
+
- No execute/onSuccess/onFailure params. Just inputs and return value.
|
|
2748
|
+
- throw = failure path, return = success path
|
|
2749
|
+
- Synchronous. Use execSync for shell commands.
|
|
2750
|
+
- Preferred for deterministic operations.
|
|
2751
|
+
|
|
2752
|
+
Standard nodes:
|
|
2753
|
+
- execute: boolean param gates execution
|
|
2754
|
+
- Return { onSuccess: boolean, onFailure: boolean, ...outputs }
|
|
2755
|
+
- Can be async for I/O operations
|
|
2756
|
+
|
|
2757
|
+
Async agent nodes:
|
|
2758
|
+
- Use (globalThis as any).__fw_agent_channel__ to pause workflow
|
|
2759
|
+
- Call channel.request({ agentId, context, prompt }) which returns a Promise
|
|
2760
|
+
- Workflow suspends until agent responds
|
|
2761
|
+
- NOT @expression (must be async)
|
|
2762
|
+
|
|
2763
|
+
Pass-through pattern:
|
|
2764
|
+
- FW auto-connects ports by matching names on adjacent nodes
|
|
2765
|
+
- To forward data through intermediate nodes, declare it as both @input and @output with the same name
|
|
2766
|
+
- For non-adjacent wiring, use @connect sourceNode.port -> targetNode.port
|
|
2767
|
+
|
|
2768
|
+
Data flow:
|
|
2769
|
+
- @path A -> B -> C: Linear execution path (sugar for multiple @connect)
|
|
2770
|
+
- @autoConnect: Auto-wire all nodes in declaration order
|
|
2771
|
+
- @connect: Explicit port-to-port wiring
|
|
2772
|
+
- Merge strategies for fan-in: FIRST, LAST, COLLECT, MERGE, CONCAT`
|
|
2773
|
+
};
|
|
2774
|
+
var CAP_FW_VALIDATE = {
|
|
2775
|
+
name: "fw-validate",
|
|
2776
|
+
description: "Flow Weaver validation error codes and common fix patterns.",
|
|
2777
|
+
prompt: `## Validation Errors
|
|
2778
|
+
|
|
2779
|
+
When you encounter validation errors, suggest the specific fix. Common resolutions:
|
|
2780
|
+
- UNKNOWN_NODE_TYPE: Ensure the referenced function has @flowWeaver nodeType annotation
|
|
2781
|
+
- MISSING_REQUIRED_INPUT: Add a @connect from a source port or make the input optional with [brackets]
|
|
2782
|
+
- UNKNOWN_SOURCE_PORT / UNKNOWN_TARGET_PORT: Check port name spelling in @connect
|
|
2783
|
+
- CYCLE_DETECTED: Break the cycle; use scoped iteration (@scope, @map) instead of circular dependencies`
|
|
2784
|
+
};
|
|
2785
|
+
var CAP_FW_GENESIS = {
|
|
2786
|
+
name: "fw-genesis",
|
|
2787
|
+
description: "Flow Weaver genesis protocol for self-evolving workflows.",
|
|
2788
|
+
prompt: `## Genesis Protocol
|
|
2789
|
+
|
|
2790
|
+
Genesis is a 17-step self-evolving workflow engine:
|
|
2791
|
+
1. Load config 2. Observe project 3. Load task workflow 4. Diff fingerprint
|
|
2792
|
+
5. Check stabilize mode 6. Wait for agent 7. Propose evolution 8. Validate proposal
|
|
2793
|
+
9. Snapshot for rollback 10. Apply changes 11. Compile and validate
|
|
2794
|
+
12. Diff workflow 13. Check approval threshold 14. Wait for approval
|
|
2795
|
+
15. Commit or rollback 16. Update history 17. Report summary
|
|
2796
|
+
|
|
2797
|
+
When stabilize mode is active, only fix-up operations are allowed.`
|
|
2798
|
+
};
|
|
2799
|
+
var CAP_FW_CLI = {
|
|
2800
|
+
name: "fw-cli",
|
|
2801
|
+
description: "Flow Weaver CLI command reference for compile, validate, diagram, and other operations.",
|
|
2802
|
+
prompt: `## CLI Commands
|
|
2803
|
+
|
|
2804
|
+
Note: compile, validate, modify, diff, diagram, and describe operations are available as direct plan steps (no CLI needed).`
|
|
2805
|
+
};
|
|
2806
|
+
var CAP_CODE_REVIEW = {
|
|
2807
|
+
name: "code-review",
|
|
2808
|
+
description: "Code review guidelines, quality checklist, and security review patterns.",
|
|
2809
|
+
prompt: `## Code Review
|
|
2810
|
+
|
|
2811
|
+
When reviewing code, check for:
|
|
2812
|
+
1. Correctness: Does the code do what the task asked?
|
|
2813
|
+
2. Security: No hardcoded secrets, no injection vulnerabilities, no exposed APIs
|
|
2814
|
+
3. Style: Consistent with project conventions, proper naming, no dead code
|
|
2815
|
+
4. Testing: Are there tests? Do they cover edge cases?
|
|
2816
|
+
5. Performance: No unnecessary loops, no blocking calls in async code
|
|
2817
|
+
|
|
2818
|
+
Report concerns with specific file:line references and suggested fixes.`
|
|
2819
|
+
};
|
|
2820
|
+
var CAP_WEB = {
|
|
2821
|
+
name: "web",
|
|
2822
|
+
description: "Web fetch capability for fetching URLs and external resources.",
|
|
2823
|
+
tools: ["web_fetch"],
|
|
2824
|
+
prompt: `## Web
|
|
2825
|
+
- web_fetch(url): Fetch a URL and return its content. Use for API docs, examples, etc.`
|
|
2826
|
+
};
|
|
2827
|
+
var CAP_CONTEXT = {
|
|
2828
|
+
name: "context",
|
|
2829
|
+
description: "Project file listings, directory structure, and workspace context.",
|
|
2830
|
+
prompt: `## Project Context
|
|
2831
|
+
|
|
2832
|
+
Use list_files to understand the project structure before making changes.
|
|
2833
|
+
The context bundle (when available) provides a snapshot of the workspace.`
|
|
2834
|
+
};
|
|
2835
|
+
var BUILT_IN_CAPABILITIES = [
|
|
2836
|
+
CAP_CORE,
|
|
2837
|
+
CAP_FILE_OPS,
|
|
2838
|
+
CAP_SHELL,
|
|
2839
|
+
CAP_TASK_MGMT,
|
|
2840
|
+
CAP_FW_GRAMMAR,
|
|
2841
|
+
CAP_FW_VALIDATE,
|
|
2842
|
+
CAP_FW_GENESIS,
|
|
2843
|
+
CAP_FW_CLI,
|
|
2844
|
+
CAP_CODE_REVIEW,
|
|
2845
|
+
CAP_WEB,
|
|
2846
|
+
CAP_CONTEXT
|
|
2847
|
+
];
|
|
2848
|
+
var capabilityMap = new Map(
|
|
2849
|
+
BUILT_IN_CAPABILITIES.map((c) => [c.name, c])
|
|
2850
|
+
);
|
|
2851
|
+
|
|
2852
|
+
// src/bot/behavior-defaults.ts
|
|
2853
|
+
var STRATEGY_CAPABILITIES = {
|
|
2854
|
+
frugal: ["core", "file-ops", "shell", "context"],
|
|
2855
|
+
balanced: ["core", "file-ops", "shell", "task-mgmt", "fw-grammar", "fw-validate", "context"],
|
|
2856
|
+
performance: ["core", "file-ops", "shell", "task-mgmt", "fw-grammar", "fw-validate", "fw-genesis", "fw-cli", "code-review", "web", "context"]
|
|
2857
|
+
};
|
|
2858
|
+
var STRATEGY_BUDGETS = {
|
|
2859
|
+
frugal: 0.1,
|
|
2860
|
+
balanced: 0.5,
|
|
2861
|
+
performance: 1
|
|
2862
|
+
};
|
|
2863
|
+
|
|
2640
2864
|
// src/ui/profile-editor.tsx
|
|
2641
2865
|
var React9 = require("react");
|
|
2642
2866
|
var { useState: useState6, useEffect: useEffect4, useCallback: useCallback4 } = React9;
|
|
@@ -2657,6 +2881,7 @@ var {
|
|
|
2657
2881
|
Switch,
|
|
2658
2882
|
ToggleGroup,
|
|
2659
2883
|
CollapsibleSection: CollapsibleSection2,
|
|
2884
|
+
ScrollArea: ScrollArea3,
|
|
2660
2885
|
toast: toast4,
|
|
2661
2886
|
usePackWorkspace: usePackWorkspace4
|
|
2662
2887
|
} = require("@fw/plugin-ui-kit");
|
|
@@ -2716,6 +2941,8 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2716
2941
|
const [capDescription, setCapDescription] = useState6("");
|
|
2717
2942
|
const [instructions, setInstructions] = useState6("");
|
|
2718
2943
|
const [requireApproval, setRequireApproval] = useState6(false);
|
|
2944
|
+
const [knowledgeCaps, setKnowledgeCaps] = useState6(() => [...STRATEGY_CAPABILITIES.balanced]);
|
|
2945
|
+
const [budget, setBudget] = useState6(STRATEGY_BUDGETS.balanced);
|
|
2719
2946
|
const [behavior, setBehavior] = useState6(defaultBehaviorForStrategy("balanced"));
|
|
2720
2947
|
const [blockedInput, setBlockedInput] = useState6("");
|
|
2721
2948
|
const [allowedInput, setAllowedInput] = useState6("");
|
|
@@ -2727,6 +2954,8 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2727
2954
|
if (p !== "custom") {
|
|
2728
2955
|
setCostStrategy(p);
|
|
2729
2956
|
setBehavior(defaultBehaviorForStrategy(p));
|
|
2957
|
+
setKnowledgeCaps([...STRATEGY_CAPABILITIES[p]]);
|
|
2958
|
+
setBudget(STRATEGY_BUDGETS[p]);
|
|
2730
2959
|
}
|
|
2731
2960
|
}, []);
|
|
2732
2961
|
const updatePhase = useCallback4((phase, field, value) => {
|
|
@@ -2768,6 +2997,22 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2768
2997
|
);
|
|
2769
2998
|
setInstructions(prefs.instructions || "");
|
|
2770
2999
|
setRequireApproval(!!prefs.requireApproval);
|
|
3000
|
+
if (prefs.behavior) {
|
|
3001
|
+
const b = prefs.behavior;
|
|
3002
|
+
if (Array.isArray(b.capabilities)) {
|
|
3003
|
+
setKnowledgeCaps(b.capabilities);
|
|
3004
|
+
} else {
|
|
3005
|
+
setKnowledgeCaps([...STRATEGY_CAPABILITIES[strat]]);
|
|
3006
|
+
}
|
|
3007
|
+
if (typeof b.budget === "number") {
|
|
3008
|
+
setBudget(b.budget);
|
|
3009
|
+
} else {
|
|
3010
|
+
setBudget(STRATEGY_BUDGETS[strat]);
|
|
3011
|
+
}
|
|
3012
|
+
} else {
|
|
3013
|
+
setKnowledgeCaps([...STRATEGY_CAPABILITIES[strat]]);
|
|
3014
|
+
setBudget(STRATEGY_BUDGETS[strat]);
|
|
3015
|
+
}
|
|
2771
3016
|
if (prefs.behavior) {
|
|
2772
3017
|
const b = prefs.behavior;
|
|
2773
3018
|
const phases = b.phases;
|
|
@@ -2812,6 +3057,13 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2812
3057
|
const handleRemoveCapability = useCallback4((index) => {
|
|
2813
3058
|
setCapabilities((prev) => prev.filter((_, i) => i !== index));
|
|
2814
3059
|
}, []);
|
|
3060
|
+
const handleToggleKnowledgeCap = useCallback4((capName2) => {
|
|
3061
|
+
setKnowledgeCaps((prev) => {
|
|
3062
|
+
if (capName2 === "core") return prev;
|
|
3063
|
+
return prev.includes(capName2) ? prev.filter((n) => n !== capName2) : [...prev, capName2];
|
|
3064
|
+
});
|
|
3065
|
+
setPreset("custom");
|
|
3066
|
+
}, []);
|
|
2815
3067
|
const handleAddScopePath = useCallback4((type) => {
|
|
2816
3068
|
const input = type === "blocked" ? blockedInput : allowedInput;
|
|
2817
3069
|
const trimmed = input.trim();
|
|
@@ -2852,6 +3104,8 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2852
3104
|
}
|
|
2853
3105
|
}
|
|
2854
3106
|
const behaviorPayload = {
|
|
3107
|
+
capabilities: knowledgeCaps,
|
|
3108
|
+
budget,
|
|
2855
3109
|
phases,
|
|
2856
3110
|
escalation: { maxAttempts: behavior.maxAttempts, onExhausted: behavior.onExhausted },
|
|
2857
3111
|
scope: behavior.blockedPaths.length > 0 || behavior.allowedPaths.length > 0 ? {
|
|
@@ -2897,7 +3151,7 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
2897
3151
|
} catch (err) {
|
|
2898
3152
|
toast4(err instanceof Error ? err.message : `Failed to ${mode} profile`, { type: "error" });
|
|
2899
3153
|
}
|
|
2900
|
-
}, [mode, profileId, name, description, botId, icon, color, costStrategy, capabilities, instructions, requireApproval, behavior, callTool, onSave]);
|
|
3154
|
+
}, [mode, profileId, name, description, botId, icon, color, costStrategy, capabilities, knowledgeCaps, budget, instructions, requireApproval, behavior, callTool, onSave]);
|
|
2901
3155
|
const handleDelete = useCallback4(async () => {
|
|
2902
3156
|
if (!profileId) return;
|
|
2903
3157
|
const ok = await ctx.confirm("Are you sure you want to delete this profile?", {
|
|
@@ -3001,361 +3255,431 @@ function ProfileEditor({ mode, profileId, bots, onSave, onCancel, onDelete }) {
|
|
|
3001
3255
|
),
|
|
3002
3256
|
// ── Scrollable form body ──
|
|
3003
3257
|
React9.createElement(
|
|
3004
|
-
|
|
3258
|
+
ScrollArea3,
|
|
3005
3259
|
{
|
|
3006
|
-
|
|
3007
|
-
style: { flex: 1, minHeight: 0, overflow: "auto", padding: "12px 16px" }
|
|
3260
|
+
style: { flex: 1, minHeight: 0 }
|
|
3008
3261
|
},
|
|
3009
|
-
// ── Name ──
|
|
3010
|
-
React9.createElement(
|
|
3011
|
-
Field3,
|
|
3012
|
-
{ label: "Name" },
|
|
3013
|
-
React9.createElement(Input2, {
|
|
3014
|
-
type: "text",
|
|
3015
|
-
size: "small",
|
|
3016
|
-
placeholder: "Profile name",
|
|
3017
|
-
value: name,
|
|
3018
|
-
onChange: (v) => setName(v),
|
|
3019
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3020
|
-
inputBoxStyle: { maxWidth: "none" }
|
|
3021
|
-
})
|
|
3022
|
-
),
|
|
3023
|
-
// ── Description ──
|
|
3024
3262
|
React9.createElement(
|
|
3025
|
-
|
|
3026
|
-
{
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
value: description,
|
|
3032
|
-
onChange: (v) => setDescription(v),
|
|
3033
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3034
|
-
inputBoxStyle: { maxWidth: "none" }
|
|
3035
|
-
})
|
|
3036
|
-
),
|
|
3037
|
-
// ── Bot ──
|
|
3038
|
-
React9.createElement(
|
|
3039
|
-
Field3,
|
|
3040
|
-
{ label: "Bot" },
|
|
3041
|
-
React9.createElement(Input2, {
|
|
3042
|
-
type: "select",
|
|
3043
|
-
size: "small",
|
|
3044
|
-
options: bots.map((b) => ({ id: b.id, label: b.name, icon: b.icon || "smartToy" })),
|
|
3045
|
-
optionId: botId,
|
|
3046
|
-
onChange: (id) => setBotId(id),
|
|
3047
|
-
disabled: mode === "edit",
|
|
3048
|
-
placeholder: "Select bot",
|
|
3049
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 }
|
|
3050
|
-
})
|
|
3051
|
-
),
|
|
3052
|
-
// ── Icon ──
|
|
3053
|
-
React9.createElement(
|
|
3054
|
-
Field3,
|
|
3055
|
-
{ label: "Icon", align: "start" },
|
|
3056
|
-
React9.createElement(IconPicker, {
|
|
3057
|
-
catalog: ICON_CATALOG,
|
|
3058
|
-
value: icon,
|
|
3059
|
-
onChange: (v) => setIcon(v),
|
|
3060
|
-
accentColor: color,
|
|
3061
|
-
variant: "inline"
|
|
3062
|
-
})
|
|
3063
|
-
),
|
|
3064
|
-
// ── Color ──
|
|
3065
|
-
React9.createElement(
|
|
3066
|
-
Field3,
|
|
3067
|
-
{ label: "Color", align: "start" },
|
|
3068
|
-
React9.createElement(ColorPicker, {
|
|
3069
|
-
colors: BOT_COLORS,
|
|
3070
|
-
value: color,
|
|
3071
|
-
onChange: (v) => setColor(v),
|
|
3072
|
-
variant: "inline"
|
|
3073
|
-
})
|
|
3074
|
-
),
|
|
3075
|
-
// ── Preset (ToggleGroup with Custom option) ──
|
|
3076
|
-
React9.createElement(
|
|
3077
|
-
Field3,
|
|
3078
|
-
{ label: "Preset", align: "start" },
|
|
3079
|
-
React9.createElement(ToggleGroup, {
|
|
3080
|
-
options: [
|
|
3081
|
-
{ label: "Fast", value: "frugal", icon: "speed", selected: preset === "frugal" },
|
|
3082
|
-
{ label: "Mid", value: "balanced", icon: "balance", selected: preset === "balanced" },
|
|
3083
|
-
{ label: "Smart", value: "performance", icon: "psychology", selected: preset === "performance" },
|
|
3084
|
-
{ label: "Custom", value: "custom", icon: "settings", selected: preset === "custom" }
|
|
3085
|
-
],
|
|
3086
|
-
onSelect: handlePresetChange,
|
|
3087
|
-
size: "extraSmall"
|
|
3088
|
-
})
|
|
3089
|
-
),
|
|
3090
|
-
// ── Phase Configuration (always visible, readOnly when preset) ──
|
|
3091
|
-
React9.createElement(
|
|
3092
|
-
Field3,
|
|
3093
|
-
{ label: "Phases", align: "start" },
|
|
3263
|
+
Flex8,
|
|
3264
|
+
{
|
|
3265
|
+
variant: "column-stretch-start-nowrap-10",
|
|
3266
|
+
style: { padding: "12px 16px" }
|
|
3267
|
+
},
|
|
3268
|
+
// ── Name ──
|
|
3094
3269
|
React9.createElement(
|
|
3095
|
-
|
|
3096
|
-
{
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3270
|
+
Field3,
|
|
3271
|
+
{ label: "Name" },
|
|
3272
|
+
React9.createElement(Input2, {
|
|
3273
|
+
type: "text",
|
|
3274
|
+
size: "small",
|
|
3275
|
+
placeholder: "Profile name",
|
|
3276
|
+
value: name,
|
|
3277
|
+
onChange: (v) => setName(v),
|
|
3278
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3279
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
3104
3280
|
})
|
|
3105
|
-
)
|
|
3106
|
-
|
|
3107
|
-
// ── Escalation (always visible, readOnly when preset) ──
|
|
3108
|
-
React9.createElement(
|
|
3109
|
-
Field3,
|
|
3110
|
-
{ label: "Retries", align: "start" },
|
|
3281
|
+
),
|
|
3282
|
+
// ── Description ──
|
|
3111
3283
|
React9.createElement(
|
|
3112
|
-
|
|
3113
|
-
{
|
|
3114
|
-
|
|
3115
|
-
|
|
3284
|
+
Field3,
|
|
3285
|
+
{ label: "Description" },
|
|
3286
|
+
React9.createElement(Input2, {
|
|
3287
|
+
type: "text",
|
|
3288
|
+
size: "small",
|
|
3289
|
+
placeholder: "What does this profile do?",
|
|
3290
|
+
value: description,
|
|
3291
|
+
onChange: (v) => setDescription(v),
|
|
3292
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3293
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
3294
|
+
})
|
|
3295
|
+
),
|
|
3296
|
+
// ── Bot ──
|
|
3297
|
+
React9.createElement(
|
|
3298
|
+
Field3,
|
|
3299
|
+
{ label: "Bot" },
|
|
3300
|
+
React9.createElement(Input2, {
|
|
3301
|
+
type: "select",
|
|
3302
|
+
size: "small",
|
|
3303
|
+
options: bots.map((b) => ({ id: b.id, label: b.name, icon: b.icon || "smartToy" })),
|
|
3304
|
+
optionId: botId,
|
|
3305
|
+
onChange: (id) => setBotId(id),
|
|
3306
|
+
disabled: mode === "edit",
|
|
3307
|
+
placeholder: "Select bot",
|
|
3308
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 }
|
|
3309
|
+
})
|
|
3310
|
+
),
|
|
3311
|
+
// ── Icon ──
|
|
3312
|
+
React9.createElement(
|
|
3313
|
+
Field3,
|
|
3314
|
+
{ label: "Icon", align: "start" },
|
|
3315
|
+
React9.createElement(IconPicker, {
|
|
3316
|
+
catalog: ICON_CATALOG,
|
|
3317
|
+
value: icon,
|
|
3318
|
+
onChange: (v) => setIcon(v),
|
|
3319
|
+
accentColor: color,
|
|
3320
|
+
variant: "inline"
|
|
3321
|
+
})
|
|
3322
|
+
),
|
|
3323
|
+
// ── Color ──
|
|
3324
|
+
React9.createElement(
|
|
3325
|
+
Field3,
|
|
3326
|
+
{ label: "Color", align: "start" },
|
|
3327
|
+
React9.createElement(ColorPicker, {
|
|
3328
|
+
colors: BOT_COLORS,
|
|
3329
|
+
value: color,
|
|
3330
|
+
onChange: (v) => setColor(v),
|
|
3331
|
+
variant: "inline"
|
|
3332
|
+
})
|
|
3333
|
+
),
|
|
3334
|
+
// ── Preset (ToggleGroup with Custom option) ──
|
|
3335
|
+
React9.createElement(
|
|
3336
|
+
Field3,
|
|
3337
|
+
{ label: "Preset", align: "start" },
|
|
3338
|
+
React9.createElement(ToggleGroup, {
|
|
3339
|
+
options: [
|
|
3340
|
+
{ label: "Fast", value: "frugal", icon: "speed", selected: preset === "frugal" },
|
|
3341
|
+
{ label: "Mid", value: "balanced", icon: "balance", selected: preset === "balanced" },
|
|
3342
|
+
{ label: "Smart", value: "performance", icon: "psychology", selected: preset === "performance" },
|
|
3343
|
+
{ label: "Custom", value: "custom", icon: "settings", selected: preset === "custom" }
|
|
3344
|
+
],
|
|
3345
|
+
onSelect: handlePresetChange,
|
|
3346
|
+
size: "extraSmall"
|
|
3347
|
+
})
|
|
3348
|
+
),
|
|
3349
|
+
// ── Knowledge Capabilities (checkbox grid) ──
|
|
3350
|
+
React9.createElement(
|
|
3351
|
+
Field3,
|
|
3352
|
+
{ label: "Knowledge", align: "start" },
|
|
3353
|
+
React9.createElement(
|
|
3354
|
+
Flex8,
|
|
3355
|
+
{ variant: "column-stretch-start-nowrap-2" },
|
|
3356
|
+
...BUILT_IN_CAPABILITIES.map(
|
|
3357
|
+
(cap) => React9.createElement(
|
|
3358
|
+
Flex8,
|
|
3359
|
+
{
|
|
3360
|
+
key: cap.name,
|
|
3361
|
+
variant: "row-center-start-nowrap-8",
|
|
3362
|
+
style: { minHeight: 28, padding: "1px 0" }
|
|
3363
|
+
},
|
|
3364
|
+
React9.createElement(Checkbox2, {
|
|
3365
|
+
checked: knowledgeCaps.includes(cap.name),
|
|
3366
|
+
onChange: () => handleToggleKnowledgeCap(cap.name),
|
|
3367
|
+
disabled: cap.name === "core" || !isCustom,
|
|
3368
|
+
size: "sm"
|
|
3369
|
+
}),
|
|
3370
|
+
React9.createElement(Typography8, {
|
|
3371
|
+
variant: "smallCaption-thick",
|
|
3372
|
+
color: knowledgeCaps.includes(cap.name) ? "color-text-high" : "color-text-subtle",
|
|
3373
|
+
style: { minWidth: 80 }
|
|
3374
|
+
}, cap.name),
|
|
3375
|
+
React9.createElement(Typography8, {
|
|
3376
|
+
variant: "smallCaption-regular",
|
|
3377
|
+
color: "color-text-subtle",
|
|
3378
|
+
style: { flex: 1 }
|
|
3379
|
+
}, cap.description)
|
|
3380
|
+
)
|
|
3381
|
+
)
|
|
3382
|
+
)
|
|
3383
|
+
),
|
|
3384
|
+
// ── Budget ──
|
|
3385
|
+
React9.createElement(
|
|
3386
|
+
Field3,
|
|
3387
|
+
{ label: "Budget", align: "center" },
|
|
3116
3388
|
React9.createElement(
|
|
3117
|
-
|
|
3118
|
-
{
|
|
3389
|
+
Flex8,
|
|
3390
|
+
{ variant: "row-center-start-nowrap-6" },
|
|
3391
|
+
React9.createElement(Typography8, {
|
|
3392
|
+
variant: "smallCaption-regular",
|
|
3393
|
+
color: "color-text-subtle"
|
|
3394
|
+
}, "$"),
|
|
3119
3395
|
React9.createElement(Input2, {
|
|
3120
3396
|
type: "number",
|
|
3121
3397
|
size: "small",
|
|
3122
|
-
value: String(
|
|
3398
|
+
value: String(budget),
|
|
3123
3399
|
readOnly: !isCustom,
|
|
3124
|
-
onChange: isCustom ? (v) =>
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3400
|
+
onChange: isCustom ? (v) => {
|
|
3401
|
+
const n = parseFloat(v);
|
|
3402
|
+
if (!isNaN(n) && n >= 0) setBudget(n);
|
|
3403
|
+
} : void 0,
|
|
3404
|
+
defaultBoxStyle: { width: 80 }
|
|
3405
|
+
}),
|
|
3406
|
+
React9.createElement(Typography8, {
|
|
3407
|
+
variant: "smallCaption-regular",
|
|
3408
|
+
color: "color-text-subtle"
|
|
3409
|
+
}, "/ task")
|
|
3410
|
+
)
|
|
3411
|
+
),
|
|
3412
|
+
// ── Phase Configuration (always visible, readOnly when preset) ──
|
|
3413
|
+
React9.createElement(
|
|
3414
|
+
Field3,
|
|
3415
|
+
{ label: "Phases", align: "start" },
|
|
3128
3416
|
React9.createElement(
|
|
3129
|
-
|
|
3130
|
-
{
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
],
|
|
3137
|
-
|
|
3138
|
-
readOnly: !isCustom,
|
|
3139
|
-
size: "extraSmall"
|
|
3417
|
+
Flex8,
|
|
3418
|
+
{
|
|
3419
|
+
variant: "column-stretch-start-nowrap-6"
|
|
3420
|
+
},
|
|
3421
|
+
...Object.entries(behavior).filter(([k]) => !["maxAttempts", "onExhausted", "blockedPaths", "allowedPaths"].includes(k)).map(([phaseName, phase]) => {
|
|
3422
|
+
const phaseObj = phase;
|
|
3423
|
+
const isLlm = phaseObj.tier !== void 0;
|
|
3424
|
+
const label = phaseName.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
|
|
3425
|
+
return phaseRow(phaseName, label, isLlm);
|
|
3140
3426
|
})
|
|
3141
3427
|
)
|
|
3142
|
-
)
|
|
3143
|
-
|
|
3144
|
-
// ── Scope Constraints (collapsible) ──
|
|
3145
|
-
// ── Custom: Scope Constraints (inline) ──
|
|
3146
|
-
isCustom && React9.createElement(
|
|
3147
|
-
Field3,
|
|
3148
|
-
{ label: "Scope", align: "start" },
|
|
3428
|
+
),
|
|
3429
|
+
// ── Escalation (always visible, readOnly when preset) ──
|
|
3149
3430
|
React9.createElement(
|
|
3150
|
-
|
|
3151
|
-
{
|
|
3152
|
-
variant: "column-stretch-start-nowrap-8"
|
|
3153
|
-
},
|
|
3154
|
-
// Blocked paths
|
|
3431
|
+
Field3,
|
|
3432
|
+
{ label: "Retries", align: "start" },
|
|
3155
3433
|
React9.createElement(
|
|
3156
|
-
|
|
3157
|
-
{
|
|
3434
|
+
Flex8,
|
|
3435
|
+
{
|
|
3436
|
+
variant: "column-stretch-start-nowrap-8"
|
|
3437
|
+
},
|
|
3158
3438
|
React9.createElement(
|
|
3159
|
-
|
|
3160
|
-
{
|
|
3439
|
+
Field3,
|
|
3440
|
+
{ label: "Max attempts", labelWidth: 100, align: "center" },
|
|
3441
|
+
React9.createElement(Input2, {
|
|
3442
|
+
type: "number",
|
|
3443
|
+
size: "small",
|
|
3444
|
+
value: String(behavior.maxAttempts),
|
|
3445
|
+
readOnly: !isCustom,
|
|
3446
|
+
onChange: isCustom ? (v) => updateEscalation("maxAttempts", Math.max(1, parseInt(v) || 1)) : void 0,
|
|
3447
|
+
defaultBoxStyle: { width: 60 }
|
|
3448
|
+
})
|
|
3449
|
+
),
|
|
3450
|
+
React9.createElement(
|
|
3451
|
+
Field3,
|
|
3452
|
+
{ label: "On exhausted", labelWidth: 100, align: "start" },
|
|
3453
|
+
React9.createElement(ToggleGroup, {
|
|
3454
|
+
options: [
|
|
3455
|
+
{ label: "Block", value: "block", icon: "block", selected: behavior.onExhausted === "block" },
|
|
3456
|
+
{ label: "Reassign", value: "reassign", icon: "sync", selected: behavior.onExhausted === "reassign" },
|
|
3457
|
+
{ label: "Notify", value: "notify", icon: "notifications", selected: behavior.onExhausted === "notify" }
|
|
3458
|
+
],
|
|
3459
|
+
onSelect: (v) => updateEscalation("onExhausted", v),
|
|
3460
|
+
readOnly: !isCustom,
|
|
3461
|
+
size: "extraSmall"
|
|
3462
|
+
})
|
|
3463
|
+
)
|
|
3464
|
+
)
|
|
3465
|
+
),
|
|
3466
|
+
// ── Scope Constraints (collapsible) ──
|
|
3467
|
+
// ── Custom: Scope Constraints (inline) ──
|
|
3468
|
+
isCustom && React9.createElement(
|
|
3469
|
+
Field3,
|
|
3470
|
+
{ label: "Scope", align: "start" },
|
|
3471
|
+
React9.createElement(
|
|
3472
|
+
Flex8,
|
|
3473
|
+
{
|
|
3474
|
+
variant: "column-stretch-start-nowrap-8"
|
|
3475
|
+
},
|
|
3476
|
+
// Blocked paths
|
|
3477
|
+
React9.createElement(
|
|
3478
|
+
Field3,
|
|
3479
|
+
{ label: "Blocked", labelWidth: 70, align: "start" },
|
|
3161
3480
|
React9.createElement(
|
|
3162
3481
|
Flex8,
|
|
3163
|
-
{ variant: "
|
|
3164
|
-
React9.createElement(
|
|
3165
|
-
type: "text",
|
|
3166
|
-
size: "small",
|
|
3167
|
-
placeholder: "e.g. src/",
|
|
3168
|
-
value: blockedInput,
|
|
3169
|
-
onChange: (v) => setBlockedInput(v),
|
|
3170
|
-
onEnter: () => handleAddScopePath("blocked"),
|
|
3171
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3172
|
-
inputBoxStyle: { maxWidth: "none" }
|
|
3173
|
-
}),
|
|
3174
|
-
React9.createElement(IconButton6, {
|
|
3175
|
-
icon: "add",
|
|
3176
|
-
size: "sm",
|
|
3177
|
-
variant: "outlined",
|
|
3178
|
-
color: "primary",
|
|
3179
|
-
onClick: () => handleAddScopePath("blocked"),
|
|
3180
|
-
disabled: !blockedInput.trim()
|
|
3181
|
-
})
|
|
3182
|
-
),
|
|
3183
|
-
...behavior.blockedPaths.map(
|
|
3184
|
-
(p, i) => React9.createElement(
|
|
3482
|
+
{ variant: "column-stretch-start-nowrap-4" },
|
|
3483
|
+
React9.createElement(
|
|
3185
3484
|
Flex8,
|
|
3186
|
-
{
|
|
3187
|
-
React9.createElement(
|
|
3188
|
-
|
|
3485
|
+
{ variant: "row-center-start-nowrap-4" },
|
|
3486
|
+
React9.createElement(Input2, {
|
|
3487
|
+
type: "text",
|
|
3488
|
+
size: "small",
|
|
3489
|
+
placeholder: "e.g. src/",
|
|
3490
|
+
value: blockedInput,
|
|
3491
|
+
onChange: (v) => setBlockedInput(v),
|
|
3492
|
+
onEnter: () => handleAddScopePath("blocked"),
|
|
3493
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3494
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
3495
|
+
}),
|
|
3189
3496
|
React9.createElement(IconButton6, {
|
|
3190
|
-
icon: "
|
|
3191
|
-
size: "
|
|
3192
|
-
variant: "
|
|
3193
|
-
color: "
|
|
3194
|
-
onClick: () =>
|
|
3497
|
+
icon: "add",
|
|
3498
|
+
size: "sm",
|
|
3499
|
+
variant: "outlined",
|
|
3500
|
+
color: "primary",
|
|
3501
|
+
onClick: () => handleAddScopePath("blocked"),
|
|
3502
|
+
disabled: !blockedInput.trim()
|
|
3195
3503
|
})
|
|
3504
|
+
),
|
|
3505
|
+
...behavior.blockedPaths.map(
|
|
3506
|
+
(p, i) => React9.createElement(
|
|
3507
|
+
Flex8,
|
|
3508
|
+
{ key: `b-${p}-${i}`, variant: "row-center-start-nowrap-6" },
|
|
3509
|
+
React9.createElement(Icon5, { name: "block", size: 12, color: "color-status-negative" }),
|
|
3510
|
+
React9.createElement(Typography8, { variant: "smallCaption-regular", color: "color-text-high", style: { flex: 1 } }, p),
|
|
3511
|
+
React9.createElement(IconButton6, {
|
|
3512
|
+
icon: "close",
|
|
3513
|
+
size: "xs",
|
|
3514
|
+
variant: "clear",
|
|
3515
|
+
color: "danger",
|
|
3516
|
+
onClick: () => handleRemoveScopePath("blocked", i)
|
|
3517
|
+
})
|
|
3518
|
+
)
|
|
3196
3519
|
)
|
|
3197
3520
|
)
|
|
3198
|
-
)
|
|
3199
|
-
|
|
3200
|
-
// Allowed paths
|
|
3201
|
-
React9.createElement(
|
|
3202
|
-
Field3,
|
|
3203
|
-
{ label: "Allowed", labelWidth: 70, align: "start" },
|
|
3521
|
+
),
|
|
3522
|
+
// Allowed paths
|
|
3204
3523
|
React9.createElement(
|
|
3205
|
-
|
|
3206
|
-
{
|
|
3524
|
+
Field3,
|
|
3525
|
+
{ label: "Allowed", labelWidth: 70, align: "start" },
|
|
3207
3526
|
React9.createElement(
|
|
3208
3527
|
Flex8,
|
|
3209
|
-
{ variant: "
|
|
3210
|
-
React9.createElement(
|
|
3211
|
-
type: "text",
|
|
3212
|
-
size: "small",
|
|
3213
|
-
placeholder: "e.g. config/",
|
|
3214
|
-
value: allowedInput,
|
|
3215
|
-
onChange: (v) => setAllowedInput(v),
|
|
3216
|
-
onEnter: () => handleAddScopePath("allowed"),
|
|
3217
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3218
|
-
inputBoxStyle: { maxWidth: "none" }
|
|
3219
|
-
}),
|
|
3220
|
-
React9.createElement(IconButton6, {
|
|
3221
|
-
icon: "add",
|
|
3222
|
-
size: "sm",
|
|
3223
|
-
variant: "outlined",
|
|
3224
|
-
color: "primary",
|
|
3225
|
-
onClick: () => handleAddScopePath("allowed"),
|
|
3226
|
-
disabled: !allowedInput.trim()
|
|
3227
|
-
})
|
|
3228
|
-
),
|
|
3229
|
-
...behavior.allowedPaths.map(
|
|
3230
|
-
(p, i) => React9.createElement(
|
|
3528
|
+
{ variant: "column-stretch-start-nowrap-4" },
|
|
3529
|
+
React9.createElement(
|
|
3231
3530
|
Flex8,
|
|
3232
|
-
{
|
|
3233
|
-
React9.createElement(
|
|
3234
|
-
|
|
3531
|
+
{ variant: "row-center-start-nowrap-4" },
|
|
3532
|
+
React9.createElement(Input2, {
|
|
3533
|
+
type: "text",
|
|
3534
|
+
size: "small",
|
|
3535
|
+
placeholder: "e.g. config/",
|
|
3536
|
+
value: allowedInput,
|
|
3537
|
+
onChange: (v) => setAllowedInput(v),
|
|
3538
|
+
onEnter: () => handleAddScopePath("allowed"),
|
|
3539
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3540
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
3541
|
+
}),
|
|
3235
3542
|
React9.createElement(IconButton6, {
|
|
3236
|
-
icon: "
|
|
3237
|
-
size: "
|
|
3238
|
-
variant: "
|
|
3239
|
-
color: "
|
|
3240
|
-
onClick: () =>
|
|
3543
|
+
icon: "add",
|
|
3544
|
+
size: "sm",
|
|
3545
|
+
variant: "outlined",
|
|
3546
|
+
color: "primary",
|
|
3547
|
+
onClick: () => handleAddScopePath("allowed"),
|
|
3548
|
+
disabled: !allowedInput.trim()
|
|
3241
3549
|
})
|
|
3550
|
+
),
|
|
3551
|
+
...behavior.allowedPaths.map(
|
|
3552
|
+
(p, i) => React9.createElement(
|
|
3553
|
+
Flex8,
|
|
3554
|
+
{ key: `a-${p}-${i}`, variant: "row-center-start-nowrap-6" },
|
|
3555
|
+
React9.createElement(Icon5, { name: "checkCircle", size: 12, color: "color-status-positive" }),
|
|
3556
|
+
React9.createElement(Typography8, { variant: "smallCaption-regular", color: "color-text-high", style: { flex: 1 } }, p),
|
|
3557
|
+
React9.createElement(IconButton6, {
|
|
3558
|
+
icon: "close",
|
|
3559
|
+
size: "xs",
|
|
3560
|
+
variant: "clear",
|
|
3561
|
+
color: "danger",
|
|
3562
|
+
onClick: () => handleRemoveScopePath("allowed", i)
|
|
3563
|
+
})
|
|
3564
|
+
)
|
|
3242
3565
|
)
|
|
3243
3566
|
)
|
|
3244
3567
|
)
|
|
3245
3568
|
)
|
|
3246
|
-
)
|
|
3247
|
-
|
|
3248
|
-
// ── Capabilities ──
|
|
3249
|
-
React9.createElement(
|
|
3250
|
-
Field3,
|
|
3251
|
-
{ label: "Capabilities", align: "start" },
|
|
3569
|
+
),
|
|
3570
|
+
// ── Capabilities ──
|
|
3252
3571
|
React9.createElement(
|
|
3253
|
-
|
|
3254
|
-
{
|
|
3255
|
-
// Add row
|
|
3572
|
+
Field3,
|
|
3573
|
+
{ label: "Capabilities", align: "start" },
|
|
3256
3574
|
React9.createElement(
|
|
3257
3575
|
Flex8,
|
|
3258
|
-
{ variant: "
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3576
|
+
{ variant: "column-stretch-start-nowrap-6" },
|
|
3577
|
+
// Add row
|
|
3578
|
+
React9.createElement(
|
|
3579
|
+
Flex8,
|
|
3580
|
+
{ variant: "row-center-start-nowrap-4", style: { minWidth: 0 } },
|
|
3581
|
+
React9.createElement(Input2, {
|
|
3582
|
+
type: "text",
|
|
3583
|
+
size: "small",
|
|
3584
|
+
placeholder: "Name",
|
|
3585
|
+
value: capName,
|
|
3586
|
+
onChange: (v) => setCapName(v),
|
|
3587
|
+
defaultBoxStyle: { flex: "0 1 120px", minWidth: 0 },
|
|
3588
|
+
inputBoxStyle: { maxWidth: "none", minWidth: 0 }
|
|
3589
|
+
}),
|
|
3590
|
+
React9.createElement(Input2, {
|
|
3591
|
+
type: "text",
|
|
3592
|
+
size: "small",
|
|
3593
|
+
placeholder: "Description",
|
|
3594
|
+
value: capDescription,
|
|
3595
|
+
onChange: (v) => setCapDescription(v),
|
|
3596
|
+
onEnter: handleAddCapability,
|
|
3597
|
+
defaultBoxStyle: { flex: "1 1 0", minWidth: 0 },
|
|
3598
|
+
inputBoxStyle: { maxWidth: "none", minWidth: 0 }
|
|
3599
|
+
}),
|
|
3600
|
+
React9.createElement(IconButton6, {
|
|
3601
|
+
icon: "add",
|
|
3602
|
+
size: "sm",
|
|
3603
|
+
variant: "outlined",
|
|
3604
|
+
color: "primary",
|
|
3605
|
+
onClick: handleAddCapability,
|
|
3606
|
+
disabled: !capName.trim() || !capDescription.trim(),
|
|
3607
|
+
style: { flexShrink: 0 }
|
|
3608
|
+
})
|
|
3609
|
+
),
|
|
3610
|
+
// Table
|
|
3611
|
+
capabilities.length > 0 && React9.createElement(Table2, {
|
|
3612
|
+
size: "compact",
|
|
3613
|
+
showHeader: false,
|
|
3614
|
+
data: capabilities,
|
|
3615
|
+
getRowKey: (_row, i) => `cap-${i}`,
|
|
3616
|
+
columns: [
|
|
3617
|
+
{
|
|
3618
|
+
key: "name",
|
|
3619
|
+
header: "Name",
|
|
3620
|
+
width: "30%",
|
|
3621
|
+
render: (val) => React9.createElement("div", { style: { lineHeight: "28px" } }, String(val))
|
|
3622
|
+
},
|
|
3623
|
+
{
|
|
3624
|
+
key: "description",
|
|
3625
|
+
header: "Description",
|
|
3626
|
+
render: (val) => React9.createElement("div", { style: { lineHeight: "28px" } }, String(val))
|
|
3627
|
+
},
|
|
3628
|
+
{
|
|
3629
|
+
key: "actions",
|
|
3630
|
+
header: "",
|
|
3631
|
+
width: "32px",
|
|
3632
|
+
align: "right",
|
|
3633
|
+
render: (_val, _row, idx) => React9.createElement(IconButton6, {
|
|
3634
|
+
icon: "close",
|
|
3635
|
+
size: "xs",
|
|
3636
|
+
variant: "clear",
|
|
3637
|
+
color: "danger",
|
|
3638
|
+
onClick: () => handleRemoveCapability(idx)
|
|
3639
|
+
})
|
|
3640
|
+
}
|
|
3641
|
+
]
|
|
3285
3642
|
})
|
|
3286
|
-
)
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
size: "xs",
|
|
3313
|
-
variant: "clear",
|
|
3314
|
-
color: "danger",
|
|
3315
|
-
onClick: () => handleRemoveCapability(idx)
|
|
3316
|
-
})
|
|
3317
|
-
}
|
|
3318
|
-
]
|
|
3643
|
+
)
|
|
3644
|
+
),
|
|
3645
|
+
// ── Instructions (multiline) ──
|
|
3646
|
+
React9.createElement(
|
|
3647
|
+
Field3,
|
|
3648
|
+
{ label: "Instructions", align: "start" },
|
|
3649
|
+
React9.createElement(Input2, {
|
|
3650
|
+
type: "text",
|
|
3651
|
+
size: "small",
|
|
3652
|
+
multiline: true,
|
|
3653
|
+
placeholder: "Behavioral protocol for this profile (optional)",
|
|
3654
|
+
value: instructions,
|
|
3655
|
+
onChange: (v) => setInstructions(v),
|
|
3656
|
+
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3657
|
+
inputBoxStyle: { maxWidth: "none" }
|
|
3658
|
+
})
|
|
3659
|
+
),
|
|
3660
|
+
// ── Require Approval ──
|
|
3661
|
+
React9.createElement(
|
|
3662
|
+
Field3,
|
|
3663
|
+
{ label: "" },
|
|
3664
|
+
React9.createElement(Checkbox2, {
|
|
3665
|
+
checked: requireApproval,
|
|
3666
|
+
onChange: (v) => setRequireApproval(v),
|
|
3667
|
+
label: "Require approval",
|
|
3668
|
+
size: "sm"
|
|
3319
3669
|
})
|
|
3670
|
+
),
|
|
3671
|
+
// ── Save button ──
|
|
3672
|
+
React9.createElement(
|
|
3673
|
+
Flex8,
|
|
3674
|
+
{ variant: "row-center-end-nowrap-8" },
|
|
3675
|
+
React9.createElement(Button4, {
|
|
3676
|
+
size: "xs",
|
|
3677
|
+
variant: "fill",
|
|
3678
|
+
color: "primary",
|
|
3679
|
+
onClick: handleSave,
|
|
3680
|
+
disabled: !name.trim() || !botId || capabilities.length === 0
|
|
3681
|
+
}, mode === "create" ? "Create" : "Save")
|
|
3320
3682
|
)
|
|
3321
|
-
),
|
|
3322
|
-
// ── Instructions (multiline) ──
|
|
3323
|
-
React9.createElement(
|
|
3324
|
-
Field3,
|
|
3325
|
-
{ label: "Instructions", align: "start" },
|
|
3326
|
-
React9.createElement(Input2, {
|
|
3327
|
-
type: "text",
|
|
3328
|
-
size: "small",
|
|
3329
|
-
multiline: true,
|
|
3330
|
-
placeholder: "Behavioral protocol for this profile (optional)",
|
|
3331
|
-
value: instructions,
|
|
3332
|
-
onChange: (v) => setInstructions(v),
|
|
3333
|
-
defaultBoxStyle: { flex: 1, minWidth: 0 },
|
|
3334
|
-
inputBoxStyle: { maxWidth: "none" }
|
|
3335
|
-
})
|
|
3336
|
-
),
|
|
3337
|
-
// ── Require Approval ──
|
|
3338
|
-
React9.createElement(
|
|
3339
|
-
Field3,
|
|
3340
|
-
{ label: "" },
|
|
3341
|
-
React9.createElement(Checkbox2, {
|
|
3342
|
-
checked: requireApproval,
|
|
3343
|
-
onChange: (v) => setRequireApproval(v),
|
|
3344
|
-
label: "Require approval",
|
|
3345
|
-
size: "sm"
|
|
3346
|
-
})
|
|
3347
|
-
),
|
|
3348
|
-
// ── Save button ──
|
|
3349
|
-
React9.createElement(
|
|
3350
|
-
Flex8,
|
|
3351
|
-
{ variant: "row-center-end-nowrap-8" },
|
|
3352
|
-
React9.createElement(Button4, {
|
|
3353
|
-
size: "xs",
|
|
3354
|
-
variant: "fill",
|
|
3355
|
-
color: "primary",
|
|
3356
|
-
onClick: handleSave,
|
|
3357
|
-
disabled: !name.trim() || !botId || capabilities.length === 0
|
|
3358
|
-
}, mode === "create" ? "Create" : "Save")
|
|
3359
3683
|
)
|
|
3360
3684
|
)
|
|
3361
3685
|
);
|
|
@@ -3368,7 +3692,7 @@ var React10 = require("react");
|
|
|
3368
3692
|
var {
|
|
3369
3693
|
Flex: Flex9,
|
|
3370
3694
|
Typography: Typography9,
|
|
3371
|
-
ScrollArea:
|
|
3695
|
+
ScrollArea: ScrollArea4,
|
|
3372
3696
|
Chip: Chip6,
|
|
3373
3697
|
SectionTitle: SectionTitle2
|
|
3374
3698
|
} = require("@fw/plugin-ui-kit");
|
|
@@ -3415,7 +3739,7 @@ function DecisionLog({ decisions }) {
|
|
|
3415
3739
|
},
|
|
3416
3740
|
React10.createElement(SectionTitle2, null, "Decision Log"),
|
|
3417
3741
|
React10.createElement(
|
|
3418
|
-
|
|
3742
|
+
ScrollArea4,
|
|
3419
3743
|
{
|
|
3420
3744
|
style: { maxHeight: "260px" }
|
|
3421
3745
|
},
|
|
@@ -3481,7 +3805,7 @@ var React11 = require("react");
|
|
|
3481
3805
|
var { useState: useState7, useEffect: useEffect5, useCallback: useCallback5, useRef: useRef3 } = React11;
|
|
3482
3806
|
var {
|
|
3483
3807
|
Flex: Flex10,
|
|
3484
|
-
ScrollArea:
|
|
3808
|
+
ScrollArea: ScrollArea5,
|
|
3485
3809
|
EmptyState: EmptyState3,
|
|
3486
3810
|
Typography: Typography10,
|
|
3487
3811
|
StatusIcon: StatusIcon4,
|