@namzu/sdk 62.12.0 → 62.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/agents/file-definitions.d.ts +7 -0
- package/dist/agents/file-definitions.d.ts.map +1 -1
- package/dist/agents/file-definitions.js +20 -0
- package/dist/agents/file-definitions.js.map +1 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/bridge/acp/server.d.ts +8 -1
- package/dist/bridge/acp/server.d.ts.map +1 -1
- package/dist/bridge/acp/server.js +12 -0
- package/dist/bridge/acp/server.js.map +1 -1
- package/dist/connector/index.d.ts +1 -1
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +1 -1
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/client.d.ts +96 -0
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +488 -13
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +1 -0
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +1 -0
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/tasks.d.ts +40 -0
- package/dist/connector/mcp/tasks.d.ts.map +1 -0
- package/dist/connector/mcp/tasks.js +55 -0
- package/dist/connector/mcp/tasks.js.map +1 -0
- package/dist/constants/data-epoch.d.ts +18 -0
- package/dist/constants/data-epoch.d.ts.map +1 -0
- package/dist/constants/data-epoch.js +18 -0
- package/dist/constants/data-epoch.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +1 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/constants/mcp/index.d.ts +1 -1
- package/dist/constants/mcp/index.d.ts.map +1 -1
- package/dist/constants/mcp/index.js +5 -0
- package/dist/constants/mcp/index.js.map +1 -1
- package/dist/constants/telemetry/index.d.ts +12 -0
- package/dist/constants/telemetry/index.d.ts.map +1 -1
- package/dist/constants/telemetry/index.js +12 -0
- package/dist/constants/telemetry/index.js.map +1 -1
- package/dist/eval/bootstrap.d.ts +122 -0
- package/dist/eval/bootstrap.d.ts.map +1 -0
- package/dist/eval/bootstrap.js +227 -0
- package/dist/eval/bootstrap.js.map +1 -0
- package/dist/eval/compare.d.ts +109 -0
- package/dist/eval/compare.d.ts.map +1 -0
- package/dist/eval/compare.js +324 -0
- package/dist/eval/compare.js.map +1 -0
- package/dist/eval/disclosure.d.ts +70 -0
- package/dist/eval/disclosure.d.ts.map +1 -0
- package/dist/eval/disclosure.js +64 -0
- package/dist/eval/disclosure.js.map +1 -0
- package/dist/eval/experiment.d.ts +23 -0
- package/dist/eval/experiment.d.ts.map +1 -1
- package/dist/eval/experiment.js +87 -15
- package/dist/eval/experiment.js.map +1 -1
- package/dist/eval/from-turn.d.ts.map +1 -1
- package/dist/eval/from-turn.js +5 -0
- package/dist/eval/from-turn.js.map +1 -1
- package/dist/eval/index.d.ts +13 -2
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js +6 -1
- package/dist/eval/index.js.map +1 -1
- package/dist/eval/report-stats.d.ts +77 -0
- package/dist/eval/report-stats.d.ts.map +1 -0
- package/dist/eval/report-stats.js +184 -0
- package/dist/eval/report-stats.js.map +1 -0
- package/dist/eval/run-options.d.ts +30 -0
- package/dist/eval/run-options.d.ts.map +1 -0
- package/dist/eval/run-options.js +20 -0
- package/dist/eval/run-options.js.map +1 -0
- package/dist/eval/run-summary.d.ts +36 -0
- package/dist/eval/run-summary.d.ts.map +1 -0
- package/dist/eval/run-summary.js +57 -0
- package/dist/eval/run-summary.js.map +1 -0
- package/dist/eval/scorers.d.ts +32 -0
- package/dist/eval/scorers.d.ts.map +1 -1
- package/dist/eval/scorers.js +77 -0
- package/dist/eval/scorers.js.map +1 -1
- package/dist/eval/types.d.ts +74 -0
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.d.ts +3 -0
- package/dist/manager/session/turn-recorder.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.js +18 -2
- package/dist/manager/session/turn-recorder.js.map +1 -1
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1 -1
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/loader.d.ts +11 -0
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +15 -2
- package/dist/plugin/loader.js.map +1 -1
- package/dist/public-runtime.d.ts +10 -6
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +13 -5
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/command/kernel-commands.d.ts +3 -0
- package/dist/registry/command/kernel-commands.d.ts.map +1 -1
- package/dist/registry/command/kernel-commands.js +76 -5
- package/dist/registry/command/kernel-commands.js.map +1 -1
- package/dist/runtime/query/cancelled-before-start.d.ts.map +1 -1
- package/dist/runtime/query/cancelled-before-start.js +2 -0
- package/dist/runtime/query/cancelled-before-start.js.map +1 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +17 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +18 -1
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +80 -1
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +18 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +5 -0
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js +2 -0
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/runtime/query/turn/answer-claims.d.ts +52 -0
- package/dist/runtime/query/turn/answer-claims.d.ts.map +1 -0
- package/dist/runtime/query/turn/answer-claims.js +348 -0
- package/dist/runtime/query/turn/answer-claims.js.map +1 -0
- package/dist/runtime/query/turn/outcome-ledger.d.ts +7 -0
- package/dist/runtime/query/turn/outcome-ledger.d.ts.map +1 -1
- package/dist/runtime/query/turn/outcome-ledger.js +13 -0
- package/dist/runtime/query/turn/outcome-ledger.js.map +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/loader.d.ts +15 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +17 -3
- package/dist/skills/loader.js.map +1 -1
- package/dist/store/goal/index.d.ts +3 -1
- package/dist/store/goal/index.d.ts.map +1 -1
- package/dist/store/goal/index.js +6 -0
- package/dist/store/goal/index.js.map +1 -1
- package/dist/telemetry/genai.d.ts +98 -0
- package/dist/telemetry/genai.d.ts.map +1 -0
- package/dist/telemetry/genai.js +189 -0
- package/dist/telemetry/genai.js.map +1 -0
- package/dist/telemetry/runtime-accessors.d.ts +19 -0
- package/dist/telemetry/runtime-accessors.d.ts.map +1 -1
- package/dist/telemetry/runtime-accessors.js +43 -1
- package/dist/telemetry/runtime-accessors.js.map +1 -1
- package/dist/tools/goal/confirmation.d.ts +154 -0
- package/dist/tools/goal/confirmation.d.ts.map +1 -0
- package/dist/tools/goal/confirmation.js +290 -0
- package/dist/tools/goal/confirmation.js.map +1 -0
- package/dist/tools/goal/index.d.ts +4 -1
- package/dist/tools/goal/index.d.ts.map +1 -1
- package/dist/tools/goal/index.js +27 -2
- package/dist/tools/goal/index.js.map +1 -1
- package/dist/tools/hand-back/index.d.ts +48 -0
- package/dist/tools/hand-back/index.d.ts.map +1 -0
- package/dist/tools/hand-back/index.js +129 -0
- package/dist/tools/hand-back/index.js.map +1 -0
- package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
- package/dist/tools/schedules/schedule-tool.js +15 -1
- package/dist/tools/schedules/schedule-tool.js.map +1 -1
- package/dist/tools/schedules/types.d.ts +10 -0
- package/dist/tools/schedules/types.d.ts.map +1 -1
- package/dist/toolsets/manager.d.ts.map +1 -1
- package/dist/toolsets/manager.js +12 -0
- package/dist/toolsets/manager.js.map +1 -1
- package/dist/types/acp/index.d.ts +18 -0
- package/dist/types/acp/index.d.ts.map +1 -1
- package/dist/types/connector/mcp.d.ts +18 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/goal/index.d.ts +12 -0
- package/dist/types/goal/index.d.ts.map +1 -1
- package/dist/types/session/config.d.ts +8 -0
- package/dist/types/session/config.d.ts.map +1 -1
- package/dist/types/session/hand-back.d.ts +29 -0
- package/dist/types/session/hand-back.d.ts.map +1 -0
- package/dist/types/session/hand-back.js +11 -0
- package/dist/types/session/hand-back.js.map +1 -0
- package/dist/types/session/outcome.d.ts +37 -0
- package/dist/types/session/outcome.d.ts.map +1 -1
- package/dist/types/session/outcome.js.map +1 -1
- package/dist/types/session/turn.d.ts +19 -1
- package/dist/types/session/turn.d.ts.map +1 -1
- package/dist/types/session/turn.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/file-definitions.ts +21 -0
- package/src/agents/index.ts +1 -0
- package/src/bridge/acp/server.ts +20 -0
- package/src/connector/index.ts +1 -0
- package/src/connector/mcp/client.ts +531 -14
- package/src/connector/mcp/index.ts +1 -0
- package/src/connector/mcp/tasks.ts +81 -0
- package/src/constants/data-epoch.ts +17 -0
- package/src/constants/index.ts +1 -0
- package/src/constants/mcp/index.ts +6 -1
- package/src/constants/telemetry/index.ts +13 -0
- package/src/eval/bootstrap.ts +314 -0
- package/src/eval/compare.ts +473 -0
- package/src/eval/disclosure.ts +136 -0
- package/src/eval/experiment.ts +127 -15
- package/src/eval/from-turn.ts +5 -0
- package/src/eval/index.ts +51 -0
- package/src/eval/report-stats.ts +257 -0
- package/src/eval/run-options.ts +49 -0
- package/src/eval/run-summary.ts +104 -0
- package/src/eval/scorers.ts +83 -0
- package/src/eval/types.ts +76 -0
- package/src/manager/session/turn-recorder.ts +23 -2
- package/src/plugin/index.ts +7 -1
- package/src/plugin/loader.ts +16 -2
- package/src/public-runtime.ts +70 -0
- package/src/public-types.ts +9 -0
- package/src/registry/command/kernel-commands.ts +94 -6
- package/src/runtime/query/cancelled-before-start.ts +2 -0
- package/src/runtime/query/index.ts +20 -0
- package/src/runtime/query/iteration/index.ts +85 -1
- package/src/runtime/query/iteration/phases/tool-review.ts +24 -1
- package/src/runtime/query/iteration/stream-turn.ts +10 -0
- package/src/runtime/query/result.ts +2 -0
- package/src/runtime/query/turn/answer-claims.ts +413 -0
- package/src/runtime/query/turn/outcome-ledger.ts +12 -0
- package/src/skills/index.ts +1 -0
- package/src/skills/loader.ts +21 -3
- package/src/store/goal/index.ts +11 -0
- package/src/telemetry/genai.ts +202 -0
- package/src/telemetry/runtime-accessors.ts +40 -1
- package/src/tools/goal/confirmation.ts +375 -0
- package/src/tools/goal/index.ts +37 -1
- package/src/tools/hand-back/index.ts +150 -0
- package/src/tools/schedules/schedule-tool.ts +19 -1
- package/src/tools/schedules/types.ts +10 -0
- package/src/toolsets/manager.ts +22 -0
- package/src/types/acp/index.ts +20 -0
- package/src/types/connector/mcp.ts +18 -0
- package/src/types/goal/index.ts +13 -0
- package/src/types/session/config.ts +8 -0
- package/src/types/session/hand-back.ts +31 -0
- package/src/types/session/outcome.ts +42 -0
- package/src/types/session/turn.ts +19 -1
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
StaleGoalError,
|
|
9
9
|
} from '../../store/goal/index.js'
|
|
10
10
|
import type { HostCommandDescriptor } from '../../types/command/index.js'
|
|
11
|
-
import type { GoalRef, SessionGoal } from '../../types/goal/index.js'
|
|
11
|
+
import type { GoalConfirmedBy, GoalRef, SessionGoal } from '../../types/goal/index.js'
|
|
12
12
|
import type { SessionId, TenantId } from '../../types/ids/index.js'
|
|
13
13
|
import type { Skill } from '../../types/skills/index.js'
|
|
14
14
|
import { isInvocableBy, skillInvocation } from '../../types/skills/index.js'
|
|
@@ -48,9 +48,12 @@ export interface GoalCommandScope {
|
|
|
48
48
|
readonly tenantId: TenantId
|
|
49
49
|
/** Process-local permission for automatic continuation. */
|
|
50
50
|
readonly activation?: SessionGoalActivation
|
|
51
|
+
/** What a goal that does not choose is confirmed by; shown by `/goal status`. Default `model`. */
|
|
52
|
+
readonly defaultConfirmedBy?: GoalConfirmedBy
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
const GOAL_ARGUMENTS =
|
|
55
|
+
const GOAL_ARGUMENTS =
|
|
56
|
+
'[status|set [--confirmed-by record|model] <objective>|<objective>|edit <objective>|pause|resume|clear]'
|
|
54
57
|
const GOAL_USAGE = `Usage: /goal ${GOAL_ARGUMENTS}`
|
|
55
58
|
|
|
56
59
|
type ParsedGoalCommand =
|
|
@@ -78,6 +81,60 @@ function parseGoalCommand(args: readonly string[]): ParsedGoalCommand {
|
|
|
78
81
|
return { kind: 'create', objective: input }
|
|
79
82
|
}
|
|
80
83
|
|
|
84
|
+
type ConfirmedByFlag =
|
|
85
|
+
| {
|
|
86
|
+
readonly kind: 'ok'
|
|
87
|
+
readonly args: readonly string[]
|
|
88
|
+
readonly confirmedBy?: GoalConfirmedBy
|
|
89
|
+
}
|
|
90
|
+
| { readonly kind: 'invalid' }
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Takes `--confirmed-by <model|record>` (or `=`) out of the arguments, but only
|
|
94
|
+
* where a flag stands: at the front, right after `set`, or closing the command. In the middle the words
|
|
95
|
+
* belong to the objective, so a goal about the flag itself keeps its text.
|
|
96
|
+
*/
|
|
97
|
+
function takeConfirmedBy(args: readonly string[]): ConfirmedByFlag {
|
|
98
|
+
const head: string[] = []
|
|
99
|
+
let i = 0
|
|
100
|
+
if ((args[0] ?? '').toLowerCase() === 'set') {
|
|
101
|
+
head.push(args[0] ?? '')
|
|
102
|
+
i = 1
|
|
103
|
+
}
|
|
104
|
+
let found: GoalConfirmedBy | undefined
|
|
105
|
+
for (; i < args.length; i++) {
|
|
106
|
+
const arg = args[i] ?? ''
|
|
107
|
+
let value: string
|
|
108
|
+
if (arg === '--confirmed-by') {
|
|
109
|
+
value = args[i + 1] ?? ''
|
|
110
|
+
i++
|
|
111
|
+
} else if (arg.startsWith('--confirmed-by=')) {
|
|
112
|
+
value = arg.slice('--confirmed-by='.length)
|
|
113
|
+
} else {
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
if (value !== 'model' && value !== 'record') return { kind: 'invalid' }
|
|
117
|
+
found = value
|
|
118
|
+
}
|
|
119
|
+
let tail = args.slice(i)
|
|
120
|
+
// A flag may also close the command; in the middle its words are the objective's.
|
|
121
|
+
const last = tail[tail.length - 1] ?? ''
|
|
122
|
+
const beforeLast = tail[tail.length - 2] ?? ''
|
|
123
|
+
let closing: string | undefined
|
|
124
|
+
if (last.startsWith('--confirmed-by=')) {
|
|
125
|
+
closing = last.slice('--confirmed-by='.length)
|
|
126
|
+
tail = tail.slice(0, -1)
|
|
127
|
+
} else if (beforeLast === '--confirmed-by') {
|
|
128
|
+
closing = last
|
|
129
|
+
tail = tail.slice(0, -2)
|
|
130
|
+
}
|
|
131
|
+
if (closing !== undefined) {
|
|
132
|
+
if (closing !== 'model' && closing !== 'record') return { kind: 'invalid' }
|
|
133
|
+
found = closing
|
|
134
|
+
}
|
|
135
|
+
return { kind: 'ok', args: [...head, ...tail], ...(found ? { confirmedBy: found } : {}) }
|
|
136
|
+
}
|
|
137
|
+
|
|
81
138
|
function goalRef(goal: SessionGoal): GoalRef {
|
|
82
139
|
return { id: goal.id, revision: goal.revision }
|
|
83
140
|
}
|
|
@@ -92,10 +149,19 @@ function goalCommands(goal: SessionGoal, armed: boolean): string {
|
|
|
92
149
|
return '/goal set <objective>, /goal clear'
|
|
93
150
|
}
|
|
94
151
|
|
|
95
|
-
function renderGoal(
|
|
152
|
+
function renderGoal(
|
|
153
|
+
title: string,
|
|
154
|
+
goal: SessionGoal,
|
|
155
|
+
armed: boolean,
|
|
156
|
+
defaultConfirmedBy: GoalConfirmedBy = 'model',
|
|
157
|
+
): string {
|
|
96
158
|
return [
|
|
97
159
|
title,
|
|
98
160
|
`Status: ${goal.phase}`,
|
|
161
|
+
...(goal.confirmedBy === 'record' ||
|
|
162
|
+
(goal.confirmedBy === undefined && defaultConfirmedBy === 'record')
|
|
163
|
+
? ['Confirmed by: the record of the work']
|
|
164
|
+
: []),
|
|
99
165
|
`Automatic continuation: ${armed ? 'enabled' : 'paused'}`,
|
|
100
166
|
`Automatic turns: ${goal.roundsAdmitted} / ${goal.maxGoalRounds}`,
|
|
101
167
|
...(goal.blockedReason
|
|
@@ -108,7 +174,12 @@ function renderGoal(title: string, goal: SessionGoal, armed: boolean): string {
|
|
|
108
174
|
}
|
|
109
175
|
|
|
110
176
|
function renderScopedGoal(title: string, goal: SessionGoal, scope: GoalCommandScope): string {
|
|
111
|
-
return renderGoal(
|
|
177
|
+
return renderGoal(
|
|
178
|
+
title,
|
|
179
|
+
goal,
|
|
180
|
+
scope.activation?.isArmed(scope.sessionId, goal) ?? false,
|
|
181
|
+
scope.defaultConfirmedBy,
|
|
182
|
+
)
|
|
112
183
|
}
|
|
113
184
|
|
|
114
185
|
function missingGoal(action: string) {
|
|
@@ -125,7 +196,20 @@ async function runGoalCommand(scope: GoalCommandScope | undefined, args: readonl
|
|
|
125
196
|
reason: 'Goals need a durable session. This host did not supply one for the current command.',
|
|
126
197
|
}
|
|
127
198
|
}
|
|
128
|
-
const
|
|
199
|
+
const flag = takeConfirmedBy(args)
|
|
200
|
+
if (flag.kind === 'invalid') {
|
|
201
|
+
return {
|
|
202
|
+
kind: 'refused' as const,
|
|
203
|
+
reason: `--confirmed-by takes record or model.\n${GOAL_USAGE}`,
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const command = parseGoalCommand(flag.args)
|
|
207
|
+
if (flag.confirmedBy !== undefined && command.kind !== 'create') {
|
|
208
|
+
return {
|
|
209
|
+
kind: 'refused' as const,
|
|
210
|
+
reason: `--confirmed-by is chosen when a goal is set.\n${GOAL_USAGE}`,
|
|
211
|
+
}
|
|
212
|
+
}
|
|
129
213
|
try {
|
|
130
214
|
const current = await scope.store.getGoal(scope.sessionId, scope.tenantId)
|
|
131
215
|
switch (command.kind) {
|
|
@@ -154,7 +238,11 @@ async function runGoalCommand(scope: GoalCommandScope | undefined, args: readonl
|
|
|
154
238
|
}
|
|
155
239
|
}
|
|
156
240
|
const created = await scope.store.createGoal(
|
|
157
|
-
{
|
|
241
|
+
{
|
|
242
|
+
sessionId: scope.sessionId,
|
|
243
|
+
objective: command.objective,
|
|
244
|
+
...(flag.confirmedBy !== undefined ? { confirmedBy: flag.confirmedBy } : {}),
|
|
245
|
+
},
|
|
158
246
|
scope.tenantId,
|
|
159
247
|
)
|
|
160
248
|
scope.activation?.arm(created)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TurnRecorder } from '../../manager/session/turn-recorder.js'
|
|
2
2
|
import { GENAI, NAMZU, agentTurnSpanName, parentContext } from '../../telemetry/attributes.js'
|
|
3
|
+
import { agentRunAttributes } from '../../telemetry/genai.js'
|
|
3
4
|
import { getTracer } from '../../telemetry/runtime-accessors.js'
|
|
4
5
|
import type { MessageId } from '../../types/ids/index.js'
|
|
5
6
|
import { type Message, createSystemMessage } from '../../types/message/index.js'
|
|
@@ -82,6 +83,7 @@ export async function* settlePreStartCancellation(
|
|
|
82
83
|
[GENAI.AGENT_ID]: params.agentId,
|
|
83
84
|
[GENAI.REQUEST_MODEL]: turnConfig.model,
|
|
84
85
|
[GENAI.SYSTEM]: params.provider.id,
|
|
86
|
+
...agentRunAttributes(params.provider.id),
|
|
85
87
|
})
|
|
86
88
|
|
|
87
89
|
const push = (message: Message, ids: ReadonlyMap<Message, MessageId>): void => {
|
|
@@ -36,10 +36,16 @@ import {
|
|
|
36
36
|
parentContext,
|
|
37
37
|
serializeSpan,
|
|
38
38
|
} from '../../telemetry/attributes.js'
|
|
39
|
+
import { agentRunAttributes } from '../../telemetry/genai.js'
|
|
39
40
|
import { getTracer } from '../../telemetry/runtime-accessors.js'
|
|
40
41
|
import { buildAdvisoryTools } from '../../tools/advisory/index.js'
|
|
41
42
|
import { SearchToolsTool } from '../../tools/builtins/search-tools.js'
|
|
42
43
|
import { createStructuredOutputTool } from '../../tools/builtins/structuredOutput.js'
|
|
44
|
+
import {
|
|
45
|
+
HAND_BACK_GUIDANCE,
|
|
46
|
+
HAND_BACK_GUIDANCE_CONTRIBUTION_ID,
|
|
47
|
+
buildHandBackTool,
|
|
48
|
+
} from '../../tools/hand-back/index.js'
|
|
43
49
|
import { buildTaskTools } from '../../tools/task/index.js'
|
|
44
50
|
import { ToolManager } from '../../toolsets/manager.js'
|
|
45
51
|
import { toolset } from '../../toolsets/toolset.js'
|
|
@@ -1283,6 +1289,10 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
|
|
|
1283
1289
|
for (const tool of taskTools) addRuntimeTool(tool, 'deferred')
|
|
1284
1290
|
}
|
|
1285
1291
|
|
|
1292
|
+
// The way out of a task that cannot be done as specified. Only when the host
|
|
1293
|
+
// turned it on; with it off the tool is absent and the prompt is as before.
|
|
1294
|
+
if (turnConfig.handBack === true) addRuntimeTool(buildHandBackTool(), 'active')
|
|
1295
|
+
|
|
1286
1296
|
// `search_tools` is added only when something could actually be
|
|
1287
1297
|
// deferred — one of the runtime tools above, or a caller toolset that
|
|
1288
1298
|
// declared itself `deferred(...)`. Nothing deferred means nothing for
|
|
@@ -1789,6 +1799,15 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
|
|
|
1789
1799
|
// The turn's own registry when the host passed none, so a hook's
|
|
1790
1800
|
// annotation has somewhere to land.
|
|
1791
1801
|
const promptContributions = params.promptContributions ?? new PromptContributionRegistry()
|
|
1802
|
+
if (turnConfig.handBack === true) {
|
|
1803
|
+
promptContributions.replace({
|
|
1804
|
+
id: HAND_BACK_GUIDANCE_CONTRIBUTION_ID,
|
|
1805
|
+
placement: 'static',
|
|
1806
|
+
render: () => HAND_BACK_GUIDANCE,
|
|
1807
|
+
})
|
|
1808
|
+
} else {
|
|
1809
|
+
promptContributions.unregister(HAND_BACK_GUIDANCE_CONTRIBUTION_ID)
|
|
1810
|
+
}
|
|
1792
1811
|
|
|
1793
1812
|
const promptBuilder = new PromptBuilder({
|
|
1794
1813
|
systemPrompt: params.systemPrompt,
|
|
@@ -2110,6 +2129,7 @@ export async function* query(params: QueryParams): AsyncGenerator<SessionEvent,
|
|
|
2110
2129
|
[GENAI.AGENT_ID]: params.agentId,
|
|
2111
2130
|
[GENAI.REQUEST_MODEL]: turnConfig.model,
|
|
2112
2131
|
[GENAI.SYSTEM]: params.provider.id,
|
|
2132
|
+
...agentRunAttributes(params.provider.id),
|
|
2113
2133
|
})
|
|
2114
2134
|
|
|
2115
2135
|
let sandbox: Sandbox | undefined
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
} from '../../../telemetry/attributes.js'
|
|
30
30
|
import { getTracer } from '../../../telemetry/runtime-accessors.js'
|
|
31
31
|
import { STRUCTURED_OUTPUT_TOOL_NAME } from '../../../tools/builtins/structuredOutput.js'
|
|
32
|
+
import { SESSION_GOAL_TOOL_NAMES } from '../../../tools/goal/index.js'
|
|
33
|
+
import { HAND_BACK_TOOL_NAME, parseHandBack } from '../../../tools/hand-back/index.js'
|
|
32
34
|
import type { ToolManager } from '../../../toolsets/manager.js'
|
|
33
35
|
import { RECALLED_MEMORY_ENTRY_KEY, recalledMemoryIds } from '../../../turn/memory-recall.js'
|
|
34
36
|
import { type CostInfo, type TokenUsage, promptSizeOf } from '../../../types/common/index.js'
|
|
@@ -48,6 +50,7 @@ import {
|
|
|
48
50
|
import { classifyProviderError, readOutputOverflow } from '../../../types/provider/errors.js'
|
|
49
51
|
import type { ChatCompletionResponse, ReasoningEffort } from '../../../types/provider/index.js'
|
|
50
52
|
import type { AnswerReview, AnswerReviewContext } from '../../../types/session/answer-review.js'
|
|
53
|
+
import type { HandBack } from '../../../types/session/hand-back.js'
|
|
51
54
|
import type {
|
|
52
55
|
RecalledMemory,
|
|
53
56
|
SessionEvent,
|
|
@@ -136,6 +139,9 @@ import {
|
|
|
136
139
|
} from './step-shaping.js'
|
|
137
140
|
import { streamProviderTurn } from './stream-turn.js'
|
|
138
141
|
|
|
142
|
+
/** Notes a host may add before a turn ends (`TurnConfig.outcome.beforeEnd`) in one turn. */
|
|
143
|
+
const MAX_BEFORE_END_NOTES = 16
|
|
144
|
+
|
|
139
145
|
/** Capped steps in a row after which the per-step cap stops applying for the turn's next step. */
|
|
140
146
|
const MAX_CAPPED_STREAK = 3
|
|
141
147
|
|
|
@@ -339,6 +345,7 @@ export class IterationOrchestrator {
|
|
|
339
345
|
private readonly completionAudit?: CompletionAudit
|
|
340
346
|
/** What the turn changed and what checked it; see {@link OutcomeLedger}. Kept whether or not the host asked. */
|
|
341
347
|
private readonly outcomeLedger: OutcomeLedger
|
|
348
|
+
private beforeEndNotes = 0
|
|
342
349
|
private outcomeHydrated = false
|
|
343
350
|
/** The next step must call a tool, at low effort: set by the stall monitor or a capped step. */
|
|
344
351
|
private forceActionNextStep = false
|
|
@@ -2016,6 +2023,14 @@ export class IterationOrchestrator {
|
|
|
2016
2023
|
recorder.pushMessage(createRuntimeContextMessage(auditReminder, 'progress-nudge'))
|
|
2017
2024
|
continue
|
|
2018
2025
|
}
|
|
2026
|
+
const endNote =
|
|
2027
|
+
!forceFinalize && closingStopReason === undefined
|
|
2028
|
+
? await this.askBeforeEnd()
|
|
2029
|
+
: undefined
|
|
2030
|
+
if (endNote !== undefined) {
|
|
2031
|
+
recorder.pushMessage(createRuntimeContextMessage(endNote, 'progress-nudge'))
|
|
2032
|
+
continue
|
|
2033
|
+
}
|
|
2019
2034
|
if (!forceFinalize && closingStopReason === undefined) {
|
|
2020
2035
|
const feedback = yield* this.askStopHooks()
|
|
2021
2036
|
const stoppedByHook = this.ctx.toolExecutor.takeHalt?.()
|
|
@@ -2074,6 +2089,28 @@ export class IterationOrchestrator {
|
|
|
2074
2089
|
if (reviewOutcome.decision === 'stop') {
|
|
2075
2090
|
return
|
|
2076
2091
|
}
|
|
2092
|
+
|
|
2093
|
+
// The model handed the task back to a person. Nothing else ran in
|
|
2094
|
+
// this step (its sibling calls were refused), and no further model
|
|
2095
|
+
// call is made: the turn ends here, as a turn that ended on its own.
|
|
2096
|
+
const handedBack = this.takeHandBack(reviewOutcome.results, response)
|
|
2097
|
+
if (handedBack !== undefined) {
|
|
2098
|
+
this.ctx.log.info('The model handed the task back — ending turn', {
|
|
2099
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
2100
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
2101
|
+
'namzu.hand_back.kind': handedBack.kind,
|
|
2102
|
+
})
|
|
2103
|
+
recorder.setHandedBack(handedBack)
|
|
2104
|
+
recorder.setStopReason('end_turn')
|
|
2105
|
+
await this.ctx.emitEvent({
|
|
2106
|
+
type: 'iteration_completed',
|
|
2107
|
+
turnId: recorder.turnId,
|
|
2108
|
+
iteration: iterationNum,
|
|
2109
|
+
hasToolCalls: true,
|
|
2110
|
+
})
|
|
2111
|
+
yield* this.ctx.drainPending()
|
|
2112
|
+
break
|
|
2113
|
+
}
|
|
2077
2114
|
const needsCorrection = await this.recordToolStructuredFailure(
|
|
2078
2115
|
reviewOutcome.results,
|
|
2079
2116
|
iterationNum,
|
|
@@ -3406,8 +3443,14 @@ export class IterationOrchestrator {
|
|
|
3406
3443
|
else this.outcomeLedger.restore(restored.snapshot)
|
|
3407
3444
|
}
|
|
3408
3445
|
|
|
3409
|
-
/**
|
|
3446
|
+
/**
|
|
3447
|
+
* Whether a call is one the outcome record may treat as only looking. The
|
|
3448
|
+
* goal tools write the goal's own record, never the workspace; counting a
|
|
3449
|
+
* report of completion as a possible change would make every check before it
|
|
3450
|
+
* read as not known to be fresh.
|
|
3451
|
+
*/
|
|
3410
3452
|
private lookedOnly(toolName: string, input: unknown): boolean {
|
|
3453
|
+
if ((SESSION_GOAL_TOOL_NAMES as readonly string[]).includes(toolName)) return true
|
|
3411
3454
|
try {
|
|
3412
3455
|
return !callChangedState(toolName, this.ctx.tools.get(toolName)?.isReadOnly?.(input), false)
|
|
3413
3456
|
} catch {
|
|
@@ -3474,6 +3517,47 @@ export class IterationOrchestrator {
|
|
|
3474
3517
|
}
|
|
3475
3518
|
}
|
|
3476
3519
|
|
|
3520
|
+
/**
|
|
3521
|
+
* The host's say before the turn ends (`TurnConfig.outcome.beforeEnd`): a note
|
|
3522
|
+
* for the model, or `undefined` to let the turn end. Bounded, and a hook that
|
|
3523
|
+
* fails never fails the turn.
|
|
3524
|
+
*/
|
|
3525
|
+
async askBeforeEnd(): Promise<string | undefined> {
|
|
3526
|
+
const hook = this.ctx.turnConfig.outcome?.beforeEnd
|
|
3527
|
+
if (hook === undefined || this.beforeEndNotes >= MAX_BEFORE_END_NOTES) return undefined
|
|
3528
|
+
try {
|
|
3529
|
+
const note = await hook(async () => {
|
|
3530
|
+
this.hydrateOutcome()
|
|
3531
|
+
return await this.outcomeLedger.preview()
|
|
3532
|
+
})
|
|
3533
|
+
if (typeof note !== 'string' || note.trim() === '') return undefined
|
|
3534
|
+
this.beforeEndNotes += 1
|
|
3535
|
+
return note
|
|
3536
|
+
} catch (err) {
|
|
3537
|
+
this.ctx.log.warn('The host hook before the turn ends failed; the turn ends', {
|
|
3538
|
+
'exception.message': toErrorMessage(err),
|
|
3539
|
+
})
|
|
3540
|
+
return undefined
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
/**
|
|
3545
|
+
* The hand-back this step made, when the setting is on and `hand_back_task`
|
|
3546
|
+
* succeeded; the first one when the model made several (the rest were refused).
|
|
3547
|
+
*/
|
|
3548
|
+
private takeHandBack(
|
|
3549
|
+
results: readonly ToolCallOutcome[],
|
|
3550
|
+
response: ChatCompletionResponse,
|
|
3551
|
+
): HandBack | undefined {
|
|
3552
|
+
if (this.ctx.turnConfig.handBack !== true) return undefined
|
|
3553
|
+
const hit = results.find(
|
|
3554
|
+
(r) => r.toolName === HAND_BACK_TOOL_NAME && r.isError !== true && r.skipped !== true,
|
|
3555
|
+
)
|
|
3556
|
+
if (!hit) return undefined
|
|
3557
|
+
const call = (response.message.toolCalls ?? []).find((c) => c.id === hit.toolCallId)
|
|
3558
|
+
return call ? parseHandBack(call.function.arguments) : undefined
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3477
3561
|
/** The outcome record as the turn leaves it; `undefined` when none was kept. */
|
|
3478
3562
|
async takeOutcome(): Promise<TurnOutcome | undefined> {
|
|
3479
3563
|
try {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { allowRuleScope } from '../../../../authorization/gate.js'
|
|
2
2
|
import type { AuthorizationGate } from '../../../../authorization/index.js'
|
|
3
|
+
import {
|
|
4
|
+
HAND_BACK_SIBLING_REFUSAL,
|
|
5
|
+
HAND_BACK_TOOL_NAME,
|
|
6
|
+
parseHandBack,
|
|
7
|
+
} from '../../../../tools/hand-back/index.js'
|
|
3
8
|
import { isTrustedReadOnly } from '../../../../tools/trusted-read-only.js'
|
|
4
9
|
import type { ToolSourceRef } from '../../../../toolsets/types.js'
|
|
5
10
|
import type {
|
|
@@ -259,7 +264,25 @@ export async function* runToolReview(
|
|
|
259
264
|
* with the tracker's refusal instead of being run — the one denial the
|
|
260
265
|
* tracker makes, on top of whatever the caller already denied.
|
|
261
266
|
*/
|
|
262
|
-
const withRepeatRefusals = (
|
|
267
|
+
const withRepeatRefusals = (given?: ToolCallDenials): ToolCallDenials | undefined => {
|
|
268
|
+
// A step that hands the task back runs nothing else: the first hand-back
|
|
269
|
+
// call is the step, every other call in it is refused.
|
|
270
|
+
let denials = given
|
|
271
|
+
if (ctx.turnConfig?.handBack === true) {
|
|
272
|
+
const handBack = toolCallSummaries.find(
|
|
273
|
+
(summary) =>
|
|
274
|
+
summary.name === HAND_BACK_TOOL_NAME && parseHandBack(summary.input) !== undefined,
|
|
275
|
+
)
|
|
276
|
+
if (handBack) {
|
|
277
|
+
let siblings: Map<string, string> | undefined
|
|
278
|
+
for (const summary of toolCallSummaries) {
|
|
279
|
+
if (summary.id === handBack.id || given?.has(summary.id)) continue
|
|
280
|
+
siblings ??= new Map(given ?? [])
|
|
281
|
+
siblings.set(summary.id, HAND_BACK_SIBLING_REFUSAL)
|
|
282
|
+
}
|
|
283
|
+
denials = siblings ?? given
|
|
284
|
+
}
|
|
285
|
+
}
|
|
263
286
|
const tracker = ctx.repeatCalls
|
|
264
287
|
if (!tracker) return denials
|
|
265
288
|
let merged: Map<string, string> | undefined
|
|
@@ -15,6 +15,12 @@ import {
|
|
|
15
15
|
toolCallFramingViolation,
|
|
16
16
|
} from '../../../provider/tool-call-framing.js'
|
|
17
17
|
import { GENAI, NAMZU, chatSpanName, parentContext } from '../../../telemetry/attributes.js'
|
|
18
|
+
import {
|
|
19
|
+
chatStartAttributes,
|
|
20
|
+
chatUsageAttributes,
|
|
21
|
+
errorTypeAttributes,
|
|
22
|
+
genAiErrorType,
|
|
23
|
+
} from '../../../telemetry/genai.js'
|
|
18
24
|
import {
|
|
19
25
|
recordModelDuration,
|
|
20
26
|
recordTimeToFirstToken,
|
|
@@ -200,6 +206,7 @@ async function settleCancelledTurn(args: {
|
|
|
200
206
|
[GENAI.USAGE_OUTPUT_TOKENS]: args.usage.completionTokens,
|
|
201
207
|
[NAMZU.CACHE_READ_TOKENS]: args.usage.cachedTokens ?? 0,
|
|
202
208
|
[NAMZU.CACHE_WRITE_TOKENS]: args.usage.cacheWriteTokens ?? 0,
|
|
209
|
+
...chatUsageAttributes(args.usage),
|
|
203
210
|
})
|
|
204
211
|
args.span.setStatus({ code: SpanStatusCode.OK })
|
|
205
212
|
args.span.end()
|
|
@@ -277,6 +284,7 @@ export async function* streamProviderTurn(
|
|
|
277
284
|
? { [GENAI.REQUEST_TEMPERATURE]: params.temperature }
|
|
278
285
|
: {}),
|
|
279
286
|
...(params.maxTokens !== undefined ? { [GENAI.REQUEST_MAX_TOKENS]: params.maxTokens } : {}),
|
|
287
|
+
...chatStartAttributes(provider.id),
|
|
280
288
|
})
|
|
281
289
|
|
|
282
290
|
const messageId = announceAs ?? generateMessageId()
|
|
@@ -1053,6 +1061,7 @@ export async function* streamProviderTurn(
|
|
|
1053
1061
|
yield* drainPending()
|
|
1054
1062
|
|
|
1055
1063
|
if (streamError && !recoveredToolInputFromStreamError) {
|
|
1064
|
+
chatSpan.setAttributes(errorTypeAttributes(genAiErrorType(streamCause)))
|
|
1056
1065
|
chatSpan.setStatus({ code: SpanStatusCode.ERROR, message: streamError })
|
|
1057
1066
|
chatSpan.end()
|
|
1058
1067
|
|
|
@@ -1132,6 +1141,7 @@ export async function* streamProviderTurn(
|
|
|
1132
1141
|
[GENAI.USAGE_OUTPUT_TOKENS]: usage.completionTokens,
|
|
1133
1142
|
[NAMZU.CACHE_READ_TOKENS]: usage.cachedTokens ?? 0,
|
|
1134
1143
|
[NAMZU.CACHE_WRITE_TOKENS]: usage.cacheWriteTokens ?? 0,
|
|
1144
|
+
...chatUsageAttributes(usage),
|
|
1135
1145
|
})
|
|
1136
1146
|
chatSpan.setStatus({ code: SpanStatusCode.OK })
|
|
1137
1147
|
chatSpan.end()
|
|
@@ -5,6 +5,7 @@ import { isCallerAbortError, isProviderRequestError } from '../../provider/error
|
|
|
5
5
|
import { TokenBudgetAdmissionError } from '../../provider/token-budget.js'
|
|
6
6
|
import type { ActivityStore } from '../../store/activity/memory.js'
|
|
7
7
|
import { GENAI, NAMZU } from '../../telemetry/attributes.js'
|
|
8
|
+
import { errorTypeAttributes, genAiErrorType } from '../../telemetry/genai.js'
|
|
8
9
|
import { explainError } from '../../types/errors/catalog.js'
|
|
9
10
|
import { toPlatformError } from '../../types/errors/index.js'
|
|
10
11
|
import type { CheckpointId } from '../../types/hitl/index.js'
|
|
@@ -211,6 +212,7 @@ export class ResultAssembler {
|
|
|
211
212
|
rootSpan.setAttributes({
|
|
212
213
|
[NAMZU.TURN_STATUS]: 'error',
|
|
213
214
|
[NAMZU.ITERATION]: recorder.currentIteration,
|
|
215
|
+
...errorTypeAttributes(genAiErrorType(err)),
|
|
214
216
|
})
|
|
215
217
|
rootSpan.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage })
|
|
216
218
|
rootSpan.recordException(err instanceof Error ? err : new Error(errorMessage))
|