@elevasis/core 0.47.0 → 0.48.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/auth/index.d.ts +80 -150
- package/dist/knowledge/index.d.ts +2 -1
- package/dist/knowledge/index.js +17 -1
- package/dist/test-utils/index.d.ts +80 -150
- package/package.json +1 -1
- package/src/execution/engine/agent/actions/__tests__/processor.test.ts +709 -531
- package/src/execution/engine/agent/actions/processor.ts +165 -116
- package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +91 -8
- package/src/execution/engine/agent/reasoning/prompt-sections/base-actions.ts +16 -13
- package/src/execution/engine/agent/reasoning/prompt-sections/tools.ts +7 -6
- package/src/execution/engine/tools/messages.ts +6 -5
- package/src/knowledge/__tests__/queries.test.ts +8 -0
- package/src/knowledge/published.ts +1 -1
- package/src/operations/sessions/server/session.ts +112 -43
- package/src/operations/sessions/types.ts +9 -7
- package/src/platform/constants/versions.ts +1 -1
- package/src/supabase/database.types.ts +125 -157
|
@@ -1,116 +1,165 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Action Phase Processor
|
|
3
|
-
* Orchestrates execution of LLM-planned actions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { IterationContext } from '../core/types'
|
|
7
|
-
import type { LLMIterationResponse } from '../reasoning/types'
|
|
8
|
-
import type { AgentAction, ToolCallAction } from './types'
|
|
9
|
-
import { executeToolCall } from './executor'
|
|
10
|
-
import { executeNavigateKnowledge } from './navigate-knowledge-executor'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Validate action sequence for correctness
|
|
14
|
-
* Ensures no invalid patterns that would cause undefined behavior
|
|
15
|
-
*
|
|
16
|
-
* Rules:
|
|
17
|
-
* - No multiple 'complete' actions
|
|
18
|
-
* - 'complete' cannot mix with 'navigate-knowledge' (loading knowledge without
|
|
19
|
-
* reasoning about it is always wasteful
|
|
20
|
-
* - 'complete' CAN mix with 'tool-call' (side-effect tools like navigate_user,
|
|
21
|
-
* update_filters are fire-and-forget
|
|
22
|
-
* Promise.allSettled before completion is signaled)
|
|
23
|
-
* - 'message' actions ARE allowed before 'complete' (user-facing communication)
|
|
24
|
-
*
|
|
25
|
-
* @param actions - Action array to validate
|
|
26
|
-
* @throws Error if validation fails
|
|
27
|
-
*/
|
|
28
|
-
function validateActionSequence(actions: AgentAction[]): void {
|
|
29
|
-
// Count completion actions
|
|
30
|
-
const completeActions = actions.filter((a) => a.type === 'complete')
|
|
31
|
-
|
|
32
|
-
// Rule 1: No duplicate completions
|
|
33
|
-
if (completeActions.length > 1) {
|
|
34
|
-
throw new Error('Multiple complete actions not allowed in single iteration')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Rule 2: Completion cannot mix with navigate-knowledge
|
|
38
|
-
// (tool-call + complete is allowed
|
|
39
|
-
if (completeActions.length === 1) {
|
|
40
|
-
const hasNavigateKnowledge = actions.some((a) => a.type === 'navigate-knowledge')
|
|
41
|
-
if (hasNavigateKnowledge) {
|
|
42
|
-
throw new Error('Complete action cannot mix with navigate-knowledge actions')
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Action Phase Processor
|
|
3
|
+
* Orchestrates execution of LLM-planned actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IterationContext } from '../core/types'
|
|
7
|
+
import type { LLMIterationResponse } from '../reasoning/types'
|
|
8
|
+
import type { AgentAction, ToolCallAction } from './types'
|
|
9
|
+
import { executeToolCall } from './executor'
|
|
10
|
+
import { executeNavigateKnowledge } from './navigate-knowledge-executor'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validate action sequence for correctness
|
|
14
|
+
* Ensures no invalid patterns that would cause undefined behavior
|
|
15
|
+
*
|
|
16
|
+
* Rules:
|
|
17
|
+
* - No multiple 'complete' actions
|
|
18
|
+
* - 'complete' cannot mix with 'navigate-knowledge' (loading knowledge without
|
|
19
|
+
* reasoning about it is always wasteful - the LLM should iterate instead)
|
|
20
|
+
* - 'complete' CAN mix with 'tool-call' (side-effect tools like navigate_user,
|
|
21
|
+
* update_filters are fire-and-forget - tool calls execute first via
|
|
22
|
+
* Promise.allSettled before completion is signaled)
|
|
23
|
+
* - 'message' actions ARE allowed before 'complete' (user-facing communication)
|
|
24
|
+
*
|
|
25
|
+
* @param actions - Action array to validate
|
|
26
|
+
* @throws Error if validation fails
|
|
27
|
+
*/
|
|
28
|
+
function validateActionSequence(actions: AgentAction[]): void {
|
|
29
|
+
// Count completion actions
|
|
30
|
+
const completeActions = actions.filter((a) => a.type === 'complete')
|
|
31
|
+
|
|
32
|
+
// Rule 1: No duplicate completions
|
|
33
|
+
if (completeActions.length > 1) {
|
|
34
|
+
throw new Error('Multiple complete actions not allowed in single iteration')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Rule 2: Completion cannot mix with navigate-knowledge
|
|
38
|
+
// (tool-call + complete is allowed - side-effect tools execute before completion)
|
|
39
|
+
if (completeActions.length === 1) {
|
|
40
|
+
const hasNavigateKnowledge = actions.some((a) => a.type === 'navigate-knowledge')
|
|
41
|
+
if (hasNavigateKnowledge) {
|
|
42
|
+
throw new Error('Complete action cannot mix with navigate-knowledge actions')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Collapse multiple session-visible messages into one assistant message.
|
|
49
|
+
*
|
|
50
|
+
* Session turns should produce at most one visible assistant bubble per
|
|
51
|
+
* iteration. Non-session executions keep the historical behavior because their
|
|
52
|
+
* messages are not rendered as conversational bubbles.
|
|
53
|
+
*/
|
|
54
|
+
function normalizeSessionMessages(actions: AgentAction[], sessionCapable: boolean): AgentAction[] {
|
|
55
|
+
if (!sessionCapable) {
|
|
56
|
+
return actions
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const messages = actions.filter((action) => action.type === 'message')
|
|
60
|
+
if (messages.length <= 1) {
|
|
61
|
+
return actions
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const collapsedText = messages.map((message) => message.text).join('\n\n')
|
|
65
|
+
const collapsedMessage: AgentAction = { type: 'message', text: collapsedText }
|
|
66
|
+
let emittedCollapsedMessage = false
|
|
67
|
+
|
|
68
|
+
return actions.flatMap((action): AgentAction[] => {
|
|
69
|
+
if (action.type !== 'message') {
|
|
70
|
+
return [action]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (emittedCollapsedMessage) {
|
|
74
|
+
return []
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
emittedCollapsedMessage = true
|
|
78
|
+
return [collapsedMessage]
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Process all actions from LLM response
|
|
84
|
+
* Executes tool calls in parallel, handles completion, and messages sequentially
|
|
85
|
+
*
|
|
86
|
+
* Tool calls are parallelized using Promise.allSettled() for performance:
|
|
87
|
+
* - Independent tool calls execute concurrently (up to 5x faster)
|
|
88
|
+
* - Partial failures don't abort successful tools
|
|
89
|
+
* - Results added to memory as they complete
|
|
90
|
+
*
|
|
91
|
+
* Other actions (navigate-knowledge, message, complete) remain sequential
|
|
92
|
+
* because they are order-dependent.
|
|
93
|
+
*
|
|
94
|
+
* @param iterationContext - Agent execution context
|
|
95
|
+
* @param response - LLM response with actions to execute
|
|
96
|
+
* @returns Object with shouldComplete flag (no finalAnswer - generated in completion phase)
|
|
97
|
+
*/
|
|
98
|
+
export async function processActions(
|
|
99
|
+
iterationContext: IterationContext,
|
|
100
|
+
response: LLMIterationResponse
|
|
101
|
+
): Promise<{ shouldComplete: boolean }> {
|
|
102
|
+
// Validate action sequence before processing
|
|
103
|
+
validateActionSequence(response.nextActions)
|
|
104
|
+
const normalizedActions = normalizeSessionMessages(response.nextActions, !!iterationContext.config.sessionCapable)
|
|
105
|
+
|
|
106
|
+
let shouldComplete = false
|
|
107
|
+
|
|
108
|
+
// Group actions by parallelizability
|
|
109
|
+
const toolCalls: ToolCallAction[] = []
|
|
110
|
+
const otherActions: AgentAction[] = []
|
|
111
|
+
|
|
112
|
+
for (const action of normalizedActions) {
|
|
113
|
+
if (action.type === 'tool-call') {
|
|
114
|
+
toolCalls.push(action)
|
|
115
|
+
} else {
|
|
116
|
+
otherActions.push(action)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Execute tool calls in parallel (if any)
|
|
121
|
+
// Uses Promise.allSettled() for partial success handling:
|
|
122
|
+
// - If 4/5 tools succeed, we get those results
|
|
123
|
+
// - Each tool handles errors independently and adds to memory
|
|
124
|
+
// - No result aggregation needed (each tool call adds to memory directly)
|
|
125
|
+
if (toolCalls.length > 0) {
|
|
126
|
+
await Promise.allSettled(toolCalls.map((action) => executeToolCall(iterationContext, action)))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Execute other actions sequentially (order matters)
|
|
130
|
+
for (const action of otherActions) {
|
|
131
|
+
switch (action.type) {
|
|
132
|
+
case 'navigate-knowledge':
|
|
133
|
+
await executeNavigateKnowledge(iterationContext, action)
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
case 'complete':
|
|
137
|
+
shouldComplete = true
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
case 'message': {
|
|
141
|
+
// Emit assistant message event (immediate persistence + streaming)
|
|
142
|
+
await iterationContext.executionContext.onMessageEvent?.({
|
|
143
|
+
type: 'assistant_message',
|
|
144
|
+
text: action.text
|
|
145
|
+
})
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A user-facing message with no tool calls and no explicit completion ends a
|
|
152
|
+
// conversational turn. Without this, a tool-less sessionCapable agent loops and
|
|
153
|
+
// emits multiple message bubbles for a single user turn when the LLM omits `complete`.
|
|
154
|
+
if (
|
|
155
|
+
!shouldComplete &&
|
|
156
|
+
iterationContext.config.sessionCapable &&
|
|
157
|
+
toolCalls.length === 0 &&
|
|
158
|
+
normalizedActions.some((a) => a.type === 'message') &&
|
|
159
|
+
!normalizedActions.some((a) => a.type === 'navigate-knowledge')
|
|
160
|
+
) {
|
|
161
|
+
shouldComplete = true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return { shouldComplete }
|
|
165
|
+
}
|
|
@@ -86,7 +86,7 @@ describe('buildReasoningRequest', () => {
|
|
|
86
86
|
})
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
describe('session capability', () => {
|
|
89
|
+
describe('session capability', () => {
|
|
90
90
|
it('should set includeMessageAction to false when sessionCapable is not set', () => {
|
|
91
91
|
const context = createMockContext()
|
|
92
92
|
const request = buildReasoningRequest(context)
|
|
@@ -113,7 +113,7 @@ describe('buildReasoningRequest', () => {
|
|
|
113
113
|
expect(request.includeMessageAction).toBe(true)
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
it('should set includeMessageAction to false when sessionCapable is false', () => {
|
|
116
|
+
it('should set includeMessageAction to false when sessionCapable is false', () => {
|
|
117
117
|
const context = createMockContext({
|
|
118
118
|
config: {
|
|
119
119
|
type: 'agent',
|
|
@@ -128,12 +128,95 @@ describe('buildReasoningRequest', () => {
|
|
|
128
128
|
}
|
|
129
129
|
})
|
|
130
130
|
const request = buildReasoningRequest(context)
|
|
131
|
-
|
|
132
|
-
expect(request.includeMessageAction).toBe(false)
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
131
|
+
|
|
132
|
+
expect(request.includeMessageAction).toBe(false)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should explain session message normalization and completion pairing', () => {
|
|
136
|
+
const context = createMockContext({
|
|
137
|
+
config: {
|
|
138
|
+
type: 'agent',
|
|
139
|
+
kind: 'utility',
|
|
140
|
+
resourceId: 'test-agent',
|
|
141
|
+
name: 'Test Agent',
|
|
142
|
+
description: 'Test agent',
|
|
143
|
+
version: '1.0.0',
|
|
144
|
+
status: 'dev',
|
|
145
|
+
systemPrompt: 'You are a test agent',
|
|
146
|
+
sessionCapable: true
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
const request = buildReasoningRequest(context)
|
|
150
|
+
|
|
151
|
+
expect(request.systemPrompt).toContain('Send at most one message per iteration')
|
|
152
|
+
expect(request.systemPrompt).toContain('Multiple messages in a session turn are collapsed into one visible assistant message')
|
|
153
|
+
expect(request.systemPrompt).toContain('send message + complete in the SAME iteration')
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('action completion prompt contract', () => {
|
|
158
|
+
it('should allow complete with fire-and-forget tool calls while blocking navigate-knowledge completion', () => {
|
|
159
|
+
const mockTool = {
|
|
160
|
+
name: 'navigate_user',
|
|
161
|
+
description: 'Navigate the UI',
|
|
162
|
+
inputSchema: z.object({ path: z.string() }),
|
|
163
|
+
outputSchema: z.object({ ok: z.boolean() }),
|
|
164
|
+
execute: async () => ({ ok: true })
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const toolRegistry = new Map()
|
|
168
|
+
toolRegistry.set('navigate_user', mockTool)
|
|
169
|
+
|
|
170
|
+
const context = createMockContext({ toolRegistry })
|
|
171
|
+
const request = buildReasoningRequest(context)
|
|
172
|
+
|
|
173
|
+
expect(request.systemPrompt).toContain('"complete" CAN mix with fire-and-forget tool-call actions')
|
|
174
|
+
expect(request.systemPrompt).toContain('"complete" CANNOT mix with navigate-knowledge actions')
|
|
175
|
+
expect(request.systemPrompt).not.toContain('"complete" CANNOT mix with tool-call or navigate-knowledge')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('should tell agents not to complete after navigate-knowledge', () => {
|
|
179
|
+
const context = createMockContext({
|
|
180
|
+
config: {
|
|
181
|
+
type: 'agent',
|
|
182
|
+
kind: 'utility',
|
|
183
|
+
resourceId: 'test-agent',
|
|
184
|
+
name: 'Test Agent',
|
|
185
|
+
description: 'Test agent',
|
|
186
|
+
version: '1.0.0',
|
|
187
|
+
status: 'dev',
|
|
188
|
+
systemPrompt: 'You are a test agent',
|
|
189
|
+
sessionCapable: true
|
|
190
|
+
},
|
|
191
|
+
knowledgeMap: {
|
|
192
|
+
nodes: {
|
|
193
|
+
support: {
|
|
194
|
+
id: 'support',
|
|
195
|
+
description: 'Support knowledge',
|
|
196
|
+
loaded: false,
|
|
197
|
+
load: async () => ({ prompt: 'Support prompt' })
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} as Partial<IterationContext>)
|
|
202
|
+
const request = buildReasoningRequest(context)
|
|
203
|
+
|
|
204
|
+
expect(request.includeNavigateKnowledge).toBe(true)
|
|
205
|
+
expect(request.systemPrompt).toContain('"complete" cannot mix with navigate-knowledge')
|
|
206
|
+
expect(request.systemPrompt).toContain('You used navigate-knowledge and need the newly loaded knowledge in the next iteration')
|
|
207
|
+
|
|
208
|
+
const navigateExampleStart = request.systemPrompt.indexOf('**Iteration 1 - Navigate to load knowledge:**')
|
|
209
|
+
const nextIterationStart = request.systemPrompt.indexOf('**Iteration 2 - Use newly available tools:**')
|
|
210
|
+
const navigateExample = request.systemPrompt.slice(navigateExampleStart, nextIterationStart)
|
|
211
|
+
|
|
212
|
+
expect(navigateExampleStart).toBeGreaterThan(-1)
|
|
213
|
+
expect(nextIterationStart).toBeGreaterThan(navigateExampleStart)
|
|
214
|
+
expect(navigateExample).toContain('"type": "navigate-knowledge"')
|
|
215
|
+
expect(navigateExample).not.toContain('"complete"')
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe('security prompt', () => {
|
|
137
220
|
it('should include standard security rules by default', () => {
|
|
138
221
|
const context = createMockContext()
|
|
139
222
|
const request = buildReasoningRequest(context)
|
|
@@ -68,25 +68,28 @@ ${actionsList}
|
|
|
68
68
|
|
|
69
69
|
## Rules
|
|
70
70
|
|
|
71
|
-
- Batch independent tool calls in one iteration (faster execution)
|
|
72
|
-
- Dependent operations need separate iterations (tool B needs tool A's result)
|
|
73
|
-
- "complete" cannot mix with
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
- Batch independent tool calls in one iteration (faster execution)
|
|
72
|
+
- Dependent operations need separate iterations (tool B needs tool A's result)
|
|
73
|
+
- "complete" cannot mix with navigate-knowledge${includeNavigateKnowledge ? '' : ' (when available)'}
|
|
74
|
+
- "complete" can mix with tool-call when the tool is a fire-and-forget side effect and you do not need its result before ending${
|
|
75
|
+
includeMessageAction
|
|
76
|
+
? `
|
|
77
|
+
- Always send at least one message before completing
|
|
78
|
+
- Send at most one message per iteration. Multiple messages in a session turn are collapsed into one visible assistant message.
|
|
79
|
+
- When you have your answer, send message + complete in the SAME iteration. Never send a message alone then complete in a later iteration.
|
|
80
|
+
- Never repeat or rephrase the same answer across iterations. One clear answer, then complete.`
|
|
81
|
+
: ''
|
|
82
|
+
}
|
|
81
83
|
|
|
82
84
|
**Use "complete" when:**
|
|
83
85
|
- Task finished successfully
|
|
84
86
|
- Tool returned empty/error results (inform user first)
|
|
85
87
|
- You need user input to proceed (ask question first)
|
|
86
88
|
|
|
87
|
-
**Don't use "complete" when:**
|
|
88
|
-
- You just called a tool and need its results
|
|
89
|
-
-
|
|
89
|
+
**Don't use "complete" when:**
|
|
90
|
+
- You just called a tool and need its results
|
|
91
|
+
- You used navigate-knowledge and need the newly loaded knowledge in the next iteration
|
|
92
|
+
- More iterations are needed
|
|
90
93
|
|
|
91
94
|
## Examples
|
|
92
95
|
|
|
@@ -33,12 +33,13 @@ export function buildToolsPrompt(tools: ToolDefinition[]): string {
|
|
|
33
33
|
section +=
|
|
34
34
|
'{\n "type": "tool-call",\n "id": "unique-id",\n "name": "tool-name",\n "input": { /* tool input matching schema */ }\n}\n\n'
|
|
35
35
|
|
|
36
|
-
section += '**IMPORTANT RULES:**\n'
|
|
37
|
-
section += '1. "complete" CANNOT mix with
|
|
38
|
-
section += '2. "complete" CAN mix with message
|
|
39
|
-
section += '3.
|
|
40
|
-
section += '4.
|
|
41
|
-
section += '5.
|
|
36
|
+
section += '**IMPORTANT RULES:**\n'
|
|
37
|
+
section += '1. "complete" CANNOT mix with navigate-knowledge actions in the same response\n'
|
|
38
|
+
section += '2. "complete" CAN mix with message - always pair your final message with complete in the same iteration\n'
|
|
39
|
+
section += '3. "complete" CAN mix with fire-and-forget tool-call actions when you do not need their results\n'
|
|
40
|
+
section += '4. To use tools and inspect their results, return ONLY tool-call actions, then wait for results in the next iteration\n'
|
|
41
|
+
section += '5. After receiving tool results, you can either call more tools OR complete with final answer\n'
|
|
42
|
+
section += '6. navigate-knowledge actions load new capabilities - tools become available in the next iteration\n'
|
|
42
43
|
|
|
43
44
|
return section + '\n'
|
|
44
45
|
}
|
|
@@ -14,11 +14,12 @@ import type { ToolingErrorType } from './types'
|
|
|
14
14
|
* Token usage metadata optionally attached to a ToolCallResponse.
|
|
15
15
|
* Populated for LLM tool calls where cost accounting is available.
|
|
16
16
|
*/
|
|
17
|
-
export interface TokenUsage {
|
|
18
|
-
inputTokens: number
|
|
19
|
-
outputTokens: number
|
|
20
|
-
cost?: number
|
|
21
|
-
|
|
17
|
+
export interface TokenUsage {
|
|
18
|
+
inputTokens: number
|
|
19
|
+
outputTokens: number
|
|
20
|
+
cost?: number
|
|
21
|
+
model?: string
|
|
22
|
+
}
|
|
22
23
|
|
|
23
24
|
/** Outbound tool-call from worker to parent */
|
|
24
25
|
export interface ToolCallMessage {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import { bySystem, byOntology, byKind, byOwner, governs, governedBy, parsePath, omSearch, omDescribe } from '../queries'
|
|
3
3
|
import { byOntology as publicByOntology } from '../index'
|
|
4
|
+
import { byOntology as publishedByOntology } from '../published'
|
|
4
5
|
import { formatText, formatJson, formatIdsOnly, formatOmSearchHits, formatOmDescribe } from '../format'
|
|
5
6
|
import type { OrganizationGraph } from '../../organization-model/graph/types'
|
|
6
7
|
import type { OrgKnowledgeNode } from '../../organization-model/domains/knowledge'
|
|
@@ -259,6 +260,13 @@ describe('byOntology', () => {
|
|
|
259
260
|
'knowledge.playbook-d'
|
|
260
261
|
])
|
|
261
262
|
})
|
|
263
|
+
|
|
264
|
+
it('is exported from the published knowledge API', () => {
|
|
265
|
+
expect(publishedByOntology).toBe(byOntology)
|
|
266
|
+
expect(publishedByOntology(GRAPH, 'sales.crm:object/deal', NODES).map((node) => node.id)).toEqual([
|
|
267
|
+
'knowledge.playbook-d'
|
|
268
|
+
])
|
|
269
|
+
})
|
|
262
270
|
})
|
|
263
271
|
|
|
264
272
|
// ---------------------------------------------------------------------------
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { bySystem, byKind, byOwner, governs, governedBy, parsePath } from './queries'
|
|
1
|
+
export { bySystem, byOntology, byKind, byOwner, governs, governedBy, parsePath } from './queries'
|
|
2
2
|
export type { KnowledgeMount, ParsedKnowledgePath, OmSearchHitKind } from './queries'
|
|
3
3
|
|
|
4
4
|
export { formatText, formatJson, formatIdsOnly } from './format'
|