@haaaiawd/second-nature 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +64 -21
- package/package.json +8 -2
- package/runtime/cli/action-bridge.d.ts +11 -0
- package/runtime/cli/action-bridge.js +27 -0
- package/runtime/cli/commands/credential.d.ts +2 -0
- package/runtime/cli/commands/credential.js +40 -0
- package/runtime/cli/commands/index.d.ts +12 -0
- package/runtime/cli/commands/index.js +138 -0
- package/runtime/cli/commands/policy.d.ts +12 -0
- package/runtime/cli/commands/policy.js +43 -0
- package/runtime/cli/explain/format-explanation.d.ts +10 -0
- package/runtime/cli/explain/format-explanation.js +10 -0
- package/runtime/cli/explain/resolve-subject.d.ts +2 -0
- package/runtime/cli/explain/resolve-subject.js +26 -0
- package/runtime/cli/index.d.ts +25 -0
- package/runtime/cli/index.js +36 -0
- package/runtime/cli/read-models/index.d.ts +20 -0
- package/runtime/cli/read-models/index.js +161 -0
- package/runtime/cli/read-models/types.d.ts +75 -0
- package/runtime/cli/read-models/types.js +1 -0
- package/runtime/connectors/agent-network/evomap/adapter.d.ts +23 -0
- package/runtime/connectors/agent-network/evomap/adapter.js +69 -0
- package/runtime/connectors/agent-network/evomap/index.d.ts +2 -0
- package/runtime/connectors/agent-network/evomap/index.js +2 -0
- package/runtime/connectors/agent-network/evomap/manifest.d.ts +2 -0
- package/runtime/connectors/agent-network/evomap/manifest.js +7 -0
- package/runtime/connectors/base/channel-health.d.ts +29 -0
- package/runtime/connectors/base/channel-health.js +23 -0
- package/runtime/connectors/base/contract.d.ts +81 -0
- package/runtime/connectors/base/contract.js +71 -0
- package/runtime/connectors/base/failure-taxonomy.d.ts +13 -0
- package/runtime/connectors/base/failure-taxonomy.js +105 -0
- package/runtime/connectors/base/index.d.ts +6 -0
- package/runtime/connectors/base/index.js +6 -0
- package/runtime/connectors/base/manifest.d.ts +11 -0
- package/runtime/connectors/base/manifest.js +36 -0
- package/runtime/connectors/base/policy-layer.d.ts +27 -0
- package/runtime/connectors/base/policy-layer.js +213 -0
- package/runtime/connectors/base/route-planner.d.ts +10 -0
- package/runtime/connectors/base/route-planner.js +98 -0
- package/runtime/connectors/index.d.ts +4 -0
- package/runtime/connectors/index.js +4 -0
- package/runtime/connectors/social-community/instreet/adapter.d.ts +32 -0
- package/runtime/connectors/social-community/instreet/adapter.js +79 -0
- package/runtime/connectors/social-community/instreet/index.d.ts +2 -0
- package/runtime/connectors/social-community/instreet/index.js +2 -0
- package/runtime/connectors/social-community/instreet/manifest.d.ts +2 -0
- package/runtime/connectors/social-community/instreet/manifest.js +7 -0
- package/runtime/connectors/social-community/moltbook/adapter.d.ts +15 -0
- package/runtime/connectors/social-community/moltbook/adapter.js +48 -0
- package/runtime/connectors/social-community/moltbook/index.d.ts +2 -0
- package/runtime/connectors/social-community/moltbook/index.js +2 -0
- package/runtime/connectors/social-community/moltbook/manifest.d.ts +7 -0
- package/runtime/connectors/social-community/moltbook/manifest.js +12 -0
- package/runtime/core/second-nature/guidance/apply-guidance.d.ts +10 -0
- package/runtime/core/second-nature/guidance/apply-guidance.js +10 -0
- package/runtime/core/second-nature/guidance/request-guidance.d.ts +18 -0
- package/runtime/core/second-nature/guidance/request-guidance.js +22 -0
- package/runtime/core/second-nature/index.d.ts +14 -0
- package/runtime/core/second-nature/index.js +14 -0
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +100 -0
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +139 -0
- package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +2 -0
- package/runtime/core/second-nature/orchestrator/guard-layer.js +54 -0
- package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +3 -0
- package/runtime/core/second-nature/orchestrator/intent-planner.js +92 -0
- package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +14 -0
- package/runtime/core/second-nature/orchestrator/lease-manager.js +58 -0
- package/runtime/core/second-nature/orchestrator/resume-from-checkpoint.d.ts +32 -0
- package/runtime/core/second-nature/orchestrator/resume-from-checkpoint.js +23 -0
- package/runtime/core/second-nature/outreach/build-message.d.ts +16 -0
- package/runtime/core/second-nature/outreach/build-message.js +27 -0
- package/runtime/core/second-nature/outreach/evaluate-outreach.d.ts +13 -0
- package/runtime/core/second-nature/outreach/evaluate-outreach.js +41 -0
- package/runtime/core/second-nature/quiet/quiet-pipeline.d.ts +34 -0
- package/runtime/core/second-nature/quiet/quiet-pipeline.js +35 -0
- package/runtime/core/second-nature/reflection/run-narrative-reflection.d.ts +39 -0
- package/runtime/core/second-nature/reflection/run-narrative-reflection.js +29 -0
- package/runtime/core/second-nature/rhythm/rhythm-policy.d.ts +18 -0
- package/runtime/core/second-nature/rhythm/rhythm-policy.js +24 -0
- package/runtime/core/second-nature/rhythm/select-window.d.ts +3 -0
- package/runtime/core/second-nature/rhythm/select-window.js +50 -0
- package/runtime/core/second-nature/runtime/lifecycle-service.d.ts +26 -0
- package/runtime/core/second-nature/runtime/lifecycle-service.js +38 -0
- package/runtime/core/second-nature/runtime/service-entry.d.ts +36 -0
- package/runtime/core/second-nature/runtime/service-entry.js +44 -0
- package/runtime/core/second-nature/types.d.ts +37 -0
- package/runtime/core/second-nature/types.js +1 -0
- package/runtime/guidance/contracts.d.ts +48 -0
- package/runtime/guidance/contracts.js +54 -0
- package/runtime/guidance/fallback.d.ts +2 -0
- package/runtime/guidance/fallback.js +17 -0
- package/runtime/guidance/guidance-assembler.d.ts +5 -0
- package/runtime/guidance/guidance-assembler.js +62 -0
- package/runtime/guidance/index.d.ts +8 -0
- package/runtime/guidance/index.js +8 -0
- package/runtime/guidance/output-guard.d.ts +10 -0
- package/runtime/guidance/output-guard.js +29 -0
- package/runtime/guidance/persona-selection.d.ts +11 -0
- package/runtime/guidance/persona-selection.js +90 -0
- package/runtime/guidance/review-workflow.d.ts +15 -0
- package/runtime/guidance/review-workflow.js +60 -0
- package/runtime/guidance/template-registry.d.ts +3 -0
- package/runtime/guidance/template-registry.js +45 -0
- package/runtime/guidance/types.d.ts +72 -0
- package/runtime/guidance/types.js +1 -0
- package/runtime/observability/db/index.d.ts +10 -0
- package/runtime/observability/db/index.js +17 -0
- package/runtime/observability/db/schema/index.d.ts +946 -0
- package/runtime/observability/db/schema/index.js +70 -0
- package/runtime/observability/index.d.ts +12 -0
- package/runtime/observability/index.js +11 -0
- package/runtime/observability/projections/guidance-audit.d.ts +16 -0
- package/runtime/observability/projections/guidance-audit.js +35 -0
- package/runtime/observability/projections/outreach-quality-audit.d.ts +15 -0
- package/runtime/observability/projections/outreach-quality-audit.js +9 -0
- package/runtime/observability/projections/reflection-audit.d.ts +17 -0
- package/runtime/observability/projections/reflection-audit.js +9 -0
- package/runtime/observability/query/compose-evidence.d.ts +56 -0
- package/runtime/observability/query/compose-evidence.js +43 -0
- package/runtime/observability/query/evidence-query-engine.d.ts +17 -0
- package/runtime/observability/query/evidence-query-engine.js +166 -0
- package/runtime/observability/redaction/manifest.d.ts +18 -0
- package/runtime/observability/redaction/manifest.js +109 -0
- package/runtime/observability/redaction/policy.d.ts +19 -0
- package/runtime/observability/redaction/policy.js +71 -0
- package/runtime/observability/services/decision-ledger.d.ts +33 -0
- package/runtime/observability/services/decision-ledger.js +115 -0
- package/runtime/observability/services/execution-telemetry.d.ts +32 -0
- package/runtime/observability/services/execution-telemetry.js +126 -0
- package/runtime/observability/services/governance-audit.d.ts +27 -0
- package/runtime/observability/services/governance-audit.js +139 -0
- package/runtime/observability/services/redaction-store.d.ts +3 -0
- package/runtime/observability/services/redaction-store.js +20 -0
- package/runtime/shared/types/continuity.d.ts +69 -0
- package/runtime/shared/types/continuity.js +1 -0
- package/runtime/shared/types/credential.d.ts +22 -0
- package/runtime/shared/types/credential.js +1 -0
- package/runtime/shared/types/index.d.ts +3 -0
- package/runtime/shared/types/index.js +3 -0
- package/runtime/shared/types/outreach.d.ts +19 -0
- package/runtime/shared/types/outreach.js +1 -0
- package/runtime/storage/bootstrap/repair.d.ts +3 -0
- package/runtime/storage/bootstrap/repair.js +5 -0
- package/runtime/storage/db/index.d.ts +10 -0
- package/runtime/storage/db/index.js +17 -0
- package/runtime/storage/db/schema/assets.d.ts +140 -0
- package/runtime/storage/db/schema/assets.js +10 -0
- package/runtime/storage/db/schema/credentials.d.ts +178 -0
- package/runtime/storage/db/schema/credentials.js +12 -0
- package/runtime/storage/db/schema/index.d.ts +6 -0
- package/runtime/storage/db/schema/index.js +6 -0
- package/runtime/storage/db/schema/intent-commits.d.ts +161 -0
- package/runtime/storage/db/schema/intent-commits.js +11 -0
- package/runtime/storage/db/schema/policies.d.ts +81 -0
- package/runtime/storage/db/schema/policies.js +7 -0
- package/runtime/storage/db/schema/proposals.d.ts +216 -0
- package/runtime/storage/db/schema/proposals.js +14 -0
- package/runtime/storage/db/schema/provenance.d.ts +104 -0
- package/runtime/storage/db/schema/provenance.js +8 -0
- package/runtime/storage/index.d.ts +16 -0
- package/runtime/storage/index.js +16 -0
- package/runtime/storage/memory/workspace/paths.d.ts +62 -0
- package/runtime/storage/memory/workspace/paths.js +160 -0
- package/runtime/storage/memory/workspace/store.d.ts +26 -0
- package/runtime/storage/memory/workspace/store.js +153 -0
- package/runtime/storage/memory/workspace/types.d.ts +45 -0
- package/runtime/storage/memory/workspace/types.js +1 -0
- package/runtime/storage/repositories/asset-repository.d.ts +8 -0
- package/runtime/storage/repositories/asset-repository.js +19 -0
- package/runtime/storage/repositories/credential-repository.d.ts +8 -0
- package/runtime/storage/repositories/credential-repository.js +19 -0
- package/runtime/storage/repositories/index.d.ts +6 -0
- package/runtime/storage/repositories/index.js +6 -0
- package/runtime/storage/repositories/intent-commit-repository.d.ts +10 -0
- package/runtime/storage/repositories/intent-commit-repository.js +35 -0
- package/runtime/storage/repositories/policy-repository.d.ts +8 -0
- package/runtime/storage/repositories/policy-repository.js +19 -0
- package/runtime/storage/repositories/proposal-repository.d.ts +9 -0
- package/runtime/storage/repositories/proposal-repository.js +26 -0
- package/runtime/storage/repositories/provenance-repository.d.ts +20 -0
- package/runtime/storage/repositories/provenance-repository.js +41 -0
- package/runtime/storage/services/credential-vault.d.ts +8 -0
- package/runtime/storage/services/credential-vault.js +78 -0
- package/runtime/storage/services/daily-log-pipeline.d.ts +47 -0
- package/runtime/storage/services/daily-log-pipeline.js +86 -0
- package/runtime/storage/services/effect-commit-store.d.ts +11 -0
- package/runtime/storage/services/effect-commit-store.js +93 -0
- package/runtime/storage/services/governance-layer.d.ts +40 -0
- package/runtime/storage/services/governance-layer.js +103 -0
- package/runtime/storage/services/persona-candidate-loader.d.ts +5 -0
- package/runtime/storage/services/persona-candidate-loader.js +41 -0
- package/runtime/storage/services/provenance-service.d.ts +40 -0
- package/runtime/storage/services/provenance-service.js +43 -0
- package/runtime/storage/services/quiet-input-loader.d.ts +40 -0
- package/runtime/storage/services/quiet-input-loader.js +131 -0
- package/runtime/storage/services/repair-and-backup.d.ts +22 -0
- package/runtime/storage/services/repair-and-backup.js +73 -0
- package/runtime/storage/state-api.d.ts +46 -0
- package/runtime/storage/state-api.js +73 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export const FAILURE_CLASSES = [
|
|
2
|
+
"transport_failure",
|
|
3
|
+
"auth_failure",
|
|
4
|
+
"credential_expired",
|
|
5
|
+
"verification_required",
|
|
6
|
+
"rate_limited",
|
|
7
|
+
"cooldown_blocked",
|
|
8
|
+
"parse_failure",
|
|
9
|
+
"protocol_mismatch",
|
|
10
|
+
"semantic_rejection",
|
|
11
|
+
"idempotency_conflict",
|
|
12
|
+
"concurrency_conflict",
|
|
13
|
+
"permanent_input_error",
|
|
14
|
+
"unknown_platform_change",
|
|
15
|
+
];
|
|
16
|
+
const RETRYABLE_BY_CLASS = {
|
|
17
|
+
transport_failure: true,
|
|
18
|
+
auth_failure: false,
|
|
19
|
+
credential_expired: false,
|
|
20
|
+
verification_required: false,
|
|
21
|
+
rate_limited: true,
|
|
22
|
+
cooldown_blocked: false,
|
|
23
|
+
parse_failure: false,
|
|
24
|
+
protocol_mismatch: false,
|
|
25
|
+
semantic_rejection: false,
|
|
26
|
+
idempotency_conflict: false,
|
|
27
|
+
concurrency_conflict: true,
|
|
28
|
+
permanent_input_error: false,
|
|
29
|
+
unknown_platform_change: false,
|
|
30
|
+
};
|
|
31
|
+
export class ConnectorPolicyError extends Error {
|
|
32
|
+
failureClass;
|
|
33
|
+
retryAfterMs;
|
|
34
|
+
constructor(failureClass, message, retryAfterMs) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.failureClass = failureClass;
|
|
37
|
+
this.retryAfterMs = retryAfterMs;
|
|
38
|
+
this.name = "ConnectorPolicyError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function readRetryAfterMs(input) {
|
|
42
|
+
const retryAfterMs = input.retryAfterMs;
|
|
43
|
+
if (typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0) {
|
|
44
|
+
return retryAfterMs;
|
|
45
|
+
}
|
|
46
|
+
const retryAfterSeconds = input.retryAfterSeconds;
|
|
47
|
+
if (typeof retryAfterSeconds === "number" && Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0) {
|
|
48
|
+
return retryAfterSeconds * 1000;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
export function classifyFailure(error) {
|
|
53
|
+
if (error instanceof ConnectorPolicyError) {
|
|
54
|
+
return {
|
|
55
|
+
class: error.failureClass,
|
|
56
|
+
retryable: RETRYABLE_BY_CLASS[error.failureClass],
|
|
57
|
+
retryAfterMs: error.retryAfterMs,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (error instanceof SyntaxError) {
|
|
61
|
+
return { class: "parse_failure", retryable: false };
|
|
62
|
+
}
|
|
63
|
+
if (error && typeof error === "object") {
|
|
64
|
+
const record = error;
|
|
65
|
+
const code = record.code;
|
|
66
|
+
if (typeof code === "string") {
|
|
67
|
+
if (code === "verification_required")
|
|
68
|
+
return { class: "verification_required", retryable: RETRYABLE_BY_CLASS.verification_required };
|
|
69
|
+
if (code === "credential_expired")
|
|
70
|
+
return { class: "credential_expired", retryable: RETRYABLE_BY_CLASS.credential_expired };
|
|
71
|
+
if (code === "cooldown_blocked")
|
|
72
|
+
return { class: "cooldown_blocked", retryable: RETRYABLE_BY_CLASS.cooldown_blocked };
|
|
73
|
+
if (code === "idempotency_conflict")
|
|
74
|
+
return { class: "idempotency_conflict", retryable: RETRYABLE_BY_CLASS.idempotency_conflict };
|
|
75
|
+
if (code === "concurrency_conflict")
|
|
76
|
+
return { class: "concurrency_conflict", retryable: RETRYABLE_BY_CLASS.concurrency_conflict };
|
|
77
|
+
if (code === "protocol_mismatch")
|
|
78
|
+
return { class: "protocol_mismatch", retryable: RETRYABLE_BY_CLASS.protocol_mismatch };
|
|
79
|
+
if (code === "semantic_rejection")
|
|
80
|
+
return { class: "semantic_rejection", retryable: RETRYABLE_BY_CLASS.semantic_rejection };
|
|
81
|
+
if (code === "transport_failure")
|
|
82
|
+
return { class: "transport_failure", retryable: RETRYABLE_BY_CLASS.transport_failure };
|
|
83
|
+
if (code === "permanent_input_error")
|
|
84
|
+
return { class: "permanent_input_error", retryable: RETRYABLE_BY_CLASS.permanent_input_error };
|
|
85
|
+
}
|
|
86
|
+
const status = record.status;
|
|
87
|
+
if (status === 429) {
|
|
88
|
+
return {
|
|
89
|
+
class: "rate_limited",
|
|
90
|
+
retryable: RETRYABLE_BY_CLASS.rate_limited,
|
|
91
|
+
retryAfterMs: readRetryAfterMs(record),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (status === 401 || status === 403) {
|
|
95
|
+
return { class: "auth_failure", retryable: RETRYABLE_BY_CLASS.auth_failure };
|
|
96
|
+
}
|
|
97
|
+
if (status === 400 || status === 404 || status === 422) {
|
|
98
|
+
return { class: "permanent_input_error", retryable: RETRYABLE_BY_CLASS.permanent_input_error };
|
|
99
|
+
}
|
|
100
|
+
if (status === 500 || status === 502 || status === 503 || status === 504) {
|
|
101
|
+
return { class: "transport_failure", retryable: RETRYABLE_BY_CLASS.transport_failure };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { class: "unknown_platform_change", retryable: RETRYABLE_BY_CLASS.unknown_platform_change };
|
|
105
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CapabilityIntent, type ChannelType, type ConnectorManifestLike } from "./contract.js";
|
|
2
|
+
export type ConnectorManifest = ConnectorManifestLike;
|
|
3
|
+
export declare class CapabilityContractRegistry {
|
|
4
|
+
private readonly byPlatform;
|
|
5
|
+
register(manifest: ConnectorManifest): void;
|
|
6
|
+
loadManifest(platformId: string): ConnectorManifest;
|
|
7
|
+
hasCapability(platformId: string, intent: CapabilityIntent): boolean;
|
|
8
|
+
listCapabilities(platformId: string): CapabilityIntent[];
|
|
9
|
+
listChannels(platformId: string): ChannelType[];
|
|
10
|
+
}
|
|
11
|
+
export declare function parseConnectorManifest(input: unknown): ConnectorManifest;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CAPABILITY_INTENTS, CHANNEL_TYPES } from "./contract.js";
|
|
3
|
+
const connectorManifestSchema = z.object({
|
|
4
|
+
platformId: z.string().min(1),
|
|
5
|
+
supportedCapabilities: z.array(z.enum(CAPABILITY_INTENTS)).min(1),
|
|
6
|
+
channelPriority: z.array(z.enum(CHANNEL_TYPES)).min(1),
|
|
7
|
+
credentialTypes: z.array(z.string().min(1)).min(1),
|
|
8
|
+
degradedChannels: z.array(z.enum(CHANNEL_TYPES)).optional(),
|
|
9
|
+
});
|
|
10
|
+
export class CapabilityContractRegistry {
|
|
11
|
+
byPlatform = new Map();
|
|
12
|
+
register(manifest) {
|
|
13
|
+
const parsed = connectorManifestSchema.parse(manifest);
|
|
14
|
+
this.byPlatform.set(parsed.platformId, parsed);
|
|
15
|
+
}
|
|
16
|
+
loadManifest(platformId) {
|
|
17
|
+
const found = this.byPlatform.get(platformId);
|
|
18
|
+
if (!found) {
|
|
19
|
+
throw new Error(`connector_manifest_not_found:${platformId}`);
|
|
20
|
+
}
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
hasCapability(platformId, intent) {
|
|
24
|
+
const manifest = this.loadManifest(platformId);
|
|
25
|
+
return manifest.supportedCapabilities.includes(intent);
|
|
26
|
+
}
|
|
27
|
+
listCapabilities(platformId) {
|
|
28
|
+
return [...this.loadManifest(platformId).supportedCapabilities];
|
|
29
|
+
}
|
|
30
|
+
listChannels(platformId) {
|
|
31
|
+
return [...this.loadManifest(platformId).channelPriority];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function parseConnectorManifest(input) {
|
|
35
|
+
return connectorManifestSchema.parse(input);
|
|
36
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type FailureClass } from "./failure-taxonomy.js";
|
|
2
|
+
import type { CapabilityIntent, ConnectorRequest, ConnectorResult, ExecutionPlan, ExecutionRunner, RoutePlanner } from "./contract.js";
|
|
3
|
+
import type { ExecutionTelemetry } from "../../observability/services/execution-telemetry.js";
|
|
4
|
+
export interface RetryPolicy {
|
|
5
|
+
maxRetries: number;
|
|
6
|
+
baseDelayMs: number;
|
|
7
|
+
maxDelayMs: number;
|
|
8
|
+
jitter: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface CooldownPort {
|
|
11
|
+
isBlocked(platformId: string, intent: CapabilityIntent): Promise<{
|
|
12
|
+
blocked: boolean;
|
|
13
|
+
retryAfterMs?: number;
|
|
14
|
+
}>;
|
|
15
|
+
markFailure(platformId: string, intent: CapabilityIntent, failureClass: FailureClass, retryAfterMs?: number): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface ConnectorPolicyContext {
|
|
18
|
+
routePlanner: RoutePlanner;
|
|
19
|
+
executionRunner: ExecutionRunner;
|
|
20
|
+
telemetry?: ExecutionTelemetry;
|
|
21
|
+
cooldownPort?: CooldownPort;
|
|
22
|
+
retryPolicy?: Partial<RetryPolicy>;
|
|
23
|
+
allowDegradedFallback?: (plan: ExecutionPlan, request: ConnectorRequest) => boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function createConnectorPolicyLayer(ctx: ConnectorPolicyContext): {
|
|
26
|
+
executeWithPolicy(intent: CapabilityIntent, request: ConnectorRequest): Promise<ConnectorResult<unknown>>;
|
|
27
|
+
};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { classifyFailure } from "./failure-taxonomy.js";
|
|
2
|
+
const DEFAULT_RETRY_MAX = 3;
|
|
3
|
+
const DEFAULT_BASE_DELAY_MS = 1000;
|
|
4
|
+
const DEFAULT_MAX_DELAY_MS = 30000;
|
|
5
|
+
function resolveRetryPolicy(input) {
|
|
6
|
+
return {
|
|
7
|
+
maxRetries: input?.maxRetries ?? DEFAULT_RETRY_MAX,
|
|
8
|
+
baseDelayMs: input?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
|
|
9
|
+
maxDelayMs: input?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
|
|
10
|
+
jitter: input?.jitter ?? true,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function computeRetryDelayMs(attempt, policy, retryAfterMs) {
|
|
14
|
+
if (typeof retryAfterMs === "number" && retryAfterMs > 0) {
|
|
15
|
+
return retryAfterMs;
|
|
16
|
+
}
|
|
17
|
+
const base = Math.min(policy.baseDelayMs * 2 ** Math.max(0, attempt - 1), policy.maxDelayMs);
|
|
18
|
+
if (!policy.jitter)
|
|
19
|
+
return base;
|
|
20
|
+
return Math.floor(base * 0.8 + Math.random() * base * 0.4);
|
|
21
|
+
}
|
|
22
|
+
async function sleep(ms) {
|
|
23
|
+
if (ms <= 0)
|
|
24
|
+
return;
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
26
|
+
}
|
|
27
|
+
function makeTraceId(request, plan) {
|
|
28
|
+
return `${request.platformId}:${request.intent}:${plan.channel}:${Date.now()}`;
|
|
29
|
+
}
|
|
30
|
+
function resolveIdentity(request) {
|
|
31
|
+
if (!request.decisionId || !request.intentId) {
|
|
32
|
+
throw new Error("connector_policy_missing_decision_or_intent_identity");
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
decisionId: request.decisionId,
|
|
36
|
+
intentId: request.intentId,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function isDegradedChannel(channel) {
|
|
40
|
+
return channel === "cli" || channel === "skill" || channel === "browser";
|
|
41
|
+
}
|
|
42
|
+
function adaptProtocolErrors(error) {
|
|
43
|
+
if (!error || typeof error !== "object") {
|
|
44
|
+
return error;
|
|
45
|
+
}
|
|
46
|
+
const record = error;
|
|
47
|
+
const detail = typeof record.detail === "string" ? record.detail : "";
|
|
48
|
+
if (detail === "node_secret_required") {
|
|
49
|
+
return { code: "verification_required", detail };
|
|
50
|
+
}
|
|
51
|
+
if (detail === "bundle_required") {
|
|
52
|
+
return { code: "protocol_mismatch", detail };
|
|
53
|
+
}
|
|
54
|
+
if (detail === "asset_id mismatch") {
|
|
55
|
+
return { code: "protocol_mismatch", detail };
|
|
56
|
+
}
|
|
57
|
+
return error;
|
|
58
|
+
}
|
|
59
|
+
export function createConnectorPolicyLayer(ctx) {
|
|
60
|
+
const retryPolicy = resolveRetryPolicy(ctx.retryPolicy);
|
|
61
|
+
const allowDegradedFallback = ctx.allowDegradedFallback ?? (() => true);
|
|
62
|
+
return {
|
|
63
|
+
async executeWithPolicy(intent, request) {
|
|
64
|
+
if (ctx.cooldownPort) {
|
|
65
|
+
const cooldown = await ctx.cooldownPort.isBlocked(request.platformId, intent);
|
|
66
|
+
if (cooldown.blocked) {
|
|
67
|
+
return {
|
|
68
|
+
status: "terminal_failure",
|
|
69
|
+
failureClass: "cooldown_blocked",
|
|
70
|
+
retryAfterMs: cooldown.retryAfterMs,
|
|
71
|
+
metadata: {
|
|
72
|
+
platformId: request.platformId,
|
|
73
|
+
channel: request.preferredChannel ?? "api_rest",
|
|
74
|
+
latencyMs: 0,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const identity = resolveIdentity(request);
|
|
80
|
+
let plan;
|
|
81
|
+
try {
|
|
82
|
+
plan = await ctx.routePlanner.planRoute(intent, request);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const failure = classifyFailure(error);
|
|
86
|
+
return {
|
|
87
|
+
status: "terminal_failure",
|
|
88
|
+
failureClass: failure.class,
|
|
89
|
+
retryAfterMs: failure.retryAfterMs,
|
|
90
|
+
metadata: {
|
|
91
|
+
platformId: request.platformId,
|
|
92
|
+
channel: request.preferredChannel ?? "api_rest",
|
|
93
|
+
latencyMs: 0,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (isDegradedChannel(plan.channel) && !allowDegradedFallback(plan, request)) {
|
|
98
|
+
return {
|
|
99
|
+
status: "terminal_failure",
|
|
100
|
+
failureClass: "protocol_mismatch",
|
|
101
|
+
metadata: {
|
|
102
|
+
platformId: request.platformId,
|
|
103
|
+
channel: plan.channel,
|
|
104
|
+
latencyMs: 0,
|
|
105
|
+
degraded: true,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
let lastFailure;
|
|
110
|
+
for (let attempt = 1; attempt <= retryPolicy.maxRetries; attempt += 1) {
|
|
111
|
+
const traceId = makeTraceId(request, plan);
|
|
112
|
+
const attemptId = `attempt-${traceId}-${attempt}`;
|
|
113
|
+
if (ctx.telemetry) {
|
|
114
|
+
await ctx.telemetry.recordExecutionAttempt({
|
|
115
|
+
id: attemptId,
|
|
116
|
+
traceId,
|
|
117
|
+
decisionId: identity.decisionId,
|
|
118
|
+
intentId: identity.intentId,
|
|
119
|
+
platformId: request.platformId,
|
|
120
|
+
capability: request.intent,
|
|
121
|
+
channel: plan.channel,
|
|
122
|
+
status: "started",
|
|
123
|
+
retryPolicy: JSON.stringify(retryPolicy),
|
|
124
|
+
idempotencyKey: request.idempotencyKey,
|
|
125
|
+
startedAt: new Date().toISOString(),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const raw = await ctx.executionRunner.run(plan, request);
|
|
129
|
+
if (raw.success) {
|
|
130
|
+
if (ctx.telemetry) {
|
|
131
|
+
await ctx.telemetry.recordExecutionAttempt({
|
|
132
|
+
id: `${attemptId}-done`,
|
|
133
|
+
traceId,
|
|
134
|
+
decisionId: identity.decisionId,
|
|
135
|
+
intentId: identity.intentId,
|
|
136
|
+
platformId: request.platformId,
|
|
137
|
+
capability: request.intent,
|
|
138
|
+
channel: plan.channel,
|
|
139
|
+
status: "succeeded",
|
|
140
|
+
retryPolicy: JSON.stringify(retryPolicy),
|
|
141
|
+
idempotencyKey: request.idempotencyKey,
|
|
142
|
+
startedAt: new Date().toISOString(),
|
|
143
|
+
finishedAt: new Date().toISOString(),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
status: "success",
|
|
148
|
+
data: raw.payload,
|
|
149
|
+
metadata: {
|
|
150
|
+
platformId: raw.platformId,
|
|
151
|
+
channel: raw.channel,
|
|
152
|
+
latencyMs: raw.latencyMs,
|
|
153
|
+
degraded: raw.degraded,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const classified = classifyFailure(adaptProtocolErrors(raw.error));
|
|
158
|
+
lastFailure = {
|
|
159
|
+
failureClass: classified.class,
|
|
160
|
+
retryAfterMs: classified.retryAfterMs,
|
|
161
|
+
channel: raw.channel,
|
|
162
|
+
};
|
|
163
|
+
if (ctx.telemetry) {
|
|
164
|
+
await ctx.telemetry.recordExecutionAttempt({
|
|
165
|
+
id: `${attemptId}-failed`,
|
|
166
|
+
traceId,
|
|
167
|
+
decisionId: identity.decisionId,
|
|
168
|
+
intentId: identity.intentId,
|
|
169
|
+
platformId: request.platformId,
|
|
170
|
+
capability: request.intent,
|
|
171
|
+
channel: plan.channel,
|
|
172
|
+
status: "failed",
|
|
173
|
+
failureClass: classified.class,
|
|
174
|
+
retryPolicy: JSON.stringify(retryPolicy),
|
|
175
|
+
idempotencyKey: request.idempotencyKey,
|
|
176
|
+
startedAt: new Date().toISOString(),
|
|
177
|
+
finishedAt: new Date().toISOString(),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (ctx.cooldownPort) {
|
|
181
|
+
await ctx.cooldownPort.markFailure(request.platformId, intent, classified.class, classified.retryAfterMs);
|
|
182
|
+
}
|
|
183
|
+
const isRetryable = classified.retryable;
|
|
184
|
+
if (!isRetryable || attempt >= retryPolicy.maxRetries) {
|
|
185
|
+
return {
|
|
186
|
+
status: "terminal_failure",
|
|
187
|
+
failureClass: classified.class,
|
|
188
|
+
retryAfterMs: classified.retryAfterMs,
|
|
189
|
+
metadata: {
|
|
190
|
+
platformId: raw.platformId,
|
|
191
|
+
channel: raw.channel,
|
|
192
|
+
latencyMs: raw.latencyMs,
|
|
193
|
+
degraded: raw.degraded,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const delay = computeRetryDelayMs(attempt, retryPolicy, classified.retryAfterMs);
|
|
198
|
+
await sleep(delay);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
status: "terminal_failure",
|
|
202
|
+
failureClass: lastFailure?.failureClass ?? "unknown_platform_change",
|
|
203
|
+
retryAfterMs: lastFailure?.retryAfterMs,
|
|
204
|
+
metadata: {
|
|
205
|
+
platformId: request.platformId,
|
|
206
|
+
channel: lastFailure?.channel ?? plan.channel,
|
|
207
|
+
latencyMs: 0,
|
|
208
|
+
degraded: isDegradedChannel(lastFailure?.channel ?? plan.channel),
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CapabilityIntent, type ConnectorRequest, type ExecutionPlan, type RouteContextPort } from "./contract.js";
|
|
2
|
+
import type { CapabilityContractRegistry } from "./manifest.js";
|
|
3
|
+
import { ChannelHealthStore } from "./channel-health.js";
|
|
4
|
+
export declare class ConnectorRoutePlanner {
|
|
5
|
+
private readonly registry;
|
|
6
|
+
private readonly statePort;
|
|
7
|
+
private readonly channelHealth;
|
|
8
|
+
constructor(registry: CapabilityContractRegistry, statePort: RouteContextPort, channelHealth: ChannelHealthStore);
|
|
9
|
+
planRoute(intent: CapabilityIntent, request: ConnectorRequest): Promise<ExecutionPlan>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ConnectorPolicyError } from "./failure-taxonomy.js";
|
|
2
|
+
const HIGH_RISK_SIDE_EFFECTS = new Set([
|
|
3
|
+
"post.publish",
|
|
4
|
+
"comment.reply",
|
|
5
|
+
"message.send",
|
|
6
|
+
"task.claim",
|
|
7
|
+
]);
|
|
8
|
+
function endpointModeFor(channel) {
|
|
9
|
+
if (channel === "a2a")
|
|
10
|
+
return "a2a_envelope";
|
|
11
|
+
if (channel === "cli")
|
|
12
|
+
return "cli_stdout";
|
|
13
|
+
if (channel === "skill" || channel === "browser")
|
|
14
|
+
return "skill_call";
|
|
15
|
+
return "rest_json";
|
|
16
|
+
}
|
|
17
|
+
const DEFAULT_DEGRADED_CHANNELS = ["cli", "skill", "browser"];
|
|
18
|
+
function isDegradedChannel(channel, degradedChannels) {
|
|
19
|
+
const policy = degradedChannels && degradedChannels.length > 0 ? degradedChannels : DEFAULT_DEGRADED_CHANNELS;
|
|
20
|
+
return policy.includes(channel);
|
|
21
|
+
}
|
|
22
|
+
function chooseByCredentialState(channels, credential) {
|
|
23
|
+
if (credential.status === "pending_verification") {
|
|
24
|
+
if (channels.includes("skill"))
|
|
25
|
+
return "skill";
|
|
26
|
+
if (channels.includes("browser"))
|
|
27
|
+
return "browser";
|
|
28
|
+
throw new ConnectorPolicyError("verification_required", "verification_recovery_channel_missing");
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function choosePreferred(channels, preferred) {
|
|
33
|
+
if (preferred && channels.includes(preferred))
|
|
34
|
+
return preferred;
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
function chooseHealthy(channels, platformId, health) {
|
|
38
|
+
for (const channel of channels) {
|
|
39
|
+
const snapshot = health.get(platformId, channel);
|
|
40
|
+
if (!snapshot)
|
|
41
|
+
return channel;
|
|
42
|
+
if (snapshot.healthy && !snapshot.degraded)
|
|
43
|
+
return channel;
|
|
44
|
+
if (snapshot.healthy)
|
|
45
|
+
return channel;
|
|
46
|
+
}
|
|
47
|
+
return channels[0];
|
|
48
|
+
}
|
|
49
|
+
function enforceSideEffectSafety(intent, channel, degradedChannels) {
|
|
50
|
+
if (!HIGH_RISK_SIDE_EFFECTS.has(intent)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isDegradedChannel(channel, degradedChannels)) {
|
|
54
|
+
throw new ConnectorPolicyError("protocol_mismatch", "degraded_channel_not_allowed_for_side_effect");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export class ConnectorRoutePlanner {
|
|
58
|
+
registry;
|
|
59
|
+
statePort;
|
|
60
|
+
channelHealth;
|
|
61
|
+
constructor(registry, statePort, channelHealth) {
|
|
62
|
+
this.registry = registry;
|
|
63
|
+
this.statePort = statePort;
|
|
64
|
+
this.channelHealth = channelHealth;
|
|
65
|
+
}
|
|
66
|
+
async planRoute(intent, request) {
|
|
67
|
+
const manifest = this.registry.loadManifest(request.platformId);
|
|
68
|
+
if (!manifest.supportedCapabilities.includes(intent)) {
|
|
69
|
+
throw new ConnectorPolicyError("protocol_mismatch", "capability_not_supported_by_manifest");
|
|
70
|
+
}
|
|
71
|
+
const cooldown = await this.statePort.loadCooldownState(request.platformId, intent);
|
|
72
|
+
if (cooldown.blocked) {
|
|
73
|
+
throw new ConnectorPolicyError("cooldown_blocked", "platform_or_intent_cooldown_blocked", cooldown.retryAfterMs);
|
|
74
|
+
}
|
|
75
|
+
const credential = await this.statePort.loadCredentialState(request.platformId);
|
|
76
|
+
if (credential.status === "missing" || credential.status === "revoked" || credential.status === "failed") {
|
|
77
|
+
throw new ConnectorPolicyError("auth_failure", "credential_unavailable_for_route");
|
|
78
|
+
}
|
|
79
|
+
if (credential.status === "expired") {
|
|
80
|
+
throw new ConnectorPolicyError("credential_expired", "credential_expired_for_route");
|
|
81
|
+
}
|
|
82
|
+
const channels = [...manifest.channelPriority];
|
|
83
|
+
const byCredential = chooseByCredentialState(channels, credential);
|
|
84
|
+
const preferred = choosePreferred(channels, request.preferredChannel);
|
|
85
|
+
const selected = byCredential ?? preferred ?? chooseHealthy(channels, request.platformId, this.channelHealth);
|
|
86
|
+
if (!selected) {
|
|
87
|
+
throw new ConnectorPolicyError("protocol_mismatch", "no_available_channel");
|
|
88
|
+
}
|
|
89
|
+
enforceSideEffectSafety(intent, selected, manifest.degradedChannels);
|
|
90
|
+
return {
|
|
91
|
+
platformId: request.platformId,
|
|
92
|
+
intent,
|
|
93
|
+
channel: selected,
|
|
94
|
+
endpointMode: endpointModeFor(selected),
|
|
95
|
+
idempotencyKey: request.idempotencyKey,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CredentialContext } from "../../../shared/types/credential.js";
|
|
2
|
+
import type { ConnectorRequest, ExecutionPlan, RawAttempt } from "../../base/contract.js";
|
|
3
|
+
export interface InStreetApiClient {
|
|
4
|
+
listNotifications(payload: Record<string, unknown>, apiKey: string): Promise<unknown>;
|
|
5
|
+
sendMessage(payload: Record<string, unknown>, apiKey: string): Promise<unknown>;
|
|
6
|
+
replyComment(payload: Record<string, unknown>, apiKey: string): Promise<unknown>;
|
|
7
|
+
heartbeat(apiKey: string): Promise<unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface InStreetSkillRunner {
|
|
10
|
+
resumeVerification(ctx: CredentialContext): Promise<{
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
status: "active" | "failed";
|
|
13
|
+
}>;
|
|
14
|
+
run(intent: ExecutionPlan["intent"], payload: Record<string, unknown>, context: {
|
|
15
|
+
credential: CredentialContext;
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
}): Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface InStreetCredentialPort {
|
|
20
|
+
loadCredentialState(platformId: string): Promise<CredentialContext>;
|
|
21
|
+
persistVerificationOutcome(platformId: string, outcome: {
|
|
22
|
+
status: "active" | "failed";
|
|
23
|
+
apiKey?: string;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createInStreetRunner(input: {
|
|
27
|
+
apiClient: InStreetApiClient;
|
|
28
|
+
credentialPort: InStreetCredentialPort;
|
|
29
|
+
skillRunner: InStreetSkillRunner;
|
|
30
|
+
}): {
|
|
31
|
+
run(plan: ExecutionPlan, request: ConnectorRequest): Promise<RawAttempt>;
|
|
32
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export function createInStreetRunner(input) {
|
|
2
|
+
const { apiClient, credentialPort, skillRunner } = input;
|
|
3
|
+
return {
|
|
4
|
+
async run(plan, request) {
|
|
5
|
+
const started = Date.now();
|
|
6
|
+
try {
|
|
7
|
+
const credential = await credentialPort.loadCredentialState(request.platformId);
|
|
8
|
+
const apiKey = await ensureActiveApiKey(request.platformId, credential, credentialPort, skillRunner, plan.channel);
|
|
9
|
+
const payload = await executeInStreet(plan, request.payload, apiClient, skillRunner, credential, apiKey);
|
|
10
|
+
return {
|
|
11
|
+
platformId: request.platformId,
|
|
12
|
+
channel: plan.channel,
|
|
13
|
+
latencyMs: Date.now() - started,
|
|
14
|
+
degraded: plan.channel === "skill" || plan.channel === "browser",
|
|
15
|
+
success: true,
|
|
16
|
+
payload: {
|
|
17
|
+
capability: request.intent,
|
|
18
|
+
channel: plan.channel,
|
|
19
|
+
data: payload,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
platformId: request.platformId,
|
|
26
|
+
channel: plan.channel,
|
|
27
|
+
latencyMs: Date.now() - started,
|
|
28
|
+
degraded: plan.channel === "skill" || plan.channel === "browser",
|
|
29
|
+
success: false,
|
|
30
|
+
error,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function ensureActiveApiKey(platformId, credential, credentialPort, skillRunner, channel) {
|
|
37
|
+
if (credential.status === "pending_verification") {
|
|
38
|
+
if (channel !== "skill" && channel !== "browser") {
|
|
39
|
+
throw { code: "verification_required", detail: "instreet verification requires skill_or_browser channel" };
|
|
40
|
+
}
|
|
41
|
+
const outcome = await skillRunner.resumeVerification(credential);
|
|
42
|
+
await credentialPort.persistVerificationOutcome(platformId, {
|
|
43
|
+
status: outcome.status,
|
|
44
|
+
apiKey: outcome.apiKey,
|
|
45
|
+
});
|
|
46
|
+
if (outcome.status !== "active") {
|
|
47
|
+
throw { code: "verification_required", detail: "instreet verification still pending" };
|
|
48
|
+
}
|
|
49
|
+
if (!outcome.apiKey) {
|
|
50
|
+
throw { code: "auth_failure", detail: "instreet verification returned active_without_api_key" };
|
|
51
|
+
}
|
|
52
|
+
return outcome.apiKey;
|
|
53
|
+
}
|
|
54
|
+
if (credential.status !== "active" || !credential.encryptedValue) {
|
|
55
|
+
throw { code: "auth_failure", detail: `instreet credential not active: ${credential.status}` };
|
|
56
|
+
}
|
|
57
|
+
return credential.encryptedValue;
|
|
58
|
+
}
|
|
59
|
+
async function executeInStreet(plan, payload, apiClient, skillRunner, credential, apiKey) {
|
|
60
|
+
if (plan.channel !== "api_rest" && plan.channel !== "skill" && plan.channel !== "browser") {
|
|
61
|
+
throw { code: "protocol_mismatch", detail: `unsupported instreet channel: ${plan.channel}` };
|
|
62
|
+
}
|
|
63
|
+
if (plan.channel === "skill" || plan.channel === "browser") {
|
|
64
|
+
return skillRunner.run(plan.intent, payload, { credential, apiKey });
|
|
65
|
+
}
|
|
66
|
+
if (plan.intent === "notification.list") {
|
|
67
|
+
return apiClient.listNotifications(payload, apiKey);
|
|
68
|
+
}
|
|
69
|
+
if (plan.intent === "message.send") {
|
|
70
|
+
return apiClient.sendMessage(payload, apiKey);
|
|
71
|
+
}
|
|
72
|
+
if (plan.intent === "comment.reply") {
|
|
73
|
+
return apiClient.replyComment(payload, apiKey);
|
|
74
|
+
}
|
|
75
|
+
if (plan.intent === "agent.heartbeat") {
|
|
76
|
+
return apiClient.heartbeat(apiKey);
|
|
77
|
+
}
|
|
78
|
+
throw { code: "protocol_mismatch", detail: `unsupported instreet intent: ${plan.intent}` };
|
|
79
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const instreetManifest = {
|
|
2
|
+
platformId: "instreet",
|
|
3
|
+
supportedCapabilities: ["notification.list", "message.send", "comment.reply", "agent.heartbeat"],
|
|
4
|
+
channelPriority: ["api_rest", "skill", "browser"],
|
|
5
|
+
credentialTypes: ["api_key", "verification_code"],
|
|
6
|
+
degradedChannels: ["skill", "browser"],
|
|
7
|
+
};
|