@arke-institute/klados-testing 0.1.3 → 0.3.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/dist/entities.d.ts +8 -1
- package/dist/entities.d.ts.map +1 -1
- package/dist/entities.js +10 -1
- package/dist/entities.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/invoke.d.ts.map +1 -1
- package/dist/invoke.js +3 -1
- package/dist/invoke.js.map +1 -1
- package/dist/logs.d.ts +99 -2
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +381 -0
- package/dist/logs.js.map +1 -1
- package/dist/types.d.ts +88 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/workflows.d.ts +204 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +256 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +3 -3
package/dist/entities.d.ts
CHANGED
|
@@ -33,12 +33,19 @@ export declare function deleteEntity(id: string): Promise<void>;
|
|
|
33
33
|
* Create a new collection
|
|
34
34
|
*
|
|
35
35
|
* Uses POST /collections to get proper owner permissions.
|
|
36
|
+
* By default, collections include standard roles with public *:view access.
|
|
36
37
|
*
|
|
37
38
|
* @example
|
|
38
39
|
* ```typescript
|
|
40
|
+
* // Minimal - gets default roles
|
|
39
41
|
* const collection = await createCollection({
|
|
40
42
|
* label: 'Test Collection',
|
|
41
|
-
*
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* // Agent-accessible collection
|
|
46
|
+
* const agentCollection = await createCollection({
|
|
47
|
+
* label: 'Agent Collection',
|
|
48
|
+
* roles: { public: ['*:view', '*:invoke'] }
|
|
42
49
|
* });
|
|
43
50
|
* ```
|
|
44
51
|
*/
|
package/dist/entities.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3D;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAED
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhF;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3D;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CAQrB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAK7B"}
|
package/dist/entities.js
CHANGED
|
@@ -51,12 +51,19 @@ export async function deleteEntity(id) {
|
|
|
51
51
|
* Create a new collection
|
|
52
52
|
*
|
|
53
53
|
* Uses POST /collections to get proper owner permissions.
|
|
54
|
+
* By default, collections include standard roles with public *:view access.
|
|
54
55
|
*
|
|
55
56
|
* @example
|
|
56
57
|
* ```typescript
|
|
58
|
+
* // Minimal - gets default roles
|
|
57
59
|
* const collection = await createCollection({
|
|
58
60
|
* label: 'Test Collection',
|
|
59
|
-
*
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* // Agent-accessible collection
|
|
64
|
+
* const agentCollection = await createCollection({
|
|
65
|
+
* label: 'Agent Collection',
|
|
66
|
+
* roles: { public: ['*:view', '*:invoke'] }
|
|
60
67
|
* });
|
|
61
68
|
* ```
|
|
62
69
|
*/
|
|
@@ -65,6 +72,8 @@ export async function createCollection(options) {
|
|
|
65
72
|
label: options.label,
|
|
66
73
|
description: options.description,
|
|
67
74
|
allowed_types: options.allowedTypes,
|
|
75
|
+
roles: options.roles,
|
|
76
|
+
use_roles_default: options.useRolesDefault,
|
|
68
77
|
});
|
|
69
78
|
}
|
|
70
79
|
/**
|
package/dist/entities.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,CAAC;IAED,OAAO,UAAU,CAAS,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU;IACxC,OAAO,UAAU,CAAS,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,0BAA0B;IAC1B,MAAM,GAAG,GAAG,MAAM,UAAU,CAAkB,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAE5E,yBAAyB;IACzB,MAAM,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE;QAC5C,UAAU,EAAE,GAAG,CAAC,GAAG;KACpB,CAAC,CAAC;AACL,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"entities.js","sourceRoot":"","sources":["../src/entities.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA4B;IAC7D,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IACzC,CAAC;IAED,OAAO,UAAU,CAAS,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU;IACxC,OAAO,UAAU,CAAS,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,0BAA0B;IAC1B,MAAM,GAAG,GAAG,MAAM,UAAU,CAAkB,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAE5E,yBAAyB;IACzB,MAAM,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE;QAC5C,UAAU,EAAE,GAAG,CAAC,GAAG;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAgC;IAEhC,OAAO,UAAU,CAAa,MAAM,EAAE,cAAc,EAAE;QACpD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,aAAa,EAAE,OAAO,CAAC,YAAY;QACnC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,iBAAiB,EAAE,OAAO,CAAC,eAAe;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,YAAoB;IAEpB,OAAO,UAAU,CACf,KAAK,EACL,gBAAgB,YAAY,WAAW,CACxC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -53,8 +53,10 @@
|
|
|
53
53
|
*/
|
|
54
54
|
export { configureTestClient, getConfig, resetTestClient, apiRequest, sleep, log } from './client.js';
|
|
55
55
|
export { createEntity, getEntity, deleteEntity, createCollection, getCollectionEntities } from './entities.js';
|
|
56
|
-
export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry } from './logs.js';
|
|
56
|
+
export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry, getLogChildren, buildWorkflowTree, waitForWorkflowTree, } from './logs.js';
|
|
57
57
|
export { invokeKlados } from './invoke.js';
|
|
58
|
+
export { invokeRhiza, createRhiza, getWorkflowLogs, waitForWorkflowCompletion, assertWorkflowCompleted, assertWorkflowPath, } from './workflows.js';
|
|
58
59
|
export { assertLogCompleted, assertLogFailed, assertLogHasMessages, assertLogMessageCount, assertLogHasHandoff, } from './assertions.js';
|
|
59
|
-
export type { TestConfig, Entity, Collection, CollectionEntities, InvokeResult, LogMessage, KladosLogEntry, CreateEntityOptions, CreateCollectionOptions, InvokeKladosOptions, WaitForLogOptions, LogMessageCriteria, } from './types.js';
|
|
60
|
+
export type { TestConfig, Entity, Collection, CollectionEntities, InvokeResult, LogMessage, KladosLogEntry, CreateEntityOptions, CreateCollectionOptions, InvokeKladosOptions, WaitForLogOptions, LogMessageCriteria, LogTreeNode, WorkflowLogTree, WaitForWorkflowTreeOptions, } from './types.js';
|
|
61
|
+
export type { InvokeRhizaOptions, InvokeRhizaResult, WorkflowCompletionResult, CreateRhizaOptions, FlowStep, ThenSpec, } from './workflows.js';
|
|
60
62
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGtG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGtG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG/G,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,WAAW,EAEX,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,UAAU,EACV,MAAM,EACN,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAElB,WAAW,EACX,eAAe,EACf,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,GACT,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -56,9 +56,13 @@ export { configureTestClient, getConfig, resetTestClient, apiRequest, sleep, log
|
|
|
56
56
|
// Entity operations
|
|
57
57
|
export { createEntity, getEntity, deleteEntity, createCollection, getCollectionEntities } from './entities.js';
|
|
58
58
|
// Log utilities
|
|
59
|
-
export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry
|
|
59
|
+
export { getKladosLog, getFirstLogFromCollection, waitForKladosLog, getLogMessages, getLogEntry,
|
|
60
|
+
// Tree-based traversal
|
|
61
|
+
getLogChildren, buildWorkflowTree, waitForWorkflowTree, } from './logs.js';
|
|
60
62
|
// Klados invocation
|
|
61
63
|
export { invokeKlados } from './invoke.js';
|
|
64
|
+
// Workflow utilities
|
|
65
|
+
export { invokeRhiza, createRhiza, getWorkflowLogs, waitForWorkflowCompletion, assertWorkflowCompleted, assertWorkflowPath, } from './workflows.js';
|
|
62
66
|
// Assertions
|
|
63
67
|
export { assertLogCompleted, assertLogFailed, assertLogHasMessages, assertLogMessageCount, assertLogHasHandoff, } from './assertions.js';
|
|
64
68
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtG,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE/G,gBAAgB;AAChB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,gBAAgB;AAChB,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtG,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE/G,gBAAgB;AAChB,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,gBAAgB,EAChB,cAAc,EACd,WAAW;AACX,uBAAuB;AACvB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAqB;AACrB,OAAO,EACL,WAAW,EACX,WAAW,EACX,eAAe,EACf,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAExB,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC"}
|
package/dist/invoke.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CA2BvB"}
|
package/dist/invoke.js
CHANGED
|
@@ -26,9 +26,11 @@ import { apiRequest } from './client.js';
|
|
|
26
26
|
export async function invokeKlados(options) {
|
|
27
27
|
const body = {
|
|
28
28
|
target_collection: options.targetCollection,
|
|
29
|
-
job_collection: options.jobCollection,
|
|
30
29
|
confirm: options.confirm ?? true,
|
|
31
30
|
};
|
|
31
|
+
if (options.jobCollection) {
|
|
32
|
+
body.job_collection = options.jobCollection;
|
|
33
|
+
}
|
|
32
34
|
if (options.targetEntity) {
|
|
33
35
|
body.target_entity = options.targetEntity;
|
|
34
36
|
}
|
package/dist/invoke.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,IAAI,GAA4B;QACpC,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;QAC3C,
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../src/invoke.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,IAAI,GAA4B;QACpC,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;QAC3C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;KACjC,CAAC;IAEF,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAC9C,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAChD,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,CAAC;IAED,OAAO,UAAU,CACf,MAAM,EACN,WAAW,OAAO,CAAC,QAAQ,SAAS,EACpC,IAAI,CACL,CAAC;AACJ,CAAC"}
|
package/dist/logs.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Klados log utilities for testing
|
|
3
|
+
*
|
|
4
|
+
* Includes tree-based traversal for multi-step workflows and scatter/gather operations.
|
|
3
5
|
*/
|
|
4
|
-
import type { KladosLogEntry, WaitForLogOptions } from './types.js';
|
|
6
|
+
import type { KladosLogEntry, WaitForLogOptions, WorkflowLogTree, WaitForWorkflowTreeOptions } from './types.js';
|
|
5
7
|
/**
|
|
6
8
|
* Get a klados log entry by ID
|
|
7
9
|
*
|
|
@@ -75,9 +77,21 @@ export declare function getLogEntry(log: KladosLogEntry): {
|
|
|
75
77
|
};
|
|
76
78
|
handoffs?: Array<{
|
|
77
79
|
target: string;
|
|
78
|
-
type: "invoke" | "scatter" | "complete" | "error" | "none";
|
|
80
|
+
type: "invoke" | "pass" | "scatter" | "gather" | "complete" | "error" | "none";
|
|
79
81
|
job_id?: string;
|
|
80
82
|
error?: string;
|
|
83
|
+
outputs?: string[];
|
|
84
|
+
invocations
|
|
85
|
+
/**
|
|
86
|
+
* Result of getting log children
|
|
87
|
+
*/
|
|
88
|
+
?: Array<{
|
|
89
|
+
target: string;
|
|
90
|
+
request?: Record<string, unknown>;
|
|
91
|
+
}>;
|
|
92
|
+
delegated?: boolean;
|
|
93
|
+
dispatch_id?: string;
|
|
94
|
+
done_slots?: number;
|
|
81
95
|
}>;
|
|
82
96
|
error?: {
|
|
83
97
|
code: string;
|
|
@@ -85,4 +99,87 @@ export declare function getLogEntry(log: KladosLogEntry): {
|
|
|
85
99
|
retryable: boolean;
|
|
86
100
|
};
|
|
87
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Result of getting log children
|
|
104
|
+
*/
|
|
105
|
+
interface LogChildrenResult {
|
|
106
|
+
/** Array of child log entity IDs */
|
|
107
|
+
childIds: string[];
|
|
108
|
+
/** Total count of sent_to relationships (may be more than childIds if some don't exist yet) */
|
|
109
|
+
sentToCount: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get children of a log by querying for outgoing sent_to relationships
|
|
113
|
+
*
|
|
114
|
+
* In the Rhiza log tree:
|
|
115
|
+
* - Parents have `sent_to` outgoing relationships pointing to children
|
|
116
|
+
* - Children have `received_from` outgoing relationships pointing to parents
|
|
117
|
+
* - We use `sent_to` for traversal since it's an outgoing relationship (no indexing lag)
|
|
118
|
+
*
|
|
119
|
+
* @param logEntityId - Log entity ID to find children of
|
|
120
|
+
* @returns Object with child IDs and total sent_to count
|
|
121
|
+
*/
|
|
122
|
+
export declare function getLogChildren(logEntityId: string): Promise<LogChildrenResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Build a snapshot of the workflow log tree
|
|
125
|
+
*
|
|
126
|
+
* This traverses the log tree starting from the first_log relationship
|
|
127
|
+
* on the job collection, following incoming received_from relationships
|
|
128
|
+
* to discover all logs in the workflow.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const tree = await buildWorkflowTree(jobCollectionId);
|
|
133
|
+
*
|
|
134
|
+
* if (tree.isComplete) {
|
|
135
|
+
* console.log('Workflow finished with', tree.logs.size, 'logs');
|
|
136
|
+
* if (tree.hasErrors) {
|
|
137
|
+
* console.log('Errors:', tree.errors);
|
|
138
|
+
* }
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @param jobCollectionId - Job collection ID
|
|
143
|
+
* @returns Current state of the workflow log tree
|
|
144
|
+
*/
|
|
145
|
+
export declare function buildWorkflowTree(jobCollectionId: string): Promise<WorkflowLogTree>;
|
|
146
|
+
/**
|
|
147
|
+
* Wait for a workflow to complete by polling the log tree
|
|
148
|
+
*
|
|
149
|
+
* This function properly handles:
|
|
150
|
+
* - Multi-step workflows (A → B → C)
|
|
151
|
+
* - Scatter operations (A → [B1, B2, B3])
|
|
152
|
+
* - Nested scatters
|
|
153
|
+
* - Gather operations
|
|
154
|
+
* - Mixed success/error branches
|
|
155
|
+
*
|
|
156
|
+
* Unlike `waitForKladosLog` which only checks the first log, this function
|
|
157
|
+
* traverses the entire log tree and waits for ALL branches to complete.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // Wait for a scatter workflow to complete
|
|
162
|
+
* const tree = await waitForWorkflowTree(jobCollectionId, {
|
|
163
|
+
* timeout: 60000,
|
|
164
|
+
* pollInterval: 2000,
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* if (tree.isComplete) {
|
|
168
|
+
* console.log('All', tree.logs.size, 'logs completed');
|
|
169
|
+
* if (tree.hasErrors) {
|
|
170
|
+
* console.log('Some branches failed:', tree.errors);
|
|
171
|
+
* } else {
|
|
172
|
+
* console.log('Workflow succeeded!');
|
|
173
|
+
* }
|
|
174
|
+
* } else {
|
|
175
|
+
* console.log('Workflow timed out');
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* @param jobCollectionId - Job collection ID
|
|
180
|
+
* @param options - Wait options
|
|
181
|
+
* @returns Final state of the workflow log tree
|
|
182
|
+
*/
|
|
183
|
+
export declare function waitForWorkflowTree(jobCollectionId: string, options?: WaitForWorkflowTreeOptions): Promise<WorkflowLogTree>;
|
|
184
|
+
export {};
|
|
88
185
|
//# sourceMappingURL=logs.d.ts.map
|
package/dist/logs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAEV,cAAc,EACd,iBAAiB,EAEjB,eAAe,EACf,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAEzE;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,gBAAgB,CACpC,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA0BhC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,qCAEjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc;;;;;;;;qBAzBzC,CADG;uBAAmC,CAAC;;iBAGZ,CAAC;aAG9B,CAAC;;;;;;;;;;cAkBE,CAAC;aAAyB,CAAC;eAMxB,CAAC;;QAIX;;WAEG;QACH,CALA;;mBAAyD,CAAC;;iBAM5B,CAAC;mBAEuB,CAAC;kBAKtB,CAAC;;;;;;;EAjBjC;AAMD;;GAEG;AACH,UAAU,iBAAiB;IACzB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,+FAA+F;IAC/F,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiBpF;AAyMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,eAAe,CAAC,CAoE1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,mBAAmB,CACvC,eAAe,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,eAAe,CAAC,CAyD1B"}
|
package/dist/logs.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Klados log utilities for testing
|
|
3
|
+
*
|
|
4
|
+
* Includes tree-based traversal for multi-step workflows and scatter/gather operations.
|
|
3
5
|
*/
|
|
4
6
|
import { apiRequest, sleep } from './client.js';
|
|
5
7
|
/**
|
|
@@ -89,4 +91,383 @@ export function getLogMessages(log) {
|
|
|
89
91
|
export function getLogEntry(log) {
|
|
90
92
|
return log.properties.log_data.entry;
|
|
91
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Get children of a log by querying for outgoing sent_to relationships
|
|
96
|
+
*
|
|
97
|
+
* In the Rhiza log tree:
|
|
98
|
+
* - Parents have `sent_to` outgoing relationships pointing to children
|
|
99
|
+
* - Children have `received_from` outgoing relationships pointing to parents
|
|
100
|
+
* - We use `sent_to` for traversal since it's an outgoing relationship (no indexing lag)
|
|
101
|
+
*
|
|
102
|
+
* @param logEntityId - Log entity ID to find children of
|
|
103
|
+
* @returns Object with child IDs and total sent_to count
|
|
104
|
+
*/
|
|
105
|
+
export async function getLogChildren(logEntityId) {
|
|
106
|
+
try {
|
|
107
|
+
const entity = await apiRequest('GET', `/entities/${logEntityId}`);
|
|
108
|
+
// Look for sent_to relationships pointing to children
|
|
109
|
+
// Note: GET /entities/{id} only returns outgoing relationships,
|
|
110
|
+
// so no direction check is needed.
|
|
111
|
+
const sentToRels = entity.relationships?.filter((r) => r.predicate === 'sent_to') ?? [];
|
|
112
|
+
const childIds = sentToRels.map((r) => r.peer);
|
|
113
|
+
return {
|
|
114
|
+
childIds,
|
|
115
|
+
sentToCount: sentToRels.length,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return { childIds: [], sentToCount: 0 };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Extract expected children count from log messages
|
|
124
|
+
*
|
|
125
|
+
* Scatter workers log numCopies in their success message metadata.
|
|
126
|
+
* This is the most reliable source for expected children count.
|
|
127
|
+
*
|
|
128
|
+
* @param log - Log entry to analyze
|
|
129
|
+
* @returns Number of expected children from messages, or null if not found
|
|
130
|
+
*/
|
|
131
|
+
function extractExpectedChildrenFromMessages(log) {
|
|
132
|
+
const messages = log.properties.log_data.messages ?? [];
|
|
133
|
+
for (const msg of messages) {
|
|
134
|
+
// Check for numCopies in message metadata (from scatter worker)
|
|
135
|
+
if (msg.metadata?.numCopies !== undefined) {
|
|
136
|
+
return msg.metadata.numCopies;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Calculate expected children count from handoffs
|
|
143
|
+
*
|
|
144
|
+
* Priority:
|
|
145
|
+
* 1. numCopies from log messages (worker-provided, legacy support)
|
|
146
|
+
* 2. outputs array from handoff record (framework-provided, most reliable)
|
|
147
|
+
* 3. invocations array length (for local scatters without outputs field)
|
|
148
|
+
* 4. Handoff type analysis (pass = 1, etc.)
|
|
149
|
+
*
|
|
150
|
+
* @param log - Log entry to analyze
|
|
151
|
+
* @returns Number of expected children, or -1 if unknown (keep polling)
|
|
152
|
+
*/
|
|
153
|
+
function getExpectedChildrenCount(log) {
|
|
154
|
+
// First, check log messages for numCopies (from scatter worker - legacy support)
|
|
155
|
+
const numCopies = extractExpectedChildrenFromMessages(log);
|
|
156
|
+
if (numCopies !== null) {
|
|
157
|
+
return numCopies;
|
|
158
|
+
}
|
|
159
|
+
// Fall back to handoff analysis
|
|
160
|
+
const entry = log.properties.log_data.entry;
|
|
161
|
+
const handoffs = entry.handoffs ?? [];
|
|
162
|
+
if (handoffs.length === 0) {
|
|
163
|
+
return 0; // No handoffs = leaf node
|
|
164
|
+
}
|
|
165
|
+
let total = 0;
|
|
166
|
+
for (const handoff of handoffs) {
|
|
167
|
+
if (handoff.type === 'invoke' || handoff.type === 'pass') {
|
|
168
|
+
// Invoke/pass creates 1 child
|
|
169
|
+
total += 1;
|
|
170
|
+
}
|
|
171
|
+
else if (handoff.type === 'scatter') {
|
|
172
|
+
// Scatter creates N children
|
|
173
|
+
// Priority: outputs array (framework-provided) > invocations > unknown
|
|
174
|
+
if (handoff.outputs && handoff.outputs.length > 0) {
|
|
175
|
+
// Use outputs array - this is the most reliable source
|
|
176
|
+
// Subtract done_slots since those don't create children
|
|
177
|
+
const doneSlots = handoff.done_slots ?? 0;
|
|
178
|
+
total += handoff.outputs.length - doneSlots;
|
|
179
|
+
}
|
|
180
|
+
else if (handoff.invocations && handoff.invocations.length > 0) {
|
|
181
|
+
// Use invocations array for local scatters (legacy)
|
|
182
|
+
total += handoff.invocations.length;
|
|
183
|
+
}
|
|
184
|
+
else if (handoff.delegated) {
|
|
185
|
+
// Delegated scatter without outputs field (shouldn't happen with new code)
|
|
186
|
+
// Return -1 to indicate we need to keep polling
|
|
187
|
+
total = -1;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// Fallback: expect at least 1 child
|
|
192
|
+
total += 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (handoff.type === 'gather') {
|
|
196
|
+
// Gather creates 1 child (the gather target)
|
|
197
|
+
total += 1;
|
|
198
|
+
}
|
|
199
|
+
// Other types = 0 children
|
|
200
|
+
}
|
|
201
|
+
return total;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Build a log tree node recursively
|
|
205
|
+
*
|
|
206
|
+
* @param logEntityId - Entity ID of the log
|
|
207
|
+
* @param logsMap - Map to collect all discovered logs
|
|
208
|
+
* @param visited - Set of visited log IDs to prevent cycles
|
|
209
|
+
*/
|
|
210
|
+
async function buildTreeNode(logEntityId, logsMap, visited) {
|
|
211
|
+
if (visited.has(logEntityId)) {
|
|
212
|
+
// Prevent infinite loops on malformed data
|
|
213
|
+
const existingLog = logsMap.get(logEntityId);
|
|
214
|
+
if (existingLog) {
|
|
215
|
+
return {
|
|
216
|
+
log: existingLog,
|
|
217
|
+
children: [],
|
|
218
|
+
isLeaf: true,
|
|
219
|
+
isTerminal: existingLog.properties.status === 'done' ||
|
|
220
|
+
existingLog.properties.status === 'error',
|
|
221
|
+
expectedChildren: 0,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
visited.add(logEntityId);
|
|
227
|
+
// Fetch the log entry
|
|
228
|
+
let log;
|
|
229
|
+
try {
|
|
230
|
+
log = await getKladosLog(logEntityId);
|
|
231
|
+
logsMap.set(logEntityId, log);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// Log doesn't exist yet or fetch failed
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const isTerminal = log.properties.status === 'done' || log.properties.status === 'error';
|
|
238
|
+
// Find children via sent_to relationships
|
|
239
|
+
const { childIds } = await getLogChildren(logEntityId);
|
|
240
|
+
// Get expected children count (from log messages or handoff analysis)
|
|
241
|
+
const expectedChildren = getExpectedChildrenCount(log);
|
|
242
|
+
// Recursively build child nodes
|
|
243
|
+
const children = [];
|
|
244
|
+
for (const childId of childIds) {
|
|
245
|
+
const childNode = await buildTreeNode(childId, logsMap, visited);
|
|
246
|
+
if (childNode) {
|
|
247
|
+
children.push(childNode);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// A node is a leaf if it's terminal AND has no expected children
|
|
251
|
+
// OR if it has error status (errors stop the branch)
|
|
252
|
+
const isLeaf = log.properties.status === 'error' ||
|
|
253
|
+
(isTerminal && expectedChildren === 0);
|
|
254
|
+
return {
|
|
255
|
+
log,
|
|
256
|
+
children,
|
|
257
|
+
isLeaf,
|
|
258
|
+
isTerminal,
|
|
259
|
+
expectedChildren,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Collect all leaf nodes from a tree
|
|
264
|
+
*/
|
|
265
|
+
function collectLeaves(node) {
|
|
266
|
+
if (node.children.length === 0) {
|
|
267
|
+
return [node];
|
|
268
|
+
}
|
|
269
|
+
return node.children.flatMap(collectLeaves);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Check if all expected children have been discovered in the tree
|
|
273
|
+
*
|
|
274
|
+
* Returns false if:
|
|
275
|
+
* - We don't know how many children to expect (expectedChildren === -1)
|
|
276
|
+
* - We have fewer children than expected
|
|
277
|
+
* - Any child hasn't discovered all its children (recursive)
|
|
278
|
+
*/
|
|
279
|
+
function checkAllChildrenDiscovered(node) {
|
|
280
|
+
// If node is still running, children may not exist yet - assume OK for now
|
|
281
|
+
if (!node.isTerminal) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
// If we don't know expected children count, keep polling
|
|
285
|
+
if (node.expectedChildren < 0) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
// If we have fewer children than expected, not complete
|
|
289
|
+
if (node.children.length < node.expectedChildren) {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
// Recursively check all children
|
|
293
|
+
for (const child of node.children) {
|
|
294
|
+
if (!checkAllChildrenDiscovered(child)) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Build a snapshot of the workflow log tree
|
|
302
|
+
*
|
|
303
|
+
* This traverses the log tree starting from the first_log relationship
|
|
304
|
+
* on the job collection, following incoming received_from relationships
|
|
305
|
+
* to discover all logs in the workflow.
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* const tree = await buildWorkflowTree(jobCollectionId);
|
|
310
|
+
*
|
|
311
|
+
* if (tree.isComplete) {
|
|
312
|
+
* console.log('Workflow finished with', tree.logs.size, 'logs');
|
|
313
|
+
* if (tree.hasErrors) {
|
|
314
|
+
* console.log('Errors:', tree.errors);
|
|
315
|
+
* }
|
|
316
|
+
* }
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* @param jobCollectionId - Job collection ID
|
|
320
|
+
* @returns Current state of the workflow log tree
|
|
321
|
+
*/
|
|
322
|
+
export async function buildWorkflowTree(jobCollectionId) {
|
|
323
|
+
const logsMap = new Map();
|
|
324
|
+
const visited = new Set();
|
|
325
|
+
// Find root via first_log relationship
|
|
326
|
+
const firstLogId = await getFirstLogFromCollection(jobCollectionId);
|
|
327
|
+
if (!firstLogId) {
|
|
328
|
+
return {
|
|
329
|
+
root: null,
|
|
330
|
+
logs: logsMap,
|
|
331
|
+
isComplete: false,
|
|
332
|
+
hasErrors: false,
|
|
333
|
+
leaves: [],
|
|
334
|
+
errors: [],
|
|
335
|
+
allChildrenDiscovered: false,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Build tree starting from root
|
|
339
|
+
const root = await buildTreeNode(firstLogId, logsMap, visited);
|
|
340
|
+
if (!root) {
|
|
341
|
+
return {
|
|
342
|
+
root: null,
|
|
343
|
+
logs: logsMap,
|
|
344
|
+
isComplete: false,
|
|
345
|
+
hasErrors: false,
|
|
346
|
+
leaves: [],
|
|
347
|
+
errors: [],
|
|
348
|
+
allChildrenDiscovered: false,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
// Collect leaves and analyze tree
|
|
352
|
+
const leaves = collectLeaves(root);
|
|
353
|
+
const allChildrenDiscovered = checkAllChildrenDiscovered(root);
|
|
354
|
+
// Workflow is complete when:
|
|
355
|
+
// 1. All leaves are terminal (done or error)
|
|
356
|
+
// 2. All expected children have been discovered
|
|
357
|
+
const allLeavesTerminal = leaves.every((leaf) => leaf.isTerminal);
|
|
358
|
+
const isComplete = allLeavesTerminal && allChildrenDiscovered;
|
|
359
|
+
// Collect errors
|
|
360
|
+
const errors = [];
|
|
361
|
+
for (const log of logsMap.values()) {
|
|
362
|
+
if (log.properties.status === 'error') {
|
|
363
|
+
const entry = log.properties.log_data.entry;
|
|
364
|
+
if (entry.error) {
|
|
365
|
+
errors.push({
|
|
366
|
+
logId: log.id,
|
|
367
|
+
kladosId: log.properties.klados_id,
|
|
368
|
+
error: entry.error,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
root,
|
|
375
|
+
logs: logsMap,
|
|
376
|
+
isComplete,
|
|
377
|
+
hasErrors: errors.length > 0,
|
|
378
|
+
leaves,
|
|
379
|
+
errors,
|
|
380
|
+
allChildrenDiscovered,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Wait for a workflow to complete by polling the log tree
|
|
385
|
+
*
|
|
386
|
+
* This function properly handles:
|
|
387
|
+
* - Multi-step workflows (A → B → C)
|
|
388
|
+
* - Scatter operations (A → [B1, B2, B3])
|
|
389
|
+
* - Nested scatters
|
|
390
|
+
* - Gather operations
|
|
391
|
+
* - Mixed success/error branches
|
|
392
|
+
*
|
|
393
|
+
* Unlike `waitForKladosLog` which only checks the first log, this function
|
|
394
|
+
* traverses the entire log tree and waits for ALL branches to complete.
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```typescript
|
|
398
|
+
* // Wait for a scatter workflow to complete
|
|
399
|
+
* const tree = await waitForWorkflowTree(jobCollectionId, {
|
|
400
|
+
* timeout: 60000,
|
|
401
|
+
* pollInterval: 2000,
|
|
402
|
+
* });
|
|
403
|
+
*
|
|
404
|
+
* if (tree.isComplete) {
|
|
405
|
+
* console.log('All', tree.logs.size, 'logs completed');
|
|
406
|
+
* if (tree.hasErrors) {
|
|
407
|
+
* console.log('Some branches failed:', tree.errors);
|
|
408
|
+
* } else {
|
|
409
|
+
* console.log('Workflow succeeded!');
|
|
410
|
+
* }
|
|
411
|
+
* } else {
|
|
412
|
+
* console.log('Workflow timed out');
|
|
413
|
+
* }
|
|
414
|
+
* ```
|
|
415
|
+
*
|
|
416
|
+
* @param jobCollectionId - Job collection ID
|
|
417
|
+
* @param options - Wait options
|
|
418
|
+
* @returns Final state of the workflow log tree
|
|
419
|
+
*/
|
|
420
|
+
export async function waitForWorkflowTree(jobCollectionId, options) {
|
|
421
|
+
const timeout = options?.timeout ?? 30000;
|
|
422
|
+
const pollInterval = options?.pollInterval ?? 2000;
|
|
423
|
+
const startTime = Date.now();
|
|
424
|
+
let lastTree = {
|
|
425
|
+
root: null,
|
|
426
|
+
logs: new Map(),
|
|
427
|
+
isComplete: false,
|
|
428
|
+
hasErrors: false,
|
|
429
|
+
leaves: [],
|
|
430
|
+
errors: [],
|
|
431
|
+
allChildrenDiscovered: false,
|
|
432
|
+
};
|
|
433
|
+
// Track stability: require the same log count for 2 consecutive polls
|
|
434
|
+
// before declaring complete. This handles async sent_to relationship updates.
|
|
435
|
+
let stableCount = 0;
|
|
436
|
+
let lastLogCount = 0;
|
|
437
|
+
while (Date.now() - startTime < timeout) {
|
|
438
|
+
try {
|
|
439
|
+
const tree = await buildWorkflowTree(jobCollectionId);
|
|
440
|
+
lastTree = tree;
|
|
441
|
+
// Call optional progress callback
|
|
442
|
+
if (options?.onPoll) {
|
|
443
|
+
options.onPoll(tree, Date.now() - startTime);
|
|
444
|
+
}
|
|
445
|
+
if (tree.isComplete) {
|
|
446
|
+
// Check if the tree is stable (same log count as last poll)
|
|
447
|
+
if (tree.logs.size === lastLogCount) {
|
|
448
|
+
stableCount++;
|
|
449
|
+
// Require 2 stable polls before returning (handles async relationship updates)
|
|
450
|
+
if (stableCount >= 2) {
|
|
451
|
+
return tree;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
// Log count changed, reset stability counter
|
|
456
|
+
stableCount = 0;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
stableCount = 0;
|
|
461
|
+
}
|
|
462
|
+
lastLogCount = tree.logs.size;
|
|
463
|
+
}
|
|
464
|
+
catch {
|
|
465
|
+
// Ignore errors during polling, just retry
|
|
466
|
+
stableCount = 0;
|
|
467
|
+
}
|
|
468
|
+
await sleep(pollInterval);
|
|
469
|
+
}
|
|
470
|
+
// Timeout - return last known state
|
|
471
|
+
return lastTree;
|
|
472
|
+
}
|
|
92
473
|
//# sourceMappingURL=logs.js.map
|