@xpert-ai/plugin-sdk 3.18.7 → 3.20.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/MIDDLEWARE_APPS.md +71 -0
  3. package/README.md +57 -0
  4. package/RESOURCE-CARDS-VALIDATION.md +51 -0
  5. package/RESOURCE-CARDS.md +361 -0
  6. package/TOOL-IMAGES.md +85 -0
  7. package/agent-results.cjs.default.js +1 -0
  8. package/agent-results.cjs.js +20 -0
  9. package/agent-results.cjs.mjs +2 -0
  10. package/agent-results.d.ts +1 -0
  11. package/agent-results.esm.js +4 -0
  12. package/index.cjs.js +586 -162
  13. package/index.esm.js +530 -167
  14. package/model-provider.cjs.js +5 -0
  15. package/model-provider.esm.js +5 -1
  16. package/package.json +8 -2
  17. package/results.cjs.js +50 -0
  18. package/results.esm.js +46 -0
  19. package/runtime-capabilities.md +35 -0
  20. package/src/agent-results.d.ts +2 -0
  21. package/src/index.d.ts +5 -0
  22. package/src/lib/agent/handoff/agent-chat.contract.d.ts +6 -1
  23. package/src/lib/agent/handoff/agent-runtime-message.contract.d.ts +319 -0
  24. package/src/lib/agent/handoff/index.d.ts +1 -0
  25. package/src/lib/agent/index.d.ts +2 -0
  26. package/src/lib/agent/middleware/capabilities/assistant-task.d.ts +55 -20
  27. package/src/lib/agent/middleware/index.d.ts +1 -0
  28. package/src/lib/agent/middleware/model-requirements.d.ts +9 -0
  29. package/src/lib/agent/middleware/strategy.interface.d.ts +4 -0
  30. package/src/lib/agent/middleware/types.d.ts +20 -3
  31. package/src/lib/agent/resource-card.d.ts +3 -0
  32. package/src/lib/agent/runtime/activity.d.ts +6 -0
  33. package/src/lib/agent/runtime/capability.d.ts +37 -0
  34. package/src/lib/agent/runtime/cli-model-profile.d.ts +62 -0
  35. package/src/lib/agent/runtime/dispatch.d.ts +517 -0
  36. package/src/lib/agent/runtime/execution-runner.d.ts +66 -0
  37. package/src/lib/agent/runtime/index.d.ts +10 -0
  38. package/src/lib/agent/runtime/model-execution.d.ts +15 -0
  39. package/src/lib/agent/runtime/results.d.ts +335 -0
  40. package/src/lib/agent/runtime/strategy.d.ts +53 -0
  41. package/src/lib/agent/runtime/task-wait.d.ts +35 -0
  42. package/src/lib/agent/runtime/types.d.ts +156 -0
  43. package/src/lib/ai-model/ai-model-provider.interface.d.ts +2 -0
  44. package/src/lib/ai-model/ai-model.d.ts +2 -0
  45. package/src/lib/ai-model/index.d.ts +3 -0
  46. package/src/lib/ai-model/llm.d.ts +4 -2
  47. package/src/lib/ai-model/native-model.d.ts +22 -0
  48. package/src/lib/ai-model/realtime.d.ts +36 -0
  49. package/src/lib/ai-model/token-usage.d.ts +13 -0
  50. package/src/lib/assistant-capability/index.d.ts +42 -0
  51. package/src/lib/connector/runtime-capability.d.ts +2 -0
  52. package/src/lib/connector/strategy.interface.d.ts +8 -0
  53. package/src/lib/core/context/request-context.d.ts +6 -0
  54. package/src/lib/core/strategy-bus.d.ts +0 -3
  55. package/src/lib/evolution/runtime-capability.d.ts +2 -1
  56. package/src/lib/integration/strategy.interface.d.ts +22 -0
  57. package/src/lib/mcp/app.d.ts +14 -1
  58. package/src/lib/project-task/index.d.ts +66 -0
  59. package/src/lib/project-type/index.d.ts +71 -0
  60. package/src/lib/resource-card-provider/index.d.ts +3 -0
  61. package/src/lib/resource-card-provider/provider.decorator.d.ts +4 -0
  62. package/src/lib/resource-card-provider/provider.registry.d.ts +14 -0
  63. package/src/lib/resource-card-provider/types.d.ts +36 -0
  64. package/src/lib/resource-card.d.ts +6 -0
  65. package/src/lib/runtime/capabilities/index.d.ts +1 -0
  66. package/src/lib/runtime/capabilities/knowledge-graph.d.ts +59 -0
  67. package/src/lib/runtime/capabilities/knowledgebase-documents.d.ts +21 -0
  68. package/src/lib/runtime/capabilities/knowledgebase.d.ts +8 -3
  69. package/src/lib/runtime/capabilities/project-access.d.ts +2 -1
  70. package/src/lib/runtime/capabilities/project-provisioning.d.ts +13 -0
  71. package/src/lib/runtime/capabilities/tool-images.d.ts +24 -0
  72. package/src/lib/runtime/runtime-scope.d.ts +7 -1
  73. package/src/lib/sandbox/execution-environment.d.ts +12 -0
  74. package/src/lib/sandbox/execution.d.ts +13 -0
  75. package/src/lib/sandbox/index.d.ts +1 -0
  76. package/src/lib/sandbox/managed-service.d.ts +1 -0
  77. package/src/lib/sandbox/protocol.d.ts +2 -0
  78. package/src/lib/tool-provider/types.d.ts +6 -0
  79. package/src/lib/types.d.ts +2 -1
  80. package/src/lib/workflow/trigger/strategy.interface.d.ts +2 -1
@@ -0,0 +1,361 @@
1
+ # Conversation Resource Cards
2
+
3
+ A Resource Card is a persisted receipt for a business resource. File Artifacts remain the content/version/sharing model. Creating a scheduler or Project does not create an empty Artifact. A card may include `resource.artifactId` when it represents an existing file Artifact.
4
+
5
+ ## Ownership and lifecycle
6
+
7
+ | Layer | Responsibility |
8
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
9
+ | Domain service / Runtime | Commit business changes and execution facts; own authorization, decisions and revisions. |
10
+ | Plugin ResourceCard Provider | Construct the initial card and resolve its current, authorized presentation using the same formatter. |
11
+ | Tool / middleware | Emit the card after the business commit, using the active RunnableConfig. |
12
+ | Host | Persist and bind the card to the actual reply; discover providers, batch refreshes, validate identities and isolate failures. |
13
+ | ChatKit / Workbench | Render and reconcile generic cards; authorize navigation through the registered View. |
14
+
15
+ `createCard()` is a plugin-owned typed method, not an additional SDK interface or
16
+ registry operation. Only `resolveMany()` is standardized, and registering a
17
+ Provider remains optional. A static card does not need a Provider. Providers
18
+ format and read facts; they do not become the owner of business state.
19
+
20
+ ```mermaid
21
+ flowchart LR
22
+ D[Committed domain result] --> P[Provider.createCard]
23
+ P --> E[emitResourceCard]
24
+ E --> M[Host binds and persists message card]
25
+ M --> C[ChatKit generic card]
26
+ A[Thread activity subscription] --> H[Host refresh command / registry]
27
+ H --> R[Provider.resolveMany]
28
+ R -. reuses formatter .-> P
29
+ R --> S[Host validates read projection]
30
+ S --> C
31
+ ```
32
+
33
+ ## Emit after a successful tool mutation
34
+
35
+ ```ts
36
+ import { emitResourceCard } from '@xpert-ai/plugin-sdk'
37
+
38
+ const task = await tasks.create(input)
39
+ try {
40
+ await emitResourceCard(
41
+ {
42
+ resource: { namespace: 'platform', type: 'scheduled-task', id: task.id },
43
+ title: task.name,
44
+ description: `${task.scheduleDescription} · ${task.timeZone || 'UTC'}`,
45
+ icon: { type: 'emoji', value: '◷' },
46
+ open: {
47
+ target: 'workbench.view',
48
+ viewKey: 'platform.scheduler__detail',
49
+ selectionId: task.id
50
+ }
51
+ },
52
+ runnableConfig
53
+ )
54
+ } catch (error) {
55
+ logger.warn('Task created; resource receipt delivery failed', error)
56
+ }
57
+ return task
58
+ ```
59
+
60
+ Tools, middleware and plugin code can use the same helper inside an active Agent run. Pass its RunnableConfig to preserve callback context. The helper dispatches `ON_CHAT_EVENT`; the host binds the actual reply and execution, normalizes to a `MESSAGE` event and persists `type: 'resource_card'` content before forwarding. Emitters cannot choose message ownership. A presentation failure must not report a committed business mutation as failed or trigger another creation.
61
+
62
+ `resource.namespace + resource.type + resource.id` identifies the receipt **within a single reply**. Re-emitting replaces its snapshot at the same position. Other replies keep their own snapshots. The canonical part ID is produced by `resourceCardId`; callers should not concatenate an ID themselves. Text extraction and model history exclude these parts. Branches retain the content with their owning messages, and history loading never triggers navigation.
63
+
64
+ Targets are an allowlisted JSON protocol:
65
+
66
+ - `workbench.view`: required `viewKey`, optional `selectionId`, optional `parameters` containing scalars or scalar arrays.
67
+ - `assistant.project`: additionally requires the **platform Project ID** in `projectId`, and a `viewKey`.
68
+ - `workbench.file`: required `viewKey`, `fileKey` and `targetId`; opens a file preview with an original-file download action. Optional `previewFile` supplies a separate preview reference.
69
+
70
+ Targets cannot contain URLs, scripts or arbitrary client commands. Icons use the existing sanitized SVG, emoji or font renderer. Navigation and resource queries still pass through the host's View availability and access checks. An unavailable Workbench, missing View or denied/deleted resource produces feedback instead of an automatic fallback.
71
+
72
+ By default the card title/description is a snapshot. Opening loads current business state. Types that register the optional ResourceCard Provider below opt in to live refresh while a conversation is observed. Explicit scheduler-card navigation remembers the selected task per conversation and supports browser refresh/back/forward.
73
+
74
+ ## Optional live resource state
75
+
76
+ Plugins can opt exact resource types into live refresh with `ResourceCardProvider`
77
+ and `IResourceCardProvider`. Existing emitters need no change. Register the class
78
+ in the plugin module's `providers`; the host discovers it through the existing
79
+ StrategyBus lifecycle. Do not register a CQRS handler or a registry in the plugin.
80
+
81
+ ```ts
82
+ import { Injectable } from '@nestjs/common'
83
+ import type { ConversationResourceCard } from '@xpert-ai/contracts'
84
+ import {
85
+ ResourceCardProvider,
86
+ type IResourceCardProvider,
87
+ type ResourceCardContext,
88
+ type ResourceCardReadRequest,
89
+ type ResourceCardResolution
90
+ } from '@xpert-ai/plugin-sdk'
91
+
92
+ @Injectable()
93
+ @ResourceCardProvider({ namespace: 'my-plugin', type: 'report' })
94
+ export class ReportCardProvider implements IResourceCardProvider {
95
+ constructor(private readonly reports: ReportsService) {}
96
+
97
+ createCard(report: { id: string; title: string; description: string }): ConversationResourceCard {
98
+ return {
99
+ resource: { namespace: 'my-plugin', type: 'report', id: report.id },
100
+ title: report.title,
101
+ description: report.description,
102
+ open: { target: 'workbench.view', viewKey: 'my-plugin__reports', selectionId: report.id }
103
+ }
104
+ }
105
+
106
+ async resolveMany(
107
+ context: ResourceCardContext,
108
+ requests: readonly ResourceCardReadRequest[]
109
+ ): Promise<ResourceCardResolution[]> {
110
+ // ReportsService is the plugin's domain service. This read must enforce
111
+ // tenant, organization, user and resource access and honor context.signal.
112
+ const summaries = await this.reports.readAuthorizedSummaries(context, [
113
+ ...new Set(requests.map(({ card }) => card.resource.id))
114
+ ])
115
+ return requests.map(({ key, card }) => {
116
+ const summary = summaries.get(card.resource.id)
117
+ return summary === undefined
118
+ ? { key, status: 'unavailable', reason: 'forbidden' }
119
+ : {
120
+ key,
121
+ status: 'resolved',
122
+ card: this.createCard({ id: card.resource.id, title: card.title, description: summary })
123
+ }
124
+ })
125
+ }
126
+ }
127
+ ```
128
+
129
+ The decorator accepts multiple `{ namespace, type }` arguments. Each pair belongs
130
+ to one provider owner across installation scopes; another plugin cannot shadow
131
+ it. Same-plugin instances follow the existing organization, tenant, system and
132
+ builtin scope resolution. Refresh/uninstall removes that installation's routes.
133
+
134
+ Keep initial card construction in the same provider (for example, a typed
135
+ `createCard()` method), and reuse it from both tool receipts and `resolveMany()`.
136
+ Creation inputs belong to the plugin; the SDK only standardizes the optional
137
+ refresh contract. Tools remain responsible for emitting the returned card with
138
+ `emitResourceCard(provider.createCard(committedResult), runnableConfig)` after
139
+ the business commit, and isolating emission failures as in the first example.
140
+
141
+ The host calls `resolveMany` once per matched provider per snapshot, only for
142
+ cards already present in the authorized conversation. Context identity comes
143
+ from the host; `projectId` is optional. Requests include persisted message and
144
+ execution bindings for resources that require those association checks. Echo
145
+ `key` unchanged and return one result per request, including repeated resources
146
+ in different messages. Missing resources return `not_found`; denied resources
147
+ return `forbidden`. Do not return private diagnostics in presentation data.
148
+
149
+ Providers only read durable business state. Do not start jobs, decide acceptance,
150
+ write message history or poll a Computer CLI for each viewer. Use batched reads.
151
+ The host applies a two-second deadline and abort signal per provider, validates
152
+ returned card/resource identities, and supplies the original message bindings.
153
+ Invalid, missing, duplicated or failed responses receive a generic refresh
154
+ failure description; unavailable results receive a localized unavailable
155
+ message. Other providers and run discovery continue. Ignore late results and
156
+ honor the abort signal in cancellable I/O; the host cannot forcibly stop plugin
157
+ code or an uncancellable database call.
158
+
159
+ Live projections are viewer-specific and do not rewrite stored receipts or
160
+ create new cards. Removing the provider falls back to the saved receipt; clicking
161
+ still uses the View's access checks. Card navigation and result payloads keep the
162
+ existing ChatKit protocol. The updated ChatKit UI displays all committed cards
163
+ during streaming, without business-namespace-specific presentation branches.
164
+
165
+ The host has one `RefreshConversationResourceCardsCommand` handler in the message
166
+ module. `ThreadActivityService` supplies references; the handler dispatches
167
+ through `ResourceCardProviderRegistry`. The built-in Project Task Provider uses
168
+ this same path and retains its task, invocation and pinned-review checks.
169
+
170
+ ## Implemented scope and release boundary
171
+
172
+ The optional Provider path covers creation, persisted message binding, scoped
173
+ registration/replacement/removal, authorized batched refresh, failure isolation
174
+ and generic ChatKit display/navigation. `ProjectTaskCardProvider` is the built-in
175
+ implementation: delegation and refresh both call its `createCard()`; task
176
+ creation emits only a tool step, and each implementation/review attempt emits
177
+ its own execution card. Runtime success is distinct from business acceptance.
178
+
179
+ This is not a custom React/component extension API. A plugin supplies the shared
180
+ card data and a registered View target. Independent execution viewers remain
181
+ separate features. Activity currently polls full snapshots; there is no generic
182
+ card outbox, pagination or reconstruction of missing historical receipts.
183
+ Transactional first-conversation Project receipts below have their own durable
184
+ attachment mechanism; ordinary `emitResourceCard` does not inherit it.
185
+
186
+ Deploy the updated host/plugin SDK and matching ChatKit app assets together.
187
+ Local builds or copied app assets do not publish npm packages. After deployment,
188
+ reload the host once, then test a fresh delegation without refreshing during
189
+ execution: one card appears, its status updates, and the resumed Agent reply
190
+ streams automatically. Test Provider registration/refresh/removal with a
191
+ non-project fixture separately; a Project Task run alone does not prove an
192
+ external plugin's installation lifecycle.
193
+
194
+ ## Composable content and image groups
195
+
196
+ Use the optional `content` array to compose ordered presentation blocks inside one resource card. Each block can have a `title`:
197
+
198
+ | Kind | Items | Presentation |
199
+ | --------------- | ----------------------------- | ------------------------------------------------------------------- |
200
+ | `image-gallery` | `images: ResourceCardImage[]` | One responsive row initially; More expands the remaining images. |
201
+ | `file-list` | `files: ResourceCardFile[]` | File titles, optional descriptions and authorized download actions. |
202
+ | `fields` | `fields: ResourceCardField[]` | Read-only label/value pairs. |
203
+
204
+ For example, add this `content` property to the card passed to `emitResourceCard`:
205
+
206
+ ```ts
207
+ content: [
208
+ { kind: 'fields', fields: [{ label: '状态', value: '已完成' }] },
209
+ {
210
+ kind: 'image-gallery',
211
+ title: '施工配图',
212
+ images: [
213
+ {
214
+ id: 'site-layout',
215
+ title: '施工现场平面布置图',
216
+ alt: '施工分区、出入口和运输路线',
217
+ file: {
218
+ viewKey: 'bid.view-provider__bid.studio',
219
+ fileKey: 'bid-project-image',
220
+ targetId: `${projectId}:${assetVersionId}`
221
+ }
222
+ }
223
+ ]
224
+ }
225
+ ]
226
+ ```
227
+
228
+ New producers emit `content`, not top-level `images`. The reader converts historical top-level `images` only when `content` is absent. Image and file IDs must be unique within their block. The parser accepts up to 32 blocks and 100 items per block; these are transport bounds, not business image quotas. Invalid or unknown blocks are skipped independently.
229
+
230
+ Reference committed, immutable file versions. The View must declare the file key and implement its authorized resolver. Image previews require the `preview` purpose; download actions require `download`. Do not store signed URLs, private file paths, credentials or base64 pixels in a card.
231
+
232
+ ChatKit resolves visible thumbnails through the SDK View file-access session/grant API, reads authorized bytes and releases the session. Collapsed images are loaded only after expansion. Clicking an image opens a file preview with its own URL lifetime and an original-file download action. Failed previews can be retried without rerunning the business tool.
233
+
234
+ Committed cards appear as soon as their events arrive, including while the Assistant reply is streaming. Later events upsert the same card instead of adding duplicates. Cards render independently of text message bubbles and remain available in history.
235
+
236
+ The stream mapper binds an external Assistant's actual execution from runtime metadata; the root reply owns persistence. External Assistant transcripts retain cards for that execution and its descendants without counting them as tools or process steps. Plugins cannot supply either owner identity in the card payload.
237
+
238
+ For Bid, `bid_submit_role_task` emits one group only after the illustration task is accepted, including native writing and queued post-writing tasks. Repeated submissions upsert the same group in the current reply. Unaccepted candidates and omitted needs are excluded. An emission failure never changes the accepted submission result.
239
+
240
+ This extension requires coordinated ChatKit types/UI and host contracts/SDK/server updates before deploying a consuming plugin. Source tests do not upgrade installed packages.
241
+
242
+ ## File preview and original download
243
+
244
+ Use `workbench.file` for an exported document's Open action. It opens the file preview rather than the business View:
245
+
246
+ ```ts
247
+ open: {
248
+ target: 'workbench.file',
249
+ viewKey: 'bid.view-provider__bid.studio',
250
+ fileKey: 'bid-export-docx',
251
+ targetId: exportVersionId,
252
+ previewFile: {
253
+ viewKey: 'bid.view-provider__bid.studio',
254
+ fileKey: 'bid-export-preview-pdf',
255
+ targetId: exportVersionId
256
+ }
257
+ }
258
+ ```
259
+
260
+ `previewFile` is optional and uses the same `{ viewKey, fileKey, targetId }` reference shape. It can point to a derived PDF for a DOCX original. The preview and original download are authorized independently; Download always resolves the original reference. An unavailable preview can be retried without disabling Download. A resource card itself never grants file access.
261
+
262
+ Workbench navigation and file access are separate capabilities. If tabs are unavailable, a host can still provide authorized inline images and downloads. Leaving the runtime scope cancels pending file access and closes scoped file previews.
263
+
264
+ ## Transactional first-conversation Project receipts
265
+
266
+ Implement the public `IProjectTypeProvider.createForConversation` interface and return optional `resourceCards` along with the managed state:
267
+
268
+ ```ts
269
+ async createForConversation(context, input) {
270
+ const bid = await input.transaction.save(makeBid({
271
+ platformProjectId: input.projectId,
272
+ title: input.name
273
+ }))
274
+ return {
275
+ name: bid.title,
276
+ status: 'active',
277
+ viewKey: 'bid__projects', // Existing business entry remains independent.
278
+ selectionId: bid.id,
279
+ resourceCards: [{
280
+ resource: { namespace: 'platform', type: 'project', id: input.projectId },
281
+ title: bid.title,
282
+ open: {
283
+ target: 'assistant.project',
284
+ projectId: input.projectId,
285
+ viewKey: 'platform.project-tasks__timeline'
286
+ }
287
+ }]
288
+ }
289
+ }
290
+ ```
291
+
292
+ The host validates the target against `input.projectId`. It stores pending receipts in `Project.settings.conversationBootstrap` in the same transaction as the business write and conversation binding. `ProjectResourceCardService` locks the Project, then atomically updates the first Assistant message and `resourceCardMessageId`. Streaming begins after commit. A failed attachment leaves a pending receipt; competing first sends claim it once. Manual Project creation has no conversation receipt.
293
+
294
+ Do not emit directly inside the creation transaction: an event would escape a rollback. Plugins returning no receipts keep existing behavior.
295
+
296
+ ## Scheduler example
297
+
298
+ `SchedulerAgentMiddleware` declares the `scheduler` Feature. `SchedulerDetailViewProvider` contributes the on-demand `platform.scheduler__detail` View using the built Remote Component assets. Its selection is the stable task ID. Data/actions call existing task access, update, pause and resume services; execution navigation verifies the conversation belongs to that task. Existing cron parsing and other scheduler tools are unchanged.
299
+
300
+ While the detail View stays open, switching tasks retains each unsaved form draft in memory. Saving commits through the existing service; drafts are not background-saved or polled.
301
+
302
+ Build assets with:
303
+
304
+ ```sh
305
+ corepack pnpm exec tsc -p packages/server-ai/src/xpert-task/remote-components/scheduler-detail/tsconfig.json --noEmit
306
+ node packages/server-ai/src/xpert-task/remote-components/scheduler-detail/build.mjs
307
+ node packages/server-ai/src/xpert-task/remote-components/scheduler-detail/build.mjs --check
308
+ corepack pnpm remote-view:preview --config packages/server-ai/src/xpert-task/remote-components/scheduler-detail/preview.config.mjs --port 4325
309
+ ```
310
+
311
+ The preview explicitly uses fixture data, not a live scheduler.
312
+
313
+ ## Coordinated dependency rollout
314
+
315
+ 1. Build/release ChatKit types and Xpert SDK message contracts.
316
+ 2. Build/release ChatKit UI and wrappers together. Verify the iframe assets contain `resource_card` handling.
317
+ 3. Update the platform's single ChatKit catalog and relevant dependency lockfiles to those published versions, then build/release platform contracts and plugin-sdk against them.
318
+ 4. Build Bid against that public plugin-sdk (no local decorator/interface shim), run `verify:dist`, then deploy the matching host and plugin.
319
+
320
+ This change prepares changesets; it does not publish packages or deploy production. Platform contracts re-export the protocol from `@xpert-ai/chatkit-types`; plugin-sdk re-exports those contracts. Building local source does not publish packages or update the platform's pinned dependencies. Verify the installed release supports `content` blocks and `workbench.file` before deploying consumers. Local Bid workspace overrides may resolve sibling builds; do not describe a source alias or preview as a deployed package upgrade.
321
+
322
+ Existing message JSON is additive and needs no migration, new Artifact table or historical backfill.
323
+
324
+ ## Agent task results
325
+
326
+ Browser views import result schemas and types from `@xpert-ai/plugin-sdk/agent-results`.
327
+ This public entry only exports portable result contracts and Zod validation; the SDK root also exports server dependencies.
328
+ Do not reach into another package's `src` directory or import the server SDK root from a browser bundle.
329
+
330
+ `emitResourceCard(card, runnableConfig)` emits the existing ChatKit `resource_card` contract. It does not create an Artifact or grant access to one. Emit after the referenced business object has been committed.
331
+
332
+ ```ts
333
+ await emitResourceCard(
334
+ {
335
+ resource: { namespace: 'my-plugin', type: 'report', id: report.id },
336
+ title: report.title,
337
+ open: { target: 'workbench.view', viewKey: 'my-plugin__reports', selectionId: report.id }
338
+ },
339
+ config
340
+ )
341
+ ```
342
+
343
+ Use stable namespace/type/id values. Repeated observations update the same card in the current reply. The host supplies `messageId` and `executionId`, persists the card, and excludes it from model/transcript text. Callers cannot choose another reply. The registered View must recheck authorization on every read and file download. Do not put credentials, arbitrary URLs, commands, or private paths in navigation parameters.
344
+
345
+ Task results use the provider-neutral `AgentResultItem` union: analysis, changes, tests, and explicitly declared file deliverables. File delivery defaults to `none`; `files` exports only the declared files and `archive` packages only an explicit selection. Export failure is recorded separately from task execution. A card for an exported artifact refers to the committed artifact and opens the authorized task results View.
346
+
347
+ New artifact references must include the committed `versionId`. The task-results View will not download older references without a pinned version: falling back to the current artifact version could deliver unrelated later content. Such task results remain readable.
348
+
349
+ Middleware using the host task-results View declares `AGENT_TASK_RESULTS_FEATURE` in `meta.features`. The View uses `AGENT_WORKBENCH_SLOT`, opens on demand, and declares support for selection and parameter queries. Other plugins should register their own governed View and feature; emitting a card alone does not activate a View.
350
+
351
+ Local rollout requires the matching ChatKit types/UI with resource-card support, then host contracts/SDK/server, then consuming plugins. Building a local SDK does not publish a new registry package.
352
+
353
+ `api:build` builds the task-results browser bundle before copying its assets. For a source-run API, first run `corepack pnpm nx run api:build-agent-results`. Generated `app.js` and `app.css` are ignored; commit the source and build configuration only.
354
+
355
+ ## Coding invocation cards and activity
356
+
357
+ The built-in `platform.agent-invocation/execution` provider owns direct Coding invocation card creation and refresh. Runtime middleware requests the card through the optional `AgentInvocationApi.getResourceCard()` after start. Project dispatch keeps its existing `platform.project-tasks/execution` identity and does not emit a second generic card.
358
+
359
+ The card opens `platform.coding-execution__execution` with the exact invocation ID. Public CLI activity is written through the optional Runtime `context.activity` recorder and queried by the View provider. Resource-card refresh contains only presentation/state/target updates; it does not transport command output or invoke a CLI. Final summary cards are suppressed only when a Coding execution card already covers the run; independently delivered files retain their own cards.
360
+
361
+ See [Coding Execution View](../server-ai/src/agent-invocation/execution-view/README.md) for the capability, authorization, storage, retention and navigation contract.
package/TOOL-IMAGES.md ADDED
@@ -0,0 +1,85 @@
1
+ # Tool images with immutable references
2
+
3
+ For the API responsibilities, image lifecycle, validation limits and server-only
4
+ text-result policy, see the [tool images feature guide](../../docs/tool-images.md).
5
+
6
+ Use `ToolImagesRuntimeCapability` inside an Agent middleware when a tool returns
7
+ an image for visual inspection. The host stores validated image bytes in
8
+ Workspace Files and an immutable Artifact version. The tool returns only a small
9
+ summary and `ToolOutputPresentation`; do not put a Base64 data URL, file path,
10
+ signed URL or image buffer in tool content, business state or checkpoints.
11
+
12
+ ```ts
13
+ import { tool } from '@langchain/core/tools'
14
+ import { z } from 'zod'
15
+ import { ToolImagesRuntimeCapability, mergeModelRequirements, type AgentMiddleware } from '@xpert-ai/plugin-sdk'
16
+
17
+ // Inside createMiddleware(context), this facade resolves each actual invocation's
18
+ // host scope, including child executions whose conversation was assigned later.
19
+ const images = context.runtime.capabilities!.require(ToolImagesRuntimeCapability)
20
+ const inspectName = 'inspect_process_image'
21
+ const inspectImage = tool(
22
+ async ({ candidateId }) => {
23
+ // Business authorization and candidate selection remain in the owning plugin.
24
+ const prepared = await loadAuthorizedCandidate(candidateId)
25
+ const presentation = await images.save({
26
+ buffer: prepared.buffer,
27
+ mimeType: prepared.mimeType, // image/png, image/jpeg or image/webp
28
+ title: prepared.title
29
+ })
30
+ return [JSON.stringify({ candidateId, sha256: prepared.sha256 }), presentation]
31
+ },
32
+ {
33
+ name: inspectName,
34
+ description: 'Inspect an authorized construction image candidate.',
35
+ schema: z.object({ candidateId: z.string() }),
36
+ responseFormat: 'content_and_artifact'
37
+ }
38
+ )
39
+
40
+ const middleware: AgentMiddleware = {
41
+ name: 'construction-image-inspection',
42
+ tools: [inspectImage],
43
+ wrapModelCall: async (request, handler) => {
44
+ const projected = await images.prepareModelInput(request.messages, [inspectName])
45
+ return handler({
46
+ ...request,
47
+ ...projected,
48
+ requirements: mergeModelRequirements(request.requirements, projected.requirements)
49
+ })
50
+ }
51
+ }
52
+ ```
53
+
54
+ `loadAuthorizedCandidate` is application-specific: validate its business scope and
55
+ resolve trusted bytes before saving them. Do not accept scope or arbitrary paths
56
+ from model input. Record a successful business “viewed” receipt only after `save`
57
+ succeeds, and require the actual visual review before accepting the asset.
58
+
59
+ `prepareModelInput` is a pure outbound projection over persisted references. It
60
+ hydrates only the current complete tool round, preserves the tool-call ID and
61
+ summary mapping, and validates Artifact ownership, conversation, immutable
62
+ version, MIME type, dimensions, byte length and SHA-256. There are at most three
63
+ images per model request. Names passed to this method identify tools whose
64
+ successful results must contain valid image presentations. Ordinary error
65
+ ToolMessages remain textual so the model can select another candidate.
66
+
67
+ The returned temporary HumanMessage **must never be written to a message channel,
68
+ database or checkpoint**. Merge the returned `requirements` into the request with
69
+ `mergeModelRequirements`. Image input adds `features: [ModelFeature.VISION]`;
70
+ the host preserves the union across middleware and checks both the main model
71
+ and every fallback for registered image-input support. Requirements apply only
72
+ to this invocation and are not Agent state or user-supplied tool arguments.
73
+ Only VISION requirements are currently supported; unsupported features and
74
+ unknown requirement fields fail explicitly. An unknown or text-only model cannot silently discard the pixels.
75
+
76
+ Historical references are not hydrated again. Legacy inline image bytes are
77
+ removed only from outbound clones; a current legacy image result without a valid
78
+ reference must be recreated through the image tool. A fresh middleware can resume
79
+ from saved references in the same conversation, without an in-memory allow-list.
80
+ The public API has no identity or storage path fields: the host binds tenant,
81
+ organization, authenticated user, conversation and Workspace scope. Missing scope,
82
+ foreign references, revoked assets and checksum changes fail explicitly.
83
+
84
+ Deploy compatible ChatKit types, SDK and host runtime before adopting this API.
85
+ This source contract does not imply that a matching SDK version has been published.
@@ -0,0 +1 @@
1
+ exports._default = require('./agent-results.cjs.js').default;
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var results = require('./results.cjs.js');
4
+ var contracts = require('@xpert-ai/contracts');
5
+ require('./_extends.cjs.js');
6
+ require('zod/v3');
7
+
8
+
9
+
10
+ exports.AGENT_TASK_RESULTS_FEATURE = results.AGENT_TASK_RESULTS_FEATURE;
11
+ exports.agentResultItemSchema = results.agentResultItemSchema;
12
+ exports.agentTaskResultSchema = results.agentTaskResultSchema;
13
+ Object.defineProperty(exports, "agentOutputDeliverySchema", {
14
+ enumerable: true,
15
+ get: function () { return contracts.agentOutputDeliverySchema; }
16
+ });
17
+ Object.defineProperty(exports, "agentResultPathSchema", {
18
+ enumerable: true,
19
+ get: function () { return contracts.agentResultPathSchema; }
20
+ });
@@ -0,0 +1,2 @@
1
+ export * from './agent-results.cjs.js';
2
+ export { _default as default } from './agent-results.cjs.default.js';
@@ -0,0 +1 @@
1
+ export * from "./src/agent-results";
@@ -0,0 +1,4 @@
1
+ export { A as AGENT_TASK_RESULTS_FEATURE, a as agentResultItemSchema, b as agentTaskResultSchema } from './results.esm.js';
2
+ export { agentOutputDeliverySchema, agentResultPathSchema } from '@xpert-ai/contracts';
3
+ import './_extends.esm.js';
4
+ import 'zod/v3';