@absolutejs/ai 0.0.33 → 0.0.35

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/ai/index.js CHANGED
@@ -3680,15 +3680,30 @@ var createUiCards = (definitions) => {
3680
3680
  };
3681
3681
  // src/ai/ui/catalog.ts
3682
3682
  var CHART_TYPES = ["bar", "line", "donut"];
3683
+ var FORM_FIELD_TYPES = [
3684
+ "text",
3685
+ "textarea",
3686
+ "number",
3687
+ "select",
3688
+ "date",
3689
+ "checkbox"
3690
+ ];
3683
3691
  var CHART_MAX_SERIES = 8;
3684
3692
  var CHART_MAX_POINTS = 24;
3685
3693
  var TABLE_MAX_COLUMNS = 8;
3686
3694
  var TABLE_MAX_ROWS = 30;
3687
3695
  var STAT_TILES_MAX = 6;
3696
+ var UI_ACTIONS_MAX = 3;
3697
+ var FORM_MAX_FIELDS = 8;
3698
+ var FORM_SELECT_MAX_OPTIONS = 12;
3688
3699
  var LABEL_MAX_CHARS = 80;
3689
3700
  var TITLE_MAX_CHARS = 120;
3690
3701
  var CELL_MAX_CHARS = 160;
3691
3702
  var UNIT_MAX_CHARS = 8;
3703
+ var ACTION_LABEL_MAX_CHARS = 40;
3704
+ var DESCRIPTION_MAX_CHARS = 280;
3705
+ var ACTION_TOOL_PATTERN = /^[a-z][a-z0-9_]{1,63}$/;
3706
+ var FIELD_NAME_PATTERN = /^[a-z][a-zA-Z0-9_]{0,63}$/;
3692
3707
  var isRecord6 = (value) => typeof value === "object" && value !== null;
3693
3708
  var cleanString = (value, maxChars) => typeof value === "string" && value.trim().length > 0 ? value.trim().slice(0, maxChars) : null;
3694
3709
  var cleanStringArray = (value, maxItems, maxChars) => {
@@ -3712,6 +3727,40 @@ var cleanNumberArray = (value, maxItems) => {
3712
3727
  }
3713
3728
  return cleaned;
3714
3729
  };
3730
+ var parseUiActions = (value) => {
3731
+ if (!Array.isArray(value) || value.length === 0)
3732
+ return;
3733
+ const actions = [];
3734
+ for (const raw of value.slice(0, UI_ACTIONS_MAX)) {
3735
+ if (!isRecord6(raw))
3736
+ continue;
3737
+ const label = cleanString(raw.label, ACTION_LABEL_MAX_CHARS);
3738
+ const tool = typeof raw.tool === "string" && ACTION_TOOL_PATTERN.test(raw.tool) ? raw.tool : null;
3739
+ if (!label || !tool || !isRecord6(raw.input))
3740
+ continue;
3741
+ actions.push({ input: raw.input, label, tool });
3742
+ }
3743
+ return actions.length > 0 ? actions : undefined;
3744
+ };
3745
+ var ACTIONS_SCHEMA = {
3746
+ description: "Optional action buttons under the card (max 3): each invokes one of YOUR tools with a fully-resolved input when the member clicks it. Use real ids you looked up \u2014 never placeholders. Approval-gated tools queue their normal approval card.",
3747
+ items: {
3748
+ properties: {
3749
+ input: {
3750
+ description: "The exact tool input to send on click",
3751
+ type: "object"
3752
+ },
3753
+ label: {
3754
+ description: 'Short button label, e.g. "Create follow-up task"',
3755
+ type: "string"
3756
+ },
3757
+ tool: { description: "The tool name to invoke", type: "string" }
3758
+ },
3759
+ required: ["label", "tool", "input"],
3760
+ type: "object"
3761
+ },
3762
+ type: "array"
3763
+ };
3715
3764
  var parseChartSpec = (input) => {
3716
3765
  if (!isRecord6(input))
3717
3766
  return null;
@@ -3748,6 +3797,9 @@ var parseChartSpec = (input) => {
3748
3797
  spec.unitPrefix = unitPrefix;
3749
3798
  if (unitSuffix)
3750
3799
  spec.unitSuffix = unitSuffix;
3800
+ const actions = parseUiActions(input.actions);
3801
+ if (actions)
3802
+ spec.actions = actions;
3751
3803
  return spec;
3752
3804
  };
3753
3805
  var parseTableSpec = (input) => {
@@ -3771,6 +3823,9 @@ var parseTableSpec = (input) => {
3771
3823
  const title = cleanString(input.title, TITLE_MAX_CHARS);
3772
3824
  if (title)
3773
3825
  spec.title = title;
3826
+ const actions = parseUiActions(input.actions);
3827
+ if (actions)
3828
+ spec.actions = actions;
3774
3829
  return spec;
3775
3830
  };
3776
3831
  var parseStatTilesSpec = (input) => {
@@ -3795,7 +3850,63 @@ var parseStatTilesSpec = (input) => {
3795
3850
  }
3796
3851
  tiles.push(tile);
3797
3852
  }
3798
- return { tiles };
3853
+ const spec = { tiles };
3854
+ const actions = parseUiActions(input.actions);
3855
+ if (actions)
3856
+ spec.actions = actions;
3857
+ return spec;
3858
+ };
3859
+ var parseFormField = (raw) => {
3860
+ if (!isRecord6(raw))
3861
+ return null;
3862
+ const name = typeof raw.name === "string" && FIELD_NAME_PATTERN.test(raw.name) ? raw.name : null;
3863
+ const label = cleanString(raw.label, LABEL_MAX_CHARS);
3864
+ const type = FORM_FIELD_TYPES.find((entry) => entry === raw.type);
3865
+ if (!name || !label || !type)
3866
+ return null;
3867
+ const field = { label, name, type };
3868
+ const placeholder = cleanString(raw.placeholder, LABEL_MAX_CHARS);
3869
+ if (placeholder)
3870
+ field.placeholder = placeholder;
3871
+ if (raw.required === true)
3872
+ field.required = true;
3873
+ const value = cleanString(raw.value, CELL_MAX_CHARS);
3874
+ if (value)
3875
+ field.value = value;
3876
+ const options = cleanStringArray(raw.options, FORM_SELECT_MAX_OPTIONS, LABEL_MAX_CHARS);
3877
+ if (options)
3878
+ field.options = options;
3879
+ if (type === "select" && !options)
3880
+ return null;
3881
+ return field;
3882
+ };
3883
+ var parseFormFields = (value) => {
3884
+ if (!Array.isArray(value) || value.length === 0)
3885
+ return null;
3886
+ const fields = [];
3887
+ const seen = new Set;
3888
+ for (const raw of value.slice(0, FORM_MAX_FIELDS)) {
3889
+ const field = parseFormField(raw);
3890
+ if (!field || seen.has(field.name))
3891
+ return null;
3892
+ seen.add(field.name);
3893
+ fields.push(field);
3894
+ }
3895
+ return fields;
3896
+ };
3897
+ var parseFormSpec = (input) => {
3898
+ if (!isRecord6(input))
3899
+ return null;
3900
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
3901
+ const fields = parseFormFields(input.fields);
3902
+ const [submit] = parseUiActions([input.submit]) ?? [];
3903
+ if (!title || !fields || !submit)
3904
+ return null;
3905
+ const spec = { fields, submit, title };
3906
+ const description = cleanString(input.description, DESCRIPTION_MAX_CHARS);
3907
+ if (description)
3908
+ spec.description = description;
3909
+ return spec;
3799
3910
  };
3800
3911
  var SERIES_SCHEMA = {
3801
3912
  properties: {
@@ -3814,6 +3925,7 @@ var chartCard = {
3814
3925
  description: "Render a real chart inline in the chat from data you have (tool results, the conversation). Use whenever numbers COMPARE or TREND: revenue by partner (bar), pipeline over time (line), share of a whole (donut). Rules: bar/line take up to 8 series aligned to the same labels; donut takes exactly ONE series of non-negative values (one slice per label). Prefer a chart over a wall of numbers, but never invent data for it.",
3815
3926
  inputSchema: {
3816
3927
  properties: {
3928
+ actions: ACTIONS_SCHEMA,
3817
3929
  labels: {
3818
3930
  description: "Category labels \u2014 x-axis for bar/line, slice names for donut (max 24)",
3819
3931
  items: { type: "string" },
@@ -3846,6 +3958,7 @@ var tableCard = {
3846
3958
  description: "Render a compact data table inline in the chat (max 8 columns \xD7 30 rows). Use for structured comparisons the member will scan \u2014 matches side by side, deal terms, task lists with dates. All cells are strings; format numbers yourself.",
3847
3959
  inputSchema: {
3848
3960
  properties: {
3961
+ actions: ACTIONS_SCHEMA,
3849
3962
  columns: {
3850
3963
  description: "Column headers (max 8)",
3851
3964
  items: { type: "string" },
@@ -3869,6 +3982,7 @@ var statTilesCard = {
3869
3982
  description: "Render a row of headline stat tiles inline in the chat (max 6): a label, a big value, and an optional delta with direction. Use for the 2-4 numbers that ARE the answer \u2014 total attributed revenue, pipeline value, credits remaining \u2014 instead of burying them in prose.",
3870
3983
  inputSchema: {
3871
3984
  properties: {
3985
+ actions: ACTIONS_SCHEMA,
3872
3986
  tiles: {
3873
3987
  description: "The tiles (max 6)",
3874
3988
  items: {
@@ -3896,7 +4010,72 @@ var statTilesCard = {
3896
4010
  name: "render_stat_tiles",
3897
4011
  parse: parseStatTilesSpec
3898
4012
  };
3899
- var BUILTIN_UI_CARDS = [chartCard, tableCard, statTilesCard];
4013
+ var formCard = {
4014
+ ack: "(form rendered inline \u2014 the member fills and submits it, which runs the bound tool with their values. Do NOT re-ask for these values in text; wait for the submission)",
4015
+ description: "Render an inline form when you need SEVERAL structured inputs from the member before running a tool (task details, scheduling constraints, outreach parameters) \u2014 one form beats asking field-by-field in prose. Bind submit to one of YOUR tools with any values you already know pre-filled in submit.input; on submit the member's field values are merged into submit.input under each field's name and the tool runs exactly like a clicked action button. Field names must therefore be the tool's actual input property names. Never use it for values you could look up yourself.",
4016
+ inputSchema: {
4017
+ properties: {
4018
+ description: {
4019
+ description: "Optional one-line helper text under the title",
4020
+ type: "string"
4021
+ },
4022
+ fields: {
4023
+ description: "The inputs to collect (max 8). Each field's name must be a real input property of the submit tool.",
4024
+ items: {
4025
+ properties: {
4026
+ label: { description: "Human label for the field", type: "string" },
4027
+ name: {
4028
+ description: 'Tool-input property name the value submits under, e.g. "title"',
4029
+ type: "string"
4030
+ },
4031
+ options: {
4032
+ description: "Choices \u2014 required for select fields (max 12)",
4033
+ items: { type: "string" },
4034
+ type: "array"
4035
+ },
4036
+ placeholder: { type: "string" },
4037
+ required: { type: "boolean" },
4038
+ type: { enum: [...FORM_FIELD_TYPES], type: "string" },
4039
+ value: {
4040
+ description: 'Prefill value (checkbox: "true"/"false")',
4041
+ type: "string"
4042
+ }
4043
+ },
4044
+ required: ["name", "label", "type"],
4045
+ type: "object"
4046
+ },
4047
+ type: "array"
4048
+ },
4049
+ submit: {
4050
+ description: "The submit binding: label for the button, the tool to run, and any input values you already resolved (real ids, never placeholders)",
4051
+ properties: {
4052
+ input: {
4053
+ description: "Pre-resolved input values; field values are merged in on top under their field names",
4054
+ type: "object"
4055
+ },
4056
+ label: {
4057
+ description: 'Button label, e.g. "Create task"',
4058
+ type: "string"
4059
+ },
4060
+ tool: { description: "The tool name to invoke", type: "string" }
4061
+ },
4062
+ required: ["label", "tool", "input"],
4063
+ type: "object"
4064
+ },
4065
+ title: { description: "Short form title", type: "string" }
4066
+ },
4067
+ required: ["title", "fields", "submit"],
4068
+ type: "object"
4069
+ },
4070
+ name: "render_form",
4071
+ parse: parseFormSpec
4072
+ };
4073
+ var BUILTIN_UI_CARDS = [
4074
+ chartCard,
4075
+ tableCard,
4076
+ statTilesCard,
4077
+ formCard
4078
+ ];
3900
4079
  // src/ai/ui/svg.ts
3901
4080
  var LIGHT_UI_THEME = {
3902
4081
  grid: "#e4e4e0",
@@ -5046,8 +5225,10 @@ export {
5046
5225
  resolveRenderers,
5047
5226
  renderChartSvg,
5048
5227
  providerStatusPage,
5228
+ parseUiActions,
5049
5229
  parseTableSpec,
5050
5230
  parseStatTilesSpec,
5231
+ parseFormSpec,
5051
5232
  parseChartSpec,
5052
5233
  parseAIMessage,
5053
5234
  openaiResponses,
@@ -5064,6 +5245,7 @@ export {
5064
5245
  generateAIWithTools,
5065
5246
  generateAI,
5066
5247
  gemini,
5248
+ formCard,
5067
5249
  fetchProviderApiStatus,
5068
5250
  deepseek,
5069
5251
  createUiCards,
@@ -5078,12 +5260,16 @@ export {
5078
5260
  anthropic,
5079
5261
  alibaba,
5080
5262
  aiChat,
5263
+ UI_ACTIONS_MAX,
5081
5264
  TABLE_MAX_ROWS,
5082
5265
  TABLE_MAX_COLUMNS,
5083
5266
  STAT_TILES_MAX,
5084
5267
  ProviderError,
5085
5268
  PROVIDER_STATUS_PAGES,
5086
5269
  LIGHT_UI_THEME,
5270
+ FORM_SELECT_MAX_OPTIONS,
5271
+ FORM_MAX_FIELDS,
5272
+ FORM_FIELD_TYPES,
5087
5273
  DARK_UI_THEME,
5088
5274
  CHART_TYPES,
5089
5275
  CHART_MAX_SERIES,
@@ -5091,5 +5277,5 @@ export {
5091
5277
  BUILTIN_UI_CARDS
5092
5278
  };
5093
5279
 
5094
- //# debugId=D43CDA3E59D2F6FB64756E2164756E21
5280
+ //# debugId=975418BCAB9B044864756E2164756E21
5095
5281
  //# sourceMappingURL=index.js.map