@stina/extension-api 0.56.0 → 0.58.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stina/extension-api",
3
- "version": "0.56.0",
3
+ "version": "0.58.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -578,7 +578,7 @@ export function validateChatCard(card: unknown): ChatCardValidation {
578
578
  // -----------------------------------------------------------------------------
579
579
 
580
580
  /**
581
- * Render one field's type compactly: `line|bar|area`, `number?`, `{a, b?}[]`.
581
+ * Render one field's type compactly: `line|bar|area`, `number?`, `{a, b?}[≤24]`.
582
582
  *
583
583
  * Enough for a reader to write a valid value, and short enough that the whole
584
584
  * vocabulary fits in a tool description without crowding out everything else
@@ -597,7 +597,12 @@ function describeType(schema: z.ZodTypeAny): string {
597
597
  return 'component[]'
598
598
  case 'ZodArray': {
599
599
  const inner = describeType((def as { type: z.ZodTypeAny }).type)
600
- return `${inner}[]`
600
+ // The cap belongs in the vocabulary. A model writing a card from a tool's
601
+ // data has no other way to learn that a forecast takes 24 steps and not
602
+ // the 48 hours it is holding, and finds out by having the whole card
603
+ // refused — which is the expensive way to be told.
604
+ const max = (def as { maxLength?: { value: number } | null }).maxLength?.value
605
+ return typeof max === 'number' ? `${inner}[≤${max}]` : `${inner}[]`
601
606
  }
602
607
  case 'ZodObject': {
603
608
  const shape = (schema as unknown as z.AnyZodObject).shape
@@ -52,8 +52,27 @@ export interface ToolResult {
52
52
  * Validate with `validateChatCard` before returning one. A card that fails the
53
53
  * profile is dropped by the host rather than half-rendered, so a tool that
54
54
  * skips the check finds out from the user, which is the wrong end.
55
+ *
56
+ * Most tools should prefer {@link ToolResult.cardSuggestion}: a card drawn here
57
+ * is shown whatever the user asked, and a timeline of ten mails is the wrong
58
+ * answer to "did Anna write back?".
55
59
  */
56
60
  display?: ExtensionComponentData
61
+
62
+ /**
63
+ * The shape this tool thinks its answer has: one component name from the chat
64
+ * card profile, such as `"Timeline"` or `"WeatherForecast"`.
65
+ *
66
+ * A suggestion, not a drawing. It travels to the model with the result, and
67
+ * Stina decides whether to show a card at all, what goes in it, and how much of
68
+ * the data belongs there — summing three days into one figure, or answering in
69
+ * a sentence because the user asked a yes-or-no question. The tool knows the
70
+ * shape of its data; only she knows the shape of the question.
71
+ *
72
+ * A name outside the profile is dropped by the host with a warning, since it
73
+ * would send her after a component that does not exist.
74
+ */
75
+ cardSuggestion?: string
57
76
  }
58
77
 
59
78
  /**