@corenel/harness 0.20.0 → 0.21.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.
Files changed (131) hide show
  1. package/dist/chat/engine.d.ts +47 -0
  2. package/dist/chat/engine.d.ts.map +1 -0
  3. package/dist/chat/engine.js +803 -0
  4. package/dist/chat/engine.js.map +1 -0
  5. package/dist/chat/events.d.ts +5 -0
  6. package/dist/chat/events.d.ts.map +1 -0
  7. package/dist/chat/events.js +100 -0
  8. package/dist/chat/events.js.map +1 -0
  9. package/dist/chat/index.d.ts +9 -0
  10. package/dist/chat/index.d.ts.map +1 -0
  11. package/dist/chat/index.js +9 -0
  12. package/dist/chat/index.js.map +1 -0
  13. package/dist/chat/liveFold.d.ts +10 -0
  14. package/dist/chat/liveFold.d.ts.map +1 -0
  15. package/dist/chat/liveFold.js +31 -0
  16. package/dist/chat/liveFold.js.map +1 -0
  17. package/dist/chat/messages.d.ts +20 -0
  18. package/dist/chat/messages.d.ts.map +1 -0
  19. package/dist/chat/messages.js +56 -0
  20. package/dist/chat/messages.js.map +1 -0
  21. package/dist/chat/persist.d.ts +39 -0
  22. package/dist/chat/persist.d.ts.map +1 -0
  23. package/dist/chat/persist.js +107 -0
  24. package/dist/chat/persist.js.map +1 -0
  25. package/dist/chat/runWatchdog.d.ts +21 -0
  26. package/dist/chat/runWatchdog.d.ts.map +1 -0
  27. package/dist/chat/runWatchdog.js +92 -0
  28. package/dist/chat/runWatchdog.js.map +1 -0
  29. package/dist/chat/stitch.d.ts +26 -0
  30. package/dist/chat/stitch.d.ts.map +1 -0
  31. package/dist/chat/stitch.js +40 -0
  32. package/dist/chat/stitch.js.map +1 -0
  33. package/dist/chat/types.d.ts +163 -0
  34. package/dist/chat/types.d.ts.map +1 -0
  35. package/dist/chat/types.js +2 -0
  36. package/dist/chat/types.js.map +1 -0
  37. package/dist/core/loop.d.ts.map +1 -1
  38. package/dist/core/loop.js +50 -15
  39. package/dist/core/loop.js.map +1 -1
  40. package/dist/core/spawn.d.ts +10 -0
  41. package/dist/core/spawn.d.ts.map +1 -1
  42. package/dist/core/spawn.js +28 -5
  43. package/dist/core/spawn.js.map +1 -1
  44. package/dist/fileSchema.js +1 -1
  45. package/dist/guardrail/builtins.d.ts.map +1 -1
  46. package/dist/guardrail/builtins.js +11 -6
  47. package/dist/guardrail/builtins.js.map +1 -1
  48. package/dist/guardrail/guardrail.d.ts +8 -0
  49. package/dist/guardrail/guardrail.d.ts.map +1 -1
  50. package/dist/guardrail/guardrail.js +12 -0
  51. package/dist/guardrail/guardrail.js.map +1 -1
  52. package/dist/guardrail/index.d.ts +1 -1
  53. package/dist/guardrail/index.d.ts.map +1 -1
  54. package/dist/guardrail/index.js +1 -1
  55. package/dist/guardrail/index.js.map +1 -1
  56. package/dist/guardrail/serialize.d.ts.map +1 -1
  57. package/dist/guardrail/serialize.js +3 -0
  58. package/dist/guardrail/serialize.js.map +1 -1
  59. package/dist/guardrail/validate.d.ts.map +1 -1
  60. package/dist/guardrail/validate.js +4 -0
  61. package/dist/guardrail/validate.js.map +1 -1
  62. package/dist/orchestrator/sidecarTools.d.ts.map +1 -1
  63. package/dist/orchestrator/sidecarTools.js +8 -4
  64. package/dist/orchestrator/sidecarTools.js.map +1 -1
  65. package/dist/prompts/fitProject.d.ts +6 -0
  66. package/dist/prompts/fitProject.d.ts.map +1 -0
  67. package/dist/prompts/fitProject.js +6 -0
  68. package/dist/prompts/fitProject.js.map +1 -0
  69. package/dist/prompts/library/defaults.generated.js +7 -7
  70. package/dist/prompts/library/defaults.generated.js.map +1 -1
  71. package/dist/prompts/library/index.d.ts +2 -1
  72. package/dist/prompts/library/index.d.ts.map +1 -1
  73. package/dist/prompts/library/index.js +11 -16
  74. package/dist/prompts/library/index.js.map +1 -1
  75. package/dist/providers/gateway.d.ts +1 -0
  76. package/dist/providers/gateway.d.ts.map +1 -1
  77. package/dist/providers/gateway.js +1 -0
  78. package/dist/providers/gateway.js.map +1 -1
  79. package/dist/sidecar/askUserBroker.d.ts +40 -0
  80. package/dist/sidecar/askUserBroker.d.ts.map +1 -0
  81. package/dist/sidecar/askUserBroker.js +103 -0
  82. package/dist/sidecar/askUserBroker.js.map +1 -0
  83. package/dist/sidecar/fleetJwe.d.ts +25 -0
  84. package/dist/sidecar/fleetJwe.d.ts.map +1 -0
  85. package/dist/sidecar/fleetJwe.js +115 -0
  86. package/dist/sidecar/fleetJwe.js.map +1 -0
  87. package/dist/sidecar/host.d.ts +77 -1
  88. package/dist/sidecar/host.d.ts.map +1 -1
  89. package/dist/sidecar/host.js +220 -6
  90. package/dist/sidecar/host.js.map +1 -1
  91. package/dist/sidecar/identity.d.ts +4 -0
  92. package/dist/sidecar/identity.d.ts.map +1 -1
  93. package/dist/sidecar/memberGate.d.ts.map +1 -1
  94. package/dist/sidecar/memberGate.js +5 -0
  95. package/dist/sidecar/memberGate.js.map +1 -1
  96. package/dist/sidecar/server.d.ts +46 -4
  97. package/dist/sidecar/server.d.ts.map +1 -1
  98. package/dist/sidecar/server.js +523 -13
  99. package/dist/sidecar/server.js.map +1 -1
  100. package/dist/systemParts.d.ts +0 -1
  101. package/dist/systemParts.d.ts.map +1 -1
  102. package/dist/systemParts.js +6 -2
  103. package/dist/systemParts.js.map +1 -1
  104. package/dist/todos.d.ts +8 -0
  105. package/dist/todos.d.ts.map +1 -1
  106. package/dist/todos.js +21 -17
  107. package/dist/todos.js.map +1 -1
  108. package/dist/tools/builtins.d.ts +8 -0
  109. package/dist/tools/builtins.d.ts.map +1 -1
  110. package/dist/tools/builtins.js +21 -1
  111. package/dist/tools/builtins.js.map +1 -1
  112. package/dist/tools/namespaces.d.ts +8 -0
  113. package/dist/tools/namespaces.d.ts.map +1 -1
  114. package/dist/tools/namespaces.js +18 -0
  115. package/dist/tools/namespaces.js.map +1 -1
  116. package/dist/tools/skillTool.d.ts.map +1 -1
  117. package/dist/tools/skillTool.js +22 -1
  118. package/dist/tools/skillTool.js.map +1 -1
  119. package/dist/tools/toolFacts.d.ts +9 -0
  120. package/dist/tools/toolFacts.d.ts.map +1 -0
  121. package/dist/tools/toolFacts.js +19 -0
  122. package/dist/tools/toolFacts.js.map +1 -0
  123. package/dist/tools/toolSearch.d.ts +25 -6
  124. package/dist/tools/toolSearch.d.ts.map +1 -1
  125. package/dist/tools/toolSearch.js +62 -14
  126. package/dist/tools/toolSearch.js.map +1 -1
  127. package/dist/tools/workflowTool.d.ts +34 -0
  128. package/dist/tools/workflowTool.d.ts.map +1 -0
  129. package/dist/tools/workflowTool.js +122 -0
  130. package/dist/tools/workflowTool.js.map +1 -0
  131. package/package.json +6 -3
@@ -0,0 +1,92 @@
1
+ export const WATCHDOG_SOFT_MS = 45000;
2
+ export const WATCHDOG_TOOL_HARD_MS = 10 * 60 * 1000;
3
+ export function createRunWatchdog(onTimeout, opts) {
4
+ const softMs = opts?.softMs ?? WATCHDOG_SOFT_MS;
5
+ const hardMs = opts?.hardMs ?? WATCHDOG_TOOL_HARD_MS;
6
+ const toolsInFlight = new Set();
7
+ let soft;
8
+ let hard;
9
+ // What is left of the hard cap while tools are in flight, and when it was last armed.
10
+ let hardLeft = null;
11
+ let hardSince = 0;
12
+ let pauses = 0;
13
+ let done = false;
14
+ const fire = (reason) => {
15
+ if (done)
16
+ return;
17
+ done = true;
18
+ if (soft)
19
+ clearTimeout(soft);
20
+ if (hard)
21
+ clearTimeout(hard);
22
+ onTimeout(reason);
23
+ };
24
+ const armHard = () => {
25
+ if (done || pauses > 0 || hardLeft === null || hard)
26
+ return;
27
+ hardSince = Date.now();
28
+ hard = setTimeout(() => fire('tool-hard-cap'), hardLeft);
29
+ };
30
+ // Stops the hard cap, keeping what is left of it.
31
+ const holdHard = () => {
32
+ if (!hard)
33
+ return;
34
+ clearTimeout(hard);
35
+ hard = undefined;
36
+ if (hardLeft !== null)
37
+ hardLeft = Math.max(0, hardLeft - (Date.now() - hardSince));
38
+ };
39
+ const bump = () => {
40
+ if (soft)
41
+ clearTimeout(soft);
42
+ if (done || pauses > 0)
43
+ return;
44
+ if (toolsInFlight.size > 0) {
45
+ // Soft timer stays down mid-tool; the hard cap (armed on tool-call) guards.
46
+ return;
47
+ }
48
+ soft = setTimeout(() => fire('silent'), softMs);
49
+ };
50
+ return {
51
+ onEvent(e) {
52
+ if (e.type === 'tool-call' && e.id != null) {
53
+ if (toolsInFlight.size === 0) {
54
+ hardLeft = hardMs;
55
+ armHard();
56
+ }
57
+ toolsInFlight.add(e.id);
58
+ }
59
+ else if (e.type === 'tool-result' && e.id != null) {
60
+ toolsInFlight.delete(e.id);
61
+ if (toolsInFlight.size === 0) {
62
+ if (hard) {
63
+ clearTimeout(hard);
64
+ hard = undefined;
65
+ }
66
+ hardLeft = null;
67
+ }
68
+ }
69
+ bump();
70
+ },
71
+ pause() {
72
+ pauses += 1;
73
+ if (soft)
74
+ clearTimeout(soft);
75
+ holdHard();
76
+ },
77
+ bump() {
78
+ if (pauses > 0)
79
+ pauses -= 1;
80
+ armHard();
81
+ bump();
82
+ },
83
+ clear() {
84
+ done = true;
85
+ if (soft)
86
+ clearTimeout(soft);
87
+ if (hard)
88
+ clearTimeout(hard);
89
+ },
90
+ };
91
+ }
92
+ //# sourceMappingURL=runWatchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runWatchdog.js","sourceRoot":"","sources":["../../chat/runWatchdog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ToolCheckMark, ToolHooksMark, TurnVerification } from '@corenel/protocol';
2
+ import type { ConversationTurn } from '../conversation';
3
+ import type { RunLoopResult } from './types';
4
+ /** The run's reply goes onto its user turn: FROM THE TAIL, by the count the run
5
+ * reports -- never an absolute offset into what was sent. Rung-2 compaction
6
+ * rewrites the array in place and the rewrite is shorter than the input, so an
7
+ * offset ran off the end and the reply was dropped. Each tool message gets its
8
+ * measured duration (`_ms`), its injection check (`_check`) and what its System
9
+ * One hooks did (`_hooks`; never a blocked result, which stays in the page). Note
10
+ * turns the run injected are removed (the run's own copy is in the reply), and
11
+ * the last compaction seam takes the run's folded view. */
12
+ export declare function stitchTurn(args: {
13
+ turns: ConversationTurn[];
14
+ userTurnId: string;
15
+ result: RunLoopResult;
16
+ toolChecks: Record<string, ToolCheckMark>;
17
+ toolHooks?: Record<string, ToolHooksMark>;
18
+ injectedTurnIds: string[];
19
+ seamIds: string[];
20
+ verification?: TurnVerification;
21
+ auditIncomplete?: {
22
+ lost: number;
23
+ unconfirmed?: boolean;
24
+ };
25
+ }): ConversationTurn[];
26
+ //# sourceMappingURL=stitch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stitch.d.ts","sourceRoot":"","sources":["../../chat/stitch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;2DAO2D;AAC3D,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,eAAe,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D,GAAG,gBAAgB,EAAE,CA4BrB"}
@@ -0,0 +1,40 @@
1
+ import { stampFoldedView } from './messages.js';
2
+ /** The run's reply goes onto its user turn: FROM THE TAIL, by the count the run
3
+ * reports -- never an absolute offset into what was sent. Rung-2 compaction
4
+ * rewrites the array in place and the rewrite is shorter than the input, so an
5
+ * offset ran off the end and the reply was dropped. Each tool message gets its
6
+ * measured duration (`_ms`), its injection check (`_check`) and what its System
7
+ * One hooks did (`_hooks`; never a blocked result, which stays in the page). Note
8
+ * turns the run injected are removed (the run's own copy is in the reply), and
9
+ * the last compaction seam takes the run's folded view. */
10
+ export function stitchTurn(args) {
11
+ const { result: res, toolChecks: checks } = args;
12
+ const hooks = args.toolHooks ?? {};
13
+ const created = res.messages.slice(res.messages.length - res.appended).map((m) => {
14
+ const tid = m.tool_call_id;
15
+ if (m.role !== 'tool' || !tid)
16
+ return m;
17
+ return {
18
+ ...m,
19
+ ...(res.toolMs[tid] != null ? { _ms: res.toolMs[tid] } : {}),
20
+ ...(checks[tid] ? { _check: checks[tid] } : {}),
21
+ ...(hooks[tid] ? { _hooks: hooks[tid] } : {}),
22
+ };
23
+ });
24
+ const stitched = args.turns
25
+ .filter((t) => !args.injectedTurnIds.includes(t.id))
26
+ .map((t) => (t.id === args.userTurnId
27
+ ? {
28
+ ...t,
29
+ messages: [t.messages[0], ...created],
30
+ stats: res.stats,
31
+ ...(args.verification ? { verification: args.verification } : {}),
32
+ ...(args.auditIncomplete ? { auditIncomplete: args.auditIncomplete } : {}),
33
+ }
34
+ : t));
35
+ const lastSeam = args.seamIds[args.seamIds.length - 1];
36
+ return lastSeam
37
+ ? stampFoldedView(stitched, lastSeam, res.messages.filter((m) => m.role !== 'system'), args.userTurnId)
38
+ : stitched;
39
+ }
40
+ //# sourceMappingURL=stitch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stitch.js","sourceRoot":"","sources":["../../chat/stitch.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C;;;;;;;2DAO2D;AAC3D,MAAM,UAAU,UAAU,CAAC,IAU1B;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC/E,MAAM,GAAG,GAAI,CAA+B,CAAC,YAAY,CAAC;QAC1D,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC;QACxC,OAAO;YACL,GAAG,CAAC;YACJ,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9C,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU;QACnC,CAAC,CAAC;YACE,GAAG,CAAC;YACJ,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC;YACrC,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3E;QACH,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACV,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvD,OAAO,QAAQ;QACb,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC;QACvG,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC"}
@@ -0,0 +1,163 @@
1
+ import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
2
+ import type { AgentEvent, AskAnswers, AskQuestion, Usage } from '@corenel/protocol';
3
+ import type { ConversationTurn, TurnStats } from '../conversation';
4
+ import type { GuardVerdict } from '../guards';
5
+ type Pascal<S extends string> = S extends `${infer H}-${infer T}` ? `${Capitalize<H>}${Pascal<T>}` : Capitalize<S>;
6
+ /** Which conversation an event belongs to: one host serves every conversation. */
7
+ export interface ChatEventContext {
8
+ conversationId: string;
9
+ }
10
+ /** One required handler per AgentEvent member, named `on` + the PascalCase type. */
11
+ export type ChatEventHandlers = {
12
+ [E in AgentEvent as `on${Pascal<E['type']>}`]: (e: E, ctx: ChatEventContext) => void;
13
+ };
14
+ export interface ChatInput {
15
+ text: string;
16
+ images?: string[];
17
+ }
18
+ export interface ChatRequest {
19
+ conversationId: string | null;
20
+ input: ChatInput;
21
+ agent?: string;
22
+ }
23
+ export interface ChatTurnResult {
24
+ conversationId: string | null;
25
+ userTurnId: string;
26
+ outcome: 'done' | 'stopped' | 'failed' | 'refused';
27
+ stopReason?: string;
28
+ error?: string;
29
+ stats?: TurnStats;
30
+ /** True when runLoop was called, or hostTurn's produce ran. */
31
+ ran: boolean;
32
+ /** Which entry point started the turn. */
33
+ kind: 'send' | 'retry' | 'host-turn';
34
+ }
35
+ export interface ChatRun {
36
+ conversationId: Promise<string | null>;
37
+ done: Promise<ChatTurnResult>;
38
+ stop(reason: 'user' | 'budget' | 'access'): void;
39
+ inject(messages: {
40
+ id: string;
41
+ text: string;
42
+ }[], hard: boolean): boolean;
43
+ }
44
+ export interface LiveTool {
45
+ id: string;
46
+ name: string;
47
+ args?: Record<string, unknown>;
48
+ result?: string;
49
+ isError?: boolean;
50
+ done?: boolean;
51
+ ms?: number;
52
+ partial?: string;
53
+ }
54
+ export interface LiveState {
55
+ text: string;
56
+ tools: LiveTool[];
57
+ }
58
+ export interface ChatState {
59
+ turns: ConversationTurn[];
60
+ live: LiveState | null;
61
+ running: boolean;
62
+ error: string;
63
+ lastStopReason: string | null;
64
+ injectedIds: string[];
65
+ runId: string | null;
66
+ loaded: boolean;
67
+ loadMissed: boolean;
68
+ persistedLen: number | null;
69
+ saveBlocked: 'load-failed' | null;
70
+ mergeTick: number;
71
+ /** A console command typed into the chat that is still running, or null. */
72
+ pendingCommand: {
73
+ command: string;
74
+ startedAt: number;
75
+ } | null;
76
+ }
77
+ export interface StoredConversation {
78
+ id: string;
79
+ title: string;
80
+ titleLocked?: boolean;
81
+ model?: string;
82
+ messages: unknown[];
83
+ /** The system prompt frozen on the first turn. Saved while the engine holds one; a loaded one is used without asking host.system. */
84
+ system?: string;
85
+ }
86
+ export interface ChatPermissionRequest {
87
+ tool: string;
88
+ summary: string;
89
+ agent?: string;
90
+ input?: unknown;
91
+ signal: AbortSignal;
92
+ }
93
+ /** `by` says who allowed: 'session' when an earlier always-allow answered it without asking. */
94
+ export interface ChatPermissionAnswer {
95
+ allow: boolean;
96
+ always?: boolean;
97
+ note?: string;
98
+ by?: 'human' | 'session';
99
+ }
100
+ export interface RunLoopControl {
101
+ conversationId: string;
102
+ system: string;
103
+ signal: AbortSignal;
104
+ onEvent(e: AgentEvent): void;
105
+ onStart(runId: string): void;
106
+ onInjected(ids: string[]): void;
107
+ askPermission(req: ChatPermissionRequest): Promise<ChatPermissionAnswer>;
108
+ askUser(questions: AskQuestion[]): Promise<AskAnswers | null>;
109
+ reviewEdit(callId: string): Promise<unknown>;
110
+ /** Holds the watchdog while a host-owned prompt (a budget ask, a move offer) waits on a person. */
111
+ paused<T>(ask: () => Promise<T>): Promise<T>;
112
+ }
113
+ export interface RunLoopResult {
114
+ messages: ChatCompletionMessageParam[];
115
+ appended: number;
116
+ stopReason: string;
117
+ usage?: Usage;
118
+ stats?: TurnStats;
119
+ toolMs: Record<string, number>;
120
+ }
121
+ export interface ChatHost<O> extends ChatEventHandlers {
122
+ /** 'inject' is asked before each mid-run message is delivered; a refusal delivers nothing. */
123
+ guard(ctx: {
124
+ conversationId: string | null;
125
+ agent?: string;
126
+ kind: 'send' | 'retry' | 'host-turn' | 'inject';
127
+ }): Promise<GuardVerdict>;
128
+ createConversation(title: string): Promise<string>;
129
+ loadConversation(id: string): Promise<StoredConversation | null>;
130
+ writeConversation(c: StoredConversation, opts: {
131
+ allowTruncate: boolean;
132
+ }): Promise<void>;
133
+ runOptions(ctx: {
134
+ conversationId: string;
135
+ agent?: string;
136
+ }): Promise<O>;
137
+ /** Asked on a conversation's first turn, or when none is held (after Chat.resetSystem); the text is reused after that. */
138
+ system(ctx: {
139
+ conversationId: string;
140
+ agent?: string;
141
+ }): Promise<string>;
142
+ runLoop(messages: ChatCompletionMessageParam[], opts: O, control: RunLoopControl): Promise<RunLoopResult>;
143
+ injectInto(runId: string, messages: {
144
+ id: string;
145
+ text: string;
146
+ }[], hard: boolean): boolean;
147
+ askPermission(conversationId: string, req: ChatPermissionRequest): Promise<ChatPermissionAnswer>;
148
+ askUser(conversationId: string, questions: AskQuestion[], signal: AbortSignal): Promise<AskAnswers | null>;
149
+ reviewEdit(conversationId: string, callId: string, signal: AbortSignal): Promise<unknown>;
150
+ suggestFollowups(ctx: {
151
+ conversationId: string;
152
+ messages: ChatCompletionMessageParam[];
153
+ signal: AbortSignal;
154
+ }): void;
155
+ /** Called exactly once per turn, on every path of send, retry and hostTurn,
156
+ * including a refusal before the guard (empty input, a run already going, a
157
+ * load that lost a race to another run, a retry refused up front). `ran`
158
+ * says whether runLoop (or hostTurn's produce) was called. */
159
+ turnComplete(result: ChatTurnResult): void;
160
+ stateChanged(conversationId: string, global: boolean): void;
161
+ }
162
+ export {};
163
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../chat/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../chat/types.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../core/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../core/loop.ts"],"names":[],"mappings":"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"}
package/dist/core/loop.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { streamCompletion } from '../providers/gateway.js';
2
2
  import { resolveRecovery, classifyStreamError, classifyToolError, shouldRetryStream, backoffDelay, toolRecoveryHint, ToolFailureTracker, abortableSleep, } from './recovery.js';
3
3
  import { alog } from '../log.js';
4
- import { initialState, evaluateTurnStart, evaluateToolCall, evaluateCompletion } from '../guardrail/guardrail.js';
4
+ import { initialState, evaluateTurnStart, evaluateToolCall, evaluateCompletion, toolGateAdmits } from '../guardrail/guardrail.js';
5
5
  import { checkFeature } from '../guards.js';
6
6
  import { STANDARD_POLICY } from '../guardrail/builtins.js';
7
7
  import { toolAddress } from '../tools/namespaces.js';
@@ -13,7 +13,8 @@ import { afterCompaction, compactHistory, compactionDecision, estimateFill, isCo
13
13
  import { makeRecallHistoryTool, makeUpdateDirectivesTool } from '../tools/foldTools.js';
14
14
  import { contextNote, contextWindowLine, initialPressureGate, pressureDecision } from './contextPressure.js';
15
15
  import { fillToolsMarker } from '../prompts/toolsMarker.js';
16
- import { createToolLoader, serverIndex } from '../tools/toolSearch.js';
16
+ import { createToolLoader, serverIndex, isMcpTool } from '../tools/toolSearch.js';
17
+ import { listedIndex, shellToolLine } from '../tools/toolFacts.js';
17
18
  import { createSkillTool, skillIndex } from '../tools/skillTool.js';
18
19
  import { crewToolGuidance } from '../tools/crewList.js';
19
20
  import { createTurnVerifier } from './turnVerify.js';
@@ -145,7 +146,13 @@ export async function runAgent(args) {
145
146
  * `activeTools` is what one request may carry right now -- the eager tools,
146
147
  * `tool_search`, then the loaded ones, capped. Eager first so a full loaded
147
148
  * set can never push out `read_file`. */
148
- const deferred = args.deferredTools ?? [];
149
+ /* A tool the policy's tools gate refuses is not something this run can do,
150
+ * so it is never offered: not sent as a function, not named in the Listed or
151
+ * shell lines, and not in the pool `tool_search` searches. Calling it by name
152
+ * still reaches the policy gate below (`refused`), which refuses it. */
153
+ const admitted = (t) => toolGateAdmits(policy, { name: t.name, address: toolAddress(t) });
154
+ const deferred = (args.deferredTools ?? []).filter(admitted);
155
+ const refused = new Map([...tools, ...(args.deferredTools ?? [])].filter((t) => !admitted(t)).map((t) => [t.name, t]));
149
156
  const loader = deferred.length
150
157
  ? createToolLoader({ deferred, loaded: args.loadedTools, onChange: (names) => emit({ type: 'tools-loaded', names }) })
151
158
  : null;
@@ -157,7 +164,7 @@ export async function runAgent(args) {
157
164
  ];
158
165
  /* Fold tools LAST: when MAX_PROVIDER_TOOLS caps this list, they must never be
159
166
  * what pushes `use_skill` or `tool_search` off the end. */
160
- const eager = [...tools, ...(skills.length ? [createSkillTool(skills)] : []), ...(loader ? [loader.searchTool] : []), ...foldTools];
167
+ const eager = [...tools.filter(admitted), ...(skills.length ? [createSkillTool(skills)] : []), ...(loader ? [loader.searchTool] : []), ...foldTools];
161
168
  const capped = (list) => (list.length > MAX_PROVIDER_TOOLS ? list.slice(0, MAX_PROVIDER_TOOLS) : list);
162
169
  const activeTools = () => capped(loader ? [...eager, ...loader.loaded()] : eager);
163
170
  let sent = activeTools();
@@ -171,8 +178,20 @@ export async function runAgent(args) {
171
178
  * the indexes: the browser composes its prompt with a tools marker, so
172
179
  * PromptHost.toolGuidance is handed no names there and cannot key on them.
173
180
  * Only when there is a system prompt to add it to. */
174
- const crewGuidance = system ? crewToolGuidance(eager.map((t) => t.name)) : '';
175
- const systemParts = [system, skillIndex(skills), loader ? serverIndex(deferred) : '', crewGuidance, contextWindowLine(ctxWindow)].filter(Boolean);
181
+ const reachable = [...eager.filter(admitted), ...deferred].map((t) => t.name);
182
+ // Held = sent on this request. A shell tool only reachable by search does
183
+ // not let the run run commands until a search loads it.
184
+ const held = sent.filter(admitted).map((t) => t.name);
185
+ const crewGuidance = system ? crewToolGuidance(reachable) : '';
186
+ const systemParts = [
187
+ system,
188
+ skillIndex(skills),
189
+ loader ? serverIndex(deferred.filter(isMcpTool)) : '',
190
+ loader ? listedIndex(deferred) : '',
191
+ system ? shellToolLine(held) : '',
192
+ crewGuidance,
193
+ contextWindowLine(ctxWindow),
194
+ ].filter(Boolean);
176
195
  const indexedSystem = systemParts.length ? systemParts.join('\n\n') : system;
177
196
  const filledSystem = indexedSystem ? fillToolsMarker(indexedSystem, sent) : indexedSystem;
178
197
  if (filledSystem && !messages.some((m) => m.role === 'system')) {
@@ -207,15 +226,26 @@ export async function runAgent(args) {
207
226
  let toolDefs = defsFor(sent);
208
227
  /* Dispatch from the SAME trimmed set. A tool that was not advertised must not
209
228
  * be callable either, or a model that guessed a name would reach something
210
- * the request never offered -- which includes a deferred tool nobody loaded. */
229
+ * the request never offered. The one exception is the run's deferred pool:
230
+ * those tools ARE offered, by name in the prompt and through `tool_search`,
231
+ * so calling one loads it (see the dispatch below). */
211
232
  let toolByName = new Map(sent.map((t) => [t.name, t]));
212
233
  /* What `list_tools` reports when the host supplied no listing of its own:
213
- * the tools THIS request carries, read at call time so tools a
214
- * `tool_search` loaded are included. Every loop answers for itself, so a
215
- * delegated callee lists its own surface, never its caller's. Without it a
216
- * host that never wired `ctx.listTools` (the daemon did not) tells the model
217
- * discovery is unavailable, and a model can read that as having no tools. */
218
- const listSent = () => sent.map((t) => ({ name: t.name, description: t.description, parameters: t.parameters }));
234
+ * everything the run can reach. The tools THIS request carries, read at call
235
+ * time so tools a `tool_search` loaded are included, then the rest of the
236
+ * deferred pool (already policy-filtered), marked: a Listed tool is one
237
+ * search away, and leaving it out reads as not having it. Every loop answers
238
+ * for itself, so a delegated callee lists its own surface, never its
239
+ * caller's. Without it a host that never wired `ctx.listTools` (the daemon
240
+ * did not) tells the model discovery is unavailable, and a model can read
241
+ * that as having no tools. */
242
+ const listReachable = () => {
243
+ const names = new Set(sent.map((t) => t.name));
244
+ return [
245
+ ...sent.map((t) => ({ name: t.name, description: t.description, parameters: t.parameters })),
246
+ ...deferred.filter((t) => !names.has(t.name)).map((t) => ({ name: t.name, description: t.description, parameters: t.parameters, deferred: true })),
247
+ ];
248
+ };
219
249
  // 'deferred' strategy only, and CRITICAL to the design: compact the INCOMING
220
250
  // history too, not just what this run produces. Without this, a result that
221
251
  // was sent full and never got a "subsequent call" WITHIN the run that
@@ -663,7 +693,12 @@ export async function runAgent(args) {
663
693
  const checkedLevel = dontsChecked.get(call.id) ?? null;
664
694
  if (checkedLevel === null)
665
695
  emit({ type: 'tool-call', id: call.id, name: call.name, args: parsed });
666
- const tool = toolByName.get(call.name);
696
+ /* A deferred tool called by name without a search: the prompt names the
697
+ * Listed ones, so this is the model doing what it was told. It is loaded
698
+ * as a search would load it (sent from the next call, counted toward the
699
+ * cap) and goes through every gate below. A tool the policy refuses was
700
+ * never offered; it is not loaded, and the policy gate refuses it. */
701
+ const tool = toolByName.get(call.name) ?? loader?.load(call.name) ?? refused.get(call.name);
667
702
  if (!tool) {
668
703
  messages.push({ role: 'tool', tool_call_id: call.id, content: `Error: unknown tool "${call.name}"` });
669
704
  emit({ type: 'tool-result', id: call.id, name: call.name, result: 'unknown tool', isError: true });
@@ -793,7 +828,7 @@ export async function runAgent(args) {
793
828
  try {
794
829
  // Per-call context: callId lets a tool correlate with UI state keyed by
795
830
  // tool_call id (propose_edit blocks on its review).
796
- const result = await tool.run(parsed, { ...toolCtx, listTools: toolCtx.listTools ?? listSent, callId: call.id, stream });
831
+ const result = await tool.run(parsed, { ...toolCtx, listTools: toolCtx.listTools ?? listReachable, callId: call.id, stream });
797
832
  callSettled = true;
798
833
  if (tool.mutates)
799
834
  await verifier.after(call.id, 'ok');