@dbx-tools/shared-teams 0.3.39
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/README.md +73 -0
- package/index.ts +8 -0
- package/package.json +50 -0
- package/src/activity.ts +145 -0
- package/src/card.ts +125 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @dbx-tools/shared-teams
|
|
2
|
+
|
|
3
|
+
Browser-safe Adaptive Card and Bot Framework activity schemas (plus inferred
|
|
4
|
+
types) for the Teams add-on.
|
|
5
|
+
|
|
6
|
+
Import this package when a UI, Mastra tool schema, server route, or test needs
|
|
7
|
+
to validate the same Adaptive Card payloads that
|
|
8
|
+
[`@dbx-tools/teams`](../../node/teams) builds and
|
|
9
|
+
[`@dbx-tools/ui-teams`](../../ui/teams) renders.
|
|
10
|
+
|
|
11
|
+
Key features:
|
|
12
|
+
|
|
13
|
+
- High-level `CardSpec` contract - the small, model-friendly vocabulary a model
|
|
14
|
+
drafts (title, subtitle, text, facts, link actions) instead of hand-authoring
|
|
15
|
+
raw Adaptive Card JSON.
|
|
16
|
+
- `AdaptiveCard` envelope schema for the compiled Adaptive Card 1.5 document the
|
|
17
|
+
`adaptivecards` renderer consumes and Teams accepts.
|
|
18
|
+
- `CardResult` schema for the build response returned to a model or a browser.
|
|
19
|
+
- `Activity` contract for the conversation endpoint - the Bot Framework envelope
|
|
20
|
+
a Teams channel exchanges, with `CardAttachment` tagging a card as
|
|
21
|
+
`application/vnd.microsoft.card.adaptive`, plus the `toCardAttachment` /
|
|
22
|
+
`cardsOf` helpers both sides use so attachments are wrapped and read
|
|
23
|
+
identically. Unknown activity fields are preserved rather than stripped, since
|
|
24
|
+
a real channel sends far more than this reads.
|
|
25
|
+
- Model/tool-friendly schemas that avoid JSON Schema constraints known to cause
|
|
26
|
+
problems with some serving endpoints (no array `minItems`).
|
|
27
|
+
|
|
28
|
+
## Validate A Drafted Card
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { card, type CardSpec } from "@dbx-tools/shared-teams";
|
|
32
|
+
|
|
33
|
+
const spec: CardSpec = card.cardSpecSchema.parse({
|
|
34
|
+
title: "Deployment succeeded",
|
|
35
|
+
subtitle: "prod • 2m ago",
|
|
36
|
+
text: "The **api** service rolled out cleanly.",
|
|
37
|
+
facts: [
|
|
38
|
+
{ title: "Version", value: "1.4.2" },
|
|
39
|
+
{ title: "Owner", value: "alice" },
|
|
40
|
+
],
|
|
41
|
+
actions: [{ title: "View run", url: "https://example.com/runs/42" }],
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The spec schema is intentionally small so a model produces valid input rather
|
|
46
|
+
than free-form card JSON the renderer would reject.
|
|
47
|
+
|
|
48
|
+
## Validate A Compiled Card
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const result = card.cardResultSchema.parse(await response.json());
|
|
52
|
+
// result.card is a full Adaptive Card document ready to render or post to Teams.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`adaptiveCardSchema` pins the envelope every consumer relies on (`type`,
|
|
56
|
+
`$schema`, `version`, `body`); the builder in `@dbx-tools/teams` owns the exact
|
|
57
|
+
element shapes inside `body` / `actions`.
|
|
58
|
+
|
|
59
|
+
## Modules
|
|
60
|
+
|
|
61
|
+
- `card` - `cardFactSchema`, `cardActionSchema`, `cardSpecSchema`,
|
|
62
|
+
`adaptiveCardSchema`, `cardResultSchema`, the `ADAPTIVE_CARD_VERSION` /
|
|
63
|
+
`ADAPTIVE_CARD_SCHEMA_URL` constants, and flat inferred types: `CardFact`,
|
|
64
|
+
`CardAction`, `CardSpec`, `AdaptiveCard`, and `CardResult`.
|
|
65
|
+
- `activity` - `activitySchema`, `activityRequestSchema`,
|
|
66
|
+
`activityResponseSchema`, `cardAttachmentSchema`, `channelAccountSchema`,
|
|
67
|
+
`conversationAccountSchema`, the `ADAPTIVE_CARD_CONTENT_TYPE` /
|
|
68
|
+
`ACTIVITY_TYPES` constants, the `toCardAttachment` / `cardsOf` helpers, and
|
|
69
|
+
the `Activity`, `ActivityRequest`, `ActivityResponse`, `CardAttachment`,
|
|
70
|
+
`ChannelAccount`, `ConversationAccount`, and `ActivityType` types.
|
|
71
|
+
|
|
72
|
+
The schemas intentionally avoid array `.min()` constraints so they can be reused
|
|
73
|
+
as model/tool JSON schemas for serving endpoints that reject `minItems`.
|
package/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// GENERATED by projen watch - DO NOT EDIT.
|
|
2
|
+
// Regenerated from the exporting modules in ./src.
|
|
3
|
+
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
|
+
|
|
5
|
+
export * as activity from "./src/activity";
|
|
6
|
+
export * as card from "./src/card";
|
|
7
|
+
export type { ActivityType, ChannelAccount, ConversationAccount, CardAttachment, Activity, ActivityRequest, ActivityResponse } from "./src/activity";
|
|
8
|
+
export type { CardFact, CardAction, CardSpec, AdaptiveCard, CardResult } from "./src/card";
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dbx-tools/shared-teams",
|
|
3
|
+
"repository": {
|
|
4
|
+
"type": "git",
|
|
5
|
+
"url": "git+https://github.com/reggie-db/dbx-tools.git",
|
|
6
|
+
"directory": "workspaces/shared/teams"
|
|
7
|
+
},
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"@types/node": "^24.6.0",
|
|
10
|
+
"tsx": "^4.23.0",
|
|
11
|
+
"typescript": "^5.9.3"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"zod": "4.3.6",
|
|
15
|
+
"@dbx-tools/shared-core": "0.3.39"
|
|
16
|
+
},
|
|
17
|
+
"main": "index.ts",
|
|
18
|
+
"license": "UNLICENSED",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"version": "0.3.39",
|
|
23
|
+
"types": "index.ts",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": "./index.ts",
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"index.ts",
|
|
31
|
+
"src"
|
|
32
|
+
],
|
|
33
|
+
"dbxToolsConfig": {
|
|
34
|
+
"tags": [
|
|
35
|
+
"shared"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"pnpm exec projen\".",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "projen build",
|
|
41
|
+
"compile": "projen compile",
|
|
42
|
+
"default": "projen default",
|
|
43
|
+
"package": "projen package",
|
|
44
|
+
"post-compile": "projen post-compile",
|
|
45
|
+
"pre-compile": "projen pre-compile",
|
|
46
|
+
"test": "projen test",
|
|
47
|
+
"watch": "projen watch",
|
|
48
|
+
"projen": "projen"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/activity.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-format contract for the Teams conversation endpoint: the Bot Framework
|
|
3
|
+
* `Activity` a Teams-like client posts, and the activity (carrying Adaptive Card
|
|
4
|
+
* attachments) the agent answers with.
|
|
5
|
+
*
|
|
6
|
+
* Why this shape rather than a bespoke `{ message }` envelope: Teams does not
|
|
7
|
+
* speak a custom chat API. A channel delivers a bot a JSON `Activity` and reads
|
|
8
|
+
* back activities whose `attachments` carry
|
|
9
|
+
* `application/vnd.microsoft.card.adaptive` payloads. Modelling the real
|
|
10
|
+
* protocol here means the same endpoint that backs the in-repo preview chat is
|
|
11
|
+
* the one a Bot Framework channel could call - the analogue of how the Mastra
|
|
12
|
+
* plugin exposes MCP at a path rather than inventing a tool-call API.
|
|
13
|
+
*
|
|
14
|
+
* Only the subset the conversation endpoint actually reads or writes is
|
|
15
|
+
* modelled. `Activity` is a large, evolving envelope, so unknown fields are
|
|
16
|
+
* PRESERVED rather than stripped (see {@link activitySchema}) - a channel sends
|
|
17
|
+
* far more than this, and dropping it would corrupt a round-trip.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
import { adaptiveCardSchema } from "./card";
|
|
24
|
+
|
|
25
|
+
/** The attachment content type Teams uses for an Adaptive Card. */
|
|
26
|
+
export const ADAPTIVE_CARD_CONTENT_TYPE = "application/vnd.microsoft.card.adaptive";
|
|
27
|
+
|
|
28
|
+
/** Bot Framework activity types this endpoint understands. */
|
|
29
|
+
export const ACTIVITY_TYPES = ["message", "conversationUpdate", "typing"] as const;
|
|
30
|
+
|
|
31
|
+
/** A Bot Framework activity type. */
|
|
32
|
+
export type ActivityType = (typeof ACTIVITY_TYPES)[number];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A participant in a conversation. `id` is the stable key; `name` is the
|
|
36
|
+
* display label a chat transcript shows.
|
|
37
|
+
*/
|
|
38
|
+
export const channelAccountSchema = z.object({
|
|
39
|
+
id: z.string().describe("Stable id of the user or bot."),
|
|
40
|
+
name: z.string().optional().describe("Display name shown in the transcript."),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
/** A conversation participant (user or bot). */
|
|
44
|
+
export type ChannelAccount = z.infer<typeof channelAccountSchema>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The conversation an activity belongs to. The `id` is what maps onto a Mastra
|
|
48
|
+
* memory thread, so a client that keeps sending the same id gets a continuous
|
|
49
|
+
* conversation.
|
|
50
|
+
*/
|
|
51
|
+
export const conversationAccountSchema = z.object({
|
|
52
|
+
id: z.string().describe("Conversation id; maps to the agent's memory thread."),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/** The conversation an activity belongs to. */
|
|
56
|
+
export type ConversationAccount = z.infer<typeof conversationAccountSchema>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* An Adaptive Card attachment - how a card reaches a Teams client. The card
|
|
60
|
+
* document lives under `content`, tagged by `contentType`.
|
|
61
|
+
*/
|
|
62
|
+
export const cardAttachmentSchema = z.object({
|
|
63
|
+
contentType: z.literal(ADAPTIVE_CARD_CONTENT_TYPE),
|
|
64
|
+
content: adaptiveCardSchema.describe("The compiled Adaptive Card document."),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/** An Adaptive Card attachment on an activity. */
|
|
68
|
+
export type CardAttachment = z.infer<typeof cardAttachmentSchema>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A Bot Framework activity.
|
|
72
|
+
*
|
|
73
|
+
* `.passthrough()` is deliberate: a real channel sends `channelId`,
|
|
74
|
+
* `serviceUrl`, `timestamp`, `replyToId`, `channelData` and more. This endpoint
|
|
75
|
+
* reads only what it needs, but an unknown field is part of the caller's
|
|
76
|
+
* envelope and is kept so a client can round-trip its own metadata.
|
|
77
|
+
*/
|
|
78
|
+
export const activitySchema = z
|
|
79
|
+
.object({
|
|
80
|
+
type: z.enum(ACTIVITY_TYPES).describe("Activity type; `message` carries user text."),
|
|
81
|
+
id: z.string().optional().describe("Activity id, assigned by the sender."),
|
|
82
|
+
text: z.string().optional().describe("Message text, present on a `message` activity."),
|
|
83
|
+
from: channelAccountSchema.optional().describe("Who sent the activity."),
|
|
84
|
+
recipient: channelAccountSchema.optional().describe("Who the activity is addressed to."),
|
|
85
|
+
conversation: conversationAccountSchema
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("Conversation the activity belongs to."),
|
|
88
|
+
attachments: z
|
|
89
|
+
.array(cardAttachmentSchema)
|
|
90
|
+
.optional()
|
|
91
|
+
.describe("Adaptive Card attachments carried by the activity."),
|
|
92
|
+
timestamp: z.string().optional().describe("ISO-8601 time the activity was created."),
|
|
93
|
+
})
|
|
94
|
+
.passthrough();
|
|
95
|
+
|
|
96
|
+
/** A Bot Framework activity. */
|
|
97
|
+
export type Activity = z.infer<typeof activitySchema>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The request body the conversation endpoint accepts: an inbound activity plus
|
|
101
|
+
* optional routing hints that are NOT part of the Bot Framework envelope
|
|
102
|
+
* (which agent to run, which serving model to use). Keeping them as siblings of
|
|
103
|
+
* `activity` leaves the protocol payload untouched.
|
|
104
|
+
*/
|
|
105
|
+
export const activityRequestSchema = z.object({
|
|
106
|
+
activity: activitySchema.describe("The inbound Bot Framework activity."),
|
|
107
|
+
agentId: z
|
|
108
|
+
.string()
|
|
109
|
+
.optional()
|
|
110
|
+
.describe("Mastra agent to answer with. Defaults to the plugin's default agent."),
|
|
111
|
+
model: z.string().optional().describe("Optional serving-endpoint override for this turn."),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/** A request to the Teams conversation endpoint. */
|
|
115
|
+
export type ActivityRequest = z.infer<typeof activityRequestSchema>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The endpoint's response: the activities to append to the transcript. An array
|
|
119
|
+
* because one turn may answer with several activities (Teams itself allows a
|
|
120
|
+
* bot to send more than one reply), and because a future streaming/typing
|
|
121
|
+
* variant can grow into the same shape without a breaking change.
|
|
122
|
+
*/
|
|
123
|
+
export const activityResponseSchema = z.object({
|
|
124
|
+
activities: z.array(activitySchema).describe("Activities the bot replies with."),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
/** The response from the Teams conversation endpoint. */
|
|
128
|
+
export type ActivityResponse = z.infer<typeof activityResponseSchema>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Wrap a compiled Adaptive Card as a Teams attachment.
|
|
132
|
+
*
|
|
133
|
+
* Browser-safe and shared so the server (building a reply) and any client
|
|
134
|
+
* (rendering an optimistic local activity) tag attachments identically.
|
|
135
|
+
*/
|
|
136
|
+
export const toCardAttachment = (card: z.infer<typeof adaptiveCardSchema>): CardAttachment => ({
|
|
137
|
+
contentType: ADAPTIVE_CARD_CONTENT_TYPE,
|
|
138
|
+
content: card,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/** Read the Adaptive Card documents carried by an activity, if any. */
|
|
142
|
+
export const cardsOf = (activity: Activity): z.infer<typeof adaptiveCardSchema>[] =>
|
|
143
|
+
(activity.attachments ?? [])
|
|
144
|
+
.filter((attachment) => attachment.contentType === ADAPTIVE_CARD_CONTENT_TYPE)
|
|
145
|
+
.map((attachment) => attachment.content);
|
package/src/card.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-format contract for the Teams add-on: the semantic card a model drafts
|
|
3
|
+
* and the Adaptive Card document that drafting compiles to. Pure (zod +
|
|
4
|
+
* inferred types, no Node-only imports) so the server-side card builder, the
|
|
5
|
+
* Mastra tool, and the React Adaptive Cards renderer all validate / type
|
|
6
|
+
* against one definition.
|
|
7
|
+
*
|
|
8
|
+
* The model does NOT hand-author raw Adaptive Card JSON. It describes a card in
|
|
9
|
+
* a small, high-level vocabulary ({@link CardSpec}) - a title, some text/fact
|
|
10
|
+
* blocks, and optional link actions - and the builder compiles that into a
|
|
11
|
+
* valid Adaptive Card 1.5 document ({@link AdaptiveCard}). Keeping the model's
|
|
12
|
+
* surface small avoids the two failure modes of free-form card JSON: an invalid
|
|
13
|
+
* schema the renderer rejects, and a card that renders but ignores Teams' host
|
|
14
|
+
* constraints.
|
|
15
|
+
*
|
|
16
|
+
* Array fields intentionally avoid `.min()` / `.nonempty()`: those emit
|
|
17
|
+
* `minItems` in the JSON schema, which some Model Serving endpoints reject
|
|
18
|
+
* ("array types do not support minItems") when the schema is forwarded as a
|
|
19
|
+
* tool definition.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
|
|
26
|
+
/** The Adaptive Card schema version the builder targets. Teams supports 1.5. */
|
|
27
|
+
export const ADAPTIVE_CARD_VERSION = "1.5";
|
|
28
|
+
|
|
29
|
+
/** The Adaptive Card `$schema` URL a well-formed document declares. */
|
|
30
|
+
export const ADAPTIVE_CARD_SCHEMA_URL = "http://adaptivecards.io/schemas/adaptive-card.json";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A single labelled fact, rendered as a row in an Adaptive Card `FactSet`.
|
|
34
|
+
* Facts are the right shape for compact key/value detail (status, owner, due
|
|
35
|
+
* date) that would be noise as prose.
|
|
36
|
+
*/
|
|
37
|
+
export const cardFactSchema = z.object({
|
|
38
|
+
title: z.string().describe('Fact label shown on the left (e.g. "Status", "Owner").'),
|
|
39
|
+
value: z.string().describe('Fact value shown on the right (e.g. "Open", "alice").'),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/** A labelled key/value fact in a {@link CardSpec}. */
|
|
43
|
+
export type CardFact = z.infer<typeof cardFactSchema>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* An action button rendered under the card body. Only an open-URL action is
|
|
47
|
+
* modelled: it is the one action that is safe to render in any host without a
|
|
48
|
+
* back-end wired up, and it covers the common "here is the link" case.
|
|
49
|
+
*/
|
|
50
|
+
export const cardActionSchema = z.object({
|
|
51
|
+
title: z.string().describe('Button label (e.g. "Open ticket", "View run").'),
|
|
52
|
+
url: z
|
|
53
|
+
.string()
|
|
54
|
+
.describe("Absolute https URL the button opens when tapped (an Action.OpenUrl target)."),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/** A link action button in a {@link CardSpec}. */
|
|
58
|
+
export type CardAction = z.infer<typeof cardActionSchema>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The high-level card a model asks to build (the tool input). Deliberately
|
|
62
|
+
* small: a heading, optional supporting text, optional facts, and optional link
|
|
63
|
+
* buttons. The builder turns this into a full Adaptive Card document.
|
|
64
|
+
*/
|
|
65
|
+
export const cardSpecSchema = z.object({
|
|
66
|
+
title: z.string().describe("Card heading, shown bold at the top of the card."),
|
|
67
|
+
subtitle: z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("Optional lighter subheading under the title (e.g. a category or timestamp)."),
|
|
71
|
+
text: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe(
|
|
75
|
+
[
|
|
76
|
+
"Optional body text under the heading. A limited Markdown subset is",
|
|
77
|
+
"supported by the Teams host: **bold**, _italic_, links, and '-' bullet",
|
|
78
|
+
"lists. Do NOT use headings, tables, or fenced code blocks - use the",
|
|
79
|
+
"`facts` array for tabular key/value detail instead.",
|
|
80
|
+
].join(" "),
|
|
81
|
+
),
|
|
82
|
+
facts: z
|
|
83
|
+
.array(cardFactSchema)
|
|
84
|
+
.optional()
|
|
85
|
+
.describe("Optional key/value rows rendered as a FactSet (label on the left, value right)."),
|
|
86
|
+
actions: z
|
|
87
|
+
.array(cardActionSchema)
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Optional link buttons rendered under the body, each opening a URL."),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/** The validated semantic card a model asked to build. */
|
|
93
|
+
export type CardSpec = z.infer<typeof cardSpecSchema>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The compiled Adaptive Card document - the JSON the `adaptivecards` renderer
|
|
97
|
+
* consumes. Typed loosely (`elements` / `actions` as record arrays) because the
|
|
98
|
+
* full Adaptive Card schema is large and host-versioned; the builder owns the
|
|
99
|
+
* exact element shapes and this contract only pins the envelope every consumer
|
|
100
|
+
* relies on (`type`, `version`, `body`).
|
|
101
|
+
*/
|
|
102
|
+
export const adaptiveCardSchema = z.object({
|
|
103
|
+
type: z.literal("AdaptiveCard"),
|
|
104
|
+
$schema: z.string(),
|
|
105
|
+
version: z.string(),
|
|
106
|
+
body: z.array(z.record(z.string(), z.unknown())),
|
|
107
|
+
actions: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
/** A compiled Adaptive Card document ready to render or post to Teams. */
|
|
111
|
+
export type AdaptiveCard = z.infer<typeof adaptiveCardSchema>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The result the card tool returns: the compiled Adaptive Card plus the
|
|
115
|
+
* `title` echoed back for a caller that wants a label without re-reading the
|
|
116
|
+
* document. Kept separate from {@link AdaptiveCard} so the tool output stays
|
|
117
|
+
* additive.
|
|
118
|
+
*/
|
|
119
|
+
export const cardResultSchema = z.object({
|
|
120
|
+
title: z.string().describe("The card title, echoed for convenience."),
|
|
121
|
+
card: adaptiveCardSchema.describe("The compiled Adaptive Card document."),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/** The result of building a card. */
|
|
125
|
+
export type CardResult = z.infer<typeof cardResultSchema>;
|