@aifabrix/builder 2.52.1 → 2.53.1
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/lib/app/deploy-config.js +3 -2
- package/lib/channels/add-channel.js +11 -41
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +26 -17
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-runtime-resolver.js +5 -1
- package/lib/channels/channel-status-display.js +30 -3
- package/lib/channels/microsoft-copilot-entra-sso-form.js +73 -2
- package/lib/channels/microsoft-copilot-entra-sso.js +26 -5
- package/lib/channels/microsoft-copilot-limits.js +22 -3
- package/lib/channels/microsoft-copilot-package.js +59 -14
- package/lib/channels/microsoft-copilot-validate.js +40 -10
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/role-assistant.js +46 -8
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/integration-definition/apply.js +12 -14
- package/lib/integration-definition/enrich-openapi-operations.js +9 -10
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +6 -0
- package/lib/programmatic/openapi-envelope-examples.js +11 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +39 -13
- package/lib/programmatic/openapi-result-schemas.js +30 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +18 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +6 -0
- package/lib/programmatic/run-integration-definition.js +13 -5
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +100 -21
- package/lib/role-assistant/test-runner-bid-document.js +1 -1
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +11 -7
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +68 -105
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +33 -40
- package/lib/schema/external-datasource.schema.json +13 -4
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +2 -1
- package/lib/utils/promote-dev-docker-image.js +15 -10
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +8 -1
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/miso-controller/application.yaml +2 -1
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +6 -2
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +8 -5
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +74 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +29 -14
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +6 -2
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Archive/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -283
- package/jest.projects.js +0 -79
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +0 -205
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -125
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build work.start Intent payload for role-assistant cases.
|
|
3
|
+
* @fileoverview Extracted from test-runner.js (file-size) + 517.1 attachments
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
const { buildStartAttachments } = require('./test-runner-attachments');
|
|
10
|
+
|
|
11
|
+
function buildRuntimeId(prefix) {
|
|
12
|
+
if (typeof crypto.randomUUID === 'function') {
|
|
13
|
+
return `${prefix}-${crypto.randomUUID()}`;
|
|
14
|
+
}
|
|
15
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function applyOptionalStringField(payload, value, key) {
|
|
19
|
+
if (typeof value === 'string' && value.trim()) {
|
|
20
|
+
payload[key] = value.trim();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveInputObject(testCase) {
|
|
25
|
+
const input = testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
26
|
+
return Array.isArray(input) ? {} : input;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveInputMessage(testCase) {
|
|
30
|
+
const input = resolveInputObject(testCase);
|
|
31
|
+
const candidates = [input.message, input.text, input.prompt];
|
|
32
|
+
for (const row of candidates) {
|
|
33
|
+
if (typeof row === 'string' && row.trim()) {
|
|
34
|
+
return row.trim();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function applyStartPayloadOptionalFields(payload, input) {
|
|
41
|
+
const mappedFields = [
|
|
42
|
+
['activationId', 'activationId'],
|
|
43
|
+
['workerTaskId', 'workerTaskId'],
|
|
44
|
+
['principalRef', 'principalRef'],
|
|
45
|
+
['businessRoleRef', 'businessRoleRef']
|
|
46
|
+
];
|
|
47
|
+
for (const [inputKey, payloadKey] of mappedFields) {
|
|
48
|
+
applyOptionalStringField(payload, input[inputKey], payloadKey);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildStartPayloadSourceMetadata(roleKey, testCase, input) {
|
|
53
|
+
return {
|
|
54
|
+
roleKey,
|
|
55
|
+
caseId: testCase.caseId,
|
|
56
|
+
runner: 'aifabrix-role-assistant-test',
|
|
57
|
+
...(input.sourceMetadata && typeof input.sourceMetadata === 'object' ? input.sourceMetadata : {})
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function buildStartIntentPayload(roleKey, testCase) {
|
|
62
|
+
const input = resolveInputObject(testCase);
|
|
63
|
+
const message = resolveInputMessage(testCase);
|
|
64
|
+
const hasContent = typeof input.content !== 'undefined';
|
|
65
|
+
if (!hasContent && !message) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Role assistant test case "${testCase.caseId}" is missing input.message or input.content for runtime execution.`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
const payload = {
|
|
71
|
+
submissionId: String(input.submissionId || buildRuntimeId(`ra-${roleKey}`)),
|
|
72
|
+
content: hasContent ? input.content : message,
|
|
73
|
+
comModelRef: String(input.comModelRef || 'aifabrix.com/intent/default'),
|
|
74
|
+
comModelVersion: String(input.comModelVersion || '1.0'),
|
|
75
|
+
comVocabulary:
|
|
76
|
+
Array.isArray(input.comVocabulary) && input.comVocabulary.length > 0
|
|
77
|
+
? input.comVocabulary.map((row) => String(row))
|
|
78
|
+
: ['objective', 'entity', 'action'],
|
|
79
|
+
sourceType: String(input.sourceType || 'api'),
|
|
80
|
+
sourceLanguage: String(input.sourceLanguage || 'en'),
|
|
81
|
+
responseLanguage: String(input.responseLanguage || input.sourceLanguage || 'en'),
|
|
82
|
+
sourceMetadata: buildStartPayloadSourceMetadata(roleKey, testCase, input)
|
|
83
|
+
};
|
|
84
|
+
applyStartPayloadOptionalFields(payload, input);
|
|
85
|
+
const attachments = buildStartAttachments(testCase);
|
|
86
|
+
if (attachments && attachments.length > 0) {
|
|
87
|
+
payload.attachments = attachments;
|
|
88
|
+
}
|
|
89
|
+
return payload;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
buildStartIntentPayload,
|
|
94
|
+
resolveInputObject,
|
|
95
|
+
resolveInputMessage
|
|
96
|
+
};
|
|
@@ -322,15 +322,17 @@ function synthesizeBidApplyAnswer(wait, prompt, kind, testCase) {
|
|
|
322
322
|
const wantsBody = kind === 'missingRequestBody' || /missing required request body/i.test(prompt);
|
|
323
323
|
const wantsPath = kind === 'missingPathParams' || /missing required path params/i.test(prompt);
|
|
324
324
|
const bid = loadCaseBidDocument(testCase);
|
|
325
|
+
// Always attach the full BID for apply waits (path or body). Path-only responds
|
|
326
|
+
// that send only systemKey let CIP POST an empty definition → Invalid BID.
|
|
325
327
|
if (!bid || (!wantsBody && !wantsPath)) {
|
|
326
328
|
return undefined;
|
|
327
329
|
}
|
|
328
|
-
const out =
|
|
330
|
+
const out = { integrationDefinition: bid };
|
|
329
331
|
const targetSystemKey = resolveTargetSystemKey(testCase);
|
|
330
332
|
if (targetSystemKey) {
|
|
331
333
|
out.systemKey = targetSystemKey;
|
|
332
334
|
}
|
|
333
|
-
return
|
|
335
|
+
return out;
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
function synthesizeTargetSystemKeyAnswer(wait, prompt, kind, testCase) {
|
|
@@ -353,11 +355,17 @@ function synthesizeTargetSystemKeyAnswer(wait, prompt, kind, testCase) {
|
|
|
353
355
|
|
|
354
356
|
function synthesizeWaitAnswer(wait, statusRow, objective, testCase) {
|
|
355
357
|
const prompt = String(wait.prompt || statusRow?.message || '').trim();
|
|
358
|
+
const kind = String(wait.objectRef?.kind || '').trim();
|
|
359
|
+
// BID apply before field/path synthesis — "(fields: systemKey)" must not
|
|
360
|
+
// drop integrationDefinition and let CIP POST an empty BID.
|
|
361
|
+
const bidAnswer = synthesizeBidApplyAnswer(wait, prompt, kind, testCase);
|
|
362
|
+
if (bidAnswer !== undefined) {
|
|
363
|
+
return bidAnswer;
|
|
364
|
+
}
|
|
356
365
|
const fieldAnswer = synthesizeFieldAnswer(wait, statusRow, objective, testCase);
|
|
357
366
|
if (fieldAnswer !== undefined) {
|
|
358
367
|
return fieldAnswer;
|
|
359
368
|
}
|
|
360
|
-
const kind = String(wait.objectRef?.kind || '').trim();
|
|
361
369
|
const isMissingInput =
|
|
362
370
|
kind === 'missingRequestBody' ||
|
|
363
371
|
kind === 'missingPathParams' ||
|
|
@@ -369,10 +377,6 @@ function synthesizeWaitAnswer(wait, statusRow, objective, testCase) {
|
|
|
369
377
|
if (pathAnswer !== undefined) {
|
|
370
378
|
return pathAnswer;
|
|
371
379
|
}
|
|
372
|
-
const bidAnswer = synthesizeBidApplyAnswer(wait, prompt, kind, testCase);
|
|
373
|
-
if (bidAnswer !== undefined) {
|
|
374
|
-
return bidAnswer;
|
|
375
|
-
}
|
|
376
380
|
const targetAnswer = synthesizeTargetSystemKeyAnswer(wait, prompt, kind, testCase);
|
|
377
381
|
return targetAnswer || synthesizeFromCapability(resolveWaitCapabilityText(wait), extractObjectiveHints(objective));
|
|
378
382
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Work Hub test-runner helpers (ids, delays, path detection).
|
|
3
|
+
* @fileoverview Pure helpers for role-assistant Work Hub harness
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const TERMINAL_TASK = new Set(['completed', 'failed', 'cancelled', 'canceled']);
|
|
9
|
+
const PLAN_LOST_RE =
|
|
10
|
+
/work plan not found|plan not found|404|ephemeral|reload|timed out|timeout|network error|econnreset|socket|fetch failed/i;
|
|
11
|
+
const APPROVAL_NOT_PENDING_RE = /approval state is not pending|not pending/i;
|
|
12
|
+
|
|
13
|
+
function delayMs(ms) {
|
|
14
|
+
const wait = Number(ms);
|
|
15
|
+
if (!Number.isFinite(wait) || wait <= 0) {
|
|
16
|
+
return Promise.resolve();
|
|
17
|
+
}
|
|
18
|
+
return new Promise((resolve) => setTimeout(resolve, wait));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveInput(testCase) {
|
|
22
|
+
const input = testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
23
|
+
return Array.isArray(input) ? {} : input;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function resolveObjective(testCase) {
|
|
27
|
+
const input = resolveInput(testCase);
|
|
28
|
+
const candidates = [input.message, input.text, input.prompt, input.objective];
|
|
29
|
+
for (const row of candidates) {
|
|
30
|
+
if (typeof row === 'string' && row.trim()) {
|
|
31
|
+
return row.trim();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function wantsWorkHubPath(testCase) {
|
|
38
|
+
const input = resolveInput(testCase);
|
|
39
|
+
const pathToken = String(input.executionPath || input.mode || '').trim().toLowerCase();
|
|
40
|
+
if (pathToken === 'workhub' || pathToken === 'work-hub' || pathToken === 'plan') {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (pathToken === 'work.start' || pathToken === 'start' || pathToken === 'intent') {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return Boolean(resolveObjective(testCase));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function unwrapId(value) {
|
|
50
|
+
if (typeof value === 'string' && value.trim()) {
|
|
51
|
+
return value.trim();
|
|
52
|
+
}
|
|
53
|
+
if (value && typeof value === 'object') {
|
|
54
|
+
const nested = value.id || value.value || value.ref;
|
|
55
|
+
if (typeof nested === 'string' && nested.trim()) {
|
|
56
|
+
return nested.trim();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function extractPeFromTask(task) {
|
|
63
|
+
const candidates = [task?.processExecutionId, task?.processExecutionRef];
|
|
64
|
+
for (const row of candidates) {
|
|
65
|
+
const id = unwrapId(row);
|
|
66
|
+
if (id) {
|
|
67
|
+
return id;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function planAlreadyActivated(plan) {
|
|
74
|
+
const assistant = plan?.recommendedAssistant;
|
|
75
|
+
if (!assistant || typeof assistant !== 'object' || assistant.isActivated !== true) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return Boolean(unwrapId(assistant.activationId));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isPlanLostError(error) {
|
|
82
|
+
return PLAN_LOST_RE.test(String((error && error.message) || error || ''));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isApprovalNotPendingError(error) {
|
|
86
|
+
return APPROVAL_NOT_PENDING_RE.test(String((error && error.message) || error || ''));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
TERMINAL_TASK,
|
|
91
|
+
delayMs,
|
|
92
|
+
resolveInput,
|
|
93
|
+
resolveObjective,
|
|
94
|
+
wantsWorkHubPath,
|
|
95
|
+
unwrapId,
|
|
96
|
+
extractPeFromTask,
|
|
97
|
+
planAlreadyActivated,
|
|
98
|
+
isPlanLostError,
|
|
99
|
+
isApprovalNotPendingError
|
|
100
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Soft Work Hub outcomes for insufficient-info / clarify-first Intent.
|
|
3
|
+
* Soft cases may stop before accept when Intent is not Act-ready — that is a
|
|
4
|
+
* governed fail-closed outcome, not a harness failure.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
function isIntentNotActReadyError(error) {
|
|
10
|
+
const msg = String((error && error.message) || error || '');
|
|
11
|
+
return /not Act-ready|intentNotActReady/i.test(msg);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function attachPlanIdToError(error, planId) {
|
|
15
|
+
if (error && typeof error === 'object' && planId) {
|
|
16
|
+
error.planId = planId;
|
|
17
|
+
}
|
|
18
|
+
return error;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildSoftClarifyLifecycleResult(roleKey, testCase, planId, error) {
|
|
22
|
+
const message = String((error && error.message) || error || 'intentNotActReady');
|
|
23
|
+
return {
|
|
24
|
+
roleKey,
|
|
25
|
+
caseId: testCase.caseId,
|
|
26
|
+
processExecutionId: null,
|
|
27
|
+
startResponse: {
|
|
28
|
+
planId: planId || null,
|
|
29
|
+
path: 'workHub',
|
|
30
|
+
softClarifyStop: true
|
|
31
|
+
},
|
|
32
|
+
finalStatus: {
|
|
33
|
+
status: 'stopped',
|
|
34
|
+
wait: null,
|
|
35
|
+
reason: 'intentNotActReady'
|
|
36
|
+
},
|
|
37
|
+
timeline: [],
|
|
38
|
+
interactions: [{ type: 'softClarifyStop', message }],
|
|
39
|
+
workResult: null,
|
|
40
|
+
workResultError: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {Function} createActivateAcceptPlan
|
|
46
|
+
* @param {Object} startArgs
|
|
47
|
+
* @param {string} startArgs.dataplaneUrl
|
|
48
|
+
* @param {Object} startArgs.authConfig
|
|
49
|
+
* @param {Object} startArgs.planBody
|
|
50
|
+
* @param {string} startArgs.assistantName
|
|
51
|
+
* @param {Object} [startArgs.options]
|
|
52
|
+
* @param {Object} softCtx
|
|
53
|
+
* @param {string} softCtx.roleKey
|
|
54
|
+
* @param {Object} softCtx.testCase
|
|
55
|
+
*/
|
|
56
|
+
async function startWorkHubOrSoftClarify(createActivateAcceptPlan, startArgs, softCtx) {
|
|
57
|
+
const { dataplaneUrl, authConfig, planBody, assistantName, options } = startArgs;
|
|
58
|
+
const { roleKey, testCase } = softCtx;
|
|
59
|
+
try {
|
|
60
|
+
return {
|
|
61
|
+
soft: false,
|
|
62
|
+
started: await createActivateAcceptPlan(
|
|
63
|
+
dataplaneUrl,
|
|
64
|
+
authConfig,
|
|
65
|
+
planBody,
|
|
66
|
+
assistantName,
|
|
67
|
+
options
|
|
68
|
+
)
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (testCase?.expected?.soft === true && isIntentNotActReadyError(error)) {
|
|
72
|
+
return {
|
|
73
|
+
soft: true,
|
|
74
|
+
result: buildSoftClarifyLifecycleResult(roleKey, testCase, error.planId, error)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = {
|
|
82
|
+
isIntentNotActReadyError,
|
|
83
|
+
attachPlanIdToError,
|
|
84
|
+
buildSoftClarifyLifecycleResult,
|
|
85
|
+
startWorkHubOrSoftClarify
|
|
86
|
+
};
|
|
@@ -25,89 +25,23 @@ const {
|
|
|
25
25
|
} = require('./test-runner-workhub-answers');
|
|
26
26
|
const {
|
|
27
27
|
shouldApplyBidAfterWait,
|
|
28
|
-
|
|
28
|
+
shouldSoftHttpBidApply,
|
|
29
|
+
applyCaseBidViaBuilderApi,
|
|
30
|
+
persistCaseOpenApiViaBuilderApi
|
|
29
31
|
} = require('./test-runner-bid-apply');
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function resolveInput(testCase) {
|
|
45
|
-
const input = testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
46
|
-
return Array.isArray(input) ? {} : input;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function resolveObjective(testCase) {
|
|
50
|
-
const input = resolveInput(testCase);
|
|
51
|
-
const candidates = [input.message, input.text, input.prompt, input.objective];
|
|
52
|
-
for (const row of candidates) {
|
|
53
|
-
if (typeof row === 'string' && row.trim()) {
|
|
54
|
-
return row.trim();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return '';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function wantsWorkHubPath(testCase) {
|
|
61
|
-
const input = resolveInput(testCase);
|
|
62
|
-
const pathToken = String(input.executionPath || input.mode || '').trim().toLowerCase();
|
|
63
|
-
if (pathToken === 'workhub' || pathToken === 'work-hub' || pathToken === 'plan') {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (pathToken === 'work.start' || pathToken === 'start' || pathToken === 'intent') {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
return Boolean(resolveObjective(testCase));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function unwrapId(value) {
|
|
73
|
-
if (typeof value === 'string' && value.trim()) {
|
|
74
|
-
return value.trim();
|
|
75
|
-
}
|
|
76
|
-
if (value && typeof value === 'object') {
|
|
77
|
-
const nested = value.id || value.value || value.ref;
|
|
78
|
-
if (typeof nested === 'string' && nested.trim()) {
|
|
79
|
-
return nested.trim();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return '';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function extractPeFromTask(task) {
|
|
86
|
-
const candidates = [task?.processExecutionId, task?.processExecutionRef];
|
|
87
|
-
for (const row of candidates) {
|
|
88
|
-
const id = unwrapId(row);
|
|
89
|
-
if (id) {
|
|
90
|
-
return id;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return '';
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function planAlreadyActivated(plan) {
|
|
97
|
-
const assistant = plan?.recommendedAssistant;
|
|
98
|
-
if (!assistant || typeof assistant !== 'object' || assistant.isActivated !== true) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
return Boolean(unwrapId(assistant.activationId));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function isPlanLostError(error) {
|
|
105
|
-
return PLAN_LOST_RE.test(String((error && error.message) || error || ''));
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function isApprovalNotPendingError(error) {
|
|
109
|
-
return APPROVAL_NOT_PENDING_RE.test(String((error && error.message) || error || ''));
|
|
110
|
-
}
|
|
32
|
+
const { resolveTargetSystemKey } = require('./test-runner-bid-document');
|
|
33
|
+
const {
|
|
34
|
+
TERMINAL_TASK,
|
|
35
|
+
delayMs,
|
|
36
|
+
resolveInput,
|
|
37
|
+
resolveObjective,
|
|
38
|
+
wantsWorkHubPath,
|
|
39
|
+
unwrapId,
|
|
40
|
+
extractPeFromTask,
|
|
41
|
+
planAlreadyActivated,
|
|
42
|
+
isPlanLostError,
|
|
43
|
+
isApprovalNotPendingError
|
|
44
|
+
} = require('./test-runner-workhub-helpers');
|
|
111
45
|
|
|
112
46
|
async function waitDataplaneHealthy(dataplaneUrl, attempts = 12) {
|
|
113
47
|
const base = String(dataplaneUrl || '')
|
|
@@ -153,11 +87,18 @@ async function acceptPlanForTask(dataplaneUrl, authConfig, planId) {
|
|
|
153
87
|
}
|
|
154
88
|
|
|
155
89
|
async function createActivateAcceptOnce(dataplaneUrl, authConfig, planBody, assistantName) {
|
|
90
|
+
const {
|
|
91
|
+
attachPlanIdToError
|
|
92
|
+
} = require('./test-runner-workhub-soft');
|
|
156
93
|
await waitDataplaneHealthy(dataplaneUrl);
|
|
157
94
|
const plan = await createWorkTaskPlan(dataplaneUrl, authConfig, planBody);
|
|
158
95
|
const planId = await activateIfNeeded(dataplaneUrl, authConfig, plan, assistantName);
|
|
159
|
-
|
|
160
|
-
|
|
96
|
+
try {
|
|
97
|
+
const taskId = await acceptPlanForTask(dataplaneUrl, authConfig, planId);
|
|
98
|
+
return { planId, taskId };
|
|
99
|
+
} catch (error) {
|
|
100
|
+
throw attachPlanIdToError(error, planId);
|
|
101
|
+
}
|
|
161
102
|
}
|
|
162
103
|
|
|
163
104
|
async function createActivateAcceptPlan(dataplaneUrl, authConfig, planBody, assistantName, options) {
|
|
@@ -249,19 +190,23 @@ function recordSkippedResponse(interactions, peId, fingerprint, wait) {
|
|
|
249
190
|
});
|
|
250
191
|
}
|
|
251
192
|
|
|
252
|
-
|
|
193
|
+
function recordBidEmit(testCase, interactions, peId) {
|
|
194
|
+
const { loadCaseBidDocument } = require('./test-runner-workhub-answers');
|
|
195
|
+
const emittedBid = loadCaseBidDocument(testCase);
|
|
196
|
+
if (!(emittedBid && emittedBid.meta && emittedBid.meta.suiteRunId)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
interactions.push({
|
|
200
|
+
type: 'bid-emit',
|
|
201
|
+
processExecutionId: peId,
|
|
202
|
+
suiteRunId: emittedBid.meta.suiteRunId,
|
|
203
|
+
definitionId: emittedBid.definitionId,
|
|
204
|
+
definitionHash: emittedBid.definitionHash
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function softHttpBidApplyAfterWait(authConfig, testCase, interactions, peId) {
|
|
253
209
|
try {
|
|
254
|
-
const { loadCaseBidDocument } = require('./test-runner-workhub-answers');
|
|
255
|
-
const emittedBid = loadCaseBidDocument(testCase);
|
|
256
|
-
if (emittedBid && emittedBid.meta && emittedBid.meta.suiteRunId) {
|
|
257
|
-
interactions.push({
|
|
258
|
-
type: 'bid-emit',
|
|
259
|
-
processExecutionId: peId,
|
|
260
|
-
suiteRunId: emittedBid.meta.suiteRunId,
|
|
261
|
-
definitionId: emittedBid.definitionId,
|
|
262
|
-
definitionHash: emittedBid.definitionHash
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
210
|
const applied = await applyCaseBidViaBuilderApi(authConfig, testCase);
|
|
266
211
|
interactions.push({
|
|
267
212
|
type: 'bid-apply',
|
|
@@ -269,13 +214,15 @@ async function applyBidAfterWait(authConfig, testCase, interactions, peId) {
|
|
|
269
214
|
systemKey: applied && applied.systemKey,
|
|
270
215
|
definitionHash: applied && applied.definitionHash,
|
|
271
216
|
suiteRunId: applied && applied.suiteRunId,
|
|
272
|
-
status: applied && applied.status
|
|
217
|
+
status: applied && applied.status,
|
|
218
|
+
softHttp: true
|
|
273
219
|
});
|
|
274
220
|
} catch (applyErr) {
|
|
275
221
|
interactions.push({
|
|
276
222
|
type: 'bid-apply-error',
|
|
277
223
|
processExecutionId: peId,
|
|
278
|
-
error: applyErr.message || String(applyErr)
|
|
224
|
+
error: applyErr.message || String(applyErr),
|
|
225
|
+
softHttp: true
|
|
279
226
|
});
|
|
280
227
|
}
|
|
281
228
|
}
|
|
@@ -305,11 +252,24 @@ async function respondToWaitingExecution(
|
|
|
305
252
|
recordSkippedResponse(interactions, peId, fingerprint, wait);
|
|
306
253
|
return;
|
|
307
254
|
}
|
|
255
|
+
// Stage suite OpenAPI into workspace before CIP apply (517.2 layout).
|
|
256
|
+
// Product path: DE admits persistsuppliedopenapi; this is lab debt until then.
|
|
257
|
+
if (shouldApplyBidAfterWait(testCase, wait)) {
|
|
258
|
+
const systemKey = resolveTargetSystemKey(testCase);
|
|
259
|
+
if (systemKey) {
|
|
260
|
+
await persistCaseOpenApiViaBuilderApi(authConfig, testCase, systemKey);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
308
263
|
await respondWorkExecution(dataplaneUrl, authConfig, peId, payload);
|
|
309
264
|
await continueWorkExecution(dataplaneUrl, authConfig, peId, {});
|
|
310
265
|
interactions.push({ type: 'respond', processExecutionId: peId, fingerprint });
|
|
311
266
|
if (shouldApplyBidAfterWait(testCase, wait)) {
|
|
312
|
-
|
|
267
|
+
recordBidEmit(testCase, interactions, peId);
|
|
268
|
+
}
|
|
269
|
+
// Soft HTTP apply is lab debt only. Hard cases (expected.soft !== true) rely on
|
|
270
|
+
// DE → capability.execute(template.applyintegrationdefinition) after continue.
|
|
271
|
+
if (shouldSoftHttpBidApply(testCase, wait)) {
|
|
272
|
+
await softHttpBidApplyAfterWait(authConfig, testCase, interactions, peId);
|
|
313
273
|
}
|
|
314
274
|
}
|
|
315
275
|
|
|
@@ -429,6 +389,7 @@ function buildWorkHubLifecycleResult(roleKey, testCase, started, pollState, peBu
|
|
|
429
389
|
}
|
|
430
390
|
|
|
431
391
|
async function runWorkHubCaseLifecycle(roleKey, testCase, runtimeContext, options = {}) {
|
|
392
|
+
const { startWorkHubOrSoftClarify } = require('./test-runner-workhub-soft');
|
|
432
393
|
const dataplaneUrl = runtimeContext?.dataplaneUrl;
|
|
433
394
|
const authConfig = runtimeContext?.authConfig;
|
|
434
395
|
const objective = resolveObjective(testCase);
|
|
@@ -445,13 +406,15 @@ async function runWorkHubCaseLifecycle(roleKey, testCase, runtimeContext, option
|
|
|
445
406
|
objective,
|
|
446
407
|
digitalWorkerKey: String(input.digitalWorkerKey || roleKey).trim()
|
|
447
408
|
};
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
authConfig,
|
|
451
|
-
|
|
452
|
-
assistantName,
|
|
453
|
-
options
|
|
409
|
+
const gate = await startWorkHubOrSoftClarify(
|
|
410
|
+
createActivateAcceptPlan,
|
|
411
|
+
{ dataplaneUrl, authConfig, planBody, assistantName, options },
|
|
412
|
+
{ roleKey, testCase }
|
|
454
413
|
);
|
|
414
|
+
if (gate.soft) {
|
|
415
|
+
return gate.result;
|
|
416
|
+
}
|
|
417
|
+
const started = gate.started;
|
|
455
418
|
const pollState = await pollWorkHubTask(
|
|
456
419
|
dataplaneUrl,
|
|
457
420
|
authConfig,
|
|
@@ -18,6 +18,11 @@ const {
|
|
|
18
18
|
getWorkExecutionResult
|
|
19
19
|
} = require('../api/work.api');
|
|
20
20
|
const { wantsWorkHubPath, runWorkHubCaseLifecycle } = require('./test-runner-workhub');
|
|
21
|
+
const {
|
|
22
|
+
buildStartIntentPayload,
|
|
23
|
+
resolveInputObject,
|
|
24
|
+
resolveInputMessage
|
|
25
|
+
} = require('./test-runner-start-payload');
|
|
21
26
|
const TERMINAL_STATUSES = new Set(['completed', 'stopped']);
|
|
22
27
|
const WAITING_STATUS = 'waiting';
|
|
23
28
|
|
|
@@ -52,22 +57,6 @@ function applyOptionalStringField(payload, value, key) {
|
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
function resolveInputObject(testCase) {
|
|
56
|
-
const input = testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
57
|
-
return Array.isArray(input) ? {} : input;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function resolveInputMessage(testCase) {
|
|
61
|
-
const input = resolveInputObject(testCase);
|
|
62
|
-
const candidates = [input.message, input.text, input.prompt];
|
|
63
|
-
for (const row of candidates) {
|
|
64
|
-
if (typeof row === 'string' && row.trim()) {
|
|
65
|
-
return row.trim();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return '';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
60
|
function isExecutableRoleAssistantCase(testCase) {
|
|
72
61
|
const input = resolveInputObject(testCase);
|
|
73
62
|
if (typeof input.content !== 'undefined') {
|
|
@@ -79,53 +68,6 @@ function isExecutableRoleAssistantCase(testCase) {
|
|
|
79
68
|
return false;
|
|
80
69
|
}
|
|
81
70
|
|
|
82
|
-
function buildStartPayloadSourceMetadata(roleKey, testCase, input) {
|
|
83
|
-
return {
|
|
84
|
-
roleKey,
|
|
85
|
-
caseId: testCase.caseId,
|
|
86
|
-
runner: 'aifabrix-role-assistant-test',
|
|
87
|
-
...(input.sourceMetadata && typeof input.sourceMetadata === 'object' ? input.sourceMetadata : {})
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function applyStartPayloadOptionalFields(payload, input) {
|
|
92
|
-
const mappedFields = [
|
|
93
|
-
['activationId', 'activationId'],
|
|
94
|
-
['workerTaskId', 'workerTaskId'],
|
|
95
|
-
['principalRef', 'principalRef'],
|
|
96
|
-
['businessRoleRef', 'businessRoleRef']
|
|
97
|
-
];
|
|
98
|
-
for (const [inputKey, payloadKey] of mappedFields) {
|
|
99
|
-
applyOptionalStringField(payload, input[inputKey], payloadKey);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function buildStartIntentPayload(roleKey, testCase) {
|
|
104
|
-
const input = resolveInputObject(testCase);
|
|
105
|
-
const message = resolveInputMessage(testCase);
|
|
106
|
-
const hasContent = typeof input.content !== 'undefined';
|
|
107
|
-
if (!hasContent && !message) {
|
|
108
|
-
throw new Error(
|
|
109
|
-
`Role assistant test case "${testCase.caseId}" is missing input.message or input.content for runtime execution.`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
const payload = {
|
|
113
|
-
submissionId: String(input.submissionId || buildRuntimeId(`ra-${roleKey}`)),
|
|
114
|
-
content: hasContent ? input.content : message,
|
|
115
|
-
comModelRef: String(input.comModelRef || 'aifabrix.com/intent/default'),
|
|
116
|
-
comModelVersion: String(input.comModelVersion || '1.0'),
|
|
117
|
-
comVocabulary: Array.isArray(input.comVocabulary) && input.comVocabulary.length > 0
|
|
118
|
-
? input.comVocabulary.map((row) => String(row))
|
|
119
|
-
: ['objective', 'entity', 'action'],
|
|
120
|
-
sourceType: String(input.sourceType || 'api'),
|
|
121
|
-
sourceLanguage: String(input.sourceLanguage || 'en'),
|
|
122
|
-
responseLanguage: String(input.responseLanguage || input.sourceLanguage || 'en'),
|
|
123
|
-
sourceMetadata: buildStartPayloadSourceMetadata(roleKey, testCase, input)
|
|
124
|
-
};
|
|
125
|
-
applyStartPayloadOptionalFields(payload, input);
|
|
126
|
-
return payload;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
71
|
function extractProcessExecutionId(startResponse) {
|
|
130
72
|
const candidates = [
|
|
131
73
|
startResponse?.intent?.processExecutionId,
|