create-walle 0.9.25 → 0.9.26
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/README.md +8 -0
- package/bin/create-walle.js +815 -45
- package/package.json +2 -2
- package/template/bin/ctm-dev-cleanup.js +90 -4
- package/template/bin/ctm-launch.sh +49 -1
- package/template/bin/dev.sh +45 -1
- package/template/bin/ensure-stable-node.js +132 -0
- package/template/bin/install-service.sh +9 -0
- package/template/claude-task-manager/api-prompts.js +899 -119
- package/template/claude-task-manager/approval-agent.js +360 -40
- package/template/claude-task-manager/bin/ctm-disclaim.c +42 -0
- package/template/claude-task-manager/bin/ctm-hotkey.swift +67 -81
- package/template/claude-task-manager/bin/ctm-screen-auth.swift +37 -0
- package/template/claude-task-manager/bin/install-hotkey.sh +97 -49
- package/template/claude-task-manager/bin/restart-ctm.sh +14 -0
- package/template/claude-task-manager/db.js +399 -48
- package/template/claude-task-manager/docs/approval-hook-sandbox.md +84 -0
- package/template/claude-task-manager/docs/codex-app-server-approvals.md +72 -0
- package/template/claude-task-manager/docs/codex-native-sandbox.md +47 -0
- package/template/claude-task-manager/docs/prompt-editing-tree-design.md +18 -1
- package/template/claude-task-manager/lib/approval-hook.js +200 -0
- package/template/claude-task-manager/lib/approval-self-adapt.js +1 -0
- package/template/claude-task-manager/lib/auth-rules.js +11 -0
- package/template/claude-task-manager/lib/background-llm.js +32 -4
- package/template/claude-task-manager/lib/codesign-identity.js +140 -0
- package/template/claude-task-manager/lib/codex-app-server-client.js +119 -0
- package/template/claude-task-manager/lib/codex-approval-bridge.js +118 -0
- package/template/claude-task-manager/lib/codex-history-terminal-renderer.js +571 -0
- package/template/claude-task-manager/lib/codex-paths.js +73 -0
- package/template/claude-task-manager/lib/codex-rollout-snapshot.js +164 -0
- package/template/claude-task-manager/lib/codex-rollout-tail.js +72 -0
- package/template/claude-task-manager/lib/codex-sandbox-args.js +47 -0
- package/template/claude-task-manager/lib/coding-agent-models.js +118 -71
- package/template/claude-task-manager/lib/command-targets.js +163 -0
- package/template/claude-task-manager/lib/conversation-tail-merge.js +61 -19
- package/template/claude-task-manager/lib/db-owner-worker-client.js +29 -1
- package/template/claude-task-manager/lib/escalation-review.js +80 -3
- package/template/claude-task-manager/lib/flow-control.js +52 -0
- package/template/claude-task-manager/lib/fs-watcher.js +24 -15
- package/template/claude-task-manager/lib/ingest-cooldown.js +68 -0
- package/template/claude-task-manager/lib/jsonl-conversation-parser.js +8 -4
- package/template/claude-task-manager/lib/launchd-recovery.js +92 -0
- package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +207 -52
- package/template/claude-task-manager/lib/mobile-push-store.js +7 -0
- package/template/claude-task-manager/lib/model-overview-brain-fallback.js +102 -1
- package/template/claude-task-manager/lib/model-overview-cache.js +1 -0
- package/template/claude-task-manager/lib/oauth-proxy-supervisor.js +2 -1
- package/template/claude-task-manager/lib/perf-tracker.js +29 -2
- package/template/claude-task-manager/lib/permission-match.js +146 -16
- package/template/claude-task-manager/lib/project-slug.js +33 -0
- package/template/claude-task-manager/lib/prompt-intent.js +51 -4
- package/template/claude-task-manager/lib/read-pool-client.js +48 -3
- package/template/claude-task-manager/lib/real-node.js +73 -0
- package/template/claude-task-manager/lib/runtime-work-registry.js +131 -14
- package/template/claude-task-manager/lib/session-content-backfill.js +24 -5
- package/template/claude-task-manager/lib/session-diagnostics-batch.js +87 -0
- package/template/claude-task-manager/lib/session-history.js +5 -7
- package/template/claude-task-manager/lib/session-host-manager.js +19 -0
- package/template/claude-task-manager/lib/session-jobs.js +6 -0
- package/template/claude-task-manager/lib/session-message-response-cache.js +89 -0
- package/template/claude-task-manager/lib/session-messages-page.js +211 -0
- package/template/claude-task-manager/lib/session-messages-projection.js +170 -0
- package/template/claude-task-manager/lib/session-standup.js +8 -0
- package/template/claude-task-manager/lib/session-timeline-summary.js +16 -2
- package/template/claude-task-manager/lib/session-token-usage.js +30 -8
- package/template/claude-task-manager/lib/session-workspace-binding.js +29 -15
- package/template/claude-task-manager/lib/storage-migration.js +2 -1
- package/template/claude-task-manager/lib/transcript-store.js +179 -12
- package/template/claude-task-manager/lib/walle-ctm-history.js +298 -11
- package/template/claude-task-manager/lib/walle-permission-reply.js +49 -0
- package/template/claude-task-manager/lib/walle-session-cache.js +22 -1
- package/template/claude-task-manager/lib/walle-supervisor.js +42 -3
- package/template/claude-task-manager/package.json +5 -2
- package/template/claude-task-manager/prompt-harvest.js +31 -11
- package/template/claude-task-manager/providers/claude-code.js +29 -1
- package/template/claude-task-manager/providers/codex.js +13 -1
- package/template/claude-task-manager/public/css/setup.css +11 -0
- package/template/claude-task-manager/public/css/walle-session.css +132 -4
- package/template/claude-task-manager/public/css/walle.css +89 -0
- package/template/claude-task-manager/public/icon-16.png +0 -0
- package/template/claude-task-manager/public/icon-32.png +0 -0
- package/template/claude-task-manager/public/icon-512.png +0 -0
- package/template/claude-task-manager/public/index.html +2483 -165
- package/template/claude-task-manager/public/js/activation-render-check.js +55 -0
- package/template/claude-task-manager/public/js/flow-control-policy.js +52 -0
- package/template/claude-task-manager/public/js/message-renderer.js +60 -1
- package/template/claude-task-manager/public/js/prompts.js +13 -1
- package/template/claude-task-manager/public/js/session-status-precedence.js +9 -3
- package/template/claude-task-manager/public/js/setup.js +54 -10
- package/template/claude-task-manager/public/js/stream-resize-policy.js +80 -0
- package/template/claude-task-manager/public/js/stream-view.js +78 -0
- package/template/claude-task-manager/public/js/terminal-reconciler.js +52 -2
- package/template/claude-task-manager/public/js/tool-state.js +155 -0
- package/template/claude-task-manager/public/js/walle-session.js +887 -326
- package/template/claude-task-manager/public/js/walle.js +306 -195
- package/template/claude-task-manager/public/m/app.css +1 -0
- package/template/claude-task-manager/public/m/app.js +33 -3
- package/template/claude-task-manager/queue-engine.js +45 -1
- package/template/claude-task-manager/server.js +3367 -540
- package/template/claude-task-manager/workers/approval-blocklist.js +130 -17
- package/template/claude-task-manager/workers/db-owner-worker.js +31 -1
- package/template/claude-task-manager/workers/read-pool-worker.js +92 -5
- package/template/claude-task-manager/workers/session-host-process.js +10 -0
- package/template/claude-task-manager/workers/state-detectors/codex.js +58 -7
- package/template/package.json +2 -3
- package/template/shared/icons/AppIcon-ctm.icns +0 -0
- package/template/shared/icons/AppIcon-walle.icns +0 -0
- package/template/wall-e/agent.js +139 -18
- package/template/wall-e/api-walle.js +201 -22
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +1981 -0
- package/template/wall-e/brain.js +1049 -39
- package/template/wall-e/chat.js +427 -86
- package/template/wall-e/coding/acceptance-contract.js +26 -1
- package/template/wall-e/coding/action-memory-policy.js +353 -0
- package/template/wall-e/coding/action-memory-store.js +814 -0
- package/template/wall-e/coding/initial-messages.js +197 -0
- package/template/wall-e/coding/no-progress-guard.js +327 -0
- package/template/wall-e/coding/permission-service.js +88 -22
- package/template/wall-e/coding/session-workspaces.js +81 -0
- package/template/wall-e/coding/shell-sandbox.js +124 -0
- package/template/wall-e/coding/stream-processor.js +63 -2
- package/template/wall-e/coding/tool-execution-controller.js +14 -1
- package/template/wall-e/coding/tool-registry.js +1 -1
- package/template/wall-e/coding/transcript-writer.js +3 -0
- package/template/wall-e/coding-orchestrator.js +636 -35
- package/template/wall-e/coding-prompts.js +51 -2
- package/template/wall-e/docs/model-routing-policy.md +59 -0
- package/template/wall-e/docs/walle-shell-sandbox.md +61 -0
- package/template/wall-e/extraction/knowledge-extractor.js +76 -23
- package/template/wall-e/http/chat-api.js +30 -12
- package/template/wall-e/http/model-admin.js +93 -1
- package/template/wall-e/lib/background-lanes.js +133 -0
- package/template/wall-e/lib/boot-profile.js +11 -0
- package/template/wall-e/lib/brain-owner-worker-client.js +324 -0
- package/template/wall-e/lib/brain-read-pool-client.js +311 -0
- package/template/wall-e/lib/diagnostics-flags.js +87 -0
- package/template/wall-e/lib/event-loop-monitor.js +74 -3
- package/template/wall-e/lib/mcp-integration.js +7 -1
- package/template/wall-e/lib/real-node.js +98 -0
- package/template/wall-e/lib/runtime-health.js +206 -0
- package/template/wall-e/lib/runtime-worker-pool.js +101 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +231 -0
- package/template/wall-e/lib/scheduler.js +446 -17
- package/template/wall-e/lib/service-health.js +61 -2
- package/template/wall-e/lib/service-readiness.js +258 -0
- package/template/wall-e/lib/usage.js +152 -0
- package/template/wall-e/lib/worker-thread-pool.js +389 -0
- package/template/wall-e/llm/client.js +81 -4
- package/template/wall-e/llm/default-fallback.js +54 -8
- package/template/wall-e/llm/mlx.js +536 -73
- package/template/wall-e/llm/mlx.plugin.json +1 -1
- package/template/wall-e/llm/ollama.js +342 -43
- package/template/wall-e/llm/provider-error.js +18 -1
- package/template/wall-e/llm/provider-health-state.js +176 -0
- package/template/wall-e/llm/routing-policy.js +796 -0
- package/template/wall-e/llm/supported-models.js +5 -0
- package/template/wall-e/loops/tasks.js +60 -14
- package/template/wall-e/loops/think.js +89 -24
- package/template/wall-e/mcp-server.js +192 -28
- package/template/wall-e/server.js +32 -7
- package/template/wall-e/skills/script-skill-runner.js +8 -1
- package/template/wall-e/skills/skill-planner.js +64 -1
- package/template/wall-e/tools/builtin-middleware.js +67 -2
- package/template/wall-e/tools/local-tools.js +116 -26
- package/template/wall-e/tools/permission-checker.js +52 -4
- package/template/wall-e/tools/permission-rules.js +36 -0
- package/template/wall-e/tools/shell-analyzer.js +46 -1
- package/template/wall-e/training/gemma-e4b-qlora.js +314 -0
- package/template/wall-e/training/real-trajectory-miner.js +2617 -0
- package/template/wall-e/training/replay-eval-analysis.js +151 -0
- package/template/wall-e/training/run-shell-command-selector.js +277 -0
- package/template/wall-e/training/tool-sft-dataset.js +312 -0
- package/template/wall-e/training/tool-sft-renderers.js +144 -0
- package/template/wall-e/training/tool-trace-harvester.js +1440 -0
- package/template/wall-e/training/trajectory-action-selector.js +364 -0
- package/template/wall-e/weather-runtime.js +232 -0
- package/template/wall-e/workers/brain-owner-worker.js +162 -0
- package/template/wall-e/workers/brain-read-worker.js +148 -0
- package/template/wall-e/workers/runtime-worker.js +145 -0
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const VERIFICATION_TOOL_NAME_RE = /(?:test|verify|screenshot|smoke|diagnostic|lint|build|check_url|url_check|pdf_info|pdf_render_pages|make_pdf)/i;
|
|
4
|
-
|
|
4
|
+
// A run_shell command counts as verification ONLY when it invokes a real
|
|
5
|
+
// test/lint/build runner. The old pattern matched the bare words
|
|
6
|
+
// test|spec|lint|build|typecheck anywhere in the command JSON, so the
|
|
7
|
+
// shell-builtin existence probe `test -d node_modules && echo ...` (and any
|
|
8
|
+
// path containing "test") classified as a SUCCESSFUL verification — which both
|
|
9
|
+
// over-credited acceptance evidence and tripped the stream loop's
|
|
10
|
+
// verified-after-edit early exit, ending coding turns with no final answer
|
|
11
|
+
// (session c3f3af97: reply stopped at "...Let me check package.json").
|
|
12
|
+
const VERIFICATION_COMMAND_RE = new RegExp([
|
|
13
|
+
// package-manager script runners (`npm test`, `npm run build`, `bun run lint`, …)
|
|
14
|
+
String.raw`\b(?:npm|pnpm|yarn|bun)\s+(?:test\b|run\s+\S+)`,
|
|
15
|
+
// direct test/lint/type runners
|
|
16
|
+
String.raw`\b(?:pytest|jest|mocha|vitest|playwright|tsc|eslint|stylelint|ruff|mypy|flake8|rspec|phpunit)\b`,
|
|
17
|
+
String.raw`\bnode\s+--(?:test|check)\b`,
|
|
18
|
+
// language toolchains
|
|
19
|
+
String.raw`\b(?:cargo|go)\s+(?:test|build|check|vet)\b`,
|
|
20
|
+
String.raw`\bmake\s+(?:test|check|lint|build)\b`,
|
|
21
|
+
String.raw`\bmvn\s+(?:test|verify|package)\b`,
|
|
22
|
+
String.raw`\bgradlew?\s+(?:test|build|check)\b`,
|
|
23
|
+
// frontend build/lint CLIs
|
|
24
|
+
String.raw`\b(?:vue-cli-service|vite|webpack|rollup|esbuild|next|nuxt|ng)\s+(?:test|lint|build|typecheck|e2e)\b`,
|
|
25
|
+
// misc verification probes
|
|
26
|
+
String.raw`\bgit\s+diff\s+--check\b`,
|
|
27
|
+
String.raw`\bcurl\s+[^|;&]*(?:localhost|127\.0\.0\.1)`,
|
|
28
|
+
String.raw`\b(?:check_url|pdfinfo|pdftoppm|pdftotext)\b`,
|
|
29
|
+
].join('|'), 'i');
|
|
5
30
|
|
|
6
31
|
function callName(call = {}) {
|
|
7
32
|
return String(call.name || call.tool || '');
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_MIN_SCORE = 120;
|
|
4
|
+
const DEFAULT_MIN_MARGIN = 15;
|
|
5
|
+
const DEFAULT_LIMIT = 8;
|
|
6
|
+
const MODES = new Set(['off', 'audit', 'assist', 'apply']);
|
|
7
|
+
const SELECTORS = new Set(['store', 'replay', 'auto']);
|
|
8
|
+
const REPLAY_SELECTOR_TOOLS = new Set(['run_shell', 'apply_patch', 'edit_file', 'write_file']);
|
|
9
|
+
|
|
10
|
+
class ActionMemoryPolicy {
|
|
11
|
+
constructor({
|
|
12
|
+
store = null,
|
|
13
|
+
mode = 'audit',
|
|
14
|
+
selector = 'store',
|
|
15
|
+
minScore = DEFAULT_MIN_SCORE,
|
|
16
|
+
minMargin = DEFAULT_MIN_MARGIN,
|
|
17
|
+
limit = DEFAULT_LIMIT,
|
|
18
|
+
maxCandidates = DEFAULT_LIMIT,
|
|
19
|
+
memoryLimit = 200,
|
|
20
|
+
logger = console,
|
|
21
|
+
} = {}) {
|
|
22
|
+
this.store = store;
|
|
23
|
+
this.mode = normalizeMode(mode);
|
|
24
|
+
this.selector = normalizeSelector(selector);
|
|
25
|
+
this.minScore = finiteNumber(minScore, DEFAULT_MIN_SCORE);
|
|
26
|
+
this.minMargin = finiteNumber(minMargin, DEFAULT_MIN_MARGIN);
|
|
27
|
+
this.limit = Math.max(1, Math.trunc(finiteNumber(limit, DEFAULT_LIMIT)));
|
|
28
|
+
this.maxCandidates = Math.max(1, Math.trunc(finiteNumber(maxCandidates, this.limit)));
|
|
29
|
+
this.memoryLimit = Math.max(1, Math.trunc(finiteNumber(memoryLimit, 200)));
|
|
30
|
+
this.logger = logger;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async evaluateToolCall({
|
|
34
|
+
call = {},
|
|
35
|
+
context = {},
|
|
36
|
+
model = {},
|
|
37
|
+
sessionId = '',
|
|
38
|
+
prompt = '',
|
|
39
|
+
} = {}) {
|
|
40
|
+
const clonedCall = cloneToolCall(call);
|
|
41
|
+
const toolName = toolNameFromCall(clonedCall);
|
|
42
|
+
const prediction = { name: toolName, input: clonedCall.input || {} };
|
|
43
|
+
const baseDecision = {
|
|
44
|
+
mode: this.mode,
|
|
45
|
+
selector: this.selector,
|
|
46
|
+
action: 'skip',
|
|
47
|
+
accepted: false,
|
|
48
|
+
selectedEntryId: '',
|
|
49
|
+
selectedScore: null,
|
|
50
|
+
candidateCount: 0,
|
|
51
|
+
reasons: [],
|
|
52
|
+
reason: '',
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (!this.store || this.mode === 'off' || !toolName) {
|
|
56
|
+
return { call: clonedCall, decision: { ...baseDecision, reason: 'disabled_or_unavailable' }, candidates: [] };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const selected = await this.selectCandidate({ context, prediction, toolName });
|
|
60
|
+
const selection = selected.selection || null;
|
|
61
|
+
const candidates = selected.candidates || [];
|
|
62
|
+
const selectedInput = safeObject(selection?.input);
|
|
63
|
+
const canUseSelection = Boolean(selection?.accepted && selection?.tool === toolName && Object.keys(selectedInput).length);
|
|
64
|
+
const decision = {
|
|
65
|
+
...baseDecision,
|
|
66
|
+
selectedEntryId: selection?.id || '',
|
|
67
|
+
selectedScore: Number.isFinite(Number(selection?.score)) ? Number(selection.score) : null,
|
|
68
|
+
candidateCount: candidates.length,
|
|
69
|
+
reasons: Array.isArray(selection?.reasons) ? selection.reasons.slice() : [],
|
|
70
|
+
reason: canUseSelection ? 'candidate_selected' : 'no_accepted_candidate',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
let preparedCall = clonedCall;
|
|
74
|
+
if (this.mode === 'audit') {
|
|
75
|
+
decision.action = 'observe';
|
|
76
|
+
decision.accepted = false;
|
|
77
|
+
decision.reason = selection?.id ? 'audit_only' : 'no_candidate';
|
|
78
|
+
} else if (canUseSelection && this.mode === 'assist') {
|
|
79
|
+
const mergedInput = fillMissingFields(clonedCall.input || {}, selectedInput);
|
|
80
|
+
preparedCall = { ...clonedCall, input: mergedInput };
|
|
81
|
+
decision.action = 'assist';
|
|
82
|
+
decision.accepted = true;
|
|
83
|
+
} else if (canUseSelection && this.mode === 'apply') {
|
|
84
|
+
preparedCall = { ...clonedCall, input: cloneJson(selectedInput) };
|
|
85
|
+
decision.action = 'apply';
|
|
86
|
+
decision.accepted = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.recordAudit({
|
|
90
|
+
mode: this.mode,
|
|
91
|
+
context,
|
|
92
|
+
prediction,
|
|
93
|
+
selected: selection ? { ...selection, accepted: decision.accepted } : null,
|
|
94
|
+
candidates,
|
|
95
|
+
reason: decision.reason,
|
|
96
|
+
model,
|
|
97
|
+
sessionId,
|
|
98
|
+
prompt,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return { call: preparedCall, decision, candidates };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async selectCandidate({ context, prediction, toolName }) {
|
|
105
|
+
if ((this.selector === 'replay' || this.selector === 'auto') && REPLAY_SELECTOR_TOOLS.has(toolName)) {
|
|
106
|
+
const replaySelected = this.selectReplayCandidate({ context, prediction, toolName });
|
|
107
|
+
if (replaySelected.selection || replaySelected.candidates?.length || this.selector === 'replay') {
|
|
108
|
+
return replaySelected;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!this.store?.selectActionMemoryCandidate) return { selection: null, candidates: [] };
|
|
112
|
+
return this.store.selectActionMemoryCandidate({
|
|
113
|
+
context,
|
|
114
|
+
prediction,
|
|
115
|
+
toolName,
|
|
116
|
+
minScore: this.minScore,
|
|
117
|
+
minMargin: this.minMargin,
|
|
118
|
+
limit: this.limit,
|
|
119
|
+
}) || { selection: null, candidates: [] };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
selectReplayCandidate({ context = {}, prediction = null, toolName = '' } = {}) {
|
|
123
|
+
if (!this.store?.searchActionMemoryCandidates) return { selection: null, candidates: [] };
|
|
124
|
+
const example = replayExampleFromRuntimeContext(context, { toolName, prediction });
|
|
125
|
+
try {
|
|
126
|
+
if (toolName === 'run_shell') {
|
|
127
|
+
const {
|
|
128
|
+
applyRunShellCommandSelection,
|
|
129
|
+
} = require('../training/run-shell-command-selector');
|
|
130
|
+
const selected = applyRunShellCommandSelection(example, prediction, {
|
|
131
|
+
actionMemoryStore: this.store,
|
|
132
|
+
maxCandidates: this.maxCandidates,
|
|
133
|
+
memoryLimit: this.memoryLimit,
|
|
134
|
+
});
|
|
135
|
+
return normalizeRunShellPolicySelection(selected, prediction);
|
|
136
|
+
}
|
|
137
|
+
const {
|
|
138
|
+
applyTrajectoryActionSelection,
|
|
139
|
+
} = require('../training/trajectory-action-selector');
|
|
140
|
+
return applyTrajectoryActionSelection(example, prediction, {
|
|
141
|
+
actionMemoryStore: this.store,
|
|
142
|
+
maxCandidates: this.maxCandidates,
|
|
143
|
+
memoryLimit: this.memoryLimit,
|
|
144
|
+
minScore: this.minScore,
|
|
145
|
+
});
|
|
146
|
+
} catch (err) {
|
|
147
|
+
this.logger?.warn?.(`[action-memory] replay selector failed: ${err.message}`);
|
|
148
|
+
return { selection: null, candidates: [] };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
recordAudit(row) {
|
|
153
|
+
if (!this.store?.recordSelectionAudit) return null;
|
|
154
|
+
try {
|
|
155
|
+
return this.store.recordSelectionAudit(row);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
this.logger?.warn?.(`[action-memory] failed to record selection audit: ${err.message}`);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function executeToolCallWithActionMemoryPolicy({
|
|
164
|
+
call = {},
|
|
165
|
+
context = {},
|
|
166
|
+
model = {},
|
|
167
|
+
sessionId = '',
|
|
168
|
+
prompt = '',
|
|
169
|
+
policy = null,
|
|
170
|
+
execute,
|
|
171
|
+
} = {}) {
|
|
172
|
+
if (typeof execute !== 'function') throw new Error('executeToolCallWithActionMemoryPolicy requires execute');
|
|
173
|
+
const evaluated = policy?.evaluateToolCall
|
|
174
|
+
? await policy.evaluateToolCall({ call, context, model, sessionId, prompt })
|
|
175
|
+
: { call: cloneToolCall(call), decision: { mode: 'off', action: 'skip', accepted: false }, candidates: [] };
|
|
176
|
+
const execution = await execute(evaluated.call, evaluated.decision);
|
|
177
|
+
if (execution && typeof execution === 'object') {
|
|
178
|
+
execution.actionMemory = {
|
|
179
|
+
decision: evaluated.decision,
|
|
180
|
+
candidateCount: evaluated.candidates.length,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return execution;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function cloneToolCall(call = {}) {
|
|
187
|
+
return {
|
|
188
|
+
...call,
|
|
189
|
+
input: cloneJson(call.input || {}),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function toolNameFromCall(call = {}) {
|
|
194
|
+
return String(call.name || call.tool || '').trim();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function fillMissingFields(originalInput = {}, memoryInput = {}) {
|
|
198
|
+
const merged = cloneJson(originalInput || {});
|
|
199
|
+
for (const [key, value] of Object.entries(memoryInput || {})) {
|
|
200
|
+
if (merged[key] === undefined || merged[key] === null || merged[key] === '') {
|
|
201
|
+
merged[key] = cloneJson(value);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return merged;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function cloneJson(value) {
|
|
208
|
+
try {
|
|
209
|
+
return JSON.parse(JSON.stringify(value ?? null));
|
|
210
|
+
} catch {
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function safeObject(value) {
|
|
216
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function finiteNumber(value, fallback) {
|
|
220
|
+
const numeric = Number(value);
|
|
221
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function normalizeMode(mode) {
|
|
225
|
+
const value = String(mode || 'audit').trim().toLowerCase();
|
|
226
|
+
return MODES.has(value) ? value : 'audit';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function normalizeSelector(selector) {
|
|
230
|
+
const value = String(selector || 'store').trim().toLowerCase();
|
|
231
|
+
return SELECTORS.has(value) ? value : 'store';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function normalizeRunShellPolicySelection(selected = {}, prediction = null) {
|
|
235
|
+
const candidates = (selected.candidates || []).map((candidate) => ({
|
|
236
|
+
...candidate,
|
|
237
|
+
tool: 'run_shell',
|
|
238
|
+
input: { command: candidate.command },
|
|
239
|
+
id: candidate.memoryEntryId || '',
|
|
240
|
+
candidateId: candidate.id || '',
|
|
241
|
+
reasons: [
|
|
242
|
+
candidate.reason,
|
|
243
|
+
candidate.source,
|
|
244
|
+
...(candidate.memoryReasons || []),
|
|
245
|
+
].filter(Boolean),
|
|
246
|
+
}));
|
|
247
|
+
const selection = selected.selection || null;
|
|
248
|
+
if (!selection?.command) return { selection: null, candidates };
|
|
249
|
+
const matched = candidates.find((candidate) => candidate.command === selection.command) || {};
|
|
250
|
+
return {
|
|
251
|
+
selection: {
|
|
252
|
+
id: selection.memoryEntryId || matched.id || '',
|
|
253
|
+
candidateId: selection.id || matched.candidateId || '',
|
|
254
|
+
tool: 'run_shell',
|
|
255
|
+
input: {
|
|
256
|
+
...(prediction?.input || {}),
|
|
257
|
+
command: selection.command,
|
|
258
|
+
},
|
|
259
|
+
score: finiteNumber(selection.score ?? matched.score, null),
|
|
260
|
+
reasons: [
|
|
261
|
+
selection.reason,
|
|
262
|
+
selection.source,
|
|
263
|
+
...(selection.memoryReasons || matched.memoryReasons || []),
|
|
264
|
+
].filter(Boolean),
|
|
265
|
+
sourceKind: selection.source,
|
|
266
|
+
sourceRowId: selection.sourceRowId || matched.sourceRowId,
|
|
267
|
+
sourceSessionId: selection.sourceSessionId || matched.sourceSessionId,
|
|
268
|
+
sourceToolCallId: selection.sourceToolCallId || matched.sourceToolCallId,
|
|
269
|
+
targetHint: selection.command,
|
|
270
|
+
accepted: true,
|
|
271
|
+
},
|
|
272
|
+
candidates,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function replayExampleFromRuntimeContext(context = {}, { toolName = '', prediction = null } = {}) {
|
|
277
|
+
const labels = {
|
|
278
|
+
workflow_family_id: context.familyId || context.workflowFamilyId || context.workflow_family_id || null,
|
|
279
|
+
workflow_repo: context.repoKey || context.repo || context.workflowRepo || context.workflow_repo || null,
|
|
280
|
+
workflow_intent: context.intent || context.workflowIntent || context.workflow_intent || null,
|
|
281
|
+
tool_name: toolName || prediction?.name || null,
|
|
282
|
+
};
|
|
283
|
+
const verificationCommands = normalizeCommandList(
|
|
284
|
+
context.verificationCommands || context.verification_commands || context.rememberedTaskCommands
|
|
285
|
+
);
|
|
286
|
+
if (verificationCommands.length) labels.verification_commands = verificationCommands;
|
|
287
|
+
|
|
288
|
+
const stateLines = [
|
|
289
|
+
['tool sequence', context.sequence || context.stateSequence || context.toolSequence],
|
|
290
|
+
['last tool', context.lastTool || context.last_tool],
|
|
291
|
+
['recent shell commands', formatRecentShellCommands(context.recentShellCommands || context.recent_shell_commands)],
|
|
292
|
+
['known failures', formatListValue(context.knownFailures || context.known_failures)],
|
|
293
|
+
['verification status', context.verificationStatus || context.verification_status],
|
|
294
|
+
['remembered task commands', formatCommandList(context.rememberedTaskCommands || context.remembered_task_commands)],
|
|
295
|
+
['remembered workflow commands', formatCommandList(context.rememberedWorkflowCommands || context.remembered_workflow_commands)],
|
|
296
|
+
]
|
|
297
|
+
.filter(([, value]) => value)
|
|
298
|
+
.map(([label, value]) => `- ${label}: ${value}`);
|
|
299
|
+
|
|
300
|
+
const taskText = String(context.taskText || context.task || context.userTask || context.taskPreview || '').trim();
|
|
301
|
+
const content = [
|
|
302
|
+
`Task:\n${taskText}`,
|
|
303
|
+
'',
|
|
304
|
+
'Current Wall-E state:',
|
|
305
|
+
...stateLines,
|
|
306
|
+
].join('\n').trim();
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
labels,
|
|
310
|
+
messages: [{ role: 'user', content }],
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function normalizeCommandList(value) {
|
|
315
|
+
if (!value) return [];
|
|
316
|
+
if (Array.isArray(value)) return value.map((item) => String(item || '').trim()).filter(Boolean);
|
|
317
|
+
return String(value).split(/\n|,\s+(?=(?:cd |git |npm |node |pnpm |yarn |uv |rg |sed |python|pytest|cargo|go |make ))/i)
|
|
318
|
+
.map((item) => item.trim())
|
|
319
|
+
.filter(Boolean);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function formatCommandList(value) {
|
|
323
|
+
return normalizeCommandList(value).join(', ');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function formatRecentShellCommands(value) {
|
|
327
|
+
if (!value) return '';
|
|
328
|
+
if (typeof value === 'string') return value.trim();
|
|
329
|
+
if (!Array.isArray(value)) return '';
|
|
330
|
+
return value.map((item) => {
|
|
331
|
+
if (typeof item === 'string') return item.trim();
|
|
332
|
+
const command = item.command || item.input?.command || item.args?.command || '';
|
|
333
|
+
if (!command) return '';
|
|
334
|
+
const status = item.status || (item.ok === false ? 'tool_error' : 'tool_result');
|
|
335
|
+
return `${status}: ${command}`;
|
|
336
|
+
}).filter(Boolean).join(', ');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function formatListValue(value) {
|
|
340
|
+
if (!value) return '';
|
|
341
|
+
if (Array.isArray(value)) return value.map((item) => String(item || '').trim()).filter(Boolean).join(', ');
|
|
342
|
+
return String(value || '').trim();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
module.exports = {
|
|
346
|
+
ActionMemoryPolicy,
|
|
347
|
+
DEFAULT_LIMIT,
|
|
348
|
+
DEFAULT_MIN_MARGIN,
|
|
349
|
+
DEFAULT_MIN_SCORE,
|
|
350
|
+
executeToolCallWithActionMemoryPolicy,
|
|
351
|
+
fillMissingFields,
|
|
352
|
+
replayExampleFromRuntimeContext,
|
|
353
|
+
};
|