@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
|
@@ -34,6 +34,7 @@ export type {
|
|
|
34
34
|
} from './era.js'
|
|
35
35
|
export { buildEnvelope, decodeResult, encodeMcpHeaderValue } from './envelope.js'
|
|
36
36
|
export type { McpEnvelope, McpEnvelopeInput, MCPDecodedResult } from './envelope.js'
|
|
37
|
+
export { MCP_TASKS_EXTENSION } from './tasks.js'
|
|
37
38
|
|
|
38
39
|
// The repo's first refusal path: a tool definition namzu declines to expose.
|
|
39
40
|
// Exported so a host can ask the same question of a schema it holds — and
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { MCPInputRequest } from '../../types/connector/index.js'
|
|
2
|
+
|
|
3
|
+
/** The extension's identifier, in both the client's and the server's `extensions`. */
|
|
4
|
+
export const MCP_TASKS_EXTENSION = 'io.modelcontextprotocol/tasks'
|
|
5
|
+
|
|
6
|
+
/** Poll no faster than this whatever the server suggests, and no slower than the cap. */
|
|
7
|
+
export const MCP_TASK_MIN_POLL_MS = 100
|
|
8
|
+
export const MCP_TASK_MAX_POLL_MS = 30_000
|
|
9
|
+
/** The interval used when the server names none. */
|
|
10
|
+
export const MCP_TASK_DEFAULT_POLL_MS = 1_000
|
|
11
|
+
|
|
12
|
+
export type MCPTaskStatus = 'working' | 'input_required' | 'completed' | 'failed' | 'cancelled'
|
|
13
|
+
|
|
14
|
+
/** One reading of a task: what `CreateTaskResult` and a `tasks/get` result both carry. */
|
|
15
|
+
export interface MCPTaskState {
|
|
16
|
+
readonly taskId: string
|
|
17
|
+
readonly status: MCPTaskStatus
|
|
18
|
+
readonly statusMessage?: string
|
|
19
|
+
readonly lastUpdatedAt?: string
|
|
20
|
+
readonly pollIntervalMs?: number
|
|
21
|
+
/** `input_required`: what the server wants, as `{ method }` entries. */
|
|
22
|
+
readonly inputRequests?: readonly MCPInputRequest[]
|
|
23
|
+
/** `completed`: the result the original request would have returned. */
|
|
24
|
+
readonly result?: unknown
|
|
25
|
+
/** `failed`: the JSON-RPC error. */
|
|
26
|
+
readonly error?: { readonly code?: unknown; readonly message?: unknown; readonly data?: unknown }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const STATUSES = new Set<string>(['working', 'input_required', 'completed', 'failed', 'cancelled'])
|
|
30
|
+
|
|
31
|
+
/** Is this result a task handle rather than a result? */
|
|
32
|
+
export function isCreateTaskResult(raw: unknown): boolean {
|
|
33
|
+
return (
|
|
34
|
+
typeof raw === 'object' &&
|
|
35
|
+
raw !== null &&
|
|
36
|
+
(raw as { resultType?: unknown }).resultType === 'task'
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read a `CreateTaskResult` or a `tasks/get` result, or refuse it.
|
|
42
|
+
*
|
|
43
|
+
* Returns `undefined` for anything that is not a task with a non-empty
|
|
44
|
+
* `taskId` and a status the extension defines, so a malformed answer ends the
|
|
45
|
+
* wait with a clear error instead of polling a handle nobody can name.
|
|
46
|
+
*/
|
|
47
|
+
export function decodeTaskState(raw: unknown): MCPTaskState | undefined {
|
|
48
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined
|
|
49
|
+
const r = raw as Record<string, unknown>
|
|
50
|
+
if (typeof r.taskId !== 'string' || r.taskId.length === 0) return undefined
|
|
51
|
+
if (typeof r.status !== 'string' || !STATUSES.has(r.status)) return undefined
|
|
52
|
+
const inputRequests =
|
|
53
|
+
typeof r.inputRequests === 'object' && r.inputRequests !== null
|
|
54
|
+
? Object.values(r.inputRequests as Record<string, unknown>).filter(
|
|
55
|
+
(item): item is MCPInputRequest =>
|
|
56
|
+
typeof item === 'object' &&
|
|
57
|
+
item !== null &&
|
|
58
|
+
typeof (item as { method?: unknown }).method === 'string',
|
|
59
|
+
)
|
|
60
|
+
: undefined
|
|
61
|
+
return {
|
|
62
|
+
taskId: r.taskId,
|
|
63
|
+
status: r.status as MCPTaskStatus,
|
|
64
|
+
...(typeof r.statusMessage === 'string' ? { statusMessage: r.statusMessage } : {}),
|
|
65
|
+
...(typeof r.lastUpdatedAt === 'string' ? { lastUpdatedAt: r.lastUpdatedAt } : {}),
|
|
66
|
+
...(typeof r.pollIntervalMs === 'number' && Number.isFinite(r.pollIntervalMs)
|
|
67
|
+
? { pollIntervalMs: r.pollIntervalMs }
|
|
68
|
+
: {}),
|
|
69
|
+
...(inputRequests ? { inputRequests } : {}),
|
|
70
|
+
...('result' in r ? { result: r.result } : {}),
|
|
71
|
+
...(typeof r.error === 'object' && r.error !== null
|
|
72
|
+
? { error: r.error as MCPTaskState['error'] }
|
|
73
|
+
: {}),
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** How long to wait before the next `tasks/get`, from what the server last suggested. */
|
|
78
|
+
export function taskPollDelayMs(suggested: number | undefined): number {
|
|
79
|
+
const wanted = suggested ?? MCP_TASK_DEFAULT_POLL_MS
|
|
80
|
+
return Math.min(Math.max(wanted, MCP_TASK_MIN_POLL_MS), MCP_TASK_MAX_POLL_MS)
|
|
81
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data epoch: which generation of on-disk formats this engine writes.
|
|
3
|
+
*
|
|
4
|
+
* One integer, told to a host's client in the answer to `initialize`
|
|
5
|
+
* (`kernel.dataEpoch`). A program that keeps several engines side by side and
|
|
6
|
+
* lets them share one person's conversations compares it: two engines with the
|
|
7
|
+
* same epoch can read and write each other's files; two with different epochs
|
|
8
|
+
* may not.
|
|
9
|
+
*
|
|
10
|
+
* Raise it when an older engine can no longer safely read or write what this
|
|
11
|
+
* one writes: a stamped store moves to a version the older one refuses, a
|
|
12
|
+
* format gains a field the older one would drop or misread, a file is renamed
|
|
13
|
+
* or moved. Do not raise it for a change an older engine ignores or reads the
|
|
14
|
+
* same way. The inventory of formats, and the test that makes a change to a
|
|
15
|
+
* stamped version a decision, are in `docs/sdk/kernel-facts.md`.
|
|
16
|
+
*/
|
|
17
|
+
export const DATA_EPOCH = 1
|
package/src/constants/index.ts
CHANGED
|
@@ -177,8 +177,13 @@ export const MCP_PARAM_HEADER_PREFIX = 'Mcp-Param-'
|
|
|
177
177
|
* WHICH tool is being called without reading the body is the whole point of
|
|
178
178
|
* mirroring it into a header.
|
|
179
179
|
*/
|
|
180
|
-
export const MCP_NAME_HEADER_METHODS: Readonly<Record<string, 'name' | 'uri'>> = {
|
|
180
|
+
export const MCP_NAME_HEADER_METHODS: Readonly<Record<string, 'name' | 'uri' | 'taskId'>> = {
|
|
181
181
|
'tools/call': 'name',
|
|
182
182
|
'prompts/get': 'name',
|
|
183
183
|
'resources/read': 'uri',
|
|
184
|
+
// The tasks extension: an intermediary routes a task's requests to the
|
|
185
|
+
// instance that holds it, by this header.
|
|
186
|
+
'tasks/get': 'taskId',
|
|
187
|
+
'tasks/update': 'taskId',
|
|
188
|
+
'tasks/cancel': 'taskId',
|
|
184
189
|
}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
export const GENAI = {
|
|
2
2
|
OPERATION_NAME: 'gen_ai.operation.name',
|
|
3
|
+
/**
|
|
4
|
+
* Namzu's own provider id. Not in the pinned
|
|
5
|
+
* GenAI convention, which names the provider with {@link GENAI.PROVIDER_NAME}.
|
|
6
|
+
* Kept because it is existing output.
|
|
7
|
+
*/
|
|
3
8
|
SYSTEM: 'gen_ai.system',
|
|
4
9
|
|
|
10
|
+
/** Convention `gen_ai.provider.name`: set only when our provider id maps to a value the convention lists. */
|
|
11
|
+
PROVIDER_NAME: 'gen_ai.provider.name',
|
|
12
|
+
/** `true` on a model call made in streaming mode. */
|
|
13
|
+
REQUEST_STREAM: 'gen_ai.request.stream',
|
|
14
|
+
|
|
5
15
|
REQUEST_MODEL: 'gen_ai.request.model',
|
|
6
16
|
REQUEST_TEMPERATURE: 'gen_ai.request.temperature',
|
|
7
17
|
REQUEST_MAX_TOKENS: 'gen_ai.request.max_tokens',
|
|
@@ -12,6 +22,9 @@ export const GENAI = {
|
|
|
12
22
|
|
|
13
23
|
USAGE_INPUT_TOKENS: 'gen_ai.usage.input_tokens',
|
|
14
24
|
USAGE_OUTPUT_TOKENS: 'gen_ai.usage.output_tokens',
|
|
25
|
+
USAGE_CACHE_READ_INPUT_TOKENS: 'gen_ai.usage.cache_read.input_tokens',
|
|
26
|
+
USAGE_CACHE_CREATION_INPUT_TOKENS: 'gen_ai.usage.cache_creation.input_tokens',
|
|
27
|
+
USAGE_REASONING_OUTPUT_TOKENS: 'gen_ai.usage.reasoning.output_tokens',
|
|
15
28
|
|
|
16
29
|
/**
|
|
17
30
|
* Which kind of token a usage measurement counts. The convention keys
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intervals for an eval, by resampling cases.
|
|
3
|
+
*
|
|
4
|
+
* A pass rate printed alone invites conclusions the data cannot carry: on 80
|
|
5
|
+
* tasks a difference of -1.25 points came with a 95% interval from -10.0 to
|
|
6
|
+
* +7.5, which says almost nothing. The interval here is a percentile
|
|
7
|
+
* bootstrap over CASES. A case is the unit that was sampled from the world, so
|
|
8
|
+
* a case is what gets resampled, and all of a case's repeats travel with it:
|
|
9
|
+
* repeats of one case are not independent evidence about the suite, and
|
|
10
|
+
* treating them as such would narrow the interval for free.
|
|
11
|
+
*
|
|
12
|
+
* Nothing in here reads the clock or an unseeded random source. The generator
|
|
13
|
+
* is a small deterministic one fed by a seed that the report records, so the
|
|
14
|
+
* same cases and the same seed give the same interval.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Fewest cases an interval is computed for. Below it the report says why. */
|
|
18
|
+
export const MIN_CASES_FOR_INTERVAL = 5
|
|
19
|
+
|
|
20
|
+
/** Resamples drawn per interval. */
|
|
21
|
+
export const BOOTSTRAP_RESAMPLES = 2000
|
|
22
|
+
|
|
23
|
+
/** The seed used when none is given. A fixed number, so a report is reproducible. */
|
|
24
|
+
export const DEFAULT_EVAL_SEED = 1
|
|
25
|
+
|
|
26
|
+
/** Coverage of every interval in this module. */
|
|
27
|
+
export const INTERVAL_LEVEL = 0.95
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* What one case contributes: the sum of its judged runs' scores, how many of
|
|
31
|
+
* those runs passed, and how many were judged at all. `judged` is at least 1;
|
|
32
|
+
* a case with no judged run has nothing to say and is left out by the caller.
|
|
33
|
+
*/
|
|
34
|
+
export interface CaseTally {
|
|
35
|
+
readonly scoreSum: number
|
|
36
|
+
readonly passes: number
|
|
37
|
+
readonly judged: number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* An interval, or the reason there is none.
|
|
42
|
+
*
|
|
43
|
+
* `estimate` is the number the interval is around, and is present even when
|
|
44
|
+
* no interval is computed, so a reader always has the point value and the
|
|
45
|
+
* explanation for why it carries no bounds.
|
|
46
|
+
*/
|
|
47
|
+
export type Interval =
|
|
48
|
+
| {
|
|
49
|
+
readonly computed: true
|
|
50
|
+
readonly estimate: number
|
|
51
|
+
readonly low: number
|
|
52
|
+
readonly high: number
|
|
53
|
+
}
|
|
54
|
+
| {
|
|
55
|
+
readonly computed: false
|
|
56
|
+
readonly estimate: number | null
|
|
57
|
+
readonly reason: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The method and its settings, written next to the numbers so they can be reproduced. */
|
|
61
|
+
export interface BootstrapMethod {
|
|
62
|
+
readonly kind: 'percentile bootstrap over cases, repeats kept together'
|
|
63
|
+
readonly level: typeof INTERVAL_LEVEL
|
|
64
|
+
readonly resamples: number
|
|
65
|
+
readonly seed: number
|
|
66
|
+
/** Cases the interval was drawn over. */
|
|
67
|
+
readonly cases: number
|
|
68
|
+
readonly minimumCases: number
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface CaseIntervals {
|
|
72
|
+
readonly method: BootstrapMethod
|
|
73
|
+
/** Mean score over judged runs. */
|
|
74
|
+
readonly mean: Interval
|
|
75
|
+
/** Passed runs over judged runs. */
|
|
76
|
+
readonly passRate: Interval
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The same for a paired difference, second side minus first. */
|
|
80
|
+
export interface DifferenceIntervals {
|
|
81
|
+
readonly method: BootstrapMethod
|
|
82
|
+
readonly mean: Interval
|
|
83
|
+
readonly passRate: Interval
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A bad `--repeat` or `--seed`. A RangeError, so existing handlers still see
|
|
88
|
+
* one, and marked with a code so a CLI can tell it from a RangeError a suite's
|
|
89
|
+
* own code threw (and from one thrown by another copy of this class).
|
|
90
|
+
*/
|
|
91
|
+
export class EvalUsageError extends RangeError {
|
|
92
|
+
readonly code = 'EVAL_USAGE'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** True for an {@link EvalUsageError}, even one built by another copy of the SDK. */
|
|
96
|
+
export function isEvalUsageError(err: unknown): err is EvalUsageError {
|
|
97
|
+
return err instanceof RangeError && (err as { code?: unknown }).code === 'EVAL_USAGE'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Validate a seed: an integer that fits in 32 bits, unsigned.
|
|
102
|
+
* Thrown as an EvalUsageError so a CLI can turn it into a usage error.
|
|
103
|
+
*/
|
|
104
|
+
export function validateSeed(value: number | undefined): number {
|
|
105
|
+
if (value === undefined) return DEFAULT_EVAL_SEED
|
|
106
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
|
|
107
|
+
throw new EvalUsageError(
|
|
108
|
+
`seed must be an integer from 0 to 4294967295, or omitted; received ${String(value)}`,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
return value
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* mulberry32: a 32-bit generator with one word of state. Not for secrets;
|
|
116
|
+
* its job is to be the same on every machine for a given seed.
|
|
117
|
+
*/
|
|
118
|
+
export function createSeededRandom(seed: number): () => number {
|
|
119
|
+
let state = validateSeed(seed) >>> 0
|
|
120
|
+
return () => {
|
|
121
|
+
state = (state + 0x6d2b79f5) >>> 0
|
|
122
|
+
let t = state
|
|
123
|
+
t = Math.imul(t ^ (t >>> 15), t | 1)
|
|
124
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
|
|
125
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function quantile(sorted: Float64Array, p: number): number {
|
|
130
|
+
const position = p * (sorted.length - 1)
|
|
131
|
+
const lower = Math.floor(position)
|
|
132
|
+
const upper = Math.ceil(position)
|
|
133
|
+
const low = sorted[lower] as number
|
|
134
|
+
const high = sorted[upper] as number
|
|
135
|
+
return low + (high - low) * (position - lower)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Draw `resamples` samples of `n` indices with replacement, hand each to
|
|
140
|
+
* `statistics`, and return the 2.5th and 97.5th percentiles of the two numbers
|
|
141
|
+
* it returns. Both statistics see the same draw, so the two intervals come
|
|
142
|
+
* from one set of resampled suites.
|
|
143
|
+
*/
|
|
144
|
+
function bootstrap(
|
|
145
|
+
n: number,
|
|
146
|
+
seed: number,
|
|
147
|
+
statistics: (draw: Int32Array) => readonly [number, number],
|
|
148
|
+
): { mean: [number, number]; passRate: [number, number] } {
|
|
149
|
+
const random = createSeededRandom(seed)
|
|
150
|
+
const draw = new Int32Array(n)
|
|
151
|
+
const means = new Float64Array(BOOTSTRAP_RESAMPLES)
|
|
152
|
+
const rates = new Float64Array(BOOTSTRAP_RESAMPLES)
|
|
153
|
+
for (let b = 0; b < BOOTSTRAP_RESAMPLES; b++) {
|
|
154
|
+
for (let i = 0; i < n; i++) draw[i] = Math.floor(random() * n)
|
|
155
|
+
const [mean, rate] = statistics(draw)
|
|
156
|
+
means[b] = mean
|
|
157
|
+
rates[b] = rate
|
|
158
|
+
}
|
|
159
|
+
means.sort()
|
|
160
|
+
rates.sort()
|
|
161
|
+
const lowP = (1 - INTERVAL_LEVEL) / 2
|
|
162
|
+
const highP = 1 - lowP
|
|
163
|
+
return {
|
|
164
|
+
mean: [quantile(means, lowP), quantile(means, highP)],
|
|
165
|
+
passRate: [quantile(rates, lowP), quantile(rates, highP)],
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function methodOf(seed: number, cases: number): BootstrapMethod {
|
|
170
|
+
return {
|
|
171
|
+
kind: 'percentile bootstrap over cases, repeats kept together',
|
|
172
|
+
level: INTERVAL_LEVEL,
|
|
173
|
+
resamples: BOOTSTRAP_RESAMPLES,
|
|
174
|
+
seed,
|
|
175
|
+
cases,
|
|
176
|
+
minimumCases: MIN_CASES_FOR_INTERVAL,
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function tooFew(one: string, many: string, n: number): string {
|
|
181
|
+
return `only ${n} ${n === 1 ? one : many}; an interval needs at least ${MIN_CASES_FOR_INTERVAL}`
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function pooledMeanAndRate(
|
|
185
|
+
tallies: readonly CaseTally[],
|
|
186
|
+
draw?: Int32Array,
|
|
187
|
+
): [number, number] {
|
|
188
|
+
let score = 0
|
|
189
|
+
let passes = 0
|
|
190
|
+
let judged = 0
|
|
191
|
+
const count = draw ? draw.length : tallies.length
|
|
192
|
+
for (let i = 0; i < count; i++) {
|
|
193
|
+
const t = tallies[draw ? (draw[i] as number) : i] as CaseTally
|
|
194
|
+
score += t.scoreSum
|
|
195
|
+
passes += t.passes
|
|
196
|
+
judged += t.judged
|
|
197
|
+
}
|
|
198
|
+
return judged === 0 ? [Number.NaN, Number.NaN] : [score / judged, passes / judged]
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 95% intervals for the mean score and the pass rate over a set of cases.
|
|
203
|
+
*
|
|
204
|
+
* Each resample draws as many cases as there are, with replacement, and pools
|
|
205
|
+
* their runs. Cases without a judged run must not be passed in.
|
|
206
|
+
*/
|
|
207
|
+
export function bootstrapCases(tallies: readonly CaseTally[], seed: number): CaseIntervals {
|
|
208
|
+
const checked = validateSeed(seed)
|
|
209
|
+
const n = tallies.length
|
|
210
|
+
const method = methodOf(checked, n)
|
|
211
|
+
const [meanEstimate, rateEstimate] = n === 0 ? [null, null] : pooledMeanAndRate(tallies)
|
|
212
|
+
if (n < MIN_CASES_FOR_INTERVAL) {
|
|
213
|
+
const reason = tooFew('case with a judged run', 'cases with a judged run', n)
|
|
214
|
+
return {
|
|
215
|
+
method,
|
|
216
|
+
mean: { computed: false, estimate: meanEstimate, reason },
|
|
217
|
+
passRate: { computed: false, estimate: rateEstimate, reason },
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const result = bootstrap(n, checked, (draw) => pooledMeanAndRate(tallies, draw))
|
|
221
|
+
return {
|
|
222
|
+
method,
|
|
223
|
+
mean: {
|
|
224
|
+
computed: true,
|
|
225
|
+
estimate: meanEstimate as number,
|
|
226
|
+
low: result.mean[0],
|
|
227
|
+
high: result.mean[1],
|
|
228
|
+
},
|
|
229
|
+
passRate: {
|
|
230
|
+
computed: true,
|
|
231
|
+
estimate: rateEstimate as number,
|
|
232
|
+
low: result.passRate[0],
|
|
233
|
+
high: result.passRate[1],
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** One case seen from both sides of a comparison. */
|
|
239
|
+
export interface PairedTally {
|
|
240
|
+
readonly a: CaseTally
|
|
241
|
+
readonly b: CaseTally
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 95% intervals for the difference of two runs over the same cases, `b` minus
|
|
246
|
+
* `a`. A resample draws PAIRS, so the two sides of a case always travel
|
|
247
|
+
* together; that is what makes the interval a paired one, and it is much
|
|
248
|
+
* narrower than two separate intervals when the cases are the thing that
|
|
249
|
+
* varies.
|
|
250
|
+
*/
|
|
251
|
+
export function bootstrapPairedDifference(
|
|
252
|
+
pairs: readonly PairedTally[],
|
|
253
|
+
seed: number,
|
|
254
|
+
): DifferenceIntervals {
|
|
255
|
+
const checked = validateSeed(seed)
|
|
256
|
+
const n = pairs.length
|
|
257
|
+
const method = methodOf(checked, n)
|
|
258
|
+
const aSide = pairs.map((p) => p.a)
|
|
259
|
+
const bSide = pairs.map((p) => p.b)
|
|
260
|
+
const difference = (draw?: Int32Array): [number, number] => {
|
|
261
|
+
const [bMean, bRate] = pooledMeanAndRate(bSide, draw)
|
|
262
|
+
const [aMean, aRate] = pooledMeanAndRate(aSide, draw)
|
|
263
|
+
return [bMean - aMean, bRate - aRate]
|
|
264
|
+
}
|
|
265
|
+
const [meanEstimate, rateEstimate] = n === 0 ? [null, null] : difference()
|
|
266
|
+
if (n < MIN_CASES_FOR_INTERVAL) {
|
|
267
|
+
const reason = tooFew('paired case', 'paired cases', n)
|
|
268
|
+
return {
|
|
269
|
+
method,
|
|
270
|
+
mean: { computed: false, estimate: meanEstimate, reason },
|
|
271
|
+
passRate: { computed: false, estimate: rateEstimate, reason },
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const result = bootstrap(n, checked, (draw) => difference(draw))
|
|
275
|
+
return {
|
|
276
|
+
method,
|
|
277
|
+
mean: {
|
|
278
|
+
computed: true,
|
|
279
|
+
estimate: meanEstimate as number,
|
|
280
|
+
low: result.mean[0],
|
|
281
|
+
high: result.mean[1],
|
|
282
|
+
},
|
|
283
|
+
passRate: {
|
|
284
|
+
computed: true,
|
|
285
|
+
estimate: rateEstimate as number,
|
|
286
|
+
low: result.passRate[0],
|
|
287
|
+
high: result.passRate[1],
|
|
288
|
+
},
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Exact two-sided sign test on discordant pairs: under no difference each flip
|
|
294
|
+
* is equally likely to go either way, so the count going one way is
|
|
295
|
+
* Binomial(n, 1/2). Returns twice the smaller tail, capped at 1; with no flips
|
|
296
|
+
* at all the answer is 1.
|
|
297
|
+
*/
|
|
298
|
+
export function exactSignTestP(oneWay: number, otherWay: number): number {
|
|
299
|
+
const n = oneWay + otherWay
|
|
300
|
+
if (n === 0) return 1
|
|
301
|
+
const k = Math.min(oneWay, otherWay)
|
|
302
|
+
const logFactorial = new Float64Array(n + 1)
|
|
303
|
+
for (let i = 2; i <= n; i++) logFactorial[i] = (logFactorial[i - 1] as number) + Math.log(i)
|
|
304
|
+
let tail = 0
|
|
305
|
+
for (let i = 0; i <= k; i++) {
|
|
306
|
+
const logTerm =
|
|
307
|
+
(logFactorial[n] as number) -
|
|
308
|
+
(logFactorial[i] as number) -
|
|
309
|
+
(logFactorial[n - i] as number) -
|
|
310
|
+
n * Math.LN2
|
|
311
|
+
tail += Math.exp(logTerm)
|
|
312
|
+
}
|
|
313
|
+
return Math.min(1, 2 * tail)
|
|
314
|
+
}
|