@apnex/network-adapter 0.1.2 → 0.1.5
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/dist/build-info.json +6 -0
- package/dist/file-logger.d.ts +42 -0
- package/dist/file-logger.js +122 -0
- package/dist/file-logger.js.map +1 -0
- package/dist/index.d.ts +37 -13
- package/dist/index.js +42 -15
- package/dist/index.js.map +1 -1
- package/dist/kernel/adapter-config.d.ts +47 -0
- package/dist/kernel/adapter-config.js +90 -0
- package/dist/kernel/adapter-config.js.map +1 -0
- package/dist/kernel/agent-client.d.ts +25 -20
- package/dist/kernel/build-identity.d.ts +24 -0
- package/dist/kernel/build-identity.js +45 -0
- package/dist/kernel/build-identity.js.map +1 -0
- package/dist/kernel/event-router.d.ts +22 -1
- package/dist/kernel/event-router.js +45 -7
- package/dist/kernel/event-router.js.map +1 -1
- package/dist/kernel/handshake.d.ts +40 -4
- package/dist/kernel/handshake.js +46 -7
- package/dist/kernel/handshake.js.map +1 -1
- package/dist/kernel/harness-manifest.d.ts +51 -0
- package/dist/kernel/harness-manifest.js +96 -0
- package/dist/kernel/harness-manifest.js.map +1 -0
- package/dist/kernel/liveness-signal.d.ts +35 -0
- package/dist/kernel/liveness-signal.js +61 -0
- package/dist/kernel/liveness-signal.js.map +1 -0
- package/dist/kernel/liveness-watchdog.d.ts +78 -0
- package/dist/kernel/liveness-watchdog.js +115 -0
- package/dist/kernel/liveness-watchdog.js.map +1 -0
- package/dist/kernel/mcp-agent-client.d.ts +2 -2
- package/dist/kernel/mcp-agent-client.js +49 -3
- package/dist/kernel/mcp-agent-client.js.map +1 -1
- package/dist/kernel/poll-backstop.d.ts +93 -4
- package/dist/kernel/poll-backstop.js +193 -25
- package/dist/kernel/poll-backstop.js.map +1 -1
- package/dist/kernel/state-sync.d.ts +2 -13
- package/dist/kernel/state-sync.js.map +1 -1
- package/dist/notification-log.d.ts +8 -0
- package/dist/notification-log.js +10 -0
- package/dist/notification-log.js.map +1 -1
- package/dist/observability.d.ts +24 -0
- package/dist/observability.js +52 -0
- package/dist/observability.js.map +1 -0
- package/dist/prompt-format.js +82 -9
- package/dist/prompt-format.js.map +1 -1
- package/dist/tool-manager/catalog/health-revision.d.ts +43 -0
- package/dist/tool-manager/catalog/health-revision.js +61 -0
- package/dist/tool-manager/catalog/health-revision.js.map +1 -0
- package/dist/tool-manager/{tool-catalog-cache.d.ts → catalog/tool-catalog-cache.d.ts} +39 -19
- package/dist/tool-manager/{tool-catalog-cache.js → catalog/tool-catalog-cache.js} +53 -26
- package/dist/tool-manager/catalog/tool-catalog-cache.js.map +1 -0
- package/dist/tool-manager/catalog/tool-surface-reconciler.d.ts +93 -0
- package/dist/tool-manager/catalog/tool-surface-reconciler.js +101 -0
- package/dist/tool-manager/catalog/tool-surface-reconciler.js.map +1 -0
- package/dist/tool-manager/contracts.d.ts +91 -0
- package/dist/tool-manager/contracts.js +20 -0
- package/dist/tool-manager/contracts.js.map +1 -0
- package/dist/tool-manager/dispatch/dispatch.d.ts +77 -0
- package/dist/tool-manager/dispatch/dispatch.js +170 -0
- package/dist/tool-manager/dispatch/dispatch.js.map +1 -0
- package/dist/tool-manager/dispatch/tool-call-policy.d.ts +32 -0
- package/dist/tool-manager/dispatch/tool-call-policy.js +56 -0
- package/dist/tool-manager/dispatch/tool-call-policy.js.map +1 -0
- package/dist/tool-manager/{dispatcher.d.ts → orchestrator/dispatcher.d.ts} +110 -31
- package/dist/tool-manager/orchestrator/dispatcher.js +559 -0
- package/dist/tool-manager/orchestrator/dispatcher.js.map +1 -0
- package/dist/tool-manager/work-protocol/claimable-digest-tracker.d.ts +60 -0
- package/dist/tool-manager/work-protocol/claimable-digest-tracker.js +66 -0
- package/dist/tool-manager/work-protocol/claimable-digest-tracker.js.map +1 -0
- package/dist/tool-manager/work-protocol/work-lease-tracker.d.ts +59 -0
- package/dist/tool-manager/work-protocol/work-lease-tracker.js +134 -0
- package/dist/tool-manager/work-protocol/work-lease-tracker.js.map +1 -0
- package/dist/wire/mcp-transport.d.ts +1 -1
- package/dist/wire/mcp-transport.js +31 -7
- package/dist/wire/mcp-transport.js.map +1 -1
- package/dist/wire/slot-gate.d.ts +40 -0
- package/dist/wire/slot-gate.js +61 -0
- package/dist/wire/slot-gate.js.map +1 -0
- package/dist/wire/transport.d.ts +18 -0
- package/package.json +6 -3
- package/dist/kernel/instance.d.ts +0 -40
- package/dist/kernel/instance.js +0 -79
- package/dist/kernel/instance.js.map +0 -1
- package/dist/tool-manager/dispatcher.js +0 -379
- package/dist/tool-manager/dispatcher.js.map +0 -1
- package/dist/tool-manager/tool-catalog-cache.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* contracts.ts — the agnostic Tool-Manager contract (Slice A).
|
|
3
|
+
*
|
|
4
|
+
* The internal-sovereign-module boundary for tool catalog + dispatch. These
|
|
5
|
+
* interfaces are host- AND transport-agnostic BY CONSTRUCTION: nothing here
|
|
6
|
+
* imports `@modelcontextprotocol/sdk`, `McpAgentClient`, or any binding. A
|
|
7
|
+
* consumer (the MCP binding, pi's native binding, a future ACP binding) depends
|
|
8
|
+
* ONLY on these types — never on the concrete kernel classes (A3 Air-Gap).
|
|
9
|
+
*
|
|
10
|
+
* Design: docs/designs/m-sovereign-tool-manager-design.md
|
|
11
|
+
* Axioms: A3 Sovereign Composition (Law of One, Air-Gap, Semantic Bit-Masking,
|
|
12
|
+
* Earned Exposure — this is an INTERNAL module, not a published package).
|
|
13
|
+
*
|
|
14
|
+
* SLICE A INVARIANT: purely additive. `McpAgentClient` (via `IAgentClient`)
|
|
15
|
+
* structurally satisfies `IToolDispatchAgent` today with zero changes — this
|
|
16
|
+
* file only NAMES the subset the tool-manager actually needs, so the dispatch
|
|
17
|
+
* authority (Slice B) can depend on the interface instead of the class.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Neutral tool descriptor — MCP-shaped fields (name / description / JSON-Schema
|
|
21
|
+
* inputSchema) but NOT an MCP SDK type. Every binding materializes its own host
|
|
22
|
+
* representation from this (MCP `Tool`, pi typebox `parameters`, …). This is the
|
|
23
|
+
* bit-perfect interface both sides agree on (A3 Semantic Bit-Masking).
|
|
24
|
+
*
|
|
25
|
+
* Structurally identical to `@apnex/cognitive-layer`'s `Tool`, deliberately
|
|
26
|
+
* re-declared here so the contract owns its own shape and carries no dependency
|
|
27
|
+
* on the cognitive layer.
|
|
28
|
+
*/
|
|
29
|
+
export interface ToolDescriptor {
|
|
30
|
+
name: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
inputSchema?: unknown;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Options forwarded to a dispatch-time agent call. Mirrors the kernel's
|
|
37
|
+
* `AgentCallOptions` subset the tool-manager relies on.
|
|
38
|
+
*/
|
|
39
|
+
export interface ToolDispatchCallOptions {
|
|
40
|
+
/** Mark this call internal-machinery — skip LLM-facing result transforms. */
|
|
41
|
+
internal?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The minimal agent surface the Tool-Manager needs. `McpAgentClient` /
|
|
45
|
+
* `IAgentClient` satisfy this structurally — the tool-manager imports THIS,
|
|
46
|
+
* never the class, which is what keeps the module carve-able and breaks the
|
|
47
|
+
* would-be circular dependency (tool-manager → kernel).
|
|
48
|
+
*
|
|
49
|
+
* `listTools()` already returns the tier-filtered, cognitively-enriched surface
|
|
50
|
+
* (the kernel owns that filtering) — the tool-manager consumes the finished
|
|
51
|
+
* descriptor and does not re-derive it.
|
|
52
|
+
*/
|
|
53
|
+
export interface IToolDispatchAgent {
|
|
54
|
+
readonly state: string;
|
|
55
|
+
readonly isConnected: boolean;
|
|
56
|
+
call(method: string, params: Record<string, unknown>, opts?: ToolDispatchCallOptions): Promise<unknown>;
|
|
57
|
+
listTools(): Promise<ToolDescriptor[]>;
|
|
58
|
+
getMetrics?(): {
|
|
59
|
+
agentId?: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Neutral dispatch result. Bindings format this into their host shape (MCP
|
|
64
|
+
* `content[]` + `isError`, pi `ToolResult`, …). NOT an MCP `CallToolResult`.
|
|
65
|
+
*/
|
|
66
|
+
export interface ToolDispatchResult {
|
|
67
|
+
/** Raw dispatch return — a string, or a JSON-serializable value. */
|
|
68
|
+
value: unknown;
|
|
69
|
+
isError: boolean;
|
|
70
|
+
/** Present when `isError` — the normalized failure message. */
|
|
71
|
+
errorMessage?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The Tool-Manager authority (Slice B fills the impl). Owns exactly two
|
|
75
|
+
* concerns (A3 Law of One): the tool CATALOG (what tools exist, projected for a
|
|
76
|
+
* host) and tool DISPATCH (the per-call behavior wrapper currently trapped in
|
|
77
|
+
* the MCP `CallTool` handler body). Every binding terminates in `dispatch()`.
|
|
78
|
+
*/
|
|
79
|
+
export interface IToolManager {
|
|
80
|
+
/** Catalog authority — the derive-from-one-walk surface (A2). */
|
|
81
|
+
listTools(agent: IToolDispatchAgent): Promise<ToolDescriptor[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Dispatch authority — the per-call behavior wrapper. Owns signal-FSM
|
|
84
|
+
* wrapping, queueItemId injection, active-call idle-gate bookkeeping, work-
|
|
85
|
+
* lease observation, and error normalization. (Slice B.)
|
|
86
|
+
*/
|
|
87
|
+
dispatch(agent: IToolDispatchAgent, name: string, args: Record<string, unknown>): Promise<ToolDispatchResult>;
|
|
88
|
+
/** idle-gate reads (the wake/stall reconciler consumes these). */
|
|
89
|
+
getActiveCallCount(): number;
|
|
90
|
+
isIdle(): boolean;
|
|
91
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* contracts.ts — the agnostic Tool-Manager contract (Slice A).
|
|
3
|
+
*
|
|
4
|
+
* The internal-sovereign-module boundary for tool catalog + dispatch. These
|
|
5
|
+
* interfaces are host- AND transport-agnostic BY CONSTRUCTION: nothing here
|
|
6
|
+
* imports `@modelcontextprotocol/sdk`, `McpAgentClient`, or any binding. A
|
|
7
|
+
* consumer (the MCP binding, pi's native binding, a future ACP binding) depends
|
|
8
|
+
* ONLY on these types — never on the concrete kernel classes (A3 Air-Gap).
|
|
9
|
+
*
|
|
10
|
+
* Design: docs/designs/m-sovereign-tool-manager-design.md
|
|
11
|
+
* Axioms: A3 Sovereign Composition (Law of One, Air-Gap, Semantic Bit-Masking,
|
|
12
|
+
* Earned Exposure — this is an INTERNAL module, not a published package).
|
|
13
|
+
*
|
|
14
|
+
* SLICE A INVARIANT: purely additive. `McpAgentClient` (via `IAgentClient`)
|
|
15
|
+
* structurally satisfies `IToolDispatchAgent` today with zero changes — this
|
|
16
|
+
* file only NAMES the subset the tool-manager actually needs, so the dispatch
|
|
17
|
+
* authority (Slice B) can depend on the interface instead of the class.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=contracts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/tool-manager/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dispatch.ts — the tool DISPATCH authority (Slice B).
|
|
3
|
+
*
|
|
4
|
+
* This is the per-call behavior wrapper extracted VERBATIM from the MCP
|
|
5
|
+
* `CallTool` handler body in `dispatcher.ts` (the god-object). It owns the
|
|
6
|
+
* OIS-Hub dispatch policy that EVERY host binding must share:
|
|
7
|
+
* - idle-gate bookkeeping (activeCallCount) for the wake/stall reconciler
|
|
8
|
+
* - callToolGate wait + bug-126 timeout
|
|
9
|
+
* - "Hub not connected" pre-check
|
|
10
|
+
* - injectQueueItemId (ADR-017)
|
|
11
|
+
* - signal_working_* FSM wrapping (mission-62)
|
|
12
|
+
* - workLeases.observe (idea-353)
|
|
13
|
+
* - onToolCallResult host hook
|
|
14
|
+
* - error normalization + W10 terminal-log discipline
|
|
15
|
+
*
|
|
16
|
+
* SLICE B DISCIPLINE: this is a faithful EXTRACT-AND-DELEGATE. The logic, its
|
|
17
|
+
* order, the log lines, and the return shape are preserved byte-for-byte from
|
|
18
|
+
* the original handler so the 272-test regression suite certifies behavioral
|
|
19
|
+
* identity. The MCP `CallTool` handler in `dispatcher.ts` now calls
|
|
20
|
+
* `runToolDispatch(...)` and returns its result directly.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately NOT done here (deferred to Slice C, per the two-phase rule):
|
|
23
|
+
* - converting the MCP-shaped return to the neutral `ToolDispatchResult`
|
|
24
|
+
* - relocating callToolGate / "Hub not connected" to the MCP binding
|
|
25
|
+
* - collapsing the closure / renaming
|
|
26
|
+
* Faithful move first; structural cleanup when files move.
|
|
27
|
+
*
|
|
28
|
+
* Design: docs/designs/m-sovereign-tool-manager-design.md (Slice B)
|
|
29
|
+
* Axioms: A3 (Air-Gap — depends on injected deps, not the closure), A8 (certify
|
|
30
|
+
* before ascending — regression parity is the gate).
|
|
31
|
+
*/
|
|
32
|
+
import type { IToolDispatchAgent } from "../contracts.js";
|
|
33
|
+
import { WorkLeaseTracker } from "../work-protocol/work-lease-tracker.js";
|
|
34
|
+
/**
|
|
35
|
+
* The MCP-shaped result the CallTool handler returns today. Preserved verbatim
|
|
36
|
+
* in Slice B (the neutral `ToolDispatchResult` conversion is a Slice-C concern).
|
|
37
|
+
*/
|
|
38
|
+
export interface McpToolCallResult {
|
|
39
|
+
content: Array<{
|
|
40
|
+
type: "text";
|
|
41
|
+
text: string;
|
|
42
|
+
}>;
|
|
43
|
+
isError?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Explicit dependency context for a single tool dispatch. In the god-object
|
|
47
|
+
* these were closure variables; making them injected params is the A3 Air-Gap
|
|
48
|
+
* boundary being realized — `runToolDispatch` is now understandable and testable
|
|
49
|
+
* from its inputs alone (A3 Local Reasoning), with no hidden closure state.
|
|
50
|
+
*/
|
|
51
|
+
export interface ToolDispatchContext {
|
|
52
|
+
/** Late-bound agent accessor (null = not connected yet). */
|
|
53
|
+
getAgent: () => IToolDispatchAgent | null;
|
|
54
|
+
/** ADR-017 queueItemId tracking map (shared with the notification path). */
|
|
55
|
+
pendingActionMap: Map<string, string>;
|
|
56
|
+
/** idea-353 lease tracker (shared with the wake/stall reconciler). */
|
|
57
|
+
workLeases: WorkLeaseTracker;
|
|
58
|
+
/** Increment on dispatch entry (idle-gate); returns nothing. */
|
|
59
|
+
onCallStart: () => void;
|
|
60
|
+
/** Decrement on dispatch exit (idle-gate). */
|
|
61
|
+
onCallEnd: () => void;
|
|
62
|
+
/** Optional gate the dispatch awaits before touching the Hub. */
|
|
63
|
+
callToolGate?: Promise<void>;
|
|
64
|
+
/** bug-126 gate timeout (ms). Default 30000; 0 disables. */
|
|
65
|
+
callToolGateTimeoutMs?: number;
|
|
66
|
+
/** idea-353 W2 host observation hook (best-effort). */
|
|
67
|
+
onToolCallResult?: (method: string, args: Record<string, unknown>, result: unknown) => void;
|
|
68
|
+
/** Diagnostic logger. */
|
|
69
|
+
log: (msg: string) => void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Execute one host-driven tool call through the full OIS dispatch policy.
|
|
73
|
+
*
|
|
74
|
+
* Extracted verbatim from the CallTool handler; `ctx` supplies what were closure
|
|
75
|
+
* variables. Returns the same MCP-shaped result the handler returned.
|
|
76
|
+
*/
|
|
77
|
+
export declare function runToolDispatch(ctx: ToolDispatchContext, requestedTool: string, incomingArgs: Record<string, unknown>): Promise<McpToolCallResult>;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dispatch.ts — the tool DISPATCH authority (Slice B).
|
|
3
|
+
*
|
|
4
|
+
* This is the per-call behavior wrapper extracted VERBATIM from the MCP
|
|
5
|
+
* `CallTool` handler body in `dispatcher.ts` (the god-object). It owns the
|
|
6
|
+
* OIS-Hub dispatch policy that EVERY host binding must share:
|
|
7
|
+
* - idle-gate bookkeeping (activeCallCount) for the wake/stall reconciler
|
|
8
|
+
* - callToolGate wait + bug-126 timeout
|
|
9
|
+
* - "Hub not connected" pre-check
|
|
10
|
+
* - injectQueueItemId (ADR-017)
|
|
11
|
+
* - signal_working_* FSM wrapping (mission-62)
|
|
12
|
+
* - workLeases.observe (idea-353)
|
|
13
|
+
* - onToolCallResult host hook
|
|
14
|
+
* - error normalization + W10 terminal-log discipline
|
|
15
|
+
*
|
|
16
|
+
* SLICE B DISCIPLINE: this is a faithful EXTRACT-AND-DELEGATE. The logic, its
|
|
17
|
+
* order, the log lines, and the return shape are preserved byte-for-byte from
|
|
18
|
+
* the original handler so the 272-test regression suite certifies behavioral
|
|
19
|
+
* identity. The MCP `CallTool` handler in `dispatcher.ts` now calls
|
|
20
|
+
* `runToolDispatch(...)` and returns its result directly.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately NOT done here (deferred to Slice C, per the two-phase rule):
|
|
23
|
+
* - converting the MCP-shaped return to the neutral `ToolDispatchResult`
|
|
24
|
+
* - relocating callToolGate / "Hub not connected" to the MCP binding
|
|
25
|
+
* - collapsing the closure / renaming
|
|
26
|
+
* Faithful move first; structural cleanup when files move.
|
|
27
|
+
*
|
|
28
|
+
* Design: docs/designs/m-sovereign-tool-manager-design.md (Slice B)
|
|
29
|
+
* Axioms: A3 (Air-Gap — depends on injected deps, not the closure), A8 (certify
|
|
30
|
+
* before ascending — regression parity is the gate).
|
|
31
|
+
*/
|
|
32
|
+
import { injectQueueItemId, TOOL_CALL_SIGNAL_SKIP } from "./tool-call-policy.js";
|
|
33
|
+
/** True when the agent is present and not explicitly disconnected. */
|
|
34
|
+
function isUsableAgent(agent) {
|
|
35
|
+
return !!agent && agent.isConnected !== false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Execute one host-driven tool call through the full OIS dispatch policy.
|
|
39
|
+
*
|
|
40
|
+
* Extracted verbatim from the CallTool handler; `ctx` supplies what were closure
|
|
41
|
+
* variables. Returns the same MCP-shaped result the handler returned.
|
|
42
|
+
*/
|
|
43
|
+
export async function runToolDispatch(ctx, requestedTool, incomingArgs) {
|
|
44
|
+
const { log } = ctx;
|
|
45
|
+
const callStartedAt = Date.now();
|
|
46
|
+
log(`[CallTool] ${requestedTool} entered`);
|
|
47
|
+
// idea-353 W1 idle-gate: mark the agent busy for the full lifespan of this
|
|
48
|
+
// host CallTool (gate-wait included), cleared in the finally below.
|
|
49
|
+
ctx.onCallStart();
|
|
50
|
+
try {
|
|
51
|
+
if (ctx.callToolGate) {
|
|
52
|
+
log(`[CallTool] ${requestedTool} awaiting callToolGate`);
|
|
53
|
+
// mission-88 W10 (bug-126 fix): timeout the gate await to prevent
|
|
54
|
+
// indefinite hang on pending-forever sessionReady. Default 30s; set
|
|
55
|
+
// callToolGateTimeoutMs=0 to disable (test-only). Structured
|
|
56
|
+
// `gate-timeout` log emitted on timeout; isError response returned.
|
|
57
|
+
const timeoutMs = ctx.callToolGateTimeoutMs ?? 30000;
|
|
58
|
+
if (timeoutMs > 0) {
|
|
59
|
+
let timeoutHandle;
|
|
60
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
61
|
+
timeoutHandle = setTimeout(() => {
|
|
62
|
+
reject(new Error(`callToolGate timeout after ${timeoutMs}ms`));
|
|
63
|
+
}, timeoutMs);
|
|
64
|
+
});
|
|
65
|
+
try {
|
|
66
|
+
await Promise.race([ctx.callToolGate, timeoutPromise]);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if (timeoutHandle)
|
|
70
|
+
clearTimeout(timeoutHandle);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
await ctx.callToolGate;
|
|
75
|
+
}
|
|
76
|
+
log(`[CallTool] ${requestedTool} gate passed (+${Date.now() - callStartedAt}ms)`);
|
|
77
|
+
}
|
|
78
|
+
const agent = ctx.getAgent();
|
|
79
|
+
if (!isUsableAgent(agent)) {
|
|
80
|
+
log(`[CallTool] ${requestedTool} aborted — Hub not connected`);
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: JSON.stringify({
|
|
86
|
+
error: "Hub not connected",
|
|
87
|
+
message: "The Hub adapter is not currently connected.",
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const name = requestedTool;
|
|
95
|
+
const outgoingArgs = injectQueueItemId(name, incomingArgs, ctx.pendingActionMap);
|
|
96
|
+
// ── Mission-62 W3 — activity FSM signal wrapping ─────────────
|
|
97
|
+
// Wrap each LLM-driven tool call with signal_working_started +
|
|
98
|
+
// signal_working_completed RPCs (fire-and-forget). Skip-list prevents
|
|
99
|
+
// recursion + handshake/lifecycle tools.
|
|
100
|
+
const wrapWithSignal = !TOOL_CALL_SIGNAL_SKIP.has(name);
|
|
101
|
+
if (wrapWithSignal) {
|
|
102
|
+
agent.call("signal_working_started", { toolName: name }).catch((err) => {
|
|
103
|
+
log(`[mission-62] signal_working_started fire-and-forget failed (non-fatal): ${err?.message ?? err}`);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
let result;
|
|
107
|
+
const agentCallStart = Date.now();
|
|
108
|
+
log(`[CallTool] ${name} dispatching to agent.call (wrapWithSignal=${wrapWithSignal})`);
|
|
109
|
+
try {
|
|
110
|
+
result = await agent.call(name, outgoingArgs);
|
|
111
|
+
log(`[CallTool] ${name} agent.call returned in ${Date.now() - agentCallStart}ms`);
|
|
112
|
+
// idea-355 §4.3 (invariant #3) — kernel-side W2 observer. Feed this
|
|
113
|
+
// agent's own work-verb results to the lease tracker so the heartbeat
|
|
114
|
+
// tick's stall-prompt has a populated lease map. Best-effort.
|
|
115
|
+
try {
|
|
116
|
+
ctx.workLeases.observe(name, outgoingArgs, result, Date.now());
|
|
117
|
+
}
|
|
118
|
+
catch (obsErr) {
|
|
119
|
+
log(`[idea-353] kernel lease observe threw (non-fatal): ${obsErr?.message ?? obsErr}`);
|
|
120
|
+
}
|
|
121
|
+
// idea-353 W2: optional host hook for host-specific observation.
|
|
122
|
+
if (ctx.onToolCallResult) {
|
|
123
|
+
try {
|
|
124
|
+
ctx.onToolCallResult(name, outgoingArgs, result);
|
|
125
|
+
}
|
|
126
|
+
catch (hookErr) {
|
|
127
|
+
log(`[idea-353] onToolCallResult hook threw (non-fatal): ${hookErr?.message ?? hookErr}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
if (wrapWithSignal) {
|
|
133
|
+
agent.call("signal_working_completed", {}).catch((err) => {
|
|
134
|
+
log(`[mission-62] signal_working_completed fire-and-forget failed (non-fatal): ${err?.message ?? err}`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
log(`[CallTool] ${name} completed in ${Date.now() - callStartedAt}ms total`);
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: "text",
|
|
143
|
+
text: typeof result === "string"
|
|
144
|
+
? result
|
|
145
|
+
: JSON.stringify(result, null, 2),
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
152
|
+
// mission-88 W10 (bug-126 fix): post-condition logging discipline — every
|
|
153
|
+
// CallTool entry MUST emit exactly one terminal log line.
|
|
154
|
+
const outcome = message.startsWith("callToolGate timeout")
|
|
155
|
+
? "gate-timeout"
|
|
156
|
+
: "error-response";
|
|
157
|
+
log(`[CallTool] ${requestedTool} terminal: outcome=${outcome} elapsed=${Date.now() - callStartedAt}ms message="${message}"`);
|
|
158
|
+
return {
|
|
159
|
+
content: [
|
|
160
|
+
{ type: "text", text: JSON.stringify({ error: message, w10_outcome: outcome }) },
|
|
161
|
+
],
|
|
162
|
+
isError: true,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
// idea-353 W1 idle-gate: this CallTool is no longer in flight.
|
|
167
|
+
ctx.onCallEnd();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/tool-manager/dispatch/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tool-call-policy.ts — pure OIS-Hub tool-call policy helpers (Slice B).
|
|
3
|
+
*
|
|
4
|
+
* Extracted VERBATIM from `dispatcher.ts` so both the dispatch authority
|
|
5
|
+
* (`dispatch.ts`) and the god-object shell can share them without a circular
|
|
6
|
+
* import. Pure functions + one constant; no closure, no MCP, no kernel.
|
|
7
|
+
*
|
|
8
|
+
* These encode OIS-Hub-specific dispatch POLICY (the §8 debt in the design):
|
|
9
|
+
* the thread/queue queueItemId settlement rule + the signal-FSM skip-list. They
|
|
10
|
+
* live in the tool-manager module (isolated), NOT in a generic core — which is
|
|
11
|
+
* exactly why the module is not a publishable package (Earned Exposure / the
|
|
12
|
+
* standalone-utility test).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Mission-62 W3: tools that should NOT trigger signal_working_* wrapping. The
|
|
16
|
+
* signal_* tools themselves would recurse infinitely; register_role +
|
|
17
|
+
* claim_session + drain_pending_actions are lifecycle tools, not semantic
|
|
18
|
+
* tool-call-work.
|
|
19
|
+
*/
|
|
20
|
+
export declare const TOOL_CALL_SIGNAL_SKIP: ReadonlySet<string>;
|
|
21
|
+
/** Compose the pendingActionMap key. Pure helper; exported for tests. */
|
|
22
|
+
export declare function pendingKey(dispatchType: string, entityRef: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Inject `sourceQueueItemId` into a settling tool call's arguments when a
|
|
25
|
+
* pendingActionMap entry is registered for the call's target. Currently only
|
|
26
|
+
* `create_thread_reply` settles a thread_message dispatch; extend this set as
|
|
27
|
+
* new auto-injection rules are ratified.
|
|
28
|
+
*
|
|
29
|
+
* Side effect: deletes the consumed map entry. Explicit sourceQueueItemId in the
|
|
30
|
+
* args wins over the map (no rewrite).
|
|
31
|
+
*/
|
|
32
|
+
export declare function injectQueueItemId(name: string, args: Record<string, unknown>, pendingActionMap: Map<string, string>): Record<string, unknown>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tool-call-policy.ts — pure OIS-Hub tool-call policy helpers (Slice B).
|
|
3
|
+
*
|
|
4
|
+
* Extracted VERBATIM from `dispatcher.ts` so both the dispatch authority
|
|
5
|
+
* (`dispatch.ts`) and the god-object shell can share them without a circular
|
|
6
|
+
* import. Pure functions + one constant; no closure, no MCP, no kernel.
|
|
7
|
+
*
|
|
8
|
+
* These encode OIS-Hub-specific dispatch POLICY (the §8 debt in the design):
|
|
9
|
+
* the thread/queue queueItemId settlement rule + the signal-FSM skip-list. They
|
|
10
|
+
* live in the tool-manager module (isolated), NOT in a generic core — which is
|
|
11
|
+
* exactly why the module is not a publishable package (Earned Exposure / the
|
|
12
|
+
* standalone-utility test).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Mission-62 W3: tools that should NOT trigger signal_working_* wrapping. The
|
|
16
|
+
* signal_* tools themselves would recurse infinitely; register_role +
|
|
17
|
+
* claim_session + drain_pending_actions are lifecycle tools, not semantic
|
|
18
|
+
* tool-call-work.
|
|
19
|
+
*/
|
|
20
|
+
export const TOOL_CALL_SIGNAL_SKIP = new Set([
|
|
21
|
+
"signal_working_started",
|
|
22
|
+
"signal_working_completed",
|
|
23
|
+
"signal_quota_blocked",
|
|
24
|
+
"signal_quota_recovered",
|
|
25
|
+
"register_role",
|
|
26
|
+
"claim_session",
|
|
27
|
+
"drain_pending_actions",
|
|
28
|
+
]);
|
|
29
|
+
/** Compose the pendingActionMap key. Pure helper; exported for tests. */
|
|
30
|
+
export function pendingKey(dispatchType, entityRef) {
|
|
31
|
+
return `${dispatchType}:${entityRef}`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Inject `sourceQueueItemId` into a settling tool call's arguments when a
|
|
35
|
+
* pendingActionMap entry is registered for the call's target. Currently only
|
|
36
|
+
* `create_thread_reply` settles a thread_message dispatch; extend this set as
|
|
37
|
+
* new auto-injection rules are ratified.
|
|
38
|
+
*
|
|
39
|
+
* Side effect: deletes the consumed map entry. Explicit sourceQueueItemId in the
|
|
40
|
+
* args wins over the map (no rewrite).
|
|
41
|
+
*/
|
|
42
|
+
export function injectQueueItemId(name, args, pendingActionMap) {
|
|
43
|
+
if (name !== "create_thread_reply")
|
|
44
|
+
return args;
|
|
45
|
+
const threadId = args.threadId;
|
|
46
|
+
if (typeof threadId !== "string")
|
|
47
|
+
return args;
|
|
48
|
+
if ("sourceQueueItemId" in args)
|
|
49
|
+
return args;
|
|
50
|
+
const queueItemId = pendingActionMap.get(pendingKey("thread_message", threadId));
|
|
51
|
+
if (!queueItemId)
|
|
52
|
+
return args;
|
|
53
|
+
pendingActionMap.delete(pendingKey("thread_message", threadId));
|
|
54
|
+
return { ...args, sourceQueueItemId: queueItemId };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=tool-call-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-call-policy.js","sourceRoot":"","sources":["../../../src/tool-manager/dispatch/tool-call-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IAChE,wBAAwB;IACxB,0BAA0B;IAC1B,sBAAsB;IACtB,wBAAwB;IACxB,eAAe;IACf,eAAe;IACf,uBAAuB;CACxB,CAAC,CAAC;AAEH,yEAAyE;AACzE,MAAM,UAAU,UAAU,CAAC,YAAoB,EAAE,SAAiB;IAChE,OAAO,GAAG,YAAY,IAAI,SAAS,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAY,EACZ,IAA6B,EAC7B,gBAAqC;IAErC,IAAI,IAAI,KAAK,qBAAqB;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,mBAAmB,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjF,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,gBAAgB,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChE,OAAO,EAAE,GAAG,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC;AACrD,CAAC"}
|