@adonis-agora/agent 0.30.2 → 0.33.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 +866 -0
- package/dist/assets/spa/assets/{index-Cfi3g3b2.js → index-3Q2m5_Ax.js} +1 -1
- package/dist/assets/spa/index.html +1 -1
- package/dist/providers/agent_provider.d.ts.map +1 -1
- package/dist/providers/agent_provider.js +157 -9
- package/dist/providers/agent_provider.js.map +1 -1
- package/dist/src/agent-deps-factory.d.ts +16 -2
- package/dist/src/agent-deps-factory.d.ts.map +1 -1
- package/dist/src/agent-deps-factory.js +8 -0
- package/dist/src/agent-deps-factory.js.map +1 -1
- package/dist/src/agent-deps.d.ts +21 -1
- package/dist/src/agent-deps.d.ts.map +1 -1
- package/dist/src/agent-deps.js.map +1 -1
- package/dist/src/agent-loop.d.ts +226 -9
- package/dist/src/agent-loop.d.ts.map +1 -1
- package/dist/src/agent-loop.js +1311 -208
- package/dist/src/agent-loop.js.map +1 -1
- package/dist/src/agent-service.d.ts +27 -0
- package/dist/src/agent-service.d.ts.map +1 -1
- package/dist/src/agent-service.js +29 -0
- package/dist/src/agent-service.js.map +1 -1
- package/dist/src/ai-sdk/ai-sdk-model.d.ts.map +1 -1
- package/dist/src/ai-sdk/ai-sdk-model.js +21 -1
- package/dist/src/ai-sdk/ai-sdk-model.js.map +1 -1
- package/dist/src/client/sse.d.ts +32 -2
- package/dist/src/client/sse.d.ts.map +1 -1
- package/dist/src/client/sse.js +45 -2
- package/dist/src/client/sse.js.map +1 -1
- package/dist/src/define_config.d.ts +41 -7
- package/dist/src/define_config.d.ts.map +1 -1
- package/dist/src/define_config.js.map +1 -1
- package/dist/src/durable/agent-run-workflow.d.ts +10 -11
- package/dist/src/durable/agent-run-workflow.d.ts.map +1 -1
- package/dist/src/durable/agent-run-workflow.js +49 -21
- package/dist/src/durable/agent-run-workflow.js.map +1 -1
- package/dist/src/durable/durable-agent-runner.d.ts +3 -2
- package/dist/src/durable/durable-agent-runner.d.ts.map +1 -1
- package/dist/src/durable/durable-agent-runner.js +2 -2
- package/dist/src/durable/durable-agent-runner.js.map +1 -1
- package/dist/src/elicitation.d.ts +207 -0
- package/dist/src/elicitation.d.ts.map +1 -0
- package/dist/src/elicitation.js +315 -0
- package/dist/src/elicitation.js.map +1 -0
- package/dist/src/evals/approval-prior.d.ts +58 -0
- package/dist/src/evals/approval-prior.d.ts.map +1 -0
- package/dist/src/evals/approval-prior.js +82 -0
- package/dist/src/evals/approval-prior.js.map +1 -0
- package/dist/src/evals/evaluate.d.ts +51 -0
- package/dist/src/evals/evaluate.d.ts.map +1 -0
- package/dist/src/evals/evaluate.js +76 -0
- package/dist/src/evals/evaluate.js.map +1 -0
- package/dist/src/evals/governance-sample-source.d.ts +23 -0
- package/dist/src/evals/governance-sample-source.d.ts.map +1 -0
- package/dist/src/evals/governance-sample-source.js +93 -0
- package/dist/src/evals/governance-sample-source.js.map +1 -0
- package/dist/src/evals/in-memory-score-store.d.ts +16 -0
- package/dist/src/evals/in-memory-score-store.d.ts.map +1 -0
- package/dist/src/evals/in-memory-score-store.js +57 -0
- package/dist/src/evals/in-memory-score-store.js.map +1 -0
- package/dist/src/evals/index.d.ts +15 -0
- package/dist/src/evals/index.d.ts.map +1 -0
- package/dist/src/evals/index.js +14 -0
- package/dist/src/evals/index.js.map +1 -0
- package/dist/src/evals/judge.d.ts +30 -0
- package/dist/src/evals/judge.d.ts.map +1 -0
- package/dist/src/evals/judge.js +53 -0
- package/dist/src/evals/judge.js.map +1 -0
- package/dist/src/evals/live-scoring.d.ts +42 -0
- package/dist/src/evals/live-scoring.d.ts.map +1 -0
- package/dist/src/evals/live-scoring.js +103 -0
- package/dist/src/evals/live-scoring.js.map +1 -0
- package/dist/src/evals/sample-source.d.ts +40 -0
- package/dist/src/evals/sample-source.d.ts.map +1 -0
- package/dist/src/evals/sample-source.js +33 -0
- package/dist/src/evals/sample-source.js.map +1 -0
- package/dist/src/evals/score-store.d.ts +54 -0
- package/dist/src/evals/score-store.d.ts.map +1 -0
- package/dist/src/evals/score-store.js +2 -0
- package/dist/src/evals/score-store.js.map +1 -0
- package/dist/src/evals/scorers/answer-relevancy.scorer.d.ts +28 -0
- package/dist/src/evals/scorers/answer-relevancy.scorer.d.ts.map +1 -0
- package/dist/src/evals/scorers/answer-relevancy.scorer.js +42 -0
- package/dist/src/evals/scorers/answer-relevancy.scorer.js.map +1 -0
- package/dist/src/evals/scorers/approval-outcome.scorer.d.ts +22 -0
- package/dist/src/evals/scorers/approval-outcome.scorer.d.ts.map +1 -0
- package/dist/src/evals/scorers/approval-outcome.scorer.js +60 -0
- package/dist/src/evals/scorers/approval-outcome.scorer.js.map +1 -0
- package/dist/src/evals/scorers/approval-risk.scorer.d.ts +28 -0
- package/dist/src/evals/scorers/approval-risk.scorer.d.ts.map +1 -0
- package/dist/src/evals/scorers/approval-risk.scorer.js +54 -0
- package/dist/src/evals/scorers/approval-risk.scorer.js.map +1 -0
- package/dist/src/evals/scorers/run-completion.scorer.d.ts +18 -0
- package/dist/src/evals/scorers/run-completion.scorer.d.ts.map +1 -0
- package/dist/src/evals/scorers/run-completion.scorer.js +55 -0
- package/dist/src/evals/scorers/run-completion.scorer.js.map +1 -0
- package/dist/src/evals/summarize.d.ts +44 -0
- package/dist/src/evals/summarize.d.ts.map +1 -0
- package/dist/src/evals/summarize.js +87 -0
- package/dist/src/evals/summarize.js.map +1 -0
- package/dist/src/evals/types.d.ts +81 -0
- package/dist/src/evals/types.d.ts.map +1 -0
- package/dist/src/evals/types.js +15 -0
- package/dist/src/evals/types.js.map +1 -0
- package/dist/src/history-window.d.ts +50 -11
- package/dist/src/history-window.d.ts.map +1 -1
- package/dist/src/history-window.js +84 -12
- package/dist/src/history-window.js.map +1 -1
- package/dist/src/index.d.ts +11 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/server.d.ts +8 -0
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +27 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp-client/importer.d.ts +75 -0
- package/dist/src/mcp-client/importer.d.ts.map +1 -0
- package/dist/src/mcp-client/importer.js +161 -0
- package/dist/src/mcp-client/importer.js.map +1 -0
- package/dist/src/mcp-client/index.d.ts +9 -0
- package/dist/src/mcp-client/index.d.ts.map +1 -0
- package/dist/src/mcp-client/index.js +8 -0
- package/dist/src/mcp-client/index.js.map +1 -0
- package/dist/src/mcp-client/options.d.ts +99 -0
- package/dist/src/mcp-client/options.d.ts.map +1 -0
- package/dist/src/mcp-client/options.js +2 -0
- package/dist/src/mcp-client/options.js.map +1 -0
- package/dist/src/mcp-client/tool-input.d.ts +39 -0
- package/dist/src/mcp-client/tool-input.d.ts.map +1 -0
- package/dist/src/mcp-client/tool-input.js +61 -0
- package/dist/src/mcp-client/tool-input.js.map +1 -0
- package/dist/src/mcp-client/tool-kind.d.ts +37 -0
- package/dist/src/mcp-client/tool-kind.d.ts.map +1 -0
- package/dist/src/mcp-client/tool-kind.js +20 -0
- package/dist/src/mcp-client/tool-kind.js.map +1 -0
- package/dist/src/mcp-client/tool-name.d.ts +22 -0
- package/dist/src/mcp-client/tool-name.d.ts.map +1 -0
- package/dist/src/mcp-client/tool-name.js +35 -0
- package/dist/src/mcp-client/tool-name.js.map +1 -0
- package/dist/src/mcp-client/tool-source.d.ts +75 -0
- package/dist/src/mcp-client/tool-source.d.ts.map +1 -0
- package/dist/src/mcp-client/tool-source.js +244 -0
- package/dist/src/mcp-client/tool-source.js.map +1 -0
- package/dist/src/mcp-client/transient.d.ts +28 -0
- package/dist/src/mcp-client/transient.d.ts.map +1 -0
- package/dist/src/mcp-client/transient.js +126 -0
- package/dist/src/mcp-client/transient.js.map +1 -0
- package/dist/src/mcp-client/unsafe-regex.d.ts +23 -0
- package/dist/src/mcp-client/unsafe-regex.d.ts.map +1 -0
- package/dist/src/mcp-client/unsafe-regex.js +194 -0
- package/dist/src/mcp-client/unsafe-regex.js.map +1 -0
- package/dist/src/memory.d.ts +448 -0
- package/dist/src/memory.d.ts.map +1 -0
- package/dist/src/memory.js +330 -0
- package/dist/src/memory.js.map +1 -0
- package/dist/src/pagination.d.ts +63 -0
- package/dist/src/pagination.d.ts.map +1 -0
- package/dist/src/pagination.js +16 -0
- package/dist/src/pagination.js.map +1 -0
- package/dist/src/processors.d.ts +134 -0
- package/dist/src/processors.d.ts.map +1 -0
- package/dist/src/processors.js +215 -0
- package/dist/src/processors.js.map +1 -0
- package/dist/src/rag/qdrant-store.d.ts +48 -6
- package/dist/src/rag/qdrant-store.d.ts.map +1 -1
- package/dist/src/rag/qdrant-store.js +77 -24
- package/dist/src/rag/qdrant-store.js.map +1 -1
- package/dist/src/replay-integrity.d.ts +17 -0
- package/dist/src/replay-integrity.d.ts.map +1 -0
- package/dist/src/replay-integrity.js +19 -0
- package/dist/src/replay-integrity.js.map +1 -0
- package/dist/src/runners/inline-agent-runner.d.ts +33 -7
- package/dist/src/runners/inline-agent-runner.d.ts.map +1 -1
- package/dist/src/runners/inline-agent-runner.js +113 -27
- package/dist/src/runners/inline-agent-runner.js.map +1 -1
- package/dist/src/skills.d.ts +291 -0
- package/dist/src/skills.d.ts.map +1 -0
- package/dist/src/skills.js +0 -0
- package/dist/src/skills.js.map +1 -0
- package/dist/src/spi/agent-runner.d.ts +20 -6
- package/dist/src/spi/agent-runner.d.ts.map +1 -1
- package/dist/src/spi/agent-store.d.ts +53 -0
- package/dist/src/spi/agent-store.d.ts.map +1 -1
- package/dist/src/spi/governance-queries.d.ts +33 -13
- package/dist/src/spi/governance-queries.d.ts.map +1 -1
- package/dist/src/spi/history-window.d.ts +64 -10
- package/dist/src/spi/history-window.d.ts.map +1 -1
- package/dist/src/spi/model-provider.d.ts +18 -0
- package/dist/src/spi/model-provider.d.ts.map +1 -1
- package/dist/src/spi/processors.d.ts +161 -0
- package/dist/src/spi/processors.d.ts.map +1 -0
- package/dist/src/spi/processors.js +57 -0
- package/dist/src/spi/processors.js.map +1 -0
- package/dist/src/spi/token-stream-sink.d.ts +43 -0
- package/dist/src/spi/token-stream-sink.d.ts.map +1 -1
- package/dist/src/spi/token-stream-sink.js +17 -1
- package/dist/src/spi/token-stream-sink.js.map +1 -1
- package/dist/src/sse.d.ts +5 -2
- package/dist/src/sse.d.ts.map +1 -1
- package/dist/src/sse.js +11 -2
- package/dist/src/sse.js.map +1 -1
- package/dist/src/stores/lucid-governance-queries.d.ts +5 -2
- package/dist/src/stores/lucid-governance-queries.d.ts.map +1 -1
- package/dist/src/stores/lucid-governance-queries.js +14 -5
- package/dist/src/stores/lucid-governance-queries.js.map +1 -1
- package/dist/src/stores/lucid-schema.d.ts.map +1 -1
- package/dist/src/stores/lucid-schema.js +15 -0
- package/dist/src/stores/lucid-schema.js.map +1 -1
- package/dist/src/stores/lucid.d.ts +11 -3
- package/dist/src/stores/lucid.d.ts.map +1 -1
- package/dist/src/stores/lucid.js +65 -0
- package/dist/src/stores/lucid.js.map +1 -1
- package/dist/src/structured-output.d.ts +57 -0
- package/dist/src/structured-output.d.ts.map +1 -0
- package/dist/src/structured-output.js +80 -0
- package/dist/src/structured-output.js.map +1 -0
- package/dist/src/telescope/agent-governance-providers.js +2 -2
- package/dist/src/telescope/agent-governance-providers.js.map +1 -1
- package/dist/src/testing/fake-model-provider.d.ts +8 -4
- package/dist/src/testing/fake-model-provider.d.ts.map +1 -1
- package/dist/src/testing/fake-model-provider.js +6 -9
- package/dist/src/testing/fake-model-provider.js.map +1 -1
- package/dist/src/testing/in-memory-governance-queries.d.ts.map +1 -1
- package/dist/src/testing/in-memory-governance-queries.js +8 -3
- package/dist/src/testing/in-memory-governance-queries.js.map +1 -1
- package/dist/src/testing/in-memory-store.d.ts +4 -3
- package/dist/src/testing/in-memory-store.d.ts.map +1 -1
- package/dist/src/testing/in-memory-store.js +13 -7
- package/dist/src/testing/in-memory-store.js.map +1 -1
- package/dist/src/testing/index.d.ts +1 -1
- package/dist/src/testing/index.d.ts.map +1 -1
- package/dist/src/testing/index.js.map +1 -1
- package/dist/src/tool-registry.d.ts +9 -0
- package/dist/src/tool-registry.d.ts.map +1 -1
- package/dist/src/tool-registry.js +11 -0
- package/dist/src/tool-registry.js.map +1 -1
- package/dist/src/types.d.ts +55 -2
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +20 -10
- package/skills/agent-personas-agents/SKILL.md +16 -12
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ModelProvider } from '../../spi/model-provider.js';
|
|
2
|
+
import type { ScorableRun, ScoreResult, Scorer, ScorerKind } from '../types.js';
|
|
3
|
+
/** {@link AnswerRelevancyScorer}'s stable name. */
|
|
4
|
+
export declare const ANSWER_RELEVANCY_SCORER = "answer-relevancy";
|
|
5
|
+
export interface AnswerRelevancyOptions {
|
|
6
|
+
/** The judge. Deliberately a separate {@link ModelProvider} — nothing forces it to be the model under test. */
|
|
7
|
+
model: ModelProvider;
|
|
8
|
+
/** Override the grading instructions (e.g. to add domain rules the judge must apply). */
|
|
9
|
+
systemPrompt?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* LLM-as-judge: does the answer address the question that was asked?
|
|
13
|
+
*
|
|
14
|
+
* The expensive family, and the reason this module is offline-first — grading a turn costs a whole
|
|
15
|
+
* model call, so it happens over stored runs on your schedule, not inside the turn where it would
|
|
16
|
+
* double the latency and the bill of every message a user sends.
|
|
17
|
+
*
|
|
18
|
+
* `null` when there is no question or no answer to compare: a judge asked to grade an empty string
|
|
19
|
+
* will invent a number, and `run-completion` has already scored that run 0.
|
|
20
|
+
*/
|
|
21
|
+
export declare class AnswerRelevancyScorer implements Scorer {
|
|
22
|
+
private readonly options;
|
|
23
|
+
readonly name = "answer-relevancy";
|
|
24
|
+
readonly kind: ScorerKind;
|
|
25
|
+
constructor(options: AnswerRelevancyOptions);
|
|
26
|
+
score(run: ScorableRun): Promise<ScoreResult | null>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=answer-relevancy.scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-relevancy.scorer.d.ts","sourceRoot":"","sources":["../../../../src/evals/scorers/answer-relevancy.scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAW1D,MAAM,WAAW,sBAAsB;IACrC,+GAA+G;IAC/G,KAAK,EAAE,aAAa,CAAC;IACrB,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,qBAAa,qBAAsB,YAAW,MAAM;IAItC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,QAAQ,CAAC,IAAI,sBAA2B;IACxC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAW;IAEpC,YAA6B,OAAO,EAAE,sBAAsB,EAAI;IAE1D,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAWzD;CACF"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { discardingSink, MAX_JUDGE_SCORE, parseJudgeVerdict } from '../judge.js';
|
|
2
|
+
/** {@link AnswerRelevancyScorer}'s stable name. */
|
|
3
|
+
export const ANSWER_RELEVANCY_SCORER = 'answer-relevancy';
|
|
4
|
+
const DEFAULT_JUDGE_PROMPT = [
|
|
5
|
+
'You grade an AI assistant answer for RELEVANCY to the question it was given.',
|
|
6
|
+
'Judge only whether the answer addresses what was asked — not style, length, or whether you',
|
|
7
|
+
'personally agree with it. An answer that is fluent but answers a different question scores low.',
|
|
8
|
+
'',
|
|
9
|
+
`Reply in exactly this shape, with no other text: "SCORE: <0-${MAX_JUDGE_SCORE}>" on the first`,
|
|
10
|
+
'line and "REASON: <one sentence>" on the second.',
|
|
11
|
+
].join('\n');
|
|
12
|
+
/**
|
|
13
|
+
* LLM-as-judge: does the answer address the question that was asked?
|
|
14
|
+
*
|
|
15
|
+
* The expensive family, and the reason this module is offline-first — grading a turn costs a whole
|
|
16
|
+
* model call, so it happens over stored runs on your schedule, not inside the turn where it would
|
|
17
|
+
* double the latency and the bill of every message a user sends.
|
|
18
|
+
*
|
|
19
|
+
* `null` when there is no question or no answer to compare: a judge asked to grade an empty string
|
|
20
|
+
* will invent a number, and `run-completion` has already scored that run 0.
|
|
21
|
+
*/
|
|
22
|
+
export class AnswerRelevancyScorer {
|
|
23
|
+
options;
|
|
24
|
+
name = ANSWER_RELEVANCY_SCORER;
|
|
25
|
+
kind = 'model';
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
async score(run) {
|
|
30
|
+
if (run.input.trim() === '' || run.output.trim() === '') {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const result = await this.options.model.runTurn({
|
|
34
|
+
system: this.options.systemPrompt ?? DEFAULT_JUDGE_PROMPT,
|
|
35
|
+
messages: [{ role: 'user', content: `QUESTION:\n${run.input}\n\nANSWER:\n${run.output}` }],
|
|
36
|
+
tools: [],
|
|
37
|
+
sink: discardingSink(),
|
|
38
|
+
});
|
|
39
|
+
return parseJudgeVerdict(result.text);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=answer-relevancy.scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answer-relevancy.scorer.js","sourceRoot":"","sources":["../../../../src/evals/scorers/answer-relevancy.scorer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGjF,mDAAmD;AACnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AAE1D,MAAM,oBAAoB,GAAG;IAC3B,8EAA8E;IAC9E,4FAA4F;IAC5F,iGAAiG;IACjG,EAAE;IACF,+DAA+D,eAAe,iBAAiB;IAC/F,kDAAkD;CACnD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AASb;;;;;;;;;GASG;AACH,MAAM,OAAO,qBAAqB;IAIH,OAAO;IAH3B,IAAI,GAAG,uBAAuB,CAAC;IAC/B,IAAI,GAAe,OAAO,CAAC;IAEpC,YAA6B,OAA+B;uBAA/B,OAAO;IAA2B,CAAC;IAEhE,KAAK,CAAC,KAAK,CAAC,GAAgB;QAC1B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YAC9C,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,oBAAoB;YACzD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,CAAC,KAAK,gBAAgB,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1F,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,cAAc,EAAE;SACvB,CAAC,CAAC;QACH,OAAO,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ScorableRun, ScoreResult, Scorer, ScorerKind } from '../types.js';
|
|
2
|
+
/** {@link ApprovalOutcomeScorer}'s stable name. */
|
|
3
|
+
export declare const APPROVAL_OUTCOME_SCORER = "approval-outcome";
|
|
4
|
+
/**
|
|
5
|
+
* Every HITL rejection is a negative quality label a human produced for free.
|
|
6
|
+
*
|
|
7
|
+
* The library already stops an `action` tool and asks a person "should this run?". That answer is
|
|
8
|
+
* recorded on the tool call, and it is the only ground truth in the whole system that nobody had to
|
|
9
|
+
* be paid to collect: an operator who clicks reject has told you the agent proposed the wrong thing,
|
|
10
|
+
* in the words of the domain, at the moment it mattered. This scorer reads that back as the fraction
|
|
11
|
+
* of a run's decided actions a human said yes to.
|
|
12
|
+
*
|
|
13
|
+
* `null` — not 1 — for a run that proposed no action, or whose actions are all still
|
|
14
|
+
* `pending_approval`. Most runs are read-only and carry no human verdict at all; counting those as
|
|
15
|
+
* perfect would bury the runs that do carry one under an average of ~1.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ApprovalOutcomeScorer implements Scorer {
|
|
18
|
+
readonly name = "approval-outcome";
|
|
19
|
+
readonly kind: ScorerKind;
|
|
20
|
+
score(run: ScorableRun): Promise<ScoreResult | null>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=approval-outcome.scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-outcome.scorer.d.ts","sourceRoot":"","sources":["../../../../src/evals/scorers/approval-outcome.scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAoB,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElG,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAW1D;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,MAAM;IAClD,QAAQ,CAAC,IAAI,sBAA2B;IACxC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAU;IAE7B,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA2BzD;CACF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** {@link ApprovalOutcomeScorer}'s stable name. */
|
|
2
|
+
export const APPROVAL_OUTCOME_SCORER = 'approval-outcome';
|
|
3
|
+
/**
|
|
4
|
+
* The statuses an `action` tool call can only reach AFTER a human approved it. `failed` belongs
|
|
5
|
+
* here: the approval happened and the tool then blew up on its own, which is a tool problem, not a
|
|
6
|
+
* verdict on whether the agent should have proposed it. (`run-completion` is what charges for that
|
|
7
|
+
* failure.) `pending_approval` is the undecided state, and `auto_executed` never applies — an action
|
|
8
|
+
* never auto-executes.
|
|
9
|
+
*/
|
|
10
|
+
const APPROVED_STATUSES = new Set(['executed', 'failed']);
|
|
11
|
+
/**
|
|
12
|
+
* Every HITL rejection is a negative quality label a human produced for free.
|
|
13
|
+
*
|
|
14
|
+
* The library already stops an `action` tool and asks a person "should this run?". That answer is
|
|
15
|
+
* recorded on the tool call, and it is the only ground truth in the whole system that nobody had to
|
|
16
|
+
* be paid to collect: an operator who clicks reject has told you the agent proposed the wrong thing,
|
|
17
|
+
* in the words of the domain, at the moment it mattered. This scorer reads that back as the fraction
|
|
18
|
+
* of a run's decided actions a human said yes to.
|
|
19
|
+
*
|
|
20
|
+
* `null` — not 1 — for a run that proposed no action, or whose actions are all still
|
|
21
|
+
* `pending_approval`. Most runs are read-only and carry no human verdict at all; counting those as
|
|
22
|
+
* perfect would bury the runs that do carry one under an average of ~1.
|
|
23
|
+
*/
|
|
24
|
+
export class ApprovalOutcomeScorer {
|
|
25
|
+
name = APPROVAL_OUTCOME_SCORER;
|
|
26
|
+
kind = 'rule';
|
|
27
|
+
async score(run) {
|
|
28
|
+
const actions = run.toolCalls.filter((call) => call.toolType === 'action');
|
|
29
|
+
const approved = actions.filter((call) => APPROVED_STATUSES.has(call.status));
|
|
30
|
+
const rejected = actions.filter((call) => call.status === 'rejected');
|
|
31
|
+
const decided = approved.length + rejected.length;
|
|
32
|
+
if (decided === 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const metadata = {
|
|
36
|
+
proposed: actions.length,
|
|
37
|
+
approved: approved.length,
|
|
38
|
+
rejected: rejected.length,
|
|
39
|
+
pending: actions.length - decided,
|
|
40
|
+
rejectedTools: toolNames(rejected),
|
|
41
|
+
};
|
|
42
|
+
if (rejected.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
score: 1,
|
|
45
|
+
reason: `a human approved all ${decided} decided action${decided === 1 ? '' : 's'}`,
|
|
46
|
+
metadata,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
score: approved.length / decided,
|
|
51
|
+
reason: `a human approved ${approved.length} of ${decided} decided actions (rejected: ${toolNames(rejected).join(', ')})`,
|
|
52
|
+
metadata,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The distinct tool names in a set of calls, sorted — a stable reason string and metadata value. */
|
|
57
|
+
function toolNames(calls) {
|
|
58
|
+
return [...new Set(calls.map((call) => call.toolName))].sort();
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=approval-outcome.scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-outcome.scorer.js","sourceRoot":"","sources":["../../../../src/evals/scorers/approval-outcome.scorer.ts"],"names":[],"mappings":"AAEA,mDAAmD;AACnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,qBAAqB;IACvB,IAAI,GAAG,uBAAuB,CAAC;IAC/B,IAAI,GAAe,MAAM,CAAC;IAEnC,KAAK,CAAC,KAAK,CAAC,GAAgB;QAC1B,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAClD,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAG;YACf,QAAQ,EAAE,OAAO,CAAC,MAAM;YACxB,QAAQ,EAAE,QAAQ,CAAC,MAAM;YACzB,QAAQ,EAAE,QAAQ,CAAC,MAAM;YACzB,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,OAAO;YACjC,aAAa,EAAE,SAAS,CAAC,QAAQ,CAAC;SACnC,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,wBAAwB,OAAO,kBAAkB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;gBACnF,QAAQ;aACT,CAAC;QACJ,CAAC;QACD,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,OAAO;YAChC,MAAM,EAAE,oBAAoB,QAAQ,CAAC,MAAM,OAAO,OAAO,+BAA+B,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YACzH,QAAQ;SACT,CAAC;IACJ,CAAC;CACF;AAED,qGAAqG;AACrG,SAAS,SAAS,CAAC,KAAyB;IAC1C,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ToolApprovalPrior } from '../approval-prior.js';
|
|
2
|
+
import type { ScorableRun, ScoreResult, Scorer, ScorerKind } from '../types.js';
|
|
3
|
+
/** {@link ApprovalRiskScorer}'s stable name. */
|
|
4
|
+
export declare const APPROVAL_RISK_SCORER = "approval-risk";
|
|
5
|
+
/**
|
|
6
|
+
* How likely a human is to reject what this run proposed — BEFORE a human looks at it.
|
|
7
|
+
*
|
|
8
|
+
* {@link import('./approval-outcome.scorer.js').ApprovalOutcomeScorer} reads verdicts that already
|
|
9
|
+
* exist; this turns the same corpus into a prediction, so a pending approvals inbox can be drained
|
|
10
|
+
* riskiest-first and a run that is about to be rejected can be caught while it is still cheap. It is
|
|
11
|
+
* the statistical family, not the rule-based one: the number is a smoothed frequency estimate over
|
|
12
|
+
* past decisions, and its `metadata` carries the sample it rests on so a 1-of-1 rejection is never
|
|
13
|
+
* mistaken for certainty.
|
|
14
|
+
*
|
|
15
|
+
* A run scores as its WORST proposed action, not the average of them. A turn that proposes one tool
|
|
16
|
+
* humans reject nine times in ten is a risky turn no matter how many safe reads it made alongside.
|
|
17
|
+
*
|
|
18
|
+
* `null` for a run that proposed no action — the same "not applicable, not perfect" rule as the
|
|
19
|
+
* outcome scorer.
|
|
20
|
+
*/
|
|
21
|
+
export declare class ApprovalRiskScorer implements Scorer {
|
|
22
|
+
private readonly prior;
|
|
23
|
+
readonly name = "approval-risk";
|
|
24
|
+
readonly kind: ScorerKind;
|
|
25
|
+
constructor(prior: ToolApprovalPrior);
|
|
26
|
+
score(run: ScorableRun): Promise<ScoreResult | null>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=approval-risk.scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-risk.scorer.d.ts","sourceRoot":"","sources":["../../../../src/evals/scorers/approval-risk.scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF,gDAAgD;AAChD,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAUpD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAmB,YAAW,MAAM;IAInC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,QAAQ,CAAC,IAAI,mBAAwB;IACrC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAiB;IAE1C,YAA6B,KAAK,EAAE,iBAAiB,EAAI;IAEnD,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA4BzD;CACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { approvalPosterior } from '../approval-prior.js';
|
|
2
|
+
/** {@link ApprovalRiskScorer}'s stable name. */
|
|
3
|
+
export const APPROVAL_RISK_SCORER = 'approval-risk';
|
|
4
|
+
/**
|
|
5
|
+
* How likely a human is to reject what this run proposed — BEFORE a human looks at it.
|
|
6
|
+
*
|
|
7
|
+
* {@link import('./approval-outcome.scorer.js').ApprovalOutcomeScorer} reads verdicts that already
|
|
8
|
+
* exist; this turns the same corpus into a prediction, so a pending approvals inbox can be drained
|
|
9
|
+
* riskiest-first and a run that is about to be rejected can be caught while it is still cheap. It is
|
|
10
|
+
* the statistical family, not the rule-based one: the number is a smoothed frequency estimate over
|
|
11
|
+
* past decisions, and its `metadata` carries the sample it rests on so a 1-of-1 rejection is never
|
|
12
|
+
* mistaken for certainty.
|
|
13
|
+
*
|
|
14
|
+
* A run scores as its WORST proposed action, not the average of them. A turn that proposes one tool
|
|
15
|
+
* humans reject nine times in ten is a risky turn no matter how many safe reads it made alongside.
|
|
16
|
+
*
|
|
17
|
+
* `null` for a run that proposed no action — the same "not applicable, not perfect" rule as the
|
|
18
|
+
* outcome scorer.
|
|
19
|
+
*/
|
|
20
|
+
export class ApprovalRiskScorer {
|
|
21
|
+
prior;
|
|
22
|
+
name = APPROVAL_RISK_SCORER;
|
|
23
|
+
kind = 'statistical';
|
|
24
|
+
constructor(prior) {
|
|
25
|
+
this.prior = prior;
|
|
26
|
+
}
|
|
27
|
+
async score(run) {
|
|
28
|
+
const actions = run.toolCalls.filter((call) => call.toolType === 'action');
|
|
29
|
+
if (actions.length === 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const proposed = [...new Set(actions.map((call) => call.toolName))]
|
|
33
|
+
.sort()
|
|
34
|
+
.map((toolName) => {
|
|
35
|
+
const counts = this.prior.get(toolName);
|
|
36
|
+
return {
|
|
37
|
+
toolName,
|
|
38
|
+
approved: counts?.approved ?? 0,
|
|
39
|
+
rejected: counts?.rejected ?? 0,
|
|
40
|
+
pApprove: approvalPosterior(counts),
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
const riskiest = proposed.reduce((worst, candidate) => candidate.pApprove < worst.pApprove ? candidate : worst);
|
|
44
|
+
const decided = riskiest.approved + riskiest.rejected;
|
|
45
|
+
return {
|
|
46
|
+
score: riskiest.pApprove,
|
|
47
|
+
reason: decided === 0
|
|
48
|
+
? `no human has ever decided on ${riskiest.toolName}, the riskiest of ${proposed.length} proposed action(s)`
|
|
49
|
+
: `the riskiest proposed action is ${riskiest.toolName} — humans approved ${riskiest.approved} of its ${decided} past calls`,
|
|
50
|
+
metadata: { riskiestTool: riskiest.toolName, proposed },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=approval-risk.scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval-risk.scorer.js","sourceRoot":"","sources":["../../../../src/evals/scorers/approval-risk.scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0B,MAAM,sBAAsB,CAAC;AAGjF,gDAAgD;AAChD,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC;AAUpD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,kBAAkB;IAIA,KAAK;IAHzB,IAAI,GAAG,oBAAoB,CAAC;IAC5B,IAAI,GAAe,aAAa,CAAC;IAE1C,YAA6B,KAAwB;qBAAxB,KAAK;IAAsB,CAAC;IAEzD,KAAK,CAAC,KAAK,CAAC,GAAgB;QAC1B,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;QAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAqB,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;aAClF,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YAChB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxC,OAAO;gBACL,QAAQ;gBACR,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,CAAC;gBAC/B,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,CAAC;gBAC/B,QAAQ,EAAE,iBAAiB,CAAC,MAAM,CAAC;aACpC,CAAC;QACJ,CAAC,CAAC,CAAC;QACL,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CACpD,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CACxD,CAAC;QACF,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;QACtD,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,QAAQ;YACxB,MAAM,EACJ,OAAO,KAAK,CAAC;gBACX,CAAC,CAAC,gCAAgC,QAAQ,CAAC,QAAQ,qBAAqB,QAAQ,CAAC,MAAM,qBAAqB;gBAC5G,CAAC,CAAC,mCAAmC,QAAQ,CAAC,QAAQ,sBAAsB,QAAQ,CAAC,QAAQ,WAAW,OAAO,aAAa;YAChI,QAAQ,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE;SACxD,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ScorableRun, ScoreResult, Scorer, ScorerKind } from '../types.js';
|
|
2
|
+
/** {@link RunCompletionScorer}'s stable name, for a `where.scorer` filter or a resumed backfill. */
|
|
3
|
+
export declare const RUN_COMPLETION_SCORER = "run-completion";
|
|
4
|
+
/**
|
|
5
|
+
* Did the turn actually deliver? Deterministic, free, and the baseline every other scorer is read
|
|
6
|
+
* against.
|
|
7
|
+
*
|
|
8
|
+
* It is NOT the governance success rate. That counts a run as a success the moment it settles
|
|
9
|
+
* `completed`, which a turn that answered nothing after three failed tool calls also does. This asks
|
|
10
|
+
* the narrower question the ledger cannot: was there an answer, and was the agent whole while it
|
|
11
|
+
* wrote one.
|
|
12
|
+
*/
|
|
13
|
+
export declare class RunCompletionScorer implements Scorer {
|
|
14
|
+
readonly name = "run-completion";
|
|
15
|
+
readonly kind: ScorerKind;
|
|
16
|
+
score(run: ScorableRun): Promise<ScoreResult | null>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=run-completion.scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-completion.scorer.d.ts","sourceRoot":"","sources":["../../../../src/evals/scorers/run-completion.scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEhF,oGAAoG;AACpG,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAStD;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,MAAM;IAChD,QAAQ,CAAC,IAAI,oBAAyB;IACtC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAU;IAE7B,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAiCzD;CACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** {@link RunCompletionScorer}'s stable name, for a `where.scorer` filter or a resumed backfill. */
|
|
2
|
+
export const RUN_COMPLETION_SCORER = 'run-completion';
|
|
3
|
+
/**
|
|
4
|
+
* An answer assembled from a partially-broken toolset. Kept distinguishable from BOTH a clean answer
|
|
5
|
+
* (1) and no answer at all (0): the user did get a reply, and it was written without whatever the
|
|
6
|
+
* failed tool was going to say.
|
|
7
|
+
*/
|
|
8
|
+
const PARTIAL_TOOLING_SCORE = 0.5;
|
|
9
|
+
/**
|
|
10
|
+
* Did the turn actually deliver? Deterministic, free, and the baseline every other scorer is read
|
|
11
|
+
* against.
|
|
12
|
+
*
|
|
13
|
+
* It is NOT the governance success rate. That counts a run as a success the moment it settles
|
|
14
|
+
* `completed`, which a turn that answered nothing after three failed tool calls also does. This asks
|
|
15
|
+
* the narrower question the ledger cannot: was there an answer, and was the agent whole while it
|
|
16
|
+
* wrote one.
|
|
17
|
+
*/
|
|
18
|
+
export class RunCompletionScorer {
|
|
19
|
+
name = RUN_COMPLETION_SCORER;
|
|
20
|
+
kind = 'rule';
|
|
21
|
+
async score(run) {
|
|
22
|
+
const failedCalls = run.toolCalls.filter((call) => call.status === 'failed');
|
|
23
|
+
const metadata = {
|
|
24
|
+
status: run.status,
|
|
25
|
+
outputChars: run.output.trim().length,
|
|
26
|
+
toolCalls: run.toolCalls.length,
|
|
27
|
+
failedToolCalls: failedCalls.length,
|
|
28
|
+
};
|
|
29
|
+
// A run still in flight has no outcome to judge — scoring it would freeze a verdict the run is
|
|
30
|
+
// about to contradict.
|
|
31
|
+
if (run.status === 'running') {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (run.status === 'failed' || run.status === 'cancelled') {
|
|
35
|
+
return {
|
|
36
|
+
score: 0,
|
|
37
|
+
reason: `the run ${run.status} (${run.error ?? 'unclassified'})`,
|
|
38
|
+
metadata,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (run.output.trim() === '') {
|
|
42
|
+
return { score: 0, reason: 'the run completed without answering anything', metadata };
|
|
43
|
+
}
|
|
44
|
+
if (failedCalls.length > 0) {
|
|
45
|
+
const names = [...new Set(failedCalls.map((call) => call.toolName))].sort().join(', ');
|
|
46
|
+
return {
|
|
47
|
+
score: PARTIAL_TOOLING_SCORE,
|
|
48
|
+
reason: `answered, but ${failedCalls.length} of ${run.toolCalls.length} tool calls failed (${names})`,
|
|
49
|
+
metadata,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return { score: 1, reason: 'the run completed and answered with every tool intact', metadata };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=run-completion.scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-completion.scorer.js","sourceRoot":"","sources":["../../../../src/evals/scorers/run-completion.scorer.ts"],"names":[],"mappings":"AAEA,oGAAoG;AACpG,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,OAAO,mBAAmB;IACrB,IAAI,GAAG,qBAAqB,CAAC;IAC7B,IAAI,GAAe,MAAM,CAAC;IAEnC,KAAK,CAAC,KAAK,CAAC,GAAgB;QAC1B,MAAM,WAAW,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC7E,MAAM,QAAQ,GAAG;YACf,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM;YACrC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,MAAM;YAC/B,eAAe,EAAE,WAAW,CAAC,MAAM;SACpC,CAAC;QAEF,+FAA+F;QAC/F,uBAAuB;QACvB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC1D,OAAO;gBACL,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,WAAW,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,cAAc,GAAG;gBAChE,QAAQ;aACT,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC7B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,8CAA8C,EAAE,QAAQ,EAAE,CAAC;QACxF,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvF,OAAO;gBACL,KAAK,EAAE,qBAAqB;gBAC5B,MAAM,EAAE,iBAAiB,WAAW,CAAC,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,MAAM,uBAAuB,KAAK,GAAG;gBACrG,QAAQ;aACT,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,uDAAuD,EAAE,QAAQ,EAAE,CAAC;IACjG,CAAC;CACF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { RunScore } from './score-store.js';
|
|
2
|
+
import type { ScorerKind } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The pure aggregation core over persisted scores, mirroring the governance read-model: an adapter's
|
|
5
|
+
* only job is fetching rows, and every surface that reports a mean score runs the SAME arithmetic
|
|
6
|
+
* here, so a dashboard and a CI gate can never disagree about whether quality moved.
|
|
7
|
+
*/
|
|
8
|
+
/** Rollup for one scorer over a set of scores. */
|
|
9
|
+
export interface ScorerSummaryRow {
|
|
10
|
+
scorer: string;
|
|
11
|
+
kind: ScorerKind;
|
|
12
|
+
/** How many runs this scorer actually scored. A mean over 3 samples is not a metric — read this first. */
|
|
13
|
+
samples: number;
|
|
14
|
+
meanScore: number;
|
|
15
|
+
minScore: number;
|
|
16
|
+
maxScore: number;
|
|
17
|
+
}
|
|
18
|
+
/** Rollup for one agent under one scorer. */
|
|
19
|
+
export interface AgentScoreRow {
|
|
20
|
+
/** `'(default)'` when the scored run named no agent, mirroring the governance breakdown. */
|
|
21
|
+
agentName: string;
|
|
22
|
+
scorer: string;
|
|
23
|
+
samples: number;
|
|
24
|
+
meanScore: number;
|
|
25
|
+
}
|
|
26
|
+
/** One point on the daily quality trend, per scorer. */
|
|
27
|
+
export interface ScoreTrendPoint {
|
|
28
|
+
day: string;
|
|
29
|
+
scorer: string;
|
|
30
|
+
samples: number;
|
|
31
|
+
meanScore: number;
|
|
32
|
+
}
|
|
33
|
+
/** Rollup per scorer, worst mean first — the ordering that puts the problem at the top. */
|
|
34
|
+
export declare function summarizeByScorer(rows: RunScore[]): ScorerSummaryRow[];
|
|
35
|
+
/** Rollup per (agent, scorer) pair, worst mean first — which persona drags which signal down. */
|
|
36
|
+
export declare function summarizeByAgent(rows: RunScore[]): AgentScoreRow[];
|
|
37
|
+
/** Daily mean per scorer, ascending by day then scorer — the "is it getting better" series. */
|
|
38
|
+
export declare function bucketScoreTrend(rows: RunScore[]): ScoreTrendPoint[];
|
|
39
|
+
/**
|
|
40
|
+
* The lowest-scoring runs, worst first, capped at `limit` — the triage queue. Every scorer carries a
|
|
41
|
+
* `reason`, so this is the one view that answers "show me what went wrong" without a second read.
|
|
42
|
+
*/
|
|
43
|
+
export declare function worstScoredRuns(rows: RunScore[], limit: number): RunScore[];
|
|
44
|
+
//# sourceMappingURL=summarize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../../../src/evals/summarize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AAEH,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,0GAA0G;IAC1G,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE,CAsBtE;AAED,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,CAyBlE;AAED,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAqBpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAI3E"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Bucket key for a score whose run named no agent (mirrors the governance run breakdown). */
|
|
2
|
+
const DEFAULT_AGENT_BUCKET = '(default)';
|
|
3
|
+
/** Mean of a bucket. Every caller below builds its buckets by pushing, so none is ever empty. */
|
|
4
|
+
function mean(values) {
|
|
5
|
+
let total = 0;
|
|
6
|
+
for (const value of values) {
|
|
7
|
+
total += value;
|
|
8
|
+
}
|
|
9
|
+
return total / values.length;
|
|
10
|
+
}
|
|
11
|
+
/** Rollup per scorer, worst mean first — the ordering that puts the problem at the top. */
|
|
12
|
+
export function summarizeByScorer(rows) {
|
|
13
|
+
const byScorer = new Map();
|
|
14
|
+
for (const row of rows) {
|
|
15
|
+
const bucket = byScorer.get(row.scorer) ?? { kind: row.kind, scores: [] };
|
|
16
|
+
bucket.scores.push(row.score);
|
|
17
|
+
byScorer.set(row.scorer, bucket);
|
|
18
|
+
}
|
|
19
|
+
const result = [];
|
|
20
|
+
for (const [scorer, bucket] of byScorer) {
|
|
21
|
+
result.push({
|
|
22
|
+
scorer,
|
|
23
|
+
kind: bucket.kind,
|
|
24
|
+
samples: bucket.scores.length,
|
|
25
|
+
meanScore: mean(bucket.scores),
|
|
26
|
+
minScore: Math.min(...bucket.scores),
|
|
27
|
+
maxScore: Math.max(...bucket.scores),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
result.sort((left, right) => left.meanScore - right.meanScore || left.scorer.localeCompare(right.scorer));
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/** Rollup per (agent, scorer) pair, worst mean first — which persona drags which signal down. */
|
|
34
|
+
export function summarizeByAgent(rows) {
|
|
35
|
+
const byPair = new Map();
|
|
36
|
+
for (const row of rows) {
|
|
37
|
+
const agentName = row.agentName ?? DEFAULT_AGENT_BUCKET;
|
|
38
|
+
const key = `${agentName} ${row.scorer}`;
|
|
39
|
+
const bucket = byPair.get(key) ?? { agentName, scorer: row.scorer, scores: [] };
|
|
40
|
+
bucket.scores.push(row.score);
|
|
41
|
+
byPair.set(key, bucket);
|
|
42
|
+
}
|
|
43
|
+
const result = [];
|
|
44
|
+
for (const bucket of byPair.values()) {
|
|
45
|
+
result.push({
|
|
46
|
+
agentName: bucket.agentName,
|
|
47
|
+
scorer: bucket.scorer,
|
|
48
|
+
samples: bucket.scores.length,
|
|
49
|
+
meanScore: mean(bucket.scores),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
result.sort((left, right) => left.meanScore - right.meanScore ||
|
|
53
|
+
left.agentName.localeCompare(right.agentName) ||
|
|
54
|
+
left.scorer.localeCompare(right.scorer));
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/** Daily mean per scorer, ascending by day then scorer — the "is it getting better" series. */
|
|
58
|
+
export function bucketScoreTrend(rows) {
|
|
59
|
+
const byDay = new Map();
|
|
60
|
+
for (const row of rows) {
|
|
61
|
+
const key = `${row.day} ${row.scorer}`;
|
|
62
|
+
const bucket = byDay.get(key) ?? { day: row.day, scorer: row.scorer, scores: [] };
|
|
63
|
+
bucket.scores.push(row.score);
|
|
64
|
+
byDay.set(key, bucket);
|
|
65
|
+
}
|
|
66
|
+
const result = [];
|
|
67
|
+
for (const bucket of byDay.values()) {
|
|
68
|
+
result.push({
|
|
69
|
+
day: bucket.day,
|
|
70
|
+
scorer: bucket.scorer,
|
|
71
|
+
samples: bucket.scores.length,
|
|
72
|
+
meanScore: mean(bucket.scores),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
result.sort((left, right) => left.day.localeCompare(right.day) || left.scorer.localeCompare(right.scorer));
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The lowest-scoring runs, worst first, capped at `limit` — the triage queue. Every scorer carries a
|
|
80
|
+
* `reason`, so this is the one view that answers "show me what went wrong" without a second read.
|
|
81
|
+
*/
|
|
82
|
+
export function worstScoredRuns(rows, limit) {
|
|
83
|
+
return [...rows]
|
|
84
|
+
.sort((left, right) => left.score - right.score || left.runId.localeCompare(right.runId))
|
|
85
|
+
.slice(0, limit);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=summarize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summarize.js","sourceRoot":"","sources":["../../../src/evals/summarize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evaluation SPI: a {@link Scorer} turns ONE stored run into a number plus the sentence that
|
|
3
|
+
* justifies it. Everything else here (the batch runner, the score store, the summaries) is plumbing
|
|
4
|
+
* around that one call.
|
|
5
|
+
*
|
|
6
|
+
* Scoring is offline-first. A {@link ScorableRun} is assembled from what the agent already persisted
|
|
7
|
+
* — the run row, its transcript, its tool calls and their HITL outcomes — so a scorer never sits
|
|
8
|
+
* inside a turn, never adds latency to one, and can be re-run over history the day a new scorer is
|
|
9
|
+
* written.
|
|
10
|
+
*/
|
|
11
|
+
/** One tool call the run made, reduced to what a scorer can judge. */
|
|
12
|
+
export interface ScorableToolCall {
|
|
13
|
+
toolCallId: string;
|
|
14
|
+
toolName: string;
|
|
15
|
+
/** `'read'` (auto-executed) or `'action'` — only an `action` carries a human decision. */
|
|
16
|
+
toolType: string;
|
|
17
|
+
/** A {@link import('../types.js').ToolCallStatus} as the store recorded it. */
|
|
18
|
+
status: string;
|
|
19
|
+
/** Wall time of the execution; `null` for a call that never executed. */
|
|
20
|
+
executionMs: number | null;
|
|
21
|
+
/** The failure text for a `failed` call; `null` otherwise. */
|
|
22
|
+
error: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** One stored run, flattened into the unit a scorer judges. */
|
|
25
|
+
export interface ScorableRun {
|
|
26
|
+
runId: string;
|
|
27
|
+
threadId: string;
|
|
28
|
+
actorRef: string;
|
|
29
|
+
agentName: string | null;
|
|
30
|
+
/** `'running'` | `'completed'` | `'failed'` | `'cancelled'`, as the store recorded it. */
|
|
31
|
+
status: string;
|
|
32
|
+
/** The user text that opened the turn; `''` when the run holds none. */
|
|
33
|
+
input: string;
|
|
34
|
+
/** The assistant text the turn produced; `''` when the run answered nothing. */
|
|
35
|
+
output: string;
|
|
36
|
+
toolCalls: ScorableToolCall[];
|
|
37
|
+
durationMs: number | null;
|
|
38
|
+
/**
|
|
39
|
+
* The run's failure message as the read-model carries it; `null` for a run that did not fail. The
|
|
40
|
+
* read-model records prose here rather than a stable slug, so a scorer quotes it instead of
|
|
41
|
+
* branching on it.
|
|
42
|
+
*/
|
|
43
|
+
error: string | null;
|
|
44
|
+
/** ISO timestamp the run started — the day a score is bucketed under. */
|
|
45
|
+
startedAt: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Which family a scorer belongs to, kept on the persisted score so a summary can separate a free
|
|
49
|
+
* deterministic signal from one that cost money to produce.
|
|
50
|
+
*
|
|
51
|
+
* - `rule` — deterministic, derived from the run alone (no corpus, no model).
|
|
52
|
+
* - `statistical` — an estimate over a corpus of past runs (frequencies, priors).
|
|
53
|
+
* - `model` — LLM-as-judge: another model call, therefore the expensive family.
|
|
54
|
+
*/
|
|
55
|
+
export type ScorerKind = 'rule' | 'statistical' | 'model';
|
|
56
|
+
/** One scorer's verdict on one run. */
|
|
57
|
+
export interface ScoreResult {
|
|
58
|
+
/** Normalized to `0..1`, where 1 is good. A scorer that cannot honour that range is a bug. */
|
|
59
|
+
score: number;
|
|
60
|
+
/** Why THAT number, in one sentence — the thing an operator reads before the number. */
|
|
61
|
+
reason: string;
|
|
62
|
+
/** Scorer-specific detail (counts, per-tool breakdowns) persisted alongside the score. */
|
|
63
|
+
metadata?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A quality signal over a stored run.
|
|
67
|
+
*
|
|
68
|
+
* `score` returns `null` for a run the scorer has nothing to say about — an approval scorer facing a
|
|
69
|
+
* run that proposed no action, a judge facing an empty answer. That is deliberately NOT a 0: a score
|
|
70
|
+
* of 0 says "bad", `null` says "not applicable", and averaging the two together is how a quality
|
|
71
|
+
* metric silently stops meaning anything.
|
|
72
|
+
*/
|
|
73
|
+
export interface Scorer {
|
|
74
|
+
/** Stable identifier, persisted on every score row and used to resume a backfill. */
|
|
75
|
+
name: string;
|
|
76
|
+
kind: ScorerKind;
|
|
77
|
+
score(run: ScorableRun): Promise<ScoreResult | null>;
|
|
78
|
+
}
|
|
79
|
+
/** Clamp a computed score into the `0..1` range {@link ScoreResult.score} promises. */
|
|
80
|
+
export declare function clampScore(value: number): number;
|
|
81
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/evals/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC;AAE1D,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,MAAM;IACrB,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CACtD;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evaluation SPI: a {@link Scorer} turns ONE stored run into a number plus the sentence that
|
|
3
|
+
* justifies it. Everything else here (the batch runner, the score store, the summaries) is plumbing
|
|
4
|
+
* around that one call.
|
|
5
|
+
*
|
|
6
|
+
* Scoring is offline-first. A {@link ScorableRun} is assembled from what the agent already persisted
|
|
7
|
+
* — the run row, its transcript, its tool calls and their HITL outcomes — so a scorer never sits
|
|
8
|
+
* inside a turn, never adds latency to one, and can be re-run over history the day a new scorer is
|
|
9
|
+
* written.
|
|
10
|
+
*/
|
|
11
|
+
/** Clamp a computed score into the `0..1` range {@link ScoreResult.score} promises. */
|
|
12
|
+
export function clampScore(value) {
|
|
13
|
+
return Math.min(1, Math.max(0, value));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/evals/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2EH,uFAAuF;AACvF,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC"}
|