mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix: run composite tool sections through the catalog
situation_brief, military_awareness and the HUD caption called other tools directly, so replaced tools and interceptors did not apply to their sections. Tools now reach each other through the catalog, and interceptors see these calls with the calling tool as parent. Surfaces become a view over the composed catalog, so a composite offered on voice keeps sections that voice does not list.
This commit is contained in:
1 parent
7ddee426e7
commit
963c791a5c
9 files changed
+219
-65
No files matched your search
+34
-8
@@ -4,6 +4,8 @@
|
||||
* or both. Applications can pass overrides when they compose a surface.
|
||||
*/
|
||||
|
||||
import { ToolError } from './catalog.js';
|
||||
|
||||
export const SURFACES = Object.freeze(['mcp', 'voice']);
|
||||
|
||||
const voiceOff = Object.freeze({ voice: false });
|
||||
@@ -33,19 +35,18 @@ export const TOOL_SURFACES = Object.freeze({
|
||||
/**
|
||||
* The tools a surface offers, in their original order. `overrides` uses the
|
||||
* table's shape and wins over it, such as `{ get_weather_map: { voice: true } }`.
|
||||
* Unknown tool names or surfaces throw, so a typo cannot silently do nothing.
|
||||
* An override naming an unknown tool or surface throws, so a typo cannot
|
||||
* silently do nothing.
|
||||
*/
|
||||
export function toolsForSurface(tools, surface, overrides = {}) {
|
||||
if (!SURFACES.includes(surface))
|
||||
throw new TypeError(`Unknown tool surface: ${surface}`);
|
||||
const names = new Set(tools.map((tool) => tool.name));
|
||||
for (const table of [TOOL_SURFACES, overrides]) {
|
||||
for (const [name, entry] of Object.entries(table)) {
|
||||
if (!names.has(name)) throw new TypeError(`Unknown tool: ${name}`);
|
||||
for (const key of Object.keys(entry)) {
|
||||
if (!SURFACES.includes(key))
|
||||
throw new TypeError(`Unknown tool surface for ${name}: ${key}`);
|
||||
}
|
||||
for (const [name, entry] of Object.entries(overrides)) {
|
||||
if (!names.has(name)) throw new TypeError(`Unknown tool: ${name}`);
|
||||
for (const key of Object.keys(entry)) {
|
||||
if (!SURFACES.includes(key))
|
||||
throw new TypeError(`Unknown tool surface for ${name}: ${key}`);
|
||||
}
|
||||
}
|
||||
return tools.filter(
|
||||
@@ -54,3 +55,28 @@ export function toolsForSurface(tools, surface, overrides = {}) {
|
||||
TOOL_SURFACES[tool.name]?.[surface]) !== false,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A view of a composed catalog that lists and calls only the tools a surface
|
||||
* offers. Tools that combine others still reach the whole catalog, so a
|
||||
* composite such as military_awareness keeps its sections on every surface.
|
||||
*/
|
||||
export function catalogForSurface(catalog, surface, overrides = {}) {
|
||||
const offered = new Set(
|
||||
toolsForSurface(catalog.list(), surface, overrides).map(
|
||||
(tool) => tool.name,
|
||||
),
|
||||
);
|
||||
return Object.freeze({
|
||||
list: () => catalog.list().filter((tool) => offered.has(tool.name)),
|
||||
get: (name) => (offered.has(name) ? catalog.get(name) : undefined),
|
||||
async call(name, args, options) {
|
||||
if (!offered.has(name))
|
||||
throw new ToolError(
|
||||
'unsupported',
|
||||
`No tool named ${name} is available`,
|
||||
);
|
||||
return catalog.call(name, args, options);
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user