@directive-run/knowledge 1.23.0 → 1.23.1
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/ai/ai-security.md +2 -2
- package/examples/cloudflare-directive-ai.ts +178 -0
- package/package.json +4 -4
- package/sitemap.md +9 -0
package/ai/ai-security.md
CHANGED
|
@@ -388,8 +388,8 @@ source publishes PII into a fact and the agent's prompt template embeds
|
|
|
388
388
|
that fact (`"Hello ${facts.email}..."`), the PII reaches the LLM call
|
|
389
389
|
without hitting the input guardrail chain.
|
|
390
390
|
|
|
391
|
-
This is
|
|
392
|
-
|
|
391
|
+
This is a documented gap in the input-only guardrail chain — the fix
|
|
392
|
+
is a fact-store-boundary guardrail that runs on every fact write:
|
|
393
393
|
|
|
394
394
|
```ts
|
|
395
395
|
import { createSystem, createModule, t } from "@directive-run/core";
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Example: cloudflare-directive-ai
|
|
2
|
+
// Source: examples/cloudflare-directive-ai/src/module.ts
|
|
3
|
+
// Pure module file — no DOM wiring
|
|
4
|
+
|
|
5
|
+
import { createModule, createSystem } from "@directive-run/core";
|
|
6
|
+
import { sourceFromDOAlarm } from "@directive-run/sources/cloudflare";
|
|
7
|
+
import { schema, type PublishingStatus } from "./schema.js";
|
|
8
|
+
import type { AuditLog, Broadcaster } from "./deps.js";
|
|
9
|
+
import { createPublishingChain, type PublishingChain } from "./agents.js";
|
|
10
|
+
|
|
11
|
+
export interface PublishingDeps {
|
|
12
|
+
auditLog: AuditLog;
|
|
13
|
+
broadcaster: Broadcaster;
|
|
14
|
+
anthropicApiKey: string;
|
|
15
|
+
storage: DurableObjectStorage;
|
|
16
|
+
intervalMs?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PublishingModuleHandle {
|
|
20
|
+
alarmTick: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function createPublishingSystem(deps: PublishingDeps) {
|
|
24
|
+
const chain = createPublishingChain(deps.anthropicApiKey);
|
|
25
|
+
const handle: PublishingModuleHandle = {
|
|
26
|
+
alarmTick: () => {},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const alarmSource = sourceFromDOAlarm({
|
|
30
|
+
storage: deps.storage,
|
|
31
|
+
intervalMs: deps.intervalMs ?? 5 * 60 * 1000,
|
|
32
|
+
eventName: "tick",
|
|
33
|
+
payload: () => ({}),
|
|
34
|
+
onTickRegistered: (tick) => {
|
|
35
|
+
handle.alarmTick = tick;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const publishingModule = createModule("publishing", {
|
|
40
|
+
schema,
|
|
41
|
+
|
|
42
|
+
init: (facts) => {
|
|
43
|
+
facts.status = "idle" satisfies PublishingStatus;
|
|
44
|
+
facts.currentArticle = {};
|
|
45
|
+
facts.ingestQueue = [];
|
|
46
|
+
facts.reviewQueue = [];
|
|
47
|
+
facts.errorLog = [];
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
derive: {
|
|
51
|
+
queueDepth: (facts) => facts.ingestQueue.length,
|
|
52
|
+
reviewDepth: (facts) => facts.reviewQueue.length,
|
|
53
|
+
isReadyToAggregate: (facts) =>
|
|
54
|
+
facts.ingestQueue.length >= 3 && facts.status === "idle",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
events: {
|
|
58
|
+
ingest: (facts, payload) => {
|
|
59
|
+
facts.ingestQueue = [
|
|
60
|
+
...facts.ingestQueue,
|
|
61
|
+
{ url: payload.url, capturedAt: new Date().toISOString() },
|
|
62
|
+
];
|
|
63
|
+
},
|
|
64
|
+
tick: (facts) => {
|
|
65
|
+
if (facts.status === "failed" || facts.status === "published") {
|
|
66
|
+
facts.status = "idle";
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
sources: {
|
|
72
|
+
alarm: alarmSource,
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
constraints: {
|
|
76
|
+
startAggregation: {
|
|
77
|
+
priority: 100,
|
|
78
|
+
when: (facts) =>
|
|
79
|
+
facts.ingestQueue.length >= 3 && facts.status === "idle",
|
|
80
|
+
require: (facts) => ({
|
|
81
|
+
type: "RUN_PUBLISHING_CHAIN",
|
|
82
|
+
sources: facts.ingestQueue.slice(0, 8),
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
routeArticle: {
|
|
87
|
+
priority: 90,
|
|
88
|
+
when: (facts) => facts.status === "reviewing",
|
|
89
|
+
require: (facts) => ({
|
|
90
|
+
type: "ROUTE_ARTICLE",
|
|
91
|
+
article: facts.currentArticle,
|
|
92
|
+
}),
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
resolvers: {
|
|
97
|
+
runChain: {
|
|
98
|
+
requirement: "RUN_PUBLISHING_CHAIN",
|
|
99
|
+
key: (req) => `chain-${req.sources.map((s) => s.url).join("|")}`,
|
|
100
|
+
resolve: async (req, context) => {
|
|
101
|
+
context.facts.status = "aggregating";
|
|
102
|
+
context.facts.ingestQueue = context.facts.ingestQueue.slice(
|
|
103
|
+
req.sources.length,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await chain.run(req.sources, "demo");
|
|
108
|
+
|
|
109
|
+
context.facts.currentArticle = result;
|
|
110
|
+
context.facts.status = "reviewing";
|
|
111
|
+
await deps.auditLog.append({
|
|
112
|
+
event: "chain-completed",
|
|
113
|
+
at: new Date().toISOString(),
|
|
114
|
+
sources: req.sources.length,
|
|
115
|
+
confidence: result.confidence,
|
|
116
|
+
slug: result.slug,
|
|
117
|
+
});
|
|
118
|
+
} catch (err) {
|
|
119
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
120
|
+
context.facts.errorLog = [
|
|
121
|
+
...context.facts.errorLog,
|
|
122
|
+
{
|
|
123
|
+
at: new Date().toISOString(),
|
|
124
|
+
source: "publishing-chain",
|
|
125
|
+
message,
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
context.facts.status = "failed";
|
|
129
|
+
await deps.auditLog.append({
|
|
130
|
+
event: "chain-failed",
|
|
131
|
+
at: new Date().toISOString(),
|
|
132
|
+
error: message,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
routeArticle: {
|
|
139
|
+
requirement: "ROUTE_ARTICLE",
|
|
140
|
+
key: (req) => `route-${req.article.slug ?? "unknown"}`,
|
|
141
|
+
resolve: async (req, context) => {
|
|
142
|
+
const confidence = req.article.confidence ?? 0;
|
|
143
|
+
const slug = req.article.slug ?? "unknown";
|
|
144
|
+
|
|
145
|
+
if (confidence >= 0.85) {
|
|
146
|
+
await deps.broadcaster.send(req.article);
|
|
147
|
+
context.facts.status = "published";
|
|
148
|
+
await deps.auditLog.append({
|
|
149
|
+
event: "auto-published",
|
|
150
|
+
at: new Date().toISOString(),
|
|
151
|
+
slug,
|
|
152
|
+
confidence,
|
|
153
|
+
});
|
|
154
|
+
} else {
|
|
155
|
+
context.facts.reviewQueue = [
|
|
156
|
+
...context.facts.reviewQueue,
|
|
157
|
+
{ articleId: slug, confidence },
|
|
158
|
+
];
|
|
159
|
+
context.facts.status = "idle";
|
|
160
|
+
await deps.auditLog.append({
|
|
161
|
+
event: "routed-to-review",
|
|
162
|
+
at: new Date().toISOString(),
|
|
163
|
+
slug,
|
|
164
|
+
confidence,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const system = createSystem({ module: publishingModule });
|
|
173
|
+
|
|
174
|
+
return { system, handle };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export type PublishingSystem = ReturnType<typeof createPublishingSystem>;
|
|
178
|
+
export type { PublishingChain };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directive-run/knowledge",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.1",
|
|
4
4
|
"description": "Knowledge files, examples, and validation for Directive — the constraint-driven TypeScript runtime.",
|
|
5
5
|
"license": "(MIT OR Apache-2.0)",
|
|
6
6
|
"author": "Jason Comes",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"tsup": "^8.3.5",
|
|
53
53
|
"tsx": "^4.19.2",
|
|
54
54
|
"typescript": "^5.7.2",
|
|
55
|
-
"vitest": "^3.
|
|
56
|
-
"@directive-run/core": "1.23.
|
|
57
|
-
"@directive-run/ai": "1.23.
|
|
55
|
+
"vitest": "^3.2.6",
|
|
56
|
+
"@directive-run/core": "1.23.1",
|
|
57
|
+
"@directive-run/ai": "1.23.1"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "tsx scripts/generate-api-skeleton.ts && tsx scripts/generate-sitemap.ts && tsx scripts/extract-examples.ts && tsup",
|
package/sitemap.md
CHANGED
|
@@ -86,6 +86,7 @@ Website: https://directive.run
|
|
|
86
86
|
- [Persistence](https://directive.run/docs/plugins/persistence)
|
|
87
87
|
- [Performance](https://directive.run/docs/plugins/performance)
|
|
88
88
|
- [Circuit Breaker](https://directive.run/docs/plugins/circuit-breaker)
|
|
89
|
+
- [Clobber Loop Detector](https://directive.run/docs/plugins/clobber-loop)
|
|
89
90
|
- [Observability](https://directive.run/docs/plugins/observability)
|
|
90
91
|
- [Custom Plugins](https://directive.run/docs/plugins/custom)
|
|
91
92
|
|
|
@@ -108,6 +109,14 @@ Website: https://directive.run
|
|
|
108
109
|
- [Resolver Binding](https://directive.run/docs/resolver-binding)
|
|
109
110
|
- [Audit Ledger](https://directive.run/docs/audit-ledger)
|
|
110
111
|
|
|
112
|
+
### Broadcast
|
|
113
|
+
- [Overview](https://directive.run/docs/broadcast)
|
|
114
|
+
- [GitHub Action](https://directive.run/docs/broadcast/action)
|
|
115
|
+
- [CLI](https://directive.run/docs/broadcast/cli)
|
|
116
|
+
- [Cloudflare Worker](https://directive.run/docs/broadcast/worker)
|
|
117
|
+
- [MCP server](https://directive.run/docs/broadcast/mcp)
|
|
118
|
+
- [README badge](https://directive.run/docs/broadcast/badge)
|
|
119
|
+
|
|
111
120
|
### Examples
|
|
112
121
|
- [Number Match](https://directive.run/docs/examples/counter)
|
|
113
122
|
- [Auth Flow](https://directive.run/docs/examples/auth-flow)
|