@ouro.bot/cli 0.0.1-alpha.0 → 0.1.0-alpha.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/AdoptionSpecialist.ouro/agent.json +20 -0
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +22 -0
- package/AdoptionSpecialist.ouro/psyche/identities/basilisk.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jafar.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/jormungandr.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/kaa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/medusa.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/nagini.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/ouroboros.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/python.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/quetzalcoatl.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/sir-hiss.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-serpent.md +31 -0
- package/AdoptionSpecialist.ouro/psyche/identities/the-snake.md +31 -0
- package/README.md +224 -6
- package/dist/heart/agent-entry.js +17 -0
- package/dist/heart/api-error.js +34 -0
- package/dist/heart/config.js +296 -0
- package/dist/heart/core.js +485 -0
- package/dist/heart/daemon/daemon-cli.js +626 -0
- package/dist/heart/daemon/daemon-entry.js +74 -0
- package/dist/heart/daemon/daemon.js +310 -0
- package/dist/heart/daemon/hatch-flow.js +284 -0
- package/dist/heart/daemon/hatch-specialist.js +107 -0
- package/dist/heart/daemon/health-monitor.js +79 -0
- package/dist/heart/daemon/message-router.js +98 -0
- package/dist/heart/daemon/ouro-bot-entry.js +23 -0
- package/dist/heart/daemon/ouro-bot-wrapper.js +90 -0
- package/dist/heart/daemon/ouro-entry.js +23 -0
- package/dist/heart/daemon/ouro-uti.js +212 -0
- package/dist/heart/daemon/process-manager.js +220 -0
- package/dist/heart/daemon/runtime-logging.js +98 -0
- package/dist/heart/daemon/subagent-installer.js +125 -0
- package/dist/heart/daemon/task-scheduler.js +237 -0
- package/dist/heart/harness.js +26 -0
- package/dist/heart/identity.js +270 -0
- package/dist/heart/kicks.js +144 -0
- package/dist/heart/primitives.js +4 -0
- package/dist/heart/providers/anthropic.js +329 -0
- package/dist/heart/providers/azure.js +66 -0
- package/dist/heart/providers/minimax.js +53 -0
- package/dist/heart/providers/openai-codex.js +162 -0
- package/dist/heart/streaming.js +412 -0
- package/dist/heart/turn-coordinator.js +62 -0
- package/dist/inner-worker-entry.js +4 -0
- package/dist/mind/associative-recall.js +176 -0
- package/dist/mind/bundle-manifest.js +118 -0
- package/dist/mind/context.js +218 -0
- package/dist/mind/first-impressions.js +43 -0
- package/dist/mind/format.js +56 -0
- package/dist/mind/friends/channel.js +41 -0
- package/dist/mind/friends/resolver.js +84 -0
- package/dist/mind/friends/store-file.js +171 -0
- package/dist/mind/friends/store.js +4 -0
- package/dist/mind/friends/tokens.js +26 -0
- package/dist/mind/friends/types.js +21 -0
- package/dist/mind/memory.js +326 -0
- package/dist/mind/phrases.js +43 -0
- package/dist/mind/prompt.js +254 -0
- package/dist/mind/token-estimate.js +119 -0
- package/dist/nerves/cli-logging.js +31 -0
- package/dist/nerves/coverage/audit-rules.js +81 -0
- package/dist/nerves/coverage/audit.js +200 -0
- package/dist/nerves/coverage/cli-main.js +5 -0
- package/dist/nerves/coverage/cli.js +51 -0
- package/dist/nerves/coverage/contract.js +23 -0
- package/dist/nerves/coverage/file-completeness.js +46 -0
- package/dist/nerves/coverage/run-artifacts.js +77 -0
- package/dist/nerves/coverage/source-scanner.js +34 -0
- package/dist/nerves/index.js +152 -0
- package/dist/nerves/runtime.js +38 -0
- package/dist/repertoire/ado-client.js +211 -0
- package/dist/repertoire/ado-context.js +73 -0
- package/dist/repertoire/ado-semantic.js +841 -0
- package/dist/repertoire/ado-templates.js +146 -0
- package/dist/repertoire/coding/index.js +36 -0
- package/dist/repertoire/coding/manager.js +489 -0
- package/dist/repertoire/coding/monitor.js +60 -0
- package/dist/repertoire/coding/reporter.js +45 -0
- package/dist/repertoire/coding/spawner.js +102 -0
- package/dist/repertoire/coding/tools.js +167 -0
- package/dist/repertoire/coding/types.js +2 -0
- package/dist/repertoire/data/ado-endpoints.json +122 -0
- package/dist/repertoire/data/graph-endpoints.json +212 -0
- package/dist/repertoire/github-client.js +64 -0
- package/dist/repertoire/graph-client.js +118 -0
- package/dist/repertoire/skills.js +156 -0
- package/dist/repertoire/tasks/board.js +122 -0
- package/dist/repertoire/tasks/index.js +210 -0
- package/dist/repertoire/tasks/lifecycle.js +80 -0
- package/dist/repertoire/tasks/middleware.js +65 -0
- package/dist/repertoire/tasks/parser.js +173 -0
- package/dist/repertoire/tasks/scanner.js +132 -0
- package/dist/repertoire/tasks/transitions.js +145 -0
- package/dist/repertoire/tasks/types.js +2 -0
- package/dist/repertoire/tools-base.js +622 -0
- package/dist/repertoire/tools-github.js +53 -0
- package/dist/repertoire/tools-teams.js +308 -0
- package/dist/repertoire/tools.js +199 -0
- package/dist/senses/cli-entry.js +15 -0
- package/dist/senses/cli.js +523 -0
- package/dist/senses/commands.js +98 -0
- package/dist/senses/inner-dialog-worker.js +61 -0
- package/dist/senses/inner-dialog.js +216 -0
- package/dist/senses/teams-entry.js +15 -0
- package/dist/senses/teams.js +695 -0
- package/dist/senses/trust-gate.js +150 -0
- package/package.json +34 -11
- package/subagents/README.md +71 -0
- package/subagents/work-doer.md +233 -0
- package/subagents/work-merger.md +593 -0
- package/subagents/work-planner.md +373 -0
- package/bin/ouro.js +0 -6
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.HARNESS_PRIMITIVES_ENTRYPOINT = void 0;
|
|
18
|
+
const runtime_1 = require("../nerves/runtime");
|
|
19
|
+
__exportStar(require("./primitives"), exports);
|
|
20
|
+
exports.HARNESS_PRIMITIVES_ENTRYPOINT = "harness/primitives";
|
|
21
|
+
(0, runtime_1.emitNervesEvent)({
|
|
22
|
+
component: "harness",
|
|
23
|
+
event: "harness.module_entry_loaded",
|
|
24
|
+
message: "harness primitives entrypoint loaded",
|
|
25
|
+
meta: {},
|
|
26
|
+
});
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = void 0;
|
|
37
|
+
exports.buildDefaultAgentTemplate = buildDefaultAgentTemplate;
|
|
38
|
+
exports.getAgentName = getAgentName;
|
|
39
|
+
exports.getRepoRoot = getRepoRoot;
|
|
40
|
+
exports.getAgentBundlesRoot = getAgentBundlesRoot;
|
|
41
|
+
exports.getAgentRoot = getAgentRoot;
|
|
42
|
+
exports.getAgentSecretsPath = getAgentSecretsPath;
|
|
43
|
+
exports.loadAgentConfig = loadAgentConfig;
|
|
44
|
+
exports.resetIdentity = resetIdentity;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const os = __importStar(require("os"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const runtime_1 = require("../nerves/runtime");
|
|
49
|
+
exports.DEFAULT_AGENT_CONTEXT = {
|
|
50
|
+
maxTokens: 80000,
|
|
51
|
+
contextMargin: 20,
|
|
52
|
+
};
|
|
53
|
+
exports.DEFAULT_AGENT_PHRASES = {
|
|
54
|
+
thinking: ["working"],
|
|
55
|
+
tool: ["running tool"],
|
|
56
|
+
followup: ["processing"],
|
|
57
|
+
};
|
|
58
|
+
function buildDefaultAgentTemplate(_agentName) {
|
|
59
|
+
return {
|
|
60
|
+
version: 1,
|
|
61
|
+
enabled: true,
|
|
62
|
+
provider: "anthropic",
|
|
63
|
+
context: { ...exports.DEFAULT_AGENT_CONTEXT },
|
|
64
|
+
phrases: {
|
|
65
|
+
thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
|
|
66
|
+
tool: [...exports.DEFAULT_AGENT_PHRASES.tool],
|
|
67
|
+
followup: [...exports.DEFAULT_AGENT_PHRASES.followup],
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
let _cachedAgentName = null;
|
|
72
|
+
let _cachedAgentConfig = null;
|
|
73
|
+
/**
|
|
74
|
+
* Parse `--agent <name>` from process.argv.
|
|
75
|
+
* Caches the result after first parse.
|
|
76
|
+
* Throws if --agent is missing or has no value.
|
|
77
|
+
*/
|
|
78
|
+
function getAgentName() {
|
|
79
|
+
if (_cachedAgentName) {
|
|
80
|
+
(0, runtime_1.emitNervesEvent)({
|
|
81
|
+
event: "identity.resolve",
|
|
82
|
+
component: "config/identity",
|
|
83
|
+
message: "resolved agent name from cache",
|
|
84
|
+
meta: { source: "cache" },
|
|
85
|
+
});
|
|
86
|
+
return _cachedAgentName;
|
|
87
|
+
}
|
|
88
|
+
const idx = process.argv.indexOf("--agent");
|
|
89
|
+
if (idx === -1 || idx + 1 >= process.argv.length) {
|
|
90
|
+
throw new Error("Missing required --agent <name> argument. Usage: node cli-entry.js --agent ouroboros");
|
|
91
|
+
}
|
|
92
|
+
_cachedAgentName = process.argv[idx + 1];
|
|
93
|
+
(0, runtime_1.emitNervesEvent)({
|
|
94
|
+
event: "identity.resolve",
|
|
95
|
+
component: "config/identity",
|
|
96
|
+
message: "resolved agent name from argv",
|
|
97
|
+
meta: { source: "argv" },
|
|
98
|
+
});
|
|
99
|
+
return _cachedAgentName;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Resolve repo root from __dirname.
|
|
103
|
+
* In dev (tsx): __dirname is `<repo>/src`, so repo root is one level up.
|
|
104
|
+
* In compiled (node dist/): __dirname is `<repo>/dist`, so repo root is one level up.
|
|
105
|
+
*/
|
|
106
|
+
function getRepoRoot() {
|
|
107
|
+
return path.resolve(__dirname, "..");
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns the shared bundle root directory: `~/AgentBundles/`
|
|
111
|
+
*/
|
|
112
|
+
function getAgentBundlesRoot() {
|
|
113
|
+
return path.join(os.homedir(), "AgentBundles");
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Returns the agent-specific bundle directory: `~/AgentBundles/<agentName>.ouro/`
|
|
117
|
+
*/
|
|
118
|
+
function getAgentRoot() {
|
|
119
|
+
return path.join(getAgentBundlesRoot(), `${getAgentName()}.ouro`);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns the conventional secrets path: `~/.agentsecrets/<agentName>/secrets.json`
|
|
123
|
+
*/
|
|
124
|
+
function getAgentSecretsPath(agentName = getAgentName()) {
|
|
125
|
+
return path.join(os.homedir(), ".agentsecrets", agentName, "secrets.json");
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Load and parse `<agentRoot>/agent.json`.
|
|
129
|
+
* Caches the result after first load.
|
|
130
|
+
* Throws descriptive error if file is missing or contains invalid JSON.
|
|
131
|
+
*/
|
|
132
|
+
function loadAgentConfig() {
|
|
133
|
+
if (_cachedAgentConfig) {
|
|
134
|
+
(0, runtime_1.emitNervesEvent)({
|
|
135
|
+
event: "identity.resolve",
|
|
136
|
+
component: "config/identity",
|
|
137
|
+
message: "loaded agent config from cache",
|
|
138
|
+
meta: { source: "cache" },
|
|
139
|
+
});
|
|
140
|
+
return _cachedAgentConfig;
|
|
141
|
+
}
|
|
142
|
+
const agentRoot = getAgentRoot();
|
|
143
|
+
const configFile = path.join(agentRoot, "agent.json");
|
|
144
|
+
let raw;
|
|
145
|
+
try {
|
|
146
|
+
raw = fs.readFileSync(configFile, "utf-8");
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
(0, runtime_1.emitNervesEvent)({
|
|
150
|
+
level: "error",
|
|
151
|
+
event: "config_identity.error",
|
|
152
|
+
component: "config/identity",
|
|
153
|
+
message: "failed reading agent.json",
|
|
154
|
+
meta: {
|
|
155
|
+
path: configFile,
|
|
156
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
throw new Error(`Cannot read agent.json at ${configFile}. Does the agent directory exist?`);
|
|
160
|
+
}
|
|
161
|
+
let parsed;
|
|
162
|
+
try {
|
|
163
|
+
parsed = JSON.parse(raw);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
(0, runtime_1.emitNervesEvent)({
|
|
167
|
+
level: "error",
|
|
168
|
+
event: "config_identity.error",
|
|
169
|
+
component: "config/identity",
|
|
170
|
+
message: "invalid agent.json syntax",
|
|
171
|
+
meta: {
|
|
172
|
+
path: configFile,
|
|
173
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
throw new Error(`Invalid JSON in agent.json at ${configFile}. Check syntax.`);
|
|
177
|
+
}
|
|
178
|
+
const existingPhrases = parsed.phrases;
|
|
179
|
+
const needsFill = !existingPhrases ||
|
|
180
|
+
!existingPhrases.thinking ||
|
|
181
|
+
!existingPhrases.tool ||
|
|
182
|
+
!existingPhrases.followup;
|
|
183
|
+
if (needsFill) {
|
|
184
|
+
const filled = {
|
|
185
|
+
thinking: existingPhrases?.thinking ?? exports.DEFAULT_AGENT_PHRASES.thinking,
|
|
186
|
+
tool: existingPhrases?.tool ?? exports.DEFAULT_AGENT_PHRASES.tool,
|
|
187
|
+
followup: existingPhrases?.followup ?? exports.DEFAULT_AGENT_PHRASES.followup,
|
|
188
|
+
};
|
|
189
|
+
parsed.phrases = filled;
|
|
190
|
+
(0, runtime_1.emitNervesEvent)({
|
|
191
|
+
level: "warn",
|
|
192
|
+
event: "config_identity.error",
|
|
193
|
+
component: "config/identity",
|
|
194
|
+
message: "agent config missing phrase pools; placeholders applied",
|
|
195
|
+
meta: { path: configFile },
|
|
196
|
+
});
|
|
197
|
+
fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
198
|
+
}
|
|
199
|
+
const rawProvider = parsed.provider;
|
|
200
|
+
if (rawProvider !== "azure" &&
|
|
201
|
+
rawProvider !== "minimax" &&
|
|
202
|
+
rawProvider !== "anthropic" &&
|
|
203
|
+
rawProvider !== "openai-codex") {
|
|
204
|
+
(0, runtime_1.emitNervesEvent)({
|
|
205
|
+
level: "error",
|
|
206
|
+
event: "config_identity.error",
|
|
207
|
+
component: "config/identity",
|
|
208
|
+
message: "agent config missing or invalid provider",
|
|
209
|
+
meta: {
|
|
210
|
+
path: configFile,
|
|
211
|
+
provider: rawProvider,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
throw new Error(`agent.json at ${configFile} must include provider: "azure", "minimax", "anthropic", or "openai-codex".`);
|
|
215
|
+
}
|
|
216
|
+
const rawVersion = parsed.version;
|
|
217
|
+
const version = rawVersion === undefined ? 1 : rawVersion;
|
|
218
|
+
if (typeof version !== "number" ||
|
|
219
|
+
!Number.isInteger(version) ||
|
|
220
|
+
version < 1) {
|
|
221
|
+
(0, runtime_1.emitNervesEvent)({
|
|
222
|
+
level: "error",
|
|
223
|
+
event: "config_identity.error",
|
|
224
|
+
component: "config/identity",
|
|
225
|
+
message: "agent config missing or invalid version",
|
|
226
|
+
meta: {
|
|
227
|
+
path: configFile,
|
|
228
|
+
version: rawVersion,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
throw new Error(`agent.json at ${configFile} must include version as integer >= 1.`);
|
|
232
|
+
}
|
|
233
|
+
const rawEnabled = parsed.enabled;
|
|
234
|
+
const enabled = rawEnabled === undefined ? true : rawEnabled;
|
|
235
|
+
if (typeof enabled !== "boolean") {
|
|
236
|
+
(0, runtime_1.emitNervesEvent)({
|
|
237
|
+
level: "error",
|
|
238
|
+
event: "config_identity.error",
|
|
239
|
+
component: "config/identity",
|
|
240
|
+
message: "agent config has invalid enabled flag",
|
|
241
|
+
meta: {
|
|
242
|
+
path: configFile,
|
|
243
|
+
enabled: rawEnabled,
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
throw new Error(`agent.json at ${configFile} must include enabled as boolean.`);
|
|
247
|
+
}
|
|
248
|
+
_cachedAgentConfig = {
|
|
249
|
+
version,
|
|
250
|
+
enabled,
|
|
251
|
+
provider: rawProvider,
|
|
252
|
+
context: parsed.context,
|
|
253
|
+
phrases: parsed.phrases,
|
|
254
|
+
};
|
|
255
|
+
(0, runtime_1.emitNervesEvent)({
|
|
256
|
+
event: "identity.resolve",
|
|
257
|
+
component: "config/identity",
|
|
258
|
+
message: "loaded agent config from disk",
|
|
259
|
+
meta: { source: "disk" },
|
|
260
|
+
});
|
|
261
|
+
return _cachedAgentConfig;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Clear all cached identity state.
|
|
265
|
+
* Used in tests and when switching agent context.
|
|
266
|
+
*/
|
|
267
|
+
function resetIdentity() {
|
|
268
|
+
_cachedAgentName = null;
|
|
269
|
+
_cachedAgentConfig = null;
|
|
270
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// TODO: Kicks enforce "any action" but not "meaningful action". After a narration
|
|
3
|
+
// kick, the model can satisfy the constraint by calling a no-op tool like
|
|
4
|
+
// get_current_time({}). We need to detect trivial compliance and either re-kick
|
|
5
|
+
// or discount the tool call. Ideally, the kick message would suggest a specific
|
|
6
|
+
// tool call based on conversation context (what the user asked, what tools are
|
|
7
|
+
// relevant) rather than just saying "call a tool". That's a bigger piece of work —
|
|
8
|
+
// it requires the kick system to be context-aware.
|
|
9
|
+
// See ouroboros' observation: "i'm not chickening out. i'm satisfying a crude
|
|
10
|
+
// constraint. poorly."
|
|
11
|
+
//
|
|
12
|
+
// A kick is a self-correction. When the harness detects a malformed response,
|
|
13
|
+
// it injects an assistant-role message as if the model caught its own mistake.
|
|
14
|
+
//
|
|
15
|
+
// Kicks are:
|
|
16
|
+
// - assistant role (self-correction, not external rebuke)
|
|
17
|
+
// - first person ("I" not "you")
|
|
18
|
+
// - forward-looking (what I'm doing next, not what I did wrong)
|
|
19
|
+
// - short (one sentence)
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.hasToolIntent = hasToolIntent;
|
|
22
|
+
exports.detectKick = detectKick;
|
|
23
|
+
const KICK_MESSAGES = {
|
|
24
|
+
empty: "I sent an empty message by accident — let me try again.",
|
|
25
|
+
narration: "I narrated instead of acting. Using the tool now -- if done, calling final_answer.",
|
|
26
|
+
tool_required: "tool-required is on — I need to call a tool. use /tool-required to turn it off.",
|
|
27
|
+
};
|
|
28
|
+
const TOOL_INTENT_PATTERNS = [
|
|
29
|
+
// Explicit intent — "let me", "I'll", "I will"
|
|
30
|
+
/\blet me\b/i,
|
|
31
|
+
/\bi'll\b/i,
|
|
32
|
+
/\bi will\b/i,
|
|
33
|
+
/\bi would like to\b/i,
|
|
34
|
+
/\bi want to\b/i,
|
|
35
|
+
// "going to" variants
|
|
36
|
+
/\bi'm going to\b/i,
|
|
37
|
+
/\bgoing to\b/i,
|
|
38
|
+
/\bi am going to\b/i,
|
|
39
|
+
// Present continuous — "i'm checking", "i am querying"
|
|
40
|
+
/\bi'm \w+ing\b/i,
|
|
41
|
+
/\bi am \w+ing\b/i,
|
|
42
|
+
// Action announcements — "I need to", "I should", "I can"
|
|
43
|
+
/\bi need to\b/i,
|
|
44
|
+
/\bi should\b/i,
|
|
45
|
+
/\bi can\b/i,
|
|
46
|
+
// Obligation — "I have to", "I must"
|
|
47
|
+
/\bi have to\b/i,
|
|
48
|
+
/\bwe have to\b/i,
|
|
49
|
+
/\bi must\b/i,
|
|
50
|
+
/\bwe must\b/i,
|
|
51
|
+
// First person plural intent
|
|
52
|
+
/\bwe need to\b/i,
|
|
53
|
+
/\bwe should\b/i,
|
|
54
|
+
/\bwe can\b/i,
|
|
55
|
+
/\bwe'll\b/i,
|
|
56
|
+
/\bwe will\b/i,
|
|
57
|
+
/\bwe're going to\b/i,
|
|
58
|
+
/\bwe are going to\b/i,
|
|
59
|
+
/\blet's\b/i,
|
|
60
|
+
// Gerund phase shifts — "entering", "starting", "proceeding", "switching"
|
|
61
|
+
/\bentering\b/i,
|
|
62
|
+
/\bstarting with\b/i,
|
|
63
|
+
/\bproceeding\b/i,
|
|
64
|
+
/\bswitching to\b/i,
|
|
65
|
+
// Temporal narration — "first", "now I/we", "next turn", "next, I"
|
|
66
|
+
/\bfirst,?\s+i\b/i,
|
|
67
|
+
/\bnow i\b/i,
|
|
68
|
+
/\bnow we\b/i,
|
|
69
|
+
/\bnext turn\b/i,
|
|
70
|
+
/\bnext,?\s+i\b/i,
|
|
71
|
+
/\bnext,?\s+we\b/i,
|
|
72
|
+
// Sequential narration — "then I/we", "after that", "once I/we", "before I/we"
|
|
73
|
+
/\bthen i\b/i,
|
|
74
|
+
/\bthen we\b/i,
|
|
75
|
+
/\bafter that\b/i,
|
|
76
|
+
/\bonce i\b/i,
|
|
77
|
+
/\bonce we\b/i,
|
|
78
|
+
/\bbefore i\b/i,
|
|
79
|
+
/\bbefore we\b/i,
|
|
80
|
+
// Future intent — "about to", "gonna"
|
|
81
|
+
/\babout to\b/i,
|
|
82
|
+
/\bgonna\b/i,
|
|
83
|
+
// Hedged intent — "allow me to", "time to"
|
|
84
|
+
/\ballow me to\b/i,
|
|
85
|
+
/\btime to\b/i,
|
|
86
|
+
// Movement narration — "moving on", "moving to"
|
|
87
|
+
/\bmoving on\b/i,
|
|
88
|
+
/\bmoving to\b/i,
|
|
89
|
+
// Self-narration — "my next step", "my plan", "the plan is", "tool calls only"
|
|
90
|
+
/\bmy next step\b/i,
|
|
91
|
+
/\bmy plan\b/i,
|
|
92
|
+
/\bthe plan is\b/i,
|
|
93
|
+
/\btool calls only\b/i,
|
|
94
|
+
// "Continuing" at start of any line — narration filler (multiline so ^ matches after \n)
|
|
95
|
+
/^continuing\b/im,
|
|
96
|
+
// "continues" anywhere — progress narration ("The work continues", "continues to be complex")
|
|
97
|
+
/\bcontinues\b/i,
|
|
98
|
+
// "Next up" at start of text — e.g. "Next up:", "Next up, I'll..."
|
|
99
|
+
/^next up\b/i,
|
|
100
|
+
];
|
|
101
|
+
// Normalize curly quotes/apostrophes to straight so patterns match consistently
|
|
102
|
+
function normalize(text) {
|
|
103
|
+
return text.replace(/[\u2018\u2019\u2032]/g, "'").replace(/[\u201C\u201D]/g, '"');
|
|
104
|
+
}
|
|
105
|
+
function hasToolIntent(text) {
|
|
106
|
+
return TOOL_INTENT_PATTERNS.some((p) => p.test(normalize(text)));
|
|
107
|
+
}
|
|
108
|
+
// Detect what kind of kick is needed, or null if response is fine.
|
|
109
|
+
// Priority: empty > narration > tool_required
|
|
110
|
+
function detectKick(content, options) {
|
|
111
|
+
const isEmpty = !content?.trim();
|
|
112
|
+
if (isEmpty) {
|
|
113
|
+
(0, runtime_1.emitNervesEvent)({
|
|
114
|
+
level: "error",
|
|
115
|
+
event: "engine.error",
|
|
116
|
+
component: "engine",
|
|
117
|
+
message: "empty assistant content detected",
|
|
118
|
+
meta: { reason: "empty" },
|
|
119
|
+
});
|
|
120
|
+
return { reason: "empty", message: KICK_MESSAGES.empty };
|
|
121
|
+
}
|
|
122
|
+
if (hasToolIntent(content)) {
|
|
123
|
+
(0, runtime_1.emitNervesEvent)({
|
|
124
|
+
level: "error",
|
|
125
|
+
event: "engine.error",
|
|
126
|
+
component: "engine",
|
|
127
|
+
message: "narration-style response detected",
|
|
128
|
+
meta: { reason: "narration" },
|
|
129
|
+
});
|
|
130
|
+
return { reason: "narration", message: KICK_MESSAGES.narration };
|
|
131
|
+
}
|
|
132
|
+
if (options?.toolChoiceRequired) {
|
|
133
|
+
(0, runtime_1.emitNervesEvent)({
|
|
134
|
+
level: "error",
|
|
135
|
+
event: "engine.error",
|
|
136
|
+
component: "engine",
|
|
137
|
+
message: "tool-required mode response missing tool call",
|
|
138
|
+
meta: { reason: "tool_required" },
|
|
139
|
+
});
|
|
140
|
+
return { reason: "tool_required", message: KICK_MESSAGES.tool_required };
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const runtime_1 = require("../nerves/runtime");
|