@x12i/memorix-service 3.1.0 → 3.2.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/dist/ai-services/associate-prep.d.ts +37 -0
- package/dist/ai-services/associate-prep.d.ts.map +1 -0
- package/dist/ai-services/associate-prep.js +208 -0
- package/dist/ai-services/associate-prep.js.map +1 -0
- package/dist/ai-services/chunk-markdown.d.ts +22 -0
- package/dist/ai-services/chunk-markdown.d.ts.map +1 -0
- package/dist/ai-services/chunk-markdown.js +159 -0
- package/dist/ai-services/chunk-markdown.js.map +1 -0
- package/dist/ai-services/client.d.ts +1 -1
- package/dist/ai-services/client.d.ts.map +1 -1
- package/dist/ai-services/client.js +2 -2
- package/dist/ai-services/client.js.map +1 -1
- package/dist/ai-services/normalize-output.d.ts +7 -1
- package/dist/ai-services/normalize-output.d.ts.map +1 -1
- package/dist/ai-services/normalize-output.js +340 -60
- package/dist/ai-services/normalize-output.js.map +1 -1
- package/dist/ai-services/skill-execution.d.ts +3 -2
- package/dist/ai-services/skill-execution.d.ts.map +1 -1
- package/dist/ai-services/skill-execution.js +24 -4
- package/dist/ai-services/skill-execution.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +4 -0
- package/dist/app.js.map +1 -1
- package/dist/connector-catalog.d.ts +68 -0
- package/dist/connector-catalog.d.ts.map +1 -0
- package/dist/connector-catalog.js +258 -0
- package/dist/connector-catalog.js.map +1 -0
- package/dist/connector-role.d.ts +22 -0
- package/dist/connector-role.d.ts.map +1 -0
- package/dist/connector-role.js +71 -0
- package/dist/connector-role.js.map +1 -0
- package/dist/destination-runtime.d.ts +8 -0
- package/dist/destination-runtime.d.ts.map +1 -0
- package/dist/destination-runtime.js +11 -0
- package/dist/destination-runtime.js.map +1 -0
- package/dist/execution-target.d.ts +141 -0
- package/dist/execution-target.d.ts.map +1 -0
- package/dist/execution-target.js +853 -0
- package/dist/execution-target.js.map +1 -0
- package/dist/generic-connectors.d.ts +41 -0
- package/dist/generic-connectors.d.ts.map +1 -0
- package/dist/generic-connectors.js +158 -0
- package/dist/generic-connectors.js.map +1 -0
- package/dist/jobs-scope.d.ts +21 -0
- package/dist/jobs-scope.d.ts.map +1 -0
- package/dist/jobs-scope.js +83 -0
- package/dist/jobs-scope.js.map +1 -0
- package/dist/live.d.ts +11 -0
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +700 -73
- package/dist/live.js.map +1 -1
- package/dist/openapi/openapi.json +3445 -791
- package/dist/pipeline-compile.d.ts +35 -1
- package/dist/pipeline-compile.d.ts.map +1 -1
- package/dist/pipeline-compile.js +408 -87
- package/dist/pipeline-compile.js.map +1 -1
- package/dist/pipeline-invoke.d.ts +63 -0
- package/dist/pipeline-invoke.d.ts.map +1 -0
- package/dist/pipeline-invoke.js +114 -0
- package/dist/pipeline-invoke.js.map +1 -0
- package/dist/pipeline-ports.d.ts +13 -0
- package/dist/pipeline-ports.d.ts.map +1 -0
- package/dist/pipeline-ports.js +104 -0
- package/dist/pipeline-ports.js.map +1 -0
- package/dist/platform.d.ts +30 -1
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +228 -6
- package/dist/platform.js.map +1 -1
- package/dist/routes/connector-invocations.d.ts.map +1 -1
- package/dist/routes/connector-invocations.js +18 -21
- package/dist/routes/connector-invocations.js.map +1 -1
- package/dist/routes/jobs.d.ts +4 -0
- package/dist/routes/jobs.d.ts.map +1 -0
- package/dist/routes/jobs.js +888 -0
- package/dist/routes/jobs.js.map +1 -0
- package/dist/routes/memory.d.ts.map +1 -1
- package/dist/routes/memory.js +143 -79
- package/dist/routes/memory.js.map +1 -1
- package/dist/routes/pipelines.d.ts.map +1 -1
- package/dist/routes/pipelines.js +98 -22
- package/dist/routes/pipelines.js.map +1 -1
- package/dist/routes/relationships.d.ts.map +1 -1
- package/dist/routes/relationships.js +80 -2
- package/dist/routes/relationships.js.map +1 -1
- package/dist/runx/client.d.ts +18 -0
- package/dist/runx/client.d.ts.map +1 -0
- package/dist/runx/client.js +59 -0
- package/dist/runx/client.js.map +1 -0
- package/openapi/openapi.json +3445 -791
- package/package.json +10 -8
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Authoring pack pipeline → runtime v2 shape (pipelineId / stepId / stepKind / portConfig).
|
|
3
|
+
* Supports unified step `target` (service | ai-service | connector | pipeline | runx).
|
|
3
4
|
*/
|
|
4
|
-
import { type PipelineDefinition } from "@x12i/memorix-pipeline/v2";
|
|
5
|
+
import { type PipelineDefinition, type StepKind } from "@x12i/memorix-pipeline/v2";
|
|
5
6
|
export type ServiceDefSlice = {
|
|
6
7
|
id?: string;
|
|
7
8
|
serviceId?: string;
|
|
9
|
+
capabilities?: string[];
|
|
8
10
|
memorixAccess?: unknown;
|
|
9
11
|
/** AI-services/v1 binding (type + item); when set, compile stamps FR invoke config. */
|
|
10
12
|
aiService?: {
|
|
@@ -22,6 +24,25 @@ export type ServiceDefSlice = {
|
|
|
22
24
|
itemId?: string;
|
|
23
25
|
};
|
|
24
26
|
};
|
|
27
|
+
/** Authoring step target — same surface as Jobs execution targets + runx. */
|
|
28
|
+
export type AuthoringStepTarget = {
|
|
29
|
+
kind: "service";
|
|
30
|
+
serviceId: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "ai-service";
|
|
33
|
+
aiServiceType: string;
|
|
34
|
+
itemId: string;
|
|
35
|
+
} | {
|
|
36
|
+
kind: "connector";
|
|
37
|
+
connectorId: string;
|
|
38
|
+
sourceId: string;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "pipeline";
|
|
41
|
+
pipelineId: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "runx";
|
|
44
|
+
capabilityId: string;
|
|
45
|
+
};
|
|
25
46
|
export declare function resolveKnowxWorkerBaseUrl(): string;
|
|
26
47
|
/**
|
|
27
48
|
* Explicit test-only switch for the APS AI Services Simulator.
|
|
@@ -43,9 +64,22 @@ export declare function resolveKnowxServiceEndpoint(serviceId: string, opts?: {
|
|
|
43
64
|
workerBaseUrl?: string;
|
|
44
65
|
endpointEnv?: string;
|
|
45
66
|
}): string;
|
|
67
|
+
/** Prefer behavioral step kind from service capabilities. */
|
|
68
|
+
export declare function preferredStepKindFromCapabilities(caps: string[] | undefined): StepKind;
|
|
69
|
+
/**
|
|
70
|
+
* Build a directed call graph of pipelines that invoke other pipelines via
|
|
71
|
+
* `target.pipeline` / `run-pipeline` steps. Detects cycles when ids are known.
|
|
72
|
+
*/
|
|
73
|
+
export declare function detectPipelineCallCycles(pipelines: Array<{
|
|
74
|
+
id?: string;
|
|
75
|
+
pipelineId?: string;
|
|
76
|
+
steps?: Array<Record<string, unknown>>;
|
|
77
|
+
}>): string[];
|
|
46
78
|
export declare function compileAuthoringPipeline(input: unknown, opts?: {
|
|
47
79
|
knownServiceIds?: Set<string>;
|
|
48
80
|
workerBaseUrl?: string;
|
|
49
81
|
serviceDefs?: ServiceDefSlice[];
|
|
82
|
+
/** When set, validate nested pipeline targets exist. */
|
|
83
|
+
knownPipelineIds?: Set<string>;
|
|
50
84
|
}): PipelineDefinition;
|
|
51
85
|
//# sourceMappingURL=pipeline-compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-compile.d.ts","sourceRoot":"","sources":["../src/pipeline-compile.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pipeline-compile.d.ts","sourceRoot":"","sources":["../src/pipeline-compile.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACd,MAAM,2BAA2B,CAAC;AA+CnC,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,uFAAuF;IACvF,SAAS,CAAC,EAAE;QACV,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,0FAA0F;QAC1F,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,+CAA+C;QAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,wBAAgB,yBAAyB,IAAI,MAAM,CAMlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAO7C;AAID;;;GAGG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,GAAG,SAAS,CAMjE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE;IACL,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,MAAM,CAiBR;AAQD,6DAA6D;AAC7D,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,GACzB,QAAQ,CAOV;AA2ND;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,KAAK,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxC,CAAC,GACD,MAAM,EAAE,CAoDV;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IACL,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAChC,GACA,kBAAkB,CAmNpB"}
|
package/dist/pipeline-compile.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Authoring pack pipeline → runtime v2 shape (pipelineId / stepId / stepKind / portConfig).
|
|
3
|
+
* Supports unified step `target` (service | ai-service | connector | pipeline | runx).
|
|
3
4
|
*/
|
|
4
5
|
import { validatePipelineDefinition, STEP_KINDS, } from "@x12i/memorix-pipeline/v2";
|
|
5
6
|
import { defaultEndpointEnvForType, resolveAiServiceOriginUrl, } from "./ai-services/config.js";
|
|
@@ -22,6 +23,10 @@ const STEP_ALIASES = {
|
|
|
22
23
|
validate: "validate",
|
|
23
24
|
"map-normalize": "map-normalize",
|
|
24
25
|
"identity-dedupe": "identity-dedupe",
|
|
26
|
+
"run-pipeline": "run-pipeline",
|
|
27
|
+
pipeline: "run-pipeline",
|
|
28
|
+
"call-pipeline": "run-pipeline",
|
|
29
|
+
runx: "runx",
|
|
25
30
|
};
|
|
26
31
|
const MUTATING = new Set([
|
|
27
32
|
"persist-raw",
|
|
@@ -29,6 +34,13 @@ const MUTATING = new Set([
|
|
|
29
34
|
"relationship-write",
|
|
30
35
|
"workflow",
|
|
31
36
|
"narrative",
|
|
37
|
+
"run-pipeline",
|
|
38
|
+
]);
|
|
39
|
+
const BEHAVIORAL = new Set([
|
|
40
|
+
"enrich",
|
|
41
|
+
"analyze",
|
|
42
|
+
"decide",
|
|
43
|
+
"narrative",
|
|
32
44
|
]);
|
|
33
45
|
export function resolveKnowxWorkerBaseUrl() {
|
|
34
46
|
return (process.env.KNOWX_WORKER_URL?.trim() ||
|
|
@@ -79,6 +91,245 @@ export function resolveKnowxServiceEndpoint(serviceId, opts) {
|
|
|
79
91
|
}
|
|
80
92
|
return workerDefault;
|
|
81
93
|
}
|
|
94
|
+
function asRecord(value) {
|
|
95
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
96
|
+
? value
|
|
97
|
+
: null;
|
|
98
|
+
}
|
|
99
|
+
/** Prefer behavioral step kind from service capabilities. */
|
|
100
|
+
export function preferredStepKindFromCapabilities(caps) {
|
|
101
|
+
if (!caps?.length)
|
|
102
|
+
return "analyze";
|
|
103
|
+
if (caps.includes("enrich"))
|
|
104
|
+
return "enrich";
|
|
105
|
+
if (caps.includes("decide"))
|
|
106
|
+
return "decide";
|
|
107
|
+
if (caps.includes("narrative"))
|
|
108
|
+
return "narrative";
|
|
109
|
+
if (caps.includes("analyze"))
|
|
110
|
+
return "analyze";
|
|
111
|
+
return "analyze";
|
|
112
|
+
}
|
|
113
|
+
function parseStepTarget(step, rawKind) {
|
|
114
|
+
const target = asRecord(step.target);
|
|
115
|
+
if (target) {
|
|
116
|
+
const kind = String(target.kind ?? "").trim();
|
|
117
|
+
if (kind === "service") {
|
|
118
|
+
const serviceId = String(target.serviceId ?? "").trim();
|
|
119
|
+
if (serviceId)
|
|
120
|
+
return { kind: "service", serviceId };
|
|
121
|
+
}
|
|
122
|
+
if (kind === "ai-service" || kind === "ai") {
|
|
123
|
+
const aiServiceType = String(target.aiServiceType ?? "").trim();
|
|
124
|
+
const itemId = String(target.itemId ?? "").trim();
|
|
125
|
+
if (aiServiceType && itemId) {
|
|
126
|
+
return { kind: "ai-service", aiServiceType, itemId };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (kind === "connector") {
|
|
130
|
+
const connectorId = String(target.connectorId ?? "").trim();
|
|
131
|
+
const sourceId = String(target.sourceId ?? "").trim();
|
|
132
|
+
if (connectorId && sourceId) {
|
|
133
|
+
return { kind: "connector", connectorId, sourceId };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (kind === "pipeline") {
|
|
137
|
+
const pipelineId = String(target.pipelineId ?? "").trim();
|
|
138
|
+
if (pipelineId)
|
|
139
|
+
return { kind: "pipeline", pipelineId };
|
|
140
|
+
}
|
|
141
|
+
if (kind === "runx") {
|
|
142
|
+
const capabilityId = String(target.capabilityId ?? "").trim();
|
|
143
|
+
if (capabilityId)
|
|
144
|
+
return { kind: "runx", capabilityId };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Shorthand fields on the step.
|
|
148
|
+
const pipelineId = String(step.pipelineId ?? "").trim();
|
|
149
|
+
if (pipelineId &&
|
|
150
|
+
(rawKind === "run-pipeline" ||
|
|
151
|
+
rawKind === "pipeline" ||
|
|
152
|
+
rawKind === "call-pipeline" ||
|
|
153
|
+
rawKind === "")) {
|
|
154
|
+
return { kind: "pipeline", pipelineId };
|
|
155
|
+
}
|
|
156
|
+
const capabilityId = String(step.capabilityId ??
|
|
157
|
+
asRecord(step.portConfig)?.capabilityId ??
|
|
158
|
+
"").trim();
|
|
159
|
+
if (capabilityId && (rawKind === "runx" || rawKind === "")) {
|
|
160
|
+
return { kind: "runx", capabilityId };
|
|
161
|
+
}
|
|
162
|
+
const sourceId = String(step.sourceId ?? "").trim();
|
|
163
|
+
const connectorId = String(step.connectorId ??
|
|
164
|
+
asRecord(step.portConfig)?.connectorId ??
|
|
165
|
+
"").trim();
|
|
166
|
+
if (sourceId && connectorId) {
|
|
167
|
+
return { kind: "connector", connectorId, sourceId };
|
|
168
|
+
}
|
|
169
|
+
if (sourceId && (rawKind === "memory-pull" || rawKind === "pull" || rawKind === "collect")) {
|
|
170
|
+
return {
|
|
171
|
+
kind: "connector",
|
|
172
|
+
connectorId: connectorId || "default",
|
|
173
|
+
sourceId,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const stepAi = asRecord(step.aiService);
|
|
177
|
+
if (stepAi) {
|
|
178
|
+
const aiServiceType = String(stepAi.aiServiceType ?? "").trim();
|
|
179
|
+
const itemId = String(stepAi.itemId ?? "").trim();
|
|
180
|
+
if (aiServiceType && itemId) {
|
|
181
|
+
return { kind: "ai-service", aiServiceType, itemId };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const serviceId = String(step.serviceId ?? "").trim();
|
|
185
|
+
if (serviceId) {
|
|
186
|
+
return { kind: "service", serviceId };
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
function stampAiPortConfig(step, opts) {
|
|
191
|
+
const endpoint = resolveAiServiceOriginUrl(opts.aiServiceType, {
|
|
192
|
+
endpoint: opts.endpoint || undefined,
|
|
193
|
+
endpointEnv: opts.endpointEnv,
|
|
194
|
+
}) ?? "";
|
|
195
|
+
if (!endpoint)
|
|
196
|
+
return false;
|
|
197
|
+
const existingPc = step.portConfig ?? {};
|
|
198
|
+
const existingExec = existingPc.execution && typeof existingPc.execution === "object"
|
|
199
|
+
? existingPc.execution
|
|
200
|
+
: {};
|
|
201
|
+
const skillExec = opts.aiServiceType === "skill"
|
|
202
|
+
? defaultSkillExecutionForItem(opts.itemId, {
|
|
203
|
+
stepId: String(step.stepId ?? step.id ?? ""),
|
|
204
|
+
})
|
|
205
|
+
: undefined;
|
|
206
|
+
step.portConfig = {
|
|
207
|
+
...existingPc,
|
|
208
|
+
serviceId: opts.serviceId,
|
|
209
|
+
operation: opts.operation,
|
|
210
|
+
...(opts.memorixAccess ? { memorixAccess: opts.memorixAccess } : {}),
|
|
211
|
+
endpoint,
|
|
212
|
+
aiServiceType: opts.aiServiceType,
|
|
213
|
+
itemId: opts.itemId,
|
|
214
|
+
invokeProtocol: "ai-services/1",
|
|
215
|
+
...(skillExec || Object.keys(existingExec).length
|
|
216
|
+
? {
|
|
217
|
+
execution: {
|
|
218
|
+
...skillExec,
|
|
219
|
+
...existingExec,
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
: {}),
|
|
223
|
+
};
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
function stampServicePortConfig(step, svc, serviceId, opts) {
|
|
227
|
+
const operation = (typeof svc?.invocation?.operation === "string"
|
|
228
|
+
? svc.invocation.operation
|
|
229
|
+
: undefined) ?? serviceId;
|
|
230
|
+
const memorixAccess = Array.isArray(svc?.memorixAccess)
|
|
231
|
+
? svc.memorixAccess
|
|
232
|
+
: undefined;
|
|
233
|
+
const stepAi = step.aiService && typeof step.aiService === "object"
|
|
234
|
+
? step.aiService
|
|
235
|
+
: null;
|
|
236
|
+
const aiServiceType = String(stepAi?.aiServiceType ??
|
|
237
|
+
svc?.aiService?.aiServiceType ??
|
|
238
|
+
svc?.invocation?.aiServiceType ??
|
|
239
|
+
"").trim();
|
|
240
|
+
const itemId = String(stepAi?.itemId ?? svc?.aiService?.itemId ?? svc?.invocation?.itemId ?? "").trim();
|
|
241
|
+
if (aiServiceType && itemId) {
|
|
242
|
+
const endpointEnv = String(stepAi?.endpointEnv ??
|
|
243
|
+
svc?.aiService?.endpointEnv ??
|
|
244
|
+
svc?.invocation?.endpointEnv ??
|
|
245
|
+
defaultEndpointEnvForType(aiServiceType) ??
|
|
246
|
+
"").trim() || undefined;
|
|
247
|
+
const explicitEndpoint = String(stepAi?.endpoint ?? svc?.aiService?.endpoint ?? "").trim();
|
|
248
|
+
if (stampAiPortConfig(step, {
|
|
249
|
+
serviceId,
|
|
250
|
+
operation,
|
|
251
|
+
memorixAccess,
|
|
252
|
+
aiServiceType,
|
|
253
|
+
itemId,
|
|
254
|
+
endpointEnv,
|
|
255
|
+
endpoint: explicitEndpoint || undefined,
|
|
256
|
+
})) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// No companion URL — fall through to worker invocation (offline / CI).
|
|
260
|
+
}
|
|
261
|
+
const endpointEnv = typeof svc?.invocation?.endpointEnv === "string"
|
|
262
|
+
? svc.invocation.endpointEnv.trim()
|
|
263
|
+
: serviceId === "knowx-extract"
|
|
264
|
+
? "KNOWX_EXTRACT_WORKER_URL"
|
|
265
|
+
: undefined;
|
|
266
|
+
const endpoint = resolveKnowxServiceEndpoint(serviceId, {
|
|
267
|
+
workerBaseUrl: opts?.workerBaseUrl,
|
|
268
|
+
endpointEnv,
|
|
269
|
+
});
|
|
270
|
+
step.portConfig = {
|
|
271
|
+
...(step.portConfig ?? {}),
|
|
272
|
+
serviceId,
|
|
273
|
+
operation,
|
|
274
|
+
...(memorixAccess ? { memorixAccess } : {}),
|
|
275
|
+
endpoint,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Build a directed call graph of pipelines that invoke other pipelines via
|
|
280
|
+
* `target.pipeline` / `run-pipeline` steps. Detects cycles when ids are known.
|
|
281
|
+
*/
|
|
282
|
+
export function detectPipelineCallCycles(pipelines) {
|
|
283
|
+
const graph = new Map();
|
|
284
|
+
for (const p of pipelines) {
|
|
285
|
+
const id = String(p.pipelineId ?? p.id ?? "").trim();
|
|
286
|
+
if (!id)
|
|
287
|
+
continue;
|
|
288
|
+
if (!graph.has(id))
|
|
289
|
+
graph.set(id, new Set());
|
|
290
|
+
for (const step of p.steps ?? []) {
|
|
291
|
+
const rawKind = String(step.stepKind ?? step.kind ?? step.type ?? "");
|
|
292
|
+
const target = parseStepTarget(step, rawKind);
|
|
293
|
+
if (target?.kind === "pipeline") {
|
|
294
|
+
graph.get(id).add(target.pipelineId);
|
|
295
|
+
}
|
|
296
|
+
if (rawKind === "run-pipeline" ||
|
|
297
|
+
rawKind === "pipeline" ||
|
|
298
|
+
rawKind === "call-pipeline") {
|
|
299
|
+
const child = String(step.pipelineId ??
|
|
300
|
+
asRecord(step.portConfig)?.pipelineId ??
|
|
301
|
+
"").trim();
|
|
302
|
+
if (child)
|
|
303
|
+
graph.get(id).add(child);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const issues = [];
|
|
308
|
+
const visiting = new Set();
|
|
309
|
+
const visited = new Set();
|
|
310
|
+
const path = [];
|
|
311
|
+
function dfs(node) {
|
|
312
|
+
if (visiting.has(node)) {
|
|
313
|
+
const cycleStart = path.indexOf(node);
|
|
314
|
+
const cycle = [...path.slice(cycleStart), node].join(" → ");
|
|
315
|
+
issues.push(`pipeline call cycle: ${cycle}`);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (visited.has(node))
|
|
319
|
+
return;
|
|
320
|
+
visiting.add(node);
|
|
321
|
+
path.push(node);
|
|
322
|
+
for (const next of graph.get(node) ?? []) {
|
|
323
|
+
dfs(next);
|
|
324
|
+
}
|
|
325
|
+
path.pop();
|
|
326
|
+
visiting.delete(node);
|
|
327
|
+
visited.add(node);
|
|
328
|
+
}
|
|
329
|
+
for (const id of graph.keys())
|
|
330
|
+
dfs(id);
|
|
331
|
+
return issues;
|
|
332
|
+
}
|
|
82
333
|
export function compileAuthoringPipeline(input, opts) {
|
|
83
334
|
const raw = structuredClone(input);
|
|
84
335
|
if (typeof raw.pipelineId !== "string" || !raw.pipelineId.trim()) {
|
|
@@ -96,107 +347,177 @@ export function compileAuthoringPipeline(input, opts) {
|
|
|
96
347
|
}
|
|
97
348
|
const issues = [];
|
|
98
349
|
for (const step of raw.steps ?? []) {
|
|
99
|
-
const
|
|
350
|
+
const stepLabel = String(step.stepId ?? step.id ?? "step");
|
|
351
|
+
if (typeof step.stepId !== "string" && typeof step.id === "string") {
|
|
352
|
+
step.stepId = step.id;
|
|
353
|
+
}
|
|
354
|
+
let rawKind = String(step.stepKind ?? step.kind ?? step.type ?? "").trim();
|
|
355
|
+
const target = parseStepTarget(step, rawKind);
|
|
356
|
+
// invoke-service alias: only when target/service can be resolved.
|
|
100
357
|
if (rawKind === "invoke-service") {
|
|
101
|
-
|
|
102
|
-
|
|
358
|
+
if (!target) {
|
|
359
|
+
issues.push(`step ${stepLabel} uses unsupported invoke-service without target/serviceId`);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
rawKind = "";
|
|
103
363
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
364
|
+
// Target-driven kind selection.
|
|
365
|
+
if (target?.kind === "pipeline") {
|
|
366
|
+
step.stepKind = "run-pipeline";
|
|
367
|
+
step.portConfig = {
|
|
368
|
+
...(step.portConfig ?? {}),
|
|
369
|
+
pipelineId: target.pipelineId,
|
|
370
|
+
wait: true,
|
|
371
|
+
};
|
|
372
|
+
if (opts?.knownPipelineIds && !opts.knownPipelineIds.has(target.pipelineId)) {
|
|
373
|
+
issues.push(`step ${stepLabel} references unknown pipeline "${target.pipelineId}"`);
|
|
374
|
+
}
|
|
109
375
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
step.
|
|
376
|
+
else if (target?.kind === "runx") {
|
|
377
|
+
step.stepKind = "runx";
|
|
378
|
+
step.portConfig = {
|
|
379
|
+
...(step.portConfig ?? {}),
|
|
380
|
+
capabilityId: target.capabilityId,
|
|
381
|
+
invokeProtocol: "runx/1",
|
|
382
|
+
};
|
|
113
383
|
}
|
|
114
|
-
if (
|
|
115
|
-
step.
|
|
384
|
+
else if (target?.kind === "connector") {
|
|
385
|
+
step.stepKind = "memory-pull";
|
|
386
|
+
if (typeof step.sourceId !== "string")
|
|
387
|
+
step.sourceId = target.sourceId;
|
|
388
|
+
step.portConfig = {
|
|
389
|
+
...(step.portConfig ?? {}),
|
|
390
|
+
sourceId: target.sourceId,
|
|
391
|
+
connectorId: target.connectorId,
|
|
392
|
+
mode: asRecord(step.portConfig)?.mode ?? "knowledge",
|
|
393
|
+
trigger: asRecord(step.portConfig)?.trigger ??
|
|
394
|
+
"on-demand",
|
|
395
|
+
};
|
|
116
396
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
397
|
+
else if (target?.kind === "ai-service") {
|
|
398
|
+
step.stepKind = "analyze";
|
|
399
|
+
const serviceId = String(step.serviceId ?? "").trim() ||
|
|
400
|
+
`ai:${target.aiServiceType}:${target.itemId}`;
|
|
401
|
+
step.serviceId = serviceId;
|
|
402
|
+
const stamped = stampAiPortConfig(step, {
|
|
403
|
+
serviceId,
|
|
404
|
+
operation: serviceId,
|
|
405
|
+
aiServiceType: target.aiServiceType,
|
|
406
|
+
itemId: target.itemId,
|
|
407
|
+
endpointEnv: defaultEndpointEnvForType(target.aiServiceType),
|
|
408
|
+
});
|
|
409
|
+
if (!stamped) {
|
|
410
|
+
step.portConfig = {
|
|
411
|
+
...(step.portConfig ?? {}),
|
|
412
|
+
serviceId,
|
|
413
|
+
aiServiceType: target.aiServiceType,
|
|
414
|
+
itemId: target.itemId,
|
|
415
|
+
invokeProtocol: "ai-services/1",
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else if (target?.kind === "service") {
|
|
420
|
+
const svc = serviceById.get(target.serviceId);
|
|
421
|
+
const preferred = preferredStepKindFromCapabilities(svc?.capabilities);
|
|
422
|
+
let canonical = null;
|
|
423
|
+
if (rawKind && STEP_ALIASES[rawKind]) {
|
|
424
|
+
canonical = STEP_ALIASES[rawKind];
|
|
425
|
+
}
|
|
426
|
+
else if (rawKind && STEP_KINDS.includes(rawKind)) {
|
|
427
|
+
canonical = rawKind;
|
|
428
|
+
}
|
|
429
|
+
else if (!rawKind || rawKind === "invoke-service") {
|
|
430
|
+
canonical = preferred;
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
// Unknown kind with serviceId → prefer capabilities.
|
|
434
|
+
canonical = preferred;
|
|
435
|
+
}
|
|
436
|
+
// If author picked a non-behavioral kind with a service, keep it only
|
|
437
|
+
// when it's an existing non-target kind; otherwise use preferred.
|
|
438
|
+
if (canonical && !BEHAVIORAL.has(canonical) && rawKind && STEP_ALIASES[rawKind]) {
|
|
439
|
+
// e.g. write-record + serviceId is invalid remote; still allow pass-through kinds.
|
|
440
|
+
}
|
|
441
|
+
else if (!canonical || (rawKind === "" && preferred)) {
|
|
442
|
+
canonical = preferred;
|
|
443
|
+
}
|
|
444
|
+
if (!BEHAVIORAL.has(canonical) && target.kind === "service" && (!rawKind || rawKind === "invoke-service")) {
|
|
445
|
+
canonical = preferred;
|
|
446
|
+
}
|
|
447
|
+
step.stepKind = canonical ?? preferred;
|
|
448
|
+
step.serviceId = target.serviceId;
|
|
449
|
+
stampServicePortConfig(step, svc, target.serviceId, {
|
|
450
|
+
workerBaseUrl: opts?.workerBaseUrl,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
// Legacy: stepKind only
|
|
455
|
+
const canonical = STEP_ALIASES[rawKind] ??
|
|
456
|
+
(STEP_KINDS.includes(rawKind) ? rawKind : null);
|
|
457
|
+
if (!canonical) {
|
|
458
|
+
issues.push(`step ${stepLabel} has unknown stepKind "${rawKind}"`);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
step.stepKind = canonical;
|
|
462
|
+
// memory-pull with sourceId only
|
|
463
|
+
const sourceId = String(step.sourceId ?? "").trim();
|
|
464
|
+
if (canonical === "memory-pull" && sourceId) {
|
|
465
|
+
step.portConfig = {
|
|
466
|
+
...(step.portConfig ?? {}),
|
|
467
|
+
sourceId,
|
|
468
|
+
mode: asRecord(step.portConfig)?.mode ?? "knowledge",
|
|
469
|
+
trigger: asRecord(step.portConfig)?.trigger ??
|
|
470
|
+
"on-demand",
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
// run-pipeline with pipelineId on step
|
|
474
|
+
if (canonical === "run-pipeline") {
|
|
475
|
+
const childId = String(step.pipelineId ??
|
|
476
|
+
asRecord(step.portConfig)?.pipelineId ??
|
|
477
|
+
"").trim();
|
|
478
|
+
if (childId) {
|
|
155
479
|
step.portConfig = {
|
|
156
|
-
...
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
...(memorixAccess ? { memorixAccess } : {}),
|
|
160
|
-
endpoint,
|
|
161
|
-
aiServiceType,
|
|
162
|
-
itemId,
|
|
163
|
-
invokeProtocol: "ai-services/1",
|
|
164
|
-
...(skillExec || Object.keys(existingExec).length
|
|
165
|
-
? {
|
|
166
|
-
execution: {
|
|
167
|
-
...skillExec,
|
|
168
|
-
...existingExec,
|
|
169
|
-
},
|
|
170
|
-
}
|
|
171
|
-
: {}),
|
|
480
|
+
...(step.portConfig ?? {}),
|
|
481
|
+
pipelineId: childId,
|
|
482
|
+
wait: true,
|
|
172
483
|
};
|
|
173
|
-
continue;
|
|
174
484
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
485
|
+
}
|
|
486
|
+
// runx with capabilityId on step
|
|
487
|
+
if (canonical === "runx") {
|
|
488
|
+
const capId = String(step.capabilityId ??
|
|
489
|
+
asRecord(step.portConfig)?.capabilityId ??
|
|
490
|
+
"").trim();
|
|
491
|
+
if (capId) {
|
|
492
|
+
step.portConfig = {
|
|
493
|
+
...(step.portConfig ?? {}),
|
|
494
|
+
capabilityId: capId,
|
|
495
|
+
invokeProtocol: "runx/1",
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const serviceId = typeof step.serviceId === "string" ? step.serviceId.trim() : "";
|
|
500
|
+
if (serviceId) {
|
|
501
|
+
stampServicePortConfig(step, serviceById.get(serviceId), serviceId, { workerBaseUrl: opts?.workerBaseUrl });
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const finalKind = step.stepKind;
|
|
505
|
+
if (MUTATING.has(finalKind) && typeof step.idempotencyKeyExpr !== "string") {
|
|
506
|
+
step.idempotencyKeyExpr = `{{runId}}:${String(step.stepId ?? "step")}`;
|
|
193
507
|
}
|
|
194
508
|
}
|
|
195
509
|
if (issues.length) {
|
|
196
510
|
throw new Error(`compilePipeline failed: ${issues.join("; ")}`);
|
|
197
511
|
}
|
|
512
|
+
// Allow synthetic AI ids and runx through service validation.
|
|
513
|
+
const known = new Set(opts?.knownServiceIds ?? []);
|
|
514
|
+
for (const step of raw.steps ?? []) {
|
|
515
|
+
const sid = String(step.serviceId ?? "").trim();
|
|
516
|
+
if (sid)
|
|
517
|
+
known.add(sid);
|
|
518
|
+
}
|
|
198
519
|
validatePipelineDefinition(raw, {
|
|
199
|
-
knownServiceIds:
|
|
520
|
+
knownServiceIds: known,
|
|
200
521
|
});
|
|
201
522
|
return raw;
|
|
202
523
|
}
|