@namzu/sdk 0.1.5-rc.1-fix → 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/CHANGELOG.md +25 -0
- package/README.md +279 -129
- package/dist/bridge/tools/connector/adapter.d.ts +2 -2
- package/dist/bridge/tools/connector/adapter.d.ts.map +1 -1
- package/dist/bridge/tools/connector/adapter.js +3 -1
- package/dist/bridge/tools/connector/adapter.js.map +1 -1
- package/dist/connector/BaseConnector.d.ts +2 -1
- package/dist/connector/BaseConnector.d.ts.map +1 -1
- package/dist/connector/BaseConnector.js.map +1 -1
- package/dist/connector/builtins/http.d.ts +1 -1
- package/dist/connector/builtins/http.d.ts.map +1 -1
- package/dist/connector/builtins/http.js +1 -1
- package/dist/connector/builtins/http.js.map +1 -1
- package/dist/connector/builtins/webhook.d.ts +1 -1
- package/dist/connector/builtins/webhook.d.ts.map +1 -1
- package/dist/connector/builtins/webhook.js +1 -1
- package/dist/connector/builtins/webhook.js.map +1 -1
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +7 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/index.d.ts +5 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -23
- package/dist/index.js.map +1 -1
- package/dist/manager/connector/environment.d.ts +4 -4
- package/dist/manager/connector/environment.d.ts.map +1 -1
- package/dist/manager/connector/environment.js.map +1 -1
- package/dist/manager/connector/lifecycle.d.ts +2 -2
- package/dist/manager/connector/lifecycle.d.ts.map +1 -1
- package/dist/manager/connector/lifecycle.js.map +1 -1
- package/dist/manager/connector/tenant.d.ts +3 -3
- package/dist/manager/connector/tenant.d.ts.map +1 -1
- package/dist/manager/connector/tenant.js.map +1 -1
- package/dist/manager/index.d.ts +2 -1
- package/dist/manager/index.d.ts.map +1 -1
- package/dist/manager/index.js +2 -1
- package/dist/manager/index.js.map +1 -1
- package/dist/manager/run/emergency.d.ts.map +1 -1
- package/dist/manager/run/emergency.js +44 -12
- package/dist/manager/run/emergency.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +0 -2
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +0 -1
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/plugin/__tests__/enable-contributions.test.d.ts +2 -0
- package/dist/plugin/__tests__/enable-contributions.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/enable-contributions.test.js +265 -0
- package/dist/plugin/__tests__/enable-contributions.test.js.map +1 -0
- package/dist/plugin/__tests__/lifecycle.test.js +30 -0
- package/dist/plugin/__tests__/lifecycle.test.js.map +1 -1
- package/dist/plugin/lifecycle.d.ts +4 -1
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +157 -49
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/rag/vector-store.d.ts +2 -2
- package/dist/rag/vector-store.d.ts.map +1 -1
- package/dist/rag/vector-store.js.map +1 -1
- package/dist/registry/ManagedRegistry.d.ts +6 -0
- package/dist/registry/ManagedRegistry.d.ts.map +1 -1
- package/dist/registry/ManagedRegistry.js +9 -3
- package/dist/registry/ManagedRegistry.js.map +1 -1
- package/dist/registry/agent/definitions.d.ts +2 -7
- package/dist/registry/agent/definitions.d.ts.map +1 -1
- package/dist/registry/agent/definitions.js +3 -41
- package/dist/registry/agent/definitions.js.map +1 -1
- package/dist/registry/connector/definitions.d.ts +2 -7
- package/dist/registry/connector/definitions.d.ts.map +1 -1
- package/dist/registry/connector/definitions.js +3 -41
- package/dist/registry/connector/definitions.js.map +1 -1
- package/dist/registry/connector/scoped.d.ts +5 -4
- package/dist/registry/connector/scoped.d.ts.map +1 -1
- package/dist/registry/connector/scoped.js.map +1 -1
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +2 -4
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +4 -21
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/index.d.ts +4 -4
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +3 -3
- package/dist/run/index.js.map +1 -1
- package/dist/run/reporter.d.ts +0 -2
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +0 -1
- package/dist/run/reporter.js.map +1 -1
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +236 -0
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js.map +1 -0
- package/dist/runtime/query/__tests__/plugin-hooks.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/plugin-hooks.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/plugin-hooks.test.js +21 -0
- package/dist/runtime/query/__tests__/plugin-hooks.test.js.map +1 -0
- package/dist/runtime/query/executor.d.ts +6 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +110 -6
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +8 -6
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +13 -16
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/plugin-hooks.d.ts +11 -0
- package/dist/runtime/query/plugin-hooks.d.ts.map +1 -0
- package/dist/runtime/query/plugin-hooks.js +28 -0
- package/dist/runtime/query/plugin-hooks.js.map +1 -0
- package/dist/runtime/query/tooling.d.ts +2 -0
- 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/index.d.ts +5 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +4 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/run/disk.d.ts +0 -2
- package/dist/store/run/disk.d.ts.map +1 -1
- package/dist/store/run/disk.js +0 -1
- package/dist/store/run/disk.js.map +1 -1
- package/dist/store/task/__tests__/disk-concurrency.test.d.ts +2 -0
- package/dist/store/task/__tests__/disk-concurrency.test.d.ts.map +1 -0
- package/dist/store/task/__tests__/disk-concurrency.test.js +91 -0
- package/dist/store/task/__tests__/disk-concurrency.test.js.map +1 -0
- package/dist/store/task/disk.d.ts +6 -0
- package/dist/store/task/disk.d.ts.map +1 -1
- package/dist/store/task/disk.js +150 -36
- package/dist/store/task/disk.js.map +1 -1
- package/dist/types/connector/core.d.ts +2 -2
- package/dist/types/connector/core.d.ts.map +1 -1
- package/dist/types/connector/definition.d.ts +7 -7
- package/dist/types/connector/definition.d.ts.map +1 -1
- package/dist/types/connector/mcp.d.ts +4 -4
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/connector/scope.d.ts +3 -2
- package/dist/types/connector/scope.d.ts.map +1 -1
- package/dist/types/connector/scope.js.map +1 -1
- package/dist/types/connector/tenant.d.ts +4 -4
- package/dist/types/connector/tenant.d.ts.map +1 -1
- package/dist/types/plugin/index.d.ts +4 -21
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +1 -10
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/rag/knowledge-base.d.ts +2 -2
- package/dist/types/rag/knowledge-base.d.ts.map +1 -1
- package/dist/types/rag/scope.d.ts +2 -1
- package/dist/types/rag/scope.d.ts.map +1 -1
- package/dist/types/rag/storage.d.ts +3 -3
- package/dist/types/rag/storage.d.ts.map +1 -1
- package/dist/types/rag/vector.d.ts +3 -3
- package/dist/types/rag/vector.d.ts.map +1 -1
- package/dist/types/run/config.d.ts +0 -6
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/vault/InMemoryCredentialVault.d.ts +3 -3
- package/dist/vault/InMemoryCredentialVault.d.ts.map +1 -1
- package/dist/vault/InMemoryCredentialVault.js.map +1 -1
- package/package.json +1 -1
- package/src/bridge/tools/connector/adapter.ts +5 -3
- package/src/connector/BaseConnector.ts +2 -1
- package/src/connector/builtins/http.ts +1 -1
- package/src/connector/builtins/webhook.ts +1 -1
- package/src/contracts/api.ts +3 -0
- package/src/contracts/index.ts +10 -0
- package/src/index.ts +46 -41
- package/src/manager/connector/environment.ts +5 -5
- package/src/manager/connector/lifecycle.ts +2 -2
- package/src/manager/connector/tenant.ts +8 -3
- package/src/manager/index.ts +2 -1
- package/src/manager/run/emergency.ts +45 -16
- package/src/manager/run/persistence.ts +0 -4
- package/src/plugin/__tests__/enable-contributions.test.ts +295 -0
- package/src/plugin/__tests__/lifecycle.test.ts +44 -0
- package/src/plugin/lifecycle.ts +186 -57
- package/src/rag/vector-store.ts +2 -2
- package/src/registry/ManagedRegistry.ts +14 -3
- package/src/registry/agent/definitions.ts +3 -53
- package/src/registry/connector/definitions.ts +3 -53
- package/src/registry/connector/scoped.ts +7 -6
- package/src/registry/index.ts +1 -0
- package/src/registry/tool/execute.ts +4 -22
- package/src/run/index.ts +4 -4
- package/src/run/reporter.ts +0 -4
- package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +305 -0
- package/src/runtime/query/__tests__/plugin-hooks.test.ts +28 -0
- package/src/runtime/query/executor.ts +148 -7
- package/src/runtime/query/index.ts +16 -6
- package/src/runtime/query/iteration/index.ts +29 -16
- package/src/runtime/query/plugin-hooks.ts +34 -0
- package/src/runtime/query/tooling.ts +3 -0
- package/src/store/index.ts +6 -1
- package/src/store/run/disk.ts +0 -4
- package/src/store/task/__tests__/disk-concurrency.test.ts +118 -0
- package/src/store/task/disk.ts +150 -37
- package/src/types/connector/core.ts +2 -2
- package/src/types/connector/definition.ts +7 -7
- package/src/types/connector/mcp.ts +4 -4
- package/src/types/connector/scope.ts +3 -2
- package/src/types/connector/tenant.ts +4 -4
- package/src/types/plugin/index.ts +0 -14
- package/src/types/rag/knowledge-base.ts +2 -2
- package/src/types/rag/scope.ts +3 -1
- package/src/types/rag/storage.ts +3 -3
- package/src/types/rag/vector.ts +3 -3
- package/src/types/run/config.ts +0 -9
- package/src/vault/InMemoryCredentialVault.ts +3 -3
- package/dist/manager/agent/index.d.ts +0 -2
- package/dist/manager/agent/index.d.ts.map +0 -1
- package/dist/manager/agent/index.js +0 -2
- package/dist/manager/agent/index.js.map +0 -1
- package/dist/registry/agent/index.d.ts +0 -2
- package/dist/registry/agent/index.d.ts.map +0 -1
- package/dist/registry/agent/index.js +0 -2
- package/dist/registry/agent/index.js.map +0 -1
- package/dist/router/index.d.ts +0 -2
- package/dist/router/index.d.ts.map +0 -1
- package/dist/router/index.js +0 -2
- package/dist/router/index.js.map +0 -1
- package/src/manager/agent/index.ts +0 -1
- package/src/registry/agent/index.ts +0 -1
- package/src/router/index.ts +0 -1
package/src/rag/vector-store.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChunkId, DocumentId, KnowledgeBaseId } from '../types/ids/index.js'
|
|
1
|
+
import type { ChunkId, DocumentId, KnowledgeBaseId, TenantId } from '../types/ids/index.js'
|
|
2
2
|
import type {
|
|
3
3
|
Chunk,
|
|
4
4
|
VectorSearchResult,
|
|
@@ -57,7 +57,7 @@ export class InMemoryVectorStore implements VectorStore {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
async deleteByKnowledgeBase(knowledgeBaseId: KnowledgeBaseId, tenantId:
|
|
60
|
+
async deleteByKnowledgeBase(knowledgeBaseId: KnowledgeBaseId, tenantId: TenantId): Promise<void> {
|
|
61
61
|
for (const [id, chunk] of this.chunks) {
|
|
62
62
|
if (chunk.knowledgeBaseId === knowledgeBaseId && chunk.tenantId === tenantId) {
|
|
63
63
|
this.chunks.delete(id)
|
|
@@ -4,16 +4,23 @@ import { Registry } from './Registry.js'
|
|
|
4
4
|
export interface ManagedRegistryConfig<TDefinition> {
|
|
5
5
|
componentName: string
|
|
6
6
|
idField?: keyof TDefinition & string
|
|
7
|
+
/**
|
|
8
|
+
* Extract id from a full item. Takes precedence over `idField` when provided.
|
|
9
|
+
* Required when the id field is nested (e.g. `def.info.id`).
|
|
10
|
+
*/
|
|
11
|
+
computeId?: (item: TDefinition) => string
|
|
7
12
|
logger?: Logger
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
export class ManagedRegistry<TDefinition> extends Registry<TDefinition> {
|
|
11
16
|
protected log: Logger
|
|
12
17
|
private idField?: keyof TDefinition & string
|
|
18
|
+
private computeId?: (item: TDefinition) => string
|
|
13
19
|
|
|
14
20
|
constructor(config: ManagedRegistryConfig<TDefinition>) {
|
|
15
21
|
super()
|
|
16
22
|
this.idField = config.idField
|
|
23
|
+
this.computeId = config.computeId
|
|
17
24
|
this.log = (config.logger ?? getRootLogger()).child({
|
|
18
25
|
component: config.componentName,
|
|
19
26
|
})
|
|
@@ -45,10 +52,14 @@ export class ManagedRegistry<TDefinition> extends Registry<TDefinition> {
|
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
const item = idOrItem
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
const id = this.computeId
|
|
56
|
+
? this.computeId(item)
|
|
57
|
+
: this.idField
|
|
58
|
+
? String(item[this.idField])
|
|
59
|
+
: undefined
|
|
60
|
+
if (id === undefined) {
|
|
61
|
+
throw new Error('register(item) requires idField or computeId to be configured')
|
|
50
62
|
}
|
|
51
|
-
const id = String(item[this.idField])
|
|
52
63
|
|
|
53
64
|
if (this.has(id)) {
|
|
54
65
|
this.log.warn(`"${id}" already registered, overwriting.`)
|
|
@@ -1,61 +1,11 @@
|
|
|
1
1
|
import type { AgentType, BaseAgentConfig, BaseAgentResult } from '../../types/agent/base.js'
|
|
2
2
|
import type { Agent } from '../../types/agent/core.js'
|
|
3
3
|
import type { AgentDefinition } from '../../types/agent/factory.js'
|
|
4
|
-
import {
|
|
5
|
-
import { Registry } from '../Registry.js'
|
|
6
|
-
|
|
7
|
-
export class AgentRegistry extends Registry<AgentDefinition> {
|
|
8
|
-
private log: Logger
|
|
4
|
+
import { ManagedRegistry } from '../ManagedRegistry.js'
|
|
9
5
|
|
|
6
|
+
export class AgentRegistry extends ManagedRegistry<AgentDefinition> {
|
|
10
7
|
constructor() {
|
|
11
|
-
super()
|
|
12
|
-
this.log = getRootLogger().child({ component: 'AgentRegistry' })
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
override register(id: string, definition: AgentDefinition): void
|
|
16
|
-
override register(definition: AgentDefinition): void
|
|
17
|
-
override register(definitions: AgentDefinition[]): void
|
|
18
|
-
override register(
|
|
19
|
-
idOrDef: string | AgentDefinition | AgentDefinition[],
|
|
20
|
-
maybeDef?: AgentDefinition,
|
|
21
|
-
): void {
|
|
22
|
-
if (Array.isArray(idOrDef)) {
|
|
23
|
-
for (const def of idOrDef) {
|
|
24
|
-
this.register(def)
|
|
25
|
-
}
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (typeof idOrDef === 'string') {
|
|
30
|
-
if (!maybeDef) {
|
|
31
|
-
throw new Error('register(id, definition) requires a definition argument')
|
|
32
|
-
}
|
|
33
|
-
const id = idOrDef
|
|
34
|
-
const def = maybeDef
|
|
35
|
-
if (this.has(id)) {
|
|
36
|
-
this.log.warn(`Agent "${id}" already registered, overwriting.`)
|
|
37
|
-
}
|
|
38
|
-
super.register(id, def)
|
|
39
|
-
this.log.info(`Agent registered: ${id}`)
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const def = idOrDef
|
|
44
|
-
const id = def.info.id
|
|
45
|
-
|
|
46
|
-
if (this.has(id)) {
|
|
47
|
-
this.log.warn(`Agent "${id}" already registered, overwriting.`)
|
|
48
|
-
}
|
|
49
|
-
super.register(id, def)
|
|
50
|
-
this.log.info(`Agent registered: ${id}`)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
getOrThrow(id: string): AgentDefinition {
|
|
54
|
-
const def = this.get(id)
|
|
55
|
-
if (!def) {
|
|
56
|
-
throw new Error(`Agent not found: "${id}". Available: ${this.listIds().join(', ')}`)
|
|
57
|
-
}
|
|
58
|
-
return def
|
|
8
|
+
super({ componentName: 'AgentRegistry', computeId: (def) => def.info.id })
|
|
59
9
|
}
|
|
60
10
|
|
|
61
11
|
resolve(agentId: string): Agent<BaseAgentConfig, BaseAgentResult> {
|
|
@@ -1,59 +1,9 @@
|
|
|
1
1
|
import type { ConnectorDefinition } from '../../types/connector/index.js'
|
|
2
|
-
import {
|
|
3
|
-
import { Registry } from '../Registry.js'
|
|
4
|
-
|
|
5
|
-
export class ConnectorRegistry extends Registry<ConnectorDefinition> {
|
|
6
|
-
private log: Logger
|
|
2
|
+
import { ManagedRegistry } from '../ManagedRegistry.js'
|
|
7
3
|
|
|
4
|
+
export class ConnectorRegistry extends ManagedRegistry<ConnectorDefinition> {
|
|
8
5
|
constructor() {
|
|
9
|
-
super()
|
|
10
|
-
this.log = getRootLogger().child({ component: 'ConnectorRegistry' })
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
override register(id: string, definition: ConnectorDefinition): void
|
|
14
|
-
override register(definition: ConnectorDefinition): void
|
|
15
|
-
override register(definitions: ConnectorDefinition[]): void
|
|
16
|
-
override register(
|
|
17
|
-
idOrDef: string | ConnectorDefinition | ConnectorDefinition[],
|
|
18
|
-
maybeDef?: ConnectorDefinition,
|
|
19
|
-
): void {
|
|
20
|
-
if (Array.isArray(idOrDef)) {
|
|
21
|
-
for (const def of idOrDef) {
|
|
22
|
-
this.register(def)
|
|
23
|
-
}
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (typeof idOrDef === 'string') {
|
|
28
|
-
if (!maybeDef) {
|
|
29
|
-
throw new Error('register(id, definition) requires a definition argument')
|
|
30
|
-
}
|
|
31
|
-
const id = idOrDef
|
|
32
|
-
const def = maybeDef
|
|
33
|
-
if (this.has(id)) {
|
|
34
|
-
this.log.warn(`Connector "${id}" is already registered, overwriting.`)
|
|
35
|
-
}
|
|
36
|
-
super.register(id, def)
|
|
37
|
-
this.log.info(`Connector registered: ${id}`)
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const def = idOrDef
|
|
42
|
-
const id = def.id
|
|
43
|
-
|
|
44
|
-
if (this.has(id)) {
|
|
45
|
-
this.log.warn(`Connector "${id}" is already registered, overwriting.`)
|
|
46
|
-
}
|
|
47
|
-
super.register(id, def)
|
|
48
|
-
this.log.info(`Connector registered: ${id}`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
getOrThrow(id: string): ConnectorDefinition {
|
|
52
|
-
const def = this.get(id)
|
|
53
|
-
if (!def) {
|
|
54
|
-
throw new Error(`Connector not found: "${id}". Available: ${this.listIds().join(', ')}`)
|
|
55
|
-
}
|
|
56
|
-
return def
|
|
6
|
+
super({ componentName: 'ConnectorRegistry', idField: 'id' })
|
|
57
7
|
}
|
|
58
8
|
|
|
59
9
|
listByType(connectionType: ConnectorDefinition['connectionType']): ConnectorDefinition[] {
|
|
@@ -8,9 +8,10 @@ import type {
|
|
|
8
8
|
ScopedConnectorConfig,
|
|
9
9
|
} from '../../types/connector/index.js'
|
|
10
10
|
import { CONNECTOR_SCOPE_ORDER } from '../../types/connector/index.js'
|
|
11
|
+
import type { ConnectorId } from '../../types/ids/index.js'
|
|
11
12
|
import { type Logger, getRootLogger } from '../../utils/logger.js'
|
|
12
13
|
|
|
13
|
-
function scopeKey(scope: ConnectorScope, scopeId: string, connectorId:
|
|
14
|
+
function scopeKey(scope: ConnectorScope, scopeId: string, connectorId: ConnectorId): string {
|
|
14
15
|
return `${scope}:${scopeId}:${connectorId}`
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -28,7 +29,7 @@ export class ScopedConnectorRegistry {
|
|
|
28
29
|
this.log.info(`Scoped config set: ${key}`)
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
remove(scope: ScopeRef, connectorId:
|
|
32
|
+
remove(scope: ScopeRef, connectorId: ConnectorId): boolean {
|
|
32
33
|
const key = scopeKey(scope.scope, scope.scopeId, connectorId)
|
|
33
34
|
const removed = this.configs.delete(key)
|
|
34
35
|
if (removed) {
|
|
@@ -37,11 +38,11 @@ export class ScopedConnectorRegistry {
|
|
|
37
38
|
return removed
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
getAt(scope: ScopeRef, connectorId:
|
|
41
|
+
getAt(scope: ScopeRef, connectorId: ConnectorId): ScopedConnectorConfig | undefined {
|
|
41
42
|
return this.configs.get(scopeKey(scope.scope, scope.scopeId, connectorId))
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
resolve(connectorId:
|
|
45
|
+
resolve(connectorId: ConnectorId, chain: ScopeChain): ResolvedConnectorConfig | undefined {
|
|
45
46
|
const layers: ScopedConnectorConfig[] = []
|
|
46
47
|
|
|
47
48
|
for (const scope of CONNECTOR_SCOPE_ORDER) {
|
|
@@ -59,7 +60,7 @@ export class ScopedConnectorRegistry {
|
|
|
59
60
|
return this.mergeLayers(connectorId, layers)
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
listForConnector(connectorId:
|
|
63
|
+
listForConnector(connectorId: ConnectorId): ScopedConnectorConfig[] {
|
|
63
64
|
const results: ScopedConnectorConfig[] = []
|
|
64
65
|
for (const config of this.configs.values()) {
|
|
65
66
|
if (config.connectorId === connectorId) {
|
|
@@ -81,7 +82,7 @@ export class ScopedConnectorRegistry {
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
private mergeLayers(
|
|
84
|
-
connectorId:
|
|
85
|
+
connectorId: ConnectorId,
|
|
85
86
|
layers: ScopedConnectorConfig[],
|
|
86
87
|
): ResolvedConnectorConfig {
|
|
87
88
|
let mergedOptions: Record<string, unknown> = {}
|
package/src/registry/index.ts
CHANGED
|
@@ -12,21 +12,16 @@ import type {
|
|
|
12
12
|
ToolTierConfig,
|
|
13
13
|
} from '../../types/tool/index.js'
|
|
14
14
|
import { toErrorMessage } from '../../utils/error.js'
|
|
15
|
-
import {
|
|
16
|
-
import { Registry } from '../Registry.js'
|
|
15
|
+
import { ManagedRegistry } from '../ManagedRegistry.js'
|
|
17
16
|
|
|
18
17
|
export type { ToolExecutionResult }
|
|
19
18
|
|
|
20
|
-
export class ToolRegistry extends
|
|
21
|
-
private log: Logger
|
|
19
|
+
export class ToolRegistry extends ManagedRegistry<ToolDefinition> {
|
|
22
20
|
private availability: Map<string, ToolAvailability> = new Map()
|
|
23
21
|
private tierConfig?: ToolTierConfig
|
|
24
22
|
|
|
25
23
|
constructor(config?: ToolRegistryConfig) {
|
|
26
|
-
super()
|
|
27
|
-
this.log = (config?.logger ?? getRootLogger()).child({
|
|
28
|
-
component: 'ToolRegistry',
|
|
29
|
-
})
|
|
24
|
+
super({ componentName: 'ToolRegistry', idField: 'name', logger: config?.logger })
|
|
30
25
|
this.tierConfig = config?.tierConfig
|
|
31
26
|
}
|
|
32
27
|
|
|
@@ -54,10 +49,9 @@ export class ToolRegistry extends Registry<ToolDefinition> {
|
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
const tool = idOrToolOrTools
|
|
57
|
-
const id = tool.name
|
|
58
52
|
const state: ToolAvailability = typeof maybeTool === 'string' ? maybeTool : 'active'
|
|
59
53
|
|
|
60
|
-
this.registerOne(
|
|
54
|
+
this.registerOne(tool.name, tool, state)
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
private registerOne(id: string, tool: ToolDefinition, state: ToolAvailability): void {
|
|
@@ -69,12 +63,8 @@ export class ToolRegistry extends Registry<ToolDefinition> {
|
|
|
69
63
|
)
|
|
70
64
|
}
|
|
71
65
|
}
|
|
72
|
-
if (this.has(id)) {
|
|
73
|
-
this.log.warn(`Tool "${id}" is already registered, overwriting.`)
|
|
74
|
-
}
|
|
75
66
|
super.register(id, tool)
|
|
76
67
|
this.availability.set(id, state)
|
|
77
|
-
this.log.info(`Tool registered: ${id} (${state})`)
|
|
78
68
|
}
|
|
79
69
|
|
|
80
70
|
override unregister(id: string): boolean {
|
|
@@ -150,14 +140,6 @@ export class ToolRegistry extends Registry<ToolDefinition> {
|
|
|
150
140
|
return this.tierConfig.guidanceTemplate(this.tierConfig.tiers)
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
getOrThrow(name: string): ToolDefinition {
|
|
154
|
-
const tool = this.get(name)
|
|
155
|
-
if (!tool) {
|
|
156
|
-
throw new Error(`Tool not found: "${name}". Available tools: ${this.listIds().join(', ')}`)
|
|
157
|
-
}
|
|
158
|
-
return tool
|
|
159
|
-
}
|
|
160
|
-
|
|
161
143
|
listNames(): string[] {
|
|
162
144
|
return this.listIds()
|
|
163
145
|
}
|
package/src/run/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { RunPersistence
|
|
1
|
+
export { RunPersistence } from '../manager/run/persistence.js'
|
|
2
2
|
|
|
3
|
-
export { RunDiskStore
|
|
3
|
+
export { RunDiskStore } from '../store/run/disk.js'
|
|
4
4
|
|
|
5
|
-
export { createRunReporter
|
|
6
|
-
export type { RunReporter
|
|
5
|
+
export { createRunReporter } from './reporter.js'
|
|
6
|
+
export type { RunReporter } from './reporter.js'
|
|
7
7
|
|
|
8
8
|
export { checkLimitsDetailed, buildLimitConfig } from './LimitChecker.js'
|
|
9
9
|
export type { LimitCheckerState, LimitCheckResult } from './LimitChecker.js'
|
package/src/run/reporter.ts
CHANGED
|
@@ -16,8 +16,6 @@ export interface RunReporter {
|
|
|
16
16
|
summary(run: AgentRun): void
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export type SessionReporter = RunReporter
|
|
20
|
-
|
|
21
19
|
export function createRunReporter(parentLogger?: Logger): RunReporter {
|
|
22
20
|
const log = (parentLogger ?? getRootLogger()).child({
|
|
23
21
|
component: 'RunReporter',
|
|
@@ -223,5 +221,3 @@ export function createRunReporter(parentLogger?: Logger): RunReporter {
|
|
|
223
221
|
|
|
224
222
|
return { listener, summary }
|
|
225
223
|
}
|
|
226
|
-
|
|
227
|
-
export const createSessionReporter = createRunReporter
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import type { PluginLifecycleManager } from '../../../plugin/lifecycle.js'
|
|
3
|
+
import { ActivityStore } from '../../../store/activity/memory.js'
|
|
4
|
+
import type { RunId } from '../../../types/ids/index.js'
|
|
5
|
+
import type { PluginHookResult } from '../../../types/plugin/index.js'
|
|
6
|
+
import type { ChatCompletionResponse } from '../../../types/provider/index.js'
|
|
7
|
+
import type { RunEvent } from '../../../types/run/index.js'
|
|
8
|
+
import type { ToolRegistryContract } from '../../../types/tool/index.js'
|
|
9
|
+
import type { Logger } from '../../../utils/logger.js'
|
|
10
|
+
import { ToolExecutor } from '../executor.js'
|
|
11
|
+
|
|
12
|
+
const mockRunId = 'run_test' as RunId
|
|
13
|
+
|
|
14
|
+
function makeLogger(): Logger {
|
|
15
|
+
const stub = {
|
|
16
|
+
info: vi.fn(),
|
|
17
|
+
warn: vi.fn(),
|
|
18
|
+
error: vi.fn(),
|
|
19
|
+
debug: vi.fn(),
|
|
20
|
+
}
|
|
21
|
+
return { ...stub, child: vi.fn(() => ({ ...stub, child: vi.fn() })) } as unknown as Logger
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeToolRegistry(execute: ToolRegistryContract['execute']): ToolRegistryContract {
|
|
25
|
+
return {
|
|
26
|
+
register: vi.fn(),
|
|
27
|
+
unregister: vi.fn(),
|
|
28
|
+
execute,
|
|
29
|
+
get: vi.fn(() => undefined),
|
|
30
|
+
has: vi.fn(() => true),
|
|
31
|
+
listNames: vi.fn(() => []),
|
|
32
|
+
getAvailability: vi.fn(),
|
|
33
|
+
} as unknown as ToolRegistryContract
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function makePluginManager(
|
|
37
|
+
executeHooks: PluginLifecycleManager['executeHooks'],
|
|
38
|
+
): PluginLifecycleManager {
|
|
39
|
+
return { executeHooks } as unknown as PluginLifecycleManager
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function buildResponse(toolName: string, args: object): ChatCompletionResponse {
|
|
43
|
+
return {
|
|
44
|
+
message: {
|
|
45
|
+
role: 'assistant',
|
|
46
|
+
content: null,
|
|
47
|
+
toolCalls: [
|
|
48
|
+
{
|
|
49
|
+
id: 'call_1',
|
|
50
|
+
type: 'function',
|
|
51
|
+
function: { name: toolName, arguments: JSON.stringify(args) },
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
finishReason: 'tool_calls',
|
|
56
|
+
usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
|
|
57
|
+
} as ChatCompletionResponse
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
describe('ToolExecutor plugin hooks', () => {
|
|
61
|
+
let activityStore: ActivityStore
|
|
62
|
+
let emitted: RunEvent[]
|
|
63
|
+
let emitEvent: (e: RunEvent) => Promise<void>
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
activityStore = new ActivityStore(mockRunId, {
|
|
67
|
+
enabled: true,
|
|
68
|
+
trackToolCalls: true,
|
|
69
|
+
trackLlmTurns: true,
|
|
70
|
+
})
|
|
71
|
+
emitted = []
|
|
72
|
+
emitEvent = async (e) => {
|
|
73
|
+
emitted.push(e)
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('continues normally when no pluginManager is configured', async () => {
|
|
78
|
+
const tools = makeToolRegistry(vi.fn(async () => ({ success: true, output: 'ok' })))
|
|
79
|
+
const exec = new ToolExecutor(
|
|
80
|
+
{
|
|
81
|
+
tools,
|
|
82
|
+
runId: mockRunId,
|
|
83
|
+
workingDirectory: '/tmp',
|
|
84
|
+
permissionMode: 'auto',
|
|
85
|
+
env: {},
|
|
86
|
+
abortSignal: new AbortController().signal,
|
|
87
|
+
},
|
|
88
|
+
activityStore,
|
|
89
|
+
emitEvent,
|
|
90
|
+
makeLogger(),
|
|
91
|
+
)
|
|
92
|
+
const batch = await exec.executeBatch(buildResponse('echo', { msg: 'hi' }))
|
|
93
|
+
expect(batch.results[0]?.output).toBe('ok')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('replaces input on pre_tool_use modify', async () => {
|
|
97
|
+
const executeMock = vi.fn(async () => ({ success: true, output: 'ok' }))
|
|
98
|
+
const tools = makeToolRegistry(executeMock)
|
|
99
|
+
const pluginManager = makePluginManager(async (event) =>
|
|
100
|
+
event === 'pre_tool_use'
|
|
101
|
+
? ([{ action: 'modify', input: { replaced: true } }] as PluginHookResult[])
|
|
102
|
+
: [],
|
|
103
|
+
)
|
|
104
|
+
const exec = new ToolExecutor(
|
|
105
|
+
{
|
|
106
|
+
tools,
|
|
107
|
+
runId: mockRunId,
|
|
108
|
+
workingDirectory: '/tmp',
|
|
109
|
+
permissionMode: 'auto',
|
|
110
|
+
env: {},
|
|
111
|
+
abortSignal: new AbortController().signal,
|
|
112
|
+
pluginManager,
|
|
113
|
+
},
|
|
114
|
+
activityStore,
|
|
115
|
+
emitEvent,
|
|
116
|
+
makeLogger(),
|
|
117
|
+
)
|
|
118
|
+
await exec.executeBatch(buildResponse('echo', { original: true }))
|
|
119
|
+
expect(executeMock).toHaveBeenCalledWith('echo', { replaced: true }, expect.any(Object))
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('skips registry execution and synthesizes output on pre_tool_use skip', async () => {
|
|
123
|
+
const executeMock = vi.fn(async () => ({ success: true, output: 'should-not-run' }))
|
|
124
|
+
const tools = makeToolRegistry(executeMock)
|
|
125
|
+
const pluginManager = makePluginManager(async (event) =>
|
|
126
|
+
event === 'pre_tool_use'
|
|
127
|
+
? ([{ action: 'skip', reason: 'policy' }] as PluginHookResult[])
|
|
128
|
+
: [],
|
|
129
|
+
)
|
|
130
|
+
const exec = new ToolExecutor(
|
|
131
|
+
{
|
|
132
|
+
tools,
|
|
133
|
+
runId: mockRunId,
|
|
134
|
+
workingDirectory: '/tmp',
|
|
135
|
+
permissionMode: 'auto',
|
|
136
|
+
env: {},
|
|
137
|
+
abortSignal: new AbortController().signal,
|
|
138
|
+
pluginManager,
|
|
139
|
+
},
|
|
140
|
+
activityStore,
|
|
141
|
+
emitEvent,
|
|
142
|
+
makeLogger(),
|
|
143
|
+
)
|
|
144
|
+
const batch = await exec.executeBatch(buildResponse('echo', {}))
|
|
145
|
+
expect(executeMock).not.toHaveBeenCalled()
|
|
146
|
+
expect(batch.results[0]?.output).toBe('Tool echo skipped by plugin: policy')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('overrides post_tool_use output on error action', async () => {
|
|
150
|
+
const tools = makeToolRegistry(vi.fn(async () => ({ success: true, output: 'raw' })))
|
|
151
|
+
const pluginManager = makePluginManager(async (event) =>
|
|
152
|
+
event === 'post_tool_use'
|
|
153
|
+
? ([{ action: 'error', message: 'rejected' }] as PluginHookResult[])
|
|
154
|
+
: [],
|
|
155
|
+
)
|
|
156
|
+
const exec = new ToolExecutor(
|
|
157
|
+
{
|
|
158
|
+
tools,
|
|
159
|
+
runId: mockRunId,
|
|
160
|
+
workingDirectory: '/tmp',
|
|
161
|
+
permissionMode: 'auto',
|
|
162
|
+
env: {},
|
|
163
|
+
abortSignal: new AbortController().signal,
|
|
164
|
+
pluginManager,
|
|
165
|
+
},
|
|
166
|
+
activityStore,
|
|
167
|
+
emitEvent,
|
|
168
|
+
makeLogger(),
|
|
169
|
+
)
|
|
170
|
+
const batch = await exec.executeBatch(buildResponse('echo', {}))
|
|
171
|
+
expect(batch.results[0]?.output).toBe('Error: rejected')
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('threads modified input through chained pre_tool_use modify hooks', async () => {
|
|
175
|
+
const seenInputs: unknown[] = []
|
|
176
|
+
const executeMock = vi.fn(async (_name, input) => {
|
|
177
|
+
seenInputs.push(input)
|
|
178
|
+
return { success: true, output: 'ok' }
|
|
179
|
+
})
|
|
180
|
+
const tools = makeToolRegistry(executeMock)
|
|
181
|
+
const handlers = [
|
|
182
|
+
async (ctx: any) => {
|
|
183
|
+
seenInputs.push(['hook1-saw', ctx.toolInput])
|
|
184
|
+
return { action: 'modify', input: { step: 1 } } as PluginHookResult
|
|
185
|
+
},
|
|
186
|
+
async (ctx: any) => {
|
|
187
|
+
seenInputs.push(['hook2-saw', ctx.toolInput])
|
|
188
|
+
return { action: 'modify', input: { step: 2 } } as PluginHookResult
|
|
189
|
+
},
|
|
190
|
+
]
|
|
191
|
+
// Real PluginLifecycleManager so the modify-threading path is exercised end-to-end.
|
|
192
|
+
const { PluginLifecycleManager } = await import('../../../plugin/lifecycle.js')
|
|
193
|
+
const realManager = new PluginLifecycleManager({
|
|
194
|
+
pluginRegistry: {} as any,
|
|
195
|
+
toolRegistry: {} as any,
|
|
196
|
+
log: makeLogger(),
|
|
197
|
+
})
|
|
198
|
+
realManager['hookHandlers'].set('pre_tool_use', [
|
|
199
|
+
{ pluginId: 'p1' as any, handler: handlers[0] as any },
|
|
200
|
+
{ pluginId: 'p2' as any, handler: handlers[1] as any },
|
|
201
|
+
])
|
|
202
|
+
|
|
203
|
+
const exec = new ToolExecutor(
|
|
204
|
+
{
|
|
205
|
+
tools,
|
|
206
|
+
runId: mockRunId,
|
|
207
|
+
workingDirectory: '/tmp',
|
|
208
|
+
permissionMode: 'auto',
|
|
209
|
+
env: {},
|
|
210
|
+
abortSignal: new AbortController().signal,
|
|
211
|
+
pluginManager: realManager,
|
|
212
|
+
},
|
|
213
|
+
activityStore,
|
|
214
|
+
emitEvent,
|
|
215
|
+
makeLogger(),
|
|
216
|
+
)
|
|
217
|
+
await exec.executeBatch(buildResponse('echo', { original: true }))
|
|
218
|
+
expect(seenInputs).toEqual([
|
|
219
|
+
['hook1-saw', { original: true }],
|
|
220
|
+
['hook2-saw', { step: 1 }],
|
|
221
|
+
{ step: 2 },
|
|
222
|
+
])
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('carries modified input into synthetic skip outcome (modify -> skip chain)', async () => {
|
|
226
|
+
const executeMock = vi.fn(async () => ({ success: true, output: 'should-not-run' }))
|
|
227
|
+
const tools = makeToolRegistry(executeMock)
|
|
228
|
+
const { PluginLifecycleManager } = await import('../../../plugin/lifecycle.js')
|
|
229
|
+
const realManager = new PluginLifecycleManager({
|
|
230
|
+
pluginRegistry: {} as any,
|
|
231
|
+
toolRegistry: {} as any,
|
|
232
|
+
log: makeLogger(),
|
|
233
|
+
})
|
|
234
|
+
const seenInputs: unknown[] = []
|
|
235
|
+
realManager['hookHandlers'].set('pre_tool_use', [
|
|
236
|
+
{
|
|
237
|
+
pluginId: 'p1' as any,
|
|
238
|
+
handler: (async (ctx: any) => {
|
|
239
|
+
seenInputs.push(['hook1', ctx.toolInput])
|
|
240
|
+
return { action: 'modify', input: { patched: true } }
|
|
241
|
+
}) as any,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
pluginId: 'p2' as any,
|
|
245
|
+
handler: (async (ctx: any) => {
|
|
246
|
+
seenInputs.push(['hook2', ctx.toolInput])
|
|
247
|
+
return { action: 'skip', reason: 'after patch' }
|
|
248
|
+
}) as any,
|
|
249
|
+
},
|
|
250
|
+
])
|
|
251
|
+
|
|
252
|
+
const exec = new ToolExecutor(
|
|
253
|
+
{
|
|
254
|
+
tools,
|
|
255
|
+
runId: mockRunId,
|
|
256
|
+
workingDirectory: '/tmp',
|
|
257
|
+
permissionMode: 'auto',
|
|
258
|
+
env: {},
|
|
259
|
+
abortSignal: new AbortController().signal,
|
|
260
|
+
pluginManager: realManager,
|
|
261
|
+
},
|
|
262
|
+
activityStore,
|
|
263
|
+
emitEvent,
|
|
264
|
+
makeLogger(),
|
|
265
|
+
)
|
|
266
|
+
const batch = await exec.executeBatch(buildResponse('echo', { original: true }))
|
|
267
|
+
expect(executeMock).not.toHaveBeenCalled()
|
|
268
|
+
expect(batch.results[0]?.output).toBe('Tool echo skipped by plugin: after patch')
|
|
269
|
+
expect(seenInputs).toEqual([
|
|
270
|
+
['hook1', { original: true }],
|
|
271
|
+
['hook2', { patched: true }],
|
|
272
|
+
])
|
|
273
|
+
// Synthetic tool_executing event should carry the modified input, not the original.
|
|
274
|
+
const executingEvent = emitted.find((e) => e.type === 'tool_executing')
|
|
275
|
+
expect(executingEvent).toMatchObject({
|
|
276
|
+
type: 'tool_executing',
|
|
277
|
+
toolName: 'echo',
|
|
278
|
+
input: { patched: true },
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('throws on pre_tool_use retry misuse', async () => {
|
|
283
|
+
const tools = makeToolRegistry(vi.fn(async () => ({ success: true, output: 'ok' })))
|
|
284
|
+
const pluginManager = makePluginManager(async (event) =>
|
|
285
|
+
event === 'pre_tool_use' ? ([{ action: 'retry' }] as PluginHookResult[]) : [],
|
|
286
|
+
)
|
|
287
|
+
const exec = new ToolExecutor(
|
|
288
|
+
{
|
|
289
|
+
tools,
|
|
290
|
+
runId: mockRunId,
|
|
291
|
+
workingDirectory: '/tmp',
|
|
292
|
+
permissionMode: 'auto',
|
|
293
|
+
env: {},
|
|
294
|
+
abortSignal: new AbortController().signal,
|
|
295
|
+
pluginManager,
|
|
296
|
+
},
|
|
297
|
+
activityStore,
|
|
298
|
+
emitEvent,
|
|
299
|
+
makeLogger(),
|
|
300
|
+
)
|
|
301
|
+
await expect(exec.executeBatch(buildResponse('echo', {}))).rejects.toThrow(
|
|
302
|
+
/unsupported action 'retry'/,
|
|
303
|
+
)
|
|
304
|
+
})
|
|
305
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import type { PluginHookResult } from '../../../types/plugin/index.js'
|
|
3
|
+
import { applyLifecycleHookResults } from '../plugin-hooks.js'
|
|
4
|
+
|
|
5
|
+
describe('applyLifecycleHookResults', () => {
|
|
6
|
+
it('returns silently when all results are continue', () => {
|
|
7
|
+
const results: PluginHookResult[] = [{ action: 'continue' }, { action: 'continue' }]
|
|
8
|
+
expect(() => applyLifecycleHookResults('run_start', results)).not.toThrow()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('throws when a result is error', () => {
|
|
12
|
+
const results: PluginHookResult[] = [{ action: 'error', message: 'kaboom' }]
|
|
13
|
+
expect(() => applyLifecycleHookResults('pre_llm_call', results)).toThrow(
|
|
14
|
+
/pre_llm_call reported error: kaboom/,
|
|
15
|
+
)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it.each([
|
|
19
|
+
['skip', { action: 'skip', reason: 'no' } as PluginHookResult],
|
|
20
|
+
['modify', { action: 'modify', input: {} } as PluginHookResult],
|
|
21
|
+
['retry', { action: 'retry' } as PluginHookResult],
|
|
22
|
+
['resume', { action: 'resume', input: 'x' } as PluginHookResult],
|
|
23
|
+
])('throws on unsupported %s action for lifecycle event', (_, result) => {
|
|
24
|
+
expect(() => applyLifecycleHookResults('iteration_start', [result])).toThrow(
|
|
25
|
+
/unsupported action/,
|
|
26
|
+
)
|
|
27
|
+
})
|
|
28
|
+
})
|