@outputai/core 0.4.1-dev.10cf346.0 → 0.4.1-dev.222a94b.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/package.json +5 -4
- package/src/activity_integration/tracing.d.ts +5 -11
- package/src/activity_integration/tracing.js +4 -10
- package/src/consts.js +4 -0
- package/src/hooks/index.d.ts +3 -9
- package/src/hooks/index.js +6 -6
- package/src/interface/aggregations.js +24 -0
- package/src/interface/aggregations.spec.js +91 -0
- package/src/interface/workflow.d.ts +1 -12
- package/src/interface/workflow.js +38 -26
- package/src/interface/workflow.spec.js +183 -7
- package/src/interface/workflow_context.js +2 -4
- package/src/tracing/processors/local/index.js +10 -4
- package/src/tracing/processors/local/index.spec.js +52 -21
- package/src/tracing/processors/s3/index.js +3 -3
- package/src/tracing/processors/s3/index.spec.js +26 -1
- package/src/tracing/processors/s3/s3_client.js +11 -3
- package/src/tracing/processors/s3/s3_client.spec.js +27 -15
- package/src/tracing/tools/build_trace_tree.js +1 -1
- package/src/tracing/tools/build_trace_tree.spec.js +49 -11
- package/src/tracing/tools/utils.js +0 -28
- package/src/tracing/tools/utils.spec.js +2 -134
- package/src/tracing/trace_attribute.d.ts +38 -0
- package/src/tracing/trace_attribute.js +80 -0
- package/src/tracing/trace_engine.js +12 -2
- package/src/worker/index.js +1 -1
- package/src/worker/index.spec.js +1 -1
- package/src/worker/interceptors/activity.js +9 -2
- package/src/worker/interceptors/activity.spec.js +16 -3
- package/src/worker/interceptors.js +2 -2
- package/src/worker/sinks.js +6 -6
- package/src/tracing/tools/aggregate_trace_attributes.js +0 -118
- package/src/tracing/tools/aggregate_trace_attributes.spec.js +0 -231
- package/src/tracing/tools/index.js +0 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/core",
|
|
3
|
-
"version": "0.4.1-dev.
|
|
3
|
+
"version": "0.4.1-dev.222a94b.0",
|
|
4
4
|
"description": "The core module of the output framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,9 +19,6 @@
|
|
|
19
19
|
"./sdk_utils": {
|
|
20
20
|
"types": "./src/utils/index.d.ts",
|
|
21
21
|
"import": "./src/utils/index.js"
|
|
22
|
-
},
|
|
23
|
-
"./sdk_tracing_tools": {
|
|
24
|
-
"import": "./src/tracing/tools/index.js"
|
|
25
22
|
}
|
|
26
23
|
},
|
|
27
24
|
"files": [
|
|
@@ -36,6 +33,7 @@
|
|
|
36
33
|
},
|
|
37
34
|
"dependencies": {
|
|
38
35
|
"@aws-sdk/client-s3": "3.1038.0",
|
|
36
|
+
"@aws-sdk/lib-storage": "3.1038.0",
|
|
39
37
|
"@babel/generator": "7.29.1",
|
|
40
38
|
"@babel/parser": "7.29.2",
|
|
41
39
|
"@babel/traverse": "7.29.0",
|
|
@@ -45,6 +43,8 @@
|
|
|
45
43
|
"@temporalio/common": "1.17.0",
|
|
46
44
|
"@temporalio/worker": "1.17.0",
|
|
47
45
|
"@temporalio/workflow": "1.17.0",
|
|
46
|
+
"decimal.js": "10.6.0",
|
|
47
|
+
"json-stream-stringify": "3.1.6",
|
|
48
48
|
"redis": "5.12.1",
|
|
49
49
|
"stacktrace-parser": "0.1.11",
|
|
50
50
|
"undici": "8.1.0",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"#logger": "./src/logger.js",
|
|
68
68
|
"#utils": "./src/utils/index.js",
|
|
69
69
|
"#tracing": "./src/tracing/internal_interface.js",
|
|
70
|
+
"#trace_attribute": "./src/tracing/trace_attribute.js",
|
|
70
71
|
"#async_storage": "./src/async_storage.js",
|
|
71
72
|
"#internal_activities": "./src/internal_activities/index.js"
|
|
72
73
|
},
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { Attribute } from '#trace_attribute';
|
|
2
|
+
|
|
3
|
+
export { Attribute } from '#trace_attribute';
|
|
1
4
|
/**
|
|
2
5
|
* Creates a new event.
|
|
3
6
|
*
|
|
@@ -32,15 +35,6 @@ export declare function addEventError( args: { id: string; details: unknown } ):
|
|
|
32
35
|
*
|
|
33
36
|
* @param args
|
|
34
37
|
* @param args.eventId - The id of the event to attach the attribute to.
|
|
35
|
-
* @param args.
|
|
36
|
-
* @param args.value - The attribute value
|
|
37
|
-
*/
|
|
38
|
-
export declare function addEventAttribute( args: { eventId: string; name: string, value: unknown } ): void;
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Known attributes.
|
|
38
|
+
* @param args.attribute - The attribute to attach to the event.
|
|
42
39
|
*/
|
|
43
|
-
export declare
|
|
44
|
-
COST: 'cost';
|
|
45
|
-
TOKEN_USAGE: 'token_usage';
|
|
46
|
-
};
|
|
40
|
+
export declare function addEventAttribute( args: { eventId: string; attribute: Attribute.Instance } ): void;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { addEventActionWithContext, EventAction } from '#tracing';
|
|
2
2
|
|
|
3
|
+
export { Attribute } from '#trace_attribute';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Creates a new event.
|
|
5
7
|
*
|
|
@@ -42,13 +44,5 @@ export const addEventError = ( { id, details } ) => addEventActionWithContext( E
|
|
|
42
44
|
* @param {unknown} args.value - The attribute value
|
|
43
45
|
* @returns {void}
|
|
44
46
|
*/
|
|
45
|
-
export const addEventAttribute = ( { eventId,
|
|
46
|
-
addEventActionWithContext( EventAction.ADD_ATTR, { id: eventId, details:
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Known attributes
|
|
50
|
-
*/
|
|
51
|
-
export const Attribute = {
|
|
52
|
-
COST: 'cost',
|
|
53
|
-
TOKEN_USAGE: 'token_usage'
|
|
54
|
-
};
|
|
47
|
+
export const addEventAttribute = ( { eventId, attribute } ) =>
|
|
48
|
+
addEventActionWithContext( EventAction.ADD_ATTR, { id: eventId, details: attribute } );
|
package/src/consts.js
CHANGED
package/src/hooks/index.d.ts
CHANGED
|
@@ -16,10 +16,8 @@ export interface ErrorHookPayload {
|
|
|
16
16
|
* Payload passed to the onWorkflowStart handler when a workflow run begins.
|
|
17
17
|
*/
|
|
18
18
|
export interface WorkflowStartHookPayload {
|
|
19
|
-
/**
|
|
19
|
+
/** Identifier of the workflow run. */
|
|
20
20
|
id: string;
|
|
21
|
-
/** Temporal run id for the current execution attempt. */
|
|
22
|
-
runId: string;
|
|
23
21
|
/** Name of the workflow. */
|
|
24
22
|
name: string;
|
|
25
23
|
}
|
|
@@ -28,10 +26,8 @@ export interface WorkflowStartHookPayload {
|
|
|
28
26
|
* Payload passed to the onWorkflowEnd handler when a workflow run completes successfully.
|
|
29
27
|
*/
|
|
30
28
|
export interface WorkflowEndHookPayload {
|
|
31
|
-
/**
|
|
29
|
+
/** Identifier of the workflow run. */
|
|
32
30
|
id: string;
|
|
33
|
-
/** Temporal run id for the current execution attempt. */
|
|
34
|
-
runId: string;
|
|
35
31
|
/** Name of the workflow. */
|
|
36
32
|
name: string;
|
|
37
33
|
/** Duration of the workflow run in milliseconds. */
|
|
@@ -42,10 +38,8 @@ export interface WorkflowEndHookPayload {
|
|
|
42
38
|
* Payload passed to the onWorkflowError handler when a workflow run fails.
|
|
43
39
|
*/
|
|
44
40
|
export interface WorkflowErrorHookPayload {
|
|
45
|
-
/**
|
|
41
|
+
/** Identifier of the workflow run. */
|
|
46
42
|
id: string;
|
|
47
|
-
/** Temporal run id for the current execution attempt. */
|
|
48
|
-
runId: string;
|
|
49
43
|
/** Name of the workflow. */
|
|
50
44
|
name: string;
|
|
51
45
|
/** Elapsed time before failure in milliseconds. */
|
package/src/hooks/index.js
CHANGED
|
@@ -34,16 +34,16 @@ export const onBeforeWorkerStart = handler => messageBus.on( BusEventType.WORKER
|
|
|
34
34
|
safeInvoke( handler, undefined, 'onBeforeWorkerStart' ) );
|
|
35
35
|
|
|
36
36
|
/** Listen to workflow start events, excludes catalog workflow */
|
|
37
|
-
export const onWorkflowStart = handler => messageBus.on( BusEventType.WORKFLOW_START, ( { id,
|
|
38
|
-
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id,
|
|
37
|
+
export const onWorkflowStart = handler => messageBus.on( BusEventType.WORKFLOW_START, ( { id, name } ) =>
|
|
38
|
+
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id, name }, 'onWorkflowStart' ) : null );
|
|
39
39
|
|
|
40
40
|
/** Listen to workflow end events, excludes catalog workflow */
|
|
41
|
-
export const onWorkflowEnd = handler => messageBus.on( BusEventType.WORKFLOW_END, ( { id,
|
|
42
|
-
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id,
|
|
41
|
+
export const onWorkflowEnd = handler => messageBus.on( BusEventType.WORKFLOW_END, ( { id, name, duration } ) =>
|
|
42
|
+
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id, name, duration }, 'onWorkflowEnd' ) : null );
|
|
43
43
|
|
|
44
44
|
/** Listen to workflow error events, excludes catalog workflow */
|
|
45
|
-
export const onWorkflowError = handler => messageBus.on( BusEventType.WORKFLOW_ERROR, ( { id,
|
|
46
|
-
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id,
|
|
45
|
+
export const onWorkflowError = handler => messageBus.on( BusEventType.WORKFLOW_ERROR, ( { id, name, duration, error } ) =>
|
|
46
|
+
WORKFLOW_CATALOG !== name ? safeInvoke( handler, { id, name, duration, error }, 'onWorkflowError' ) : null );
|
|
47
47
|
|
|
48
48
|
/** Generic listener for events emitted elsewhere (outside core) */
|
|
49
49
|
export const on = ( eventName, handler ) => messageBus.on( `external:${eventName}`, payload =>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Attribute } from '#trace_attribute';
|
|
2
|
+
import Decimal from 'decimal.js';
|
|
3
|
+
|
|
4
|
+
export const aggregateAttributes = attributes => ( {
|
|
5
|
+
cost: {
|
|
6
|
+
total: attributes
|
|
7
|
+
.filter( a => [ Attribute.HTTPRequestCost.TYPE, Attribute.LLMUsage.TYPE ].includes( a.type ) )
|
|
8
|
+
.reduce( ( sum, a ) => sum.add( a.total ), Decimal( 0 ) ).toNumber()
|
|
9
|
+
},
|
|
10
|
+
tokens: {
|
|
11
|
+
total: attributes
|
|
12
|
+
.filter( a => Attribute.LLMUsage.TYPE === a.type )
|
|
13
|
+
.reduce( ( sum, a ) => sum.add( a.tokensUsed ), Decimal( 0 ) ).toNumber(),
|
|
14
|
+
...Object.entries( attributes
|
|
15
|
+
.filter( a => Attribute.LLMUsage.TYPE === a.type )
|
|
16
|
+
.flatMap( a => a.usage )
|
|
17
|
+
.reduce( ( obj, a ) => Object.assign( obj, { [a.type]: ( obj[a.type] ?? Decimal( 0 ) ).add( a.amount ) } ), {} ) )
|
|
18
|
+
.reduce( ( obj, [ k, v ] ) => Object.assign( obj, { [k]: v.toNumber() } ), {} ) // convert all values to number
|
|
19
|
+
|
|
20
|
+
},
|
|
21
|
+
httpRequests: {
|
|
22
|
+
total: attributes.filter( a => Attribute.HTTPRequestCount.TYPE === a.type ).length
|
|
23
|
+
}
|
|
24
|
+
} );
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { Attribute } from '#trace_attribute';
|
|
3
|
+
import { aggregateAttributes } from './aggregations.js';
|
|
4
|
+
|
|
5
|
+
describe( 'aggregateAttributes', () => {
|
|
6
|
+
it( 'returns zeroed aggregations when there are no attributes', () => {
|
|
7
|
+
expect( aggregateAttributes( [] ) ).toEqual( {
|
|
8
|
+
cost: { total: 0 },
|
|
9
|
+
tokens: { total: 0 },
|
|
10
|
+
httpRequests: { total: 0 }
|
|
11
|
+
} );
|
|
12
|
+
} );
|
|
13
|
+
|
|
14
|
+
it( 'aggregates costs, token usage, and HTTP request count by attribute type', () => {
|
|
15
|
+
const attributes = [
|
|
16
|
+
{
|
|
17
|
+
type: Attribute.HTTPRequestCount.TYPE,
|
|
18
|
+
url: 'https://api.example.test/a',
|
|
19
|
+
requestId: 'req-1'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: Attribute.HTTPRequestCount.TYPE,
|
|
23
|
+
url: 'https://api.example.test/b',
|
|
24
|
+
requestId: 'req-2'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: Attribute.HTTPRequestCost.TYPE,
|
|
28
|
+
url: 'https://api.example.test/a',
|
|
29
|
+
requestId: 'req-1',
|
|
30
|
+
total: 0.2
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: Attribute.LLMUsage.TYPE,
|
|
34
|
+
modelId: 'gpt-4o',
|
|
35
|
+
total: 0.3,
|
|
36
|
+
tokensUsed: 120,
|
|
37
|
+
usage: [
|
|
38
|
+
{ type: 'input', ppm: 1, amount: 100, total: 0.1 },
|
|
39
|
+
{ type: 'output', ppm: 2, amount: 20, total: 0.2 }
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: Attribute.LLMUsage.TYPE,
|
|
44
|
+
modelId: 'gpt-4o-mini',
|
|
45
|
+
total: 0.05,
|
|
46
|
+
tokensUsed: 30,
|
|
47
|
+
usage: [
|
|
48
|
+
{ type: 'input', ppm: 1, amount: 25, total: 0.025 },
|
|
49
|
+
{ type: 'reasoning', ppm: 5, amount: 5, total: 0.025 }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'unrelated',
|
|
54
|
+
total: 100,
|
|
55
|
+
tokensUsed: 100
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
expect( aggregateAttributes( attributes ) ).toEqual( {
|
|
60
|
+
cost: { total: 0.55 },
|
|
61
|
+
tokens: {
|
|
62
|
+
total: 150,
|
|
63
|
+
input: 125,
|
|
64
|
+
output: 20,
|
|
65
|
+
reasoning: 5
|
|
66
|
+
},
|
|
67
|
+
httpRequests: { total: 2 }
|
|
68
|
+
} );
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
it( 'uses LLMUsage.tokensUsed for total tokens instead of summing usage amounts', () => {
|
|
72
|
+
const attributes = [
|
|
73
|
+
{
|
|
74
|
+
type: Attribute.LLMUsage.TYPE,
|
|
75
|
+
modelId: 'provider-model',
|
|
76
|
+
total: 0.1,
|
|
77
|
+
tokensUsed: 42,
|
|
78
|
+
usage: [
|
|
79
|
+
{ type: 'input', ppm: 1, amount: 10, total: 0.01 },
|
|
80
|
+
{ type: 'output', ppm: 1, amount: 5, total: 0.005 }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
expect( aggregateAttributes( attributes ).tokens ).toEqual( {
|
|
86
|
+
total: 42,
|
|
87
|
+
input: 10,
|
|
88
|
+
output: 5
|
|
89
|
+
} );
|
|
90
|
+
} );
|
|
91
|
+
} );
|
|
@@ -63,18 +63,7 @@ export type WorkflowContext<
|
|
|
63
63
|
*
|
|
64
64
|
* @see {@link https://docs.temporal.io/workflow-execution/workflowid-runid#workflow-id}
|
|
65
65
|
*/
|
|
66
|
-
workflowId: string
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Internal Temporal run id for the current execution attempt.
|
|
70
|
-
*
|
|
71
|
-
* A single `workflowId` can map to multiple `runId`s when a workflow is
|
|
72
|
-
* retried, reset, or continued-as-new. The current run can be pinned in
|
|
73
|
-
* downstream `/workflow/{id}/runs/{rid}/...` API calls.
|
|
74
|
-
*
|
|
75
|
-
* @see {@link https://docs.temporal.io/workflow-execution/workflowid-runid#run-id}
|
|
76
|
-
*/
|
|
77
|
-
runId: string
|
|
66
|
+
workflowId: string
|
|
78
67
|
}
|
|
79
68
|
};
|
|
80
69
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// THIS RUNS IN THE TEMPORAL'S SANDBOX ENVIRONMENT
|
|
2
2
|
import { proxyActivities, inWorkflowContext, executeChild, workflowInfo, uuid4, ParentClosePolicy, continueAsNew } from '@temporalio/workflow';
|
|
3
|
+
import { defineSignal, setHandler } from '@temporalio/workflow';
|
|
3
4
|
import { validateWorkflow } from './validations/static.js';
|
|
4
5
|
import { validateWithSchema } from './validations/runtime.js';
|
|
5
|
-
import { SHARED_STEP_PREFIX, ACTIVITY_GET_TRACE_DESTINATIONS, METADATA_ACCESS_SYMBOL } from '#consts';
|
|
6
|
+
import { SHARED_STEP_PREFIX, ACTIVITY_GET_TRACE_DESTINATIONS, METADATA_ACCESS_SYMBOL, Signal } from '#consts';
|
|
6
7
|
import { deepMerge, setMetadata, toUrlSafeBase64 } from '#utils';
|
|
7
8
|
import { FatalError, ValidationError } from '#errors';
|
|
8
9
|
import { Context } from './workflow_context.js';
|
|
10
|
+
import { aggregateAttributes } from './aggregations.js';
|
|
9
11
|
|
|
10
12
|
const defaultOptions = {
|
|
11
13
|
activityOptions: {
|
|
@@ -22,6 +24,9 @@ const defaultOptions = {
|
|
|
22
24
|
disableTrace: false
|
|
23
25
|
};
|
|
24
26
|
|
|
27
|
+
export const extractErrorDetail = ( e, key ) =>
|
|
28
|
+
e ? ( e.details?.find?.( d => d[key] )?.[key] ?? extractErrorDetail( e.cause, key ) ) : null;
|
|
29
|
+
|
|
25
30
|
export function workflow( { name, description, inputSchema, outputSchema, fn, options = {}, aliases = [] } ) {
|
|
26
31
|
validateWorkflow( { name, description, inputSchema, outputSchema, fn, options, aliases } );
|
|
27
32
|
|
|
@@ -39,20 +44,15 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
39
44
|
// this returns a plain function, for example, in unit tests
|
|
40
45
|
if ( !inWorkflowContext() ) {
|
|
41
46
|
validateWithSchema( inputSchema, input, `Workflow ${name} input` );
|
|
42
|
-
const context = Context.build( {
|
|
43
|
-
workflowId: 'test-workflow',
|
|
44
|
-
runId: 'test-run',
|
|
45
|
-
continueAsNew: async () => {},
|
|
46
|
-
isContinueAsNewSuggested: () => false
|
|
47
|
-
} );
|
|
47
|
+
const context = Context.build( { workflowId: 'test-workflow', continueAsNew: async () => {}, isContinueAsNewSuggested: () => false } );
|
|
48
48
|
const output = await fn( input, deepMerge( context, extra.context ) );
|
|
49
49
|
validateWithSchema( outputSchema, output, `Workflow ${name} output` );
|
|
50
50
|
return output;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const { workflowId,
|
|
53
|
+
const { workflowId, memo, startTime } = workflowInfo();
|
|
54
54
|
|
|
55
|
-
const context = Context.build( { workflowId,
|
|
55
|
+
const context = Context.build( { workflowId, continueAsNew, isContinueAsNewSuggested: () => workflowInfo().continueAsNewSuggested } );
|
|
56
56
|
|
|
57
57
|
// Root workflows will not have the execution context yet, since it is set here.
|
|
58
58
|
const isRoot = !memo.executionContext;
|
|
@@ -62,7 +62,6 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
62
62
|
It will be used to as context for tracing (connecting events) */
|
|
63
63
|
const executionContext = memo.executionContext ?? {
|
|
64
64
|
workflowId,
|
|
65
|
-
runId,
|
|
66
65
|
workflowName: name,
|
|
67
66
|
disableTrace,
|
|
68
67
|
startTime: startTime.getTime()
|
|
@@ -75,7 +74,9 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
75
74
|
|
|
76
75
|
// Run the internal activity to retrieve the workflow trace destinations (only for root workflows, not nested)
|
|
77
76
|
const traceDestinations = isRoot ? ( await steps[ACTIVITY_GET_TRACE_DESTINATIONS]( executionContext ) ) : null;
|
|
78
|
-
|
|
77
|
+
|
|
78
|
+
const attributes = [];
|
|
79
|
+
setHandler( defineSignal( Signal.ADD_ATTRIBUTE ), e => attributes.push( e ) );
|
|
79
80
|
|
|
80
81
|
try {
|
|
81
82
|
// validation comes after setting memo to have that info already set for interceptor even if validations fail
|
|
@@ -97,17 +98,25 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
97
98
|
* @param {import('@temporalio/workflow').ActivityOptions} extra.options
|
|
98
99
|
* @returns {Promise<unknown>}
|
|
99
100
|
*/
|
|
100
|
-
startWorkflow: async ( childName, input, extra = {} ) =>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
101
|
+
startWorkflow: async ( childName, input, extra = {} ) => {
|
|
102
|
+
try {
|
|
103
|
+
const result = await executeChild( childName, {
|
|
104
|
+
args: input ? [ input ] : [],
|
|
105
|
+
workflowId: `${workflowId}-${toUrlSafeBase64( uuid4() )}`,
|
|
106
|
+
parentClosePolicy: ParentClosePolicy[extra?.detached ? 'ABANDON' : 'TERMINATE'],
|
|
107
|
+
memo: {
|
|
108
|
+
executionContext,
|
|
109
|
+
parentId: workflowId,
|
|
110
|
+
...( extra?.options?.activityOptions && { activityOptions: deepMerge( activityOptions, extra.options.activityOptions ) } )
|
|
111
|
+
}
|
|
112
|
+
} );
|
|
113
|
+
attributes.push( ...( result.attributes ?? [] ) );
|
|
114
|
+
return result.output;
|
|
115
|
+
} catch ( error ) {
|
|
116
|
+
attributes.push( ...( extractErrorDetail( error, 'attributes' ) ?? [] ) );
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
111
120
|
};
|
|
112
121
|
|
|
113
122
|
const output = await fn.call( dispatchers, input, context );
|
|
@@ -116,14 +125,17 @@ export function workflow( { name, description, inputSchema, outputSchema, fn, op
|
|
|
116
125
|
|
|
117
126
|
if ( isRoot ) {
|
|
118
127
|
// Append the trace info to the result of the workflow
|
|
119
|
-
return { output,
|
|
128
|
+
return { output, trace: { destinations: traceDestinations }, attributes, aggregations: aggregateAttributes( attributes ) };
|
|
120
129
|
}
|
|
121
130
|
|
|
122
|
-
return output;
|
|
131
|
+
return { output, attributes };
|
|
123
132
|
} catch ( e ) {
|
|
124
|
-
// Append the
|
|
133
|
+
// Append the extra info as metadata of the error, so it can be read by the interceptor.
|
|
134
|
+
e[METADATA_ACCESS_SYMBOL] = { ...( e[METADATA_ACCESS_SYMBOL] ?? {} ), attributes };
|
|
135
|
+
// if it is roo also add trace/aggregations
|
|
125
136
|
if ( isRoot ) {
|
|
126
|
-
e[METADATA_ACCESS_SYMBOL] = {
|
|
137
|
+
e[METADATA_ACCESS_SYMBOL].trace = { destinations: traceDestinations };
|
|
138
|
+
e[METADATA_ACCESS_SYMBOL].aggregations = aggregateAttributes( attributes );
|
|
127
139
|
}
|
|
128
140
|
throw e;
|
|
129
141
|
}
|