odai-dsh-agent 0.2.1 → 0.2.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.
Files changed (51) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +138 -138
  3. package/bin/odai-dsh-agent.mjs +108 -108
  4. package/package.json +69 -69
  5. package/preset/odai/agent.cordis.yml +260 -260
  6. package/preset/odai/preset.yml +3 -3
  7. package/preset/odai/runtime/compaction-config.mjs +388 -388
  8. package/preset/odai/runtime/governance.mjs +128 -128
  9. package/preset/odai/runtime/index.mjs +2461 -2263
  10. package/preset/odai/runtime/output-config.mjs +360 -304
  11. package/preset/odai/runtime/research-packet.mjs +150 -150
  12. package/preset/odai/runtime/responsibility-scope.mjs +35 -2
  13. package/preset/odai/runtime/role-overlays.mjs +27 -27
  14. package/preset/odai/runtime/route-card.mjs +168 -152
  15. package/preset/odai/runtime/router.mjs +683 -651
  16. package/preset/odai/runtime/routing-config.mjs +480 -436
  17. package/preset/odai/runtime/routing-context.mjs +321 -321
  18. package/preset/odai/runtime/semantic-memory-store.mjs +452 -452
  19. package/preset/odai/runtime/semantic-memory.mjs +842 -842
  20. package/preset/odai/runtime/session-compat.mjs +389 -389
  21. package/preset/odai/runtime/skill-bundle.mjs +318 -318
  22. package/preset/odai/runtime/skill-evolution.mjs +1413 -1413
  23. package/preset/odai/skills/odai/agents/openai.yaml +4 -4
  24. package/preset/odai/skills/odai/assets/claude-agents/agent.md +11 -11
  25. package/preset/odai/skills/odai/assets/codex-agents/config.toml +11 -11
  26. package/preset/odai/skills/odai/assets/codex-agents/role.toml +5 -5
  27. package/preset/odai/skills/odai/assets/copilot-agents/agent.md +13 -13
  28. package/preset/odai/skills/odai/assets/hooks-policy.example.json +24 -24
  29. package/preset/odai/skills/odai/assets/routing-roles/controller.md +15 -15
  30. package/preset/odai/skills/odai/assets/routing-roles/executor.md +11 -11
  31. package/preset/odai/skills/odai/assets/routing-roles/frontend.md +7 -7
  32. package/preset/odai/skills/odai/assets/routing-roles/planner.md +29 -29
  33. package/preset/odai/skills/odai/assets/routing-roles/researcher.md +6 -6
  34. package/preset/odai/skills/odai/assets/routing-roles/reviewer.md +11 -11
  35. package/preset/odai/skills/odai/assets/task-state.md +14 -14
  36. package/preset/odai/skills/odai/manifest.json +37 -37
  37. package/preset/odai/skills/odai/references/craft.md +54 -54
  38. package/preset/odai/skills/odai/references/dao.md +30 -30
  39. package/preset/odai/skills/odai/references/leverage.md +53 -53
  40. package/preset/odai/skills/odai/references/planning.md +82 -82
  41. package/preset/odai/skills/odai/references/support.md +36 -36
  42. package/preset/odai/skills/odai/references/verification.md +23 -23
  43. package/preset/odai/skills/odai/scripts/build-hooks.mjs +273 -273
  44. package/preset/odai/skills/odai/scripts/build-routing.mjs +274 -274
  45. package/preset/odai/skills/odai/scripts/install-routing.mjs +397 -397
  46. package/preset/odai/skills/odai/scripts/odai-hook.mjs +457 -457
  47. package/preset/odai/skills/odai/scripts/run-role.mjs +336 -336
  48. package/preset/odai/skills/odai/scripts/run-routing.mjs +1154 -1154
  49. package/preset/odai/skills/odai/scripts/verify-routing.mjs +103 -103
  50. package/scripts/verify-agent-load.mjs +257 -257
  51. package/src/installer.mjs +382 -382
@@ -1,152 +1,168 @@
1
- import { randomUUID } from "node:crypto";
2
-
3
- export const ROUTE_CARD_PROMPT = [
4
- "## Odai frozen route cards",
5
- "Use odai_route_card only after planning has frozen a concrete implementation boundary and executor separation has an observable net benefit.",
6
- "After the canonical executor reassessment proves observable net benefit, freeze the card before implementation continues. Otherwise continue directly without a card or process narration.",
7
- "A card must preserve the target, decisive evidence, allowed and forbidden scope, acceptance conditions, and stop condition. Do not freeze a card merely because an executor model is configured or cheaper.",
8
- "The controller owns the card. Child agents may not create, replace, or clear it. A card is claimed for one executor attempt and consumed only after an applied executor route receipt; validation, provider, or receipt failure releases the claim for retry.",
9
- "When the original current task already authorizes implementation, a planner that freezes a card must submit an executor responsibility gap so implementation continues automatically in the same user task. Ask the user only for a new task, plan-only request, changed scope, or missing user-owned authorization.",
10
- ].join("\n");
11
-
12
- function nonEmptyString(value, field) {
13
- if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${field} must be a non-empty string`);
14
- return value.trim();
15
- }
16
-
17
- function stringList(value, field, minimum = 0) {
18
- if (!Array.isArray(value) || value.length < minimum) {
19
- throw new TypeError(`${field} must be an array with at least ${minimum} item${minimum === 1 ? "" : "s"}`);
20
- }
21
- return Object.freeze(value.map((item, index) => nonEmptyString(item, `${field}[${index}]`)));
22
- }
23
-
24
- function normalizeAuthorization(value) {
25
- const status = value?.status;
26
- if (!["authorized", "plan-only", "unknown"].includes(status)) return Object.freeze({ status: "unknown" });
27
- const userMessageId = typeof value.userMessageId === "string" && value.userMessageId.length > 0 && value.userMessageId.length <= 200
28
- ? value.userMessageId
29
- : undefined;
30
- return Object.freeze({ status, ...(userMessageId ? { userMessageId } : {}) });
31
- }
32
-
33
- function normalizeCard(args, authorization) {
34
- if (args.observableBenefit !== true) {
35
- throw new TypeError("observableBenefit must be true before freezing an executor route card");
36
- }
37
- return Object.freeze({
38
- id: randomUUID(),
39
- frozen: true,
40
- observableBenefit: true,
41
- authorization: normalizeAuthorization(authorization),
42
- target: nonEmptyString(args.target, "target"),
43
- evidence: stringList(args.evidence, "evidence", 1),
44
- scope: stringList(args.scope, "scope", 1),
45
- accept: stringList(args.accept, "accept", 1),
46
- stop: nonEmptyString(args.stop, "stop"),
47
- });
48
- }
49
-
50
- function routeCardInState(events, acceptedStates) {
51
- const latestState = new Map();
52
- for (let index = (Array.isArray(events) ? events.length : 0) - 1; index >= 0; index -= 1) {
53
- const event = events[index];
54
- const cardId = event?.data?.cardId;
55
- if (typeof cardId === "string" && !latestState.has(cardId)) {
56
- if (event.type === "odai/route-card-claim-released") latestState.set(cardId, "active");
57
- else if (event.type === "odai/route-card-claimed") latestState.set(cardId, "claimed");
58
- else if (["odai/route-card-cleared", "odai/route-card-consumed"].includes(event.type)) latestState.set(cardId, "closed");
59
- }
60
- if (event?.type !== "odai/route-card-frozen") continue;
61
- const card = event.data?.card;
62
- if (card?.frozen !== true || typeof card.id !== "string") continue;
63
- const state = latestState.get(card.id) ?? "active";
64
- if (acceptedStates.has(state)) return card;
65
- }
66
- return undefined;
67
- }
68
-
69
- export function activeRouteCard(events) {
70
- return routeCardInState(events, new Set(["active"]));
71
- }
72
-
73
- export function unsettledRouteCard(events) {
74
- return routeCardInState(events, new Set(["active", "claimed"]));
75
- }
76
-
77
- export function createRouteCardTool(options = {}) {
78
- const onFrozen = typeof options.onFrozen === "function" ? options.onFrozen : () => {};
79
- const onCleared = typeof options.onCleared === "function" ? options.onCleared : () => {};
80
- const activeFor = typeof options.activeFor === "function" ? options.activeFor : () => undefined;
81
- const unsettledFor = typeof options.unsettledFor === "function" ? options.unsettledFor : activeFor;
82
- const authorizationFor = typeof options.authorizationFor === "function"
83
- ? options.authorizationFor
84
- : () => Object.freeze({ status: "unknown" });
85
- return {
86
- name: "odai_route_card",
87
- description: "Freeze or clear one structured executor route card. Use only when planning has bounded implementation and independently justified executor separation.",
88
- parameters: {
89
- type: "object",
90
- additionalProperties: false,
91
- required: ["action"],
92
- properties: {
93
- action: { type: "string", enum: ["freeze", "clear"] },
94
- target: { type: "string" },
95
- evidence: { type: "array", items: { type: "string" } },
96
- scope: { type: "array", items: { type: "string" } },
97
- accept: { type: "array", items: { type: "string" } },
98
- stop: { type: "string" },
99
- observableBenefit: { type: "boolean" },
100
- cardId: { type: "string" },
101
- },
102
- },
103
- output: {
104
- schema: {
105
- type: "object",
106
- additionalProperties: false,
107
- required: ["action", "status"],
108
- properties: {
109
- action: { type: "string", enum: ["freeze", "clear"] },
110
- status: { type: "string", enum: ["frozen", "cleared", "absent"] },
111
- card: { type: "object" },
112
- cardId: { type: "string" },
113
- },
114
- },
115
- render(_args, value) {
116
- return [{
117
- type: "text",
118
- text: value.status === "frozen"
119
- ? `Frozen executor route card ${value.card.id}: ${value.card.target}`
120
- : value.status === "cleared"
121
- ? `Cleared executor route card ${value.cardId}.`
122
- : "No active executor route card exists.",
123
- }];
124
- },
125
- },
126
- execute(args, execution) {
127
- if (!execution.agent) throw new Error("odai_route_card requires an owning agent session");
128
- const header = execution.agent.session?.header;
129
- if (header?.origin === "subagent" || (Number.isSafeInteger(header?.delegationDepth) && header.delegationDepth > 0)) {
130
- throw new Error("child agents may not change Odai route cards");
131
- }
132
- if (!args || typeof args !== "object" || Array.isArray(args)) throw new TypeError("arguments must be an object");
133
- if (args.action === "freeze") {
134
- const active = unsettledFor(execution.agent);
135
- if (active) throw new Error(`executor route card ${active.id} is already active or claimed`);
136
- const card = normalizeCard(args, authorizationFor(execution.agent));
137
- onFrozen(execution.agent, card);
138
- return Promise.resolve(Object.freeze({ action: "freeze", status: "frozen", card }));
139
- }
140
- if (args.action === "clear") {
141
- const card = activeFor(execution.agent);
142
- if (!card) return Promise.resolve(Object.freeze({ action: "clear", status: "absent" }));
143
- if (args.cardId !== undefined && args.cardId !== card.id) {
144
- throw new Error(`route card ${args.cardId} does not match active card ${card.id}`);
145
- }
146
- onCleared(execution.agent, card.id);
147
- return Promise.resolve(Object.freeze({ action: "clear", status: "cleared", cardId: card.id }));
148
- }
149
- throw new TypeError("action must be freeze or clear");
150
- },
151
- };
152
- }
1
+ import { randomUUID } from "node:crypto";
2
+
3
+ export const ROUTE_CARD_PROMPT = [
4
+ "## Odai frozen route cards",
5
+ "Use odai_route_card only after planning has frozen a concrete implementation boundary and executor separation has an observable net benefit.",
6
+ "After the canonical executor reassessment proves observable net benefit, freeze the card before implementation continues. Otherwise continue directly without a card or process narration.",
7
+ "A card must preserve the target, decisive evidence, allowed and forbidden scope, acceptance conditions, and stop condition. Do not freeze a card merely because an executor model is configured or cheaper.",
8
+ "The controller owns the card. Child agents may not create, replace, or clear it. A card is claimed for one executor attempt and consumed only after an applied executor route receipt; validation, provider, or receipt failure releases the claim for retry. A verified provider max-token interruption may reclaim that same card only after a direct user continuation, without changing its scope or authorization. A later explicit clear is terminal and cannot be undone by a delayed release.",
9
+ "When the original current task already authorizes implementation, a planner that freezes a card must submit an executor responsibility gap so implementation continues automatically in the same user task. Ask the user only for a new task, plan-only request, changed scope, or missing user-owned authorization.",
10
+ ].join("\n");
11
+
12
+ function nonEmptyString(value, field) {
13
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${field} must be a non-empty string`);
14
+ return value.trim();
15
+ }
16
+
17
+ function stringList(value, field, minimum = 0) {
18
+ if (!Array.isArray(value) || value.length < minimum) {
19
+ throw new TypeError(`${field} must be an array with at least ${minimum} item${minimum === 1 ? "" : "s"}`);
20
+ }
21
+ return Object.freeze(value.map((item, index) => nonEmptyString(item, `${field}[${index}]`)));
22
+ }
23
+
24
+ function normalizeAuthorization(value) {
25
+ const status = value?.status;
26
+ if (!["authorized", "plan-only", "unknown"].includes(status)) return Object.freeze({ status: "unknown" });
27
+ const userMessageId = typeof value.userMessageId === "string" && value.userMessageId.length > 0 && value.userMessageId.length <= 200
28
+ ? value.userMessageId
29
+ : undefined;
30
+ return Object.freeze({ status, ...(userMessageId ? { userMessageId } : {}) });
31
+ }
32
+
33
+ function normalizeCard(args, authorization) {
34
+ if (args.observableBenefit !== true) {
35
+ throw new TypeError("observableBenefit must be true before freezing an executor route card");
36
+ }
37
+ return Object.freeze({
38
+ id: randomUUID(),
39
+ frozen: true,
40
+ observableBenefit: true,
41
+ authorization: normalizeAuthorization(authorization),
42
+ target: nonEmptyString(args.target, "target"),
43
+ evidence: stringList(args.evidence, "evidence", 1),
44
+ scope: stringList(args.scope, "scope", 1),
45
+ accept: stringList(args.accept, "accept", 1),
46
+ stop: nonEmptyString(args.stop, "stop"),
47
+ });
48
+ }
49
+
50
+ function routeCardInState(events, acceptedStates) {
51
+ const source = Array.isArray(events) ? events : [];
52
+ const permanentlyCleared = new Set(source.flatMap((event) => (
53
+ event?.type === "odai/route-card-cleared" && typeof event.data?.cardId === "string"
54
+ ? [event.data.cardId]
55
+ : []
56
+ )));
57
+ const latestState = new Map();
58
+ for (let index = source.length - 1; index >= 0; index -= 1) {
59
+ const event = source[index];
60
+ const cardId = event?.data?.cardId;
61
+ if (typeof cardId === "string" && !latestState.has(cardId)) {
62
+ if (event.type === "odai/route-card-claim-released") latestState.set(cardId, "active");
63
+ else if (event.type === "odai/route-card-claimed") latestState.set(cardId, "claimed");
64
+ else if (["odai/route-card-cleared", "odai/route-card-consumed"].includes(event.type)) latestState.set(cardId, "closed");
65
+ }
66
+ if (event?.type !== "odai/route-card-frozen") continue;
67
+ const card = event.data?.card;
68
+ if (card?.frozen !== true || typeof card.id !== "string") continue;
69
+ const state = permanentlyCleared.has(card.id) ? "closed" : (latestState.get(card.id) ?? "active");
70
+ if (acceptedStates.has(state)) return card;
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ export function activeRouteCard(events) {
76
+ return routeCardInState(events, new Set(["active"]));
77
+ }
78
+
79
+ export function unsettledRouteCard(events) {
80
+ return routeCardInState(events, new Set(["active", "claimed"]));
81
+ }
82
+
83
+ export function routeCardById(events, cardId) {
84
+ if (typeof cardId !== "string" || cardId === "") return undefined;
85
+ for (let index = (Array.isArray(events) ? events.length : 0) - 1; index >= 0; index -= 1) {
86
+ const event = events[index];
87
+ const card = event?.data?.card;
88
+ if (event?.type === "odai/route-card-frozen" && card?.id === cardId && card.frozen === true) return card;
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ export function createRouteCardTool(options = {}) {
94
+ const onFrozen = typeof options.onFrozen === "function" ? options.onFrozen : () => {};
95
+ const onCleared = typeof options.onCleared === "function" ? options.onCleared : () => {};
96
+ const activeFor = typeof options.activeFor === "function" ? options.activeFor : () => undefined;
97
+ const unsettledFor = typeof options.unsettledFor === "function" ? options.unsettledFor : activeFor;
98
+ const authorizationFor = typeof options.authorizationFor === "function"
99
+ ? options.authorizationFor
100
+ : () => Object.freeze({ status: "unknown" });
101
+ return {
102
+ name: "odai_route_card",
103
+ description: "Freeze or clear one structured executor route card. Use only when planning has bounded implementation and independently justified executor separation.",
104
+ parameters: {
105
+ type: "object",
106
+ additionalProperties: false,
107
+ required: ["action"],
108
+ properties: {
109
+ action: { type: "string", enum: ["freeze", "clear"] },
110
+ target: { type: "string" },
111
+ evidence: { type: "array", items: { type: "string" } },
112
+ scope: { type: "array", items: { type: "string" } },
113
+ accept: { type: "array", items: { type: "string" } },
114
+ stop: { type: "string" },
115
+ observableBenefit: { type: "boolean" },
116
+ cardId: { type: "string" },
117
+ },
118
+ },
119
+ output: {
120
+ schema: {
121
+ type: "object",
122
+ additionalProperties: false,
123
+ required: ["action", "status"],
124
+ properties: {
125
+ action: { type: "string", enum: ["freeze", "clear"] },
126
+ status: { type: "string", enum: ["frozen", "cleared", "absent"] },
127
+ card: { type: "object" },
128
+ cardId: { type: "string" },
129
+ },
130
+ },
131
+ render(_args, value) {
132
+ return [{
133
+ type: "text",
134
+ text: value.status === "frozen"
135
+ ? `Frozen executor route card ${value.card.id}: ${value.card.target}`
136
+ : value.status === "cleared"
137
+ ? `Cleared executor route card ${value.cardId}.`
138
+ : "No active executor route card exists.",
139
+ }];
140
+ },
141
+ },
142
+ execute(args, execution) {
143
+ if (!execution.agent) throw new Error("odai_route_card requires an owning agent session");
144
+ const header = execution.agent.session?.header;
145
+ if (header?.origin === "subagent" || (Number.isSafeInteger(header?.delegationDepth) && header.delegationDepth > 0)) {
146
+ throw new Error("child agents may not change Odai route cards");
147
+ }
148
+ if (!args || typeof args !== "object" || Array.isArray(args)) throw new TypeError("arguments must be an object");
149
+ if (args.action === "freeze") {
150
+ const active = unsettledFor(execution.agent);
151
+ if (active) throw new Error(`executor route card ${active.id} is already active or claimed`);
152
+ const card = normalizeCard(args, authorizationFor(execution.agent));
153
+ onFrozen(execution.agent, card);
154
+ return Promise.resolve(Object.freeze({ action: "freeze", status: "frozen", card }));
155
+ }
156
+ if (args.action === "clear") {
157
+ const card = activeFor(execution.agent);
158
+ if (!card) return Promise.resolve(Object.freeze({ action: "clear", status: "absent" }));
159
+ if (args.cardId !== undefined && args.cardId !== card.id) {
160
+ throw new Error(`route card ${args.cardId} does not match active card ${card.id}`);
161
+ }
162
+ onCleared(execution.agent, card.id);
163
+ return Promise.resolve(Object.freeze({ action: "clear", status: "cleared", cardId: card.id }));
164
+ }
165
+ throw new TypeError("action must be freeze or clear");
166
+ },
167
+ };
168
+ }