@useorgx/openclaw-plugin 0.4.8 → 0.7.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/README.md +35 -0
- package/dashboard/dist/assets/BJgZIVUQ.js +53 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.br +0 -0
- package/dashboard/dist/assets/BJgZIVUQ.js.gz +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js +1 -0
- package/dashboard/dist/assets/BXWDRGm-.js.br +0 -0
- package/dashboard/dist/assets/BXWDRGm-.js.gz +0 -0
- package/dashboard/dist/assets/BgOYB78t.js +4 -0
- package/dashboard/dist/assets/BgOYB78t.js.br +0 -0
- package/dashboard/dist/assets/BgOYB78t.js.gz +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.br +0 -0
- package/dashboard/dist/assets/C-KIc3Wc.js.gz +0 -0
- package/dashboard/dist/assets/CE38zU4U.js +1 -0
- package/dashboard/dist/assets/CE38zU4U.js.br +0 -0
- package/dashboard/dist/assets/CE38zU4U.js.gz +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js +1 -0
- package/dashboard/dist/assets/CFGKRAzG.js.br +0 -0
- package/dashboard/dist/assets/CFGKRAzG.js.gz +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js +1 -0
- package/dashboard/dist/assets/CGGR2GZh.js.br +0 -0
- package/dashboard/dist/assets/CGGR2GZh.js.gz +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js +1 -0
- package/dashboard/dist/assets/CL_wXqR7.js.br +0 -0
- package/dashboard/dist/assets/CL_wXqR7.js.gz +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js +8 -0
- package/dashboard/dist/assets/CPFiTmlw.js.br +0 -0
- package/dashboard/dist/assets/CPFiTmlw.js.gz +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js +1 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.br +0 -0
- package/dashboard/dist/assets/CZZTvkQZ.js.gz +0 -0
- package/dashboard/dist/assets/{CpJsfbXo.js → CxQ08qFN.js} +2 -2
- package/dashboard/dist/assets/CxQ08qFN.js.br +0 -0
- package/dashboard/dist/assets/CxQ08qFN.js.gz +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js +213 -0
- package/dashboard/dist/assets/D-bf6hEI.js.br +0 -0
- package/dashboard/dist/assets/D-bf6hEI.js.gz +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js +2 -0
- package/dashboard/dist/assets/DG6y9wJI.js.br +0 -0
- package/dashboard/dist/assets/DG6y9wJI.js.gz +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js +1 -0
- package/dashboard/dist/assets/DNxKz-GV.js.br +0 -0
- package/dashboard/dist/assets/DNxKz-GV.js.gz +0 -0
- package/dashboard/dist/assets/DW_rKUic.js +11 -0
- package/dashboard/dist/assets/DW_rKUic.js.br +0 -0
- package/dashboard/dist/assets/DW_rKUic.js.gz +0 -0
- package/dashboard/dist/assets/DbNoijHm.js +1 -0
- package/dashboard/dist/assets/DbNoijHm.js.br +0 -0
- package/dashboard/dist/assets/DbNoijHm.js.gz +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js +2 -0
- package/dashboard/dist/assets/DjcdE6jC.js.br +0 -0
- package/dashboard/dist/assets/DjcdE6jC.js.gz +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js +1 -0
- package/dashboard/dist/assets/FZYuCDnt.js.br +0 -0
- package/dashboard/dist/assets/FZYuCDnt.js.gz +0 -0
- package/dashboard/dist/assets/PAUiij_z.js +1 -0
- package/dashboard/dist/assets/PAUiij_z.js.br +0 -0
- package/dashboard/dist/assets/PAUiij_z.js.gz +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js +8 -0
- package/dashboard/dist/assets/cNrhgGc1.js.br +0 -0
- package/dashboard/dist/assets/cNrhgGc1.js.gz +0 -0
- package/dashboard/dist/assets/h5biQs2I.css +1 -0
- package/dashboard/dist/assets/h5biQs2I.css.br +0 -0
- package/dashboard/dist/assets/h5biQs2I.css.gz +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js +1 -0
- package/dashboard/dist/assets/ic2FaMnh.js.br +0 -0
- package/dashboard/dist/assets/ic2FaMnh.js.gz +0 -0
- package/dashboard/dist/assets/nByHNHoW.js +1 -0
- package/dashboard/dist/assets/nByHNHoW.js.br +0 -0
- package/dashboard/dist/assets/nByHNHoW.js.gz +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css +1 -0
- package/dashboard/dist/assets/qm8xLgv-.css.br +0 -0
- package/dashboard/dist/assets/qm8xLgv-.css.gz +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js +1 -0
- package/dashboard/dist/assets/tS9mbYZi.js.br +0 -0
- package/dashboard/dist/assets/tS9mbYZi.js.gz +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.br +0 -0
- package/dashboard/dist/brand/anthropic-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openai-mark.svg.br +0 -0
- package/dashboard/dist/brand/openai-mark.svg.gz +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.br +0 -0
- package/dashboard/dist/brand/openclaw-mark.svg.gz +0 -0
- package/dashboard/dist/brand/xandy-orchestrator.png +0 -0
- package/dashboard/dist/index.html +7 -5
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/activity-actor-fields.js +26 -4
- package/dist/activity-store.js +38 -26
- package/dist/agent-context-store.js +84 -42
- package/dist/agent-run-store.js +49 -28
- package/dist/agent-suite.d.ts +9 -0
- package/dist/agent-suite.js +150 -17
- package/dist/artifacts/artifact-domain-schemas.d.ts +66 -0
- package/dist/artifacts/artifact-domain-schemas.js +357 -0
- package/dist/artifacts/register-artifact.d.ts +4 -3
- package/dist/artifacts/register-artifact.js +170 -57
- package/dist/auth/flows.d.ts +47 -0
- package/dist/auth/flows.js +169 -0
- package/dist/auth-store.js +6 -26
- package/dist/byok-store.js +5 -19
- package/dist/chat-store.d.ts +157 -0
- package/dist/chat-store.js +586 -0
- package/dist/cli/orgx.d.ts +66 -0
- package/dist/cli/orgx.js +102 -0
- package/dist/config/refresh.d.ts +32 -0
- package/dist/config/refresh.js +55 -0
- package/dist/config/resolution.d.ts +37 -0
- package/dist/config/resolution.js +178 -0
- package/dist/contracts/client.d.ts +43 -3
- package/dist/contracts/client.js +159 -30
- package/dist/contracts/retro-schema.d.ts +81 -0
- package/dist/contracts/retro-schema.js +80 -0
- package/dist/contracts/shared-types.d.ts +306 -0
- package/dist/contracts/shared-types.js +179 -0
- package/dist/contracts/skill-pack-schema.d.ts +192 -0
- package/dist/contracts/skill-pack-schema.js +180 -0
- package/dist/contracts/types.d.ts +224 -132
- package/dist/contracts/types.js +5 -0
- package/dist/entities/auto-assignment.d.ts +36 -0
- package/dist/entities/auto-assignment.js +141 -0
- package/dist/entity-comment-store.js +5 -25
- package/dist/event-sanitization.d.ts +11 -0
- package/dist/event-sanitization.js +113 -0
- package/dist/fs-utils.js +13 -1
- package/dist/gateway-watchdog.d.ts +5 -0
- package/dist/gateway-watchdog.js +50 -0
- package/dist/hash-utils.d.ts +2 -0
- package/dist/hash-utils.js +12 -0
- package/dist/hooks/post-reporting-event.mjs +1 -5
- package/dist/http/helpers/activity-headline.d.ts +10 -0
- package/dist/http/helpers/activity-headline.js +73 -0
- package/dist/http/helpers/artifact-fallback.d.ts +13 -0
- package/dist/http/helpers/artifact-fallback.js +148 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +486 -0
- package/dist/http/helpers/auto-continue-engine.js +3563 -0
- package/dist/http/helpers/autopilot-operations.d.ts +176 -0
- package/dist/http/helpers/autopilot-operations.js +554 -0
- package/dist/http/helpers/autopilot-runtime.d.ts +43 -0
- package/dist/http/helpers/autopilot-runtime.js +607 -0
- package/dist/http/helpers/autopilot-slice-utils.d.ts +56 -0
- package/dist/http/helpers/autopilot-slice-utils.js +899 -0
- package/dist/http/helpers/decision-mapper.d.ts +52 -0
- package/dist/http/helpers/decision-mapper.js +260 -0
- package/dist/http/helpers/dispatch-lifecycle.d.ts +119 -0
- package/dist/http/helpers/dispatch-lifecycle.js +809 -0
- package/dist/http/helpers/hash-utils.d.ts +1 -0
- package/dist/http/helpers/hash-utils.js +1 -0
- package/dist/http/helpers/kickoff-context.d.ts +12 -0
- package/dist/http/helpers/kickoff-context.js +228 -0
- package/dist/http/helpers/llm-client.d.ts +47 -0
- package/dist/http/helpers/llm-client.js +256 -0
- package/dist/http/helpers/mission-control.d.ts +193 -0
- package/dist/http/helpers/mission-control.js +1383 -0
- package/dist/http/helpers/openclaw-cli.d.ts +37 -0
- package/dist/http/helpers/openclaw-cli.js +283 -0
- package/dist/http/helpers/runtime-sse.d.ts +20 -0
- package/dist/http/helpers/runtime-sse.js +110 -0
- package/dist/http/helpers/sentinel-catalog.d.ts +23 -0
- package/dist/http/helpers/sentinel-catalog.js +193 -0
- package/dist/http/helpers/session-classification.d.ts +9 -0
- package/dist/http/helpers/session-classification.js +564 -0
- package/dist/http/helpers/slice-experience-v2.d.ts +137 -0
- package/dist/http/helpers/slice-experience-v2.js +677 -0
- package/dist/http/helpers/slice-run-projections.d.ts +72 -0
- package/dist/http/helpers/slice-run-projections.js +860 -0
- package/dist/http/helpers/triage-mapper.d.ts +43 -0
- package/dist/http/helpers/triage-mapper.js +549 -0
- package/dist/http/helpers/value-utils.d.ts +6 -0
- package/dist/http/helpers/value-utils.js +72 -0
- package/dist/http/helpers/workspace-scope.d.ts +15 -0
- package/dist/http/helpers/workspace-scope.js +170 -0
- package/dist/http/index.d.ts +88 -0
- package/dist/http/index.js +3610 -0
- package/dist/http/router.d.ts +23 -0
- package/dist/http/router.js +23 -0
- package/dist/http/routes/agent-control.d.ts +79 -0
- package/dist/http/routes/agent-control.js +684 -0
- package/dist/http/routes/agent-suite.d.ts +38 -0
- package/dist/http/routes/agent-suite.js +397 -0
- package/dist/http/routes/agents-catalog.d.ts +40 -0
- package/dist/http/routes/agents-catalog.js +128 -0
- package/dist/http/routes/billing.d.ts +23 -0
- package/dist/http/routes/billing.js +55 -0
- package/dist/http/routes/chat.d.ts +19 -0
- package/dist/http/routes/chat.js +522 -0
- package/dist/http/routes/debug.d.ts +14 -0
- package/dist/http/routes/debug.js +21 -0
- package/dist/http/routes/decision-actions.d.ts +20 -0
- package/dist/http/routes/decision-actions.js +103 -0
- package/dist/http/routes/delegation.d.ts +19 -0
- package/dist/http/routes/delegation.js +32 -0
- package/dist/http/routes/dispatch-gateway-envelope.d.ts +25 -0
- package/dist/http/routes/dispatch-gateway-envelope.js +26 -0
- package/dist/http/routes/entities.d.ts +63 -0
- package/dist/http/routes/entities.js +440 -0
- package/dist/http/routes/entity-dynamic.d.ts +25 -0
- package/dist/http/routes/entity-dynamic.js +191 -0
- package/dist/http/routes/health.d.ts +22 -0
- package/dist/http/routes/health.js +49 -0
- package/dist/http/routes/live-legacy.d.ts +115 -0
- package/dist/http/routes/live-legacy.js +112 -0
- package/dist/http/routes/live-misc.d.ts +81 -0
- package/dist/http/routes/live-misc.js +426 -0
- package/dist/http/routes/live-snapshot.d.ts +136 -0
- package/dist/http/routes/live-snapshot.js +916 -0
- package/dist/http/routes/live-terminal.d.ts +11 -0
- package/dist/http/routes/live-terminal.js +261 -0
- package/dist/http/routes/live-triage.d.ts +61 -0
- package/dist/http/routes/live-triage.js +248 -0
- package/dist/http/routes/mission-control-actions.d.ts +131 -0
- package/dist/http/routes/mission-control-actions.js +1791 -0
- package/dist/http/routes/mission-control-read.d.ts +73 -0
- package/dist/http/routes/mission-control-read.js +1640 -0
- package/dist/http/routes/onboarding.d.ts +34 -0
- package/dist/http/routes/onboarding.js +101 -0
- package/dist/http/routes/realtime-orchestrator.d.ts +10 -0
- package/dist/http/routes/realtime-orchestrator.js +74 -0
- package/dist/http/routes/run-control.d.ts +27 -0
- package/dist/http/routes/run-control.js +96 -0
- package/dist/http/routes/runtime-hooks.d.ts +69 -0
- package/dist/http/routes/runtime-hooks.js +437 -0
- package/dist/http/routes/sentinels-catalog.d.ts +7 -0
- package/dist/http/routes/sentinels-catalog.js +24 -0
- package/dist/http/routes/settings-byok.d.ts +23 -0
- package/dist/http/routes/settings-byok.js +163 -0
- package/dist/http/routes/summary.d.ts +18 -0
- package/dist/http/routes/summary.js +49 -0
- package/dist/http/routes/usage.d.ts +24 -0
- package/dist/http/routes/usage.js +362 -0
- package/dist/http/routes/work-artifacts.d.ts +9 -0
- package/dist/http/routes/work-artifacts.js +55 -0
- package/dist/http/shared-state.d.ts +16 -0
- package/dist/http/shared-state.js +1 -0
- package/dist/http-handler.d.ts +1 -88
- package/dist/http-handler.js +1 -10605
- package/dist/index.js +287 -2284
- package/dist/json-utils.d.ts +1 -0
- package/dist/json-utils.js +8 -0
- package/dist/local-openclaw.js +29 -6
- package/dist/mcp-client-setup.js +3 -3
- package/dist/mcp-http-handler.js +33 -59
- package/dist/next-up-queue-store.d.ts +16 -1
- package/dist/next-up-queue-store.js +93 -25
- package/dist/outbox.d.ts +5 -0
- package/dist/outbox.js +113 -9
- package/dist/paths.js +24 -5
- package/dist/reporting/rollups.d.ts +53 -0
- package/dist/reporting/rollups.js +148 -0
- package/dist/retro/domain-templates.d.ts +45 -0
- package/dist/retro/domain-templates.js +297 -0
- package/dist/retro/quality-rubric.d.ts +33 -0
- package/dist/retro/quality-rubric.js +213 -0
- package/dist/runtime-cleanup.d.ts +18 -0
- package/dist/runtime-cleanup.js +87 -0
- package/dist/runtime-instance-store.js +5 -31
- package/dist/services/background.d.ts +34 -0
- package/dist/services/background.js +45 -0
- package/dist/services/experiment-randomization.d.ts +21 -0
- package/dist/services/experiment-randomization.js +63 -0
- package/dist/services/instrumentation.d.ts +29 -0
- package/dist/services/instrumentation.js +136 -0
- package/dist/skill-pack-state.d.ts +36 -5
- package/dist/skill-pack-state.js +273 -29
- package/dist/snapshot-store.js +5 -25
- package/dist/stores/json-store.d.ts +11 -0
- package/dist/stores/json-store.js +42 -0
- package/dist/sync/local-agent-telemetry.d.ts +13 -0
- package/dist/sync/local-agent-telemetry.js +128 -0
- package/dist/sync/outbox-replay.d.ts +55 -0
- package/dist/sync/outbox-replay.js +621 -0
- package/dist/team-context-store.d.ts +23 -0
- package/dist/team-context-store.js +116 -0
- package/dist/telemetry/posthog.js +4 -2
- package/dist/tools/core-tools.d.ts +72 -0
- package/dist/tools/core-tools.js +2270 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -0
- package/dist/worker-supervisor.js +23 -0
- package/package.json +14 -4
- package/dashboard/dist/assets/B3ziCA02.js +0 -8
- package/dashboard/dist/assets/BNeJ0kpF.js +0 -1
- package/dashboard/dist/assets/BzkiMPmM.js +0 -215
- package/dashboard/dist/assets/CUV9IHHi.js +0 -1
- package/dashboard/dist/assets/Ie7d9Iq2.css +0 -1
- package/dashboard/dist/assets/sAhvFnpk.js +0 -4
package/dist/paths.js
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
function normalizeDirOverride(value) {
|
|
4
|
-
|
|
4
|
+
let trimmed = (value ?? "").trim();
|
|
5
5
|
if (!trimmed)
|
|
6
6
|
return null;
|
|
7
|
-
|
|
7
|
+
// `.env` values are often quoted; normalize them before validation.
|
|
8
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
9
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
10
|
+
trimmed = trimmed.slice(1, -1).trim();
|
|
11
|
+
if (!trimmed)
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// Reject control characters to avoid malformed or ambiguous filesystem paths.
|
|
15
|
+
if (/[\u0000-\u001f\u007f]/.test(trimmed))
|
|
16
|
+
return null;
|
|
17
|
+
// Reject common escaped/encoded null-byte sequences as well.
|
|
18
|
+
if (/\\0|\\x00|\\u0000|%00/i.test(trimmed))
|
|
8
19
|
return null;
|
|
9
20
|
return trimmed;
|
|
10
21
|
}
|
|
22
|
+
function resolveOverridePath(override) {
|
|
23
|
+
if (override === "~")
|
|
24
|
+
return homedir();
|
|
25
|
+
if (override.startsWith("~/") || override.startsWith("~\\")) {
|
|
26
|
+
return resolve(homedir(), override.slice(2));
|
|
27
|
+
}
|
|
28
|
+
return resolve(override);
|
|
29
|
+
}
|
|
11
30
|
/**
|
|
12
31
|
* Root directory for persistent OrgX plugin files.
|
|
13
32
|
*
|
|
@@ -17,7 +36,7 @@ function normalizeDirOverride(value) {
|
|
|
17
36
|
export function getOrgxPluginConfigDir() {
|
|
18
37
|
const override = normalizeDirOverride(process.env.ORGX_OPENCLAW_PLUGIN_CONFIG_DIR);
|
|
19
38
|
if (override)
|
|
20
|
-
return
|
|
39
|
+
return resolveOverridePath(override);
|
|
21
40
|
return join(homedir(), ".config", "useorgx", "openclaw-plugin");
|
|
22
41
|
}
|
|
23
42
|
export function getOrgxPluginConfigPath(filename) {
|
|
@@ -32,7 +51,7 @@ export function getOrgxPluginConfigPath(filename) {
|
|
|
32
51
|
export function getOpenClawDir() {
|
|
33
52
|
const override = normalizeDirOverride(process.env.OPENCLAW_HOME);
|
|
34
53
|
if (override)
|
|
35
|
-
return
|
|
54
|
+
return resolveOverridePath(override);
|
|
36
55
|
return join(homedir(), ".openclaw");
|
|
37
56
|
}
|
|
38
57
|
/**
|
|
@@ -44,6 +63,6 @@ export function getOpenClawDir() {
|
|
|
44
63
|
export function getOrgxOutboxDir() {
|
|
45
64
|
const override = normalizeDirOverride(process.env.ORGX_OUTBOX_DIR);
|
|
46
65
|
if (override)
|
|
47
|
-
return
|
|
66
|
+
return resolveOverridePath(override);
|
|
48
67
|
return join(getOpenClawDir(), "orgx-outbox");
|
|
49
68
|
}
|
|
@@ -18,3 +18,56 @@ export declare function computeWorkstreamRollup(taskStatuses?: unknown[]): TaskS
|
|
|
18
18
|
status: WorkstreamRollupStatus;
|
|
19
19
|
progressPct: number;
|
|
20
20
|
};
|
|
21
|
+
export type TaskCompletionReadiness = "ready" | "needs_proof" | "needs_review";
|
|
22
|
+
export interface TaskCompletionReadinessResult {
|
|
23
|
+
ready: boolean;
|
|
24
|
+
status: TaskCompletionReadiness;
|
|
25
|
+
hasArtifact: boolean;
|
|
26
|
+
hasSchemaValidatedArtifact: boolean;
|
|
27
|
+
hasQualityScore: boolean;
|
|
28
|
+
qualityScore: number | null;
|
|
29
|
+
qualityThreshold: number;
|
|
30
|
+
missingItems: string[];
|
|
31
|
+
warnings: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Evaluate whether a task has sufficient proof chain evidence to be marked
|
|
35
|
+
* complete. In phase 1 this is advisory (warn-only); callers decide whether
|
|
36
|
+
* to hard-block or soft-warn based on workspace config.
|
|
37
|
+
*/
|
|
38
|
+
export declare function computeTaskCompletionReadiness(input: {
|
|
39
|
+
artifacts?: Array<{
|
|
40
|
+
schema_validated?: boolean;
|
|
41
|
+
atomic_unit_type?: string;
|
|
42
|
+
}>;
|
|
43
|
+
qualityScore?: number | null;
|
|
44
|
+
qualityThreshold?: number;
|
|
45
|
+
hasOutcomeEvent?: boolean;
|
|
46
|
+
}): TaskCompletionReadinessResult;
|
|
47
|
+
export type LifecycleState = 'Queued' | 'Dispatching' | 'In Progress' | 'Blocked' | 'Completed' | 'Paused' | 'Failed';
|
|
48
|
+
/**
|
|
49
|
+
* Derive an honest lifecycle state for an entity based on its raw status
|
|
50
|
+
* and child statuses. This is the authoritative backend derivation —
|
|
51
|
+
* the dashboard mirrors this logic in status-taxonomy.ts.
|
|
52
|
+
*/
|
|
53
|
+
export declare function deriveLifecycleState(rawStatus: unknown, childStatuses?: unknown[]): LifecycleState;
|
|
54
|
+
/**
|
|
55
|
+
* Compute cascaded progress: parent progress derived from child task states.
|
|
56
|
+
* Returns a percentage (0–100) representing weighted completion.
|
|
57
|
+
*/
|
|
58
|
+
export declare function cascadeProgressFromChildren(childStatuses: unknown[]): number;
|
|
59
|
+
export type EvalPassRateDriftResult = {
|
|
60
|
+
alert: boolean;
|
|
61
|
+
baselinePassRate: number;
|
|
62
|
+
rollingPassRate7d: number;
|
|
63
|
+
dropPct: number;
|
|
64
|
+
thresholdDropPct: number;
|
|
65
|
+
baselineSamples: number;
|
|
66
|
+
rollingSamples: number;
|
|
67
|
+
};
|
|
68
|
+
export declare function detectEvalPassRateDrift(input: {
|
|
69
|
+
passRates: unknown[];
|
|
70
|
+
thresholdDropPct?: number;
|
|
71
|
+
rollingWindowDays?: number;
|
|
72
|
+
baselineWindowDays?: number;
|
|
73
|
+
}): EvalPassRateDriftResult | null;
|
|
@@ -82,3 +82,151 @@ export function computeWorkstreamRollup(taskStatuses = []) {
|
|
|
82
82
|
progressPct,
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
+
function normalizePassRate(value) {
|
|
86
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
87
|
+
if (!Number.isFinite(n))
|
|
88
|
+
return null;
|
|
89
|
+
if (n < 0)
|
|
90
|
+
return 0;
|
|
91
|
+
if (n <= 1)
|
|
92
|
+
return n;
|
|
93
|
+
if (n <= 100)
|
|
94
|
+
return n / 100;
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
function average(values) {
|
|
98
|
+
if (values.length <= 0)
|
|
99
|
+
return 0;
|
|
100
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
101
|
+
return total / values.length;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Evaluate whether a task has sufficient proof chain evidence to be marked
|
|
105
|
+
* complete. In phase 1 this is advisory (warn-only); callers decide whether
|
|
106
|
+
* to hard-block or soft-warn based on workspace config.
|
|
107
|
+
*/
|
|
108
|
+
export function computeTaskCompletionReadiness(input) {
|
|
109
|
+
const artifacts = Array.isArray(input.artifacts) ? input.artifacts : [];
|
|
110
|
+
const qualityThreshold = typeof input.qualityThreshold === "number" && Number.isFinite(input.qualityThreshold)
|
|
111
|
+
? input.qualityThreshold
|
|
112
|
+
: 4;
|
|
113
|
+
const qualityScore = typeof input.qualityScore === "number" && Number.isFinite(input.qualityScore)
|
|
114
|
+
? input.qualityScore
|
|
115
|
+
: null;
|
|
116
|
+
const hasArtifact = artifacts.length > 0;
|
|
117
|
+
const hasSchemaValidatedArtifact = artifacts.some((a) => a.schema_validated === true && typeof a.atomic_unit_type === "string");
|
|
118
|
+
const hasQualityScore = qualityScore !== null;
|
|
119
|
+
const qualityMeetsThreshold = qualityScore !== null && qualityScore >= qualityThreshold;
|
|
120
|
+
const missingItems = [];
|
|
121
|
+
const warnings = [];
|
|
122
|
+
if (!hasArtifact) {
|
|
123
|
+
missingItems.push("No artifact registered for this task.");
|
|
124
|
+
}
|
|
125
|
+
else if (!hasSchemaValidatedArtifact) {
|
|
126
|
+
warnings.push("Artifact(s) present but none pass domain schema validation.");
|
|
127
|
+
}
|
|
128
|
+
if (!hasQualityScore) {
|
|
129
|
+
missingItems.push("No quality score recorded.");
|
|
130
|
+
}
|
|
131
|
+
else if (!qualityMeetsThreshold) {
|
|
132
|
+
missingItems.push(`Quality score ${qualityScore} below threshold ${qualityThreshold}.`);
|
|
133
|
+
}
|
|
134
|
+
if (input.hasOutcomeEvent === false) {
|
|
135
|
+
warnings.push("No outcome event recorded (L5 Impact not met).");
|
|
136
|
+
}
|
|
137
|
+
const ready = hasArtifact && hasQualityScore && qualityMeetsThreshold;
|
|
138
|
+
let status;
|
|
139
|
+
if (ready) {
|
|
140
|
+
status = "ready";
|
|
141
|
+
}
|
|
142
|
+
else if (hasArtifact && hasQualityScore) {
|
|
143
|
+
status = "needs_review";
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
status = "needs_proof";
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
ready,
|
|
150
|
+
status,
|
|
151
|
+
hasArtifact,
|
|
152
|
+
hasSchemaValidatedArtifact,
|
|
153
|
+
hasQualityScore,
|
|
154
|
+
qualityScore,
|
|
155
|
+
qualityThreshold,
|
|
156
|
+
missingItems,
|
|
157
|
+
warnings,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Derive an honest lifecycle state for an entity based on its raw status
|
|
162
|
+
* and child statuses. This is the authoritative backend derivation —
|
|
163
|
+
* the dashboard mirrors this logic in status-taxonomy.ts.
|
|
164
|
+
*/
|
|
165
|
+
export function deriveLifecycleState(rawStatus, childStatuses) {
|
|
166
|
+
const s = classifyTaskState(rawStatus);
|
|
167
|
+
if (s === 'done')
|
|
168
|
+
return 'Completed';
|
|
169
|
+
if (s === 'blocked')
|
|
170
|
+
return 'Blocked';
|
|
171
|
+
if (!childStatuses || childStatuses.length === 0) {
|
|
172
|
+
if (s === 'active')
|
|
173
|
+
return 'In Progress';
|
|
174
|
+
return 'Queued';
|
|
175
|
+
}
|
|
176
|
+
const counts = summarizeTaskStatuses(childStatuses);
|
|
177
|
+
if (counts.total > 0 && counts.done >= counts.total)
|
|
178
|
+
return 'Completed';
|
|
179
|
+
if (counts.blocked > 0 && counts.active === 0 && counts.done < counts.total)
|
|
180
|
+
return 'Blocked';
|
|
181
|
+
if (counts.active > 0 || counts.done > 0)
|
|
182
|
+
return 'In Progress';
|
|
183
|
+
return 'Queued';
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Compute cascaded progress: parent progress derived from child task states.
|
|
187
|
+
* Returns a percentage (0–100) representing weighted completion.
|
|
188
|
+
*/
|
|
189
|
+
export function cascadeProgressFromChildren(childStatuses) {
|
|
190
|
+
if (!Array.isArray(childStatuses) || childStatuses.length === 0)
|
|
191
|
+
return 0;
|
|
192
|
+
const counts = summarizeTaskStatuses(childStatuses);
|
|
193
|
+
return toPercent(counts.done, counts.total);
|
|
194
|
+
}
|
|
195
|
+
export function detectEvalPassRateDrift(input) {
|
|
196
|
+
const thresholdDropPct = typeof input.thresholdDropPct === "number" && Number.isFinite(input.thresholdDropPct) && input.thresholdDropPct >= 0
|
|
197
|
+
? input.thresholdDropPct
|
|
198
|
+
: 5;
|
|
199
|
+
const rollingWindowDays = typeof input.rollingWindowDays === "number" && Number.isFinite(input.rollingWindowDays) && input.rollingWindowDays > 0
|
|
200
|
+
? Math.floor(input.rollingWindowDays)
|
|
201
|
+
: 7;
|
|
202
|
+
const baselineWindowDays = typeof input.baselineWindowDays === "number" &&
|
|
203
|
+
Number.isFinite(input.baselineWindowDays) &&
|
|
204
|
+
input.baselineWindowDays > 0
|
|
205
|
+
? Math.floor(input.baselineWindowDays)
|
|
206
|
+
: rollingWindowDays;
|
|
207
|
+
const normalizedPassRates = (Array.isArray(input.passRates) ? input.passRates : [])
|
|
208
|
+
.map(normalizePassRate)
|
|
209
|
+
.filter((value) => value != null);
|
|
210
|
+
const requiredSamples = rollingWindowDays + baselineWindowDays;
|
|
211
|
+
if (normalizedPassRates.length < requiredSamples)
|
|
212
|
+
return null;
|
|
213
|
+
const rollingStart = normalizedPassRates.length - rollingWindowDays;
|
|
214
|
+
const baselineEnd = rollingStart;
|
|
215
|
+
const baselineStart = Math.max(0, baselineEnd - baselineWindowDays);
|
|
216
|
+
const rollingSlice = normalizedPassRates.slice(rollingStart);
|
|
217
|
+
const baselineSlice = normalizedPassRates.slice(baselineStart, baselineEnd);
|
|
218
|
+
if (rollingSlice.length <= 0 || baselineSlice.length <= 0)
|
|
219
|
+
return null;
|
|
220
|
+
const baselinePassRate = average(baselineSlice);
|
|
221
|
+
const rollingPassRate7d = average(rollingSlice);
|
|
222
|
+
const dropPct = Number(((baselinePassRate - rollingPassRate7d) * 100).toFixed(2));
|
|
223
|
+
return {
|
|
224
|
+
alert: dropPct > thresholdDropPct,
|
|
225
|
+
baselinePassRate: Number(baselinePassRate.toFixed(4)),
|
|
226
|
+
rollingPassRate7d: Number(rollingPassRate7d.toFixed(4)),
|
|
227
|
+
dropPct,
|
|
228
|
+
thresholdDropPct,
|
|
229
|
+
baselineSamples: baselineSlice.length,
|
|
230
|
+
rollingSamples: rollingSlice.length,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
type RetroFollowUp = {
|
|
2
|
+
title: string;
|
|
3
|
+
priority?: "p0" | "p1" | "p2";
|
|
4
|
+
reason?: string;
|
|
5
|
+
};
|
|
6
|
+
export type OrgxAgentRetroDomain = "engineering" | "product" | "design" | "marketing" | "sales" | "operations" | "orchestration" | "general";
|
|
7
|
+
export declare function buildRetroTemplateForAgent(input: {
|
|
8
|
+
agentId: string | null | undefined;
|
|
9
|
+
success: boolean;
|
|
10
|
+
taskId: string | null | undefined;
|
|
11
|
+
runId: string;
|
|
12
|
+
errorMessage: string | null | undefined;
|
|
13
|
+
}): {
|
|
14
|
+
domain: OrgxAgentRetroDomain;
|
|
15
|
+
summary: string;
|
|
16
|
+
whatWentWell: string[];
|
|
17
|
+
whatWentWrong: string[];
|
|
18
|
+
decisions: string[];
|
|
19
|
+
followUps: RetroFollowUp[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Generate a structured retro using an LLM, falling back to the heuristic
|
|
23
|
+
* template produced by {@link buildRetroTemplateForAgent}.
|
|
24
|
+
*
|
|
25
|
+
* Caller: src/index.ts (~line 971) — `buildRetroTemplateForAgent` is invoked
|
|
26
|
+
* inside the session-stopped handler. Migrate that call site to use this
|
|
27
|
+
* function when ready to enable LLM-powered retros.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildRetroWithLlm(input: {
|
|
30
|
+
agentId: string | null | undefined;
|
|
31
|
+
success: boolean;
|
|
32
|
+
taskId: string | null | undefined;
|
|
33
|
+
runId: string;
|
|
34
|
+
errorMessage: string | null | undefined;
|
|
35
|
+
executionContext?: string | null;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
domain: OrgxAgentRetroDomain;
|
|
38
|
+
summary: string;
|
|
39
|
+
whatWentWell: string[];
|
|
40
|
+
whatWentWrong: string[];
|
|
41
|
+
decisions: string[];
|
|
42
|
+
followUps: RetroFollowUp[];
|
|
43
|
+
source: "llm" | "heuristic";
|
|
44
|
+
}>;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { callLlmJson } from "../http/helpers/llm-client.js";
|
|
2
|
+
const DOMAIN_TEMPLATES = {
|
|
3
|
+
engineering: {
|
|
4
|
+
summaryPrefix: "Engineering execution",
|
|
5
|
+
successWell: [
|
|
6
|
+
"Delivered implementation changes with focused validation evidence.",
|
|
7
|
+
"Kept execution scoped to the active slice and avoided unrelated churn.",
|
|
8
|
+
],
|
|
9
|
+
successDecisions: ["No immediate intervention required; keep current engineering execution pattern."],
|
|
10
|
+
successFollowUps: [
|
|
11
|
+
{
|
|
12
|
+
title: "Capture engineering implementation notes for future retros",
|
|
13
|
+
priority: "p2",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
failureDecision: "Escalate blocker triage and assign root-cause owner before the next engineering run.",
|
|
17
|
+
failureFollowUpTitle: "Reproduce failure with a targeted engineering check and patch root cause",
|
|
18
|
+
failureFollowUpReason: "Engineering runs should converge quickly on reproducible failures and ship a corrective change.",
|
|
19
|
+
},
|
|
20
|
+
product: {
|
|
21
|
+
summaryPrefix: "Product execution",
|
|
22
|
+
successWell: [
|
|
23
|
+
"Clarified scope and acceptance criteria for the requested slice.",
|
|
24
|
+
"Converted ambiguous asks into concrete execution steps.",
|
|
25
|
+
],
|
|
26
|
+
successDecisions: ["Proceed with the current product plan and track any open assumptions."],
|
|
27
|
+
successFollowUps: [{ title: "Log product assumptions and open questions", priority: "p2" }],
|
|
28
|
+
failureDecision: "Resolve product scope/acceptance ambiguity with a direct owner decision before retry.",
|
|
29
|
+
failureFollowUpTitle: "Resolve product requirement ambiguity before next run",
|
|
30
|
+
failureFollowUpReason: "Product loops fail when acceptance criteria and constraints remain underspecified.",
|
|
31
|
+
},
|
|
32
|
+
design: {
|
|
33
|
+
summaryPrefix: "Design execution",
|
|
34
|
+
successWell: [
|
|
35
|
+
"Produced design output aligned with existing system constraints.",
|
|
36
|
+
"Prioritized usability clarity over decorative changes.",
|
|
37
|
+
],
|
|
38
|
+
successDecisions: ["Continue with the approved design direction and preserve current constraints."],
|
|
39
|
+
successFollowUps: [{ title: "Attach visual QA checklist for handoff", priority: "p2" }],
|
|
40
|
+
failureDecision: "Run a blocking UX triage decision and align acceptance checkpoints before rerun.",
|
|
41
|
+
failureFollowUpTitle: "Run design QA pass and fix blocking UX mismatches",
|
|
42
|
+
failureFollowUpReason: "Design regressions should be validated with explicit viewport and interaction checks.",
|
|
43
|
+
},
|
|
44
|
+
marketing: {
|
|
45
|
+
summaryPrefix: "Marketing execution",
|
|
46
|
+
successWell: [
|
|
47
|
+
"Delivered channel-ready messaging with clear audience targeting.",
|
|
48
|
+
"Maintained consistent narrative and measurable intent.",
|
|
49
|
+
],
|
|
50
|
+
successDecisions: ["Keep the current campaign direction and monitor defined success signals."],
|
|
51
|
+
successFollowUps: [{ title: "Record campaign hypotheses and success metrics", priority: "p2" }],
|
|
52
|
+
failureDecision: "Decide on updated positioning hypothesis before the next marketing execution cycle.",
|
|
53
|
+
failureFollowUpTitle: "Diagnose marketing execution gap and tighten message-to-metric mapping",
|
|
54
|
+
failureFollowUpReason: "Marketing outcomes need explicit hypotheses, channel constraints, and measurable goals.",
|
|
55
|
+
},
|
|
56
|
+
sales: {
|
|
57
|
+
summaryPrefix: "Sales execution",
|
|
58
|
+
successWell: [
|
|
59
|
+
"Created actionable next steps tied to buyer-stage progression.",
|
|
60
|
+
"Preserved signal quality for follow-up actions and objections.",
|
|
61
|
+
],
|
|
62
|
+
successDecisions: ["Continue with the current sales motion while maintaining pipeline signal quality."],
|
|
63
|
+
successFollowUps: [{ title: "Document discovery-to-close handoff notes", priority: "p2" }],
|
|
64
|
+
failureDecision: "Trigger a sales unblock decision on objection handling and next-step ownership.",
|
|
65
|
+
failureFollowUpTitle: "Rework sales motion to unblock stalled buyer progression",
|
|
66
|
+
failureFollowUpReason: "Sales stalls usually reflect missing objection handling or unclear next actions.",
|
|
67
|
+
},
|
|
68
|
+
operations: {
|
|
69
|
+
summaryPrefix: "Operations execution",
|
|
70
|
+
successWell: [
|
|
71
|
+
"Stabilized process flow with explicit ownership and runbook alignment.",
|
|
72
|
+
"Reduced operational risk through controlled scope and sequencing.",
|
|
73
|
+
],
|
|
74
|
+
successDecisions: ["Keep current ops controls and apply runbook deltas from this run."],
|
|
75
|
+
successFollowUps: [{ title: "Add ops runbook delta from this run", priority: "p2" }],
|
|
76
|
+
failureDecision: "Escalate operational owner decision to remove the bottleneck before retrying.",
|
|
77
|
+
failureFollowUpTitle: "Patch operational bottleneck and update runbook controls",
|
|
78
|
+
failureFollowUpReason: "Operations failures should result in tighter runbooks and clearer owner accountability.",
|
|
79
|
+
},
|
|
80
|
+
orchestration: {
|
|
81
|
+
summaryPrefix: "Orchestration execution",
|
|
82
|
+
successWell: [
|
|
83
|
+
"Coordinated dependencies and sequencing across agents effectively.",
|
|
84
|
+
"Maintained clear control flow for decisions and handoffs.",
|
|
85
|
+
],
|
|
86
|
+
successDecisions: ["Preserve current orchestration sequencing and monitor handoff latency."],
|
|
87
|
+
successFollowUps: [{ title: "Capture orchestration handoff timing insights", priority: "p2" }],
|
|
88
|
+
failureDecision: "Request an orchestration sequencing decision to unblock dependency handoffs.",
|
|
89
|
+
failureFollowUpTitle: "Unblock orchestration handoff failure and re-sequence dependent work",
|
|
90
|
+
failureFollowUpReason: "Orchestration errors should tighten dependency ordering and handoff contracts.",
|
|
91
|
+
},
|
|
92
|
+
general: {
|
|
93
|
+
summaryPrefix: "Execution",
|
|
94
|
+
successWell: ["Completed the requested run without runtime error."],
|
|
95
|
+
successDecisions: ["No immediate action required; continue with the current execution flow."],
|
|
96
|
+
successFollowUps: [],
|
|
97
|
+
failureDecision: "Request a human unblock decision before the next retry.",
|
|
98
|
+
failureFollowUpTitle: "Investigate OpenClaw session failure and unblock task",
|
|
99
|
+
failureFollowUpReason: "Session ended with error.",
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
function inferDomainFromAgentId(agentId) {
|
|
103
|
+
const normalized = String(agentId ?? "").trim().toLowerCase();
|
|
104
|
+
if (!normalized)
|
|
105
|
+
return "general";
|
|
106
|
+
const compact = normalized.replace(/[^a-z0-9]/g, "");
|
|
107
|
+
const tokenSet = new Set(normalized.split(/[^a-z0-9]+/g).filter(Boolean));
|
|
108
|
+
const hasToken = (...tokens) => tokens.some((token) => tokenSet.has(token));
|
|
109
|
+
const hasTokenPrefix = (...prefixes) => Array.from(tokenSet).some((token) => prefixes.some((prefix) => token.startsWith(prefix)));
|
|
110
|
+
if (normalized.includes("sentinel") ||
|
|
111
|
+
hasToken("sentinel", "watchdog") ||
|
|
112
|
+
hasTokenPrefix("sentinel", "watch")) {
|
|
113
|
+
return "orchestration";
|
|
114
|
+
}
|
|
115
|
+
if (normalized.includes("engineering") ||
|
|
116
|
+
normalized.includes("developer") ||
|
|
117
|
+
hasToken("eng", "dev", "frontend", "backend", "fullstack", "engineer") ||
|
|
118
|
+
compact.includes("engineering") ||
|
|
119
|
+
compact.includes("developer")) {
|
|
120
|
+
return "engineering";
|
|
121
|
+
}
|
|
122
|
+
if (normalized.includes("product") ||
|
|
123
|
+
hasToken("pm", "prod") ||
|
|
124
|
+
hasTokenPrefix("product", "pm") ||
|
|
125
|
+
compact.includes("productmanager")) {
|
|
126
|
+
return "product";
|
|
127
|
+
}
|
|
128
|
+
if (normalized.includes("design") || tokenSet.has("ux") || tokenSet.has("ui"))
|
|
129
|
+
return "design";
|
|
130
|
+
if (normalized.includes("marketing") ||
|
|
131
|
+
hasToken("mktg", "growth") ||
|
|
132
|
+
hasTokenPrefix("mkt", "market")) {
|
|
133
|
+
return "marketing";
|
|
134
|
+
}
|
|
135
|
+
if (normalized.includes("sales") || hasToken("sdr", "ae") || hasTokenPrefix("sales"))
|
|
136
|
+
return "sales";
|
|
137
|
+
if (normalized.includes("operations") ||
|
|
138
|
+
normalized.includes("platform") ||
|
|
139
|
+
hasToken("ops", "sre", "infra") ||
|
|
140
|
+
hasTokenPrefix("operat", "platform", "infra")) {
|
|
141
|
+
return "operations";
|
|
142
|
+
}
|
|
143
|
+
if (normalized.includes("orchestrat") ||
|
|
144
|
+
hasToken("coord", "router") ||
|
|
145
|
+
hasTokenPrefix("coordinat", "orchestrat", "route")) {
|
|
146
|
+
return "orchestration";
|
|
147
|
+
}
|
|
148
|
+
return "general";
|
|
149
|
+
}
|
|
150
|
+
function isSentinelAgentId(agentId) {
|
|
151
|
+
const normalized = String(agentId ?? "").trim().toLowerCase();
|
|
152
|
+
if (!normalized)
|
|
153
|
+
return false;
|
|
154
|
+
const compact = normalized.replace(/[^a-z0-9]/g, "");
|
|
155
|
+
if (normalized.includes("sentinel") || compact.includes("sentinel")) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
const tokenSet = new Set(normalized.split(/[^a-z0-9]+/g).filter(Boolean));
|
|
159
|
+
return tokenSet.has("watchdog") || Array.from(tokenSet).some((token) => token.startsWith("watch"));
|
|
160
|
+
}
|
|
161
|
+
export function buildRetroTemplateForAgent(input) {
|
|
162
|
+
const domain = inferDomainFromAgentId(input.agentId);
|
|
163
|
+
const isSentinel = isSentinelAgentId(input.agentId);
|
|
164
|
+
const template = DOMAIN_TEMPLATES[domain];
|
|
165
|
+
const errorMessage = input.errorMessage?.trim() || "Session ended with error.";
|
|
166
|
+
const summary = input.taskId
|
|
167
|
+
? `${template.summaryPrefix} ${input.success ? "completed" : "blocked"} task ${input.taskId}.`
|
|
168
|
+
: `${template.summaryPrefix} run ${input.success ? "completed" : "blocked"} (session ${input.runId}).`;
|
|
169
|
+
if (input.success) {
|
|
170
|
+
return {
|
|
171
|
+
domain,
|
|
172
|
+
summary,
|
|
173
|
+
whatWentWell: template.successWell,
|
|
174
|
+
whatWentWrong: [],
|
|
175
|
+
decisions: template.successDecisions,
|
|
176
|
+
followUps: template.successFollowUps,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
domain,
|
|
181
|
+
summary,
|
|
182
|
+
whatWentWell: [],
|
|
183
|
+
whatWentWrong: [errorMessage],
|
|
184
|
+
decisions: [
|
|
185
|
+
isSentinel
|
|
186
|
+
? "Sentinel: resolve decision to unblock dependency handoffs before retrying this run."
|
|
187
|
+
: template.failureDecision,
|
|
188
|
+
],
|
|
189
|
+
followUps: [
|
|
190
|
+
{
|
|
191
|
+
title: template.failureFollowUpTitle,
|
|
192
|
+
priority: "p0",
|
|
193
|
+
reason: domain === "general"
|
|
194
|
+
? errorMessage
|
|
195
|
+
: `${template.failureFollowUpReason} Error: ${errorMessage}`,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// LLM-powered retro generation (falls back to heuristic template above)
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
const RETRO_SYSTEM_PROMPT = `You generate structured retrospectives for autonomous agent runs. Given the run context, produce a JSON object with these fields: domain (one of: engineering, product, design, marketing, sales, operations, orchestration, general), summary (1 sentence), whatWentWell (1-3 specific items), whatWentWrong (0-3 items, empty if success), decisions (1-2 actionable items), followUps (0-2 items, each with title, priority p0/p1/p2, and reason). Be specific to what actually happened — avoid generic template language.`;
|
|
204
|
+
const VALID_DOMAINS = new Set([
|
|
205
|
+
"engineering",
|
|
206
|
+
"product",
|
|
207
|
+
"design",
|
|
208
|
+
"marketing",
|
|
209
|
+
"sales",
|
|
210
|
+
"operations",
|
|
211
|
+
"orchestration",
|
|
212
|
+
"general",
|
|
213
|
+
]);
|
|
214
|
+
const VALID_PRIORITIES = new Set(["p0", "p1", "p2"]);
|
|
215
|
+
/**
|
|
216
|
+
* Generate a structured retro using an LLM, falling back to the heuristic
|
|
217
|
+
* template produced by {@link buildRetroTemplateForAgent}.
|
|
218
|
+
*
|
|
219
|
+
* Caller: src/index.ts (~line 971) — `buildRetroTemplateForAgent` is invoked
|
|
220
|
+
* inside the session-stopped handler. Migrate that call site to use this
|
|
221
|
+
* function when ready to enable LLM-powered retros.
|
|
222
|
+
*/
|
|
223
|
+
export async function buildRetroWithLlm(input) {
|
|
224
|
+
const lines = [
|
|
225
|
+
`Agent ID: ${input.agentId ?? "(unknown)"}`,
|
|
226
|
+
`Outcome: ${input.success ? "success" : "failure"}`,
|
|
227
|
+
`Task ID: ${input.taskId ?? "(none)"}`,
|
|
228
|
+
`Run ID: ${input.runId}`,
|
|
229
|
+
];
|
|
230
|
+
if (input.errorMessage) {
|
|
231
|
+
lines.push(`Error: ${input.errorMessage}`);
|
|
232
|
+
}
|
|
233
|
+
if (input.executionContext) {
|
|
234
|
+
lines.push(`Execution context: ${input.executionContext}`);
|
|
235
|
+
}
|
|
236
|
+
const userPrompt = lines.join("\n");
|
|
237
|
+
function parseRetroJson(raw) {
|
|
238
|
+
try {
|
|
239
|
+
const obj = JSON.parse(raw);
|
|
240
|
+
if (typeof obj.domain !== "string" || !VALID_DOMAINS.has(obj.domain))
|
|
241
|
+
return null;
|
|
242
|
+
if (typeof obj.summary !== "string" || obj.summary.length === 0)
|
|
243
|
+
return null;
|
|
244
|
+
if (!Array.isArray(obj.whatWentWell) || !obj.whatWentWell.every((v) => typeof v === "string"))
|
|
245
|
+
return null;
|
|
246
|
+
if (!Array.isArray(obj.whatWentWrong) || !obj.whatWentWrong.every((v) => typeof v === "string"))
|
|
247
|
+
return null;
|
|
248
|
+
if (!Array.isArray(obj.decisions) || !obj.decisions.every((v) => typeof v === "string"))
|
|
249
|
+
return null;
|
|
250
|
+
if (!Array.isArray(obj.followUps))
|
|
251
|
+
return null;
|
|
252
|
+
const followUps = [];
|
|
253
|
+
for (const fu of obj.followUps) {
|
|
254
|
+
if (!fu || typeof fu !== "object")
|
|
255
|
+
return null;
|
|
256
|
+
const rec = fu;
|
|
257
|
+
if (typeof rec.title !== "string" || rec.title.length === 0)
|
|
258
|
+
return null;
|
|
259
|
+
const entry = { title: rec.title };
|
|
260
|
+
if (typeof rec.priority === "string" && VALID_PRIORITIES.has(rec.priority)) {
|
|
261
|
+
entry.priority = rec.priority;
|
|
262
|
+
}
|
|
263
|
+
if (typeof rec.reason === "string") {
|
|
264
|
+
entry.reason = rec.reason;
|
|
265
|
+
}
|
|
266
|
+
followUps.push(entry);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
domain: obj.domain,
|
|
270
|
+
summary: obj.summary,
|
|
271
|
+
whatWentWell: obj.whatWentWell,
|
|
272
|
+
whatWentWrong: obj.whatWentWrong,
|
|
273
|
+
decisions: obj.decisions,
|
|
274
|
+
followUps,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function heuristicFallback() {
|
|
282
|
+
return buildRetroTemplateForAgent(input);
|
|
283
|
+
}
|
|
284
|
+
const response = await callLlmJson({
|
|
285
|
+
taskId: "retro",
|
|
286
|
+
systemPrompt: RETRO_SYSTEM_PROMPT,
|
|
287
|
+
userPrompt,
|
|
288
|
+
model: "openai/gpt-4.1-mini",
|
|
289
|
+
maxTokens: 512,
|
|
290
|
+
temperature: 0.2,
|
|
291
|
+
cacheTtlMs: 6 * 60 * 60_000, // 6 hours
|
|
292
|
+
}, parseRetroJson, heuristicFallback);
|
|
293
|
+
return {
|
|
294
|
+
...response.result,
|
|
295
|
+
source: response.source,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { OrgxAgentDomain } from "../contracts/types.js";
|
|
2
|
+
export type RetroQualityRubricInput = {
|
|
3
|
+
success: boolean;
|
|
4
|
+
hadError: boolean;
|
|
5
|
+
errorMessage?: string | null;
|
|
6
|
+
tokens?: number | null;
|
|
7
|
+
costUsd?: number | null;
|
|
8
|
+
decisionsCount?: number;
|
|
9
|
+
followUpsCount?: number;
|
|
10
|
+
whatWentWrongCount?: number;
|
|
11
|
+
/** Agent domain for domain-specific scoring modifiers */
|
|
12
|
+
domain?: OrgxAgentDomain | null;
|
|
13
|
+
/** Artifact metadata from the registered atomic unit */
|
|
14
|
+
artifactMetadata?: Record<string, unknown> | null;
|
|
15
|
+
};
|
|
16
|
+
export type RetroQualityRubricResult = {
|
|
17
|
+
score: number;
|
|
18
|
+
reasons: string[];
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Compute domain-specific quality modifier based on artifact metadata.
|
|
22
|
+
* Returns delta (positive = bonus, negative = penalty) and reasons.
|
|
23
|
+
*/
|
|
24
|
+
export declare function computeDomainQualityModifier(domain: OrgxAgentDomain | null | undefined, artifactMetadata: Record<string, unknown> | null | undefined): {
|
|
25
|
+
delta: number;
|
|
26
|
+
reasons: string[];
|
|
27
|
+
};
|
|
28
|
+
export declare function computeRetroQualityRubricScore(input: RetroQualityRubricInput): RetroQualityRubricResult;
|
|
29
|
+
export declare function computeRetroQualityWithLlm(input: RetroQualityRubricInput & {
|
|
30
|
+
executionContext?: string | null;
|
|
31
|
+
}): Promise<RetroQualityRubricResult & {
|
|
32
|
+
source: "llm" | "heuristic";
|
|
33
|
+
}>;
|