ultravisor 1.0.20 → 1.0.22
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/docs/_version.json +7 -0
- package/docs/css/docuserve.css +277 -23
- package/docs/features/beacon-authentication.md +24 -31
- package/docs/features/beacon-providers.md +31 -37
- package/docs/features/beacons.md +20 -19
- package/docs/features/case-study-retold-remote.md +28 -28
- package/docs/features/llm-model-setup.md +15 -15
- package/docs/features/llm.md +29 -27
- package/docs/features/platform-cards.md +10 -10
- package/docs/features/reachability-matrix.md +12 -12
- package/docs/features/tasks-content-system.md +32 -32
- package/docs/features/tasks-data-transform.md +64 -64
- package/docs/features/tasks-extension.md +14 -14
- package/docs/features/tasks-file-system.md +94 -94
- package/docs/features/tasks-flow-control.md +38 -38
- package/docs/features/tasks-http-client.md +40 -40
- package/docs/features/tasks-llm.md +58 -58
- package/docs/features/tasks-meadow-api.md +50 -50
- package/docs/features/tasks-user-interaction.md +12 -12
- package/docs/features/tasks.md +20 -20
- package/docs/features/universal-addressing.md +12 -12
- package/docs/index.html +2 -2
- package/docs/retold-catalog.json +30 -1
- package/docs/retold-keyword-index.json +15389 -12741
- package/package.json +5 -4
- package/source/services/Ultravisor-Beacon-Coordinator.cjs +40 -1
- package/source/services/Ultravisor-ExecutionEngine.cjs +9 -3
- package/source/services/Ultravisor-OperationAuditor.cjs +471 -0
- package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +72 -0
- package/source/services/tasks/data-transform/definitions/random-number.json +24 -0
- package/source/services/tasks/data-transform/definitions/random-string.json +23 -0
- package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +19 -7
- package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +30 -2
- package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +56 -2
- package/source/web_server/Ultravisor-API-Server.cjs +70 -0
- package/test/Ultravisor-Beacon-Reachability_tests.js +520 -0
- package/test/Ultravisor_tests.js +4 -4
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Hash": "random-string",
|
|
3
|
+
"Type": "random-string",
|
|
4
|
+
"Name": "Random String",
|
|
5
|
+
"Description": "Generates a random string. Useful for unique filenames, run IDs, and identifiers.",
|
|
6
|
+
"Category": "data",
|
|
7
|
+
"Capability": "Data Transform",
|
|
8
|
+
"Action": "GenerateRandomString",
|
|
9
|
+
"Tier": "Engine",
|
|
10
|
+
"EventInputs": [{ "Name": "Generate" }],
|
|
11
|
+
"EventOutputs": [
|
|
12
|
+
{ "Name": "Complete" },
|
|
13
|
+
{ "Name": "Error", "IsError": true }
|
|
14
|
+
],
|
|
15
|
+
"SettingsInputs": [
|
|
16
|
+
{ "Name": "Length", "DataType": "Number", "Required": false, "Description": "Length of the generated string. Default: 16" },
|
|
17
|
+
{ "Name": "Format", "DataType": "String", "Required": false, "Description": "Format: hex, alphanumeric, uuid. Default: hex" }
|
|
18
|
+
],
|
|
19
|
+
"StateOutputs": [
|
|
20
|
+
{ "Name": "Value", "DataType": "String", "Description": "The generated random string" }
|
|
21
|
+
],
|
|
22
|
+
"DefaultSettings": { "Length": 16, "Format": "hex" }
|
|
23
|
+
}
|
|
@@ -46,12 +46,24 @@ module.exports =
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
// Build work item settings from resolved settings
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
// Build work item settings from ALL resolved settings
|
|
50
|
+
// (includes node Data fields + state connection values)
|
|
51
|
+
let tmpSettings = {};
|
|
52
|
+
let tmpResolvedKeys = Object.keys(pResolvedSettings);
|
|
53
|
+
for (let rk = 0; rk < tmpResolvedKeys.length; rk++)
|
|
54
|
+
{
|
|
55
|
+
let tmpKey = tmpResolvedKeys[rk];
|
|
56
|
+
// Skip internal/meta fields that aren't work item settings
|
|
57
|
+
if (tmpKey === 'RemoteCapability' || tmpKey === 'RemoteAction'
|
|
58
|
+
|| tmpKey === 'AffinityKey' || tmpKey === 'TimeoutMs'
|
|
59
|
+
|| tmpKey === 'PromptMessage' || tmpKey === 'OutputAddress'
|
|
60
|
+
|| tmpKey === 'InputSchema') continue;
|
|
61
|
+
tmpSettings[tmpKey] = pResolvedSettings[tmpKey];
|
|
62
|
+
}
|
|
63
|
+
// Ensure legacy fields exist for backward compat
|
|
64
|
+
if (!tmpSettings.Command) tmpSettings.Command = '';
|
|
65
|
+
if (!tmpSettings.Parameters) tmpSettings.Parameters = '';
|
|
66
|
+
if (!tmpSettings.InputData) tmpSettings.InputData = '';
|
|
55
67
|
|
|
56
68
|
// Resolve universal addresses in InputData (JSON string).
|
|
57
69
|
// Addresses like >retold-remote/File/path become concrete
|
|
@@ -122,7 +134,7 @@ module.exports =
|
|
|
122
134
|
// Pause execution — the BeaconCoordinator will call resumeOperation when the Beacon reports back
|
|
123
135
|
return fCallback(null, {
|
|
124
136
|
WaitingForInput: true,
|
|
125
|
-
ResumeEventName: '
|
|
137
|
+
ResumeEventName: 'complete',
|
|
126
138
|
PromptMessage: `Waiting for Beacon worker (${tmpWorkItemInfo.Capability}/${tmpWorkItemInfo.Action})`,
|
|
127
139
|
OutputAddress: '',
|
|
128
140
|
Outputs: {},
|
|
@@ -106,14 +106,42 @@ module.exports =
|
|
|
106
106
|
if (tmpExistingValue !== undefined && tmpExistingValue !== null && tmpExistingValue !== '')
|
|
107
107
|
{
|
|
108
108
|
return fCallback(null, {
|
|
109
|
-
EventToFire: '
|
|
109
|
+
EventToFire: 'complete',
|
|
110
110
|
Outputs: { InputValue: tmpExistingValue },
|
|
111
111
|
Log: [`Auto-resolved from pre-seeded state: "${tmpOutputAddress}" = "${String(tmpExistingValue).substring(0, 100)}"`]
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
//
|
|
116
|
+
// If the operation was triggered programmatically (has pre-seeded params),
|
|
117
|
+
// use the DefaultValue so the whole chain runs without pausing
|
|
118
|
+
let tmpIsProgrammatic = pExecutionContext.OperationState
|
|
119
|
+
&& Object.keys(pExecutionContext.OperationState).length > 0;
|
|
120
|
+
let tmpDefaultValue = pResolvedSettings.DefaultValue
|
|
121
|
+
|| (pResolvedSettings.InputSchema && pResolvedSettings.InputSchema.Default !== undefined
|
|
122
|
+
? String(pResolvedSettings.InputSchema.Default) : undefined);
|
|
123
|
+
if (tmpIsProgrammatic && tmpDefaultValue !== undefined && tmpDefaultValue !== null && tmpDefaultValue !== '')
|
|
124
|
+
{
|
|
125
|
+
return fCallback(null, {
|
|
126
|
+
EventToFire: 'complete',
|
|
127
|
+
Outputs: { InputValue: tmpDefaultValue },
|
|
128
|
+
Log: [`Auto-resolved from default: "${tmpOutputAddress}" = "${String(tmpDefaultValue).substring(0, 100)}"`]
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// For optional fields with no default in programmatic mode, pass empty string
|
|
133
|
+
let tmpIsOptional = pResolvedSettings.InputSchema
|
|
134
|
+
&& pResolvedSettings.InputSchema.Required === false;
|
|
135
|
+
if (tmpIsProgrammatic && tmpIsOptional)
|
|
136
|
+
{
|
|
137
|
+
return fCallback(null, {
|
|
138
|
+
EventToFire: 'complete',
|
|
139
|
+
Outputs: { InputValue: '' },
|
|
140
|
+
Log: [`Auto-resolved optional field: "${tmpOutputAddress}" = "" (no value provided)`]
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// No pre-seeded value and no default — pause and wait for interactive input
|
|
117
145
|
let tmpOptions = pResolvedSettings.Options || '';
|
|
118
146
|
if (Array.isArray(tmpOptions))
|
|
119
147
|
{
|
|
@@ -29,15 +29,69 @@ class UltravisorTaskTypeValueInput extends libTaskTypeBase
|
|
|
29
29
|
let tmpPromptMessage = pResolvedSettings.PromptMessage || 'Please provide a value:';
|
|
30
30
|
let tmpOutputAddress = pResolvedSettings.OutputAddress || '';
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// Auto-resolve: if the output address already has a value in state
|
|
33
|
+
// (e.g., pre-seeded via /Operation/:Hash/Trigger with Parameters),
|
|
34
|
+
// skip the pause and fire immediately. This lets operations work both
|
|
35
|
+
// interactively (flow editor — pauses for input) and programmatically
|
|
36
|
+
// (API trigger / retold-labs operation runner — runs straight through).
|
|
37
|
+
if (tmpOutputAddress && pExecutionContext.StateManager)
|
|
38
|
+
{
|
|
39
|
+
let tmpExistingValue = pExecutionContext.StateManager.resolveAddress(
|
|
40
|
+
tmpOutputAddress, pExecutionContext, pExecutionContext.NodeHash);
|
|
41
|
+
if (tmpExistingValue !== undefined && tmpExistingValue !== null && tmpExistingValue !== '')
|
|
42
|
+
{
|
|
43
|
+
return fCallback(null, {
|
|
44
|
+
EventToFire: 'complete',
|
|
45
|
+
Outputs: { InputValue: tmpExistingValue },
|
|
46
|
+
Log: [`Auto-resolved from pre-seeded state: "${tmpOutputAddress}" = "${String(tmpExistingValue).substring(0, 100)}"`]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// If the operation was triggered programmatically (OperationState has pre-seeded values),
|
|
52
|
+
// auto-resolve using the DefaultValue so the whole chain runs without pausing.
|
|
53
|
+
// In interactive mode (empty OperationState), pause for user input.
|
|
54
|
+
let tmpIsProgrammatic = pExecutionContext.OperationState
|
|
55
|
+
&& Object.keys(pExecutionContext.OperationState).length > 0;
|
|
56
|
+
let tmpDefaultValue = pResolvedSettings.DefaultValue
|
|
57
|
+
|| (pResolvedSettings.InputSchema && pResolvedSettings.InputSchema.Default !== undefined
|
|
58
|
+
? String(pResolvedSettings.InputSchema.Default) : undefined);
|
|
59
|
+
if (tmpIsProgrammatic && tmpDefaultValue !== undefined && tmpDefaultValue !== null && tmpDefaultValue !== '')
|
|
60
|
+
{
|
|
61
|
+
return fCallback(null, {
|
|
62
|
+
EventToFire: 'complete',
|
|
63
|
+
Outputs: { InputValue: tmpDefaultValue },
|
|
64
|
+
Log: [`Auto-resolved from default: "${tmpOutputAddress}" = "${String(tmpDefaultValue).substring(0, 100)}"`]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// For optional fields with no default in programmatic mode, pass empty string
|
|
69
|
+
let tmpIsOptional = pResolvedSettings.InputSchema
|
|
70
|
+
&& pResolvedSettings.InputSchema.Required === false;
|
|
71
|
+
if (tmpIsProgrammatic && tmpIsOptional)
|
|
72
|
+
{
|
|
73
|
+
return fCallback(null, {
|
|
74
|
+
EventToFire: 'complete',
|
|
75
|
+
Outputs: { InputValue: '' },
|
|
76
|
+
Log: [`Auto-resolved optional field: "${tmpOutputAddress}" = "" (no value provided)`]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// No pre-seeded value and no default — pause and wait for interactive input
|
|
33
81
|
// The ExecutionEngine will set the run to WaitingForInput status
|
|
82
|
+
let tmpOptions = pResolvedSettings.Options || '';
|
|
83
|
+
if (Array.isArray(tmpOptions))
|
|
84
|
+
{
|
|
85
|
+
tmpOptions = JSON.stringify(tmpOptions);
|
|
86
|
+
}
|
|
87
|
+
|
|
34
88
|
return fCallback(null, {
|
|
35
89
|
WaitingForInput: true,
|
|
36
90
|
PromptMessage: tmpPromptMessage,
|
|
37
91
|
OutputAddress: tmpOutputAddress,
|
|
38
92
|
InputType: pResolvedSettings.InputType || 'text',
|
|
39
93
|
DefaultValue: pResolvedSettings.DefaultValue || '',
|
|
40
|
-
Options:
|
|
94
|
+
Options: tmpOptions,
|
|
41
95
|
Outputs: {},
|
|
42
96
|
Log: [`Waiting for input: "${tmpPromptMessage}" (-> ${tmpOutputAddress})`]
|
|
43
97
|
});
|
|
@@ -253,6 +253,60 @@ class UltravisorAPIServer extends libPictService
|
|
|
253
253
|
}.bind(this)
|
|
254
254
|
);
|
|
255
255
|
|
|
256
|
+
// --- Operation Audit ---
|
|
257
|
+
// Static port-mapping audit across all registered operations.
|
|
258
|
+
// Cross-references beacon-dispatch nodes' state connections and
|
|
259
|
+
// Data keys against the beacon action catalog's SettingsSchema.
|
|
260
|
+
this._OratorServer.get
|
|
261
|
+
(
|
|
262
|
+
'/OperationAudit',
|
|
263
|
+
function (pRequest, pResponse, fNext)
|
|
264
|
+
{
|
|
265
|
+
let tmpAuditor = this._getService('UltravisorOperationAuditor');
|
|
266
|
+
if (!tmpAuditor)
|
|
267
|
+
{
|
|
268
|
+
pResponse.send(503, { Error: 'UltravisorOperationAuditor service not available.' });
|
|
269
|
+
return fNext();
|
|
270
|
+
}
|
|
271
|
+
tmpAuditor.auditAll(
|
|
272
|
+
function (pError, pReport)
|
|
273
|
+
{
|
|
274
|
+
if (pError)
|
|
275
|
+
{
|
|
276
|
+
pResponse.send(500, { Error: pError.message });
|
|
277
|
+
return fNext();
|
|
278
|
+
}
|
|
279
|
+
pResponse.send(pReport);
|
|
280
|
+
return fNext();
|
|
281
|
+
});
|
|
282
|
+
}.bind(this)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
this._OratorServer.get
|
|
286
|
+
(
|
|
287
|
+
'/OperationAudit/:Hash',
|
|
288
|
+
function (pRequest, pResponse, fNext)
|
|
289
|
+
{
|
|
290
|
+
let tmpAuditor = this._getService('UltravisorOperationAuditor');
|
|
291
|
+
if (!tmpAuditor)
|
|
292
|
+
{
|
|
293
|
+
pResponse.send(503, { Error: 'UltravisorOperationAuditor service not available.' });
|
|
294
|
+
return fNext();
|
|
295
|
+
}
|
|
296
|
+
tmpAuditor.auditByHash(pRequest.params.Hash,
|
|
297
|
+
function (pError, pResult)
|
|
298
|
+
{
|
|
299
|
+
if (pError)
|
|
300
|
+
{
|
|
301
|
+
pResponse.send(404, { Error: pError.message });
|
|
302
|
+
return fNext();
|
|
303
|
+
}
|
|
304
|
+
pResponse.send(pResult);
|
|
305
|
+
return fNext();
|
|
306
|
+
});
|
|
307
|
+
}.bind(this)
|
|
308
|
+
);
|
|
309
|
+
|
|
256
310
|
this._OratorServer.post
|
|
257
311
|
(
|
|
258
312
|
'/Operation',
|
|
@@ -2055,6 +2109,16 @@ class UltravisorAPIServer extends libPictService
|
|
|
2055
2109
|
return;
|
|
2056
2110
|
}
|
|
2057
2111
|
|
|
2112
|
+
// Diagnostic: log what we RECEIVED from the client before forwarding
|
|
2113
|
+
// to registerBeacon. If the client sent HostID but we're storing null,
|
|
2114
|
+
// this log line pins down exactly where the drop happens (client vs
|
|
2115
|
+
// server). Gated on LogNoisiness>=2 to stay quiet in production.
|
|
2116
|
+
let tmpNoisy = (this.fable && this.fable.LogNoisiness) || 0;
|
|
2117
|
+
if (tmpNoisy >= 2)
|
|
2118
|
+
{
|
|
2119
|
+
this.log.info(`[WSRegister] received from client: Name=${pData.Name} HostID=${pData.HostID || '(none)'} SharedMounts=${JSON.stringify(pData.SharedMounts || [])} Ops=${(pData.Operations || []).length}`);
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2058
2122
|
// IMPORTANT: this enumeration must include every field the coordinator
|
|
2059
2123
|
// cares about, including HostID and SharedMounts (used by the shared-fs
|
|
2060
2124
|
// reachability auto-detect). Forgetting to forward a field here means
|
|
@@ -2073,6 +2137,12 @@ class UltravisorAPIServer extends libPictService
|
|
|
2073
2137
|
SharedMounts: pData.SharedMounts
|
|
2074
2138
|
});
|
|
2075
2139
|
|
|
2140
|
+
// Diagnostic: confirm what was actually STORED on the beacon record.
|
|
2141
|
+
if (tmpNoisy >= 2)
|
|
2142
|
+
{
|
|
2143
|
+
this.log.info(`[WSRegister] stored beacon ${tmpBeacon.BeaconID}: HostID=${tmpBeacon.HostID || '(null)'} SharedMounts=${JSON.stringify(tmpBeacon.SharedMounts || [])}`);
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2076
2146
|
pWebSocket._BeaconID = tmpBeacon.BeaconID;
|
|
2077
2147
|
this._BeaconWebSockets[tmpBeacon.BeaconID] = pWebSocket;
|
|
2078
2148
|
|