hoi4-agent-tools 3.9.0 → 4.0.0
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 +118 -0
- package/README.md +115 -147
- package/dist/bin/http.js +12 -0
- package/dist/bin/setup.js +3 -2
- package/dist/bin/stdio.js +12 -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/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 +56 -10
- package/dist/hoi4_agent_tools/core/index.js +45 -20
- 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 +215 -116
- package/dist/hoi4_agent_tools/core/job-worker.js +90 -36
- 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 +155 -0
- package/dist/hoi4_agent_tools/core/server-status-resource.js +22 -0
- package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
- package/dist/hoi4_agent_tools/core/source/cache.js +108 -29
- package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
- package/dist/hoi4_agent_tools/core/transactions.js +114 -23
- 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/event/service.js +7 -0
- 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/scenario-generator.js +11 -3
- package/dist/hoi4_agent_tools/gui/studio.js +20 -7
- 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/resources/register-modern.js +13 -1
- package/dist/hoi4_agent_tools/mcp/resources/register.js +6 -0
- 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/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 +25 -5
- package/dist/hoi4_agent_tools/mcp/tools/event.js +18 -29
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -12
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +3 -3
- package/dist/hoi4_agent_tools/mcp/tools/job.js +2 -2
- package/dist/hoi4_agent_tools/mcp/tools/map.js +13 -16
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
- package/dist/hoi4_agent_tools/mcp/tools/reference.js +22 -5
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +16 -26
- package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
- package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +37 -18
- 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/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 +83 -23
- 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/technology/service.js +7 -0
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +7 -4
- package/docs/analysis.md +13 -0
- package/docs/configuration.md +281 -0
- package/docs/development.md +24 -2
- package/docs/events.md +27 -3
- package/docs/examples.md +6 -6
- package/docs/focus.md +125 -4
- package/docs/gui.md +98 -17
- package/docs/helper-expansion.md +8 -8
- package/docs/http.md +3 -1
- package/docs/jobs.md +19 -13
- package/docs/map.md +197 -6
- package/docs/mechanics.md +4 -0
- package/docs/probability.md +42 -15
- package/docs/reference.md +71 -4
- package/docs/setup.md +45 -11
- package/docs/technology.md +26 -1
- package/docs/third-party-notices.md +11 -0
- package/docs/tools.md +151 -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 +161 -162
- 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
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { ReadResourceResultSchema } from '@modelcontextprotocol/core';
|
|
2
2
|
import { ProtocolError, ProtocolErrorCode, ResourceNotFoundError, } from '@modelcontextprotocol/server';
|
|
3
3
|
import { artifactResourceDefinition, readArtifactResource } from '../../core/artifact-resource.js';
|
|
4
|
+
import { readServerStatus, serverStatusResource } from '../../core/server-status-resource.js';
|
|
4
5
|
import { ServiceError } from '../../core/result.js';
|
|
5
6
|
/** Modern wire projection of the same non-enumerating, authorization-bound resource reader. */
|
|
6
7
|
export function registerModernResources(server, engine, context) {
|
|
7
|
-
|
|
8
|
+
// Process details are offered to the local client only, never to authenticated remote ones.
|
|
9
|
+
const local = context.principal === undefined;
|
|
10
|
+
server.setRequestHandler('resources/list', () => ({
|
|
11
|
+
resources: local ? [serverStatusResource] : [],
|
|
12
|
+
}));
|
|
8
13
|
server.setRequestHandler('resources/templates/list', () => ({
|
|
9
14
|
resourceTemplates: [artifactResourceDefinition],
|
|
10
15
|
}));
|
|
11
16
|
server.setRequestHandler('resources/read', async (request, extra) => {
|
|
17
|
+
if (local && request.params.uri === serverStatusResource.uri)
|
|
18
|
+
return ReadResourceResultSchema.parse({
|
|
19
|
+
...(await readServerStatus(engine)),
|
|
20
|
+
resultType: 'complete',
|
|
21
|
+
ttlMs: 0,
|
|
22
|
+
cacheScope: 'private',
|
|
23
|
+
});
|
|
12
24
|
try {
|
|
13
25
|
return ReadResourceResultSchema.parse({
|
|
14
26
|
...(await readArtifactResource(engine, request.params.uri, context, extra.mcpReq.signal)),
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { artifactResourceDefinition, readArtifactResource } from '../../core/artifact-resource.js';
|
|
3
|
+
import { readServerStatus, serverStatusResource } from '../../core/server-status-resource.js';
|
|
3
4
|
/** SDK-v1 registration only; ownership and byte-range behavior live in the shared core. */
|
|
4
5
|
export function registerMcpResources(server, engine, context) {
|
|
5
6
|
const { name, uriTemplate, ...metadata } = artifactResourceDefinition;
|
|
6
7
|
server.registerResource(name, new ResourceTemplate(uriTemplate, { list: undefined }), metadata, (uri, _variables, extra) => readArtifactResource(engine, uri.href, context, extra.signal));
|
|
8
|
+
// Process details are offered to the local client only, never to authenticated remote ones.
|
|
9
|
+
if (context.principal !== undefined)
|
|
10
|
+
return;
|
|
11
|
+
const { name: statusName, uri: statusUri, ...statusMetadata } = serverStatusResource;
|
|
12
|
+
server.registerResource(statusName, statusUri, statusMetadata, () => readServerStatus(engine));
|
|
7
13
|
}
|
|
@@ -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,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
|
|
@@ -112,7 +132,7 @@ export const analysisTaskTools = [
|
|
|
112
132
|
{
|
|
113
133
|
name: 'hoi4.impact_inspect',
|
|
114
134
|
title: 'Inspect cross-system impact',
|
|
115
|
-
description: 'Trace
|
|
135
|
+
description: 'Trace where symbols are defined and consumed across focuses, events, decisions, ideas, GUI and helpers, or what a changed file affects; proposed sources are analyzed in memory. 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,7 +140,7 @@ export const analysisTaskTools = [
|
|
|
120
140
|
{
|
|
121
141
|
name: 'hoi4.decision_inspect',
|
|
122
142
|
title: 'Inspect decisions and missions',
|
|
123
|
-
description: 'Inventory decisions or evaluate declared actor and target scenarios
|
|
143
|
+
description: 'Inventory decisions and missions, or evaluate one under declared actor and target scenarios: visibility, availability, payment, lifecycle and proposed-source differences. 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,
|
|
@@ -128,7 +148,7 @@ export const analysisTaskTools = [
|
|
|
128
148
|
{
|
|
129
149
|
name: 'hoi4.mechanic_test',
|
|
130
150
|
title: 'Test declared mechanic steps',
|
|
131
|
-
description: 'Interpret
|
|
151
|
+
description: 'Interpret source-backed effect steps (scripted effect, event option, decision, focus reward) on a declared state and check typed assertions; unsupported effects stay unresolved and no source changes. Example: {"test":{"id":"t","scenario":{"schemaVersion":"1.0","id":"t","state":{"treasury":10}},"steps":[...],"assertions":[...]}}. See docs/mechanics.md.',
|
|
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: 'Check a declarative package manifest against active definitions,
|
|
159
|
+
description: 'Check a declarative package manifest against active definitions, calls, registrations, localisation, assets and required suite 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 a suite of named mechanic, package or read-only tool cases, inline or from a workspace file, in resumable revision-bound batches. 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,7 +169,7 @@ export const eventTaskTools = [
|
|
|
172
169
|
{
|
|
173
170
|
name: 'hoi4.event_inspect',
|
|
174
171
|
title: 'Inspect event chains',
|
|
175
|
-
description: 'Scan, find roots, trace, explain paths, inspect state flow, lint, or
|
|
172
|
+
description: 'Scan, find roots, trace, explain paths, inspect state flow, lint, assess impact or compare (mode compare) event graphs. 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,
|
|
@@ -180,19 +177,11 @@ export const eventTaskTools = [
|
|
|
180
177
|
{
|
|
181
178
|
name: 'hoi4.event_render',
|
|
182
179
|
title: 'Render event chains',
|
|
183
|
-
description: 'Render
|
|
180
|
+
description: 'Render a source-linked event view (overview, neighborhood, options, timing, state, scope, unresolved and more) 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,23 +135,15 @@ export const focusTaskTools = [
|
|
|
135
135
|
{
|
|
136
136
|
name: 'hoi4.focus_inspect',
|
|
137
137
|
title: 'Inspect focus trees',
|
|
138
|
-
description: '
|
|
138
|
+
description: 'Read national focus trees and continuous-focus palettes: structure, layout, source references and diagnostics. 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: 'Render focus
|
|
146
|
-
description: 'Render focus HTML, SVG
|
|
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: 'Render a focus tree or continuous palette',
|
|
146
|
+
description: 'Render a focus tree or palette as a PNG with decoded icons plus HTML, SVG and JSON source maps (png:false for vector only; 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,
|
|
@@ -159,7 +151,7 @@ export const focusTaskTools = [
|
|
|
159
151
|
{
|
|
160
152
|
name: 'hoi4.focus_rewrite',
|
|
161
153
|
title: 'Create or clean up focus content',
|
|
162
|
-
description: 'Create
|
|
154
|
+
description: 'Create a focus tree or palette from a complete plan (createIfMissing), or re-lay out an existing tree without a plan. Example: {"relativePath":"common/national_focus/my_tree.txt","treeId":"my_focus_tree","layoutMode":"compact"}. Validates, writes atomically and returns the changed files with a rollback-able transaction.',
|
|
163
155
|
inputSchema: focusRewriteRequestSchema,
|
|
164
156
|
outputSchema: focusPlanOutputSchema,
|
|
165
157
|
annotations: {
|
|
@@ -72,7 +72,7 @@ export const guiTaskTools = [
|
|
|
72
72
|
{
|
|
73
73
|
name: 'hoi4.gui_inspect',
|
|
74
74
|
title: 'Inspect scripted GUI',
|
|
75
|
-
description: 'Inspect GUI sources and
|
|
75
|
+
description: 'Inspect a scripted GUI window with its linked .gui, .gfx, scripted-GUI, localisation and font sources, and layout diagnostics. 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,
|
|
@@ -80,7 +80,7 @@ export const guiTaskTools = [
|
|
|
80
80
|
{
|
|
81
81
|
name: 'hoi4.gui_render',
|
|
82
82
|
title: 'Render scripted GUI artifacts',
|
|
83
|
-
description: 'Render GUI states
|
|
83
|
+
description: 'Render a GUI window under a scenario at several states and resolutions, with click regions, hierarchy and a diagnostics report. Example: {"windowName":"my_window","scenario":{"id":"normal","flags":{"my_flag":true}}}. Returns a gallery of about 25 linked artifacts; undecided visibility stays marked unresolved.',
|
|
84
84
|
inputSchema: guiRenderRequestSchema,
|
|
85
85
|
outputSchema: guiRenderOutputSchema,
|
|
86
86
|
annotations: artifactProducing,
|
|
@@ -88,7 +88,7 @@ export const guiTaskTools = [
|
|
|
88
88
|
{
|
|
89
89
|
name: 'hoi4.gui_rewrite',
|
|
90
90
|
title: 'Create or clean up scripted GUI',
|
|
91
|
-
description: 'Apply one validated source,
|
|
91
|
+
description: 'Apply one validated GUI change as complete source, structured helpers or exact patches, plus extra text files (additionalFiles); binary art must already be in the mod. Example: {"mode":"helpers","relativePath":"interface/my_window.gui","windowName":"my_window","scenario":{"id":"normal"},"helper":{...}}. Writes atomically; returns changed files and a rollback-able transaction.',
|
|
92
92
|
inputSchema: guiRewriteRequestSchema,
|
|
93
93
|
outputSchema: guiPlanOutputSchema,
|
|
94
94
|
annotations: {
|
|
@@ -5,7 +5,7 @@ export const jobControlTools = [
|
|
|
5
5
|
{
|
|
6
6
|
name: 'hoi4.job_inspect',
|
|
7
7
|
title: 'Inspect persistent job',
|
|
8
|
-
description: 'Inspect a
|
|
8
|
+
description: 'Inspect a background operation by jobId (from a native task id): status while it runs, the original tool result once it completed. Example: {"jobId":"job_<64 hex characters>"}. Returns bounded status evidence.',
|
|
9
9
|
inputSchema: jobReferenceSchema,
|
|
10
10
|
annotations: {
|
|
11
11
|
readOnlyHint: true,
|
|
@@ -17,7 +17,7 @@ export const jobControlTools = [
|
|
|
17
17
|
{
|
|
18
18
|
name: 'hoi4.job_cancel',
|
|
19
19
|
title: 'Cancel persistent job',
|
|
20
|
-
description: 'Durably request cancellation of
|
|
20
|
+
description: 'Durably request cancellation of a background operation by jobId. A completed result stays completed. Example: {"jobId":"job_<64 hex characters>"}.',
|
|
21
21
|
inputSchema: jobReferenceSchema,
|
|
22
22
|
outputSchema: jobStatusOutputSchema,
|
|
23
23
|
annotations: {
|