@namzu/sdk 0.1.4 → 0.1.5-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advisory/executor.d.ts +2 -2
- package/dist/advisory/executor.d.ts.map +1 -1
- package/dist/advisory/executor.js.map +1 -1
- package/dist/agents/AbstractAgent.d.ts +20 -2
- package/dist/agents/AbstractAgent.d.ts.map +1 -1
- package/dist/agents/AbstractAgent.js +23 -1
- package/dist/agents/AbstractAgent.js.map +1 -1
- package/dist/agents/PipelineAgent.d.ts.map +1 -1
- package/dist/agents/PipelineAgent.js +1 -1
- package/dist/agents/PipelineAgent.js.map +1 -1
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +1 -0
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/RouterAgent.d.ts.map +1 -1
- package/dist/agents/RouterAgent.js +4 -2
- package/dist/agents/RouterAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +4 -1
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/__tests__/lock.test.d.ts +2 -0
- package/dist/agents/__tests__/lock.test.d.ts.map +1 -0
- package/dist/agents/__tests__/lock.test.js +131 -0
- package/dist/agents/__tests__/lock.test.js.map +1 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +1 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lock.d.ts +42 -0
- package/dist/agents/lock.d.ts.map +1 -0
- package/dist/agents/lock.js +54 -0
- package/dist/agents/lock.js.map +1 -0
- package/dist/bridge/a2a/message.d.ts.map +1 -1
- package/dist/bridge/a2a/message.js.map +1 -1
- package/dist/bridge/tools/connector/router.d.ts +4 -5
- package/dist/bridge/tools/connector/router.d.ts.map +1 -1
- package/dist/bridge/tools/connector/router.js.map +1 -1
- package/dist/compaction/__tests__/SlidingWindowManager.test.d.ts +2 -0
- package/dist/compaction/__tests__/SlidingWindowManager.test.d.ts.map +1 -0
- package/dist/compaction/__tests__/SlidingWindowManager.test.js +113 -0
- package/dist/compaction/__tests__/SlidingWindowManager.test.js.map +1 -0
- package/dist/compaction/__tests__/dangling.test.d.ts +2 -0
- package/dist/compaction/__tests__/dangling.test.d.ts.map +1 -0
- package/dist/compaction/__tests__/dangling.test.js +356 -0
- package/dist/compaction/__tests__/dangling.test.js.map +1 -0
- package/dist/compaction/__tests__/factory.test.d.ts +2 -0
- package/dist/compaction/__tests__/factory.test.d.ts.map +1 -0
- package/dist/compaction/__tests__/factory.test.js +43 -0
- package/dist/compaction/__tests__/factory.test.js.map +1 -0
- package/dist/compaction/dangling.d.ts +96 -0
- package/dist/compaction/dangling.d.ts.map +1 -0
- package/dist/compaction/dangling.js +274 -0
- package/dist/compaction/dangling.js.map +1 -0
- package/dist/compaction/factory.d.ts +20 -0
- package/dist/compaction/factory.d.ts.map +1 -0
- package/dist/compaction/factory.js +35 -0
- package/dist/compaction/factory.js.map +1 -0
- package/dist/compaction/index.d.ts +5 -0
- package/dist/compaction/index.d.ts.map +1 -1
- package/dist/compaction/index.js +3 -0
- package/dist/compaction/index.js.map +1 -1
- package/dist/compaction/interface.d.ts +33 -0
- package/dist/compaction/interface.d.ts.map +1 -0
- package/dist/compaction/interface.js +2 -0
- package/dist/compaction/interface.js.map +1 -0
- package/dist/compaction/managers/index.d.ts +4 -0
- package/dist/compaction/managers/index.d.ts.map +1 -0
- package/dist/compaction/managers/index.js +4 -0
- package/dist/compaction/managers/index.js.map +1 -0
- package/dist/compaction/managers/null.d.ts +12 -0
- package/dist/compaction/managers/null.d.ts.map +1 -0
- package/dist/compaction/managers/null.js +15 -0
- package/dist/compaction/managers/null.js.map +1 -0
- package/dist/compaction/managers/slidingWindow.d.ts +27 -0
- package/dist/compaction/managers/slidingWindow.d.ts.map +1 -0
- package/dist/compaction/managers/slidingWindow.js +41 -0
- package/dist/compaction/managers/slidingWindow.js.map +1 -0
- package/dist/compaction/managers/structured.d.ts +23 -0
- package/dist/compaction/managers/structured.d.ts.map +1 -0
- package/dist/compaction/managers/structured.js +144 -0
- package/dist/compaction/managers/structured.js.map +1 -0
- package/dist/compaction/types.d.ts +1 -1
- package/dist/compaction/types.d.ts.map +1 -1
- package/dist/config/runtime.d.ts +16 -16
- package/dist/config/runtime.js +1 -1
- package/dist/config/runtime.js.map +1 -1
- package/dist/constants/agent/index.d.ts +1 -1
- package/dist/constants/agent/index.d.ts.map +1 -1
- package/dist/gateway/local.d.ts +2 -2
- package/dist/gateway/local.d.ts.map +1 -1
- package/dist/gateway/local.js +10 -1
- package/dist/gateway/local.js.map +1 -1
- package/dist/index.d.ts +18 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +3 -2
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +1 -2
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +2 -1
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/plugin/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/plugin/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/lifecycle.test.js +332 -0
- package/dist/plugin/__tests__/lifecycle.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts +2 -2
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +28 -2
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/resolver.d.ts +2 -2
- package/dist/plugin/resolver.d.ts.map +1 -1
- package/dist/plugin/resolver.js.map +1 -1
- package/dist/registry/agent/definitions.d.ts +3 -2
- package/dist/registry/agent/definitions.d.ts.map +1 -1
- package/dist/registry/agent/definitions.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +2 -5
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/decision/parser.d.ts.map +1 -1
- package/dist/runtime/decision/parser.js +15 -40
- package/dist/runtime/decision/parser.js.map +1 -1
- package/dist/runtime/query/context-cache.d.ts +3 -3
- package/dist/runtime/query/context-cache.d.ts.map +1 -1
- package/dist/runtime/query/context-cache.js.map +1 -1
- package/dist/runtime/query/context.d.ts +1 -1
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js.map +1 -1
- package/dist/runtime/query/events.js +11 -11
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +4 -2
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +1 -0
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +5 -3
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +2 -1
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +2 -2
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +2 -2
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/plan.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/plan.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/plan.js.map +1 -1
- package/dist/runtime/query/prompt.d.ts +2 -2
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/result.d.ts +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +4 -2
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +1 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/store/conversation/memory.d.ts +1 -1
- package/dist/store/conversation/memory.d.ts.map +1 -1
- package/dist/store/conversation/memory.js +15 -3
- package/dist/store/conversation/memory.js.map +1 -1
- package/dist/store/run/disk.d.ts +1 -2
- package/dist/store/run/disk.d.ts.map +1 -1
- package/dist/store/run/disk.js +21 -13
- package/dist/store/run/disk.js.map +1 -1
- package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +140 -0
- package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/structuredOutput.example.js +183 -0
- package/dist/tools/builtins/__tests__/structuredOutput.example.js.map +1 -0
- package/dist/tools/builtins/__tests__/structuredOutput.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/structuredOutput.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/structuredOutput.test.js +224 -0
- package/dist/tools/builtins/__tests__/structuredOutput.test.js.map +1 -0
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +1 -2
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/index.d.ts +1 -0
- package/dist/tools/builtins/index.d.ts.map +1 -1
- package/dist/tools/builtins/index.js +3 -0
- package/dist/tools/builtins/index.js.map +1 -1
- package/dist/tools/builtins/ls.d.ts +1 -1
- package/dist/tools/builtins/structuredOutput.d.ts +27 -0
- package/dist/tools/builtins/structuredOutput.d.ts.map +1 -0
- package/dist/tools/builtins/structuredOutput.js +46 -0
- package/dist/tools/builtins/structuredOutput.js.map +1 -0
- package/dist/tools/task/list.d.ts +1 -1
- package/dist/tools/task/list.d.ts.map +1 -1
- package/dist/tools/task/list.js.map +1 -1
- package/dist/types/agent/base.d.ts +4 -1
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/index.d.ts +1 -0
- package/dist/types/agent/index.d.ts.map +1 -1
- package/dist/types/agent/index.js +1 -0
- package/dist/types/agent/index.js.map +1 -1
- package/dist/types/agent/manager.d.ts +27 -0
- package/dist/types/agent/manager.d.ts.map +1 -0
- package/dist/types/agent/manager.js +2 -0
- package/dist/types/agent/manager.js.map +1 -0
- package/dist/types/agent/reactive.d.ts +2 -2
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +2 -2
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +0 -2
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js +0 -2
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/common/index.d.ts +0 -1
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +0 -1
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/hitl/index.d.ts +1 -2
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/invocation/__tests__/state.test.d.ts +2 -0
- package/dist/types/invocation/__tests__/state.test.d.ts.map +1 -0
- package/dist/types/invocation/__tests__/state.test.js +167 -0
- package/dist/types/invocation/__tests__/state.test.js.map +1 -0
- package/dist/types/invocation/index.d.ts +37 -0
- package/dist/types/invocation/index.d.ts.map +1 -0
- package/dist/types/invocation/index.js +23 -0
- package/dist/types/invocation/index.js.map +1 -0
- package/dist/types/plugin/index.d.ts +6 -0
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +16 -0
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/run/events.d.ts +1 -1
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/index.d.ts +1 -0
- package/dist/types/run/index.d.ts.map +1 -1
- package/dist/types/run/index.js +1 -0
- package/dist/types/run/index.js.map +1 -1
- package/dist/types/run/metadata.d.ts +1 -1
- package/dist/types/run/metadata.d.ts.map +1 -1
- package/dist/types/run/state.d.ts +1 -1
- package/dist/types/run/state.d.ts.map +1 -1
- package/dist/types/run/stop-reason.d.ts +2 -0
- package/dist/types/run/stop-reason.d.ts.map +1 -0
- package/dist/types/run/stop-reason.js +2 -0
- package/dist/types/run/stop-reason.js.map +1 -0
- package/dist/types/structured-output/index.d.ts +51 -0
- package/dist/types/structured-output/index.d.ts.map +1 -0
- package/dist/types/structured-output/index.js +2 -0
- package/dist/types/structured-output/index.js.map +1 -0
- package/dist/types/tool/index.d.ts +36 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/advisory/executor.ts +2 -4
- package/src/agents/AbstractAgent.ts +26 -3
- package/src/agents/PipelineAgent.ts +1 -1
- package/src/agents/ReactiveAgent.ts +1 -0
- package/src/agents/RouterAgent.ts +8 -2
- package/src/agents/SupervisorAgent.ts +5 -1
- package/src/agents/__tests__/lock.test.ts +158 -0
- package/src/agents/index.ts +2 -0
- package/src/agents/lock.ts +66 -0
- package/src/bridge/a2a/message.ts +1 -2
- package/src/bridge/tools/connector/router.ts +4 -5
- package/src/compaction/__tests__/SlidingWindowManager.test.ts +139 -0
- package/src/compaction/__tests__/dangling.test.ts +447 -0
- package/src/compaction/__tests__/factory.test.ts +53 -0
- package/src/compaction/dangling.ts +321 -0
- package/src/compaction/factory.ts +41 -0
- package/src/compaction/index.ts +14 -0
- package/src/compaction/interface.ts +35 -0
- package/src/compaction/managers/index.ts +3 -0
- package/src/compaction/managers/null.ts +19 -0
- package/src/compaction/managers/slidingWindow.ts +57 -0
- package/src/compaction/managers/structured.ts +169 -0
- package/src/compaction/types.ts +1 -1
- package/src/config/runtime.ts +1 -1
- package/src/constants/agent/index.ts +1 -1
- package/src/gateway/local.ts +13 -4
- package/src/index.ts +38 -1
- package/src/manager/agent/lifecycle.ts +3 -2
- package/src/manager/run/persistence.ts +3 -8
- package/src/plugin/__tests__/lifecycle.test.ts +430 -0
- package/src/plugin/lifecycle.ts +32 -6
- package/src/plugin/resolver.ts +3 -3
- package/src/registry/agent/definitions.ts +3 -2
- package/src/registry/tool/execute.ts +2 -5
- package/src/runtime/decision/parser.ts +15 -40
- package/src/runtime/query/context-cache.ts +3 -4
- package/src/runtime/query/context.ts +1 -2
- package/src/runtime/query/events.ts +11 -11
- package/src/runtime/query/executor.ts +5 -3
- package/src/runtime/query/index.ts +11 -4
- package/src/runtime/query/iteration/index.ts +2 -2
- package/src/runtime/query/iteration/phases/advisory.ts +1 -2
- package/src/runtime/query/iteration/phases/checkpoint.ts +1 -2
- package/src/runtime/query/iteration/phases/context.ts +2 -2
- package/src/runtime/query/iteration/phases/plan.ts +1 -2
- package/src/runtime/query/prompt.ts +3 -3
- package/src/runtime/query/result.ts +1 -2
- package/src/runtime/query/tooling.ts +5 -2
- package/src/store/conversation/memory.ts +21 -5
- package/src/store/run/disk.ts +18 -16
- package/src/tools/builtins/__tests__/structuredOutput.example.ts +221 -0
- package/src/tools/builtins/__tests__/structuredOutput.test.ts +275 -0
- package/src/tools/builtins/grep.ts +1 -2
- package/src/tools/builtins/index.ts +3 -0
- package/src/tools/builtins/structuredOutput.ts +55 -0
- package/src/tools/task/list.ts +1 -2
- package/src/types/agent/base.ts +5 -1
- package/src/types/agent/index.ts +1 -0
- package/src/types/agent/manager.ts +36 -0
- package/src/types/agent/reactive.ts +2 -2
- package/src/types/agent/supervisor.ts +2 -2
- package/src/types/agent/task.ts +0 -4
- package/src/types/common/index.ts +0 -2
- package/src/types/hitl/index.ts +1 -2
- package/src/types/invocation/__tests__/state.test.ts +210 -0
- package/src/types/invocation/index.ts +55 -0
- package/src/types/plugin/index.ts +19 -0
- package/src/types/run/events.ts +1 -10
- package/src/types/run/index.ts +1 -0
- package/src/types/run/metadata.ts +1 -1
- package/src/types/run/state.ts +1 -1
- package/src/types/run/stop-reason.ts +10 -0
- package/src/types/structured-output/index.ts +56 -0
- package/src/types/tool/index.ts +45 -0
package/src/gateway/local.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import type { AgentManager } from '../manager/agent/lifecycle.js'
|
|
2
1
|
import type { AgentInput } from '../types/agent/base.js'
|
|
3
2
|
import type { CreateTaskOptions, TaskGateway, TaskHandle } from '../types/agent/gateway.js'
|
|
3
|
+
import type { AgentManagerContract } from '../types/agent/manager.js'
|
|
4
4
|
import type { AgentTaskContext } from '../types/agent/task.js'
|
|
5
5
|
import type { TaskId } from '../types/ids/index.js'
|
|
6
6
|
import { createUserMessage } from '../types/message/index.js'
|
|
7
7
|
import type { RunEventListener } from '../types/run/events.js'
|
|
8
|
+
import { toErrorMessage } from '../utils/error.js'
|
|
9
|
+
import { getRootLogger } from '../utils/logger.js'
|
|
8
10
|
|
|
9
11
|
export class LocalTaskGateway implements TaskGateway {
|
|
10
|
-
private agentManager:
|
|
12
|
+
private agentManager: AgentManagerContract
|
|
11
13
|
private taskContext: AgentTaskContext
|
|
12
14
|
private listener: RunEventListener | undefined
|
|
13
15
|
private trackedTaskIds: Set<TaskId> = new Set()
|
|
@@ -17,7 +19,7 @@ export class LocalTaskGateway implements TaskGateway {
|
|
|
17
19
|
private completionListeners: Set<(handle: TaskHandle) => void> = new Set()
|
|
18
20
|
|
|
19
21
|
constructor(
|
|
20
|
-
agentManager:
|
|
22
|
+
agentManager: AgentManagerContract,
|
|
21
23
|
taskContext: AgentTaskContext,
|
|
22
24
|
listener?: RunEventListener,
|
|
23
25
|
parentInput?: Pick<AgentInput, 'taskStore' | 'runtimeToolOverrides'>,
|
|
@@ -56,7 +58,14 @@ export class LocalTaskGateway implements TaskGateway {
|
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
})
|
|
59
|
-
.catch(() => {
|
|
61
|
+
.catch((err) => {
|
|
62
|
+
getRootLogger()
|
|
63
|
+
.child({ component: 'LocalTaskGateway' })
|
|
64
|
+
.error('Task completion tracking failed', {
|
|
65
|
+
taskId: task.taskId,
|
|
66
|
+
error: toErrorMessage(err),
|
|
67
|
+
})
|
|
68
|
+
})
|
|
60
69
|
|
|
61
70
|
return toHandle(task)
|
|
62
71
|
}
|
package/src/index.ts
CHANGED
|
@@ -43,6 +43,8 @@ export * from './types/advisory/index.js'
|
|
|
43
43
|
export * from './types/memory/index.js'
|
|
44
44
|
export * from './types/plugin/index.js'
|
|
45
45
|
export * from './types/sandbox/index.js'
|
|
46
|
+
export * from './types/structured-output/index.js'
|
|
47
|
+
export * from './types/invocation/index.js'
|
|
46
48
|
|
|
47
49
|
export {
|
|
48
50
|
AdvisorRegistry,
|
|
@@ -106,8 +108,10 @@ export {
|
|
|
106
108
|
RouterAgent,
|
|
107
109
|
SupervisorAgent,
|
|
108
110
|
defineAgent,
|
|
111
|
+
InvocationLock,
|
|
112
|
+
ConcurrentInvocationError,
|
|
109
113
|
} from './agents/index.js'
|
|
110
|
-
export type { DefineAgentOptions } from './agents/index.js'
|
|
114
|
+
export type { DefineAgentOptions, ConcurrencyMode, Disposable } from './agents/index.js'
|
|
111
115
|
|
|
112
116
|
export { InMemoryStore } from './store/InMemoryStore.js'
|
|
113
117
|
export type { Identifiable, Timestamped } from './store/InMemoryStore.js'
|
|
@@ -184,9 +188,16 @@ export type { ToolExecutionResult } from './registry/tool/execute.js'
|
|
|
184
188
|
export { getBuiltinTools } from './tools/builtins/index.js'
|
|
185
189
|
export { ReadFileTool } from './tools/builtins/read-file.js'
|
|
186
190
|
export { WriteFileTool } from './tools/builtins/write-file.js'
|
|
191
|
+
export { EditTool } from './tools/builtins/edit.js'
|
|
187
192
|
export { BashTool } from './tools/builtins/bash.js'
|
|
188
193
|
export { GlobTool } from './tools/builtins/glob.js'
|
|
194
|
+
export { GrepTool } from './tools/builtins/grep.js'
|
|
195
|
+
export { LsTool } from './tools/builtins/ls.js'
|
|
189
196
|
export { SearchToolsTool } from './tools/builtins/search-tools.js'
|
|
197
|
+
export {
|
|
198
|
+
createStructuredOutputTool,
|
|
199
|
+
STRUCTURED_OUTPUT_TOOL_NAME,
|
|
200
|
+
} from './tools/builtins/structuredOutput.js'
|
|
190
201
|
|
|
191
202
|
export {
|
|
192
203
|
TextChunker,
|
|
@@ -280,6 +291,23 @@ export {
|
|
|
280
291
|
} from './bridge/sse/index.js'
|
|
281
292
|
export type { MappedStreamEvent } from './bridge/sse/index.js'
|
|
282
293
|
|
|
294
|
+
export {
|
|
295
|
+
AgentBus,
|
|
296
|
+
CircuitBreaker,
|
|
297
|
+
FileLockManager,
|
|
298
|
+
EditOwnershipTracker,
|
|
299
|
+
} from './bus/index.js'
|
|
300
|
+
export type { AgentBusConfig } from './bus/index.js'
|
|
301
|
+
|
|
302
|
+
export { VerificationGate, evaluateRule } from './verification/index.js'
|
|
303
|
+
export type { ToolCallContext } from './verification/index.js'
|
|
304
|
+
|
|
305
|
+
export { buildCoordinatorTools } from './tools/coordinator/index.js'
|
|
306
|
+
export type { CoordinatorToolsOptions, TaskLaunchedCallback } from './tools/coordinator/index.js'
|
|
307
|
+
|
|
308
|
+
export { checkLimitsDetailed, buildLimitConfig } from './run/LimitChecker.js'
|
|
309
|
+
export type { LimitCheckerState, LimitCheckResult } from './run/LimitChecker.js'
|
|
310
|
+
|
|
283
311
|
export { InMemoryCredentialVault } from './vault/index.js'
|
|
284
312
|
|
|
285
313
|
export {
|
|
@@ -301,6 +329,13 @@ export {
|
|
|
301
329
|
extractFromUserMessage,
|
|
302
330
|
extractFromAssistantMessage,
|
|
303
331
|
buildVerifiedSummary,
|
|
332
|
+
findDanglingMessages,
|
|
333
|
+
removeDanglingMessages,
|
|
334
|
+
findSafeTrimIndex,
|
|
335
|
+
NullManager,
|
|
336
|
+
SlidingWindowManager,
|
|
337
|
+
StructuredCompactionManager,
|
|
338
|
+
createConversationManager,
|
|
304
339
|
} from './compaction/index.js'
|
|
305
340
|
export type {
|
|
306
341
|
WorkingState,
|
|
@@ -309,4 +344,6 @@ export type {
|
|
|
309
344
|
FileAction,
|
|
310
345
|
ToolResultSlot,
|
|
311
346
|
CompactionStrategy,
|
|
347
|
+
DanglingResult,
|
|
348
|
+
ConversationManager,
|
|
312
349
|
} from './compaction/index.js'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AGENT_MANAGER_DEFAULTS } from '../../constants/agent/index.js'
|
|
2
|
+
import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js'
|
|
1
3
|
import type { AgentRegistry } from '../../registry/agent/definitions.js'
|
|
2
4
|
import type { BaseAgentConfig, BaseAgentResult } from '../../types/agent/base.js'
|
|
3
5
|
import type {
|
|
@@ -11,8 +13,7 @@ import type {
|
|
|
11
13
|
AgentTaskState,
|
|
12
14
|
SendMessageOptions,
|
|
13
15
|
} from '../../types/agent/task.js'
|
|
14
|
-
import {
|
|
15
|
-
import { EMPTY_TOKEN_USAGE } from '../../types/common/index.js'
|
|
16
|
+
import { isTerminalAgentTaskState } from '../../types/agent/task.js'
|
|
16
17
|
import type { RunId, TaskId } from '../../types/ids/index.js'
|
|
17
18
|
import type { Message } from '../../types/message/index.js'
|
|
18
19
|
import { createChildAbortController } from '../../utils/abort.js'
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
+
import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js'
|
|
1
2
|
import { RunDiskStore } from '../../store/run/disk.js'
|
|
2
|
-
import {
|
|
3
|
-
type CostInfo,
|
|
4
|
-
EMPTY_TOKEN_USAGE,
|
|
5
|
-
type TokenUsage,
|
|
6
|
-
accumulateTokenUsage,
|
|
7
|
-
} from '../../types/common/index.js'
|
|
3
|
+
import { type CostInfo, type TokenUsage, accumulateTokenUsage } from '../../types/common/index.js'
|
|
8
4
|
import type { RunId } from '../../types/ids/index.js'
|
|
9
5
|
import type { AssistantMessage, Message } from '../../types/message/index.js'
|
|
10
6
|
import type { EmergencySaveData } from '../../types/run/emergency.js'
|
|
11
|
-
import type { AgentRun, StopReason } from '../../types/run/index.js'
|
|
12
|
-
import type { RunPersistenceConfig } from '../../types/run/index.js'
|
|
7
|
+
import type { AgentRun, RunPersistenceConfig, StopReason } from '../../types/run/index.js'
|
|
13
8
|
import { type ModelPricing, ZERO_COST, accumulateCost } from '../../utils/cost.js'
|
|
14
9
|
import { generateEmergencySaveId } from '../../utils/id.js'
|
|
15
10
|
import type { Logger } from '../../utils/logger.js'
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import type { PluginRegistry } from '../../registry/plugin/index.js'
|
|
3
|
+
import type { PluginId, RunId } from '../../types/ids/index.js'
|
|
4
|
+
import type { PluginHookContext, PluginHookResult } from '../../types/plugin/index.js'
|
|
5
|
+
import type { ToolRegistryContract } from '../../types/tool/index.js'
|
|
6
|
+
import type { Logger } from '../../utils/logger.js'
|
|
7
|
+
import { PluginLifecycleManager } from '../lifecycle.js'
|
|
8
|
+
|
|
9
|
+
describe('PluginLifecycleManager', () => {
|
|
10
|
+
let manager: PluginLifecycleManager
|
|
11
|
+
let pluginRegistry: PluginRegistry
|
|
12
|
+
let toolRegistry: ToolRegistryContract
|
|
13
|
+
let logger: Logger
|
|
14
|
+
|
|
15
|
+
const mockRunId = 'run_test' as RunId
|
|
16
|
+
const mockPluginId = 'plugin_test' as PluginId
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
// Create mock registries and logger
|
|
20
|
+
pluginRegistry = {
|
|
21
|
+
register: vi.fn(),
|
|
22
|
+
unregister: vi.fn(),
|
|
23
|
+
getOrThrow: vi.fn(),
|
|
24
|
+
findByName: vi.fn(),
|
|
25
|
+
getAll: vi.fn(() => []),
|
|
26
|
+
} as any
|
|
27
|
+
|
|
28
|
+
toolRegistry = {
|
|
29
|
+
register: vi.fn(),
|
|
30
|
+
unregister: vi.fn(),
|
|
31
|
+
execute: vi.fn(),
|
|
32
|
+
getAll: vi.fn(() => []),
|
|
33
|
+
} as any
|
|
34
|
+
|
|
35
|
+
logger = {
|
|
36
|
+
child: vi.fn(() => ({
|
|
37
|
+
info: vi.fn(),
|
|
38
|
+
warn: vi.fn(),
|
|
39
|
+
error: vi.fn(),
|
|
40
|
+
debug: vi.fn(),
|
|
41
|
+
})),
|
|
42
|
+
info: vi.fn(),
|
|
43
|
+
warn: vi.fn(),
|
|
44
|
+
error: vi.fn(),
|
|
45
|
+
debug: vi.fn(),
|
|
46
|
+
} as any
|
|
47
|
+
|
|
48
|
+
manager = new PluginLifecycleManager({
|
|
49
|
+
pluginRegistry,
|
|
50
|
+
toolRegistry,
|
|
51
|
+
log: logger,
|
|
52
|
+
hookTimeoutMs: 5000,
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('executeHooks', () => {
|
|
57
|
+
it('should return empty array when no hooks registered', async () => {
|
|
58
|
+
const results = await manager.executeHooks('run_start', { runId: mockRunId })
|
|
59
|
+
expect(results).toEqual([])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('should execute all registered hooks for an event', async () => {
|
|
63
|
+
const hook1Handler = vi.fn(async (): Promise<PluginHookResult> => ({ action: 'continue' }))
|
|
64
|
+
const hook2Handler = vi.fn(async (): Promise<PluginHookResult> => ({ action: 'continue' }))
|
|
65
|
+
|
|
66
|
+
// Register hooks manually
|
|
67
|
+
manager['hookHandlers'].set('run_start', [
|
|
68
|
+
{ pluginId: 'plugin_1' as PluginId, handler: hook1Handler },
|
|
69
|
+
{ pluginId: 'plugin_2' as PluginId, handler: hook2Handler },
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
const results = await manager.executeHooks('run_start', { runId: mockRunId })
|
|
73
|
+
|
|
74
|
+
expect(results).toHaveLength(2)
|
|
75
|
+
expect(hook1Handler).toHaveBeenCalled()
|
|
76
|
+
expect(hook2Handler).toHaveBeenCalled()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('should handle hook timeout', async () => {
|
|
80
|
+
const slowHandler = vi.fn(
|
|
81
|
+
() =>
|
|
82
|
+
new Promise<PluginHookResult>((resolve) => {
|
|
83
|
+
setTimeout(() => resolve({ action: 'continue' }), 10000)
|
|
84
|
+
}),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
manager['hookHandlers'].set('run_start', [{ pluginId: mockPluginId, handler: slowHandler }])
|
|
88
|
+
|
|
89
|
+
const managerWithShortTimeout = new PluginLifecycleManager({
|
|
90
|
+
pluginRegistry,
|
|
91
|
+
toolRegistry,
|
|
92
|
+
log: logger,
|
|
93
|
+
hookTimeoutMs: 10, // Very short timeout
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
managerWithShortTimeout['hookHandlers'].set('run_start', [
|
|
97
|
+
{ pluginId: mockPluginId, handler: slowHandler },
|
|
98
|
+
])
|
|
99
|
+
|
|
100
|
+
const results = await managerWithShortTimeout.executeHooks('run_start', {
|
|
101
|
+
runId: mockRunId,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
expect(results).toHaveLength(1)
|
|
105
|
+
expect(results[0]?.action).toBe('error')
|
|
106
|
+
if (results[0]?.action === 'error') {
|
|
107
|
+
expect(results[0].message).toContain('timeout')
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('Hook ordering semantics', () => {
|
|
112
|
+
it('should execute pre_* hooks in registration order (first registered first)', async () => {
|
|
113
|
+
const executionOrder: string[] = []
|
|
114
|
+
|
|
115
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
116
|
+
executionOrder.push('hook1')
|
|
117
|
+
return { action: 'continue' }
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
121
|
+
executionOrder.push('hook2')
|
|
122
|
+
return { action: 'continue' }
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const handler3 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
126
|
+
executionOrder.push('hook3')
|
|
127
|
+
return { action: 'continue' }
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
manager['hookHandlers'].set('pre_tool_use', [
|
|
131
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
132
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
133
|
+
{ pluginId: 'plugin_3' as PluginId, handler: handler3 },
|
|
134
|
+
])
|
|
135
|
+
|
|
136
|
+
await manager.executeHooks('pre_tool_use', { runId: mockRunId })
|
|
137
|
+
|
|
138
|
+
expect(executionOrder).toEqual(['hook1', 'hook2', 'hook3'])
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should execute post_* hooks in reverse registration order (last registered first)', async () => {
|
|
142
|
+
const executionOrder: string[] = []
|
|
143
|
+
|
|
144
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
145
|
+
executionOrder.push('hook1')
|
|
146
|
+
return { action: 'continue' }
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
150
|
+
executionOrder.push('hook2')
|
|
151
|
+
return { action: 'continue' }
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const handler3 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
155
|
+
executionOrder.push('hook3')
|
|
156
|
+
return { action: 'continue' }
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
manager['hookHandlers'].set('post_tool_use', [
|
|
160
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
161
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
162
|
+
{ pluginId: 'plugin_3' as PluginId, handler: handler3 },
|
|
163
|
+
])
|
|
164
|
+
|
|
165
|
+
await manager.executeHooks('post_tool_use', { runId: mockRunId })
|
|
166
|
+
|
|
167
|
+
// Reverse order: hook3 -> hook2 -> hook1
|
|
168
|
+
expect(executionOrder).toEqual(['hook3', 'hook2', 'hook1'])
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should execute non-pre/post hooks in registration order', async () => {
|
|
172
|
+
const executionOrder: string[] = []
|
|
173
|
+
|
|
174
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
175
|
+
executionOrder.push('hook1')
|
|
176
|
+
return { action: 'continue' }
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
180
|
+
executionOrder.push('hook2')
|
|
181
|
+
return { action: 'continue' }
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
manager['hookHandlers'].set('run_start', [
|
|
185
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
186
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
187
|
+
])
|
|
188
|
+
|
|
189
|
+
await manager.executeHooks('run_start', { runId: mockRunId })
|
|
190
|
+
|
|
191
|
+
expect(executionOrder).toEqual(['hook1', 'hook2'])
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
describe('Flow control: action priority', () => {
|
|
196
|
+
it('should short-circuit on error action', async () => {
|
|
197
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
198
|
+
return { action: 'error', message: 'Hook failed' }
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
202
|
+
return { action: 'continue' }
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
manager['hookHandlers'].set('run_start', [
|
|
206
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
207
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
const results = await manager.executeHooks('run_start', { runId: mockRunId })
|
|
211
|
+
|
|
212
|
+
expect(results).toHaveLength(1)
|
|
213
|
+
expect(results[0]?.action).toBe('error')
|
|
214
|
+
expect(handler2).not.toHaveBeenCalled()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('should short-circuit on skip action', async () => {
|
|
218
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
219
|
+
return { action: 'skip', reason: 'Condition not met' }
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
223
|
+
return { action: 'continue' }
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
manager['hookHandlers'].set('pre_tool_use', [
|
|
227
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
228
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
229
|
+
])
|
|
230
|
+
|
|
231
|
+
const results = await manager.executeHooks('pre_tool_use', { runId: mockRunId })
|
|
232
|
+
|
|
233
|
+
expect(results).toHaveLength(1)
|
|
234
|
+
expect(results[0]?.action).toBe('skip')
|
|
235
|
+
expect(handler2).not.toHaveBeenCalled()
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('should short-circuit and return resume action', async () => {
|
|
239
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
240
|
+
return { action: 'resume', input: 'new_input_value' }
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
244
|
+
return { action: 'continue' }
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
manager['hookHandlers'].set('pre_llm_call', [
|
|
248
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
249
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
250
|
+
])
|
|
251
|
+
|
|
252
|
+
const results = await manager.executeHooks('pre_llm_call', { runId: mockRunId })
|
|
253
|
+
|
|
254
|
+
expect(results).toHaveLength(1)
|
|
255
|
+
expect(results[0]?.action).toBe('resume')
|
|
256
|
+
if (results[0]?.action === 'resume') {
|
|
257
|
+
expect(results[0].input).toBe('new_input_value')
|
|
258
|
+
}
|
|
259
|
+
expect(handler2).not.toHaveBeenCalled()
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('should short-circuit and return retry action', async () => {
|
|
263
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
264
|
+
return { action: 'retry' }
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
268
|
+
return { action: 'continue' }
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
// Use pre_* hook for forward execution order (plugin_1 runs first and short-circuits).
|
|
272
|
+
// post_* hooks run in reverse order for cleanup semantics.
|
|
273
|
+
manager['hookHandlers'].set('pre_llm_call', [
|
|
274
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
275
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
276
|
+
])
|
|
277
|
+
|
|
278
|
+
const results = await manager.executeHooks('pre_llm_call', { runId: mockRunId })
|
|
279
|
+
|
|
280
|
+
expect(results).toHaveLength(1)
|
|
281
|
+
expect(results[0]?.action).toBe('retry')
|
|
282
|
+
expect(handler2).not.toHaveBeenCalled()
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('should continue executing on modify action', async () => {
|
|
286
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
287
|
+
return { action: 'modify', input: { updated: true } }
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
291
|
+
return { action: 'continue' }
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
manager['hookHandlers'].set('pre_tool_use', [
|
|
295
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
296
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
297
|
+
])
|
|
298
|
+
|
|
299
|
+
const results = await manager.executeHooks('pre_tool_use', { runId: mockRunId })
|
|
300
|
+
|
|
301
|
+
expect(results).toHaveLength(2)
|
|
302
|
+
expect(results[0]?.action).toBe('modify')
|
|
303
|
+
expect(results[1]?.action).toBe('continue')
|
|
304
|
+
expect(handler2).toHaveBeenCalled()
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
it('should continue executing on continue action', async () => {
|
|
308
|
+
const handler1 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
309
|
+
return { action: 'continue' }
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const handler2 = vi.fn(async (): Promise<PluginHookResult> => {
|
|
313
|
+
return { action: 'continue' }
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
manager['hookHandlers'].set('iteration_start', [
|
|
317
|
+
{ pluginId: 'plugin_1' as PluginId, handler: handler1 },
|
|
318
|
+
{ pluginId: 'plugin_2' as PluginId, handler: handler2 },
|
|
319
|
+
])
|
|
320
|
+
|
|
321
|
+
const results = await manager.executeHooks('iteration_start', { runId: mockRunId })
|
|
322
|
+
|
|
323
|
+
expect(results).toHaveLength(2)
|
|
324
|
+
expect(handler1).toHaveBeenCalled()
|
|
325
|
+
expect(handler2).toHaveBeenCalled()
|
|
326
|
+
})
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
describe('Hook context', () => {
|
|
330
|
+
it('should pass correct context to hook handler', async () => {
|
|
331
|
+
let capturedContext: PluginHookContext | null = null
|
|
332
|
+
|
|
333
|
+
const handler = vi.fn(async (ctx: PluginHookContext): Promise<PluginHookResult> => {
|
|
334
|
+
capturedContext = ctx
|
|
335
|
+
return { action: 'continue' }
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
manager['hookHandlers'].set('pre_tool_use', [{ pluginId: mockPluginId, handler }])
|
|
339
|
+
|
|
340
|
+
const contextData = {
|
|
341
|
+
runId: mockRunId,
|
|
342
|
+
toolName: 'test_tool',
|
|
343
|
+
toolInput: { key: 'value' },
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
await manager.executeHooks('pre_tool_use', contextData)
|
|
347
|
+
|
|
348
|
+
expect(capturedContext).not.toBeNull()
|
|
349
|
+
const ctx = capturedContext as unknown as PluginHookContext
|
|
350
|
+
expect(ctx.runId).toBe(mockRunId)
|
|
351
|
+
expect(ctx.pluginId).toBe(mockPluginId)
|
|
352
|
+
expect(ctx.event).toBe('pre_tool_use')
|
|
353
|
+
expect(ctx.toolName).toBe('test_tool')
|
|
354
|
+
expect(ctx.toolInput).toEqual({ key: 'value' })
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('should include iteration number in context when provided', async () => {
|
|
358
|
+
let capturedContext: PluginHookContext | null = null
|
|
359
|
+
|
|
360
|
+
const handler = vi.fn(async (ctx: PluginHookContext): Promise<PluginHookResult> => {
|
|
361
|
+
capturedContext = ctx
|
|
362
|
+
return { action: 'continue' }
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
manager['hookHandlers'].set('iteration_end', [{ pluginId: mockPluginId, handler }])
|
|
366
|
+
|
|
367
|
+
await manager.executeHooks('iteration_end', {
|
|
368
|
+
runId: mockRunId,
|
|
369
|
+
iteration: 5,
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
const ctx = capturedContext as unknown as PluginHookContext
|
|
373
|
+
expect(ctx.iteration).toBe(5)
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
describe('Hook execution logging', () => {
|
|
378
|
+
it('should emit hook_executed event with correct metadata', async () => {
|
|
379
|
+
const events: any[] = []
|
|
380
|
+
manager.on((evt) => events.push(evt))
|
|
381
|
+
|
|
382
|
+
const handler = vi.fn(async (): Promise<PluginHookResult> => {
|
|
383
|
+
return { action: 'continue' }
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
manager['hookHandlers'].set('run_start', [{ pluginId: mockPluginId, handler }])
|
|
387
|
+
|
|
388
|
+
await manager.executeHooks('run_start', { runId: mockRunId })
|
|
389
|
+
|
|
390
|
+
const hookExecutedEvents = events.filter((evt) => evt.type === 'plugin_hook_executed')
|
|
391
|
+
expect(hookExecutedEvents).toHaveLength(1)
|
|
392
|
+
|
|
393
|
+
const event = hookExecutedEvents[0]
|
|
394
|
+
expect(event?.pluginId).toBe(mockPluginId)
|
|
395
|
+
expect(event?.hookEvent).toBe('run_start')
|
|
396
|
+
expect(typeof event?.durationMs).toBe('number')
|
|
397
|
+
expect(event?.durationMs).toBeGreaterThanOrEqual(0)
|
|
398
|
+
})
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
describe('Exception handling', () => {
|
|
402
|
+
it('should catch thrown exceptions and return error action', async () => {
|
|
403
|
+
const handler = vi.fn(async (): Promise<PluginHookResult> => {
|
|
404
|
+
throw new Error('Handler crashed')
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
manager['hookHandlers'].set('run_start', [{ pluginId: mockPluginId, handler }])
|
|
408
|
+
|
|
409
|
+
const results = await manager.executeHooks('run_start', { runId: mockRunId })
|
|
410
|
+
|
|
411
|
+
expect(results).toHaveLength(1)
|
|
412
|
+
expect(results[0]?.action).toBe('error')
|
|
413
|
+
if (results[0]?.action === 'error') {
|
|
414
|
+
expect(results[0].message).toContain('Handler crashed')
|
|
415
|
+
}
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
it('should not throw when handler throws', async () => {
|
|
419
|
+
const handler = vi.fn(async (): Promise<PluginHookResult> => {
|
|
420
|
+
throw new Error('Handler failed')
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
manager['hookHandlers'].set('run_start', [{ pluginId: mockPluginId, handler }])
|
|
424
|
+
|
|
425
|
+
const executePromise = manager.executeHooks('run_start', { runId: mockRunId })
|
|
426
|
+
await expect(executePromise).resolves.not.toThrow()
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
})
|
|
430
|
+
})
|
package/src/plugin/lifecycle.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { join } from 'node:path'
|
|
|
2
2
|
import { pathToFileURL } from 'node:url'
|
|
3
3
|
import { HOOK_TIMEOUT_MS, PLUGIN_NAMESPACE_SEPARATOR } from '../constants/plugin/index.js'
|
|
4
4
|
import type { PluginRegistry } from '../registry/plugin/index.js'
|
|
5
|
-
import type { ToolRegistry } from '../registry/tool/execute.js'
|
|
6
5
|
import type { PluginId } from '../types/ids/index.js'
|
|
7
6
|
import type {
|
|
8
7
|
PluginDefinition,
|
|
@@ -14,7 +13,7 @@ import type {
|
|
|
14
13
|
PluginLifecycleEvent,
|
|
15
14
|
PluginScope,
|
|
16
15
|
} from '../types/plugin/index.js'
|
|
17
|
-
import type { ToolDefinition } from '../types/tool/index.js'
|
|
16
|
+
import type { ToolDefinition, ToolRegistryContract } from '../types/tool/index.js'
|
|
18
17
|
import { toErrorMessage } from '../utils/error.js'
|
|
19
18
|
import { generatePluginId } from '../utils/id.js'
|
|
20
19
|
import type { Logger } from '../utils/logger.js'
|
|
@@ -22,14 +21,14 @@ import { loadPluginManifest } from './loader.js'
|
|
|
22
21
|
|
|
23
22
|
export interface PluginLifecycleManagerConfig {
|
|
24
23
|
pluginRegistry: PluginRegistry
|
|
25
|
-
toolRegistry:
|
|
24
|
+
toolRegistry: ToolRegistryContract
|
|
26
25
|
log: Logger
|
|
27
26
|
hookTimeoutMs?: number
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
export class PluginLifecycleManager {
|
|
31
30
|
private pluginRegistry: PluginRegistry
|
|
32
|
-
private toolRegistry:
|
|
31
|
+
private toolRegistry: ToolRegistryContract
|
|
33
32
|
private listeners: PluginEventListener[] = []
|
|
34
33
|
private hookHandlers: Map<
|
|
35
34
|
PluginHookEvent,
|
|
@@ -257,7 +256,25 @@ export class PluginLifecycleManager {
|
|
|
257
256
|
|
|
258
257
|
const results: PluginHookResult[] = []
|
|
259
258
|
|
|
260
|
-
|
|
259
|
+
// Determine execution order: post_* hooks run backward (for cleanup semantics)
|
|
260
|
+
const isPost = event.startsWith('post_')
|
|
261
|
+
|
|
262
|
+
// For post_* hooks, we need to process in reverse order (last registered runs first)
|
|
263
|
+
const indicesToProcess: number[] = []
|
|
264
|
+
if (isPost) {
|
|
265
|
+
for (let i = handlers.length - 1; i >= 0; i--) {
|
|
266
|
+
indicesToProcess.push(i)
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
for (let i = 0; i < handlers.length; i++) {
|
|
270
|
+
indicesToProcess.push(i)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const idx of indicesToProcess) {
|
|
275
|
+
const hookEntry = handlers[idx]
|
|
276
|
+
if (!hookEntry) continue
|
|
277
|
+
const { pluginId, handler: handlerFn } = hookEntry
|
|
261
278
|
const hookContext: PluginHookContext = {
|
|
262
279
|
...context,
|
|
263
280
|
pluginId,
|
|
@@ -269,7 +286,7 @@ export class PluginLifecycleManager {
|
|
|
269
286
|
|
|
270
287
|
try {
|
|
271
288
|
result = await Promise.race([
|
|
272
|
-
|
|
289
|
+
handlerFn(hookContext),
|
|
273
290
|
new Promise<PluginHookResult>((_, reject) =>
|
|
274
291
|
setTimeout(() => reject(new Error('Hook timeout')), this.hookTimeoutMs),
|
|
275
292
|
),
|
|
@@ -289,6 +306,15 @@ export class PluginLifecycleManager {
|
|
|
289
306
|
})
|
|
290
307
|
|
|
291
308
|
results.push(result)
|
|
309
|
+
|
|
310
|
+
// Handle flow control: check priority order: error > skip > retry > resume > modify > continue
|
|
311
|
+
// Short-circuit on error or skip; return immediately on resume or retry
|
|
312
|
+
if (result.action === 'error' || result.action === 'skip') {
|
|
313
|
+
break
|
|
314
|
+
}
|
|
315
|
+
if (result.action === 'resume' || result.action === 'retry') {
|
|
316
|
+
break
|
|
317
|
+
}
|
|
292
318
|
}
|
|
293
319
|
|
|
294
320
|
return results
|