agentxchain 0.8.7 → 2.1.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/README.md +123 -154
- package/bin/agentxchain.js +240 -8
- package/dashboard/app.js +305 -0
- package/dashboard/components/blocked.js +145 -0
- package/dashboard/components/cross-repo.js +126 -0
- package/dashboard/components/gate.js +311 -0
- package/dashboard/components/hooks.js +177 -0
- package/dashboard/components/initiative.js +147 -0
- package/dashboard/components/ledger.js +165 -0
- package/dashboard/components/timeline.js +222 -0
- package/dashboard/index.html +352 -0
- package/package.json +16 -7
- package/scripts/agentxchain-autonudge.applescript +32 -5
- package/scripts/live-api-proxy-preflight-smoke.sh +531 -0
- package/scripts/publish-from-tag.sh +88 -0
- package/scripts/release-postflight.sh +231 -0
- package/scripts/release-preflight.sh +167 -0
- package/scripts/run-autonudge.sh +1 -1
- package/src/adapters/claude-code.js +7 -14
- package/src/adapters/cursor-local.js +17 -16
- package/src/commands/accept-turn.js +160 -0
- package/src/commands/approve-completion.js +80 -0
- package/src/commands/approve-transition.js +85 -0
- package/src/commands/branch.js +2 -2
- package/src/commands/claim.js +84 -9
- package/src/commands/config.js +16 -0
- package/src/commands/dashboard.js +70 -0
- package/src/commands/doctor.js +9 -1
- package/src/commands/init.js +540 -5
- package/src/commands/migrate.js +348 -0
- package/src/commands/multi.js +549 -0
- package/src/commands/plugin.js +157 -0
- package/src/commands/reject-turn.js +204 -0
- package/src/commands/resume.js +389 -0
- package/src/commands/status.js +196 -3
- package/src/commands/step.js +947 -0
- package/src/commands/stop.js +65 -33
- package/src/commands/template-list.js +33 -0
- package/src/commands/template-set.js +279 -0
- package/src/commands/update.js +24 -3
- package/src/commands/validate.js +20 -11
- package/src/commands/verify.js +71 -0
- package/src/commands/watch.js +112 -25
- package/src/lib/adapters/api-proxy-adapter.js +1076 -0
- package/src/lib/adapters/local-cli-adapter.js +337 -0
- package/src/lib/adapters/manual-adapter.js +169 -0
- package/src/lib/blocked-state.js +94 -0
- package/src/lib/config.js +143 -12
- package/src/lib/context-compressor.js +121 -0
- package/src/lib/context-section-parser.js +220 -0
- package/src/lib/coordinator-acceptance.js +428 -0
- package/src/lib/coordinator-config.js +461 -0
- package/src/lib/coordinator-dispatch.js +276 -0
- package/src/lib/coordinator-gates.js +487 -0
- package/src/lib/coordinator-hooks.js +239 -0
- package/src/lib/coordinator-recovery.js +523 -0
- package/src/lib/coordinator-state.js +365 -0
- package/src/lib/cross-repo-context.js +247 -0
- package/src/lib/dashboard/bridge-server.js +284 -0
- package/src/lib/dashboard/file-watcher.js +93 -0
- package/src/lib/dashboard/state-reader.js +96 -0
- package/src/lib/dispatch-bundle.js +568 -0
- package/src/lib/dispatch-manifest.js +252 -0
- package/src/lib/filter-agents.js +12 -0
- package/src/lib/gate-evaluator.js +285 -0
- package/src/lib/generate-vscode.js +158 -68
- package/src/lib/governed-state.js +2139 -0
- package/src/lib/governed-templates.js +145 -0
- package/src/lib/hook-runner.js +788 -0
- package/src/lib/next-owner.js +61 -6
- package/src/lib/normalized-config.js +539 -0
- package/src/lib/notify.js +14 -12
- package/src/lib/plugin-config-schema.js +192 -0
- package/src/lib/plugins.js +692 -0
- package/src/lib/prompt-core.js +108 -0
- package/src/lib/protocol-conformance.js +291 -0
- package/src/lib/reference-conformance-adapter.js +717 -0
- package/src/lib/repo-observer.js +597 -0
- package/src/lib/repo.js +0 -31
- package/src/lib/safe-write.js +44 -0
- package/src/lib/schema.js +189 -0
- package/src/lib/schemas/turn-result.schema.json +205 -0
- package/src/lib/seed-prompt-polling.js +15 -73
- package/src/lib/seed-prompt.js +17 -63
- package/src/lib/token-budget.js +206 -0
- package/src/lib/token-counter.js +27 -0
- package/src/lib/turn-paths.js +67 -0
- package/src/lib/turn-result-validator.js +496 -0
- package/src/lib/validation.js +167 -19
- package/src/lib/verify-command.js +72 -0
- package/src/templates/governed/api-service.json +31 -0
- package/src/templates/governed/cli-tool.json +30 -0
- package/src/templates/governed/generic.json +10 -0
- package/src/templates/governed/web-app.json +30 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token budget evaluator for preflight tokenization.
|
|
3
|
+
*
|
|
4
|
+
* Combines the context section parser, context compressor, and token counter
|
|
5
|
+
* to produce a TokenBudgetReport and effective context for api_proxy dispatch.
|
|
6
|
+
*
|
|
7
|
+
* This is a pure computation helper — it does not perform network dispatch,
|
|
8
|
+
* write audit artifacts, or mutate state.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { countTokens } from './token-counter.js';
|
|
12
|
+
import { parseContextSections, renderContextSections } from './context-section-parser.js';
|
|
13
|
+
import { compressContextSections } from './context-compressor.js';
|
|
14
|
+
import { getDispatchEffectiveContextPath } from './turn-paths.js';
|
|
15
|
+
|
|
16
|
+
const SEPARATOR = '\n\n---\n\n';
|
|
17
|
+
|
|
18
|
+
const SYSTEM_PROMPT = [
|
|
19
|
+
'You are acting as a governed agent in an AgentXchain protocol run.',
|
|
20
|
+
'Your task and rules are described in the user message.',
|
|
21
|
+
'You MUST respond with a valid JSON object matching the turn result schema provided in the prompt.',
|
|
22
|
+
'Do NOT wrap the JSON in markdown code fences. Respond with raw JSON only.',
|
|
23
|
+
].join('\n');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Evaluate the token budget for a preflight tokenization check.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} params
|
|
29
|
+
* @param {string} params.promptMd - Full PROMPT.md text
|
|
30
|
+
* @param {string} params.contextMd - Full CONTEXT.md text (may be empty)
|
|
31
|
+
* @param {string} params.provider - Provider name (e.g. "anthropic")
|
|
32
|
+
* @param {string} params.model - Model identifier
|
|
33
|
+
* @param {string} params.runtimeId - Runtime identifier for the report
|
|
34
|
+
* @param {string} params.runId - Run identifier for the report
|
|
35
|
+
* @param {string} params.turnId - Turn identifier for the report
|
|
36
|
+
* @param {number} params.contextWindowTokens - Total context window size
|
|
37
|
+
* @param {number} params.maxOutputTokens - Reserved output tokens
|
|
38
|
+
* @param {number} params.safetyMarginTokens - Safety margin tokens
|
|
39
|
+
* @returns {TokenBudgetResult}
|
|
40
|
+
*/
|
|
41
|
+
export function evaluateTokenBudget({
|
|
42
|
+
promptMd,
|
|
43
|
+
contextMd,
|
|
44
|
+
provider,
|
|
45
|
+
model,
|
|
46
|
+
runtimeId,
|
|
47
|
+
runId,
|
|
48
|
+
turnId,
|
|
49
|
+
contextWindowTokens,
|
|
50
|
+
maxOutputTokens,
|
|
51
|
+
safetyMarginTokens,
|
|
52
|
+
}) {
|
|
53
|
+
const reservedOutputTokens = maxOutputTokens || 4096;
|
|
54
|
+
const safetyMargin = safetyMarginTokens ?? 2048;
|
|
55
|
+
const availableInputTokens = contextWindowTokens - reservedOutputTokens - safetyMargin;
|
|
56
|
+
|
|
57
|
+
// Count immutable parts
|
|
58
|
+
const systemPromptTokens = countTokens(SYSTEM_PROMPT, provider);
|
|
59
|
+
const promptTokens = countTokens(promptMd || '', provider);
|
|
60
|
+
const hasSeparator = !!(contextMd && contextMd.trim());
|
|
61
|
+
const separatorTokens = hasSeparator ? countTokens(SEPARATOR, provider) : 0;
|
|
62
|
+
const immutableTokens = systemPromptTokens + promptTokens + separatorTokens;
|
|
63
|
+
|
|
64
|
+
// Build base report fields
|
|
65
|
+
const baseReport = {
|
|
66
|
+
provider,
|
|
67
|
+
model,
|
|
68
|
+
runtime_id: runtimeId,
|
|
69
|
+
run_id: runId,
|
|
70
|
+
turn_id: turnId,
|
|
71
|
+
tokenizer: 'provider_local',
|
|
72
|
+
context_window_tokens: contextWindowTokens,
|
|
73
|
+
reserved_output_tokens: reservedOutputTokens,
|
|
74
|
+
safety_margin_tokens: safetyMargin,
|
|
75
|
+
available_input_tokens: availableInputTokens,
|
|
76
|
+
system_prompt_tokens: systemPromptTokens,
|
|
77
|
+
prompt_tokens: promptTokens,
|
|
78
|
+
separator_tokens: separatorTokens,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Prompt-only overflow: if immutable parts alone exceed budget, fail immediately
|
|
82
|
+
if (immutableTokens > availableInputTokens) {
|
|
83
|
+
const originalContextTokens = hasSeparator
|
|
84
|
+
? countTokens(contextMd, provider)
|
|
85
|
+
: 0;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
sent_to_provider: false,
|
|
89
|
+
effective_context: hasSeparator ? contextMd : '',
|
|
90
|
+
report: {
|
|
91
|
+
...baseReport,
|
|
92
|
+
original_context_tokens: originalContextTokens,
|
|
93
|
+
final_context_tokens: originalContextTokens,
|
|
94
|
+
estimated_input_tokens: immutableTokens + originalContextTokens,
|
|
95
|
+
truncated: false,
|
|
96
|
+
sent_to_provider: false,
|
|
97
|
+
effective_context_path: getDispatchEffectiveContextPath(turnId),
|
|
98
|
+
sections: [],
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// No context case
|
|
104
|
+
if (!hasSeparator) {
|
|
105
|
+
return {
|
|
106
|
+
sent_to_provider: true,
|
|
107
|
+
effective_context: '',
|
|
108
|
+
report: {
|
|
109
|
+
...baseReport,
|
|
110
|
+
original_context_tokens: 0,
|
|
111
|
+
final_context_tokens: 0,
|
|
112
|
+
estimated_input_tokens: immutableTokens,
|
|
113
|
+
truncated: false,
|
|
114
|
+
sent_to_provider: true,
|
|
115
|
+
effective_context_path: getDispatchEffectiveContextPath(turnId),
|
|
116
|
+
sections: [],
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Parse context into sections and count original tokens per section
|
|
122
|
+
const sections = parseContextSections(contextMd);
|
|
123
|
+
const originalTokensById = new Map();
|
|
124
|
+
for (const section of sections) {
|
|
125
|
+
originalTokensById.set(section.id, countTokens(section.content, provider));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const originalContextTokens = countTokens(contextMd, provider);
|
|
129
|
+
|
|
130
|
+
// Budget callback for the compressor: check if the full outbound request fits
|
|
131
|
+
function fitsInBudget(effectiveContext) {
|
|
132
|
+
const contextTokens = countTokens(effectiveContext, provider);
|
|
133
|
+
return immutableTokens + contextTokens <= availableInputTokens;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check if it fits without compression
|
|
137
|
+
if (fitsInBudget(contextMd)) {
|
|
138
|
+
const sectionActions = sections.map((s) => ({
|
|
139
|
+
id: s.id,
|
|
140
|
+
required: s.required,
|
|
141
|
+
original_tokens: originalTokensById.get(s.id),
|
|
142
|
+
final_tokens: originalTokensById.get(s.id),
|
|
143
|
+
action: 'kept',
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
sent_to_provider: true,
|
|
148
|
+
effective_context: contextMd,
|
|
149
|
+
report: {
|
|
150
|
+
...baseReport,
|
|
151
|
+
original_context_tokens: originalContextTokens,
|
|
152
|
+
final_context_tokens: originalContextTokens,
|
|
153
|
+
estimated_input_tokens: immutableTokens + originalContextTokens,
|
|
154
|
+
truncated: false,
|
|
155
|
+
sent_to_provider: true,
|
|
156
|
+
effective_context_path: getDispatchEffectiveContextPath(turnId),
|
|
157
|
+
sections: sectionActions,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Run compression
|
|
163
|
+
const compressionResult = compressContextSections(sections, fitsInBudget);
|
|
164
|
+
const effectiveContext = compressionResult.effective_context;
|
|
165
|
+
const finalContextTokens = countTokens(effectiveContext, provider);
|
|
166
|
+
const estimatedInputTokens = immutableTokens + finalContextTokens;
|
|
167
|
+
const sentToProvider = !compressionResult.exhausted;
|
|
168
|
+
|
|
169
|
+
// Build per-section actions with token counts
|
|
170
|
+
const sectionActions = compressionResult.actions.map((a) => {
|
|
171
|
+
let finalTokens;
|
|
172
|
+
if (a.action === 'dropped') {
|
|
173
|
+
finalTokens = 0;
|
|
174
|
+
} else if (a.action === 'truncated') {
|
|
175
|
+
const remaining = compressionResult.sections.find((s) => s.id === a.id);
|
|
176
|
+
finalTokens = remaining ? countTokens(remaining.content, provider) : 0;
|
|
177
|
+
} else {
|
|
178
|
+
finalTokens = originalTokensById.get(a.id) ?? 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
id: a.id,
|
|
183
|
+
required: a.required,
|
|
184
|
+
original_tokens: originalTokensById.get(a.id) ?? 0,
|
|
185
|
+
final_tokens: finalTokens,
|
|
186
|
+
action: a.action,
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
sent_to_provider: sentToProvider,
|
|
192
|
+
effective_context: effectiveContext,
|
|
193
|
+
report: {
|
|
194
|
+
...baseReport,
|
|
195
|
+
original_context_tokens: originalContextTokens,
|
|
196
|
+
final_context_tokens: finalContextTokens,
|
|
197
|
+
estimated_input_tokens: estimatedInputTokens,
|
|
198
|
+
truncated: compressionResult.steps_applied > 0,
|
|
199
|
+
sent_to_provider: sentToProvider,
|
|
200
|
+
effective_context_path: getDispatchEffectiveContextPath(turnId),
|
|
201
|
+
sections: sectionActions,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export { SYSTEM_PROMPT, SEPARATOR };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { countTokens as countAnthropicTokens } from '@anthropic-ai/tokenizer';
|
|
2
|
+
|
|
3
|
+
const SUPPORTED_TOKEN_COUNTER_PROVIDERS = ['anthropic'];
|
|
4
|
+
|
|
5
|
+
export { SUPPORTED_TOKEN_COUNTER_PROVIDERS };
|
|
6
|
+
|
|
7
|
+
export function countTokens(text, provider = 'anthropic') {
|
|
8
|
+
const normalizedProvider = String(provider || '').trim().toLowerCase();
|
|
9
|
+
|
|
10
|
+
if (!SUPPORTED_TOKEN_COUNTER_PROVIDERS.includes(normalizedProvider)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`Unsupported token counter provider "${provider}". Supported: ${SUPPORTED_TOKEN_COUNTER_PROVIDERS.join(', ')}`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const normalizedText = String(text ?? '');
|
|
17
|
+
if (!normalizedText) {
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const tokens = countAnthropicTokens(normalizedText);
|
|
22
|
+
if (!Number.isInteger(tokens) || tokens < 0) {
|
|
23
|
+
throw new Error(`Anthropic tokenizer returned invalid token count: ${tokens}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return tokens;
|
|
27
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const DISPATCH_ROOT = '.agentxchain/dispatch';
|
|
2
|
+
const DISPATCH_INDEX_PATH = `${DISPATCH_ROOT}/index.json`;
|
|
3
|
+
const DISPATCH_TURNS_DIR = `${DISPATCH_ROOT}/turns`;
|
|
4
|
+
const STAGING_ROOT = '.agentxchain/staging';
|
|
5
|
+
|
|
6
|
+
export function getDispatchTurnDir(turnId) {
|
|
7
|
+
return `${DISPATCH_TURNS_DIR}/${turnId}`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getDispatchPromptPath(turnId) {
|
|
11
|
+
return `${getDispatchTurnDir(turnId)}/PROMPT.md`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getDispatchContextPath(turnId) {
|
|
15
|
+
return `${getDispatchTurnDir(turnId)}/CONTEXT.md`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getDispatchAssignmentPath(turnId) {
|
|
19
|
+
return `${getDispatchTurnDir(turnId)}/ASSIGNMENT.json`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getDispatchApiRequestPath(turnId) {
|
|
23
|
+
return `${getDispatchTurnDir(turnId)}/API_REQUEST.json`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getDispatchTokenBudgetPath(turnId) {
|
|
27
|
+
return `${getDispatchTurnDir(turnId)}/TOKEN_BUDGET.json`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getDispatchEffectiveContextPath(turnId) {
|
|
31
|
+
return `${getDispatchTurnDir(turnId)}/CONTEXT.effective.md`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getDispatchManifestPath(turnId) {
|
|
35
|
+
return `${getDispatchTurnDir(turnId)}/MANIFEST.json`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getDispatchLogPath(turnId) {
|
|
39
|
+
return `${getDispatchTurnDir(turnId)}/stdout.log`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getTurnStagingDir(turnId) {
|
|
43
|
+
return `${STAGING_ROOT}/${turnId}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getTurnStagingResultPath(turnId) {
|
|
47
|
+
return `${getTurnStagingDir(turnId)}/turn-result.json`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getTurnProviderResponsePath(turnId) {
|
|
51
|
+
return `${getTurnStagingDir(turnId)}/provider-response.json`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getTurnApiErrorPath(turnId) {
|
|
55
|
+
return `${getTurnStagingDir(turnId)}/api-error.json`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getTurnRetryTracePath(turnId) {
|
|
59
|
+
return `${getTurnStagingDir(turnId)}/retry-trace.json`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
DISPATCH_ROOT,
|
|
64
|
+
DISPATCH_INDEX_PATH,
|
|
65
|
+
DISPATCH_TURNS_DIR,
|
|
66
|
+
STAGING_ROOT,
|
|
67
|
+
};
|