@useorgx/openclaw-plugin 0.4.9 → 0.7.2

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 (224) hide show
  1. package/README.md +77 -11
  2. package/dashboard/dist/assets/6mILZQ2a.js +1 -0
  3. package/dashboard/dist/assets/6mILZQ2a.js.br +0 -0
  4. package/dashboard/dist/assets/6mILZQ2a.js.gz +0 -0
  5. package/dashboard/dist/assets/8dksYiq4.js +2 -0
  6. package/dashboard/dist/assets/8dksYiq4.js.br +0 -0
  7. package/dashboard/dist/assets/8dksYiq4.js.gz +0 -0
  8. package/dashboard/dist/assets/B5zYRHc3.js +1 -0
  9. package/dashboard/dist/assets/B5zYRHc3.js.br +0 -0
  10. package/dashboard/dist/assets/B5zYRHc3.js.gz +0 -0
  11. package/dashboard/dist/assets/B6wPWJ35.js +1 -0
  12. package/dashboard/dist/assets/B6wPWJ35.js.br +0 -0
  13. package/dashboard/dist/assets/B6wPWJ35.js.gz +0 -0
  14. package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
  15. package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
  16. package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
  17. package/dashboard/dist/assets/BWEwjt1W.js +1 -0
  18. package/dashboard/dist/assets/BWEwjt1W.js.br +0 -0
  19. package/dashboard/dist/assets/BWEwjt1W.js.gz +0 -0
  20. package/dashboard/dist/assets/BgOYB78t.js +4 -0
  21. package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
  22. package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
  23. package/dashboard/dist/assets/BzRbDCAD.css +1 -0
  24. package/dashboard/dist/assets/BzRbDCAD.css.br +0 -0
  25. package/dashboard/dist/assets/BzRbDCAD.css.gz +0 -0
  26. package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
  27. package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
  28. package/dashboard/dist/assets/C8uM3AX8.js +1 -0
  29. package/dashboard/dist/assets/C8uM3AX8.js.br +0 -0
  30. package/dashboard/dist/assets/C8uM3AX8.js.gz +0 -0
  31. package/dashboard/dist/assets/C9jy61eu.js +212 -0
  32. package/dashboard/dist/assets/C9jy61eu.js.br +0 -0
  33. package/dashboard/dist/assets/C9jy61eu.js.gz +0 -0
  34. package/dashboard/dist/assets/CC63EwFD.js +1 -0
  35. package/dashboard/dist/assets/CC63EwFD.js.br +0 -0
  36. package/dashboard/dist/assets/CC63EwFD.js.gz +0 -0
  37. package/dashboard/dist/assets/CL_wXqR7.js +1 -0
  38. package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
  39. package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
  40. package/dashboard/dist/assets/CZaT3ob_.js +1 -0
  41. package/dashboard/dist/assets/CZaT3ob_.js.br +0 -0
  42. package/dashboard/dist/assets/CZaT3ob_.js.gz +0 -0
  43. package/dashboard/dist/assets/CgaottFX.js +1 -0
  44. package/dashboard/dist/assets/CgaottFX.js.br +0 -0
  45. package/dashboard/dist/assets/CgaottFX.js.gz +0 -0
  46. package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
  47. package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
  48. package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
  49. package/dashboard/dist/assets/CzCxAZlW.js +1 -0
  50. package/dashboard/dist/assets/CzCxAZlW.js.br +0 -0
  51. package/dashboard/dist/assets/CzCxAZlW.js.gz +0 -0
  52. package/dashboard/dist/assets/D3iMTYEj.js +1 -0
  53. package/dashboard/dist/assets/D3iMTYEj.js.br +0 -0
  54. package/dashboard/dist/assets/D3iMTYEj.js.gz +0 -0
  55. package/dashboard/dist/assets/D8JNX8kq.js +2 -0
  56. package/dashboard/dist/assets/D8JNX8kq.js.br +0 -0
  57. package/dashboard/dist/assets/D8JNX8kq.js.gz +0 -0
  58. package/dashboard/dist/assets/DnA8dpj6.js +1 -0
  59. package/dashboard/dist/assets/DnA8dpj6.js.br +0 -0
  60. package/dashboard/dist/assets/DnA8dpj6.js.gz +0 -0
  61. package/dashboard/dist/assets/IUexzymk.js +1 -0
  62. package/dashboard/dist/assets/IUexzymk.js.br +0 -0
  63. package/dashboard/dist/assets/IUexzymk.js.gz +0 -0
  64. package/dashboard/dist/assets/cNrhgGc1.js +8 -0
  65. package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
  66. package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
  67. package/dashboard/dist/assets/ic2FaMnh.js +1 -0
  68. package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
  69. package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
  70. package/dashboard/dist/assets/qm8xLgv-.css +1 -0
  71. package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
  72. package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
  73. package/dashboard/dist/assets/rttbDbEx.js +1 -0
  74. package/dashboard/dist/assets/rttbDbEx.js.br +0 -0
  75. package/dashboard/dist/assets/rttbDbEx.js.gz +0 -0
  76. package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
  77. package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
  78. package/dashboard/dist/brand/openai-mark.svg.br +0 -0
  79. package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
  80. package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
  81. package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
  82. package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
  83. package/dashboard/dist/index.html +7 -5
  84. package/dashboard/dist/index.html.br +0 -0
  85. package/dashboard/dist/index.html.gz +0 -0
  86. package/dist/activity-actor-fields.js +26 -4
  87. package/dist/activity-store.js +34 -8
  88. package/dist/agent-context-store.js +79 -17
  89. package/dist/agent-run-store.js +44 -3
  90. package/dist/agent-suite.d.ts +9 -0
  91. package/dist/agent-suite.js +149 -9
  92. package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
  93. package/dist/artifacts/artifact-domain-schemas.js +357 -0
  94. package/dist/artifacts/register-artifact.d.ts +4 -3
  95. package/dist/artifacts/register-artifact.js +170 -57
  96. package/dist/chat-store.d.ts +157 -0
  97. package/dist/chat-store.js +586 -0
  98. package/dist/cli/orgx.js +11 -0
  99. package/dist/contracts/client.d.ts +43 -3
  100. package/dist/contracts/client.js +159 -30
  101. package/dist/contracts/practice-exercise-schema.d.ts +216 -0
  102. package/dist/contracts/practice-exercise-schema.js +314 -0
  103. package/dist/contracts/retro-schema.d.ts +81 -0
  104. package/dist/contracts/retro-schema.js +80 -0
  105. package/dist/contracts/shared-types.d.ts +159 -0
  106. package/dist/contracts/shared-types.js +199 -1
  107. package/dist/contracts/skill-pack-schema.d.ts +192 -0
  108. package/dist/contracts/skill-pack-schema.js +180 -0
  109. package/dist/contracts/types.d.ts +247 -2
  110. package/dist/entities/auto-assignment.js +43 -17
  111. package/dist/event-sanitization.d.ts +11 -0
  112. package/dist/event-sanitization.js +113 -0
  113. package/dist/gateway-watchdog.d.ts +5 -0
  114. package/dist/gateway-watchdog.js +50 -0
  115. package/dist/hooks/post-reporting-event.mjs +1 -5
  116. package/dist/http/helpers/activity-headline.js +13 -132
  117. package/dist/http/helpers/auto-continue-engine.d.ts +198 -10
  118. package/dist/http/helpers/auto-continue-engine.js +3145 -186
  119. package/dist/http/helpers/autopilot-operations.d.ts +19 -0
  120. package/dist/http/helpers/autopilot-operations.js +182 -31
  121. package/dist/http/helpers/autopilot-runtime.d.ts +1 -0
  122. package/dist/http/helpers/autopilot-runtime.js +328 -25
  123. package/dist/http/helpers/autopilot-slice-utils.d.ts +18 -0
  124. package/dist/http/helpers/autopilot-slice-utils.js +514 -93
  125. package/dist/http/helpers/decision-mapper.d.ts +40 -0
  126. package/dist/http/helpers/decision-mapper.js +223 -7
  127. package/dist/http/helpers/dispatch-lifecycle.d.ts +19 -2
  128. package/dist/http/helpers/dispatch-lifecycle.js +242 -37
  129. package/dist/http/helpers/kickoff-context.js +104 -0
  130. package/dist/http/helpers/llm-client.d.ts +47 -0
  131. package/dist/http/helpers/llm-client.js +256 -0
  132. package/dist/http/helpers/mission-control.d.ts +102 -3
  133. package/dist/http/helpers/mission-control.js +498 -9
  134. package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
  135. package/dist/http/helpers/sentinel-catalog.js +193 -0
  136. package/dist/http/helpers/session-classification.d.ts +9 -0
  137. package/dist/http/helpers/session-classification.js +564 -0
  138. package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
  139. package/dist/http/helpers/slice-experience-v2.js +677 -0
  140. package/dist/http/helpers/slice-run-projections.d.ts +72 -0
  141. package/dist/http/helpers/slice-run-projections.js +877 -0
  142. package/dist/http/helpers/triage-mapper.d.ts +43 -0
  143. package/dist/http/helpers/triage-mapper.js +549 -0
  144. package/dist/http/helpers/value-utils.js +7 -2
  145. package/dist/http/helpers/workspace-scope.d.ts +15 -0
  146. package/dist/http/helpers/workspace-scope.js +170 -0
  147. package/dist/http/index.js +1420 -105
  148. package/dist/http/routes/agent-suite.d.ts +9 -0
  149. package/dist/http/routes/agent-suite.js +294 -8
  150. package/dist/http/routes/agents-catalog.js +64 -19
  151. package/dist/http/routes/chat.d.ts +19 -0
  152. package/dist/http/routes/chat.js +522 -0
  153. package/dist/http/routes/decision-actions.d.ts +8 -1
  154. package/dist/http/routes/decision-actions.js +42 -5
  155. package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
  156. package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
  157. package/dist/http/routes/entities.d.ts +16 -0
  158. package/dist/http/routes/entities.js +232 -6
  159. package/dist/http/routes/live-legacy.d.ts +5 -0
  160. package/dist/http/routes/live-legacy.js +23 -509
  161. package/dist/http/routes/live-misc.d.ts +12 -0
  162. package/dist/http/routes/live-misc.js +251 -31
  163. package/dist/http/routes/live-snapshot.d.ts +49 -2
  164. package/dist/http/routes/live-snapshot.js +653 -23
  165. package/dist/http/routes/live-terminal.d.ts +11 -0
  166. package/dist/http/routes/live-terminal.js +154 -0
  167. package/dist/http/routes/live-triage.d.ts +61 -0
  168. package/dist/http/routes/live-triage.js +192 -0
  169. package/dist/http/routes/mission-control-actions.d.ts +49 -1
  170. package/dist/http/routes/mission-control-actions.js +1246 -84
  171. package/dist/http/routes/mission-control-read.d.ts +48 -3
  172. package/dist/http/routes/mission-control-read.js +1658 -20
  173. package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
  174. package/dist/http/routes/realtime-orchestrator.js +74 -0
  175. package/dist/http/routes/run-control.d.ts +5 -2
  176. package/dist/http/routes/run-control.js +10 -0
  177. package/dist/http/routes/sentinels-catalog.d.ts +7 -0
  178. package/dist/http/routes/sentinels-catalog.js +24 -0
  179. package/dist/http/routes/summary.js +10 -3
  180. package/dist/http/routes/usage.d.ts +24 -0
  181. package/dist/http/routes/usage.js +362 -0
  182. package/dist/http/routes/work-artifacts.js +28 -9
  183. package/dist/index.js +165 -27
  184. package/dist/local-openclaw.js +29 -6
  185. package/dist/mcp-client-setup.js +3 -3
  186. package/dist/mcp-http-handler.d.ts +3 -0
  187. package/dist/mcp-http-handler.js +34 -60
  188. package/dist/next-up-queue-store.d.ts +16 -1
  189. package/dist/next-up-queue-store.js +89 -7
  190. package/dist/outbox.d.ts +5 -0
  191. package/dist/outbox.js +113 -9
  192. package/dist/paths.js +36 -5
  193. package/dist/reporting/rollups.d.ts +41 -0
  194. package/dist/reporting/rollups.js +113 -0
  195. package/dist/retro/domain-templates.d.ts +45 -0
  196. package/dist/retro/domain-templates.js +297 -0
  197. package/dist/retro/quality-rubric.d.ts +33 -0
  198. package/dist/retro/quality-rubric.js +213 -0
  199. package/dist/runtime-cleanup.d.ts +18 -0
  200. package/dist/runtime-cleanup.js +87 -0
  201. package/dist/services/background.d.ts +11 -0
  202. package/dist/services/background.js +22 -0
  203. package/dist/services/experiment-randomization.d.ts +21 -0
  204. package/dist/services/experiment-randomization.js +63 -0
  205. package/dist/skill-pack-state.d.ts +36 -5
  206. package/dist/skill-pack-state.js +273 -29
  207. package/dist/sync/local-agent-telemetry.d.ts +13 -0
  208. package/dist/sync/local-agent-telemetry.js +128 -0
  209. package/dist/sync/outbox-replay.js +131 -24
  210. package/dist/team-context-store.d.ts +23 -0
  211. package/dist/team-context-store.js +116 -0
  212. package/dist/telemetry/posthog.js +4 -2
  213. package/dist/tools/core-tools.d.ts +10 -14
  214. package/dist/tools/core-tools.js +1289 -24
  215. package/dist/types.d.ts +2 -0
  216. package/dist/types.js +2 -0
  217. package/dist/worker-supervisor.js +23 -0
  218. package/package.json +20 -6
  219. package/dashboard/dist/assets/B3ziCA02.js +0 -8
  220. package/dashboard/dist/assets/B5NEElEI.css +0 -1
  221. package/dashboard/dist/assets/BhapSNAs.js +0 -215
  222. package/dashboard/dist/assets/iFdvE7lx.js +0 -1
  223. package/dashboard/dist/assets/jRJsmpYM.js +0 -1
  224. package/dashboard/dist/assets/sAhvFnpk.js +0 -4
@@ -1,8 +1,65 @@
1
1
  import { appendToOutbox } from "../../outbox.js";
2
2
  import { computeMilestoneRollup, computeWorkstreamRollup, } from "../../reporting/rollups.js";
3
3
  import { readSkillPackState } from "../../skill-pack-state.js";
4
+ import { normalizeDecisionActionType } from "../../contracts/shared-types.js";
4
5
  import { buildMissionControlGraph, deriveExecutionPolicy, inferExecutionDomainFromText, normalizeExecutionDomain, ORGX_SKILL_BY_DOMAIN, spawnGuardIsRateLimited, summarizeSpawnGuardBlockReason, } from "./mission-control.js";
5
6
  export function createDispatchLifecycle(deps) {
7
+ const decisionV2Enabled = String(process.env.DECISION_V2_ENABLED ?? "true").trim().toLowerCase() !== "false";
8
+ const decisionDedupeEnabled = String(process.env.DECISION_DEDUPE_ENABLED ?? "true").trim().toLowerCase() !== "false";
9
+ const decisionEvidenceRequiredForBlocking = String(process.env.DECISION_EVIDENCE_REQUIRED_FOR_BLOCKING ?? "false")
10
+ .trim()
11
+ .toLowerCase() === "true";
12
+ const asRecord = (value) => {
13
+ if (!value || typeof value !== "object" || Array.isArray(value))
14
+ return null;
15
+ return value;
16
+ };
17
+ const extractDecisionIdsFromChangesetResults = (value) => {
18
+ if (!Array.isArray(value))
19
+ return [];
20
+ const ids = [];
21
+ const seen = new Set();
22
+ const pushId = (candidate) => {
23
+ if (typeof candidate !== "string")
24
+ return;
25
+ const id = candidate.trim();
26
+ if (!id || seen.has(id))
27
+ return;
28
+ seen.add(id);
29
+ ids.push(id);
30
+ };
31
+ for (const entry of value) {
32
+ const record = asRecord(entry);
33
+ if (!record)
34
+ continue;
35
+ pushId(record.decision_id);
36
+ pushId(record.decisionId);
37
+ const directDecision = asRecord(record.decision);
38
+ if (directDecision) {
39
+ pushId(directDecision.id);
40
+ pushId(directDecision.decision_id);
41
+ pushId(directDecision.decisionId);
42
+ }
43
+ const entityType = (typeof record.entity_type === "string" ? record.entity_type : null) ??
44
+ (typeof record.entityType === "string" ? record.entityType : null);
45
+ if (entityType && entityType.trim().toLowerCase() === "decision") {
46
+ pushId(record.entity_id);
47
+ pushId(record.entityId);
48
+ pushId(record.id);
49
+ }
50
+ const created = asRecord(record.created);
51
+ if (created) {
52
+ const createdType = (typeof created.entity_type === "string" ? created.entity_type : null) ??
53
+ (typeof created.entityType === "string" ? created.entityType : null);
54
+ if (createdType && createdType.trim().toLowerCase() === "decision") {
55
+ pushId(created.entity_id);
56
+ pushId(created.entityId);
57
+ pushId(created.id);
58
+ }
59
+ }
60
+ }
61
+ return ids;
62
+ };
6
63
  function withProvenanceMetadata(metadata) {
7
64
  const input = metadata ?? {};
8
65
  const out = { ...input };
@@ -62,6 +119,14 @@ export function createDispatchLifecycle(deps) {
62
119
  const message = input.message.trim();
63
120
  if (!message)
64
121
  return;
122
+ const normalizedRunId = input.runId?.trim() || null;
123
+ const normalizedCorrelationId = normalizedRunId ? null : (input.correlationId?.trim() || `openclaw-${Date.now()}`);
124
+ const canonicalMetadata = {
125
+ initiative_id: initiativeId,
126
+ run_id: normalizedRunId,
127
+ slice_run_id: normalizedRunId,
128
+ correlation_id: normalizedCorrelationId,
129
+ };
65
130
  const metadataWithProvenance = withProvenanceMetadata(input.metadata);
66
131
  const activityBucket = deps.deriveStructuredActivityBucket({
67
132
  phase: input.phase,
@@ -70,15 +135,14 @@ export function createDispatchLifecycle(deps) {
70
135
  });
71
136
  const enrichedMetadata = {
72
137
  ...(metadataWithProvenance ?? {}),
138
+ ...canonicalMetadata,
73
139
  activity_bucket: activityBucket,
74
140
  };
75
141
  try {
76
142
  await deps.client.emitActivity({
77
143
  initiative_id: initiativeId,
78
- run_id: input.runId ?? undefined,
79
- correlation_id: input.runId
80
- ? undefined
81
- : (input.correlationId?.trim() || `openclaw-${Date.now()}`),
144
+ run_id: normalizedRunId ?? undefined,
145
+ correlation_id: normalizedCorrelationId ?? undefined,
82
146
  source_client: "openclaw",
83
147
  message,
84
148
  phase: input.phase,
@@ -92,7 +156,7 @@ export function createDispatchLifecycle(deps) {
92
156
  }
93
157
  catch (err) {
94
158
  const msg = deps.safeErrorMessage(err);
95
- const runId = input.runId?.trim() || "";
159
+ const runId = normalizedRunId ?? "";
96
160
  // If OrgX rejects an unknown run_id, retry by treating the local run_id as a
97
161
  // correlation key (non-UUID) so OrgX can create/attach a run deterministically.
98
162
  if (runId && /^404\b/.test(msg) && /\brun\b/i.test(msg) && /not found/i.test(msg)) {
@@ -124,9 +188,7 @@ export function createDispatchLifecycle(deps) {
124
188
  // Fall back to local outbox so activity is still visible in Mission Control/Activity.
125
189
  try {
126
190
  const timestamp = new Date().toISOString();
127
- const runId = input.runId?.trim() ||
128
- input.correlationId?.trim() ||
129
- null;
191
+ const runId = normalizedRunId || normalizedCorrelationId || null;
130
192
  const activityItem = {
131
193
  id: deps.randomUUID(),
132
194
  type: input.phase === "completed"
@@ -167,10 +229,8 @@ export function createDispatchLifecycle(deps) {
167
229
  timestamp,
168
230
  payload: {
169
231
  initiative_id: initiativeId,
170
- run_id: input.runId?.trim() || undefined,
171
- correlation_id: input.runId
172
- ? undefined
173
- : (input.correlationId?.trim() || `openclaw-${Date.now()}`),
232
+ run_id: normalizedRunId ?? undefined,
233
+ correlation_id: normalizedCorrelationId ?? undefined,
174
234
  source_client: "openclaw",
175
235
  message,
176
236
  phase: input.phase,
@@ -192,10 +252,124 @@ export function createDispatchLifecycle(deps) {
192
252
  async function requestDecisionSafe(input) {
193
253
  const initiativeId = input.initiativeId?.trim() ?? "";
194
254
  const title = input.title.trim();
195
- if (!initiativeId || !title)
196
- return;
255
+ if (!initiativeId || !title) {
256
+ return { queued: false, decisionIds: [] };
257
+ }
258
+ const normalizedOptions = [];
259
+ for (const entry of Array.isArray(input.options) ? input.options : []) {
260
+ if (typeof entry === "string") {
261
+ const label = entry.trim();
262
+ if (label.length > 0)
263
+ normalizedOptions.push(label);
264
+ continue;
265
+ }
266
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
267
+ continue;
268
+ const record = entry;
269
+ const label = typeof record.label === "string" ? record.label.trim() : "";
270
+ if (!label)
271
+ continue;
272
+ const optionPayload = {
273
+ label,
274
+ };
275
+ if (typeof record.id === "string" && record.id.trim()) {
276
+ optionPayload.id = record.id.trim();
277
+ }
278
+ if (typeof record.description === "string" && record.description.trim()) {
279
+ optionPayload.description = record.description.trim();
280
+ }
281
+ if (typeof record.implied_status === "string" && record.implied_status.trim()) {
282
+ const implied = record.implied_status.trim().toLowerCase();
283
+ if (implied === "approved" ||
284
+ implied === "declined" ||
285
+ implied === "cancelled" ||
286
+ implied === "rejected") {
287
+ optionPayload.implied_status = implied;
288
+ }
289
+ }
290
+ const normalizedActionType = normalizeDecisionActionType(record.action_type ?? record.type ?? record.verb ?? record.action);
291
+ if (normalizedActionType) {
292
+ optionPayload.action_type = normalizedActionType;
293
+ }
294
+ if (record.requires_note === true) {
295
+ optionPayload.requires_note = true;
296
+ }
297
+ normalizedOptions.push(optionPayload);
298
+ }
299
+ const normalizedEvidenceRefs = (Array.isArray(input.evidenceRefs) ? input.evidenceRefs : [])
300
+ .map((entry) => (entry && typeof entry === "object" && !Array.isArray(entry) ? entry : null))
301
+ .filter((entry) => Boolean(entry));
302
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
303
+ const asUuid = (value) => {
304
+ const normalized = value?.trim() ?? "";
305
+ return uuidPattern.test(normalized) ? normalized : undefined;
306
+ };
307
+ const asIsoDateTime = (value) => {
308
+ const normalized = value?.trim() ?? "";
309
+ if (!normalized)
310
+ return undefined;
311
+ const epoch = Date.parse(normalized);
312
+ if (!Number.isFinite(epoch))
313
+ return undefined;
314
+ return new Date(epoch).toISOString();
315
+ };
316
+ const sourceRef = input.sourceRef && typeof input.sourceRef === "object" && !Array.isArray(input.sourceRef)
317
+ ? input.sourceRef
318
+ : null;
319
+ const metadata = input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata)
320
+ ? input.metadata
321
+ : null;
322
+ const dedupeKey = input.dedupeKey?.trim() ||
323
+ `decision:${deps.stableHash([
324
+ initiativeId,
325
+ input.workstreamId?.trim() || "none",
326
+ input.conflictSource?.trim() || "general",
327
+ title.toLowerCase(),
328
+ ].join("|")).slice(0, 24)}`;
329
+ const blocking = input.blocking ?? true;
330
+ const fallbackEvidenceRefs = blocking && decisionEvidenceRequiredForBlocking && normalizedEvidenceRefs.length === 0
331
+ ? [
332
+ {
333
+ evidence_type: "decision_context",
334
+ title: "Decision context",
335
+ summary: input.summary?.trim() ||
336
+ "Blocking decision emitted without explicit evidence payload.",
337
+ payload: {
338
+ source_ref: sourceRef ?? null,
339
+ generated_by: "plugin_guardrail",
340
+ },
341
+ },
342
+ ]
343
+ : [];
344
+ const effectiveEvidenceRefs = [...normalizedEvidenceRefs, ...fallbackEvidenceRefs];
345
+ const operation = {
346
+ op: "decision.create",
347
+ title,
348
+ summary: input.summary ?? undefined,
349
+ urgency: input.urgency ?? "high",
350
+ options: normalizedOptions,
351
+ blocking,
352
+ ...(decisionV2Enabled
353
+ ? {
354
+ decision_type: input.decisionType?.trim() || undefined,
355
+ workstream_id: asUuid(input.workstreamId),
356
+ agent_id: asUuid(input.agentId),
357
+ due_at: asIsoDateTime(input.dueAt),
358
+ source_system: input.sourceSystem?.trim() || "openclaw",
359
+ conflict_source: input.conflictSource?.trim() || undefined,
360
+ dedupe_key: decisionDedupeEnabled ? dedupeKey : undefined,
361
+ recommended_action: input.recommendedAction?.trim() || undefined,
362
+ source_run_id: asUuid(input.sourceRunId),
363
+ source_session_id: input.sourceSessionId?.trim() || undefined,
364
+ source_stream_id: asUuid(input.sourceStreamId),
365
+ source_ref: sourceRef ?? undefined,
366
+ evidence_refs: effectiveEvidenceRefs.length > 0 ? effectiveEvidenceRefs : undefined,
367
+ metadata: metadata ?? undefined,
368
+ }
369
+ : {}),
370
+ };
197
371
  try {
198
- await deps.client.applyChangeset({
372
+ const response = await deps.client.applyChangeset({
199
373
  initiative_id: initiativeId,
200
374
  correlation_id: input.correlationId?.trim() || undefined,
201
375
  source_client: "openclaw",
@@ -203,34 +377,21 @@ export function createDispatchLifecycle(deps) {
203
377
  "openclaw",
204
378
  "decision",
205
379
  initiativeId,
380
+ dedupeKey,
206
381
  title,
207
382
  input.correlationId ?? null,
208
383
  ]),
209
- operations: [
210
- {
211
- op: "decision.create",
212
- title,
213
- summary: input.summary ?? undefined,
214
- urgency: input.urgency ?? "high",
215
- options: input.options ?? [],
216
- blocking: input.blocking ?? true,
217
- },
218
- ],
384
+ operations: [operation],
219
385
  });
386
+ return {
387
+ queued: true,
388
+ decisionIds: extractDecisionIdsFromChangesetResults(response?.results),
389
+ };
220
390
  }
221
391
  catch (err) {
222
392
  const timestamp = new Date().toISOString();
223
393
  const correlationId = input.correlationId?.trim() || undefined;
224
- const operations = [
225
- {
226
- op: "decision.create",
227
- title,
228
- summary: input.summary ?? undefined,
229
- urgency: input.urgency ?? "high",
230
- options: input.options ?? [],
231
- blocking: input.blocking ?? true,
232
- },
233
- ];
394
+ const operations = [operation];
234
395
  const activityItem = {
235
396
  id: deps.randomUUID(),
236
397
  type: "decision_requested",
@@ -252,7 +413,17 @@ export function createDispatchLifecycle(deps) {
252
413
  event: "decision_buffered",
253
414
  urgency: input.urgency ?? "high",
254
415
  blocking: input.blocking ?? true,
255
- options: input.options ?? [],
416
+ options: normalizedOptions,
417
+ dedupe_key: decisionDedupeEnabled ? dedupeKey : null,
418
+ decision_type: decisionV2Enabled
419
+ ? input.decisionType?.trim() || null
420
+ : null,
421
+ conflict_source: decisionV2Enabled
422
+ ? input.conflictSource?.trim() || null
423
+ : null,
424
+ source_system: decisionV2Enabled
425
+ ? input.sourceSystem?.trim() || "openclaw"
426
+ : "openclaw",
256
427
  error: deps.safeErrorMessage(err),
257
428
  },
258
429
  };
@@ -269,6 +440,7 @@ export function createDispatchLifecycle(deps) {
269
440
  "openclaw",
270
441
  "decision",
271
442
  initiativeId,
443
+ dedupeKey,
272
444
  title,
273
445
  input.correlationId ?? null,
274
446
  "outbox",
@@ -277,9 +449,10 @@ export function createDispatchLifecycle(deps) {
277
449
  },
278
450
  activityItem,
279
451
  });
452
+ return { queued: true, decisionIds: [] };
280
453
  }
281
454
  catch {
282
- // best effort
455
+ return { queued: false, decisionIds: [] };
283
456
  }
284
457
  }
285
458
  }
@@ -581,6 +754,38 @@ export function createDispatchLifecycle(deps) {
581
754
  "Pause and investigate quality gate",
582
755
  ],
583
756
  blocking: true,
757
+ decisionType: "spawn_guard_blocked",
758
+ workstreamId: workstreamId || null,
759
+ agentId: input.agentId ?? null,
760
+ sourceSystem: "openclaw",
761
+ conflictSource: "spawn_guard_blocked",
762
+ dedupeKey: [
763
+ "dispatch",
764
+ input.initiativeId ?? "none",
765
+ workstreamId || "none",
766
+ taskId || "none",
767
+ "spawn_guard_blocked",
768
+ ].join(":"),
769
+ recommendedAction: "Choose exception, reassignment, or pause before retrying dispatch.",
770
+ sourceRunId: input.runId ?? null,
771
+ sourceRef: {
772
+ run_id: input.runId ?? null,
773
+ correlation_id: input.correlationId,
774
+ task_id: taskId || null,
775
+ workstream_id: workstreamId || null,
776
+ domain: input.executionPolicy.domain,
777
+ },
778
+ evidenceRefs: [
779
+ {
780
+ evidence_type: "spawn_guard_result",
781
+ title: `Spawn guard blocked ${targetLabel}`,
782
+ summary: blockedReason,
783
+ payload: {
784
+ spawn_guard: spawnGuardResult,
785
+ required_skills: input.executionPolicy.requiredSkills,
786
+ },
787
+ },
788
+ ],
584
789
  });
585
790
  }
586
791
  return {
@@ -56,6 +56,61 @@ export function renderKickoffMessage(input) {
56
56
  const allow = normalizeKickoffLines(kickoff.tool_scope?.allow ?? null);
57
57
  const deny = normalizeKickoffLines(kickoff.tool_scope?.deny ?? null);
58
58
  const toolNotes = (kickoff.tool_scope?.notes ?? "").trim();
59
+ const personaVoice = (kickoff.persona?.voice ?? "").trim();
60
+ const collaborationStyle = (kickoff.persona?.collaboration_style ?? "").trim();
61
+ const personaDefaults = normalizeKickoffLines(kickoff.persona?.defaults ?? null);
62
+ const runtimeSettings = kickoff.runtime_settings && typeof kickoff.runtime_settings === "object"
63
+ ? kickoff.runtime_settings
64
+ : null;
65
+ const customRunInstructions = runtimeSettings && typeof runtimeSettings.custom_run_instructions === "string"
66
+ ? runtimeSettings.custom_run_instructions.trim()
67
+ : "";
68
+ const runtimeFlagLines = [
69
+ runtimeSettings && typeof runtimeSettings.decision_v2_enabled === "boolean"
70
+ ? `- Decision V2: ${runtimeSettings.decision_v2_enabled ? "enabled" : "disabled"}`
71
+ : null,
72
+ runtimeSettings && typeof runtimeSettings.decision_dedupe_enabled === "boolean"
73
+ ? `- Decision dedupe: ${runtimeSettings.decision_dedupe_enabled ? "enabled" : "disabled"}`
74
+ : null,
75
+ runtimeSettings &&
76
+ typeof runtimeSettings.decision_evidence_required_for_blocking === "boolean"
77
+ ? `- Blocking evidence required: ${runtimeSettings.decision_evidence_required_for_blocking ? "enabled" : "disabled"}`
78
+ : null,
79
+ runtimeSettings &&
80
+ typeof runtimeSettings.decision_auto_resolve_guarded_enabled === "boolean"
81
+ ? `- Guarded auto-resolve: ${runtimeSettings.decision_auto_resolve_guarded_enabled ? "enabled" : "disabled"}`
82
+ : null,
83
+ runtimeSettings &&
84
+ typeof runtimeSettings.question_auto_answer_enabled === "boolean"
85
+ ? `- Question auto-answer: ${runtimeSettings.question_auto_answer_enabled ? "enabled" : "disabled"}`
86
+ : null,
87
+ runtimeSettings &&
88
+ typeof runtimeSettings.question_auto_answer_timeout_sec === "number"
89
+ ? `- Question auto-answer timeout: ${Math.max(10, Math.min(3600, Math.floor(runtimeSettings.question_auto_answer_timeout_sec)))}s`
90
+ : runtimeSettings &&
91
+ typeof runtimeSettings.question_auto_answer_delay_seconds === "number"
92
+ ? `- Question auto-answer delay: ${Math.max(1, Math.min(900, Math.floor(runtimeSettings.question_auto_answer_delay_seconds)))}s`
93
+ : null,
94
+ runtimeSettings &&
95
+ typeof runtimeSettings.question_auto_answer_policy === "string"
96
+ ? `- Question auto-answer policy: ${runtimeSettings.question_auto_answer_policy}`
97
+ : null,
98
+ runtimeSettings &&
99
+ typeof runtimeSettings.question_blocking_behavior === "string"
100
+ ? `- Blocking question behavior: ${runtimeSettings.question_blocking_behavior}`
101
+ : null,
102
+ runtimeSettings &&
103
+ typeof runtimeSettings.question_auto_answer_action === "string"
104
+ ? `- Question auto-answer action: ${runtimeSettings.question_auto_answer_action.trim().toLowerCase() === "reject"
105
+ ? "reject"
106
+ : "approve"}`
107
+ : null,
108
+ runtimeSettings &&
109
+ runtimeSettings.workspace_question_defaults &&
110
+ typeof runtimeSettings.workspace_question_defaults === "object"
111
+ ? "- Workspace question defaults available"
112
+ : null,
113
+ ].filter((line) => Boolean(line));
59
114
  const contextHash = kickoff.context_hash?.trim() || null;
60
115
  const schemaVersion = (kickoff.schema_version ?? "").trim();
61
116
  const lines = [];
@@ -123,6 +178,26 @@ export function renderKickoffMessage(input) {
123
178
  lines.push("- Communicate early when blocked. Provide options, tradeoffs, and a recommendation.");
124
179
  lines.push("- Verify before claiming done. Prefer proof (commands/tests) over confidence.");
125
180
  lines.push("");
181
+ if (runtimeFlagLines.length > 0 || customRunInstructions) {
182
+ lines.push("## Runtime Settings");
183
+ for (const line of runtimeFlagLines)
184
+ lines.push(line);
185
+ if (customRunInstructions) {
186
+ lines.push("- Custom run instructions:");
187
+ lines.push(` ${customRunInstructions}`);
188
+ }
189
+ lines.push("");
190
+ }
191
+ if (personaVoice || collaborationStyle || personaDefaults.length > 0) {
192
+ lines.push("## Behavior");
193
+ if (personaVoice)
194
+ lines.push(`- Voice: ${personaVoice}`);
195
+ if (collaborationStyle)
196
+ lines.push(`- Collaboration style: ${collaborationStyle}`);
197
+ for (const item of personaDefaults)
198
+ lines.push(`- Default: ${item}`);
199
+ lines.push("");
200
+ }
126
201
  if (allow.length > 0 || deny.length > 0 || toolNotes) {
127
202
  lines.push("## Tool Scope");
128
203
  if (allow.length > 0)
@@ -139,6 +214,35 @@ export function renderKickoffMessage(input) {
139
214
  lines.push(`- ${item}`);
140
215
  lines.push("");
141
216
  }
217
+ const teamContext = kickoff.team_context;
218
+ if (teamContext) {
219
+ const completions = Array.isArray(teamContext.recent_completions)
220
+ ? teamContext.recent_completions.slice(0, 5)
221
+ : [];
222
+ const teamDecisions = Array.isArray(teamContext.recent_decisions)
223
+ ? teamContext.recent_decisions.slice(0, 3)
224
+ : [];
225
+ if (completions.length > 0 || teamDecisions.length > 0) {
226
+ lines.push("## Team Activity");
227
+ lines.push("Recent work by other agents (for awareness, not direct action):");
228
+ for (const c of completions) {
229
+ const outputs = Array.isArray(c.key_outputs) && c.key_outputs.length > 0
230
+ ? ` (${c.key_outputs.join(", ")})`
231
+ : "";
232
+ lines.push(`- [${c.domain}] ${c.task_title}: ${c.summary}${outputs}`);
233
+ }
234
+ if (teamDecisions.length > 0) {
235
+ lines.push("");
236
+ lines.push("Recent decisions:");
237
+ for (const d of teamDecisions) {
238
+ lines.push(`- ${d.title}: ${d.resolution}`);
239
+ }
240
+ }
241
+ lines.push("");
242
+ lines.push("Reference naturally when relevant. Do not summarize back.");
243
+ lines.push("");
244
+ }
245
+ }
142
246
  if (contextHash || schemaVersion) {
143
247
  lines.push("## Provenance");
144
248
  if (schemaVersion)
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Shared LLM client for classification, summarization, and generation tasks.
3
+ *
4
+ * Generalizes the pattern from activity-headline.ts into a reusable client
5
+ * with in-memory caching, timeout, and heuristic fallback.
6
+ */
7
+ export type LlmSource = "llm" | "heuristic";
8
+ export interface LlmRequest {
9
+ /** Namespace for cache keys (e.g. "retro", "turn_summary", "classify_status") */
10
+ taskId: string;
11
+ systemPrompt: string;
12
+ userPrompt: string;
13
+ /** Override default model. Use DEFAULT_GENERATION_MODEL for longer outputs. */
14
+ model?: string;
15
+ /** Default 0.1 */
16
+ temperature?: number;
17
+ /** Default 128 */
18
+ maxTokens?: number;
19
+ /** Default 4000ms */
20
+ timeoutMs?: number;
21
+ /** Default 12h. Set 0 to disable caching. */
22
+ cacheTtlMs?: number;
23
+ }
24
+ export interface LlmResponse<T> {
25
+ result: T;
26
+ source: LlmSource;
27
+ model: string | null;
28
+ }
29
+ export declare function resolveApiKey(): string | null;
30
+ /** Reset cached key (for testing or key rotation). */
31
+ export declare function resetApiKeyCache(): void;
32
+ /**
33
+ * Call LLM for a text completion with automatic caching and heuristic fallback.
34
+ *
35
+ * @param request - The LLM request configuration
36
+ * @param fallback - Heuristic fallback that produces a result when LLM is unavailable
37
+ * @param parse - Optional transform on the raw LLM text (default: identity)
38
+ */
39
+ export declare function callLlm(request: LlmRequest, fallback: () => string, parse?: (raw: string) => string | null): Promise<LlmResponse<string>>;
40
+ /**
41
+ * Call LLM expecting a JSON response. Parses and validates via the provided parser.
42
+ *
43
+ * @param request - The LLM request (systemPrompt should instruct JSON output)
44
+ * @param parse - Parse raw JSON string into typed result, return null on failure
45
+ * @param fallback - Heuristic fallback
46
+ */
47
+ export declare function callLlmJson<T>(request: LlmRequest, parse: (raw: string) => T | null, fallback: () => T): Promise<LlmResponse<T>>;