@absolutejs/ai 0.0.39 → 0.0.41

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
@@ -2959,6 +2959,7 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2959
2959
  stopReason: undefined,
2960
2960
  usage: undefined
2961
2961
  };
2962
+ const responseBeforeTurn = turnState.fullResponse;
2962
2963
  const stream = options.provider.stream({
2963
2964
  cacheSystemPrompt: options.cacheSystemPrompt,
2964
2965
  maxTokens: options.maxTokens,
@@ -2971,7 +2972,7 @@ var streamTurns = async function* (options, renderers, messages, signal, startTi
2971
2972
  tools: toolDefs
2972
2973
  });
2973
2974
  yield* consumeStream2(stream, chunkState, renderers, options, turnState, signal);
2974
- options.onTurn?.(turnState.turn, chunkState.usage);
2975
+ options.onTurn?.(turnState.turn, chunkState.usage, turnState.fullResponse.slice(responseBeforeTurn.length));
2975
2976
  runningTotalTokens += (chunkState.usage?.inputTokens ?? 0) + (chunkState.usage?.outputTokens ?? 0);
2976
2977
  if (chunkState.stopReason === "max_tokens") {
2977
2978
  yield {
@@ -3689,6 +3690,12 @@ var FORM_FIELD_TYPES = [
3689
3690
  "checkbox",
3690
3691
  "password"
3691
3692
  ];
3693
+ var PLAN_STEP_STATUSES = [
3694
+ "pending",
3695
+ "active",
3696
+ "done",
3697
+ "error"
3698
+ ];
3692
3699
  var CHART_MAX_SERIES = 8;
3693
3700
  var CHART_MAX_POINTS = 24;
3694
3701
  var TABLE_MAX_COLUMNS = 8;
@@ -3697,14 +3704,28 @@ var STAT_TILES_MAX = 6;
3697
3704
  var UI_ACTIONS_MAX = 3;
3698
3705
  var FORM_MAX_FIELDS = 8;
3699
3706
  var FORM_SELECT_MAX_OPTIONS = 12;
3707
+ var CHOICE_MAX_OPTIONS = 8;
3708
+ var CONFIRM_CONSEQUENCE_MAX_CHARS = 500;
3709
+ var DIFF_MAX_FILES = 6;
3710
+ var DIFF_MAX_LINES = 400;
3711
+ var PLAN_MAX_STEPS = 12;
3712
+ var CREDENTIAL_MAX_KEYS = 8;
3713
+ var CARD_ID_MAX_CHARS = 64;
3700
3714
  var LABEL_MAX_CHARS = 80;
3701
3715
  var TITLE_MAX_CHARS = 120;
3702
3716
  var CELL_MAX_CHARS = 160;
3703
3717
  var UNIT_MAX_CHARS = 8;
3704
3718
  var ACTION_LABEL_MAX_CHARS = 40;
3705
3719
  var DESCRIPTION_MAX_CHARS = 280;
3720
+ var BADGE_MAX_CHARS = 24;
3721
+ var DIFF_PATH_MAX_CHARS = 260;
3722
+ var DIFF_LINE_MAX_CHARS = 300;
3723
+ var DOCS_URL_MAX_CHARS = 300;
3706
3724
  var ACTION_TOOL_PATTERN = /^[a-z][a-z0-9_]{1,63}$/;
3707
3725
  var FIELD_NAME_PATTERN = /^[a-z][a-zA-Z0-9_]{0,63}$/;
3726
+ var CARD_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
3727
+ var ENV_KEY_PATTERN = /^[A-Z][A-Z0-9_]{0,63}$/;
3728
+ var DOCS_URL_PATTERN = /^https?:\/\//;
3708
3729
  var isRecord6 = (value) => typeof value === "object" && value !== null;
3709
3730
  var cleanString = (value, maxChars) => typeof value === "string" && value.trim().length > 0 ? value.trim().slice(0, maxChars) : null;
3710
3731
  var cleanStringArray = (value, maxItems, maxChars) => {
@@ -3728,6 +3749,17 @@ var cleanNumberArray = (value, maxItems) => {
3728
3749
  }
3729
3750
  return cleaned;
3730
3751
  };
3752
+ var cleanId = (value) => {
3753
+ if (typeof value !== "string")
3754
+ return null;
3755
+ const trimmed = value.trim().slice(0, CARD_ID_MAX_CHARS);
3756
+ return CARD_ID_PATTERN.test(trimmed) ? trimmed : null;
3757
+ };
3758
+ var applyCardId = (spec, raw) => {
3759
+ const cardId = cleanId(raw);
3760
+ if (cardId)
3761
+ spec.cardId = cardId;
3762
+ };
3731
3763
  var parseUiActions = (value) => {
3732
3764
  if (!Array.isArray(value) || value.length === 0)
3733
3765
  return;
@@ -3762,6 +3794,22 @@ var ACTIONS_SCHEMA = {
3762
3794
  },
3763
3795
  type: "array"
3764
3796
  };
3797
+ var CARD_ID_SCHEMA = {
3798
+ description: "Optional stable card identity (letters/digits/_/-, max 64 chars). Re-emit a card with the SAME cardId to update the earlier render in place instead of adding a new card.",
3799
+ type: "string"
3800
+ };
3801
+ var ACTION_BINDING_SCHEMA = {
3802
+ properties: {
3803
+ input: {
3804
+ description: "The exact tool input to send (real ids you looked up, never placeholders)",
3805
+ type: "object"
3806
+ },
3807
+ label: { description: "Button label", type: "string" },
3808
+ tool: { description: "The tool name to invoke", type: "string" }
3809
+ },
3810
+ required: ["label", "tool", "input"],
3811
+ type: "object"
3812
+ };
3765
3813
  var parseChartSpec = (input) => {
3766
3814
  if (!isRecord6(input))
3767
3815
  return null;
@@ -3801,6 +3849,7 @@ var parseChartSpec = (input) => {
3801
3849
  const actions = parseUiActions(input.actions);
3802
3850
  if (actions)
3803
3851
  spec.actions = actions;
3852
+ applyCardId(spec, input.cardId);
3804
3853
  return spec;
3805
3854
  };
3806
3855
  var parseTableSpec = (input) => {
@@ -3827,6 +3876,7 @@ var parseTableSpec = (input) => {
3827
3876
  const actions = parseUiActions(input.actions);
3828
3877
  if (actions)
3829
3878
  spec.actions = actions;
3879
+ applyCardId(spec, input.cardId);
3830
3880
  return spec;
3831
3881
  };
3832
3882
  var parseStatTilesSpec = (input) => {
@@ -3855,6 +3905,7 @@ var parseStatTilesSpec = (input) => {
3855
3905
  const actions = parseUiActions(input.actions);
3856
3906
  if (actions)
3857
3907
  spec.actions = actions;
3908
+ applyCardId(spec, input.cardId);
3858
3909
  return spec;
3859
3910
  };
3860
3911
  var parseFormField = (raw) => {
@@ -3907,6 +3958,188 @@ var parseFormSpec = (input) => {
3907
3958
  const description = cleanString(input.description, DESCRIPTION_MAX_CHARS);
3908
3959
  if (description)
3909
3960
  spec.description = description;
3961
+ applyCardId(spec, input.cardId);
3962
+ return spec;
3963
+ };
3964
+ var parseChoiceOption = (raw) => {
3965
+ if (!isRecord6(raw))
3966
+ return null;
3967
+ const id = cleanId(raw.id);
3968
+ const label = cleanString(raw.label, LABEL_MAX_CHARS);
3969
+ if (!id || !label)
3970
+ return null;
3971
+ const option = { id, label };
3972
+ const description = cleanString(raw.description, DESCRIPTION_MAX_CHARS);
3973
+ if (description)
3974
+ option.description = description;
3975
+ const badge = cleanString(raw.badge, BADGE_MAX_CHARS);
3976
+ if (badge)
3977
+ option.badge = badge;
3978
+ return option;
3979
+ };
3980
+ var parseChoiceSpec = (input) => {
3981
+ if (!isRecord6(input))
3982
+ return null;
3983
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
3984
+ const [submit] = parseUiActions([input.submit]) ?? [];
3985
+ if (!title || !submit)
3986
+ return null;
3987
+ if (!Array.isArray(input.options) || input.options.length === 0)
3988
+ return null;
3989
+ const options = [];
3990
+ const seen = new Set;
3991
+ for (const raw of input.options.slice(0, CHOICE_MAX_OPTIONS)) {
3992
+ const option = parseChoiceOption(raw);
3993
+ if (!option || seen.has(option.id))
3994
+ return null;
3995
+ seen.add(option.id);
3996
+ options.push(option);
3997
+ }
3998
+ const spec = { options, submit, title };
3999
+ const description = cleanString(input.description, DESCRIPTION_MAX_CHARS);
4000
+ if (description)
4001
+ spec.description = description;
4002
+ if (input.multi === true)
4003
+ spec.multi = true;
4004
+ applyCardId(spec, input.cardId);
4005
+ return spec;
4006
+ };
4007
+ var parseConfirmSpec = (input) => {
4008
+ if (!isRecord6(input))
4009
+ return null;
4010
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
4011
+ const consequence = cleanString(input.consequence, CONFIRM_CONSEQUENCE_MAX_CHARS);
4012
+ const confirmLabel = cleanString(input.confirmLabel, ACTION_LABEL_MAX_CHARS);
4013
+ const [confirm] = parseUiActions([input.confirm]) ?? [];
4014
+ if (!title || !consequence || !confirmLabel || !confirm)
4015
+ return null;
4016
+ const spec = { confirm, confirmLabel, consequence, title };
4017
+ const cancelLabel = cleanString(input.cancelLabel, ACTION_LABEL_MAX_CHARS);
4018
+ if (cancelLabel)
4019
+ spec.cancelLabel = cancelLabel;
4020
+ if (input.danger === true)
4021
+ spec.danger = true;
4022
+ applyCardId(spec, input.cardId);
4023
+ return spec;
4024
+ };
4025
+ var parseDiffFile = (raw, budget) => {
4026
+ if (!isRecord6(raw))
4027
+ return null;
4028
+ const path = cleanString(raw.path, DIFF_PATH_MAX_CHARS);
4029
+ if (!path || typeof raw.diff !== "string" || raw.diff.trim().length === 0) {
4030
+ return null;
4031
+ }
4032
+ const lines = raw.diff.split(/\r?\n/).map((line) => line.slice(0, DIFF_LINE_MAX_CHARS));
4033
+ const kept = lines.slice(0, Math.max(budget.remaining, 0));
4034
+ budget.remaining -= kept.length;
4035
+ const file = { diff: kept.join(`
4036
+ `), path };
4037
+ if (raw.truncated === true || kept.length < lines.length) {
4038
+ file.truncated = true;
4039
+ }
4040
+ return file;
4041
+ };
4042
+ var parseDiffSpec = (input) => {
4043
+ if (!isRecord6(input))
4044
+ return null;
4045
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
4046
+ const [apply] = parseUiActions([input.apply]) ?? [];
4047
+ if (!title || !apply)
4048
+ return null;
4049
+ if (!Array.isArray(input.files) || input.files.length === 0)
4050
+ return null;
4051
+ const budget = { remaining: DIFF_MAX_LINES };
4052
+ const files = [];
4053
+ for (const raw of input.files.slice(0, DIFF_MAX_FILES)) {
4054
+ const file = parseDiffFile(raw, budget);
4055
+ if (!file)
4056
+ return null;
4057
+ files.push(file);
4058
+ }
4059
+ const spec = { apply, files, title };
4060
+ const [reject] = parseUiActions([input.reject]) ?? [];
4061
+ if (reject)
4062
+ spec.reject = reject;
4063
+ const note = cleanString(input.note, DESCRIPTION_MAX_CHARS);
4064
+ if (note)
4065
+ spec.note = note;
4066
+ applyCardId(spec, input.cardId);
4067
+ return spec;
4068
+ };
4069
+ var parsePlanStep = (raw) => {
4070
+ if (!isRecord6(raw))
4071
+ return null;
4072
+ const id = cleanId(raw.id);
4073
+ const label = cleanString(raw.label, LABEL_MAX_CHARS);
4074
+ const status = PLAN_STEP_STATUSES.find((entry) => entry === raw.status);
4075
+ if (!id || !label || !status)
4076
+ return null;
4077
+ const step = { id, label, status };
4078
+ const detail = cleanString(raw.detail, CELL_MAX_CHARS);
4079
+ if (detail)
4080
+ step.detail = detail;
4081
+ return step;
4082
+ };
4083
+ var parsePlanSpec = (input) => {
4084
+ if (!isRecord6(input))
4085
+ return null;
4086
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
4087
+ if (!title)
4088
+ return null;
4089
+ if (!Array.isArray(input.steps) || input.steps.length === 0)
4090
+ return null;
4091
+ const steps = [];
4092
+ const seen = new Set;
4093
+ for (const raw of input.steps.slice(0, PLAN_MAX_STEPS)) {
4094
+ const step = parsePlanStep(raw);
4095
+ if (!step || seen.has(step.id))
4096
+ return null;
4097
+ seen.add(step.id);
4098
+ steps.push(step);
4099
+ }
4100
+ const spec = { steps, title };
4101
+ const note = cleanString(input.note, DESCRIPTION_MAX_CHARS);
4102
+ if (note)
4103
+ spec.note = note;
4104
+ applyCardId(spec, input.cardId);
4105
+ return spec;
4106
+ };
4107
+ var parseCredentialKey = (raw) => {
4108
+ if (!isRecord6(raw))
4109
+ return null;
4110
+ const key = typeof raw.key === "string" && ENV_KEY_PATTERN.test(raw.key) ? raw.key : null;
4111
+ if (!key)
4112
+ return null;
4113
+ const entry = { key, secret: raw.secret !== false };
4114
+ const label = cleanString(raw.label, LABEL_MAX_CHARS);
4115
+ if (label)
4116
+ entry.label = label;
4117
+ const docsUrl = cleanString(raw.docsUrl, DOCS_URL_MAX_CHARS);
4118
+ if (docsUrl && DOCS_URL_PATTERN.test(docsUrl))
4119
+ entry.docsUrl = docsUrl;
4120
+ if (typeof raw.isSet === "boolean")
4121
+ entry.isSet = raw.isSet;
4122
+ return entry;
4123
+ };
4124
+ var parseCredentialSpec = (input) => {
4125
+ if (!isRecord6(input))
4126
+ return null;
4127
+ const title = cleanString(input.title, TITLE_MAX_CHARS);
4128
+ if (!title)
4129
+ return null;
4130
+ if (!Array.isArray(input.keys) || input.keys.length === 0)
4131
+ return null;
4132
+ const keys = [];
4133
+ const seen = new Set;
4134
+ for (const raw of input.keys.slice(0, CREDENTIAL_MAX_KEYS)) {
4135
+ const entry = parseCredentialKey(raw);
4136
+ if (!entry || seen.has(entry.key))
4137
+ return null;
4138
+ seen.add(entry.key);
4139
+ keys.push(entry);
4140
+ }
4141
+ const spec = { keys, title };
4142
+ applyCardId(spec, input.cardId);
3910
4143
  return spec;
3911
4144
  };
3912
4145
  var SERIES_SCHEMA = {
@@ -3927,6 +4160,7 @@ var chartCard = {
3927
4160
  inputSchema: {
3928
4161
  properties: {
3929
4162
  actions: ACTIONS_SCHEMA,
4163
+ cardId: CARD_ID_SCHEMA,
3930
4164
  labels: {
3931
4165
  description: "Category labels \u2014 x-axis for bar/line, slice names for donut (max 24)",
3932
4166
  items: { type: "string" },
@@ -3960,6 +4194,7 @@ var tableCard = {
3960
4194
  inputSchema: {
3961
4195
  properties: {
3962
4196
  actions: ACTIONS_SCHEMA,
4197
+ cardId: CARD_ID_SCHEMA,
3963
4198
  columns: {
3964
4199
  description: "Column headers (max 8)",
3965
4200
  items: { type: "string" },
@@ -3984,6 +4219,7 @@ var statTilesCard = {
3984
4219
  inputSchema: {
3985
4220
  properties: {
3986
4221
  actions: ACTIONS_SCHEMA,
4222
+ cardId: CARD_ID_SCHEMA,
3987
4223
  tiles: {
3988
4224
  description: "The tiles (max 6)",
3989
4225
  items: {
@@ -4016,6 +4252,7 @@ var formCard = {
4016
4252
  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. Use type "password" for sensitive values (API keys, secrets, credentials) \u2014 the host renders it masked and never pre-fill a value for it.`,
4017
4253
  inputSchema: {
4018
4254
  properties: {
4255
+ cardId: CARD_ID_SCHEMA,
4019
4256
  description: {
4020
4257
  description: "Optional one-line helper text under the title",
4021
4258
  type: "string"
@@ -4071,11 +4308,229 @@ var formCard = {
4071
4308
  name: "render_form",
4072
4309
  parse: parseFormSpec
4073
4310
  };
4311
+ var choiceCard = {
4312
+ ack: "(choice card rendered inline \u2014 the member picks an option, which runs the bound tool with their selection merged in. Do not re-ask in text; wait for the selection)",
4313
+ description: "Render a structured choice card whenever the member must pick between concrete options (which plan, which duplicate record to keep, which time slot) \u2014 never ask them to 'reply 1 or 2' in prose. Give every option a stable id; on selection the host merges { choice: id } (or { choices: [ids] } when multi is true) into submit.input and invokes submit.tool exactly like a clicked action button, so put everything you already resolved into submit.input. Max 8 options.",
4314
+ inputSchema: {
4315
+ properties: {
4316
+ cardId: CARD_ID_SCHEMA,
4317
+ description: {
4318
+ description: "Optional one-line helper text under the title",
4319
+ type: "string"
4320
+ },
4321
+ multi: {
4322
+ description: "Allow selecting several options \u2014 submits { choices: [ids] } instead of { choice: id }",
4323
+ type: "boolean"
4324
+ },
4325
+ options: {
4326
+ description: "The options to choose between (max 8)",
4327
+ items: {
4328
+ properties: {
4329
+ badge: {
4330
+ description: 'Tiny annotation beside the label, e.g. "recommended"',
4331
+ type: "string"
4332
+ },
4333
+ description: {
4334
+ description: "One-line explanation of the option",
4335
+ type: "string"
4336
+ },
4337
+ id: {
4338
+ description: "Stable option id merged into submit.input on selection (letters/digits/_/-)",
4339
+ type: "string"
4340
+ },
4341
+ label: { description: "What the member sees", type: "string" }
4342
+ },
4343
+ required: ["id", "label"],
4344
+ type: "object"
4345
+ },
4346
+ type: "array"
4347
+ },
4348
+ submit: {
4349
+ ...ACTION_BINDING_SCHEMA,
4350
+ description: "The submit binding: the tool to run once a choice is made. The selection is merged into input as { choice: id } (or { choices: [ids] })"
4351
+ },
4352
+ title: { description: "The decision being made", type: "string" }
4353
+ },
4354
+ required: ["title", "options", "submit"],
4355
+ type: "object"
4356
+ },
4357
+ name: "render_choice",
4358
+ parse: parseChoiceSpec
4359
+ };
4360
+ var confirmCard = {
4361
+ ack: "(confirmation card rendered inline \u2014 NOTHING has run yet; the action only runs if the member clicks confirm. Do not claim or assume it happened; wait for the outcome)",
4362
+ description: "Render an explicit confirmation card before any destructive or irreversible action (deleting data, sending money or bulk email, cancelling a subscription). State the consequence in plain language \u2014 exactly what will happen. TRUST CONTRACT: the host invokes confirm ONLY on a real member click, never on your say-so; hosts SHOULD mint an unforgeable server-side confirmation token at click time and require it on the downstream action, so a confirmation can never be fabricated in text. Set danger: true for destructive styling. Rendering this card is never itself consent.",
4363
+ inputSchema: {
4364
+ properties: {
4365
+ cancelLabel: {
4366
+ description: 'Optional dismiss label, e.g. "Keep project"',
4367
+ type: "string"
4368
+ },
4369
+ cardId: CARD_ID_SCHEMA,
4370
+ confirm: {
4371
+ ...ACTION_BINDING_SCHEMA,
4372
+ description: "The action to run ONLY when the member clicks confirm (fully-resolved input, real ids)"
4373
+ },
4374
+ confirmLabel: {
4375
+ description: 'The confirm button label, e.g. "Delete project"',
4376
+ type: "string"
4377
+ },
4378
+ consequence: {
4379
+ description: "What will happen if confirmed, in plain language (max 500 chars)",
4380
+ type: "string"
4381
+ },
4382
+ danger: {
4383
+ description: "Render destructive (red) styling",
4384
+ type: "boolean"
4385
+ },
4386
+ title: { description: "Short question being confirmed", type: "string" }
4387
+ },
4388
+ required: ["title", "consequence", "confirmLabel", "confirm"],
4389
+ type: "object"
4390
+ },
4391
+ name: "render_confirm",
4392
+ parse: parseConfirmSpec
4393
+ };
4394
+ var diffCard = {
4395
+ ack: "(diff card rendered inline \u2014 the member reviews the changes and clicks apply or reject. Do not restate the diff in text and do not assume it was applied; wait for their decision)",
4396
+ description: "Render proposed file changes as reviewable unified diffs before applying them (max 6 files and 400 diff lines total \u2014 oversized diffs are truncated for display with truncated: true, never rejected). The diffs are DISPLAY data: the host renders the +/- coloring and nothing executes from the text. Bind apply (and optionally reject) to YOUR tools with fully-resolved input; hosts SHOULD route apply through a click-minted server-side token exactly like a confirmation card, because applying changes is destructive.",
4397
+ inputSchema: {
4398
+ properties: {
4399
+ apply: {
4400
+ ...ACTION_BINDING_SCHEMA,
4401
+ description: "The action that applies the changes when the member clicks it"
4402
+ },
4403
+ cardId: CARD_ID_SCHEMA,
4404
+ files: {
4405
+ description: "The changed files (max 6, 400 diff lines total)",
4406
+ items: {
4407
+ properties: {
4408
+ diff: {
4409
+ description: "Unified diff text for this file (display only)",
4410
+ type: "string"
4411
+ },
4412
+ path: { description: "File path being changed", type: "string" },
4413
+ truncated: {
4414
+ description: "Set true if you already cut the diff for size",
4415
+ type: "boolean"
4416
+ }
4417
+ },
4418
+ required: ["path", "diff"],
4419
+ type: "object"
4420
+ },
4421
+ type: "array"
4422
+ },
4423
+ note: {
4424
+ description: "Optional one-line note under the diffs",
4425
+ type: "string"
4426
+ },
4427
+ reject: {
4428
+ ...ACTION_BINDING_SCHEMA,
4429
+ description: "Optional action to run when the member rejects"
4430
+ },
4431
+ title: { description: "What the change set does", type: "string" }
4432
+ },
4433
+ required: ["title", "files", "apply"],
4434
+ type: "object"
4435
+ },
4436
+ name: "render_diff",
4437
+ parse: parseDiffSpec
4438
+ };
4439
+ var planCard = {
4440
+ ack: "(plan rendered inline \u2014 as you work, re-emit render_plan with the SAME cardId and updated step statuses instead of narrating progress; do not restate the steps as text)",
4441
+ description: "Render a live multi-step plan card (max 12 steps) when you start multi-step work. Display-only \u2014 it has no buttons. Set a cardId and give every step a stable id, then as you progress RE-EMIT this card with the SAME cardId and updated step statuses (pending / active / done / error): the host replaces the earlier render in place, so the member sees one live plan instead of a stack of copies.",
4442
+ inputSchema: {
4443
+ properties: {
4444
+ cardId: CARD_ID_SCHEMA,
4445
+ note: {
4446
+ description: "Optional one-line note under the steps",
4447
+ type: "string"
4448
+ },
4449
+ steps: {
4450
+ description: "The plan steps in order (max 12)",
4451
+ items: {
4452
+ properties: {
4453
+ detail: {
4454
+ description: "One-line progress or error note under the label",
4455
+ type: "string"
4456
+ },
4457
+ id: {
4458
+ description: "Stable step id \u2014 keep it identical across re-emits (letters/digits/_/-)",
4459
+ type: "string"
4460
+ },
4461
+ label: { description: "What this step does", type: "string" },
4462
+ status: { enum: [...PLAN_STEP_STATUSES], type: "string" }
4463
+ },
4464
+ required: ["id", "label", "status"],
4465
+ type: "object"
4466
+ },
4467
+ type: "array"
4468
+ },
4469
+ title: { description: "What the plan accomplishes", type: "string" }
4470
+ },
4471
+ required: ["title", "steps"],
4472
+ type: "object"
4473
+ },
4474
+ name: "render_plan",
4475
+ parse: parsePlanSpec
4476
+ };
4477
+ var credentialCard = {
4478
+ ack: "(credential request rendered inline \u2014 the member enters the values in the host UI and they are stored outside this conversation; you will receive a message naming which keys were set, never the values. Do not ask for the values in text)",
4479
+ description: "Render a credential-request card when setup needs environment values from the member (API keys, secrets, connection strings) \u2014 max 8 keys, each an ENV_STYLE name with an optional label and docs link. This card deliberately has NO submit binding and collects NOTHING through you: the host UI gathers the values and stores them outside the model loop (its own .env or secret store), then sends a continuation message naming WHICH keys were set \u2014 never the values. Never ask for secret values in plain text, and never attach values to this card (any value-like field is dropped).",
4480
+ inputSchema: {
4481
+ properties: {
4482
+ cardId: CARD_ID_SCHEMA,
4483
+ keys: {
4484
+ description: "The environment keys to request (max 8)",
4485
+ items: {
4486
+ properties: {
4487
+ docsUrl: {
4488
+ description: "Where to obtain the credential (provider dashboard URL)",
4489
+ type: "string"
4490
+ },
4491
+ isSet: {
4492
+ description: "Already configured on the host \u2014 rendered as set, with a replace affordance",
4493
+ type: "boolean"
4494
+ },
4495
+ key: {
4496
+ description: 'Environment variable name, e.g. "STRIPE_SECRET_KEY"',
4497
+ type: "string"
4498
+ },
4499
+ label: {
4500
+ description: 'Human label, e.g. "Stripe secret key"',
4501
+ type: "string"
4502
+ },
4503
+ secret: {
4504
+ description: "Mask and never echo (default true \u2014 only set false for genuinely public values)",
4505
+ type: "boolean"
4506
+ }
4507
+ },
4508
+ required: ["key"],
4509
+ type: "object"
4510
+ },
4511
+ type: "array"
4512
+ },
4513
+ title: {
4514
+ description: 'What the credentials unlock, e.g. "Connect Stripe"',
4515
+ type: "string"
4516
+ }
4517
+ },
4518
+ required: ["title", "keys"],
4519
+ type: "object"
4520
+ },
4521
+ name: "request_credentials",
4522
+ parse: parseCredentialSpec
4523
+ };
4074
4524
  var BUILTIN_UI_CARDS = [
4075
4525
  chartCard,
4076
4526
  tableCard,
4077
4527
  statTilesCard,
4078
- formCard
4528
+ formCard,
4529
+ choiceCard,
4530
+ confirmCard,
4531
+ diffCard,
4532
+ planCard,
4533
+ credentialCard
4079
4534
  ];
4080
4535
  // src/ai/ui/svg.ts
4081
4536
  var LIGHT_UI_THEME = {
@@ -5226,10 +5681,16 @@ export {
5226
5681
  resolveRenderers,
5227
5682
  renderChartSvg,
5228
5683
  providerStatusPage,
5684
+ planCard,
5229
5685
  parseUiActions,
5230
5686
  parseTableSpec,
5231
5687
  parseStatTilesSpec,
5688
+ parsePlanSpec,
5232
5689
  parseFormSpec,
5690
+ parseDiffSpec,
5691
+ parseCredentialSpec,
5692
+ parseConfirmSpec,
5693
+ parseChoiceSpec,
5233
5694
  parseChartSpec,
5234
5695
  parseAIMessage,
5235
5696
  openaiResponses,
@@ -5248,7 +5709,9 @@ export {
5248
5709
  gemini,
5249
5710
  formCard,
5250
5711
  fetchProviderApiStatus,
5712
+ diffCard,
5251
5713
  deepseek,
5714
+ credentialCard,
5252
5715
  createUiCards,
5253
5716
  createSyncConversationStore,
5254
5717
  createOAuth2ClientCredentialsTokenSource,
@@ -5256,7 +5719,9 @@ export {
5256
5719
  createConversationManager,
5257
5720
  createAIStream,
5258
5721
  createAIConnection,
5722
+ confirmCard,
5259
5723
  configureProviderResilience,
5724
+ choiceCard,
5260
5725
  chartCard,
5261
5726
  anthropic,
5262
5727
  alibaba,
@@ -5267,16 +5732,24 @@ export {
5267
5732
  STAT_TILES_MAX,
5268
5733
  ProviderError,
5269
5734
  PROVIDER_STATUS_PAGES,
5735
+ PLAN_STEP_STATUSES,
5736
+ PLAN_MAX_STEPS,
5270
5737
  LIGHT_UI_THEME,
5271
5738
  FORM_SELECT_MAX_OPTIONS,
5272
5739
  FORM_MAX_FIELDS,
5273
5740
  FORM_FIELD_TYPES,
5741
+ DIFF_MAX_LINES,
5742
+ DIFF_MAX_FILES,
5274
5743
  DARK_UI_THEME,
5744
+ CREDENTIAL_MAX_KEYS,
5745
+ CONFIRM_CONSEQUENCE_MAX_CHARS,
5746
+ CHOICE_MAX_OPTIONS,
5275
5747
  CHART_TYPES,
5276
5748
  CHART_MAX_SERIES,
5277
5749
  CHART_MAX_POINTS,
5750
+ CARD_ID_MAX_CHARS,
5278
5751
  BUILTIN_UI_CARDS
5279
5752
  };
5280
5753
 
5281
- //# debugId=F254E5F1D80164DD64756E2164756E21
5754
+ //# debugId=75AACEF004EE3AAE64756E2164756E21
5282
5755
  //# sourceMappingURL=index.js.map