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.
Files changed (37) hide show
  1. package/docs/_version.json +7 -0
  2. package/docs/css/docuserve.css +277 -23
  3. package/docs/features/beacon-authentication.md +24 -31
  4. package/docs/features/beacon-providers.md +31 -37
  5. package/docs/features/beacons.md +20 -19
  6. package/docs/features/case-study-retold-remote.md +28 -28
  7. package/docs/features/llm-model-setup.md +15 -15
  8. package/docs/features/llm.md +29 -27
  9. package/docs/features/platform-cards.md +10 -10
  10. package/docs/features/reachability-matrix.md +12 -12
  11. package/docs/features/tasks-content-system.md +32 -32
  12. package/docs/features/tasks-data-transform.md +64 -64
  13. package/docs/features/tasks-extension.md +14 -14
  14. package/docs/features/tasks-file-system.md +94 -94
  15. package/docs/features/tasks-flow-control.md +38 -38
  16. package/docs/features/tasks-http-client.md +40 -40
  17. package/docs/features/tasks-llm.md +58 -58
  18. package/docs/features/tasks-meadow-api.md +50 -50
  19. package/docs/features/tasks-user-interaction.md +12 -12
  20. package/docs/features/tasks.md +20 -20
  21. package/docs/features/universal-addressing.md +12 -12
  22. package/docs/index.html +2 -2
  23. package/docs/retold-catalog.json +30 -1
  24. package/docs/retold-keyword-index.json +15389 -12741
  25. package/package.json +5 -4
  26. package/source/services/Ultravisor-Beacon-Coordinator.cjs +40 -1
  27. package/source/services/Ultravisor-ExecutionEngine.cjs +9 -3
  28. package/source/services/Ultravisor-OperationAuditor.cjs +471 -0
  29. package/source/services/tasks/data-transform/Ultravisor-TaskConfigs-DataTransform.cjs +72 -0
  30. package/source/services/tasks/data-transform/definitions/random-number.json +24 -0
  31. package/source/services/tasks/data-transform/definitions/random-string.json +23 -0
  32. package/source/services/tasks/extension/Ultravisor-TaskConfigs-Extension.cjs +19 -7
  33. package/source/services/tasks/user-interaction/Ultravisor-TaskConfigs-UserInteraction.cjs +30 -2
  34. package/source/services/tasks/user-interaction/Ultravisor-TaskType-ValueInput.cjs +56 -2
  35. package/source/web_server/Ultravisor-API-Server.cjs +70 -0
  36. package/test/Ultravisor-Beacon-Reachability_tests.js +520 -0
  37. 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
- let tmpSettings = {
51
- Command: pResolvedSettings.Command || '',
52
- Parameters: pResolvedSettings.Parameters || '',
53
- InputData: pResolvedSettings.InputData || ''
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: 'Complete',
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: 'ValueInputComplete',
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
- // No pre-seeded value pause and wait for interactive input
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
- // Signal that this task is waiting for input
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: pResolvedSettings.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