@haaaiawd/second-nature 0.1.16 → 0.1.18
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/index.js +855 -851
- package/openclaw.plugin.json +29 -29
- package/package.json +52 -52
- package/runtime/cli/commands/index.d.ts +14 -14
- package/runtime/cli/commands/index.js +193 -193
- package/runtime/cli/explain/explain-surface-subject.d.ts +8 -8
- package/runtime/cli/explain/explain-surface-subject.js +9 -9
- package/runtime/cli/explain/format-explanation.d.ts +12 -12
- package/runtime/cli/explain/format-explanation.js +12 -12
- package/runtime/cli/explain/resolve-subject.js +41 -41
- package/runtime/cli/host-capability/classify-delivery.d.ts +14 -14
- package/runtime/cli/host-capability/classify-delivery.js +20 -20
- package/runtime/cli/host-capability/probe-host-capability.d.ts +2 -2
- package/runtime/cli/host-capability/probe-host-capability.js +58 -58
- package/runtime/cli/host-capability/record-host-capability.d.ts +6 -6
- package/runtime/cli/host-capability/record-host-capability.js +14 -14
- package/runtime/cli/host-capability/types.d.ts +71 -71
- package/runtime/cli/host-capability/types.js +6 -6
- package/runtime/cli/host-smoke/run-host-smoke.d.ts +2 -2
- package/runtime/cli/host-smoke/run-host-smoke.js +40 -40
- package/runtime/cli/host-smoke/types.d.ts +35 -35
- package/runtime/cli/host-smoke/types.js +6 -6
- package/runtime/cli/index.js +58 -54
- package/runtime/cli/ops/heartbeat-surface.d.ts +38 -35
- package/runtime/cli/ops/heartbeat-surface.js +73 -71
- package/runtime/cli/ops/ops-router.d.ts +19 -16
- package/runtime/cli/ops/ops-router.js +89 -87
- package/runtime/cli/ops/show-operator-fallback.d.ts +13 -13
- package/runtime/cli/ops/show-operator-fallback.js +22 -22
- package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +19 -10
- package/runtime/cli/ops/workspace-heartbeat-runner.js +39 -26
- package/runtime/cli/read-models/index.d.ts +29 -29
- package/runtime/cli/read-models/index.js +256 -256
- package/runtime/cli/read-models/operator-explain-map.d.ts +6 -6
- package/runtime/cli/read-models/operator-explain-map.js +10 -10
- package/runtime/cli/read-models/types.d.ts +79 -79
- package/runtime/cli/runtime/runtime-artifact-boundary.d.ts +28 -28
- package/runtime/cli/runtime/runtime-artifact-boundary.js +94 -94
- package/runtime/connectors/base/contract.d.ts +87 -87
- package/runtime/connectors/base/execution-policy.d.ts +47 -47
- package/runtime/connectors/base/execution-policy.js +82 -82
- package/runtime/connectors/base/index.d.ts +8 -8
- package/runtime/connectors/base/index.js +8 -8
- package/runtime/connectors/base/manifest.d.ts +64 -64
- package/runtime/connectors/base/manifest.js +86 -86
- package/runtime/connectors/base/map-life-evidence.d.ts +16 -16
- package/runtime/connectors/base/map-life-evidence.js +79 -79
- package/runtime/connectors/base/policy-layer.d.ts +29 -29
- package/runtime/connectors/base/policy-layer.js +198 -198
- package/runtime/connectors/base/route-planner.js +99 -99
- package/runtime/connectors/index.d.ts +5 -5
- package/runtime/connectors/index.js +5 -5
- package/runtime/connectors/near-real/near-real-connector-smoke.d.ts +19 -19
- package/runtime/connectors/near-real/near-real-connector-smoke.js +152 -152
- package/runtime/core/second-nature/heartbeat/heartbeat-executor.js +114 -114
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +63 -63
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +139 -139
- package/runtime/core/second-nature/heartbeat/index.d.ts +8 -8
- package/runtime/core/second-nature/heartbeat/index.js +7 -7
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.d.ts +21 -21
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.js +35 -35
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +28 -28
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.js +35 -35
- package/runtime/core/second-nature/heartbeat/signal.d.ts +42 -42
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +51 -51
- package/runtime/core/second-nature/index.d.ts +22 -22
- package/runtime/core/second-nature/index.js +22 -22
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +100 -100
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +144 -144
- package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +8 -8
- package/runtime/core/second-nature/orchestrator/guard-layer.js +110 -110
- package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +13 -13
- package/runtime/core/second-nature/orchestrator/intent-planner.js +199 -199
- package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +14 -14
- package/runtime/core/second-nature/orchestrator/lease-manager.js +58 -58
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.d.ts +6 -6
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +63 -63
- package/runtime/core/second-nature/outreach/delivery-target.d.ts +26 -26
- package/runtime/core/second-nature/outreach/delivery-target.js +70 -70
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +38 -38
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +119 -119
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.d.ts +7 -7
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +45 -45
- package/runtime/core/second-nature/outreach/judge-outreach.d.ts +40 -40
- package/runtime/core/second-nature/outreach/judge-outreach.js +121 -121
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.d.ts +21 -21
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +123 -123
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.d.ts +15 -15
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.js +52 -52
- package/runtime/core/second-nature/rhythm/policy-bridge.d.ts +19 -19
- package/runtime/core/second-nature/rhythm/policy-bridge.js +34 -34
- package/runtime/core/second-nature/runtime/service-entry.js +45 -45
- package/runtime/core/second-nature/types.d.ts +51 -51
- package/runtime/guidance/draft-outreach-message.d.ts +7 -7
- package/runtime/guidance/draft-outreach-message.js +42 -42
- package/runtime/guidance/evidence-guidance.d.ts +40 -40
- package/runtime/guidance/evidence-guidance.js +52 -52
- package/runtime/guidance/index.d.ts +11 -11
- package/runtime/guidance/index.js +11 -11
- package/runtime/guidance/outreach-draft-schema.d.ts +228 -228
- package/runtime/guidance/outreach-draft-schema.js +80 -80
- package/runtime/observability/audit/append-only-audit-store.d.ts +14 -14
- package/runtime/observability/audit/append-only-audit-store.js +21 -21
- package/runtime/observability/audit/audit-envelope.d.ts +51 -51
- package/runtime/observability/audit/audit-envelope.js +130 -130
- package/runtime/observability/audit/verify-audit-hash-chain.d.ts +23 -23
- package/runtime/observability/audit/verify-audit-hash-chain.js +83 -83
- package/runtime/observability/db/index.js +124 -124
- package/runtime/observability/db/schema/host-capability-reports.d.ts +180 -180
- package/runtime/observability/db/schema/host-capability-reports.js +12 -12
- package/runtime/observability/db/schema/index.d.ts +947 -947
- package/runtime/observability/db/schema/index.js +71 -71
- package/runtime/observability/index.d.ts +20 -19
- package/runtime/observability/index.js +19 -18
- package/runtime/observability/query/explain-query.d.ts +48 -48
- package/runtime/observability/query/explain-query.js +114 -114
- package/runtime/observability/query/export-audit-bundle.d.ts +22 -22
- package/runtime/observability/query/export-audit-bundle.js +27 -27
- package/runtime/observability/services/decision-ledger.d.ts +46 -46
- package/runtime/observability/services/decision-ledger.js +161 -161
- package/runtime/observability/services/governance-audit.d.ts +41 -41
- package/runtime/observability/services/governance-audit.js +163 -163
- package/runtime/observability/services/governance-plane-recorder.d.ts +47 -47
- package/runtime/observability/services/governance-plane-recorder.js +55 -55
- package/runtime/observability/services/lived-experience-audit.d.ts +97 -97
- package/runtime/observability/services/lived-experience-audit.js +162 -162
- package/runtime/observability/services/runtime-decision-recorder.d.ts +29 -0
- package/runtime/observability/services/runtime-decision-recorder.js +94 -0
- package/runtime/storage/bootstrap/native-sqlite-probe.d.ts +7 -7
- package/runtime/storage/bootstrap/native-sqlite-probe.js +28 -28
- package/runtime/storage/bootstrap/repair-gate.d.ts +17 -17
- package/runtime/storage/bootstrap/repair-gate.js +71 -71
- package/runtime/storage/bootstrap/storage-mode-smoke.d.ts +38 -38
- package/runtime/storage/bootstrap/storage-mode-smoke.js +85 -85
- package/runtime/storage/db/index.js +154 -154
- package/runtime/storage/db/schema/delivery-attempts.d.ts +199 -199
- package/runtime/storage/db/schema/delivery-attempts.js +13 -13
- package/runtime/storage/db/schema/index.d.ts +9 -9
- package/runtime/storage/db/schema/index.js +9 -9
- package/runtime/storage/db/schema/life-evidence-index.d.ts +161 -161
- package/runtime/storage/db/schema/life-evidence-index.js +11 -11
- package/runtime/storage/db/schema/operator-fallback-artifacts.d.ts +161 -161
- package/runtime/storage/db/schema/operator-fallback-artifacts.js +11 -11
- package/runtime/storage/db/schema/policies.d.ts +98 -98
- package/runtime/storage/db/schema/policies.js +8 -8
- package/runtime/storage/delivery/query-delivery-attempts.d.ts +3 -3
- package/runtime/storage/delivery/query-delivery-attempts.js +32 -32
- package/runtime/storage/delivery/types.d.ts +27 -27
- package/runtime/storage/delivery/types.js +1 -1
- package/runtime/storage/delivery/write-delivery-attempt.d.ts +6 -6
- package/runtime/storage/delivery/write-delivery-attempt.js +36 -36
- package/runtime/storage/fallback/load-operator-fallback.d.ts +14 -14
- package/runtime/storage/fallback/load-operator-fallback.js +47 -47
- package/runtime/storage/fallback/operator-fallback-types.d.ts +9 -9
- package/runtime/storage/fallback/operator-fallback-types.js +1 -1
- package/runtime/storage/fallback/operator-fallback-view.d.ts +11 -11
- package/runtime/storage/fallback/operator-fallback-view.js +1 -1
- package/runtime/storage/fallback/write-operator-fallback.d.ts +6 -6
- package/runtime/storage/fallback/write-operator-fallback.js +21 -21
- package/runtime/storage/index.d.ts +37 -37
- package/runtime/storage/index.js +30 -30
- package/runtime/storage/life-evidence/append-life-evidence.d.ts +7 -7
- package/runtime/storage/life-evidence/append-life-evidence.js +64 -64
- package/runtime/storage/life-evidence/types.d.ts +45 -45
- package/runtime/storage/life-evidence/types.js +6 -6
- package/runtime/storage/quiet/persist-quiet-artifact.d.ts +7 -7
- package/runtime/storage/quiet/persist-quiet-artifact.js +22 -22
- package/runtime/storage/quiet/quiet-artifact-types.d.ts +18 -18
- package/runtime/storage/quiet/quiet-artifact-types.js +1 -1
- package/runtime/storage/quiet/quiet-artifact-writer.d.ts +15 -15
- package/runtime/storage/quiet/quiet-artifact-writer.js +56 -56
- package/runtime/storage/repositories/credential-repository.js +30 -30
- package/runtime/storage/rhythm/rhythm-policy-snapshot.d.ts +10 -10
- package/runtime/storage/rhythm/rhythm-policy-snapshot.js +34 -34
- package/runtime/storage/services/credential-vault.d.ts +13 -13
- package/runtime/storage/services/credential-vault.js +116 -116
- package/runtime/storage/snapshots/continuity-snapshot.d.ts +9 -9
- package/runtime/storage/snapshots/continuity-snapshot.js +41 -41
- package/runtime/storage/snapshots/life-evidence-snapshot.d.ts +6 -6
- package/runtime/storage/snapshots/life-evidence-snapshot.js +114 -114
- package/runtime/storage/snapshots/types.d.ts +58 -58
- package/runtime/storage/snapshots/types.js +1 -1
- package/runtime/storage/state-api.js +104 -104
- package/runtime/storage/user-interest/load-user-interest-snapshot.d.ts +2 -2
- package/runtime/storage/user-interest/load-user-interest-snapshot.js +150 -150
- package/runtime/storage/user-interest/types.d.ts +25 -25
- package/runtime/storage/user-interest/types.js +1 -1
- package/workspace-ops-bridge.js +81 -80
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
function extractSourceRefs(platformId, data, observedAt) {
|
|
2
|
-
if (data && typeof data === "object") {
|
|
3
|
-
const record = data;
|
|
4
|
-
if (Array.isArray(record.sourceRefs)) {
|
|
5
|
-
const out = [];
|
|
6
|
-
for (const item of record.sourceRefs) {
|
|
7
|
-
if (item && typeof item === "object" && "uri" in item && "id" in item) {
|
|
8
|
-
const ref = item;
|
|
9
|
-
out.push({
|
|
10
|
-
id: String(ref.id),
|
|
11
|
-
kind: ref.kind ?? "platform_item",
|
|
12
|
-
uri: String(ref.uri),
|
|
13
|
-
excerptHash: ref.excerptHash !== undefined ? String(ref.excerptHash) : undefined,
|
|
14
|
-
observedAt: ref.observedAt !== undefined ? String(ref.observedAt) : observedAt,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
if (out.length > 0)
|
|
19
|
-
return out;
|
|
20
|
-
}
|
|
21
|
-
if (Array.isArray(record.items)) {
|
|
22
|
-
return record.items.map((item, index) => {
|
|
23
|
-
const id = item && typeof item === "object" && "id" in item
|
|
24
|
-
? String(item.id)
|
|
25
|
-
: `${platformId}-item-${index}`;
|
|
26
|
-
return {
|
|
27
|
-
id,
|
|
28
|
-
kind: "platform_item",
|
|
29
|
-
uri: `platform://${platformId}/item/${encodeURIComponent(id)}`,
|
|
30
|
-
observedAt,
|
|
31
|
-
};
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
function resolveEvidenceType(intent) {
|
|
38
|
-
if (intent === "feed.read")
|
|
39
|
-
return "platform_browse";
|
|
40
|
-
if (intent === "work.discover")
|
|
41
|
-
return "task_discovery";
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
function resolveSensitivity(intent, explicit) {
|
|
45
|
-
if (explicit)
|
|
46
|
-
return explicit;
|
|
47
|
-
if (intent === "message.send" || intent === "comment.reply")
|
|
48
|
-
return "private";
|
|
49
|
-
return "public";
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Produce a single life-evidence candidate from a connector outcome, or null if not mappable.
|
|
53
|
-
*/
|
|
54
|
-
export function mapLifeEvidence(input) {
|
|
55
|
-
if (input.result.status !== "success") {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
if (input.intent === "message.send") {
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
const evidenceType = resolveEvidenceType(input.intent);
|
|
62
|
-
if (!evidenceType) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
const observedAt = input.observedAt ?? new Date().toISOString();
|
|
66
|
-
const refs = extractSourceRefs(input.platformId, input.result.data, observedAt);
|
|
67
|
-
if (refs.length === 0) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
timestamp: observedAt,
|
|
72
|
-
evidenceType,
|
|
73
|
-
platformId: input.platformId,
|
|
74
|
-
summary: `${input.platformId}:${input.intent}`,
|
|
75
|
-
sourceRefs: refs,
|
|
76
|
-
sensitivity: resolveSensitivity(input.intent, input.sensitivityOverride),
|
|
77
|
-
producer: "connector-system",
|
|
78
|
-
};
|
|
79
|
-
}
|
|
1
|
+
function extractSourceRefs(platformId, data, observedAt) {
|
|
2
|
+
if (data && typeof data === "object") {
|
|
3
|
+
const record = data;
|
|
4
|
+
if (Array.isArray(record.sourceRefs)) {
|
|
5
|
+
const out = [];
|
|
6
|
+
for (const item of record.sourceRefs) {
|
|
7
|
+
if (item && typeof item === "object" && "uri" in item && "id" in item) {
|
|
8
|
+
const ref = item;
|
|
9
|
+
out.push({
|
|
10
|
+
id: String(ref.id),
|
|
11
|
+
kind: ref.kind ?? "platform_item",
|
|
12
|
+
uri: String(ref.uri),
|
|
13
|
+
excerptHash: ref.excerptHash !== undefined ? String(ref.excerptHash) : undefined,
|
|
14
|
+
observedAt: ref.observedAt !== undefined ? String(ref.observedAt) : observedAt,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (out.length > 0)
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(record.items)) {
|
|
22
|
+
return record.items.map((item, index) => {
|
|
23
|
+
const id = item && typeof item === "object" && "id" in item
|
|
24
|
+
? String(item.id)
|
|
25
|
+
: `${platformId}-item-${index}`;
|
|
26
|
+
return {
|
|
27
|
+
id,
|
|
28
|
+
kind: "platform_item",
|
|
29
|
+
uri: `platform://${platformId}/item/${encodeURIComponent(id)}`,
|
|
30
|
+
observedAt,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
function resolveEvidenceType(intent) {
|
|
38
|
+
if (intent === "feed.read")
|
|
39
|
+
return "platform_browse";
|
|
40
|
+
if (intent === "work.discover")
|
|
41
|
+
return "task_discovery";
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function resolveSensitivity(intent, explicit) {
|
|
45
|
+
if (explicit)
|
|
46
|
+
return explicit;
|
|
47
|
+
if (intent === "message.send" || intent === "comment.reply")
|
|
48
|
+
return "private";
|
|
49
|
+
return "public";
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Produce a single life-evidence candidate from a connector outcome, or null if not mappable.
|
|
53
|
+
*/
|
|
54
|
+
export function mapLifeEvidence(input) {
|
|
55
|
+
if (input.result.status !== "success") {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (input.intent === "message.send") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const evidenceType = resolveEvidenceType(input.intent);
|
|
62
|
+
if (!evidenceType) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const observedAt = input.observedAt ?? new Date().toISOString();
|
|
66
|
+
const refs = extractSourceRefs(input.platformId, input.result.data, observedAt);
|
|
67
|
+
if (refs.length === 0) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
timestamp: observedAt,
|
|
72
|
+
evidenceType,
|
|
73
|
+
platformId: input.platformId,
|
|
74
|
+
summary: `${input.platformId}:${input.intent}`,
|
|
75
|
+
sourceRefs: refs,
|
|
76
|
+
sensitivity: resolveSensitivity(input.intent, input.sensitivityOverride),
|
|
77
|
+
producer: "connector-system",
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { type FailureClass } from "./failure-taxonomy.js";
|
|
2
|
-
import { type EffectCommitLedgerPort } from "./execution-policy.js";
|
|
3
|
-
import type { CapabilityIntent, ConnectorRequest, ConnectorResult, ExecutionPlan, ExecutionRunner, RoutePlanner } from "./contract.js";
|
|
4
|
-
import type { ExecutionTelemetry } from "../../observability/services/execution-telemetry.js";
|
|
5
|
-
export interface RetryPolicy {
|
|
6
|
-
maxRetries: number;
|
|
7
|
-
baseDelayMs: number;
|
|
8
|
-
maxDelayMs: number;
|
|
9
|
-
jitter: boolean;
|
|
10
|
-
}
|
|
11
|
-
export interface CooldownPort {
|
|
12
|
-
isBlocked(platformId: string, intent: CapabilityIntent): Promise<{
|
|
13
|
-
blocked: boolean;
|
|
14
|
-
retryAfterMs?: number;
|
|
15
|
-
}>;
|
|
16
|
-
markFailure(platformId: string, intent: CapabilityIntent, failureClass: FailureClass, retryAfterMs?: number): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
export interface ConnectorPolicyContext {
|
|
19
|
-
routePlanner: RoutePlanner;
|
|
20
|
-
executionRunner: ExecutionRunner;
|
|
21
|
-
telemetry?: ExecutionTelemetry;
|
|
22
|
-
cooldownPort?: CooldownPort;
|
|
23
|
-
retryPolicy?: Partial<RetryPolicy>;
|
|
24
|
-
allowDegradedFallback?: (plan: ExecutionPlan, request: ConnectorRequest) => boolean;
|
|
25
|
-
effectCommitLedger?: EffectCommitLedgerPort;
|
|
26
|
-
}
|
|
27
|
-
export declare function createConnectorPolicyLayer(ctx: ConnectorPolicyContext): {
|
|
28
|
-
executeWithPolicy(intent: CapabilityIntent, request: ConnectorRequest): Promise<ConnectorResult<unknown>>;
|
|
29
|
-
};
|
|
1
|
+
import { type FailureClass } from "./failure-taxonomy.js";
|
|
2
|
+
import { type EffectCommitLedgerPort } from "./execution-policy.js";
|
|
3
|
+
import type { CapabilityIntent, ConnectorRequest, ConnectorResult, ExecutionPlan, ExecutionRunner, RoutePlanner } from "./contract.js";
|
|
4
|
+
import type { ExecutionTelemetry } from "../../observability/services/execution-telemetry.js";
|
|
5
|
+
export interface RetryPolicy {
|
|
6
|
+
maxRetries: number;
|
|
7
|
+
baseDelayMs: number;
|
|
8
|
+
maxDelayMs: number;
|
|
9
|
+
jitter: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface CooldownPort {
|
|
12
|
+
isBlocked(platformId: string, intent: CapabilityIntent): Promise<{
|
|
13
|
+
blocked: boolean;
|
|
14
|
+
retryAfterMs?: number;
|
|
15
|
+
}>;
|
|
16
|
+
markFailure(platformId: string, intent: CapabilityIntent, failureClass: FailureClass, retryAfterMs?: number): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface ConnectorPolicyContext {
|
|
19
|
+
routePlanner: RoutePlanner;
|
|
20
|
+
executionRunner: ExecutionRunner;
|
|
21
|
+
telemetry?: ExecutionTelemetry;
|
|
22
|
+
cooldownPort?: CooldownPort;
|
|
23
|
+
retryPolicy?: Partial<RetryPolicy>;
|
|
24
|
+
allowDegradedFallback?: (plan: ExecutionPlan, request: ConnectorRequest) => boolean;
|
|
25
|
+
effectCommitLedger?: EffectCommitLedgerPort;
|
|
26
|
+
}
|
|
27
|
+
export declare function createConnectorPolicyLayer(ctx: ConnectorPolicyContext): {
|
|
28
|
+
executeWithPolicy(intent: CapabilityIntent, request: ConnectorRequest): Promise<ConnectorResult<unknown>>;
|
|
29
|
+
};
|
|
@@ -1,198 +1,198 @@
|
|
|
1
|
-
import { classifyFailure } from "./failure-taxonomy.js";
|
|
2
|
-
import { enforceExecutionPolicy } from "./execution-policy.js";
|
|
3
|
-
const DEFAULT_RETRY_MAX = 3;
|
|
4
|
-
const DEFAULT_BASE_DELAY_MS = 1000;
|
|
5
|
-
const DEFAULT_MAX_DELAY_MS = 30000;
|
|
6
|
-
function resolveRetryPolicy(input) {
|
|
7
|
-
return {
|
|
8
|
-
maxRetries: input?.maxRetries ?? DEFAULT_RETRY_MAX,
|
|
9
|
-
baseDelayMs: input?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
|
|
10
|
-
maxDelayMs: input?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
|
|
11
|
-
jitter: input?.jitter ?? true,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
function computeRetryDelayMs(attempt, policy, retryAfterMs) {
|
|
15
|
-
if (typeof retryAfterMs === "number" && retryAfterMs > 0) {
|
|
16
|
-
return retryAfterMs;
|
|
17
|
-
}
|
|
18
|
-
const base = Math.min(policy.baseDelayMs * 2 ** Math.max(0, attempt - 1), policy.maxDelayMs);
|
|
19
|
-
if (!policy.jitter)
|
|
20
|
-
return base;
|
|
21
|
-
return Math.floor(base * 0.8 + Math.random() * base * 0.4);
|
|
22
|
-
}
|
|
23
|
-
async function sleep(ms) {
|
|
24
|
-
if (ms <= 0)
|
|
25
|
-
return;
|
|
26
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
-
}
|
|
28
|
-
function makeTraceId(request, plan) {
|
|
29
|
-
return `${request.platformId}:${request.intent}:${plan.channel}:${Date.now()}`;
|
|
30
|
-
}
|
|
31
|
-
function resolveIdentity(request) {
|
|
32
|
-
if (!request.decisionId || !request.intentId) {
|
|
33
|
-
throw new Error("connector_policy_missing_decision_or_intent_identity");
|
|
34
|
-
}
|
|
35
|
-
return {
|
|
36
|
-
decisionId: request.decisionId,
|
|
37
|
-
intentId: request.intentId,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function isDegradedChannel(channel) {
|
|
41
|
-
return channel === "cli" || channel === "skill" || channel === "browser";
|
|
42
|
-
}
|
|
43
|
-
function adaptProtocolErrors(error) {
|
|
44
|
-
if (!error || typeof error !== "object") {
|
|
45
|
-
return error;
|
|
46
|
-
}
|
|
47
|
-
const record = error;
|
|
48
|
-
const detail = typeof record.detail === "string" ? record.detail : "";
|
|
49
|
-
if (detail === "node_secret_required") {
|
|
50
|
-
return { code: "verification_required", detail };
|
|
51
|
-
}
|
|
52
|
-
if (detail === "bundle_required") {
|
|
53
|
-
return { code: "protocol_mismatch", detail };
|
|
54
|
-
}
|
|
55
|
-
if (detail === "asset_id mismatch") {
|
|
56
|
-
return { code: "protocol_mismatch", detail };
|
|
57
|
-
}
|
|
58
|
-
return error;
|
|
59
|
-
}
|
|
60
|
-
export function createConnectorPolicyLayer(ctx) {
|
|
61
|
-
const retryPolicy = resolveRetryPolicy(ctx.retryPolicy);
|
|
62
|
-
const allowDegradedFallback = ctx.allowDegradedFallback ?? (() => true);
|
|
63
|
-
return {
|
|
64
|
-
async executeWithPolicy(intent, request) {
|
|
65
|
-
if (ctx.cooldownPort) {
|
|
66
|
-
const cooldown = await ctx.cooldownPort.isBlocked(request.platformId, intent);
|
|
67
|
-
if (cooldown.blocked) {
|
|
68
|
-
return {
|
|
69
|
-
status: "terminal_failure",
|
|
70
|
-
failureClass: "cooldown_blocked",
|
|
71
|
-
retryAfterMs: cooldown.retryAfterMs,
|
|
72
|
-
metadata: {
|
|
73
|
-
platformId: request.platformId,
|
|
74
|
-
channel: request.preferredChannel ?? "api_rest",
|
|
75
|
-
latencyMs: 0,
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const identity = resolveIdentity(request);
|
|
81
|
-
let plan;
|
|
82
|
-
try {
|
|
83
|
-
plan = await ctx.routePlanner.planRoute(intent, request);
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
const failure = classifyFailure(error);
|
|
87
|
-
return {
|
|
88
|
-
status: "terminal_failure",
|
|
89
|
-
failureClass: failure.class,
|
|
90
|
-
retryAfterMs: failure.retryAfterMs,
|
|
91
|
-
metadata: {
|
|
92
|
-
platformId: request.platformId,
|
|
93
|
-
channel: request.preferredChannel ?? "api_rest",
|
|
94
|
-
latencyMs: 0,
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (isDegradedChannel(plan.channel) && !allowDegradedFallback(plan, request)) {
|
|
99
|
-
return {
|
|
100
|
-
status: "terminal_failure",
|
|
101
|
-
failureClass: "protocol_mismatch",
|
|
102
|
-
metadata: {
|
|
103
|
-
platformId: request.platformId,
|
|
104
|
-
channel: plan.channel,
|
|
105
|
-
latencyMs: 0,
|
|
106
|
-
degraded: true,
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
const policyGate = await enforceExecutionPolicy(plan, intent, request, {
|
|
111
|
-
effectCommitLedger: ctx.effectCommitLedger,
|
|
112
|
-
});
|
|
113
|
-
if (policyGate.skipAdapter && policyGate.existingOutcomeRef) {
|
|
114
|
-
return {
|
|
115
|
-
status: "success",
|
|
116
|
-
data: { replayedCommit: true, outcomeRef: policyGate.existingOutcomeRef },
|
|
117
|
-
metadata: {
|
|
118
|
-
platformId: request.platformId,
|
|
119
|
-
channel: plan.channel,
|
|
120
|
-
latencyMs: 0,
|
|
121
|
-
degraded: plan.degraded,
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
let lastFailure;
|
|
126
|
-
for (let attempt = 1; attempt <= retryPolicy.maxRetries; attempt += 1) {
|
|
127
|
-
const traceId = `${makeTraceId(request, plan)}:${attempt}`;
|
|
128
|
-
if (ctx.telemetry) {
|
|
129
|
-
await ctx.telemetry.startAttempt({
|
|
130
|
-
traceId,
|
|
131
|
-
decisionId: identity.decisionId,
|
|
132
|
-
intentId: identity.intentId,
|
|
133
|
-
platformId: request.platformId,
|
|
134
|
-
capability: request.intent,
|
|
135
|
-
channel: plan.channel,
|
|
136
|
-
retryPolicy: JSON.stringify(retryPolicy),
|
|
137
|
-
idempotencyKey: request.idempotencyKey,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
const raw = await ctx.executionRunner.run(plan, request);
|
|
141
|
-
if (raw.success) {
|
|
142
|
-
if (ctx.telemetry) {
|
|
143
|
-
await ctx.telemetry.completeAttempt(traceId, "succeeded");
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
status: "success",
|
|
147
|
-
data: raw.payload,
|
|
148
|
-
metadata: {
|
|
149
|
-
platformId: raw.platformId,
|
|
150
|
-
channel: raw.channel,
|
|
151
|
-
latencyMs: raw.latencyMs,
|
|
152
|
-
degraded: raw.degraded,
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
const classified = classifyFailure(adaptProtocolErrors(raw.error));
|
|
157
|
-
lastFailure = {
|
|
158
|
-
failureClass: classified.class,
|
|
159
|
-
retryAfterMs: classified.retryAfterMs,
|
|
160
|
-
channel: raw.channel,
|
|
161
|
-
};
|
|
162
|
-
if (ctx.telemetry) {
|
|
163
|
-
await ctx.telemetry.completeAttempt(traceId, "failed", undefined, classified.class);
|
|
164
|
-
}
|
|
165
|
-
if (ctx.cooldownPort) {
|
|
166
|
-
await ctx.cooldownPort.markFailure(request.platformId, intent, classified.class, classified.retryAfterMs);
|
|
167
|
-
}
|
|
168
|
-
const isRetryable = classified.retryable;
|
|
169
|
-
if (!isRetryable || attempt >= retryPolicy.maxRetries) {
|
|
170
|
-
return {
|
|
171
|
-
status: "terminal_failure",
|
|
172
|
-
failureClass: classified.class,
|
|
173
|
-
retryAfterMs: classified.retryAfterMs,
|
|
174
|
-
metadata: {
|
|
175
|
-
platformId: raw.platformId,
|
|
176
|
-
channel: raw.channel,
|
|
177
|
-
latencyMs: raw.latencyMs,
|
|
178
|
-
degraded: raw.degraded,
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
const delay = computeRetryDelayMs(attempt, retryPolicy, classified.retryAfterMs);
|
|
183
|
-
await sleep(delay);
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
status: "terminal_failure",
|
|
187
|
-
failureClass: lastFailure?.failureClass ?? "unknown_platform_change",
|
|
188
|
-
retryAfterMs: lastFailure?.retryAfterMs,
|
|
189
|
-
metadata: {
|
|
190
|
-
platformId: request.platformId,
|
|
191
|
-
channel: lastFailure?.channel ?? plan.channel,
|
|
192
|
-
latencyMs: 0,
|
|
193
|
-
degraded: isDegradedChannel(lastFailure?.channel ?? plan.channel),
|
|
194
|
-
},
|
|
195
|
-
};
|
|
196
|
-
},
|
|
197
|
-
};
|
|
198
|
-
}
|
|
1
|
+
import { classifyFailure } from "./failure-taxonomy.js";
|
|
2
|
+
import { enforceExecutionPolicy } from "./execution-policy.js";
|
|
3
|
+
const DEFAULT_RETRY_MAX = 3;
|
|
4
|
+
const DEFAULT_BASE_DELAY_MS = 1000;
|
|
5
|
+
const DEFAULT_MAX_DELAY_MS = 30000;
|
|
6
|
+
function resolveRetryPolicy(input) {
|
|
7
|
+
return {
|
|
8
|
+
maxRetries: input?.maxRetries ?? DEFAULT_RETRY_MAX,
|
|
9
|
+
baseDelayMs: input?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
|
|
10
|
+
maxDelayMs: input?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
|
|
11
|
+
jitter: input?.jitter ?? true,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function computeRetryDelayMs(attempt, policy, retryAfterMs) {
|
|
15
|
+
if (typeof retryAfterMs === "number" && retryAfterMs > 0) {
|
|
16
|
+
return retryAfterMs;
|
|
17
|
+
}
|
|
18
|
+
const base = Math.min(policy.baseDelayMs * 2 ** Math.max(0, attempt - 1), policy.maxDelayMs);
|
|
19
|
+
if (!policy.jitter)
|
|
20
|
+
return base;
|
|
21
|
+
return Math.floor(base * 0.8 + Math.random() * base * 0.4);
|
|
22
|
+
}
|
|
23
|
+
async function sleep(ms) {
|
|
24
|
+
if (ms <= 0)
|
|
25
|
+
return;
|
|
26
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
function makeTraceId(request, plan) {
|
|
29
|
+
return `${request.platformId}:${request.intent}:${plan.channel}:${Date.now()}`;
|
|
30
|
+
}
|
|
31
|
+
function resolveIdentity(request) {
|
|
32
|
+
if (!request.decisionId || !request.intentId) {
|
|
33
|
+
throw new Error("connector_policy_missing_decision_or_intent_identity");
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
decisionId: request.decisionId,
|
|
37
|
+
intentId: request.intentId,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function isDegradedChannel(channel) {
|
|
41
|
+
return channel === "cli" || channel === "skill" || channel === "browser";
|
|
42
|
+
}
|
|
43
|
+
function adaptProtocolErrors(error) {
|
|
44
|
+
if (!error || typeof error !== "object") {
|
|
45
|
+
return error;
|
|
46
|
+
}
|
|
47
|
+
const record = error;
|
|
48
|
+
const detail = typeof record.detail === "string" ? record.detail : "";
|
|
49
|
+
if (detail === "node_secret_required") {
|
|
50
|
+
return { code: "verification_required", detail };
|
|
51
|
+
}
|
|
52
|
+
if (detail === "bundle_required") {
|
|
53
|
+
return { code: "protocol_mismatch", detail };
|
|
54
|
+
}
|
|
55
|
+
if (detail === "asset_id mismatch") {
|
|
56
|
+
return { code: "protocol_mismatch", detail };
|
|
57
|
+
}
|
|
58
|
+
return error;
|
|
59
|
+
}
|
|
60
|
+
export function createConnectorPolicyLayer(ctx) {
|
|
61
|
+
const retryPolicy = resolveRetryPolicy(ctx.retryPolicy);
|
|
62
|
+
const allowDegradedFallback = ctx.allowDegradedFallback ?? (() => true);
|
|
63
|
+
return {
|
|
64
|
+
async executeWithPolicy(intent, request) {
|
|
65
|
+
if (ctx.cooldownPort) {
|
|
66
|
+
const cooldown = await ctx.cooldownPort.isBlocked(request.platformId, intent);
|
|
67
|
+
if (cooldown.blocked) {
|
|
68
|
+
return {
|
|
69
|
+
status: "terminal_failure",
|
|
70
|
+
failureClass: "cooldown_blocked",
|
|
71
|
+
retryAfterMs: cooldown.retryAfterMs,
|
|
72
|
+
metadata: {
|
|
73
|
+
platformId: request.platformId,
|
|
74
|
+
channel: request.preferredChannel ?? "api_rest",
|
|
75
|
+
latencyMs: 0,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const identity = resolveIdentity(request);
|
|
81
|
+
let plan;
|
|
82
|
+
try {
|
|
83
|
+
plan = await ctx.routePlanner.planRoute(intent, request);
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const failure = classifyFailure(error);
|
|
87
|
+
return {
|
|
88
|
+
status: "terminal_failure",
|
|
89
|
+
failureClass: failure.class,
|
|
90
|
+
retryAfterMs: failure.retryAfterMs,
|
|
91
|
+
metadata: {
|
|
92
|
+
platformId: request.platformId,
|
|
93
|
+
channel: request.preferredChannel ?? "api_rest",
|
|
94
|
+
latencyMs: 0,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (isDegradedChannel(plan.channel) && !allowDegradedFallback(plan, request)) {
|
|
99
|
+
return {
|
|
100
|
+
status: "terminal_failure",
|
|
101
|
+
failureClass: "protocol_mismatch",
|
|
102
|
+
metadata: {
|
|
103
|
+
platformId: request.platformId,
|
|
104
|
+
channel: plan.channel,
|
|
105
|
+
latencyMs: 0,
|
|
106
|
+
degraded: true,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const policyGate = await enforceExecutionPolicy(plan, intent, request, {
|
|
111
|
+
effectCommitLedger: ctx.effectCommitLedger,
|
|
112
|
+
});
|
|
113
|
+
if (policyGate.skipAdapter && policyGate.existingOutcomeRef) {
|
|
114
|
+
return {
|
|
115
|
+
status: "success",
|
|
116
|
+
data: { replayedCommit: true, outcomeRef: policyGate.existingOutcomeRef },
|
|
117
|
+
metadata: {
|
|
118
|
+
platformId: request.platformId,
|
|
119
|
+
channel: plan.channel,
|
|
120
|
+
latencyMs: 0,
|
|
121
|
+
degraded: plan.degraded,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let lastFailure;
|
|
126
|
+
for (let attempt = 1; attempt <= retryPolicy.maxRetries; attempt += 1) {
|
|
127
|
+
const traceId = `${makeTraceId(request, plan)}:${attempt}`;
|
|
128
|
+
if (ctx.telemetry) {
|
|
129
|
+
await ctx.telemetry.startAttempt({
|
|
130
|
+
traceId,
|
|
131
|
+
decisionId: identity.decisionId,
|
|
132
|
+
intentId: identity.intentId,
|
|
133
|
+
platformId: request.platformId,
|
|
134
|
+
capability: request.intent,
|
|
135
|
+
channel: plan.channel,
|
|
136
|
+
retryPolicy: JSON.stringify(retryPolicy),
|
|
137
|
+
idempotencyKey: request.idempotencyKey,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const raw = await ctx.executionRunner.run(plan, request);
|
|
141
|
+
if (raw.success) {
|
|
142
|
+
if (ctx.telemetry) {
|
|
143
|
+
await ctx.telemetry.completeAttempt(traceId, "succeeded");
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
status: "success",
|
|
147
|
+
data: raw.payload,
|
|
148
|
+
metadata: {
|
|
149
|
+
platformId: raw.platformId,
|
|
150
|
+
channel: raw.channel,
|
|
151
|
+
latencyMs: raw.latencyMs,
|
|
152
|
+
degraded: raw.degraded,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const classified = classifyFailure(adaptProtocolErrors(raw.error));
|
|
157
|
+
lastFailure = {
|
|
158
|
+
failureClass: classified.class,
|
|
159
|
+
retryAfterMs: classified.retryAfterMs,
|
|
160
|
+
channel: raw.channel,
|
|
161
|
+
};
|
|
162
|
+
if (ctx.telemetry) {
|
|
163
|
+
await ctx.telemetry.completeAttempt(traceId, "failed", undefined, classified.class);
|
|
164
|
+
}
|
|
165
|
+
if (ctx.cooldownPort) {
|
|
166
|
+
await ctx.cooldownPort.markFailure(request.platformId, intent, classified.class, classified.retryAfterMs);
|
|
167
|
+
}
|
|
168
|
+
const isRetryable = classified.retryable;
|
|
169
|
+
if (!isRetryable || attempt >= retryPolicy.maxRetries) {
|
|
170
|
+
return {
|
|
171
|
+
status: "terminal_failure",
|
|
172
|
+
failureClass: classified.class,
|
|
173
|
+
retryAfterMs: classified.retryAfterMs,
|
|
174
|
+
metadata: {
|
|
175
|
+
platformId: raw.platformId,
|
|
176
|
+
channel: raw.channel,
|
|
177
|
+
latencyMs: raw.latencyMs,
|
|
178
|
+
degraded: raw.degraded,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const delay = computeRetryDelayMs(attempt, retryPolicy, classified.retryAfterMs);
|
|
183
|
+
await sleep(delay);
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
status: "terminal_failure",
|
|
187
|
+
failureClass: lastFailure?.failureClass ?? "unknown_platform_change",
|
|
188
|
+
retryAfterMs: lastFailure?.retryAfterMs,
|
|
189
|
+
metadata: {
|
|
190
|
+
platformId: request.platformId,
|
|
191
|
+
channel: lastFailure?.channel ?? plan.channel,
|
|
192
|
+
latencyMs: 0,
|
|
193
|
+
degraded: isDegradedChannel(lastFailure?.channel ?? plan.channel),
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|