@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.
- package/CHANGELOG.md +123 -0
- package/MIDDLEWARE_APPS.md +71 -0
- package/README.md +57 -0
- package/RESOURCE-CARDS-VALIDATION.md +51 -0
- package/RESOURCE-CARDS.md +361 -0
- package/TOOL-IMAGES.md +85 -0
- package/agent-results.cjs.default.js +1 -0
- package/agent-results.cjs.js +20 -0
- package/agent-results.cjs.mjs +2 -0
- package/agent-results.d.ts +1 -0
- package/agent-results.esm.js +4 -0
- package/index.cjs.js +586 -162
- package/index.esm.js +530 -167
- package/model-provider.cjs.js +5 -0
- package/model-provider.esm.js +5 -1
- package/package.json +8 -2
- package/results.cjs.js +50 -0
- package/results.esm.js +46 -0
- package/runtime-capabilities.md +35 -0
- package/src/agent-results.d.ts +2 -0
- package/src/index.d.ts +5 -0
- package/src/lib/agent/handoff/agent-chat.contract.d.ts +6 -1
- package/src/lib/agent/handoff/agent-runtime-message.contract.d.ts +319 -0
- package/src/lib/agent/handoff/index.d.ts +1 -0
- package/src/lib/agent/index.d.ts +2 -0
- package/src/lib/agent/middleware/capabilities/assistant-task.d.ts +55 -20
- package/src/lib/agent/middleware/index.d.ts +1 -0
- package/src/lib/agent/middleware/model-requirements.d.ts +9 -0
- package/src/lib/agent/middleware/strategy.interface.d.ts +4 -0
- package/src/lib/agent/middleware/types.d.ts +20 -3
- package/src/lib/agent/resource-card.d.ts +3 -0
- package/src/lib/agent/runtime/activity.d.ts +6 -0
- package/src/lib/agent/runtime/capability.d.ts +37 -0
- package/src/lib/agent/runtime/cli-model-profile.d.ts +62 -0
- package/src/lib/agent/runtime/dispatch.d.ts +517 -0
- package/src/lib/agent/runtime/execution-runner.d.ts +66 -0
- package/src/lib/agent/runtime/index.d.ts +10 -0
- package/src/lib/agent/runtime/model-execution.d.ts +15 -0
- package/src/lib/agent/runtime/results.d.ts +335 -0
- package/src/lib/agent/runtime/strategy.d.ts +53 -0
- package/src/lib/agent/runtime/task-wait.d.ts +35 -0
- package/src/lib/agent/runtime/types.d.ts +156 -0
- package/src/lib/ai-model/ai-model-provider.interface.d.ts +2 -0
- package/src/lib/ai-model/ai-model.d.ts +2 -0
- package/src/lib/ai-model/index.d.ts +3 -0
- package/src/lib/ai-model/llm.d.ts +4 -2
- package/src/lib/ai-model/native-model.d.ts +22 -0
- package/src/lib/ai-model/realtime.d.ts +36 -0
- package/src/lib/ai-model/token-usage.d.ts +13 -0
- package/src/lib/assistant-capability/index.d.ts +42 -0
- package/src/lib/connector/runtime-capability.d.ts +2 -0
- package/src/lib/connector/strategy.interface.d.ts +8 -0
- package/src/lib/core/context/request-context.d.ts +6 -0
- package/src/lib/core/strategy-bus.d.ts +0 -3
- package/src/lib/evolution/runtime-capability.d.ts +2 -1
- package/src/lib/integration/strategy.interface.d.ts +22 -0
- package/src/lib/mcp/app.d.ts +14 -1
- package/src/lib/project-task/index.d.ts +66 -0
- package/src/lib/project-type/index.d.ts +71 -0
- package/src/lib/resource-card-provider/index.d.ts +3 -0
- package/src/lib/resource-card-provider/provider.decorator.d.ts +4 -0
- package/src/lib/resource-card-provider/provider.registry.d.ts +14 -0
- package/src/lib/resource-card-provider/types.d.ts +36 -0
- package/src/lib/resource-card.d.ts +6 -0
- package/src/lib/runtime/capabilities/index.d.ts +1 -0
- package/src/lib/runtime/capabilities/knowledge-graph.d.ts +59 -0
- package/src/lib/runtime/capabilities/knowledgebase-documents.d.ts +21 -0
- package/src/lib/runtime/capabilities/knowledgebase.d.ts +8 -3
- package/src/lib/runtime/capabilities/project-access.d.ts +2 -1
- package/src/lib/runtime/capabilities/project-provisioning.d.ts +13 -0
- package/src/lib/runtime/capabilities/tool-images.d.ts +24 -0
- package/src/lib/runtime/runtime-scope.d.ts +7 -1
- package/src/lib/sandbox/execution-environment.d.ts +12 -0
- package/src/lib/sandbox/execution.d.ts +13 -0
- package/src/lib/sandbox/index.d.ts +1 -0
- package/src/lib/sandbox/managed-service.d.ts +1 -0
- package/src/lib/sandbox/protocol.d.ts +2 -0
- package/src/lib/tool-provider/types.d.ts +6 -0
- package/src/lib/types.d.ts +2 -1
- 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 @@
|
|
|
1
|
+
export * from "./src/agent-results";
|