hoi4-agent-tools 3.10.0 → 4.0.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/CHANGELOG.md +131 -0
- package/README.md +91 -147
- package/dist/bin/http.js +10 -0
- package/dist/bin/setup.js +3 -2
- package/dist/bin/stdio.js +10 -0
- package/dist/hoi4_agent_tools/core/artifacts.js +40 -5
- package/dist/hoi4_agent_tools/core/canonical.js +18 -4
- package/dist/hoi4_agent_tools/core/condition-evaluator.js +18 -0
- package/dist/hoi4_agent_tools/core/configuration.js +7 -0
- package/dist/hoi4_agent_tools/core/domain-scan-patterns.js +12 -0
- package/dist/hoi4_agent_tools/core/domain-tools.js +65 -0
- package/dist/hoi4_agent_tools/core/domain-validation.js +5 -2
- package/dist/hoi4_agent_tools/core/engine.js +29 -2
- package/dist/hoi4_agent_tools/core/index.js +2 -2
- package/dist/hoi4_agent_tools/core/job-executor.js +14 -1
- package/dist/hoi4_agent_tools/core/job-operation-registration.js +15 -7
- package/dist/hoi4_agent_tools/core/job-store.js +78 -5
- package/dist/hoi4_agent_tools/core/job-transactions.js +31 -2
- package/dist/hoi4_agent_tools/core/job-worker-host.js +314 -127
- package/dist/hoi4_agent_tools/core/job-worker.js +96 -37
- package/dist/hoi4_agent_tools/core/operation-result.js +123 -10
- package/dist/hoi4_agent_tools/core/operation-tasks.js +49 -89
- package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +25 -21
- package/dist/hoi4_agent_tools/core/server-registry.js +22 -5
- package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
- package/dist/hoi4_agent_tools/core/source/cache.js +20 -10
- package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
- package/dist/hoi4_agent_tools/core/temporary-directories.js +293 -0
- package/dist/hoi4_agent_tools/core/transactions.js +114 -23
- package/dist/hoi4_agent_tools/core/worker-exit.js +80 -0
- package/dist/hoi4_agent_tools/core/workspace.js +84 -8
- package/dist/hoi4_agent_tools/decision/ai.js +1 -1
- package/dist/hoi4_agent_tools/decision/service.js +28 -0
- package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
- package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
- package/dist/hoi4_agent_tools/event/operations.js +14 -1
- package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
- package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
- package/dist/hoi4_agent_tools/gui/assets.js +3 -0
- package/dist/hoi4_agent_tools/gui/dds.js +8 -4
- package/dist/hoi4_agent_tools/gui/layout.js +45 -5
- package/dist/hoi4_agent_tools/gui/native-state.js +244 -0
- package/dist/hoi4_agent_tools/gui/renderer.js +12 -7
- package/dist/hoi4_agent_tools/gui/source-graph.js +17 -4
- package/dist/hoi4_agent_tools/gui/studio.js +33 -21
- package/dist/hoi4_agent_tools/gui/validators.js +8 -6
- package/dist/hoi4_agent_tools/map/bmp.js +1 -1
- package/dist/hoi4_agent_tools/map/derived.js +748 -0
- package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
- package/dist/hoi4_agent_tools/map/model.js +103 -0
- package/dist/hoi4_agent_tools/map/operations.js +427 -58
- package/dist/hoi4_agent_tools/map/references.js +483 -0
- package/dist/hoi4_agent_tools/map/service.js +136 -61
- package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
- package/dist/hoi4_agent_tools/map/validation.js +3 -0
- package/dist/hoi4_agent_tools/map/world.js +1280 -0
- package/dist/hoi4_agent_tools/mcp/prompts/probability.js +2 -2
- package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
- package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
- package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
- package/dist/hoi4_agent_tools/mcp/server/instructions.js +1 -1
- package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
- package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
- package/dist/hoi4_agent_tools/mcp/tools/analysis.js +28 -8
- package/dist/hoi4_agent_tools/mcp/tools/event.js +19 -30
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +5 -13
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +6 -6
- package/dist/hoi4_agent_tools/mcp/tools/job.js +4 -4
- package/dist/hoi4_agent_tools/mcp/tools/map.js +15 -18
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
- package/dist/hoi4_agent_tools/mcp/tools/reference.js +26 -9
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +17 -30
- package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
- package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +31 -8
- package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
- package/dist/hoi4_agent_tools/probability/operations.js +175 -13
- package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
- package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
- package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
- package/dist/hoi4_agent_tools/reference/operations.js +88 -19
- package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
- package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
- package/dist/hoi4_agent_tools/reference/service.js +6 -0
- package/dist/hoi4_agent_tools/runtime.js +14 -1
- package/dist/hoi4_agent_tools/schemas/event.js +78 -19
- package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
- package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
- package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
- package/dist/hoi4_agent_tools/schemas/map.js +122 -3
- package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
- package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
- package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
- package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
- package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
- package/dist/hoi4_agent_tools/schemas/technology.js +79 -21
- package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
- package/dist/hoi4_agent_tools/technology/operations.js +14 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +7 -4
- package/docs/analysis.md +15 -2
- package/docs/configuration.md +281 -0
- package/docs/development.md +26 -2
- package/docs/events.md +29 -6
- package/docs/examples.md +13 -28
- package/docs/focus.md +127 -5
- package/docs/gui.md +105 -21
- package/docs/helper-expansion.md +9 -9
- package/docs/http.md +3 -1
- package/docs/jobs.md +23 -14
- package/docs/map.md +199 -7
- package/docs/mechanics.md +6 -2
- package/docs/probability.md +46 -16
- package/docs/reference.md +73 -5
- package/docs/setup.md +45 -14
- package/docs/technology.md +28 -4
- package/docs/third-party-notices.md +11 -0
- package/docs/tools.md +150 -42
- package/docs/troubleshooting.md +61 -0
- package/examples/clients/codex-config.toml +5 -2
- package/examples/clients/generic.json +2 -2
- package/examples/config/config.json +7 -0
- package/npm-shrinkwrap.json +151 -156
- package/package.json +13 -8
- package/schemas/configuration.schema.json +144 -128
- package/schemas/continuous-focus-palette.schema.json +1 -1
- package/schemas/custom-weighted-pool.schema.json +1 -1
- package/schemas/decision-inspect-input.schema.json +1 -1
- package/schemas/error-log-input.schema.json +55 -0
- package/schemas/event-feature-manifest.schema.json +1 -1
- package/schemas/focus-plan.schema.json +1 -1
- package/schemas/focus-planning-sidecar.schema.json +1 -1
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +1 -1
- package/schemas/gui-scenario.schema.json +1 -1
- package/schemas/helper-expansion-request.schema.json +1 -1
- package/schemas/helper-expansion-summary.schema.json +1 -1
- package/schemas/impact-inspect-input.schema.json +1 -1
- package/schemas/map-operation.schema.json +597 -126
- package/schemas/mechanic-test-input.schema.json +1 -1
- package/schemas/mod-index-input.schema.json +51 -0
- package/schemas/operation-result.schema.json +2 -2
- package/schemas/package-check-input.schema.json +1 -1
- package/schemas/package-manifest.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +1 -1
- package/schemas/probability-compare-input.schema.json +1 -1
- package/schemas/probability-evaluate-input.schema.json +1 -1
- package/schemas/probability-inspect-input.schema.json +1 -1
- package/schemas/probability-render-input.schema.json +1 -1
- package/schemas/probability-scenario-set.schema.json +1 -1
- package/schemas/probability-sequence-input.schema.json +1 -1
- package/schemas/probability-simulate-input.schema.json +1 -1
- package/schemas/probability-sweep-input.schema.json +1 -1
- package/schemas/reference-context-input.schema.json +1 -1
- package/schemas/reference-read-input.schema.json +1 -1
- package/schemas/reference-search-input.schema.json +1 -1
- package/schemas/scenario-suite.schema.json +3 -5
- package/schemas/scenario-test-input.schema.json +3 -5
- package/schemas/script-validate-input.schema.json +1 -1
- package/schemas/shared-scenario.schema.json +1 -1
- package/schemas/source-lookup-input.schema.json +1 -1
- package/server.json +3 -3
|
@@ -5,8 +5,8 @@ export const probabilityPromptArguments = z.object({
|
|
|
5
5
|
});
|
|
6
6
|
export const probabilityPromptDefinition = {
|
|
7
7
|
name: 'hoi4.probability_analysis',
|
|
8
|
-
title: 'Analyze
|
|
9
|
-
description: '
|
|
8
|
+
title: 'Analyze AI choices and event timing',
|
|
9
|
+
description: 'Outline an analysis of AI choices, event timing, random chances or a custom weighted pool.',
|
|
10
10
|
};
|
|
11
11
|
/** One prompt body for both protocol generations; it does not run an analysis. */
|
|
12
12
|
export function probabilityPrompt(input) {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { errorResult } from '../../core/operation-result.js';
|
|
2
|
+
import { ServiceError } from '../../core/result.js';
|
|
3
|
+
/**
|
|
4
|
+
* Invalid arguments come back as a tool error naming each wrong field, what it expected and a
|
|
5
|
+
* working call, not as a protocol error: clients show a tool error's text to the model, while
|
|
6
|
+
* some reduce a protocol error to a generic "Invalid tool arguments".
|
|
7
|
+
*/
|
|
8
|
+
export const ARGUMENT_EXAMPLES = {
|
|
9
|
+
'hoi4.reference_context': '{"surface":"event"}',
|
|
10
|
+
'hoi4.reference_search': '{"query":"add_timed_idea"}',
|
|
11
|
+
'hoi4.reference_read': '{"id":"<id of a reference_search result>","revision":"<revision of the same result>"}',
|
|
12
|
+
'hoi4.source_lookup': '{"symbol":"my_scripted_effect"} or {"path":"events/my_events.txt","line":42}',
|
|
13
|
+
'hoi4.script_validate': '{"path":"events/my_events.txt"} or {"source":"add_political_power = 10","kind":"effect","scope":"country"}',
|
|
14
|
+
'hoi4.error_log': '{"scope":"mod","category":"effect"}',
|
|
15
|
+
'hoi4.mod_index': '{"mode":"overview"} or {"mode":"next_id","kind":"event","namespace":"my_mod"}',
|
|
16
|
+
'hoi4.event_inspect': '{"mode":"lint","selector":"chaosx.nr14"} or {"mode":"trace","selector":"chaosx.nr14.1","direction":"downstream"}',
|
|
17
|
+
'hoi4.event_render': '{"view":"overview","selector":"chaosx.nr14"}',
|
|
18
|
+
'hoi4.focus_inspect': '{"treeId":"my_focus_tree"}',
|
|
19
|
+
'hoi4.focus_render': '{"relativePath":"common/national_focus/my_tree.txt","treeId":"my_focus_tree"}',
|
|
20
|
+
'hoi4.focus_rewrite': '{"relativePath":"common/national_focus/my_tree.txt","treeId":"my_focus_tree","layoutMode":"compact"}',
|
|
21
|
+
'hoi4.gui_inspect': '{"windowName":"my_window"}',
|
|
22
|
+
'hoi4.gui_render': '{"windowName":"my_window","scenario":{"id":"normal"}}',
|
|
23
|
+
'hoi4.gui_rewrite': '{"mode":"patches","relativePath":"interface/my_window.gui","windowName":"my_window","scenario":{"id":"normal"},"expectedSourceHash":"<sha256 of the file>","patches":[{"start":120,"end":130,"expectedText":"x = 10 y","text":"x = 40 y"}]}',
|
|
24
|
+
'hoi4.map_inspect': '{"query":"Brandenburg","lookupOnly":true} or {"layer":"state","tile":{"x":2600,"y":500,"width":256,"height":256}}',
|
|
25
|
+
'hoi4.map_rewrite': '{"operations":[{"id":"new-state","kind":"create_state","provinceIds":[120,121],"displayName":"New State"}]}',
|
|
26
|
+
'hoi4.tech_inspect': '{"mode":"scan"} or {"mode":"explain","technologyId":"my_tech"} or {"mode":"lint"}',
|
|
27
|
+
'hoi4.tech_render': '{"view":"folder","folderId":"my_folder"}',
|
|
28
|
+
'hoi4.probability_inspect': '{"candidatePool":["my_decision"]} or {"source":"events/my_events.txt","adapter":"event_option_ai_chance"}',
|
|
29
|
+
'hoi4.probability_analyze': '{"analysis":"sweep","source":"common/decisions/my_decisions.txt","candidatePool":["my_decision"],"scenarioSet":[{"actor":"GER","state":{"variable.pressure":10}}],"sweep":{"paths":["variable.pressure"],"steps":10}}',
|
|
30
|
+
'hoi4.impact_inspect': '{"symbols":[{"kind":"scripted_effect","id":"my_effect"}]} or {"changedFiles":["mod:common/scripted_effects/my_effects.txt"]}',
|
|
31
|
+
'hoi4.decision_inspect': '{"mode":"inventory"} or {"mode":"inspect","id":"my_decision","scenarios":[{"id":"base","actor":"GER","state":{}}]}',
|
|
32
|
+
'hoi4.mechanic_test': '{"test":{"id":"my_test","scenario":{"schemaVersion":"1.0","id":"my_test","state":{"treasury":10,"savings":2}},"steps":[{"kind":"effect","source":{"kind":"scripted_effect","id":"my_effect"}}],"assertions":[{"id":"kept","kind":"conservation","paths":[{"key":"treasury"},{"key":"savings"}]}]}}',
|
|
33
|
+
'hoi4.package_check': '{"manifest":{"schemaVersion":"1.0","id":"my_package","definitions":[{"kind":"scripted_effect","id":"my_effect"}]}}',
|
|
34
|
+
'hoi4.scenario_test': '{"suitePath":"tests/my_suite.json","maxCases":20}',
|
|
35
|
+
'hoi4.job_inspect': '{"jobId":"job_<64 hex characters from a native task id>"}',
|
|
36
|
+
'hoi4.job_cancel': '{"jobId":"job_<64 hex characters from a native task id>"}',
|
|
37
|
+
};
|
|
38
|
+
function describeIssue(issue) {
|
|
39
|
+
const field = issue.path.length === 0 ? '(arguments)' : issue.path.map(String).join('.');
|
|
40
|
+
let problem = issue.message;
|
|
41
|
+
if (issue.code === 'unrecognized_keys')
|
|
42
|
+
problem = `unknown field${issue.keys.length === 1 ? '' : 's'} ${issue.keys.join(', ')}`;
|
|
43
|
+
else if (issue.code === 'invalid_value')
|
|
44
|
+
problem = `expected one of ${issue.values.map((value) => JSON.stringify(value)).join(', ')}`;
|
|
45
|
+
else if (issue.code === 'invalid_union') {
|
|
46
|
+
// Name the alternative that came closest: the one with the fewest problems.
|
|
47
|
+
const closest = [...issue.errors].sort((left, right) => left.length - right.length)[0];
|
|
48
|
+
const first = closest?.[0];
|
|
49
|
+
if (first !== undefined) {
|
|
50
|
+
const nested = describeIssue(first);
|
|
51
|
+
problem = `${issue.message}; closest form: ${nested.field === '(arguments)' ? '' : `${nested.field}: `}${nested.problem}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { field, problem: problem.slice(0, 300) };
|
|
55
|
+
}
|
|
56
|
+
export function invalidArgumentsError(toolName, error) {
|
|
57
|
+
const issues = error.issues.slice(0, 6).map(describeIssue);
|
|
58
|
+
const example = ARGUMENT_EXAMPLES[toolName];
|
|
59
|
+
const message = [
|
|
60
|
+
`Invalid arguments for ${toolName}: ${issues.map(({ field, problem }) => `${field}: ${problem}`).join('; ')}.`,
|
|
61
|
+
...(example === undefined ? [] : [`Example: ${example}.`]),
|
|
62
|
+
'The tool input schema lists every accepted field.',
|
|
63
|
+
].join(' ');
|
|
64
|
+
return new ServiceError('INVALID_ARGUMENTS', message.slice(0, 1_500), {
|
|
65
|
+
tool: toolName,
|
|
66
|
+
issues,
|
|
67
|
+
...(example === undefined ? {} : { example }),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export function invalidArgumentsResult(toolName, error, workspaceId) {
|
|
71
|
+
return errorResult(invalidArgumentsError(toolName, error), typeof workspaceId === 'string' ? workspaceId : 'current');
|
|
72
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { normalizeToolArguments } from '../../schemas/lenient-arguments.js';
|
|
3
|
+
import { invalidArgumentsResult } from './argument-errors.js';
|
|
4
|
+
import { slimListedTool } from './tool-listing.js';
|
|
2
5
|
import { CallToolResultSchema, ClientCapabilitiesSchema, ListToolsResultSchema, } from '@modelcontextprotocol/core';
|
|
3
6
|
import { CLIENT_CAPABILITIES_META_KEY, inputRequired, ProtocolError, ProtocolErrorCode, } from '@modelcontextprotocol/server';
|
|
4
7
|
import { z } from 'zod/v4';
|
|
5
8
|
import { isJobControlTool, JobControlService } from '../../core/job-controls.js';
|
|
6
|
-
import { OperationTaskService } from '../../core/operation-tasks.js';
|
|
9
|
+
import { OperationTaskService, releaseIdleWorkers } from '../../core/operation-tasks.js';
|
|
7
10
|
import { errorResult } from '../../core/operation-result.js';
|
|
8
11
|
import { PACKAGE_NAME, PACKAGE_VERSION } from '../../version.js';
|
|
9
12
|
import { MODERN_TASK_ROUTES, ModernTaskRoutingServer } from '../transports/modern-task-routing.js';
|
|
@@ -62,10 +65,16 @@ export function createModernOperationServer(engine, context = {}, tasks = new Op
|
|
|
62
65
|
},
|
|
63
66
|
instructions: SERVER_INSTRUCTIONS,
|
|
64
67
|
});
|
|
68
|
+
// Warm job workers outlive single calls, not the client session that used them.
|
|
69
|
+
const previousOnClose = server.onclose;
|
|
70
|
+
server.onclose = () => {
|
|
71
|
+
previousOnClose?.();
|
|
72
|
+
void releaseIdleWorkers(engine);
|
|
73
|
+
};
|
|
65
74
|
registerModernResources(server, engine, context);
|
|
66
75
|
registerModernPrompts(server);
|
|
67
76
|
server.setRequestHandler('tools/list', () => ListToolsResultSchema.parse({
|
|
68
|
-
tools: definitions.map(({ name, inputSchema, outputSchema, ...metadata }) => ({
|
|
77
|
+
tools: definitions.map(({ name, inputSchema, outputSchema, ...metadata }) => slimListedTool({
|
|
69
78
|
...metadata,
|
|
70
79
|
name,
|
|
71
80
|
inputSchema: {
|
|
@@ -86,9 +95,18 @@ export function createModernOperationServer(engine, context = {}, tasks = new Op
|
|
|
86
95
|
const definition = definitions.find(({ name }) => name === request.params.name);
|
|
87
96
|
if (definition === undefined)
|
|
88
97
|
throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Unknown tool');
|
|
89
|
-
const input = definition.inputSchema.safeParse(request.params.arguments ?? {});
|
|
90
|
-
if (!input.success)
|
|
91
|
-
|
|
98
|
+
const input = definition.inputSchema.safeParse(normalizeToolArguments(definition.name, request.params.arguments ?? {}));
|
|
99
|
+
if (!input.success) {
|
|
100
|
+
// A tool error, not a protocol error, so the model sees which field to correct.
|
|
101
|
+
const workspaceId = request.params.arguments
|
|
102
|
+
?.workspaceId;
|
|
103
|
+
return CallToolResultSchema.parse({
|
|
104
|
+
...invalidArgumentsResult(definition.name, input.error, workspaceId),
|
|
105
|
+
resultType: 'complete',
|
|
106
|
+
ttlMs: 0,
|
|
107
|
+
cacheScope: 'private',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
92
110
|
const capabilities = clientCapabilities(extra.mcpReq.envelope);
|
|
93
111
|
const arguments_ = z.record(z.string(), z.json()).parse(input.data);
|
|
94
112
|
let operationContext = context;
|
|
@@ -14,6 +14,7 @@ import { registerMcpResources } from '../resources/register.js';
|
|
|
14
14
|
import { installRequestLifecycle } from './request-lifecycle.js';
|
|
15
15
|
import { PersistentJobTaskStore } from './job-task-store.js';
|
|
16
16
|
import { SERVER_INSTRUCTIONS } from './instructions.js';
|
|
17
|
+
import { releaseIdleWorkers } from '../../core/operation-tasks.js';
|
|
17
18
|
export { SERVER_INSTRUCTIONS } from './instructions.js';
|
|
18
19
|
export function createMcpServer(engine, context = {}) {
|
|
19
20
|
let serverContext = context;
|
|
@@ -31,6 +32,12 @@ export function createMcpServer(engine, context = {}) {
|
|
|
31
32
|
taskStore,
|
|
32
33
|
});
|
|
33
34
|
installRequestLifecycle(server, engine);
|
|
35
|
+
// Warm job workers outlive single calls, not the client session that used them.
|
|
36
|
+
const previousOnClose = server.server.onclose;
|
|
37
|
+
server.server.onclose = () => {
|
|
38
|
+
previousOnClose?.();
|
|
39
|
+
void releaseIdleWorkers(engine);
|
|
40
|
+
};
|
|
34
41
|
serverContext = {
|
|
35
42
|
...context,
|
|
36
43
|
resolveCurrentWorkspaceId: async (signal) => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Shared agent-facing guidance for both MCP protocol generations. */
|
|
2
|
-
export const SERVER_INSTRUCTIONS = 'Start with the matching inspect tool; use hoi4.probability_inspect for weights and timing. Find local documentation with hoi4.reference_context, hoi4.reference_search and hoi4.reference_read, and source definitions with hoi4.source_lookup.
|
|
2
|
+
export const SERVER_INSTRUCTIONS = 'Start with the matching inspect tool; use hoi4.probability_inspect for weights and timing. Find local documentation with hoi4.reference_context, hoi4.reference_search and hoi4.reference_read, and source definitions with hoi4.source_lookup. Rewrite tools edit mod source. Results describe offline source and scenario models, not observed game behavior. Unresolved states are not confirmed coverage. Read linked artifacts when summaries omit detail. Long operations support negotiated MCP tasks and hoi4.job_inspect/hoi4.job_cancel; background rewrites need a stable requestKey.';
|
|
@@ -1,47 +1,41 @@
|
|
|
1
1
|
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { DOMAIN_TOOL_NAMES } from '../../core/domain-tools.js';
|
|
3
|
+
import { normalizeToolArguments } from '../../schemas/lenient-arguments.js';
|
|
4
|
+
import { referenceTools } from '../tools/reference.js';
|
|
5
|
+
import { jobControlTools } from '../tools/job.js';
|
|
6
|
+
import { invalidArgumentsResult } from './argument-errors.js';
|
|
7
|
+
import { taskToolCatalog } from './task-tool-catalog.js';
|
|
2
8
|
import { progressReporter, withProgressHeartbeat } from './progress.js';
|
|
3
9
|
import { withTaskRequestSignal } from './task-request-context.js';
|
|
10
|
+
import { slimToolList } from './tool-listing.js';
|
|
4
11
|
// Durable task compatibility and cancellation are control traffic. They must
|
|
5
12
|
// remain responsive while every domain-execution slot is occupied.
|
|
6
13
|
const controlTools = new Set(['hoi4.job_inspect', 'hoi4.job_cancel']);
|
|
7
|
-
const backgroundTools = new Set(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'hoi4.event_inspect',
|
|
14
|
-
'hoi4.event_render',
|
|
15
|
-
'hoi4.event_compare',
|
|
16
|
-
'hoi4.tech_inspect',
|
|
17
|
-
'hoi4.tech_render',
|
|
18
|
-
'hoi4.tech_compare',
|
|
19
|
-
'hoi4.probability_inspect',
|
|
20
|
-
'hoi4.probability_evaluate',
|
|
21
|
-
'hoi4.probability_sweep',
|
|
22
|
-
'hoi4.probability_simulate',
|
|
23
|
-
'hoi4.probability_sequence',
|
|
24
|
-
'hoi4.probability_compare',
|
|
25
|
-
'hoi4.probability_render',
|
|
26
|
-
'hoi4.map_inspect',
|
|
27
|
-
'hoi4.map_render',
|
|
28
|
-
'hoi4.map_rewrite',
|
|
29
|
-
'hoi4.gui_inspect',
|
|
30
|
-
'hoi4.gui_render',
|
|
31
|
-
'hoi4.gui_rewrite',
|
|
32
|
-
'hoi4.focus_inspect',
|
|
33
|
-
'hoi4.focus_render',
|
|
34
|
-
'hoi4.focus_raster',
|
|
35
|
-
'hoi4.focus_rewrite',
|
|
36
|
-
]);
|
|
14
|
+
const backgroundTools = new Set(DOMAIN_TOOL_NAMES);
|
|
15
|
+
let inputSchemas;
|
|
16
|
+
function inputSchema(name) {
|
|
17
|
+
inputSchemas ??= new Map([...taskToolCatalog, ...referenceTools, ...jobControlTools].map(({ name: toolName, inputSchema: schema }) => [toolName, schema]));
|
|
18
|
+
return inputSchemas.get(name);
|
|
19
|
+
}
|
|
37
20
|
/** Wrap the public SDK handler registration so optional tools receive the same lifecycle. */
|
|
38
21
|
export function installRequestLifecycle(server, engine) {
|
|
39
22
|
const register = server.server.setRequestHandler.bind(server.server);
|
|
40
23
|
const owner = {};
|
|
41
24
|
server.server.setRequestHandler = (schema, handler) => {
|
|
42
25
|
register(schema, (request, extra) => {
|
|
26
|
+
if (request.method === 'tools/list')
|
|
27
|
+
return Promise.resolve(handler(request, extra)).then(slimToolList);
|
|
43
28
|
if (request.method !== 'tools/call')
|
|
44
29
|
return handler(request, extra);
|
|
30
|
+
const params = request.params;
|
|
31
|
+
if (params !== undefined && typeof params.name === 'string') {
|
|
32
|
+
params.arguments = normalizeToolArguments(params.name, params.arguments);
|
|
33
|
+
// Answer invalid arguments with a tool error that names the fields and a working call.
|
|
34
|
+
const schema = params.task === undefined ? inputSchema(params.name) : undefined;
|
|
35
|
+
const parsed = schema?.safeParse(params.arguments ?? {});
|
|
36
|
+
if (parsed !== undefined && !parsed.success)
|
|
37
|
+
return Promise.resolve(invalidArgumentsResult(params.name, parsed.error, params.arguments?.workspaceId));
|
|
38
|
+
}
|
|
45
39
|
const progress = progressReporter(extra);
|
|
46
40
|
const taskCall = CallToolRequestSchema.safeParse(request);
|
|
47
41
|
if (taskCall.success && controlTools.has(taskCall.data.params.name))
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every tool schema is sent to the client's model on each session, so listed schemas carry no
|
|
3
|
+
* bytes that change nothing: the per-schema `$schema` dialect declaration (the schemas use no
|
|
4
|
+
* dialect-specific keywords, so the MCP default dialect reads them identically) and the
|
|
5
|
+
* safe-integer bounds that every unbounded integer receives.
|
|
6
|
+
*/
|
|
7
|
+
const SAFE_INTEGER_BOUNDS = new Map([
|
|
8
|
+
['maximum', Number.MAX_SAFE_INTEGER],
|
|
9
|
+
['minimum', Number.MIN_SAFE_INTEGER],
|
|
10
|
+
]);
|
|
11
|
+
function slimSchema(value) {
|
|
12
|
+
if (Array.isArray(value))
|
|
13
|
+
return value.map(slimSchema);
|
|
14
|
+
if (value === null || typeof value !== 'object')
|
|
15
|
+
return value;
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const [key, child] of Object.entries(value)) {
|
|
18
|
+
if (key === '$schema')
|
|
19
|
+
continue;
|
|
20
|
+
if (SAFE_INTEGER_BOUNDS.get(key) === child)
|
|
21
|
+
continue;
|
|
22
|
+
result[key] = slimSchema(child);
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
/** Remove redundant schema bytes from one listed tool, leaving everything else untouched. */
|
|
27
|
+
export function slimListedTool(tool) {
|
|
28
|
+
return {
|
|
29
|
+
...tool,
|
|
30
|
+
...(tool.inputSchema === undefined ? {} : { inputSchema: slimSchema(tool.inputSchema) }),
|
|
31
|
+
...(tool.outputSchema === undefined ? {} : { outputSchema: slimSchema(tool.outputSchema) }),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** Apply {@link slimListedTool} to a `tools/list` result. */
|
|
35
|
+
export function slimToolList(result) {
|
|
36
|
+
if (result === null || typeof result !== 'object' || !('tools' in result))
|
|
37
|
+
return result;
|
|
38
|
+
const { tools } = result;
|
|
39
|
+
if (!Array.isArray(tools))
|
|
40
|
+
return result;
|
|
41
|
+
return {
|
|
42
|
+
...result,
|
|
43
|
+
tools: tools.map((tool) => slimListedTool(tool)),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -36,6 +36,26 @@ const decisionOutputSchema = strictOperationResultSchema(z
|
|
|
36
36
|
overrides: nonNegativeIntegerSchema,
|
|
37
37
|
scenarios: nonNegativeIntegerSchema,
|
|
38
38
|
unresolvedDefinitions: nonNegativeIntegerSchema,
|
|
39
|
+
unresolvedSample: z
|
|
40
|
+
.array(z.object({ id: z.string(), path: z.string(), reason: z.string() }).strict())
|
|
41
|
+
.max(8)
|
|
42
|
+
.optional(),
|
|
43
|
+
outcomes: z
|
|
44
|
+
.array(z
|
|
45
|
+
.object({
|
|
46
|
+
scenarioId: z.string(),
|
|
47
|
+
found: z.boolean(),
|
|
48
|
+
eligible: z.string().optional(),
|
|
49
|
+
visible: z.string().nullable().optional(),
|
|
50
|
+
available: z.string().optional(),
|
|
51
|
+
unresolved: z
|
|
52
|
+
.array(z.object({ code: z.string(), message: z.string() }).strict())
|
|
53
|
+
.max(5)
|
|
54
|
+
.optional(),
|
|
55
|
+
})
|
|
56
|
+
.strict())
|
|
57
|
+
.max(16)
|
|
58
|
+
.optional(),
|
|
39
59
|
})
|
|
40
60
|
.strict());
|
|
41
61
|
const mechanicOutputSchema = strictOperationResultSchema(z
|
|
@@ -92,7 +112,7 @@ const packageInputSchema = z
|
|
|
92
112
|
const scenarioInputSchema = z
|
|
93
113
|
.object({
|
|
94
114
|
...scenarioTestRequestSchema.shape,
|
|
95
|
-
suite: compactValidatedInputSchema(scenarioSuiteSchema, 'Named mechanic, package
|
|
115
|
+
suite: compactValidatedInputSchema(scenarioSuiteSchema, 'Named mechanic, package or inspection cases. See docs/mechanics.md.').optional(),
|
|
96
116
|
})
|
|
97
117
|
.strict()
|
|
98
118
|
.superRefine((input, context) => {
|
|
@@ -111,8 +131,8 @@ const readOnlyAnalysisTool = {
|
|
|
111
131
|
export const analysisTaskTools = [
|
|
112
132
|
{
|
|
113
133
|
name: 'hoi4.impact_inspect',
|
|
114
|
-
title: '
|
|
115
|
-
description: '
|
|
134
|
+
title: 'Find what a script change affects',
|
|
135
|
+
description: 'Find what a script change affects across focuses, events, decisions, ideas, windows and helpers. Trace definitions and their uses, including proposed source. Example: {"symbols":[{"kind":"scripted_effect","id":"my_effect"}]}. Returns consumer counts inline; the revision-bound graph is a linked resource.',
|
|
116
136
|
inputSchema: impactInspectRequestSchema,
|
|
117
137
|
outputSchema: impactOutputSchema,
|
|
118
138
|
annotations: readOnlyAnalysisTool,
|
|
@@ -120,15 +140,15 @@ export const analysisTaskTools = [
|
|
|
120
140
|
{
|
|
121
141
|
name: 'hoi4.decision_inspect',
|
|
122
142
|
title: 'Inspect decisions and missions',
|
|
123
|
-
description: '
|
|
143
|
+
description: 'Explain why a decision or mission is hidden, unavailable or unaffordable. Inspect conditions, costs and lifecycle for declared actors and targets, or compare proposed source. Example: {"mode":"inspect","id":"my_decision","scenarios":[{"id":"base","actor":"GER","state":{}}]}. Returns each scenario outcome inline; full evidence is linked.',
|
|
124
144
|
inputSchema: decisionInspectRequestSchema,
|
|
125
145
|
outputSchema: decisionOutputSchema,
|
|
126
146
|
annotations: readOnlyAnalysisTool,
|
|
127
147
|
},
|
|
128
148
|
{
|
|
129
149
|
name: 'hoi4.mechanic_test',
|
|
130
|
-
title: 'Test
|
|
131
|
-
description: '
|
|
150
|
+
title: 'Test scripted effects',
|
|
151
|
+
description: 'Test what an effect, event option, decision or focus reward does to a declared state. Run steps and check assertions; unsupported effects stay unresolved. See docs/mechanics.md. Example: {"test":{"id":"t","scenario":{"schemaVersion":"1.0","id":"t","state":{"treasury":10}},"steps":[...],"assertions":[...]}}.',
|
|
132
152
|
inputSchema: mechanicInputSchema,
|
|
133
153
|
outputSchema: mechanicOutputSchema,
|
|
134
154
|
annotations: readOnlyAnalysisTool,
|
|
@@ -136,7 +156,7 @@ export const analysisTaskTools = [
|
|
|
136
156
|
{
|
|
137
157
|
name: 'hoi4.package_check',
|
|
138
158
|
title: 'Check package connections',
|
|
139
|
-
description: '
|
|
159
|
+
description: 'Find missing pieces of a feature by checking its package manifest against definitions, calls, registrations, localisation, assets and required test cases. Example: {"manifest":{"schemaVersion":"1.0","id":"my_package","definitions":[{"kind":"scripted_effect","id":"my_effect"}]}}. Returns present, absent, shadowed and unresolved counts inline.',
|
|
140
160
|
inputSchema: packageInputSchema,
|
|
141
161
|
outputSchema: packageOutputSchema,
|
|
142
162
|
annotations: readOnlyAnalysisTool,
|
|
@@ -144,7 +164,7 @@ export const analysisTaskTools = [
|
|
|
144
164
|
{
|
|
145
165
|
name: 'hoi4.scenario_test',
|
|
146
166
|
title: 'Run scenario suite',
|
|
147
|
-
description: 'Run named
|
|
167
|
+
description: 'Run named mechanic, package or inspection cases from a suite or workspace file. Continue unfinished batches and report failures and unresolved cases. Example: {"suitePath":"tests/my_suite.json","maxCases":20}. Returns completed, failed, unresolved and pending counts, and a continuation while cases remain.',
|
|
148
168
|
inputSchema: scenarioInputSchema,
|
|
149
169
|
outputSchema: scenarioOutputSchema,
|
|
150
170
|
annotations: readOnlyAnalysisTool,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { registerLegacyTaskTools } from '../server/legacy-task-tools.js';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
import { helperExpansionRequestSchema, helperExpansionSummarySchema, } from '../../schemas/helper-expansion.js';
|
|
4
|
-
import { eventDirectionSchema, eventGraphReferenceSchema, eventImpactSubjectSchema, eventInspectModeSchema, eventProposedSourceSchema, eventRenderViewSchema, eventSelectorSchema, eventInspectRequestSchema, eventRenderRequestSchema,
|
|
4
|
+
import { eventDirectionSchema, eventGraphReferenceSchema, eventImpactSubjectSchema, eventInspectModeSchema, eventProposedSourceSchema, eventRenderViewSchema, eventSelectorSchema, eventInspectRequestSchema, eventRenderRequestSchema, validateEventInspectToolRequest, eventStateSubjectSchema, } from '../../schemas/event.js';
|
|
5
5
|
import { compactValidatedInputSchema } from '../server/context-schemas.js';
|
|
6
6
|
import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
|
|
7
7
|
import { strictOperationResultSchema } from '../server/result.js';
|
|
8
|
-
|
|
8
|
+
// The selector is published in full: it is the field agents most often get wrong. A plain
|
|
9
|
+
// string ("my_ns.12", "my_ns", "events/file.txt") is also accepted and normalized.
|
|
10
|
+
const nestedSelectorSchema = eventSelectorSchema;
|
|
11
|
+
const nestedEndpointSchema = compactValidatedInputSchema(eventSelectorSchema, 'Same shape as selector, or a plain event ID string.');
|
|
9
12
|
const nestedStateSubjectSchema = compactValidatedInputSchema(eventStateSubjectSchema, 'State kind and name.');
|
|
10
13
|
const nestedImpactSubjectSchema = compactValidatedInputSchema(eventImpactSubjectSchema, 'Impact kind and name.');
|
|
11
14
|
const nestedGraphReferenceSchema = compactValidatedInputSchema(eventGraphReferenceSchema, 'Cached revision or graph artifact URI.');
|
|
@@ -14,30 +17,23 @@ const eventInspectInputSchema = z
|
|
|
14
17
|
.object({
|
|
15
18
|
...eventInspectRequestSchema.shape,
|
|
16
19
|
selector: nestedSelectorSchema.optional(),
|
|
17
|
-
from:
|
|
18
|
-
to:
|
|
20
|
+
from: nestedEndpointSchema.optional(),
|
|
21
|
+
to: nestedEndpointSchema.optional(),
|
|
19
22
|
stateSubject: nestedStateSubjectSchema.optional(),
|
|
20
23
|
impactSubject: nestedImpactSubjectSchema.optional(),
|
|
21
24
|
helperExpansion: compactValidatedInputSchema(helperExpansionRequestSchema, 'Bounded helper paths; opaque continuationUri resumes the same source and roots. See docs/events.md.').optional(),
|
|
25
|
+
before: nestedGraphReferenceSchema.optional(),
|
|
26
|
+
after: nestedGraphReferenceSchema.optional(),
|
|
27
|
+
proposedSources: z.array(nestedProposedSourceSchema).min(1).max(64).optional(),
|
|
22
28
|
})
|
|
23
29
|
.strict()
|
|
24
|
-
.superRefine(
|
|
30
|
+
.superRefine(validateEventInspectToolRequest);
|
|
25
31
|
const eventRenderInputSchema = z
|
|
26
32
|
.object({
|
|
27
33
|
...eventRenderRequestSchema.shape,
|
|
28
34
|
selector: nestedSelectorSchema.optional(),
|
|
29
35
|
})
|
|
30
36
|
.strict();
|
|
31
|
-
const eventCompareInputSchema = z
|
|
32
|
-
.object({
|
|
33
|
-
...eventCompareRequestSchema.shape,
|
|
34
|
-
selector: nestedSelectorSchema.optional(),
|
|
35
|
-
before: nestedGraphReferenceSchema.optional(),
|
|
36
|
-
after: nestedGraphReferenceSchema.optional(),
|
|
37
|
-
proposedSources: z.array(nestedProposedSourceSchema).min(1).max(64).optional(),
|
|
38
|
-
})
|
|
39
|
-
.strict()
|
|
40
|
-
.superRefine(validateEventCompareRequest);
|
|
41
37
|
const eventGraphCountsSchema = z
|
|
42
38
|
.object({
|
|
43
39
|
events: nonNegativeIntegerSchema,
|
|
@@ -74,7 +70,7 @@ const renderHashSchema = z
|
|
|
74
70
|
html: sha256Schema.optional(),
|
|
75
71
|
})
|
|
76
72
|
.strict();
|
|
77
|
-
const
|
|
73
|
+
const eventInspectDataSchema = z
|
|
78
74
|
.object({
|
|
79
75
|
mode: eventInspectModeSchema,
|
|
80
76
|
analysisMode: z.enum(['full', 'focused']),
|
|
@@ -84,7 +80,7 @@ const eventInspectOutputSchema = strictOperationResultSchema(z
|
|
|
84
80
|
helperExpansion: helperExpansionSummarySchema.optional(),
|
|
85
81
|
boundary: inspectBoundarySchema,
|
|
86
82
|
})
|
|
87
|
-
.strict()
|
|
83
|
+
.strict();
|
|
88
84
|
const eventRenderOutputSchema = strictOperationResultSchema(z
|
|
89
85
|
.object({
|
|
90
86
|
view: eventRenderViewSchema,
|
|
@@ -110,7 +106,7 @@ const eventRenderOutputSchema = strictOperationResultSchema(z
|
|
|
110
106
|
.strict(),
|
|
111
107
|
})
|
|
112
108
|
.strict());
|
|
113
|
-
const
|
|
109
|
+
const eventCompareDataSchema = z
|
|
114
110
|
.object({
|
|
115
111
|
beforeRevision: sha256Schema,
|
|
116
112
|
afterRevision: sha256Schema,
|
|
@@ -161,7 +157,8 @@ const eventCompareOutputSchema = strictOperationResultSchema(z
|
|
|
161
157
|
})
|
|
162
158
|
.strict(),
|
|
163
159
|
})
|
|
164
|
-
.strict()
|
|
160
|
+
.strict();
|
|
161
|
+
const eventInspectOutputSchema = strictOperationResultSchema(z.union([eventInspectDataSchema, eventCompareDataSchema]));
|
|
165
162
|
const readOnlyEventTool = {
|
|
166
163
|
readOnlyHint: true,
|
|
167
164
|
destructiveHint: false,
|
|
@@ -172,27 +169,19 @@ export const eventTaskTools = [
|
|
|
172
169
|
{
|
|
173
170
|
name: 'hoi4.event_inspect',
|
|
174
171
|
title: 'Inspect event chains',
|
|
175
|
-
description: '
|
|
172
|
+
description: 'Follow event chains and explain their options, conditions, timing and state changes. Find broken calls, inspect affected events or compare revisions with mode compare. Example: {"mode":"trace","selector":"my_mod.1","direction":"downstream"}; a selector is an event ID, a namespace, my_mod.* or a file. Returns counts and the main findings inline; the full source-linked report is a resource.',
|
|
176
173
|
inputSchema: eventInspectInputSchema,
|
|
177
174
|
outputSchema: eventInspectOutputSchema,
|
|
178
175
|
annotations: readOnlyEventTool,
|
|
179
176
|
},
|
|
180
177
|
{
|
|
181
178
|
name: 'hoi4.event_render',
|
|
182
|
-
title: '
|
|
183
|
-
description: '
|
|
179
|
+
title: 'Preview event chains',
|
|
180
|
+
description: 'Preview event routes, options, timing, state and scope as JSON, SVG and PNG. Example: {"view":"overview","selector":"my_mod"}. Images are linked artifacts; calls that cannot be resolved statically stay explicit unresolved edges.',
|
|
184
181
|
inputSchema: eventRenderInputSchema,
|
|
185
182
|
outputSchema: eventRenderOutputSchema,
|
|
186
183
|
annotations: readOnlyEventTool,
|
|
187
184
|
},
|
|
188
|
-
{
|
|
189
|
-
name: 'hoi4.event_compare',
|
|
190
|
-
title: 'Compare event chains',
|
|
191
|
-
description: 'Compare cached, artifact-backed, current, or in-memory proposed event graphs, optionally selecting one downstream chain. Full changes and explicit selection coverage are resources.',
|
|
192
|
-
inputSchema: eventCompareInputSchema,
|
|
193
|
-
outputSchema: eventCompareOutputSchema,
|
|
194
|
-
annotations: readOnlyEventTool,
|
|
195
|
-
},
|
|
196
185
|
];
|
|
197
186
|
export function registerEventTools(server) {
|
|
198
187
|
registerLegacyTaskTools(server, eventTaskTools);
|
|
@@ -135,31 +135,23 @@ export const focusTaskTools = [
|
|
|
135
135
|
{
|
|
136
136
|
name: 'hoi4.focus_inspect',
|
|
137
137
|
title: 'Inspect focus trees',
|
|
138
|
-
description: '
|
|
138
|
+
description: 'Find focus branches, prerequisites, layout problems and missing references in national trees and continuous-focus palettes. Example: {"treeId":"my_focus_tree"}. Returns counts and the main diagnostics inline; the full report is a linked resource.',
|
|
139
139
|
inputSchema: focusInspectRequestSchema,
|
|
140
140
|
outputSchema: focusInspectOutputSchema,
|
|
141
141
|
annotations: artifactProducing,
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
name: 'hoi4.focus_render',
|
|
145
|
-
title: '
|
|
146
|
-
description: '
|
|
147
|
-
inputSchema: focusRenderRequestSchema,
|
|
148
|
-
outputSchema: focusRenderOutputSchema,
|
|
149
|
-
annotations: artifactProducing,
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
name: 'hoi4.focus_raster',
|
|
153
|
-
title: 'Rasterize focus review artifacts',
|
|
154
|
-
description: 'Render focus PNG with decoded source icons; also returns HTML, SVG, and JSON.',
|
|
145
|
+
title: 'Preview a focus tree or continuous palette',
|
|
146
|
+
description: 'Preview a focus tree or palette with its icons. Export PNG, HTML, SVG and JSON source maps; png:false skips the PNG and cropFocusIds adds close-ups. Example: {"relativePath":"common/national_focus/my_tree.txt","treeId":"my_focus_tree"}. Images are linked artifacts, not inline.',
|
|
155
147
|
inputSchema: focusRenderRequestSchema,
|
|
156
148
|
outputSchema: focusRenderOutputSchema,
|
|
157
149
|
annotations: artifactProducing,
|
|
158
150
|
},
|
|
159
151
|
{
|
|
160
152
|
name: 'hoi4.focus_rewrite',
|
|
161
|
-
title: '
|
|
162
|
-
description: 'Create
|
|
153
|
+
title: 'Build or arrange a focus tree',
|
|
154
|
+
description: 'Create focus trees and continuous-focus palettes, or rearrange existing branches. Use createIfMissing with a complete plan to create content, or layoutMode to arrange an existing tree. Example: {"relativePath":"common/national_focus/my_tree.txt","treeId":"my_focus_tree","layoutMode":"compact"}. Returns the changed files.',
|
|
163
155
|
inputSchema: focusRewriteRequestSchema,
|
|
164
156
|
outputSchema: focusPlanOutputSchema,
|
|
165
157
|
annotations: {
|
|
@@ -71,24 +71,24 @@ const artifactProducing = {
|
|
|
71
71
|
export const guiTaskTools = [
|
|
72
72
|
{
|
|
73
73
|
name: 'hoi4.gui_inspect',
|
|
74
|
-
title: 'Inspect
|
|
75
|
-
description: '
|
|
74
|
+
title: 'Inspect a window',
|
|
75
|
+
description: 'Find the elements, assets and script behind a window, including layout problems, localisation and fonts. Example: {"windowName":"my_window"}. Returns element counts and fidelity inline; the full scene is a linked resource.',
|
|
76
76
|
inputSchema: guiInspectRequestSchema,
|
|
77
77
|
outputSchema: guiScanOutputSchema,
|
|
78
78
|
annotations: artifactProducing,
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: 'hoi4.gui_render',
|
|
82
|
-
title: '
|
|
83
|
-
description: '
|
|
82
|
+
title: 'Preview a window',
|
|
83
|
+
description: 'Preview a window at different resolutions and states. Shows control regions, element hierarchy and layout problems; unknown visibility stays unresolved. Example: {"windowName":"my_window","scenario":{"id":"normal","flags":{"my_flag":true}}}. Images and reports are linked resources.',
|
|
84
84
|
inputSchema: guiRenderRequestSchema,
|
|
85
85
|
outputSchema: guiRenderOutputSchema,
|
|
86
86
|
annotations: artifactProducing,
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
name: 'hoi4.gui_rewrite',
|
|
90
|
-
title: 'Create or
|
|
91
|
-
description: '
|
|
90
|
+
title: 'Create or edit a window',
|
|
91
|
+
description: 'Create or edit a window using complete source, structured helpers or exact patches. Include related text files with additionalFiles; binary art must already be in the mod. Example: {"mode":"helpers","relativePath":"interface/my_window.gui","windowName":"my_window","scenario":{"id":"normal"},"helper":{...}}. Returns the changed files.',
|
|
92
92
|
inputSchema: guiRewriteRequestSchema,
|
|
93
93
|
outputSchema: guiPlanOutputSchema,
|
|
94
94
|
annotations: {
|
|
@@ -4,8 +4,8 @@ import { errorResult } from '../../core/operation-result.js';
|
|
|
4
4
|
export const jobControlTools = [
|
|
5
5
|
{
|
|
6
6
|
name: 'hoi4.job_inspect',
|
|
7
|
-
title: '
|
|
8
|
-
description: '
|
|
7
|
+
title: 'Check a background task',
|
|
8
|
+
description: 'Check progress on a background task or retrieve its completed result. Pass jobId from the task handle. Example: {"jobId":"job_<64 hex characters>"}. Returns task status or the completed result.',
|
|
9
9
|
inputSchema: jobReferenceSchema,
|
|
10
10
|
annotations: {
|
|
11
11
|
readOnlyHint: true,
|
|
@@ -16,8 +16,8 @@ export const jobControlTools = [
|
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
name: 'hoi4.job_cancel',
|
|
19
|
-
title: '
|
|
20
|
-
description: '
|
|
19
|
+
title: 'Stop a background task',
|
|
20
|
+
description: 'Stop a background task by jobId. A result that has already completed stays available. Example: {"jobId":"job_<64 hex characters>"}.',
|
|
21
21
|
inputSchema: jobReferenceSchema,
|
|
22
22
|
outputSchema: jobStatusOutputSchema,
|
|
23
23
|
annotations: {
|