@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
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { callLlmJson } from "../http/helpers/llm-client.js";
|
|
2
|
+
const VALID_DOMAINS = new Set([
|
|
3
|
+
"engineering",
|
|
4
|
+
"product",
|
|
5
|
+
"design",
|
|
6
|
+
"marketing",
|
|
7
|
+
"sales",
|
|
8
|
+
"operations",
|
|
9
|
+
]);
|
|
10
|
+
function heuristicDomainGuess(title, summary) {
|
|
11
|
+
const haystack = `${title} ${summary ?? ""}`.toLowerCase();
|
|
12
|
+
if (/market|campaign|thread|article|tweet|copy/.test(haystack))
|
|
13
|
+
return ["marketing"];
|
|
14
|
+
if (/design|ux|ui|a11y/.test(haystack))
|
|
15
|
+
return ["design"];
|
|
16
|
+
if (/ops|runbook|incident|reliability/.test(haystack))
|
|
17
|
+
return ["operations"];
|
|
18
|
+
if (/sales|deal|pipeline/.test(haystack))
|
|
19
|
+
return ["sales"];
|
|
20
|
+
return ["engineering", "product"];
|
|
21
|
+
}
|
|
22
|
+
export async function autoAssignEntityForCreate(input) {
|
|
23
|
+
const warnings = [];
|
|
24
|
+
const byKey = new Map();
|
|
25
|
+
const addAgent = (agent) => {
|
|
26
|
+
const key = `${agent.id}:${agent.name}`.toLowerCase();
|
|
27
|
+
if (!byKey.has(key))
|
|
28
|
+
byKey.set(key, agent);
|
|
29
|
+
};
|
|
30
|
+
let liveAgents = [];
|
|
31
|
+
try {
|
|
32
|
+
const agentResp = await input.client.getLiveAgents({
|
|
33
|
+
initiative: input.initiativeId,
|
|
34
|
+
includeIdle: true,
|
|
35
|
+
});
|
|
36
|
+
liveAgents = (Array.isArray(agentResp.agents) ? agentResp.agents : [])
|
|
37
|
+
.map((raw) => {
|
|
38
|
+
if (!raw || typeof raw !== "object")
|
|
39
|
+
return null;
|
|
40
|
+
const record = raw;
|
|
41
|
+
const id = (typeof record.id === "string" && record.id.trim()) ||
|
|
42
|
+
(typeof record.agentId === "string" && record.agentId.trim()) ||
|
|
43
|
+
"";
|
|
44
|
+
const name = (typeof record.name === "string" && record.name.trim()) ||
|
|
45
|
+
(typeof record.agentName === "string" && record.agentName.trim()) ||
|
|
46
|
+
id;
|
|
47
|
+
if (!name)
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
id: id || `name:${name}`,
|
|
51
|
+
name,
|
|
52
|
+
domain: (typeof record.domain === "string" && record.domain.trim()) ||
|
|
53
|
+
(typeof record.role === "string" && record.role.trim()) ||
|
|
54
|
+
null,
|
|
55
|
+
status: (typeof record.status === "string" && record.status.trim()) || null,
|
|
56
|
+
};
|
|
57
|
+
})
|
|
58
|
+
.filter((agent) => agent !== null);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
warnings.push(`live agents unavailable (${input.toErrorMessage(err)})`);
|
|
62
|
+
}
|
|
63
|
+
const orchestrator = liveAgents.find((agent) => /holt|orchestrator/i.test(agent.name) ||
|
|
64
|
+
/orchestrator/i.test(agent.domain ?? ""));
|
|
65
|
+
if (orchestrator)
|
|
66
|
+
addAgent(orchestrator);
|
|
67
|
+
let assignmentSource = "fallback";
|
|
68
|
+
try {
|
|
69
|
+
const preflight = await input.client.delegationPreflight({
|
|
70
|
+
intent: `${input.title}${input.summary ? `: ${input.summary}` : ""}`,
|
|
71
|
+
});
|
|
72
|
+
const recommendations = preflight.data?.recommended_split ?? [];
|
|
73
|
+
const recommendedDomains = [
|
|
74
|
+
...new Set(recommendations
|
|
75
|
+
.map((entry) => String(entry.owner_domain ?? "").trim().toLowerCase())
|
|
76
|
+
.filter(Boolean)),
|
|
77
|
+
];
|
|
78
|
+
for (const domain of recommendedDomains) {
|
|
79
|
+
const match = liveAgents.find((agent) => (agent.domain ?? "").toLowerCase().includes(domain));
|
|
80
|
+
if (match)
|
|
81
|
+
addAgent(match);
|
|
82
|
+
}
|
|
83
|
+
if (recommendedDomains.length > 0) {
|
|
84
|
+
assignmentSource = "orchestrator";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
warnings.push(`delegation preflight failed (${input.toErrorMessage(err)})`);
|
|
89
|
+
}
|
|
90
|
+
if (byKey.size === 0) {
|
|
91
|
+
const domainResult = await callLlmJson({
|
|
92
|
+
taskId: "domain_assignment",
|
|
93
|
+
systemPrompt: 'Classify which agent domain(s) should handle this task. Return JSON: {"domains": [...]} with 1-2 values from: engineering, product, design, marketing, sales, operations. Be precise based on the task content.',
|
|
94
|
+
userPrompt: `Task: ${input.title}\n${input.summary ? `Details: ${input.summary}` : ""}`,
|
|
95
|
+
maxTokens: 64,
|
|
96
|
+
temperature: 0.1,
|
|
97
|
+
cacheTtlMs: 60 * 60_000, // 1 hour
|
|
98
|
+
}, (raw) => {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(raw);
|
|
101
|
+
if (Array.isArray(parsed.domains) &&
|
|
102
|
+
parsed.domains.length > 0 &&
|
|
103
|
+
parsed.domains.every((d) => typeof d === "string" && VALID_DOMAINS.has(d))) {
|
|
104
|
+
return { domains: parsed.domains };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// fall through
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}, () => ({ domains: heuristicDomainGuess(input.title, input.summary ?? null) }));
|
|
112
|
+
const domainHints = domainResult.result.domains;
|
|
113
|
+
for (const domain of domainHints) {
|
|
114
|
+
const match = liveAgents.find((agent) => (agent.domain ?? "").toLowerCase().includes(domain));
|
|
115
|
+
if (match)
|
|
116
|
+
addAgent(match);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (byKey.size === 0 && liveAgents.length > 0) {
|
|
120
|
+
addAgent(liveAgents[0]);
|
|
121
|
+
warnings.push("fallback selected first available live agent");
|
|
122
|
+
}
|
|
123
|
+
const assignedAgents = Array.from(byKey.values());
|
|
124
|
+
let updatedEntity = null;
|
|
125
|
+
try {
|
|
126
|
+
updatedEntity = (await input.client.updateEntity(input.entityType, input.entityId, {
|
|
127
|
+
assigned_agent_ids: assignedAgents.map((agent) => agent.id),
|
|
128
|
+
assigned_agent_names: assignedAgents.map((agent) => agent.name),
|
|
129
|
+
assignment_source: assignmentSource,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
warnings.push(`assignment update failed (${input.toErrorMessage(err)})`);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
assignmentSource,
|
|
137
|
+
assignedAgents,
|
|
138
|
+
warnings,
|
|
139
|
+
updatedEntity,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, } from "node:fs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { getOrgxPluginConfigDir, getOrgxPluginConfigPath } from "./paths.js";
|
|
4
4
|
import { backupCorruptFileSync, writeJsonFileAtomicSync } from "./fs-utils.js";
|
|
5
|
+
import { clearStoreFileSync, ensureStoreDirSync, parseJsonSafe, } from "./stores/json-store.js";
|
|
5
6
|
const MAX_COMMENTS_PER_ENTITY = 240;
|
|
6
7
|
const MAX_TOTAL_COMMENTS = 1_500;
|
|
7
8
|
function commentsDir() {
|
|
@@ -11,22 +12,7 @@ function commentsFile() {
|
|
|
11
12
|
return getOrgxPluginConfigPath("entity-comments.json");
|
|
12
13
|
}
|
|
13
14
|
function ensureDir() {
|
|
14
|
-
|
|
15
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
16
|
-
try {
|
|
17
|
-
chmodSync(dir, 0o700);
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
// best effort
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function parseJson(value) {
|
|
24
|
-
try {
|
|
25
|
-
return JSON.parse(value);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
15
|
+
ensureStoreDirSync(commentsDir());
|
|
30
16
|
}
|
|
31
17
|
function entityKey(entityType, entityId) {
|
|
32
18
|
return `${entityType.trim().toLowerCase()}:${entityId.trim()}`;
|
|
@@ -63,7 +49,7 @@ function readStore() {
|
|
|
63
49
|
return { updatedAt: new Date().toISOString(), commentsByEntity: {} };
|
|
64
50
|
}
|
|
65
51
|
const raw = readFileSync(file, "utf8");
|
|
66
|
-
const parsed =
|
|
52
|
+
const parsed = parseJsonSafe(raw);
|
|
67
53
|
if (!parsed || typeof parsed !== "object") {
|
|
68
54
|
backupCorruptFileSync(file);
|
|
69
55
|
return { updatedAt: new Date().toISOString(), commentsByEntity: {} };
|
|
@@ -180,11 +166,5 @@ export function mergeEntityComments(remote, local) {
|
|
|
180
166
|
return list;
|
|
181
167
|
}
|
|
182
168
|
export function clearEntityCommentsStore() {
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
rmSync(file, { force: true });
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// best effort
|
|
189
|
-
}
|
|
169
|
+
clearStoreFileSync(commentsFile());
|
|
190
170
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LiveActivityItem } from "./contracts/shared-types.js";
|
|
2
|
+
export declare function isUuid(value: string | null | undefined): boolean;
|
|
3
|
+
export declare function isSyntheticIdentifier(value: string | null | undefined): boolean;
|
|
4
|
+
type OutboxEventLike = {
|
|
5
|
+
type?: unknown;
|
|
6
|
+
payload?: unknown;
|
|
7
|
+
activityItem?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export declare function classifyOutboxReplaySkip(event: OutboxEventLike): string | null;
|
|
10
|
+
export declare function shouldHideActivityItem(item: LiveActivityItem): boolean;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
function toRecord(value) {
|
|
2
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
3
|
+
return null;
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
function pickString(input, ...keys) {
|
|
7
|
+
if (!input)
|
|
8
|
+
return null;
|
|
9
|
+
for (const key of keys) {
|
|
10
|
+
const value = input[key];
|
|
11
|
+
if (typeof value !== "string")
|
|
12
|
+
continue;
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
if (trimmed.length > 0)
|
|
15
|
+
return trimmed;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function pickBool(input, ...keys) {
|
|
20
|
+
if (!input)
|
|
21
|
+
return false;
|
|
22
|
+
for (const key of keys) {
|
|
23
|
+
if (input[key] === true)
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function containsMockMarker(value) {
|
|
29
|
+
if (!value)
|
|
30
|
+
return false;
|
|
31
|
+
const normalized = value.trim().toLowerCase();
|
|
32
|
+
if (!normalized)
|
|
33
|
+
return false;
|
|
34
|
+
// Match whole marker tokens and avoid substring false positives (e.g. "latest").
|
|
35
|
+
return /(^|[^a-z0-9])(mock|fixture|synthetic|test)([^a-z0-9]|$)/i.test(normalized);
|
|
36
|
+
}
|
|
37
|
+
export function isUuid(value) {
|
|
38
|
+
if (!value)
|
|
39
|
+
return false;
|
|
40
|
+
const trimmed = value.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return false;
|
|
43
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmed);
|
|
44
|
+
}
|
|
45
|
+
export function isSyntheticIdentifier(value) {
|
|
46
|
+
if (!value)
|
|
47
|
+
return false;
|
|
48
|
+
const trimmed = value.trim();
|
|
49
|
+
if (!trimmed)
|
|
50
|
+
return false;
|
|
51
|
+
if (isUuid(trimmed))
|
|
52
|
+
return false;
|
|
53
|
+
return /^(init|initiative|task|workstream|ws|milestone|ms|decision|artifact|demo|mock|test|sample|queue|tmp|local)-/i.test(trimmed);
|
|
54
|
+
}
|
|
55
|
+
function isMockTaggedMetadata(metadata) {
|
|
56
|
+
if (!metadata)
|
|
57
|
+
return false;
|
|
58
|
+
if (pickBool(metadata, "mock", "is_mock", "isMock"))
|
|
59
|
+
return true;
|
|
60
|
+
if (containsMockMarker(pickString(metadata, "source")) ||
|
|
61
|
+
containsMockMarker(pickString(metadata, "worker_kind", "workerKind")) ||
|
|
62
|
+
containsMockMarker(pickString(metadata, "environment"))) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
export function classifyOutboxReplaySkip(event) {
|
|
68
|
+
const eventType = typeof event.type === "string" ? event.type.trim().toLowerCase() : "";
|
|
69
|
+
const payload = toRecord(event.payload);
|
|
70
|
+
const activity = toRecord(event.activityItem);
|
|
71
|
+
const payloadMetadata = toRecord(payload?.metadata);
|
|
72
|
+
const activityMetadata = toRecord(activity?.metadata);
|
|
73
|
+
const normalizedSourceClient = pickString(payload, "source_client", "sourceClient")
|
|
74
|
+
?.trim()
|
|
75
|
+
.toLowerCase();
|
|
76
|
+
const normalizedPayloadEvent = pickString(payloadMetadata, "event")?.trim().toLowerCase();
|
|
77
|
+
const normalizedActivityEvent = pickString(activityMetadata, "event")?.trim().toLowerCase();
|
|
78
|
+
const skipMockOutboxReplay = String(process.env.ORGX_SKIP_MOCK_OUTBOX_REPLAY ?? "false")
|
|
79
|
+
.trim()
|
|
80
|
+
.toLowerCase() === "true";
|
|
81
|
+
if (skipMockOutboxReplay &&
|
|
82
|
+
(isMockTaggedMetadata(payloadMetadata) ||
|
|
83
|
+
isMockTaggedMetadata(activityMetadata) ||
|
|
84
|
+
pickBool(payload, "mock", "is_mock", "isMock"))) {
|
|
85
|
+
return "mock_event";
|
|
86
|
+
}
|
|
87
|
+
if (eventType === "artifact") {
|
|
88
|
+
const initiativeId = pickString(payload, "initiative_id", "initiativeId");
|
|
89
|
+
const entityId = pickString(payload, "entity_id", "entityId");
|
|
90
|
+
const allowSyntheticArtifact = normalizedSourceClient === "openclaw" ||
|
|
91
|
+
normalizedPayloadEvent === "autopilot_slice_artifact_buffered" ||
|
|
92
|
+
normalizedActivityEvent === "autopilot_slice_artifact_buffered";
|
|
93
|
+
if (!allowSyntheticArtifact && isSyntheticIdentifier(initiativeId)) {
|
|
94
|
+
return "synthetic_initiative_id";
|
|
95
|
+
}
|
|
96
|
+
if (!allowSyntheticArtifact && !entityId) {
|
|
97
|
+
return "missing_artifact_entity_id";
|
|
98
|
+
}
|
|
99
|
+
if (!allowSyntheticArtifact && isSyntheticIdentifier(entityId)) {
|
|
100
|
+
return "synthetic_artifact_entity_id";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
export function shouldHideActivityItem(item) {
|
|
106
|
+
const metadata = toRecord(item.metadata);
|
|
107
|
+
const hideMockActivity = String(process.env.ORGX_HIDE_MOCK_ACTIVITY ?? "false")
|
|
108
|
+
.trim()
|
|
109
|
+
.toLowerCase() === "true";
|
|
110
|
+
if (hideMockActivity && isMockTaggedMetadata(metadata))
|
|
111
|
+
return true;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
package/dist/fs-utils.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { chmodSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
function isSafeFilePath(path) {
|
|
4
|
+
if (!path)
|
|
5
|
+
return false;
|
|
6
|
+
if (/[\u0000-\u001f\u007f]/.test(path))
|
|
7
|
+
return false;
|
|
8
|
+
if (/\\0|\\x00|\\u0000|%00/i.test(path))
|
|
9
|
+
return false;
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
3
12
|
function hardenPath(path, mode) {
|
|
4
13
|
try {
|
|
5
14
|
chmodSync(path, mode);
|
|
@@ -9,7 +18,7 @@ function hardenPath(path, mode) {
|
|
|
9
18
|
}
|
|
10
19
|
}
|
|
11
20
|
export function backupCorruptFileSync(targetPath) {
|
|
12
|
-
if (!targetPath
|
|
21
|
+
if (!isSafeFilePath(targetPath))
|
|
13
22
|
return null;
|
|
14
23
|
const suffix = `${Date.now()}-${randomUUID().slice(0, 8)}`;
|
|
15
24
|
const backupPath = `${targetPath}.corrupt.${suffix}`;
|
|
@@ -23,6 +32,9 @@ export function backupCorruptFileSync(targetPath) {
|
|
|
23
32
|
}
|
|
24
33
|
}
|
|
25
34
|
export function writeFileAtomicSync(targetPath, content, options) {
|
|
35
|
+
if (!isSafeFilePath(targetPath)) {
|
|
36
|
+
throw new TypeError("targetPath must be a safe, non-empty file path");
|
|
37
|
+
}
|
|
26
38
|
const mode = options?.mode ?? 0o600;
|
|
27
39
|
const encoding = options?.encoding ?? "utf8";
|
|
28
40
|
const tmpPath = `${targetPath}.tmp.${process.pid}.${randomUUID().slice(0, 8)}`;
|
|
@@ -8,4 +8,9 @@ export declare function ensureGatewayWatchdog(logger: Logger): {
|
|
|
8
8
|
started: boolean;
|
|
9
9
|
pid: number | null;
|
|
10
10
|
};
|
|
11
|
+
export declare function stopGatewayWatchdog(logger?: Logger, timeoutMs?: number): Promise<{
|
|
12
|
+
pid: number | null;
|
|
13
|
+
wasRunning: boolean;
|
|
14
|
+
stopped: boolean;
|
|
15
|
+
}>;
|
|
11
16
|
export {};
|
package/dist/gateway-watchdog.js
CHANGED
|
@@ -8,6 +8,31 @@ const DEFAULT_MONITOR_INTERVAL_MS = 30_000;
|
|
|
8
8
|
const DEFAULT_FAILURES_BEFORE_RESTART = 2;
|
|
9
9
|
const DEFAULT_PROBE_TIMEOUT_MS = 2_500;
|
|
10
10
|
const WATCHDOG_PID_FILE = join(getOpenClawDir(), "orgx-gateway-watchdog.pid");
|
|
11
|
+
function sendSignal(pid, signal) {
|
|
12
|
+
try {
|
|
13
|
+
// Detached child uses its own process group on Unix.
|
|
14
|
+
process.kill(-pid, signal);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Fall through to direct pid kill.
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
process.kill(pid, signal);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// best effort
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function waitForExit(pid, timeoutMs) {
|
|
28
|
+
const deadline = Date.now() + Math.max(100, timeoutMs);
|
|
29
|
+
while (Date.now() < deadline) {
|
|
30
|
+
if (!isPidAlive(pid))
|
|
31
|
+
return true;
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
33
|
+
}
|
|
34
|
+
return !isPidAlive(pid);
|
|
35
|
+
}
|
|
11
36
|
function readEnvNumber(name, fallback, min) {
|
|
12
37
|
const raw = (process.env[name] ?? "").trim();
|
|
13
38
|
if (!raw)
|
|
@@ -219,3 +244,28 @@ export function ensureGatewayWatchdog(logger) {
|
|
|
219
244
|
child.unref();
|
|
220
245
|
return { started: true, pid: child.pid ?? null };
|
|
221
246
|
}
|
|
247
|
+
export async function stopGatewayWatchdog(logger = console, timeoutMs = 1_500) {
|
|
248
|
+
const pid = readWatchdogPid();
|
|
249
|
+
if (!pid) {
|
|
250
|
+
clearWatchdogPid();
|
|
251
|
+
return { pid: null, wasRunning: false, stopped: true };
|
|
252
|
+
}
|
|
253
|
+
if (!isPidAlive(pid)) {
|
|
254
|
+
clearWatchdogPid();
|
|
255
|
+
return { pid, wasRunning: false, stopped: true };
|
|
256
|
+
}
|
|
257
|
+
sendSignal(pid, "SIGTERM");
|
|
258
|
+
let stopped = await waitForExit(pid, timeoutMs);
|
|
259
|
+
if (!stopped) {
|
|
260
|
+
sendSignal(pid, "SIGKILL");
|
|
261
|
+
stopped = await waitForExit(pid, 500);
|
|
262
|
+
}
|
|
263
|
+
if (stopped) {
|
|
264
|
+
clearWatchdogPid();
|
|
265
|
+
logger.info?.("[orgx] Gateway watchdog stopped", { pid });
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
logger.warn?.("[orgx] Gateway watchdog did not exit after stop attempt", { pid });
|
|
269
|
+
}
|
|
270
|
+
return { pid, wasRunning: true, stopped };
|
|
271
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export function stableHash(value) {
|
|
3
|
+
return createHash("sha256").update(value).digest("hex");
|
|
4
|
+
}
|
|
5
|
+
export function idempotencyKey(parts) {
|
|
6
|
+
const raw = parts
|
|
7
|
+
.filter((part) => typeof part === "string" && part.length > 0)
|
|
8
|
+
.join(":");
|
|
9
|
+
const cleaned = raw.replace(/[^a-zA-Z0-9:_-]/g, "-").slice(0, 84);
|
|
10
|
+
const suffix = stableHash(raw).slice(0, 20);
|
|
11
|
+
return `${cleaned}:${suffix}`.slice(0, 120);
|
|
12
|
+
}
|
|
@@ -168,11 +168,7 @@ export async function main({
|
|
|
168
168
|
const runId = pickString(args.run_id, env.ORGX_RUN_ID);
|
|
169
169
|
const correlationId = runId
|
|
170
170
|
? undefined
|
|
171
|
-
: pickString(
|
|
172
|
-
args.correlation_id,
|
|
173
|
-
env.ORGX_CORRELATION_ID,
|
|
174
|
-
`hook-${now()}`
|
|
175
|
-
);
|
|
171
|
+
: pickString(args.correlation_id, env.ORGX_CORRELATION_ID);
|
|
176
172
|
|
|
177
173
|
const event = pickString(args.event, "hook_event");
|
|
178
174
|
const phase = pickString(args.phase, "execution");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ActivityHeadlineSource = "llm" | "heuristic";
|
|
2
|
+
export declare function summarizeActivityHeadline(input: {
|
|
3
|
+
text: string;
|
|
4
|
+
title?: string | null;
|
|
5
|
+
type?: string | null;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
headline: string;
|
|
8
|
+
source: ActivityHeadlineSource;
|
|
9
|
+
model: string | null;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { callLlm } from "./llm-client.js";
|
|
2
|
+
const ACTIVITY_HEADLINE_MAX_INPUT_CHARS = 8_000;
|
|
3
|
+
const DEFAULT_ACTIVITY_HEADLINE_MODEL = "openai/gpt-4.1-nano";
|
|
4
|
+
function normalizeSpaces(value) {
|
|
5
|
+
return value.replace(/\s+/g, " ").trim();
|
|
6
|
+
}
|
|
7
|
+
function stripMarkdownLite(value) {
|
|
8
|
+
return value
|
|
9
|
+
.replace(/```[\s\S]*?```/g, " ")
|
|
10
|
+
.replace(/`([^`]+)`/g, "$1")
|
|
11
|
+
.replace(/\*\*([^*]+)\*\*/g, "$1")
|
|
12
|
+
.replace(/__([^_]+)__/g, "$1")
|
|
13
|
+
.replace(/\*([^*\n]+)\*/g, "$1")
|
|
14
|
+
.replace(/_([^_\n]+)_/g, "$1")
|
|
15
|
+
.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, "$1")
|
|
16
|
+
.replace(/^\s{0,3}#{1,6}\s+/gm, "")
|
|
17
|
+
.replace(/^\s*[-*]\s+/gm, "")
|
|
18
|
+
.replace(/^\s*\d+\.\s+/gm, "")
|
|
19
|
+
.replace(/\r\n/g, "\n")
|
|
20
|
+
.trim();
|
|
21
|
+
}
|
|
22
|
+
function cleanActivityHeadline(value) {
|
|
23
|
+
const lines = stripMarkdownLite(value)
|
|
24
|
+
.split("\n")
|
|
25
|
+
.map((line) => normalizeSpaces(line))
|
|
26
|
+
.filter((line) => line.length > 0 && !/^\|?[:\-| ]+\|?$/.test(line));
|
|
27
|
+
const headline = lines[0] ?? "";
|
|
28
|
+
if (!headline)
|
|
29
|
+
return "";
|
|
30
|
+
if (headline.length <= 108)
|
|
31
|
+
return headline;
|
|
32
|
+
return `${headline.slice(0, 107).trimEnd()}…`;
|
|
33
|
+
}
|
|
34
|
+
function heuristicActivityHeadline(text, title) {
|
|
35
|
+
const cleanedText = cleanActivityHeadline(text);
|
|
36
|
+
if (cleanedText.length > 0)
|
|
37
|
+
return cleanedText;
|
|
38
|
+
const cleanedTitle = cleanActivityHeadline(title ?? "");
|
|
39
|
+
if (cleanedTitle.length > 0)
|
|
40
|
+
return cleanedTitle;
|
|
41
|
+
return "Activity update";
|
|
42
|
+
}
|
|
43
|
+
export async function summarizeActivityHeadline(input) {
|
|
44
|
+
const normalizedText = normalizeSpaces(input.text).slice(0, ACTIVITY_HEADLINE_MAX_INPUT_CHARS);
|
|
45
|
+
const normalizedTitle = normalizeSpaces(input.title ?? "");
|
|
46
|
+
const normalizedType = normalizeSpaces(input.type ?? "");
|
|
47
|
+
const userPrompt = [
|
|
48
|
+
"Create one short activity title for a dashboard header.",
|
|
49
|
+
"Rules:",
|
|
50
|
+
"- Max 96 characters.",
|
|
51
|
+
"- Keep key numbers/status markers (for example: 15 tasks, 0 blocked).",
|
|
52
|
+
"- No markdown, no quotes, no trailing period unless needed.",
|
|
53
|
+
"- Prefer plain language over jargon.",
|
|
54
|
+
"",
|
|
55
|
+
`Type: ${normalizedType || "activity"}`,
|
|
56
|
+
normalizedTitle ? `Current title: ${normalizedTitle}` : "",
|
|
57
|
+
"Full detail:",
|
|
58
|
+
normalizedText,
|
|
59
|
+
]
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.join("\n");
|
|
62
|
+
const model = process.env.ORGX_ACTIVITY_SUMMARY_MODEL?.trim() || DEFAULT_ACTIVITY_HEADLINE_MODEL;
|
|
63
|
+
const response = await callLlm({
|
|
64
|
+
taskId: "activity_headline",
|
|
65
|
+
systemPrompt: "You write concise activity headers for operational dashboards. Return only the header text.",
|
|
66
|
+
userPrompt,
|
|
67
|
+
model,
|
|
68
|
+
temperature: 0.1,
|
|
69
|
+
maxTokens: 48,
|
|
70
|
+
timeoutMs: 4_000,
|
|
71
|
+
}, () => heuristicActivityHeadline(normalizedText, normalizedTitle), (raw) => cleanActivityHeadline(raw) || null);
|
|
72
|
+
return { headline: response.result, source: response.source, model: response.model };
|
|
73
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LiveActivityItem } from "../../types.js";
|
|
2
|
+
type ListActivityPageResult = {
|
|
3
|
+
activities: LiveActivityItem[];
|
|
4
|
+
nextCursor: string | null;
|
|
5
|
+
};
|
|
6
|
+
type BuildArtifactFallbackDeps = {
|
|
7
|
+
listActivityPage: (input: {
|
|
8
|
+
limit: number;
|
|
9
|
+
cursor: string | null;
|
|
10
|
+
}) => ListActivityPageResult;
|
|
11
|
+
};
|
|
12
|
+
export declare function createLocalArtifactDetailFallbackBuilder(deps: BuildArtifactFallbackDeps): (artifactId: string, warning: string) => Record<string, unknown> | null;
|
|
13
|
+
export {};
|