@bpmsoftwaresolutions/ai-engine-client 1.0.0-beta.10 → 1.0.0-beta.12
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 +214 -1
- package/examples/implementation-plan-packet.minimal.json +76 -0
- package/package.json +3 -2
- package/src/index.js +73 -0
package/README.md
CHANGED
|
@@ -10,6 +10,17 @@ No repo clone required. Install the package, point it at the Azure service, and
|
|
|
10
10
|
npm install @bpmsoftwaresolutions/ai-engine-client
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## Publishing
|
|
14
|
+
|
|
15
|
+
This package is published automatically from GitHub Actions by `.github/workflows/publish-ai-engine-client.yml`.
|
|
16
|
+
|
|
17
|
+
The workflow runs on pushes to `main` when files under `packages/ai-engine-client/**` change, and it can also be started manually with `workflow_dispatch`.
|
|
18
|
+
|
|
19
|
+
Authentication supports either:
|
|
20
|
+
|
|
21
|
+
- npm trusted publishing
|
|
22
|
+
- a repository secret named `NPM_TOKEN`, `NPM_PUBLISH_TOKEN`, or `NODE_AUTH_TOKEN`
|
|
23
|
+
|
|
13
24
|
## Quick Start
|
|
14
25
|
|
|
15
26
|
```js
|
|
@@ -54,6 +65,98 @@ const persistedTurn = await client.persistAssistantTurn({
|
|
|
54
65
|
});
|
|
55
66
|
```
|
|
56
67
|
|
|
68
|
+
## Integration Notes
|
|
69
|
+
|
|
70
|
+
### Auth Modes
|
|
71
|
+
|
|
72
|
+
The package supports two authentication patterns:
|
|
73
|
+
|
|
74
|
+
1. Bearer-token auth for operator and governed routes.
|
|
75
|
+
2. Compatibility API-key auth for migration-oriented external routes and deployments that still allow shared-key access.
|
|
76
|
+
|
|
77
|
+
Header behavior is:
|
|
78
|
+
|
|
79
|
+
- If `accessToken` or `tokenProvider` is configured, the client sends `Authorization: Bearer <token>`.
|
|
80
|
+
- If bearer auth is not configured, the client sends `X-API-Key` when `apiKey` is provided.
|
|
81
|
+
- If bearer auth is not configured and `clientId` is provided, the client also sends `X-Client-Id`.
|
|
82
|
+
- The client always sends `X-Actor-Id` for audit trails unless overridden.
|
|
83
|
+
|
|
84
|
+
That means this package wraps both operator/governed routes and selected external `/api/v1/*` routes. Pick the auth mode that matches the route family exposed by your deployment.
|
|
85
|
+
|
|
86
|
+
### Route Families
|
|
87
|
+
|
|
88
|
+
- Operator and governed routes are methods such as `createProjectCharter`, `getProjectBundle`, `importImplementationPacket`, and the workflow/portfolio/governance APIs.
|
|
89
|
+
- External routes are the methods prefixed with `getExternal*`, `listExternal*`, `downloadExternal*`, plus `startSessionGovernance`, `persistAssistantTurn`, `createExternalAudioRender`, and `getLatestMemoryProjection`.
|
|
90
|
+
|
|
91
|
+
If your deployment enforces bearer auth on operator routes, API-key-only construction will not work for those methods.
|
|
92
|
+
|
|
93
|
+
### Text and Binary Downloads
|
|
94
|
+
|
|
95
|
+
Some methods do not return plain JSON:
|
|
96
|
+
|
|
97
|
+
- Markdown download helpers return `{ text, contentType, fileName, headers }`.
|
|
98
|
+
- LOGA projection helpers return markdown plus governed projection metadata: `{ text, contentType, headers, logaContract, interactionContract, projectionType, projectionVersion, sourceTruth, sourceVersion, correlationId, refreshPolicy, generatedAt, provenance }`.
|
|
99
|
+
- Binary download helpers return `{ arrayBuffer, contentType, fileName }`.
|
|
100
|
+
|
|
101
|
+
Examples:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
import fs from 'node:fs';
|
|
105
|
+
|
|
106
|
+
const markdown = await client.downloadProjectCharterReportMarkdown(projectId);
|
|
107
|
+
console.log(markdown.fileName, markdown.contentType);
|
|
108
|
+
console.log(markdown.text);
|
|
109
|
+
|
|
110
|
+
const logaRoadmap = await client.getLogaProjectRoadmapProjection(projectId);
|
|
111
|
+
console.log(logaRoadmap.projectionType, logaRoadmap.projectionVersion);
|
|
112
|
+
console.log(logaRoadmap.provenance.sourceTruth, logaRoadmap.correlationId);
|
|
113
|
+
console.log(logaRoadmap.text);
|
|
114
|
+
|
|
115
|
+
const audio = await client.downloadExternalAudioRender(audioRenderRunId);
|
|
116
|
+
await fs.promises.writeFile('render.mp3', Buffer.from(audio.arrayBuffer));
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### LOGA Projection Contract
|
|
120
|
+
|
|
121
|
+
LOGA should use the `getLoga*Projection()` methods for runtime documents. These endpoints are governed AI Engine transformations: durable SQL state is normalized into typed projection models, transformed into versioned structured markdown, and served with provenance, refresh, and action metadata for LOGA to render.
|
|
122
|
+
|
|
123
|
+
The client exposes the transport metadata from response headers so LOGA can validate the contract before rendering:
|
|
124
|
+
|
|
125
|
+
- `logaContract`: currently `ai-engine-ui/v1`
|
|
126
|
+
- `interactionContract`: currently `loga-choreography/v1`
|
|
127
|
+
- `projectionType`: for example `operator.project_roadmap`
|
|
128
|
+
- `projectionWorkflow`: currently `loga-document-projection`
|
|
129
|
+
- `projectionVersion`
|
|
130
|
+
- `sourceTruth`: normally `sql`
|
|
131
|
+
- `sourceVersion`
|
|
132
|
+
- `correlationId`
|
|
133
|
+
- `refreshPolicy`
|
|
134
|
+
- `generatedAt`
|
|
135
|
+
- `provenance`: grouped copy of the source/projection/version fields
|
|
136
|
+
|
|
137
|
+
Example:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
import {
|
|
141
|
+
AIEngineClient,
|
|
142
|
+
LOGA_CONTRACT,
|
|
143
|
+
LOGA_INTERACTION_CONTRACT,
|
|
144
|
+
} from '@bpmsoftwaresolutions/ai-engine-client';
|
|
145
|
+
|
|
146
|
+
const client = AIEngineClient.fromEnv();
|
|
147
|
+
const projection = await client.getLogaProjectRoadmapProjection(projectId);
|
|
148
|
+
|
|
149
|
+
if (projection.logaContract !== LOGA_CONTRACT) {
|
|
150
|
+
throw new Error(`Unsupported LOGA contract: ${projection.logaContract}`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(projection.interactionContract === LOGA_INTERACTION_CONTRACT);
|
|
154
|
+
renderLogaMarkdown(projection.text, {
|
|
155
|
+
projectionType: projection.projectionType,
|
|
156
|
+
provenance: projection.provenance,
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
57
160
|
### fromEnv
|
|
58
161
|
|
|
59
162
|
```js
|
|
@@ -101,6 +204,105 @@ const client = new AIEngineClient({
|
|
|
101
204
|
|
|
102
205
|
When `accessToken` or `tokenProvider` is present, the client prefers bearer auth. API key headers are only sent when bearer auth is not configured.
|
|
103
206
|
|
|
207
|
+
Some deployments accept a shared `X-API-Key` without `X-Client-Id`, while others require both `X-Client-Id` and `X-API-Key` for API-key auth. If your environment uses client-scoped API keys, provide both values.
|
|
208
|
+
|
|
209
|
+
### Project Chartering Contract
|
|
210
|
+
|
|
211
|
+
`createProjectCharter()` sends snake_case fields to `POST /api/projects/charter`. The method accepts:
|
|
212
|
+
|
|
213
|
+
- `projectName`, `objective`
|
|
214
|
+
- `businessContext`, `successCriteria`, `priority`
|
|
215
|
+
- `constraints`, `inScope`, `outOfScope`, `assumptions`
|
|
216
|
+
- `linkedWorkflows`, `linkedWorkflowSlug`
|
|
217
|
+
- `testingStrategy`, `initialContext`
|
|
218
|
+
- `requestedBy`
|
|
219
|
+
- `ensureTaskSurface`, `assignedTo`, `createAcceptanceSubtasks`
|
|
220
|
+
|
|
221
|
+
The response always includes the charter identifiers:
|
|
222
|
+
|
|
223
|
+
- `project_id`
|
|
224
|
+
- `workflow_id`
|
|
225
|
+
- `workflow_run_id`
|
|
226
|
+
- `implementation_packet_id`
|
|
227
|
+
- `implementation_packet_key`
|
|
228
|
+
- `status`
|
|
229
|
+
|
|
230
|
+
If `ensureTaskSurface` is left as `true`, the server also attempts to attach `task_surface` for the active roadmap item. That field is only available when the server can resolve an active implementation item from the project roadmap. If roadmap state is incomplete in the deployment, charter creation can still succeed while `task_surface` is unavailable.
|
|
231
|
+
|
|
232
|
+
Example:
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
const charter = await client.createProjectCharter({
|
|
236
|
+
projectName: 'Loga Cognitive Interface Cockpit Delivery',
|
|
237
|
+
objective: 'Deliver the operator cockpit and playback experience.',
|
|
238
|
+
businessContext: 'Ground the first playback surface in convert-document-to-audio.',
|
|
239
|
+
linkedWorkflowSlug: 'convert-document-to-audio',
|
|
240
|
+
ensureTaskSurface: true,
|
|
241
|
+
createAcceptanceSubtasks: true,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
console.log(charter.project_id);
|
|
245
|
+
console.log(charter.implementation_packet_key);
|
|
246
|
+
console.log(charter.task_surface?.active_item?.implementation_item_id ?? null);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Implementation Packet Import Contract
|
|
250
|
+
|
|
251
|
+
`importImplementationPacket(body)` expects the engine's `implementation_plan_packet` schema, not an arbitrary roadmap-shaped JSON document.
|
|
252
|
+
|
|
253
|
+
Minimum required top-level fields:
|
|
254
|
+
|
|
255
|
+
- `packetType`
|
|
256
|
+
- `packetVersion`
|
|
257
|
+
- `packetId`
|
|
258
|
+
- `title`
|
|
259
|
+
- `phases`
|
|
260
|
+
- `governance.requiredGates`
|
|
261
|
+
|
|
262
|
+
Minimum required fields for each item:
|
|
263
|
+
|
|
264
|
+
- `itemKey`
|
|
265
|
+
- `type`
|
|
266
|
+
- `description`
|
|
267
|
+
- `acceptanceChecks`
|
|
268
|
+
|
|
269
|
+
Allowed packet statuses include `draft`, `approved`, `blocked`, `completed`, and other governed packet lifecycle states. Custom statuses such as `draft-local-artifact` are not valid for import.
|
|
270
|
+
|
|
271
|
+
Minimal example:
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
await client.importImplementationPacket({
|
|
275
|
+
packetType: 'implementation_plan_packet',
|
|
276
|
+
packetVersion: '1.0',
|
|
277
|
+
packetId: 'impl-loga-cockpit-v1',
|
|
278
|
+
title: 'Loga Cognitive Interface Cockpit Delivery',
|
|
279
|
+
status: 'draft',
|
|
280
|
+
governance: {
|
|
281
|
+
requiredGates: ['intent', 'structure', 'promotion'],
|
|
282
|
+
},
|
|
283
|
+
phases: [
|
|
284
|
+
{
|
|
285
|
+
phaseKey: 'phase_1_foundation',
|
|
286
|
+
title: 'Foundation',
|
|
287
|
+
items: [
|
|
288
|
+
{
|
|
289
|
+
itemKey: 'define-cockpit-surface',
|
|
290
|
+
type: 'ui_slice',
|
|
291
|
+
description: 'Define the first cockpit delivery slice.',
|
|
292
|
+
acceptanceChecks: [
|
|
293
|
+
{ text: 'The initial slice is explicitly bounded.' },
|
|
294
|
+
],
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The package does not auto-convert nested human planning structures like `tasks` and `subtasks` into durable implementation-item tasks. To create persisted task records after import, use `ensureProjectRoadmapTaskSurface()` or `createImplementationTask()`.
|
|
303
|
+
|
|
304
|
+
A copyable example payload is packaged at `examples/implementation-plan-packet.minimal.json`.
|
|
305
|
+
|
|
104
306
|
### External Audio Render Example
|
|
105
307
|
|
|
106
308
|
```js
|
|
@@ -166,6 +368,17 @@ Low-level compatibility methods:
|
|
|
166
368
|
| `listAzureSqlBacpacBackups({ storageAccount, container, ... })` | List BACPAC exports through the legacy infra-shaped operator API. |
|
|
167
369
|
| `listAzureSqlBacpacBackupOperations({ databaseName, resourceGroup, serverName, ... })` | List Azure SQL operations through the legacy infra-shaped operator API. |
|
|
168
370
|
|
|
371
|
+
### LOGA Projections
|
|
372
|
+
| Method | Endpoint | Description |
|
|
373
|
+
|---|---|---|
|
|
374
|
+
| `getLogaOperatorHomeProjection()` | `GET /api/operator/projections/home` | Governed operator home runtime markdown document. |
|
|
375
|
+
| `getLogaProjectCatalogProjection()` | `GET /api/operator/projections/project-catalog` | Governed project catalog runtime markdown document. |
|
|
376
|
+
| `getLogaProjectRoadmapProjection(projectId)` | `GET /api/operator/projections/projects/:projectId/roadmap.md` | Governed project roadmap runtime markdown document. |
|
|
377
|
+
| `getLogaWorkflowRunProjection(workflowRunId)` | `GET /api/operator/projections/workflow-runs/:workflowRunId` | Governed workflow run runtime markdown document. |
|
|
378
|
+
| `getLogaEvidencePacketProjection(packetKey)` | `GET /api/operator/projections/evidence-packets/:packetKey` | Governed evidence packet runtime markdown document. |
|
|
379
|
+
|
|
380
|
+
These methods return markdown as `text` and expose projection headers as top-level fields plus `provenance`. LOGA should render the markdown emitted by AI Engine and use these metadata fields for contract validation, refresh behavior, evidence display, and action choreography.
|
|
381
|
+
|
|
169
382
|
### Retrieval Wrapper
|
|
170
383
|
| Method | Description |
|
|
171
384
|
|---|---|
|
|
@@ -449,4 +662,4 @@ Low-level compatibility methods:
|
|
|
449
662
|
|
|
450
663
|
The package talks to the AI Engine web service. All routes listed above are registered unconditionally in the Flask app and served by the deployed Azure Container App.
|
|
451
664
|
|
|
452
|
-
Operator and governed routes expect bearer-token authorization. The
|
|
665
|
+
Operator and governed routes generally expect bearer-token authorization. The package also wraps selected external `/api/v1/*` routes that support migration-oriented auth modes such as bearer or API-key compatibility, depending on deployment configuration.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packetType": "implementation_plan_packet",
|
|
3
|
+
"packetVersion": "1.0",
|
|
4
|
+
"packetId": "impl-example-governed-slice-v1",
|
|
5
|
+
"title": "Example Governed Slice Implementation Packet",
|
|
6
|
+
"status": "draft",
|
|
7
|
+
"createdBy": {
|
|
8
|
+
"kind": "operator",
|
|
9
|
+
"name": "sdk-example"
|
|
10
|
+
},
|
|
11
|
+
"sourceModel": {
|
|
12
|
+
"producer": "ai-engine-client-readme",
|
|
13
|
+
"purpose": "minimal_import_example"
|
|
14
|
+
},
|
|
15
|
+
"system": {
|
|
16
|
+
"slug": "example-governed-slice",
|
|
17
|
+
"domain": "project-chartering"
|
|
18
|
+
},
|
|
19
|
+
"scope": {
|
|
20
|
+
"productArea": "example-governed-slice",
|
|
21
|
+
"workflowIntent": "Demonstrate the minimum durable implementation packet contract.",
|
|
22
|
+
"targetSurface": "governed-project-execution",
|
|
23
|
+
"inScope": [
|
|
24
|
+
"first delivery slice"
|
|
25
|
+
],
|
|
26
|
+
"outOfScope": [
|
|
27
|
+
"full product rollout"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"northStar": {
|
|
31
|
+
"summary": "Define a small but valid governed implementation packet."
|
|
32
|
+
},
|
|
33
|
+
"governance": {
|
|
34
|
+
"requiredGates": [
|
|
35
|
+
"intent",
|
|
36
|
+
"structure",
|
|
37
|
+
"promotion"
|
|
38
|
+
],
|
|
39
|
+
"reviewRequired": true,
|
|
40
|
+
"evidenceRequiredForCompletion": true
|
|
41
|
+
},
|
|
42
|
+
"completionPolicy": {
|
|
43
|
+
"requiresEvidence": true,
|
|
44
|
+
"requiresReview": true
|
|
45
|
+
},
|
|
46
|
+
"phases": [
|
|
47
|
+
{
|
|
48
|
+
"phaseKey": "phase_1_foundation",
|
|
49
|
+
"title": "Foundation",
|
|
50
|
+
"items": [
|
|
51
|
+
{
|
|
52
|
+
"itemKey": "define-first-slice",
|
|
53
|
+
"type": "delivery_slice",
|
|
54
|
+
"priority": "high",
|
|
55
|
+
"title": "Define first governed slice",
|
|
56
|
+
"description": "Define the first durable delivery slice and bind its acceptance criteria.",
|
|
57
|
+
"status": "not_started",
|
|
58
|
+
"dependsOn": [],
|
|
59
|
+
"artifactsExpected": [
|
|
60
|
+
"delivery-slice-definition.md"
|
|
61
|
+
],
|
|
62
|
+
"acceptanceChecks": [
|
|
63
|
+
{
|
|
64
|
+
"text": "The slice is explicitly bounded.",
|
|
65
|
+
"status": "not_run"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"text": "The slice can be attached to durable task surfaces.",
|
|
69
|
+
"status": "not_run"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bpmsoftwaresolutions/ai-engine-client",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
4
4
|
"description": "Thin npm client for the AI Engine operator and retrieval APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"src",
|
|
15
|
-
"README.md"
|
|
15
|
+
"README.md",
|
|
16
|
+
"examples"
|
|
16
17
|
],
|
|
17
18
|
"engines": {
|
|
18
19
|
"node": ">=18"
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const DEFAULT_TIMEOUT_MS = 30000;
|
|
2
2
|
|
|
3
|
+
export const LOGA_CONTRACT = 'ai-engine-ui/v1';
|
|
4
|
+
export const LOGA_INTERACTION_CONTRACT = 'loga-choreography/v1';
|
|
5
|
+
export const LOGA_PROJECTION_WORKFLOW = 'loga-document-projection';
|
|
6
|
+
|
|
3
7
|
function trimTrailingSlash(value) {
|
|
4
8
|
return String(value || '').replace(/\/+$/, '');
|
|
5
9
|
}
|
|
@@ -28,6 +32,44 @@ function parseContentDispositionFilename(headerValue) {
|
|
|
28
32
|
return plainMatch ? plainMatch[1].trim() : null;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
function readResponseHeader(headers, name) {
|
|
36
|
+
if (!headers || typeof headers.get !== 'function') return null;
|
|
37
|
+
return headers.get(name) || headers.get(name.toLowerCase()) || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function extractLogaProjectionMetadata(headers) {
|
|
41
|
+
const projectionWorkflow = readResponseHeader(headers, 'x-projection-workflow');
|
|
42
|
+
const projectionVersion = readResponseHeader(headers, 'x-projection-version');
|
|
43
|
+
const sourceVersion = readResponseHeader(headers, 'x-source-version');
|
|
44
|
+
const correlationId = readResponseHeader(headers, 'x-correlation-id');
|
|
45
|
+
const logaContract = readResponseHeader(headers, 'x-loga-contract');
|
|
46
|
+
const projectionType = readResponseHeader(headers, 'x-projection-type');
|
|
47
|
+
const sourceTruth = readResponseHeader(headers, 'x-source-truth');
|
|
48
|
+
const refreshPolicy = readResponseHeader(headers, 'x-refresh-policy');
|
|
49
|
+
const generatedAt = readResponseHeader(headers, 'x-generated-at');
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
logaContract,
|
|
53
|
+
interactionContract: LOGA_INTERACTION_CONTRACT,
|
|
54
|
+
projectionType,
|
|
55
|
+
projectionWorkflow,
|
|
56
|
+
projectionVersion,
|
|
57
|
+
sourceTruth,
|
|
58
|
+
sourceVersion,
|
|
59
|
+
correlationId,
|
|
60
|
+
refreshPolicy,
|
|
61
|
+
generatedAt,
|
|
62
|
+
provenance: {
|
|
63
|
+
sourceTruth,
|
|
64
|
+
sourceVersion,
|
|
65
|
+
projectionVersion,
|
|
66
|
+
projectionWorkflow,
|
|
67
|
+
correlationId,
|
|
68
|
+
generatedAt,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
31
73
|
function isFormDataBody(value) {
|
|
32
74
|
return typeof FormData !== 'undefined' && value instanceof FormData;
|
|
33
75
|
}
|
|
@@ -709,6 +751,28 @@ export class AIEngineClient {
|
|
|
709
751
|
return this._request(`/api/operator/projects/${projectId}/bundle`);
|
|
710
752
|
}
|
|
711
753
|
|
|
754
|
+
// LOGA projections are governed runtime documents, not static reports.
|
|
755
|
+
|
|
756
|
+
async getLogaOperatorHomeProjection() {
|
|
757
|
+
return this._requestLogaProjection('/api/operator/projections/home');
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
async getLogaProjectCatalogProjection() {
|
|
761
|
+
return this._requestLogaProjection('/api/operator/projections/project-catalog');
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
async getLogaProjectRoadmapProjection(projectId) {
|
|
765
|
+
return this._requestLogaProjection(`/api/operator/projections/projects/${projectId}/roadmap.md`);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
async getLogaWorkflowRunProjection(workflowRunId) {
|
|
769
|
+
return this._requestLogaProjection(`/api/operator/projections/workflow-runs/${workflowRunId}`);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
async getLogaEvidencePacketProjection(packetKey) {
|
|
773
|
+
return this._requestLogaProjection(`/api/operator/projections/evidence-packets/${packetKey}`);
|
|
774
|
+
}
|
|
775
|
+
|
|
712
776
|
// ─── Roadmaps ──────────────────────────────────────────────────────────────
|
|
713
777
|
|
|
714
778
|
async listProjectRoadmaps({ includeInactive } = {}) {
|
|
@@ -1393,12 +1457,21 @@ export class AIEngineClient {
|
|
|
1393
1457
|
text: await response.text(),
|
|
1394
1458
|
contentType,
|
|
1395
1459
|
fileName: parseContentDispositionFilename(contentDisposition),
|
|
1460
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
1396
1461
|
};
|
|
1397
1462
|
} finally {
|
|
1398
1463
|
clearTimeout(timeoutHandle);
|
|
1399
1464
|
}
|
|
1400
1465
|
}
|
|
1401
1466
|
|
|
1467
|
+
async _requestLogaProjection(path, options = {}) {
|
|
1468
|
+
const result = await this._requestText(path, options);
|
|
1469
|
+
return {
|
|
1470
|
+
...result,
|
|
1471
|
+
...extractLogaProjectionMetadata(new Headers(result.headers || {})),
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1402
1475
|
async _requestBinary(path, { method = 'GET', query, headers, body } = {}) {
|
|
1403
1476
|
const url = appendQuery(`${this.baseUrl}${path}`, query);
|
|
1404
1477
|
const controller = new AbortController();
|