@vertesia/workflow 0.78.0 → 0.79.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.
Files changed (128) hide show
  1. package/lib/cjs/activities/advanced/createDocumentTypeFromInteractionRun.js +7 -5
  2. package/lib/cjs/activities/advanced/createDocumentTypeFromInteractionRun.js.map +1 -1
  3. package/lib/cjs/activities/advanced/createOrUpdateDocumentFromInteractionRun.js +6 -11
  4. package/lib/cjs/activities/advanced/createOrUpdateDocumentFromInteractionRun.js.map +1 -1
  5. package/lib/cjs/activities/advanced/updateDocumentFromInteractionRun.js +3 -1
  6. package/lib/cjs/activities/advanced/updateDocumentFromInteractionRun.js.map +1 -1
  7. package/lib/cjs/activities/chunkDocument.js +3 -1
  8. package/lib/cjs/activities/chunkDocument.js.map +1 -1
  9. package/lib/cjs/activities/executeInteraction.js +10 -7
  10. package/lib/cjs/activities/executeInteraction.js.map +1 -1
  11. package/lib/cjs/activities/generateDocumentProperties.js +12 -6
  12. package/lib/cjs/activities/generateDocumentProperties.js.map +1 -1
  13. package/lib/cjs/activities/generateOrAssignContentType.js +13 -10
  14. package/lib/cjs/activities/generateOrAssignContentType.js.map +1 -1
  15. package/lib/cjs/activities/index-dsl.js +3 -3
  16. package/lib/cjs/activities/index-dsl.js.map +1 -1
  17. package/lib/cjs/activities/notifyWebhook.js +136 -12
  18. package/lib/cjs/activities/notifyWebhook.js.map +1 -1
  19. package/lib/cjs/activities/rateLimiter.js +30 -0
  20. package/lib/cjs/activities/rateLimiter.js.map +1 -0
  21. package/lib/cjs/conversion/image.js +4 -2
  22. package/lib/cjs/conversion/image.js.map +1 -1
  23. package/lib/cjs/dsl/dsl-workflow.js +61 -0
  24. package/lib/cjs/dsl/dsl-workflow.js.map +1 -1
  25. package/lib/cjs/errors.js +9 -1
  26. package/lib/cjs/errors.js.map +1 -1
  27. package/lib/cjs/index.js +1 -1
  28. package/lib/cjs/index.js.map +1 -1
  29. package/lib/cjs/iterative-generation/activities/generatePart.js +2 -1
  30. package/lib/cjs/iterative-generation/activities/generatePart.js.map +1 -1
  31. package/lib/cjs/iterative-generation/activities/generateToc.js +6 -1
  32. package/lib/cjs/iterative-generation/activities/generateToc.js.map +1 -1
  33. package/lib/cjs/iterative-generation/utils.js.map +1 -1
  34. package/lib/cjs/system/notifyWebhookWorkflow.js +10 -3
  35. package/lib/cjs/system/notifyWebhookWorkflow.js.map +1 -1
  36. package/lib/esm/activities/advanced/createDocumentTypeFromInteractionRun.js +7 -5
  37. package/lib/esm/activities/advanced/createDocumentTypeFromInteractionRun.js.map +1 -1
  38. package/lib/esm/activities/advanced/createOrUpdateDocumentFromInteractionRun.js +6 -11
  39. package/lib/esm/activities/advanced/createOrUpdateDocumentFromInteractionRun.js.map +1 -1
  40. package/lib/esm/activities/advanced/updateDocumentFromInteractionRun.js +3 -1
  41. package/lib/esm/activities/advanced/updateDocumentFromInteractionRun.js.map +1 -1
  42. package/lib/esm/activities/chunkDocument.js +3 -1
  43. package/lib/esm/activities/chunkDocument.js.map +1 -1
  44. package/lib/esm/activities/executeInteraction.js +11 -8
  45. package/lib/esm/activities/executeInteraction.js.map +1 -1
  46. package/lib/esm/activities/generateDocumentProperties.js +12 -6
  47. package/lib/esm/activities/generateDocumentProperties.js.map +1 -1
  48. package/lib/esm/activities/generateOrAssignContentType.js +13 -10
  49. package/lib/esm/activities/generateOrAssignContentType.js.map +1 -1
  50. package/lib/esm/activities/index-dsl.js +1 -1
  51. package/lib/esm/activities/index-dsl.js.map +1 -1
  52. package/lib/esm/activities/notifyWebhook.js +136 -12
  53. package/lib/esm/activities/notifyWebhook.js.map +1 -1
  54. package/lib/esm/activities/rateLimiter.js +27 -0
  55. package/lib/esm/activities/rateLimiter.js.map +1 -0
  56. package/lib/esm/conversion/image.js +4 -2
  57. package/lib/esm/conversion/image.js.map +1 -1
  58. package/lib/esm/dsl/dsl-workflow.js +63 -2
  59. package/lib/esm/dsl/dsl-workflow.js.map +1 -1
  60. package/lib/esm/errors.js +7 -0
  61. package/lib/esm/errors.js.map +1 -1
  62. package/lib/esm/index.js +1 -1
  63. package/lib/esm/index.js.map +1 -1
  64. package/lib/esm/iterative-generation/activities/generatePart.js +2 -1
  65. package/lib/esm/iterative-generation/activities/generatePart.js.map +1 -1
  66. package/lib/esm/iterative-generation/activities/generateToc.js +6 -1
  67. package/lib/esm/iterative-generation/activities/generateToc.js.map +1 -1
  68. package/lib/esm/iterative-generation/utils.js.map +1 -1
  69. package/lib/esm/system/notifyWebhookWorkflow.js +11 -4
  70. package/lib/esm/system/notifyWebhookWorkflow.js.map +1 -1
  71. package/lib/tsconfig.tsbuildinfo +1 -0
  72. package/lib/types/activities/advanced/createDocumentTypeFromInteractionRun.d.ts.map +1 -1
  73. package/lib/types/activities/advanced/createOrUpdateDocumentFromInteractionRun.d.ts +1 -1
  74. package/lib/types/activities/advanced/createOrUpdateDocumentFromInteractionRun.d.ts.map +1 -1
  75. package/lib/types/activities/advanced/updateDocumentFromInteractionRun.d.ts.map +1 -1
  76. package/lib/types/activities/chunkDocument.d.ts.map +1 -1
  77. package/lib/types/activities/executeInteraction.d.ts +5 -1
  78. package/lib/types/activities/executeInteraction.d.ts.map +1 -1
  79. package/lib/types/activities/generateDocumentProperties.d.ts.map +1 -1
  80. package/lib/types/activities/generateOrAssignContentType.d.ts.map +1 -1
  81. package/lib/types/activities/index-dsl.d.ts +1 -1
  82. package/lib/types/activities/index-dsl.d.ts.map +1 -1
  83. package/lib/types/activities/notifyWebhook.d.ts +14 -3
  84. package/lib/types/activities/notifyWebhook.d.ts.map +1 -1
  85. package/lib/types/activities/rateLimiter.d.ts +11 -0
  86. package/lib/types/activities/rateLimiter.d.ts.map +1 -0
  87. package/lib/types/conversion/image.d.ts.map +1 -1
  88. package/lib/types/dsl/dsl-workflow.d.ts.map +1 -1
  89. package/lib/types/errors.d.ts +4 -0
  90. package/lib/types/errors.d.ts.map +1 -1
  91. package/lib/types/index.d.ts +1 -1
  92. package/lib/types/index.d.ts.map +1 -1
  93. package/lib/types/iterative-generation/activities/generatePart.d.ts.map +1 -1
  94. package/lib/types/iterative-generation/activities/generateToc.d.ts.map +1 -1
  95. package/lib/types/iterative-generation/utils.d.ts +2 -2
  96. package/lib/types/iterative-generation/utils.d.ts.map +1 -1
  97. package/lib/types/system/notifyWebhookWorkflow.d.ts +3 -2
  98. package/lib/types/system/notifyWebhookWorkflow.d.ts.map +1 -1
  99. package/lib/workflows-bundle.js +280 -44
  100. package/package.json +13 -5
  101. package/src/activities/advanced/createDocumentTypeFromInteractionRun.ts +8 -5
  102. package/src/activities/advanced/createOrUpdateDocumentFromInteractionRun.ts +6 -10
  103. package/src/activities/advanced/updateDocumentFromInteractionRun.ts +4 -1
  104. package/src/activities/chunkDocument.ts +4 -1
  105. package/src/activities/executeInteraction.ts +16 -9
  106. package/src/activities/generateDocumentProperties.ts +13 -7
  107. package/src/activities/generateOrAssignContentType.ts +17 -11
  108. package/src/activities/index-dsl.ts +1 -1
  109. package/src/activities/notifyWebhook.test.ts +121 -19
  110. package/src/activities/notifyWebhook.ts +164 -16
  111. package/src/activities/rateLimiter.ts +41 -0
  112. package/src/conversion/image.ts +6 -3
  113. package/src/dsl/dsl-workflow.ts +80 -0
  114. package/src/dsl/workflow-exec-child.test.ts +1 -0
  115. package/src/dsl/workflow.test.ts +1 -0
  116. package/src/errors.ts +13 -0
  117. package/src/index.ts +1 -1
  118. package/src/iterative-generation/activities/generatePart.ts +2 -1
  119. package/src/iterative-generation/activities/generateToc.ts +8 -2
  120. package/src/iterative-generation/utils.ts +2 -2
  121. package/src/system/notifyWebhookWorkflow.ts +15 -6
  122. package/lib/cjs/activities/identifyTextSections.js +0 -48
  123. package/lib/cjs/activities/identifyTextSections.js.map +0 -1
  124. package/lib/esm/activities/identifyTextSections.js +0 -45
  125. package/lib/esm/activities/identifyTextSections.js.map +0 -1
  126. package/lib/types/activities/identifyTextSections.d.ts +0 -12
  127. package/lib/types/activities/identifyTextSections.d.ts.map +0 -1
  128. package/src/activities/identifyTextSections.ts +0 -71
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/workflow",
3
- "version": "0.78.0",
3
+ "version": "0.79.0",
4
4
  "type": "module",
5
5
  "description": "Vertesia workflow DSL",
6
6
  "main": "./lib/esm/index.js",
@@ -49,11 +49,11 @@
49
49
  "tmp": "^0.2.3",
50
50
  "tmp-promise": "^3.0.3",
51
51
  "yaml": "^2.6.0",
52
- "@vertesia/client": "0.78.0",
53
52
  "@llumiverse/common": "0.22.0",
54
- "@vertesia/api-fetch-client": "0.78.0",
55
- "@vertesia/common": "0.78.0",
56
- "@vertesia/memory": "0.49.0"
53
+ "@vertesia/client": "0.79.0",
54
+ "@vertesia/api-fetch-client": "0.79.0",
55
+ "@vertesia/common": "0.79.0",
56
+ "@vertesia/memory": "0.50.0"
57
57
  },
58
58
  "ts_dual_module": {
59
59
  "outDir": "lib",
@@ -98,6 +98,11 @@
98
98
  },
99
99
  "./workflows-bundle": {
100
100
  "import": "./lib/workflows-bundle.js"
101
+ },
102
+ "./errors": {
103
+ "types": "./lib/types/errors.d.ts",
104
+ "import": "./lib/esm/errors.js",
105
+ "require": "./lib/cjs/errors.js"
101
106
  }
102
107
  },
103
108
  "types": "./lib/types/index.d.ts",
@@ -117,6 +122,9 @@
117
122
  ],
118
123
  "vars": [
119
124
  "./lib/types/dsl/vars.d.ts"
125
+ ],
126
+ "errors": [
127
+ "./lib/types/errors.d.ts"
120
128
  ]
121
129
  }
122
130
  },
@@ -3,6 +3,7 @@ import { log } from "@temporalio/activity";
3
3
  import { projectResult } from "../../dsl/projections.js";
4
4
  import { setupActivity } from "../../dsl/setup/ActivityContext.js";
5
5
  import { ActivityParamNotFoundError } from "../../errors.js";
6
+ import { parseCompletionResultsToJson } from "@llumiverse/common";
6
7
 
7
8
 
8
9
  export interface CreateDocumentTypeFromInteractionRunParams {
@@ -30,16 +31,18 @@ export async function createDocumentTypeFromInteractionRun(payload: DSLActivityE
30
31
 
31
32
  const genTypeRes = params.run.result;
32
33
 
33
- if (!genTypeRes.document_type) {
34
+ const jsonResult = parseCompletionResultsToJson(params.run.result);
35
+
36
+ if (!jsonResult.document_type) {
34
37
  log.error("No name generated for type: " + JSON.stringify(genTypeRes), genTypeRes);
35
38
  throw new Error("No name generated for type");
36
39
  }
37
40
 
38
- log.info("Generated schema for type", genTypeRes.metadata_schema);
41
+ log.info("Generated schema for type", jsonResult.metadata_schema);
39
42
  const typeData: CreateContentObjectTypePayload = {
40
- name: genTypeRes.document_type,
41
- object_schema: genTypeRes.metadata_schema,
42
- is_chunkable: !!genTypeRes.is_chunkable,
43
+ name: jsonResult.document_type,
44
+ object_schema: jsonResult.metadata_schema,
45
+ is_chunkable: !!jsonResult.is_chunkable,
43
46
  }
44
47
 
45
48
  const type = await client.types.create(typeData);
@@ -2,6 +2,7 @@ import { log } from "@temporalio/activity";
2
2
  import { ContentObjectStatus, DSLActivityExecutionPayload, DSLActivitySpec } from "@vertesia/common";
3
3
  import { setupActivity } from "../../dsl/setup/ActivityContext.js";
4
4
  import { ActivityParamNotFoundError, DocumentNotFoundError } from "../../errors.js";
5
+ import { parseCompletionResultsToJson, completionResultToString } from "@llumiverse/common";
5
6
 
6
7
  interface CreateOrUpdateObjectFromInteractionRunParams {
7
8
  /**
@@ -68,28 +69,23 @@ export async function createOrUpdateDocumentFromInteractionRun(payload: DSLActiv
68
69
 
69
70
 
70
71
  const result = run.result;
71
- const resultIsObject = typeof result === 'object';
72
+ const jsonResult = parseCompletionResultsToJson(run.result);
72
73
  const inputData = run.parameters;
73
74
 
74
- let name: string;
75
- if (resultIsObject) {
76
- name = result['name'] || result["title"] || inputData['name'] || params.fallback_name || 'Untitled';
77
- } else {
78
- name = inputData['name'] || params.fallback_name || 'Untitled';
79
- }
75
+ const name = jsonResult['name'] || jsonResult["title"] || inputData['name'] || params.fallback_name || 'Untitled';
80
76
 
81
77
  const docPayload = {
82
78
  name,
83
79
  parent: params.parent ?? undefined,
84
- properties: resultIsObject ? result : {},
85
- text: !resultIsObject ? result : undefined,
80
+ properties: jsonResult ? jsonResult : {},
81
+ text: !jsonResult ? result.map(completionResultToString).join('\n') : undefined,
86
82
  type: type?.id,
87
83
  status: ContentObjectStatus.completed,
88
84
  generation_run_info: {
89
85
  id: run.id,
90
86
  date: new Date().toISOString(),
91
87
  model: run.modelId,
92
- target: resultIsObject ? 'properties' : 'text'
88
+ target: jsonResult ? 'properties' : 'text'
93
89
  }
94
90
  };
95
91
 
@@ -1,6 +1,7 @@
1
1
  import { DSLActivityExecutionPayload, DSLActivitySpec, ExecutionRun } from "@vertesia/common";
2
2
  import { setupActivity } from "../../dsl/setup/ActivityContext.js";
3
3
  import { ActivityParamNotFoundError } from "../../errors.js";
4
+ import { parseCompletionResultsToJson } from "@llumiverse/common";
4
5
 
5
6
 
6
7
  export interface UpdateDocumentFromInteractionRunParams {
@@ -28,7 +29,9 @@ export async function updateDocumentFromInteractionRun(payload: DSLActivityExecu
28
29
  return { status: "failed", error: "no-props" };
29
30
  }
30
31
 
31
- await client.objects.update(objectId, docProps);
32
+ const jsonResult = parseCompletionResultsToJson(params.run.result);
33
+
34
+ await client.objects.update(objectId, jsonResult);
32
35
 
33
36
  return { status: "success" };
34
37
  }
@@ -3,6 +3,7 @@ import { DSLActivityExecutionPayload, DSLActivitySpec } from "@vertesia/common";
3
3
  import { setupActivity } from "../dsl/setup/ActivityContext.js";
4
4
  import { DocPart } from "../utils/chunks.js";
5
5
  import { InteractionExecutionParams, executeInteractionFromActivity } from "./executeInteraction.js";
6
+ import { parseCompletionResultsToJson } from "@llumiverse/common";
6
7
 
7
8
  const INT_CHUNK_DOCUMENT = "sys:ChunkDocument"
8
9
 
@@ -82,7 +83,9 @@ export async function chunkDocument(payload: DSLActivityExecutionPayload<ChunkDo
82
83
  content: instrumented
83
84
  });
84
85
 
85
- const parts = res.result.parts as DocPart[];
86
+ const jsonResult = parseCompletionResultsToJson(res.result);
87
+
88
+ const parts = jsonResult.parts as DocPart[];
86
89
  if (!parts || parts.length === 0) {
87
90
  log.warn('No parts found for object ID: ' + objectId, res);
88
91
  return { id: objectId, status: "failed", parts: [], message: "no parts found" }
@@ -13,7 +13,7 @@ import {
13
13
  } from "@vertesia/common";
14
14
  import { projectResult } from "../dsl/projections.js";
15
15
  import { setupActivity } from "../dsl/setup/ActivityContext.js";
16
- import { ActivityParamInvalidError, ActivityParamNotFoundError } from "../errors.js";
16
+ import { ActivityParamInvalidError, ActivityParamNotFoundError, ResourceExhaustedError } from "../errors.js";
17
17
  import { TruncateSpec, truncByMaxTokens } from "../utils/tokens.js";
18
18
  import { Readable } from "stream";
19
19
 
@@ -98,6 +98,11 @@ export interface InteractionExecutionParams {
98
98
  * Options to control generation
99
99
  */
100
100
  model_options?: ModelOptions;
101
+
102
+ /**
103
+ * activity won't be retried if it fails due to resource exhaustion (429)
104
+ */
105
+ exit_on_resource_exhaustion?: boolean;
101
106
  }
102
107
 
103
108
  /**
@@ -153,11 +158,11 @@ export async function executeInteraction(payload: DSLActivityExecutionPayload<Ex
153
158
 
154
159
  // Handle image uploads if the result contains base64 images
155
160
  if (res.output_modality === Modalities.image) {
156
- const images = res.result.images;
161
+ const images = res.result.filter((r: { type: string; }) => r.type === 'image');
157
162
  const uploadedImages = await Promise.all(
158
- images.map((image: string, index: number) => {
163
+ images.map((image: { value: string; }, index: number) => {
159
164
  // Extract base64 data and create buffer
160
- const base64Data = image.replace(/^data:image\/[a-z]+;base64,/, "");
165
+ const base64Data = image.value.replace(/^data:image\/[a-z]+;base64,/, "");
161
166
  const buffer = Buffer.from(base64Data, 'base64');
162
167
 
163
168
  // Generate filename
@@ -177,7 +182,7 @@ export async function executeInteraction(payload: DSLActivityExecutionPayload<Ex
177
182
  return client.files.uploadFile(source);
178
183
  })
179
184
  );
180
- res.result.images = uploadedImages;
185
+ res.result = uploadedImages.map(file => ({ type: "image", value: file }));
181
186
  }
182
187
 
183
188
  return projectResult(payload, params, res, {
@@ -187,15 +192,17 @@ export async function executeInteraction(payload: DSLActivityExecutionPayload<Ex
187
192
  });
188
193
 
189
194
  } catch (error: any) {
190
- log.error("Failed to execute interaction", { error });
191
- if (error.message.includes("Failed to validate merged prompt schema")) {
195
+ log.error(`Failed to execute interaction ${interactionName}`, { error });
196
+ if (error.statusCode === 429 && params.exit_on_resource_exhaustion) {
197
+ throw new ResourceExhaustedError(error.statusCode, "Resource exhausted - rate limit exceeded");
198
+ } else if (error.message.includes("Failed to validate merged prompt schema")) {
192
199
  //issue with the input data, don't retry
193
200
  throw new ActivityParamInvalidError("prompt_data", payload.activity, error.message);
194
201
  } else if (error.message.includes("modelId: Path `modelId` is required")) {
195
202
  //issue with the input data, don't retry
196
203
  throw new ActivityParamInvalidError("model", payload.activity, error.message);
197
204
  } else {
198
- throw error;
205
+ throw new Error(`Interaction Execution failed ${interactionName}: ${error.message}`);
199
206
  }
200
207
  }
201
208
  }
@@ -270,7 +277,7 @@ export async function executeInteractionFromActivity(
270
277
  })
271
278
  .catch((err) => {
272
279
  log.error(`Error executing interaction ${interactionName}`, { err });
273
- throw new Error(`Interaction Execution failed ${interactionName}: ${err.message}`);
280
+ throw err;
274
281
  });
275
282
 
276
283
  if (debug) {
@@ -1,8 +1,9 @@
1
1
  import { log } from "@temporalio/activity";
2
2
  import { DSLActivityExecutionPayload, DSLActivitySpec } from "@vertesia/common";
3
3
  import { setupActivity } from "../dsl/setup/ActivityContext.js";
4
- import { TruncateSpec } from "../utils/tokens.js";
4
+ import { TruncateSpec, truncByMaxTokens } from "../utils/tokens.js";
5
5
  import { InteractionExecutionParams, executeInteractionFromActivity } from "./executeInteraction.js";
6
+ import { parseCompletionResultsToJson } from "@llumiverse/common";
6
7
 
7
8
  const INT_EXTRACT_INFORMATION = "sys:ExtractInformation";
8
9
  export interface GenerateDocumentPropertiesParams extends InteractionExecutionParams {
@@ -55,8 +56,12 @@ export async function generateDocumentProperties(
55
56
  return undefined;
56
57
  };
57
58
 
59
+ const content = doc.text
60
+ ? truncByMaxTokens(doc.text, params.truncate || 30000)
61
+ : undefined;
62
+
58
63
  const promptData = {
59
- content: doc.text ?? undefined,
64
+ content: content,
60
65
  image: getImageRef() ?? undefined,
61
66
  human_context: project?.configuration?.human_context ?? undefined,
62
67
  };
@@ -84,11 +89,12 @@ export async function generateDocumentProperties(
84
89
  return undefined;
85
90
  }
86
91
  let text = "";
87
- if (infoRes.result.title) {
88
- text += infoRes.result.title + "\n";
92
+ const jsonResult = parseCompletionResultsToJson(infoRes.result);
93
+ if (jsonResult.title) {
94
+ text += jsonResult.title + "\n";
89
95
  }
90
- if (infoRes.result.description) {
91
- text += infoRes.result.description;
96
+ if (jsonResult.description) {
97
+ text += jsonResult.description;
92
98
  }
93
99
  if (text) {
94
100
  return text;
@@ -100,7 +106,7 @@ export async function generateDocumentProperties(
100
106
  log.info(`Extracted information from object ${objectId} with type ${type.name}`, { runId: infoRes.id });
101
107
  await client.objects.update(doc.id, {
102
108
  properties: {
103
- ...infoRes.result,
109
+ ...parseCompletionResultsToJson(infoRes.result),
104
110
  etag: doc.text_etag,
105
111
  },
106
112
  text: getText(),
@@ -15,6 +15,7 @@ import {
15
15
  InteractionExecutionParams,
16
16
  executeInteractionFromActivity,
17
17
  } from "./executeInteraction.js";
18
+ import { parseCompletionResultsToJson } from "@llumiverse/common";
18
19
 
19
20
  const INT_SELECT_DOCUMENT_TYPE = "sys:SelectDocumentType";
20
21
  const INT_GENERATE_METADATA_MODEL = "sys:GenerateMetadataModel";
@@ -119,7 +120,7 @@ export async function generateOrAssignContentType(
119
120
 
120
121
  log.info(
121
122
  "Execute SelectDocumentType interaction on content with \nexisting types - passing full types: " +
122
- existing_types.filter((t) => !t.tags?.includes("system")),
123
+ existing_types.filter((t) => !t.tags?.includes("system")),
123
124
  );
124
125
 
125
126
  const res = await executeInteractionFromActivity(
@@ -133,12 +134,15 @@ export async function generateOrAssignContentType(
133
134
  },
134
135
  );
135
136
 
136
- log.info("Selected Content Type Result: " + JSON.stringify(res.result));
137
+ const jsonResult = parseCompletionResultsToJson(res.result);
138
+
139
+ log.info("Selected Content Type Result: " + JSON.stringify(jsonResult));
140
+
137
141
 
138
142
  //if type is not identified or not present in the database, generate a new type
139
143
  let selectedType: { id: string; name: string } | undefined = undefined;
140
144
 
141
- selectedType = types.find((t) => t.name === res.result.document_type);
145
+ selectedType = types.find((t) => t.name === jsonResult.document_type);
142
146
 
143
147
  if (!selectedType) {
144
148
  log.warn("Document type not identified: starting type generation");
@@ -153,7 +157,7 @@ export async function generateOrAssignContentType(
153
157
 
154
158
  if (!selectedType) {
155
159
  log.error("Type not found: ", res.result);
156
- throw new Error("Type not found: " + res.result.document_type);
160
+ throw new Error("Type not found: " + jsonResult.document_type);
157
161
  }
158
162
 
159
163
  //update object with selected type
@@ -193,18 +197,20 @@ async function generateNewType(
193
197
  },
194
198
  );
195
199
 
196
- if (!genTypeRes.result.document_type) {
200
+ const jsonResult = parseCompletionResultsToJson(genTypeRes.result);
201
+
202
+ if (!jsonResult.document_type) {
197
203
  log.error("No name generated for type", genTypeRes);
198
204
  throw new Error("No name generated for type");
199
205
  }
200
206
 
201
- log.info("Generated schema for type", genTypeRes.result.metadata_schema);
207
+ log.info("Generated schema for type", jsonResult.metadata_schema);
202
208
  const typeData: CreateContentObjectTypePayload = {
203
- name: genTypeRes.result.document_type,
204
- description: genTypeRes.result.document_type_description,
205
- object_schema: genTypeRes.result.metadata_schema,
206
- is_chunkable: genTypeRes.result.is_chunkable,
207
- table_layout: genTypeRes.result.table_layout,
209
+ name: jsonResult.document_type,
210
+ description: jsonResult.document_type_description,
211
+ object_schema: jsonResult.metadata_schema,
212
+ is_chunkable: jsonResult.is_chunkable,
213
+ table_layout: jsonResult.table_layout,
208
214
  };
209
215
 
210
216
  const type = await client.types.create(typeData);
@@ -17,4 +17,4 @@ export { convertPdfToStructuredText } from "./media/processPdfWithTextract.js";
17
17
  export { transcribeMedia } from "./media/transcribeMediaWithGladia.js";
18
18
  export { notifyWebhook } from "./notifyWebhook.js";
19
19
  export { setDocumentStatus } from "./setDocumentStatus.js";
20
- export { identifyTextSections } from "./identifyTextSections.js";
20
+ export { checkRateLimit } from "./rateLimiter.js";
@@ -1,32 +1,134 @@
1
1
  import {
2
2
  MockActivityEnvironment,
3
- TestWorkflowEnvironment,
4
3
  } from "@temporalio/testing";
5
- import { beforeAll, describe, expect, test } from "vitest";
6
- import { notifyWebhook, NotifyWebhook } from "./notifyWebhook.js";
4
+ import { ContentEventName, DSLActivityExecutionPayload } from "@vertesia/common";
5
+ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { notifyWebhook, NotifyWebhookParams } from "./notifyWebhook.js";
7
7
 
8
- let testEnv: TestWorkflowEnvironment;
9
- let activityContext: MockActivityEnvironment;
8
+ // Mock fetch globally
9
+ vi.stubGlobal('fetch', vi.fn());
10
+
11
+ let testEnv: MockActivityEnvironment;
12
+ const mockFetch = vi.mocked(fetch);
10
13
 
11
14
  beforeAll(async () => {
12
- testEnv = await TestWorkflowEnvironment.createLocal();
13
- activityContext = new MockActivityEnvironment();
15
+ testEnv = new MockActivityEnvironment();
16
+ });
17
+
18
+ beforeEach(() => {
19
+ vi.clearAllMocks();
14
20
  });
15
21
 
16
- // https://github.com/becomposable/studio/issues/432 Skip tests
17
- // Cannot read properties of undefined (reading 'params')
22
+ const defaultParams = {
23
+ webhook: "https://vertesia.test",
24
+ method: "POST" as const,
25
+ detail: { message: "Hello World" },
26
+ workflow_id: "wf_id",
27
+ workflow_type: "wfFuncName",
28
+ workflow_run_id: "wf_run_id",
29
+ event_name: "completed",
30
+ } satisfies NotifyWebhookParams;
31
+
32
+ // Helper function to create test payload
33
+ const createTestPayload = (params: Partial<NotifyWebhookParams> = {}): DSLActivityExecutionPayload<NotifyWebhookParams> => {
34
+ const mergedParams = { ...defaultParams, ...params };
35
+ return {
36
+ auth_token: "unset",
37
+ account_id: "unset",
38
+ project_id: "unset",
39
+ params: mergedParams,
40
+ config: {
41
+ studio_url: "http://mock-studio",
42
+ store_url: "http://mock-store",
43
+ },
44
+ workflow_name: "",
45
+ event: ContentEventName.create,
46
+ objectIds: [],
47
+ vars: {},
48
+ activity: { name: "notifyWebhook", params: mergedParams }
49
+ };
50
+ };
51
+
18
52
  describe("Webhook should be notified", () => {
19
- test.skip("test POST", async () => {
20
- const activityConfig = {
21
- name: "notifyWebhook",
22
- params: {
23
- target_url: "https://en5zdcyvn4dc3.x.pipedream.net",
24
- method: "POST",
25
- payload: { message: "Hello World" },
53
+ it("test POST success", async () => {
54
+ // Mock successful response
55
+ const mockResponse = {
56
+ ok: true,
57
+ status: 200,
58
+ statusText: 'OK',
59
+ url: defaultParams.webhook
60
+ };
61
+ mockFetch.mockResolvedValueOnce(mockResponse as Response);
62
+
63
+ const payload = createTestPayload();
64
+ const res = await testEnv.run(notifyWebhook, payload);
65
+
66
+ // Verify fetch was called with correct parameters
67
+ expect(mockFetch).toHaveBeenCalledWith(defaultParams.webhook, {
68
+ method: 'POST',
69
+ body: JSON.stringify({ message: 'Hello World' }),
70
+ headers: {
71
+ 'Content-Type': 'application/json',
26
72
  },
27
- } satisfies NotifyWebhook;
73
+ });
28
74
 
29
- const res = await activityContext.run(notifyWebhook, activityConfig);
30
- expect(res).toBeDefined();
75
+ // Verify response
76
+ expect(res).toEqual({
77
+ status: 200,
78
+ message: 'OK',
79
+ url: defaultParams.webhook
80
+ });
31
81
  });
82
+
83
+ it("test POST server error", async () => {
84
+ // Mock error response with response body
85
+ const mockResponse = {
86
+ ok: false,
87
+ status: 500,
88
+ statusText: 'Internal Server Error',
89
+ url: defaultParams.webhook,
90
+ text: vi.fn().mockResolvedValue('{"error": "Database connection failed", "code": "DB_ERROR"}')
91
+ } as unknown as Response;
92
+ mockFetch.mockResolvedValueOnce(mockResponse);
93
+
94
+ const payload = createTestPayload();
95
+
96
+ // Expect the function to throw an error with response payload
97
+ await expect(testEnv.run(notifyWebhook, payload)).rejects.toThrow(
98
+ `Webhook Notification to ${defaultParams.webhook} failed with status: 500 Internal Server Error - Response: {"error": "Database connection failed", "code": "DB_ERROR"}`
99
+ );
100
+
101
+ // Verify fetch was called with correct parameters
102
+ expect(mockFetch).toHaveBeenCalledWith(defaultParams.webhook, {
103
+ method: 'POST',
104
+ body: JSON.stringify({ message: 'Hello World' }),
105
+ headers: {
106
+ 'Content-Type': 'application/json',
107
+ },
108
+ });
109
+
110
+ // Verify that text() was called to read the response
111
+ expect(mockResponse.text).toHaveBeenCalled();
112
+ });
113
+
114
+ it("test POST network error", async () => {
115
+ // Mock fetch to throw a network error
116
+ const networkError = new Error('Network request failed');
117
+ mockFetch.mockRejectedValueOnce(networkError);
118
+
119
+ const payload = createTestPayload();
120
+
121
+ // Expect the function to throw the network error
122
+ await expect(testEnv.run(notifyWebhook, payload)).rejects.toThrow('Network request failed');
123
+
124
+ // Verify fetch was called with correct parameters
125
+ expect(mockFetch).toHaveBeenCalledWith(defaultParams.webhook, {
126
+ method: 'POST',
127
+ body: JSON.stringify({ message: 'Hello World' }),
128
+ headers: {
129
+ 'Content-Type': 'application/json',
130
+ },
131
+ });
132
+ });
133
+
32
134
  });