@platforma-sdk/workflow-tengo 6.17.3 → 6.19.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 (68) hide show
  1. package/dist/index.cjs +2 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +2 -0
  4. package/dist/tengo/lib/action-context.lib.tengo +296 -0
  5. package/dist/tengo/lib/assets.lib.tengo +22 -1
  6. package/dist/tengo/lib/exec.limits.lib.tengo +3 -0
  7. package/dist/tengo/lib/exec.runcmd.lib.tengo +4 -0
  8. package/dist/tengo/lib/feats.lib.tengo +9 -1
  9. package/dist/tengo/lib/pframes.bundle.lib.tengo +30 -5
  10. package/dist/tengo/lib/pframes.table-builder.lib.tengo +58 -17
  11. package/dist/tengo/lib/render.lib.tengo +30 -0
  12. package/dist/tengo/lib/smart.lib.tengo +10 -0
  13. package/dist/tengo/lib/tpl.base.lib.tengo +11 -0
  14. package/dist/tengo/lib/v2.bquery.lib.tengo +9 -0
  15. package/dist/tengo/lib/v2.exports.lib.tengo +141 -0
  16. package/dist/tengo/lib/v2.node-rules.lib.tengo +102 -0
  17. package/dist/tengo/lib/v2.workflow.lib.tengo +281 -0
  18. package/dist/tengo/lib/workdir.lib.tengo +4 -0
  19. package/dist/tengo/lib/workdir.save.lib.tengo +3 -0
  20. package/dist/tengo/lib/workflow.bquery.lib.tengo +218 -26
  21. package/dist/tengo/tpl/annotations.compute.plj.gz +0 -0
  22. package/dist/tengo/tpl/anonymize.deanonymize.plj.gz +0 -0
  23. package/dist/tengo/tpl/anonymize.impl.plj.gz +0 -0
  24. package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
  25. package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
  26. package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
  27. package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
  28. package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
  29. package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
  30. package/dist/tengo/tpl/check_network.workdir_type_name_extractor.plj.gz +0 -0
  31. package/dist/tengo/tpl/exec.conda.create-env.plj.gz +0 -0
  32. package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
  33. package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
  34. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  35. package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
  36. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  37. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  38. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  39. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  40. package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
  41. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.build-table.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.export-parquet-pcolumn-chunk.plj.gz +0 -0
  45. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  46. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  47. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  48. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  49. package/dist/tengo/tpl/pframes.merge-resource-maps.plj.gz +0 -0
  50. package/dist/tengo/tpl/pframes.parse-to-json.plj.gz +0 -0
  51. package/dist/tengo/tpl/pframes.process-pcolumn-batch-split.plj.gz +0 -0
  52. package/dist/tengo/tpl/pframes.process-pcolumn-batch.plj.gz +0 -0
  53. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  54. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  55. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  56. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  57. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  58. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  59. package/dist/tengo/tpl/pt.import-dir.plj.gz +0 -0
  60. package/dist/tengo/tpl/pt.workflow-run.plj.gz +0 -0
  61. package/dist/tengo/tpl/v2.export-collection-for-ui.plj.gz +0 -0
  62. package/dist/tengo/tpl/v2.export-for-ui.plj.gz +0 -0
  63. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  64. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  65. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  66. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  67. package/dist/tengo/tpl/workflow.query-context-filter.plj.gz +0 -0
  68. package/package.json +2 -2
@@ -10,6 +10,8 @@ oop := import("@platforma-sdk/workflow-tengo:oop")
10
10
  tx := import("tx")
11
11
  maps := import("@platforma-sdk/workflow-tengo:maps")
12
12
  feats := import("@platforma-sdk/workflow-tengo:feats")
13
+ assets := import("@platforma-sdk/workflow-tengo:assets")
14
+ actionContext := import("@platforma-sdk/workflow-tengo:action-context")
13
15
 
14
16
 
15
17
  _SUBSCRIPTION_FIELD := "subscription"
@@ -27,15 +29,29 @@ _SUBSCRIPTION_FIELD := "subscription"
27
29
 
28
30
 
29
31
 
32
+
33
+
34
+
35
+
36
+
37
+
30
38
 
31
39
 
32
40
  createUniversal := func(tpl, isEph, inputs, ...opts) {
33
41
  ll.assert(len(opts) <= 1, "too many arguments, expected at most one options object")
34
42
  metaInputs := undefined
35
43
  inputCache := undefined
44
+ actionContextName := undefined
45
+ actionContextOff := false
46
+ actionContextBaggage := undefined
36
47
  if len(opts) == 1 && opts[0] {
37
48
  metaInputs = opts[0].metaInputs
38
49
  inputCache = opts[0].inputCache
50
+ actionContextName = opts[0].name
51
+ actionContextOff = opts[0].actionContext == false
52
+ if is_map(opts[0].actionContext) {
53
+ actionContextBaggage = opts[0].actionContext
54
+ }
39
55
  }
40
56
 
41
57
  if !is_undefined(inputCache) && inputCache > 0 && isEph {
@@ -87,6 +103,20 @@ createUniversal := func(tpl, isEph, inputs, ...opts) {
87
103
 
88
104
  rbuilder.createInputField(tplutil.INPUTS_MAP_FIELD).set(inputsMap.build())
89
105
 
106
+
107
+
108
+ if is_undefined(actionContextName) {
109
+ actionContextName = assets.templateName(tpl)
110
+ }
111
+ if !is_undefined(actionContextBaggage) {
112
+ actionContext.createContext(rbuilder.id, actionContextBaggage)
113
+ } else if actionContextOff {
114
+ actionContext.sinkhole(rbuilder.id, actionContextName)
115
+ } else {
116
+ actionContext.createChild(rbuilder.id, actionContextName)
117
+ }
118
+
119
+
90
120
  renderer := rbuilder.lockInputsAndBuild()
91
121
 
92
122
  self := undefined
@@ -12,6 +12,7 @@ json := import("json")
12
12
  times := import("times")
13
13
  constants := import("@platforma-sdk/workflow-tengo:constants")
14
14
  ffDefault := import("@platforma-sdk/workflow-tengo:ll.get-future-field-default")
15
+ actionContext := import("@platforma-sdk/workflow-tengo:action-context")
15
16
 
16
17
 
17
18
 
@@ -758,6 +759,15 @@ resource = func(r) {
758
759
 
759
760
 
760
761
 
762
+ actionContext: func() {
763
+ return actionContext.of(self.id)
764
+ },
765
+
766
+
767
+
768
+
769
+
770
+
761
771
 
762
772
  kvSetFlag: func(key, flag) {
763
773
  ll.assert(feats.fullFeaturedApi, "smart.resource.kvSetFlag: the feature is not available on older backends. Please, update the backend.")
@@ -1,6 +1,7 @@
1
1
  ll := import("@platforma-sdk/workflow-tengo:ll")
2
2
  render := import("@platforma-sdk/workflow-tengo:render")
3
3
  smart := import("@platforma-sdk/workflow-tengo:smart")
4
+ actionContext := import("@platforma-sdk/workflow-tengo:action-context")
4
5
  times := import("times")
5
6
  sets := import("@platforma-sdk/workflow-tengo:sets")
6
7
  maps := import("@platforma-sdk/workflow-tengo:maps")
@@ -152,6 +153,14 @@ tpl := func(ops) {
152
153
 
153
154
 
154
155
 
156
+
157
+ actionContext: func() {
158
+ return actionContext.self()
159
+ },
160
+
161
+
162
+
163
+
155
164
  isEphemeral: func() {
156
165
  return _isEphemeral
157
166
  },
@@ -732,6 +741,7 @@ tpl := func(ops) {
732
741
  api: func() {
733
742
  return ll.toStrict({
734
743
  renderer : self.renderer,
744
+ actionContext : self.actionContext,
735
745
  registerUnmarshaller : self.registerUnmarshaller,
736
746
  rawInputs : self.rawInputs,
737
747
  rawServiceInputs : self.rawServiceInputs,
@@ -739,6 +749,7 @@ tpl := func(ops) {
739
749
  hasInput : self.hasInput,
740
750
  inputs : self.inputs,
741
751
  defineOutputs : self.defineOutputs,
752
+ definedOutputs : func() { return copy(self.definedOutputs) },
742
753
  setOutputCache : self.setOutputCache,
743
754
  setOutputCacheMillis : self.setOutputCacheMillis,
744
755
  setOutputCacheSeconds : self.setOutputCacheSeconds,
@@ -0,0 +1,9 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+ bquery := import("@platforma-sdk/workflow-tengo:workflow.bquery")
8
+
9
+ export bquery.forFamily(2)
@@ -0,0 +1,141 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ ll := import("@platforma-sdk/workflow-tengo:ll")
13
+ smart := import("@platforma-sdk/workflow-tengo:smart")
14
+ maps := import("@platforma-sdk/workflow-tengo:maps")
15
+ constants := import("@platforma-sdk/workflow-tengo:constants")
16
+ bobject := import("@platforma-sdk/workflow-tengo:workflow.bobject")
17
+ rules := import("@platforma-sdk/workflow-tengo:v2.node-rules")
18
+
19
+ _CONSTRUCTORS_HINT := "build it with v2.exports.folder or v2.exports.collection (or pframes.pFrameBuilder)"
20
+
21
+
22
+ _see := func(value) {
23
+ if smart.isField(value) {
24
+ info := value.info()
25
+ if info.IsSet && info.Value != 0 {
26
+ return { kind: "resource", type: value.getValue().info().Type }
27
+ }
28
+ return { kind: "pending" }
29
+ }
30
+ if smart.isResource(value) {
31
+ return { kind: "resource", type: value.info().Type }
32
+ }
33
+ if ll.isMap(value) {
34
+ return { kind: "map", keys: maps.getKeys(value) }
35
+ }
36
+ return { kind: "other", typeName: type_name(value) }
37
+ }
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+ assertNode := func(value, what) {
48
+ got := rules.refusal(_see(value))
49
+ if !is_undefined(got) {
50
+ ll.panic("%s must be a typed node — a folder or a collection — or a reference to one; got %s; %s",
51
+ what, got, _CONSTRUCTORS_HINT)
52
+ }
53
+ }
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+ folder := func(entries) {
63
+ ll.assert(ll.isMap(entries) && !smart.isReference(entries),
64
+ "v2.exports.folder: expected a map of entry name to node, got %v", entries)
65
+
66
+ b := smart.mapBuilder()
67
+ for name in maps.getKeys(entries) {
68
+ rules.assertName(name, "folder entry name")
69
+ node := entries[name]
70
+ if !smart.isReference(node) && ll.isMap(node) && maps.containsKey(node, "spec") {
71
+ ll.panic("folder entry %q is not a node; items belong in a collection (v2.exports.collection)", name)
72
+ }
73
+ assertNode(node, "folder entry \"" + name + "\"")
74
+ b.add(name, node)
75
+ }
76
+ return b.build()
77
+ }
78
+
79
+
80
+ _isNoResult := func(data) {
81
+ if smart.isField(data) {
82
+ info := data.info()
83
+ if !(info.IsSet && info.Value != 0) {
84
+ return false
85
+ }
86
+ data = data.getValue()
87
+ }
88
+ return smart.isResource(data) && data.checkResourceType(constants.RTYPE_BRESOLVE_NO_RESULT)
89
+ }
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ collection := func(items) {
104
+ ll.assert(ll.isMap(items) && !smart.isReference(items),
105
+ "v2.exports.collection: expected a map of item name to {spec, data}, got %v", items)
106
+
107
+ b := smart.structBuilder(rules.COLLECTION_TYPE)
108
+ for name in maps.getKeys(items) {
109
+ rules.assertName(name, "item name")
110
+ item := items[name]
111
+ if smart.isReference(item) || !ll.isMap(item) {
112
+ ll.panic("item %q must be a map {spec, data}, got %v", name, item)
113
+ }
114
+ for key in maps.getKeys(item) {
115
+ if key != "spec" && key != "data" && key != "ref" {
116
+ ll.panic("item %q has key %q; an item has only spec and data", name, key)
117
+ }
118
+ }
119
+
120
+ if !maps.containsKey(item, "spec") || is_undefined(item.spec) {
121
+ ll.panic("item %q has no spec", name)
122
+ }
123
+ spec := item.spec
124
+ if !smart.isReference(spec) {
125
+ spec = bobject.createSpec(spec)
126
+ }
127
+ b.createInputField(name + ".spec").set(spec)
128
+
129
+ data := maps.containsKey(item, "data") ? item.data : undefined
130
+ if !is_undefined(data) && !_isNoResult(data) {
131
+ b.createInputField(name + ".data").setRefOrJson(data)
132
+ }
133
+ }
134
+ return b.lockAndBuild()
135
+ }
136
+
137
+ export ll.toStrict({
138
+ folder: folder,
139
+ collection: collection,
140
+ assertNode: assertNode
141
+ })
@@ -0,0 +1,102 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+ ll := import("@platforma-sdk/workflow-tengo:ll")
10
+ text := import("text")
11
+
12
+ FOLDER_TYPE := { Name: "std/map", Version: "1" }
13
+ COLLECTION_TYPE := { Name: "PFrame", Version: "1" }
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+ nameProblem := func(name) {
27
+ if !is_string(name) {
28
+ return "is not a string"
29
+ }
30
+ if name == "" {
31
+ return "is empty"
32
+ }
33
+ if text.contains(name, ".") {
34
+ return "contains \".\", which joins the names of a path"
35
+ }
36
+ if name == "resourceError" {
37
+ return "is reserved by the backend"
38
+ }
39
+ if text.has_prefix(name, "recovery/") {
40
+ return "starts with \"recovery/\", which the backend reserves"
41
+ }
42
+ return undefined
43
+ }
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+ assertName := func(name, what) {
52
+ problem := nameProblem(name)
53
+ if !is_undefined(problem) {
54
+ ll.panic("%s %q %s", what, name, problem)
55
+ }
56
+ }
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+ isNodeType := func(type) {
65
+ return (type.Name == FOLDER_TYPE.Name && type.Version == FOLDER_TYPE.Version) ||
66
+ (type.Name == COLLECTION_TYPE.Name && type.Version == COLLECTION_TYPE.Version)
67
+ }
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+ refusal := func(seen) {
80
+ if seen.kind == "pending" {
81
+ return undefined
82
+ }
83
+ if seen.kind == "resource" {
84
+ if isNodeType(seen.type) {
85
+ return undefined
86
+ }
87
+ return "a resource of type " + seen.type.Name + "/" + seen.type.Version
88
+ }
89
+ if seen.kind == "map" {
90
+ return "a map with keys [" + text.join(seen.keys, ", ") + "]"
91
+ }
92
+ return "a value of type " + seen.typeName
93
+ }
94
+
95
+ export ll.toStrict({
96
+ FOLDER_TYPE: FOLDER_TYPE,
97
+ COLLECTION_TYPE: COLLECTION_TYPE,
98
+ nameProblem: nameProblem,
99
+ assertName: assertName,
100
+ isNodeType: isNodeType,
101
+ refusal: refusal
102
+ })
@@ -0,0 +1,281 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ ll := import("@platforma-sdk/workflow-tengo:ll")
40
+ text := import("text")
41
+ smart := import("@platforma-sdk/workflow-tengo:smart")
42
+ sets := import("@platforma-sdk/workflow-tengo:sets")
43
+ oop := import("@platforma-sdk/workflow-tengo:oop")
44
+ bquery := import("@platforma-sdk/workflow-tengo:v2.bquery")
45
+ exports := import("@platforma-sdk/workflow-tengo:v2.exports")
46
+ pBundle := import("@platforma-sdk/workflow-tengo:pframes.bundle")
47
+ pTableBuilder := import("@platforma-sdk/workflow-tengo:pframes.table-builder")
48
+
49
+ self := import("@platforma-sdk/workflow-tengo:tpl")
50
+
51
+ _RESULT_OUTPUT := "result"
52
+ _EXPORTS_OUTPUT := "exports"
53
+ _INPUT_CONTEXT := "context"
54
+
55
+
56
+ _PREPARED_INPUTS_PREFIX := "prepared/"
57
+
58
+
59
+
60
+ self.defineOutputs([_RESULT_OUTPUT, _EXPORTS_OUTPUT])
61
+
62
+
63
+
64
+
65
+ isProduction := func() {
66
+ return self.rawInputs().isProduction.getValueAsJson() == true
67
+ }
68
+
69
+ _args := undefined
70
+
71
+
72
+
73
+
74
+ args := func() {
75
+ if is_undefined(_args) {
76
+ inputs := self.inputs()
77
+
78
+ _args = inputs.args
79
+ if is_undefined(_args) || smart.isReference(_args) {
80
+ ll.panic("Unexpected args type: %v", _args)
81
+ }
82
+
83
+ for k, v in inputs {
84
+ if text.has_prefix(k, _PREPARED_INPUTS_PREFIX) {
85
+ name := text.trim_prefix(k, _PREPARED_INPUTS_PREFIX)
86
+ ll.assert(is_undefined(_args[name]), "prepare name is already in use in inputs: %s", name)
87
+ _args[name] = v
88
+ }
89
+ }
90
+ }
91
+ return _args
92
+ }
93
+
94
+ _blockId := undefined
95
+
96
+
97
+
98
+
99
+ blockId := func() {
100
+ if is_undefined(_blockId) {
101
+ _blockId = self.inputs().blockId
102
+ ll.assert(!is_undefined(_blockId), "block id is not set in workflow inputs")
103
+ }
104
+ return _blockId
105
+ }
106
+
107
+
108
+
109
+
110
+ getBlockId := func() {
111
+ ret := blockId().getDataAsJson()
112
+ ll.assert(is_string(ret), "block id is not a string")
113
+ return ret
114
+ }
115
+
116
+ _parentContext := undefined
117
+
118
+
119
+
120
+
121
+
122
+ getParentBCtx := func() {
123
+ if is_undefined(_parentContext) {
124
+ _parentContext = self.inputs()[_INPUT_CONTEXT]
125
+ if is_undefined(_parentContext) {
126
+ ll.panic("parent context is not set in inputs")
127
+ }
128
+ }
129
+ return _parentContext
130
+ }
131
+
132
+
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+ query := func(spec, ...options) {
142
+ return bquery.create(spec, getParentBCtx(), options...)
143
+ }
144
+
145
+ _resolveOne := func(r, ...options) {
146
+ res := bquery.resolve(r, getParentBCtx(), options...)
147
+ return ll.toStrict(oop.inherit(res, {
148
+ spec: res.getFutureInputField("spec"),
149
+ data: res.getFutureInputField("data")
150
+ }))
151
+ }
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+ resolve := func(ref, ...options) {
161
+ return _resolveOne(ref, options...)
162
+ }
163
+
164
+
165
+
166
+
167
+
168
+ anchoredQuery := func(anchors, queryMap, ...opts) {
169
+ return bquery.anchoredQuery(getParentBCtx(), anchors, queryMap, opts...)
170
+ }
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+ prepare := func(cb) {
179
+ self.prepare(func(_) {
180
+ raw := cb(args())
181
+ prefixed := {}
182
+ for k, v in raw {
183
+ prefixed[_PREPARED_INPUTS_PREFIX + k] = v
184
+ }
185
+ return prefixed
186
+ })
187
+ }
188
+
189
+
190
+
191
+
192
+ validateArgs := func(argsSchema) {
193
+ self.validateInputs({
194
+ args: argsSchema
195
+ })
196
+ }
197
+
198
+
199
+
200
+
201
+
202
+ createPBundleBuilder := func() {
203
+ return pBundle.createBuilderWith(bquery, getParentBCtx())
204
+ }
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+ tableBuilder := func(format) {
216
+ return pTableBuilder.tableBuilderWith(bquery, format, getParentBCtx())
217
+ }
218
+
219
+
220
+
221
+
222
+ _assertOwnOutputs := func() {
223
+ defined := sets.fromSlice(self.definedOutputs())
224
+ if defined != sets.fromSlice([_RESULT_OUTPUT, _EXPORTS_OUTPUT]) {
225
+ ll.panic("a v2 workflow's outputs are exactly result and exports, but this template defines %v; " +
226
+ "is something it imports using @platforma-sdk/workflow-tengo:workflow?", sets.toSlice(defined))
227
+ }
228
+ }
229
+
230
+ _buildOutputs := func(results) {
231
+ ll.assert(ll.isMap(results) && !smart.isReference(results), "expected to see map result from body function")
232
+ ll.assert(
233
+ sets.fromSlice(["outputs", "exports"]) == sets.fromMapKeys(results),
234
+ "expected only outputs and exports in the returned map, found %v", sets.toSlice(sets.fromMapKeys(results))
235
+ )
236
+ ll.assert(ll.isMap(results.outputs) && !smart.isReference(results.outputs),
237
+ "expected a map in outputs returned from workflow.body")
238
+
239
+ exports.assertNode(results.exports, "exports")
240
+
241
+ resBuilder := smart.mapBuilder()
242
+ for name, value in results.outputs {
243
+ ll.assert(!is_undefined(value), "value is undefined for output %s", name)
244
+ resBuilder.add(name, value)
245
+ }
246
+
247
+ tplOutputs := {}
248
+ tplOutputs[_RESULT_OUTPUT] = resBuilder.build()
249
+ tplOutputs[_EXPORTS_OUTPUT] = results.exports
250
+ return tplOutputs
251
+ }
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+ body := func(fn) {
260
+ _assertOwnOutputs()
261
+ self.body(func(_) {
262
+ return _buildOutputs(fn(args()))
263
+ })
264
+ }
265
+
266
+ export ll.toStrict({
267
+ getParentBCtx: getParentBCtx,
268
+ query: query,
269
+ resolve: resolve,
270
+ anchoredQuery: anchoredQuery,
271
+ prepare: prepare,
272
+ args: args,
273
+ rawInputs: self.rawInputs,
274
+ body: body,
275
+ isProduction: isProduction,
276
+ blockId: blockId,
277
+ getBlockId: getBlockId,
278
+ validateArgs: validateArgs,
279
+ createPBundleBuilder: createPBundleBuilder,
280
+ tableBuilder: tableBuilder
281
+ })
@@ -19,6 +19,7 @@ path := import("@platforma-sdk/workflow-tengo:path")
19
19
  workdirDirs := import("@platforma-sdk/workflow-tengo:workdir.dirs")
20
20
  render := import("@platforma-sdk/workflow-tengo:render")
21
21
  maps := import("@platforma-sdk/workflow-tengo:maps")
22
+ actionContext := import("@platforma-sdk/workflow-tengo:action-context")
22
23
 
23
24
  _WD_CREATE_FIELD_ALLOCATION := "allocation"
24
25
  _WD_CREATE_FIELD_WORKDIR := "workdir"
@@ -411,6 +412,9 @@ _fill := func() {
411
412
  self.getField("dataIn").set(smart.createBinaryMapResource(values))
412
413
  self.getField("blobsIn").set(smart.createBlobMapResource(blobs))
413
414
 
415
+
416
+ actionContext.inherit(wd.id)
417
+
414
418
  return self.lockAndBuild().outputs()[_WD_FILL_FIELD_WORKDIR_OUT]
415
419
  }
416
420
  }))
@@ -6,6 +6,7 @@ json := import("json")
6
6
  sets := import("@platforma-sdk/workflow-tengo:sets")
7
7
  smart := import("@platforma-sdk/workflow-tengo:smart")
8
8
  constants := import("@platforma-sdk/workflow-tengo:constants")
9
+ actionContext := import("@platforma-sdk/workflow-tengo:action-context")
9
10
 
10
11
  _WORKDIR_IN_FIELD := "workdirIn"
11
12
  _RULES_FIELD := "rules"
@@ -143,6 +144,8 @@ builder := func(wdBefore) {
143
144
  )
144
145
  )
145
146
 
147
+
148
+ actionContext.inherit(super.id)
146
149
  resource := super.lockAndBuild()
147
150
 
148
151