@inflexa-ai/harness 0.1.1 → 0.3.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/README.md +48 -0
- package/dist/agents/conversation-agent.d.ts +15 -11
- package/dist/agents/conversation-agent.js +31 -34
- package/dist/agents/report-builder.js +2 -1
- package/dist/agents/sandbox/bulk-transcriptomics-agent.js +1 -1
- package/dist/agents/sandbox/cheminformatics-agent.js +1 -19
- package/dist/agents/sandbox/chromatin-agent.js +1 -10
- package/dist/agents/sandbox/dna-methylation-agent.js +1 -10
- package/dist/agents/sandbox/drug-repurposing-agent.js +4 -14
- package/dist/agents/sandbox/enrichment-agent.js +1 -10
- package/dist/agents/sandbox/ephemeral-executor.js +1 -10
- package/dist/agents/sandbox/genomic-variant-agent.js +1 -3
- package/dist/agents/sandbox/immune-profiling-agent.js +1 -13
- package/dist/agents/sandbox/metabolomics-agent.js +1 -1
- package/dist/agents/sandbox/microbiome-agent.js +1 -1
- package/dist/agents/sandbox/multi-omics-integration-agent.js +1 -12
- package/dist/agents/sandbox/multimodal-sc-agent.js +1 -1
- package/dist/agents/sandbox/network-agent.js +1 -10
- package/dist/agents/sandbox/pkpd-clinical-response-agent.js +2 -8
- package/dist/agents/sandbox/proteomics-agent.js +1 -1
- package/dist/agents/sandbox/scientific-executor.js +1 -10
- package/dist/agents/sandbox/shared.d.ts +20 -6
- package/dist/agents/sandbox/shared.js +50 -39
- package/dist/agents/sandbox/single-cell-agent.js +1 -1
- package/dist/agents/sandbox/spatial-omics-agent.js +1 -1
- package/dist/agents/sandbox/statistical-modeling-agent.js +1 -1
- package/dist/agents/sandbox/translational-safety-agent.js +3 -9
- package/dist/agents/sandbox/types.d.ts +1 -1
- package/dist/agents/system-prompt.d.ts +37 -11
- package/dist/agents/system-prompt.js +35 -12
- package/dist/app/chat-turn.d.ts +3 -0
- package/dist/app/chat-turn.js +3 -1
- package/dist/app/data-profile-orientation.d.ts +34 -0
- package/dist/app/data-profile-orientation.js +117 -0
- package/dist/app/synthesize-run.d.ts +3 -0
- package/dist/app/synthesize-run.js +3 -1
- package/dist/contracts/schemas/chat-parts.d.ts +9 -9
- package/dist/execution/artifact-metadata.d.ts +3 -0
- package/dist/execution/artifact-metadata.js +10 -3
- package/dist/execution/artifact-registration.d.ts +2 -1
- package/dist/execution/artifact-registration.js +8 -2
- package/dist/execution/ephemeral-runner.d.ts +16 -0
- package/dist/execution/ephemeral-runner.js +31 -5
- package/dist/execution/post-step-pipeline.d.ts +3 -0
- package/dist/execution/post-step-pipeline.js +24 -4
- package/dist/execution/reconcile-manifest.d.ts +7 -0
- package/dist/execution/reconcile-manifest.js +19 -5
- package/dist/execution/report-runner.d.ts +3 -0
- package/dist/execution/report-runner.js +4 -4
- package/dist/execution/run-synthesis.js +20 -19
- package/dist/execution/step-summary.d.ts +3 -0
- package/dist/execution/step-summary.js +6 -3
- package/dist/index.d.ts +9 -2
- package/dist/index.js +24 -5
- package/dist/lib/chrome.d.ts +4 -1
- package/dist/lib/chrome.js +10 -7
- package/dist/lib/console-logger.d.ts +19 -0
- package/dist/lib/console-logger.js +62 -0
- package/dist/lib/logger.d.ts +88 -0
- package/dist/lib/logger.js +37 -0
- package/dist/lib/otel.d.ts +2 -1
- package/dist/lib/otel.js +8 -3
- package/dist/loop/__fixtures__/scripted-provider.d.ts +2 -2
- package/dist/loop/__fixtures__/scripted-provider.js +2 -1
- package/dist/loop/metrics.d.ts +33 -1
- package/dist/loop/metrics.js +56 -2
- package/dist/loop/run-agent.d.ts +13 -1
- package/dist/loop/run-agent.js +19 -4
- package/dist/memory/card-builders.d.ts +8 -1
- package/dist/memory/card-builders.js +20 -3
- package/dist/memory/reconstruct-cards.js +4 -3
- package/dist/memory/thread-history.d.ts +27 -2
- package/dist/memory/thread-history.js +45 -5
- package/dist/memory/working-memory.d.ts +93 -10
- package/dist/memory/working-memory.js +220 -84
- package/dist/prompts/SOUL.d.ts +22 -9
- package/dist/prompts/SOUL.js +56 -37
- package/dist/prompts/analogical-reasoner.d.ts +1 -1
- package/dist/prompts/analogical-reasoner.js +2 -2
- package/dist/prompts/briefing.d.ts +100 -0
- package/dist/prompts/briefing.js +166 -0
- package/dist/prompts/conversation.d.ts +1 -1
- package/dist/prompts/conversation.js +94 -440
- package/dist/prompts/literature-reviewer.d.ts +1 -1
- package/dist/prompts/literature-reviewer.js +10 -10
- package/dist/prompts/planner.js +28 -59
- package/dist/prompts/report-builder.d.ts +1 -1
- package/dist/prompts/report-builder.js +71 -24
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/bulk-transcriptomics-agent.js +2 -7
- package/dist/prompts/sandbox/cheminformatics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/cheminformatics-agent.js +11 -15
- package/dist/prompts/sandbox/chromatin-agent.d.ts +1 -1
- package/dist/prompts/sandbox/chromatin-agent.js +3 -7
- package/dist/prompts/sandbox/data-profiler.d.ts +1 -1
- package/dist/prompts/sandbox/data-profiler.js +13 -8
- package/dist/prompts/sandbox/dna-methylation-agent.d.ts +1 -1
- package/dist/prompts/sandbox/dna-methylation-agent.js +2 -7
- package/dist/prompts/sandbox/drug-repurposing-agent.d.ts +1 -1
- package/dist/prompts/sandbox/drug-repurposing-agent.js +15 -16
- package/dist/prompts/sandbox/enrichment-agent.d.ts +1 -1
- package/dist/prompts/sandbox/enrichment-agent.js +2 -9
- package/dist/prompts/sandbox/genomic-variant-agent.d.ts +1 -1
- package/dist/prompts/sandbox/genomic-variant-agent.js +2 -6
- package/dist/prompts/sandbox/immune-profiling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/immune-profiling-agent.js +3 -8
- package/dist/prompts/sandbox/metabolomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/metabolomics-agent.js +1 -7
- package/dist/prompts/sandbox/microbiome-agent.d.ts +1 -1
- package/dist/prompts/sandbox/microbiome-agent.js +2 -7
- package/dist/prompts/sandbox/multi-omics-integration-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multi-omics-integration-agent.js +2 -8
- package/dist/prompts/sandbox/multimodal-sc-agent.d.ts +1 -1
- package/dist/prompts/sandbox/multimodal-sc-agent.js +2 -7
- package/dist/prompts/sandbox/network-agent.d.ts +1 -1
- package/dist/prompts/sandbox/network-agent.js +2 -7
- package/dist/prompts/sandbox/proteomics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/proteomics-agent.js +2 -9
- package/dist/prompts/sandbox/single-cell-agent.d.ts +1 -1
- package/dist/prompts/sandbox/single-cell-agent.js +2 -9
- package/dist/prompts/sandbox/spatial-omics-agent.d.ts +1 -1
- package/dist/prompts/sandbox/spatial-omics-agent.js +3 -6
- package/dist/prompts/sandbox/statistical-modeling-agent.d.ts +1 -1
- package/dist/prompts/sandbox/statistical-modeling-agent.js +2 -7
- package/dist/prompts/sandbox/translational-safety-agent.d.ts +1 -1
- package/dist/prompts/sandbox/translational-safety-agent.js +13 -14
- package/dist/prompts/sandbox-standards.d.ts +22 -14
- package/dist/prompts/sandbox-standards.js +91 -71
- package/dist/prompts/synthesis-agent.d.ts +1 -1
- package/dist/prompts/synthesis-agent.js +33 -131
- package/dist/provenance/collector.js +1 -1
- package/dist/providers/ai-sdk.js +31 -4
- package/dist/providers/prompt-cache.d.ts +74 -0
- package/dist/providers/prompt-cache.js +77 -0
- package/dist/providers/types.d.ts +33 -0
- package/dist/reference-data/catalog.d.ts +131 -0
- package/dist/reference-data/catalog.js +348 -0
- package/dist/reference-data/receipt.d.ts +41 -0
- package/dist/reference-data/receipt.js +40 -0
- package/dist/runtime/boot.d.ts +2 -2
- package/dist/runtime/boot.js +1 -1
- package/dist/runtime/connection-budget.d.ts +2 -2
- package/dist/runtime/connection-budget.js +5 -3
- package/dist/runtime/dbos.d.ts +7 -7
- package/dist/runtime/dbos.js +14 -11
- package/dist/runtime/shutdown.d.ts +2 -2
- package/dist/runtime/shutdown.js +4 -3
- package/dist/sandbox/create-sandbox.d.ts +2 -2
- package/dist/sandbox/docker-client.d.ts +2 -2
- package/dist/sandbox/docker-client.js +4 -1
- package/dist/sandbox/k8s-client.d.ts +3 -0
- package/dist/sandbox/k8s-client.js +5 -4
- package/dist/sandbox/notification-sweep.d.ts +3 -3
- package/dist/sandbox/notification-sweep.js +4 -2
- package/dist/sandbox/reaper.d.ts +3 -3
- package/dist/sandbox/reaper.js +7 -4
- package/dist/sandbox/watchdog.d.ts +3 -3
- package/dist/sandbox/watchdog.js +8 -2
- package/dist/schemas/data-profile-schemas.js +5 -3
- package/dist/schemas/plan-schemas.d.ts +21 -21
- package/dist/schemas/plan-schemas.js +9 -3
- package/dist/schemas/run-synthesis.d.ts +8 -4
- package/dist/schemas/run-synthesis.js +92 -56
- package/dist/schemas/validate-plan.js +1 -1
- package/dist/schemas/workflow-state.d.ts +7 -1
- package/dist/schemas/workflow-state.js +33 -19
- package/dist/state/artifacts.d.ts +13 -0
- package/dist/state/artifacts.js +27 -0
- package/dist/state/data-profile.d.ts +64 -5
- package/dist/state/index.d.ts +3 -3
- package/dist/state/index.js +1 -1
- package/dist/state/init.d.ts +2 -1
- package/dist/state/init.js +5 -6
- package/dist/tasks/data-profile.d.ts +25 -2
- package/dist/tasks/data-profile.js +95 -39
- package/dist/tools/bio/chembl.d.ts +38 -0
- package/dist/tools/bio/chembl.js +138 -0
- package/dist/tools/bio/comptox.d.ts +50 -0
- package/dist/tools/bio/comptox.js +149 -0
- package/dist/tools/bio/get-impc-ko-profile.js +9 -6
- package/dist/tools/bio/index.d.ts +5 -17
- package/dist/tools/bio/index.js +5 -17
- package/dist/tools/bio/keys.d.ts +14 -9
- package/dist/tools/bio/keys.js +16 -16
- package/dist/tools/bio/opentargets.d.ts +38 -0
- package/dist/tools/bio/opentargets.js +89 -0
- package/dist/tools/bio/pubchem.d.ts +29 -0
- package/dist/tools/bio/pubchem.js +92 -0
- package/dist/tools/bio/pubmed.d.ts +51 -0
- package/dist/tools/bio/pubmed.js +100 -0
- package/dist/tools/bio/search-bgee-expression.js +12 -6
- package/dist/tools/bio/search-clinical-trials.js +16 -5
- package/dist/tools/bio/search-dgidb.d.ts +11 -1
- package/dist/tools/bio/search-dgidb.js +92 -78
- package/dist/tools/bio/search-faers.js +8 -4
- package/dist/tools/bio/search-geo-datasets.js +20 -6
- package/dist/tools/bio/search-gwas-catalog.d.ts +1 -1
- package/dist/tools/bio/search-pharmgkb.js +10 -4
- package/dist/tools/display/index.d.ts +1 -0
- package/dist/tools/display/index.js +1 -0
- package/dist/tools/display/normalize-echart-spec.d.ts +61 -0
- package/dist/tools/display/normalize-echart-spec.js +211 -0
- package/dist/tools/display/show-user.d.ts +6 -1
- package/dist/tools/display/show-user.js +25 -12
- package/dist/tools/execute-plan.js +5 -2
- package/dist/tools/iterate-report.d.ts +171 -118
- package/dist/tools/iterate-report.js +336 -96
- package/dist/tools/lib/chembl-client.d.ts +12 -0
- package/dist/tools/lib/chembl-client.js +127 -0
- package/dist/tools/lib/ctx-ops.d.ts +224 -0
- package/dist/tools/lib/ctx-ops.js +450 -0
- package/dist/tools/lib/iuphar-client.js +10 -1
- package/dist/tools/lib/openfda-client.js +11 -3
- package/dist/tools/lib/pathway-client.js +10 -4
- package/dist/tools/lib/pubchem-ops.d.ts +74 -0
- package/dist/tools/lib/pubchem-ops.js +224 -0
- package/dist/tools/memory/update-working-memory.d.ts +45 -7
- package/dist/tools/memory/update-working-memory.js +111 -41
- package/dist/tools/report/index.d.ts +3 -2
- package/dist/tools/report/index.js +3 -2
- package/dist/tools/research/generate-analogy-report.js +25 -12
- package/dist/tools/research/generate-plan.d.ts +12 -5
- package/dist/tools/research/generate-plan.js +168 -37
- package/dist/tools/research/index.d.ts +1 -0
- package/dist/tools/research/index.js +1 -0
- package/dist/tools/research/inspect-data-profile.d.ts +85 -0
- package/dist/tools/research/inspect-data-profile.js +161 -0
- package/dist/tools/research/literature-reviewer.d.ts +3 -0
- package/dist/tools/research/literature-reviewer.js +5 -6
- package/dist/tools/sandbox/list-available-packages.d.ts +79 -5
- package/dist/tools/sandbox/list-available-packages.js +152 -10
- package/dist/tools/sandbox/list-available-refs.d.ts +141 -5
- package/dist/tools/sandbox/list-available-refs.js +647 -134
- package/dist/tools/sandbox/report-blocker.d.ts +39 -9
- package/dist/tools/sandbox/report-blocker.js +43 -20
- package/dist/tools/workspace/execute-command.d.ts +3 -0
- package/dist/tools/workspace/execute-command.js +3 -1
- package/dist/tools/workspace/read-file.js +4 -5
- package/dist/tools/workspace/run-exec.d.ts +4 -4
- package/dist/tools/workspace/run-exec.js +4 -4
- package/dist/tools/workspace/show-file.js +10 -6
- package/dist/tools/workspace/show-plan.js +12 -6
- package/dist/tools/workspace/workspace-search.d.ts +1 -1
- package/dist/tools/workspace/workspace-search.js +11 -5
- package/dist/workflows/execute-analysis.d.ts +46 -4
- package/dist/workflows/execute-analysis.js +118 -13
- package/dist/workflows/execute-target-assessment.d.ts +3 -0
- package/dist/workflows/execute-target-assessment.js +19 -15
- package/dist/workflows/sandbox-step.d.ts +9 -0
- package/dist/workflows/sandbox-step.js +39 -17
- package/dist/workflows/target-assessment/lib/citation-validator.js +2 -2
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +2 -1
- package/dist/workflows/target-assessment/lib/llm-step.d.ts +3 -0
- package/dist/workflows/target-assessment/lib/llm-step.js +3 -1
- package/dist/workflows/target-assessment/lib/structured-llm.d.ts +3 -0
- package/dist/workflows/target-assessment/lib/structured-llm.js +1 -0
- package/dist/workflows/target-assessment/phase5-persist.d.ts +3 -0
- package/dist/workflows/target-assessment/phase5-persist.js +8 -3
- package/dist/workflows/target-assessment/progress.d.ts +2 -1
- package/dist/workflows/target-assessment/progress.js +4 -3
- package/dist/workspace/filesystem.js +163 -74
- package/dist/workspace/paths.d.ts +2 -2
- package/dist/workspace/paths.js +2 -2
- package/package.json +95 -96
- package/dist/execution/filesystem-artifact-registry.d.ts +0 -57
- package/dist/execution/filesystem-artifact-registry.js +0 -92
- package/dist/lib/identifiers.d.ts +0 -8
- package/dist/lib/identifiers.js +0 -10
- package/dist/lib/mime-detect.d.ts +0 -17
- package/dist/lib/mime-detect.js +0 -29
- package/dist/lib/streamed-download.d.ts +0 -28
- package/dist/lib/streamed-download.js +0 -111
- package/dist/lib/trace-context.d.ts +0 -11
- package/dist/lib/trace-context.js +0 -49
- package/dist/providers/llm-capabilities.d.ts +0 -33
- package/dist/providers/llm-capabilities.js +0 -58
- package/dist/schemas/render-step-prompt.d.ts +0 -32
- package/dist/schemas/render-step-prompt.js +0 -76
- package/dist/tools/bio/find-approval-precedent.d.ts +0 -32
- package/dist/tools/bio/find-approval-precedent.js +0 -72
- package/dist/tools/bio/get-article-details.d.ts +0 -11
- package/dist/tools/bio/get-article-details.js +0 -20
- package/dist/tools/bio/get-article-full-text.d.ts +0 -19
- package/dist/tools/bio/get-article-full-text.js +0 -32
- package/dist/tools/bio/get-bioactivity.d.ts +0 -11
- package/dist/tools/bio/get-bioactivity.js +0 -23
- package/dist/tools/bio/get-drug-info.d.ts +0 -9
- package/dist/tools/bio/get-drug-info.js +0 -22
- package/dist/tools/bio/get-mechanism.d.ts +0 -8
- package/dist/tools/bio/get-mechanism.js +0 -18
- package/dist/tools/bio/get-pubchem-assays.d.ts +0 -22
- package/dist/tools/bio/get-pubchem-assays.js +0 -107
- package/dist/tools/bio/get-pubchem-cross-refs.d.ts +0 -15
- package/dist/tools/bio/get-pubchem-cross-refs.js +0 -68
- package/dist/tools/bio/get-target-safety.d.ts +0 -18
- package/dist/tools/bio/get-target-safety.js +0 -26
- package/dist/tools/bio/search-compounds.d.ts +0 -22
- package/dist/tools/bio/search-compounds.js +0 -160
- package/dist/tools/bio/search-ctx-chemical.d.ts +0 -50
- package/dist/tools/bio/search-ctx-chemical.js +0 -130
- package/dist/tools/bio/search-ctx-exposure.d.ts +0 -55
- package/dist/tools/bio/search-ctx-exposure.js +0 -176
- package/dist/tools/bio/search-ctx-hazard.d.ts +0 -111
- package/dist/tools/bio/search-ctx-hazard.js +0 -178
- package/dist/tools/bio/search-opentargets.d.ts +0 -11
- package/dist/tools/bio/search-opentargets.js +0 -25
- package/dist/tools/bio/search-pubchem-compound.d.ts +0 -26
- package/dist/tools/bio/search-pubchem-compound.js +0 -110
- package/dist/tools/bio/search-pubmed.d.ts +0 -17
- package/dist/tools/bio/search-pubmed.js +0 -31
- package/dist/tools/bio/search-targets.d.ts +0 -9
- package/dist/tools/bio/search-targets.js +0 -20
- package/dist/tools/bio/search-toxcast.d.ts +0 -36
- package/dist/tools/bio/search-toxcast.js +0 -141
- package/dist/workflows/register-workflows.d.ts +0 -51
- package/dist/workflows/register-workflows.js +0 -48
- package/dist/workflows/resume-execute-analysis.d.ts +0 -70
- package/dist/workflows/resume-execute-analysis.js +0 -80
- package/dist/workflows/target-assessment/correction-loop.d.ts +0 -45
- package/dist/workflows/target-assessment/correction-loop.js +0 -62
- package/dist/workflows/target-assessment/steps/phase0-resolve.d.ts +0 -71
- package/dist/workflows/target-assessment/steps/phase0-resolve.js +0 -21
- package/dist/workflows/target-assessment/steps/phase1-aggregate.d.ts +0 -1018
- package/dist/workflows/target-assessment/steps/phase1-aggregate.js +0 -25
- package/dist/workspace/mount-strategy.d.ts +0 -50
- package/dist/workspace/mount-strategy.js +0 -67
- package/dist/workspace/provenance-collector.d.ts +0 -34
- package/dist/workspace/provenance-collector.js +0 -16
- package/dist/workspace/workspace-paths.d.ts +0 -26
- package/dist/workspace/workspace-paths.js +0 -31
|
@@ -25,10 +25,12 @@ import { z } from "zod";
|
|
|
25
25
|
import { writeFileWithinRoot } from "../lib/fs-helpers.js";
|
|
26
26
|
import { RunSynthesisSchema } from "../schemas/run-synthesis.js";
|
|
27
27
|
import { synthesisAgentPrompt } from "../prompts/synthesis-agent.js";
|
|
28
|
+
import { composeSystemPrompt } from "../agents/system-prompt.js";
|
|
28
29
|
import { runDir } from "../workspace/paths.js";
|
|
29
30
|
import { runToTerminal } from "../loop/run-to-terminal.js";
|
|
30
31
|
import { passthroughStep } from "../loop/run-step.js";
|
|
31
32
|
import { defineTool } from "../tools/define-tool.js";
|
|
33
|
+
import { createReportBlockerToolFor } from "../tools/sandbox/report-blocker.js";
|
|
32
34
|
import { createLiteratureReviewerTool } from "../tools/research/literature-reviewer.js";
|
|
33
35
|
// ── Agent identity / budgets ────────────────────────────────────────
|
|
34
36
|
const AGENT_ID = "run-synthesizer";
|
|
@@ -125,13 +127,14 @@ function fullyValidate(candidate, ctx) {
|
|
|
125
127
|
function buildSubmitTool(holder, ctx) {
|
|
126
128
|
return defineTool({
|
|
127
129
|
id: "submit_synthesis",
|
|
128
|
-
description: "Submit the final synthesis. Re-validates payload against the
|
|
129
|
-
"
|
|
130
|
-
"PMIDs cited, numeric PMIDs). On
|
|
131
|
-
"STOP after this. On rejection
|
|
132
|
-
"fix the specific fields at each
|
|
133
|
-
"to report_blocker if the
|
|
134
|
-
|
|
130
|
+
description: "Submit the final synthesis. Re-validates the payload against the " +
|
|
131
|
+
"semantic checks the arg schema cannot express (stepId refs, " +
|
|
132
|
+
"theme→finding refs, keyReferences PMIDs cited, numeric PMIDs). On " +
|
|
133
|
+
"success returns {accepted: true} — STOP after this. On rejection " +
|
|
134
|
+
"returns {accepted: false, issues} — fix the specific fields at each " +
|
|
135
|
+
"issue path and call again, or switch to report_blocker if the " +
|
|
136
|
+
"synthesis cannot be made valid.",
|
|
137
|
+
inputSchema: z.object({ synthesis: RunSynthesisSchema }),
|
|
135
138
|
execute: async (input) => {
|
|
136
139
|
if (holder.outcome !== null) {
|
|
137
140
|
return ok({
|
|
@@ -155,18 +158,16 @@ function buildSubmitTool(holder, ctx) {
|
|
|
155
158
|
});
|
|
156
159
|
}
|
|
157
160
|
function buildBlockerTool(holder) {
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
"findings worth surfacing). Pass a short reason. Stop after calling.",
|
|
163
|
-
inputSchema: z.object({ reason: z.string().min(1) }),
|
|
164
|
-
execute: async (input) => {
|
|
165
|
-
if (holder.outcome === null) {
|
|
166
|
-
holder.outcome = { kind: "blocker", reason: input.reason };
|
|
167
|
-
}
|
|
168
|
-
return ok({ recorded: true });
|
|
161
|
+
return createReportBlockerToolFor({
|
|
162
|
+
record: (outcome) => {
|
|
163
|
+
if (holder.outcome === null)
|
|
164
|
+
holder.outcome = outcome;
|
|
169
165
|
},
|
|
166
|
+
blockedWhen: "Ends run synthesis with no synthesis written. Use it when the run " +
|
|
167
|
+
"produced no synthesizable content (all step summaries empty, " +
|
|
168
|
+
"contradictory to the point of incoherence, or no findings worth " +
|
|
169
|
+
"surfacing) — not as an escape from a synthesis you could fix and " +
|
|
170
|
+
"submit.",
|
|
170
171
|
});
|
|
171
172
|
}
|
|
172
173
|
/**
|
|
@@ -207,7 +208,7 @@ export async function generateRunSynthesis(input) {
|
|
|
207
208
|
const tools = [submitTool, blockerTool, reviewer];
|
|
208
209
|
const agent = {
|
|
209
210
|
id: AGENT_ID,
|
|
210
|
-
systemPrompt: synthesisAgentPrompt,
|
|
211
|
+
systemPrompt: composeSystemPrompt(synthesisAgentPrompt),
|
|
211
212
|
model: input.model,
|
|
212
213
|
tools,
|
|
213
214
|
maxIterations: SYNTHESIZER_MAX_ITERATIONS,
|
|
@@ -29,7 +29,10 @@ import type { LoopMessage } from "../loop/types.js";
|
|
|
29
29
|
import type { AgentChat } from "../providers/types.js";
|
|
30
30
|
import type { WorkspaceFilesystem } from "../workspace/filesystem.js";
|
|
31
31
|
import { type StepSummary } from "../schemas/step-summary.js";
|
|
32
|
+
import type { Logger } from "../lib/logger.js";
|
|
32
33
|
export interface GenerateStepSummaryOptions {
|
|
34
|
+
/** Operational logging seam; omitted falls back to no-op. */
|
|
35
|
+
readonly logger?: Logger;
|
|
33
36
|
readonly provider: AgentChat;
|
|
34
37
|
readonly session: AgentSession;
|
|
35
38
|
readonly modelId: string;
|
|
@@ -28,9 +28,11 @@ import { forSubAgent } from "../auth/types.js";
|
|
|
28
28
|
import { finalText, runAgent } from "../loop/run-agent.js";
|
|
29
29
|
import { passthroughStep } from "../loop/run-step.js";
|
|
30
30
|
import { stepSummaryPrompt } from "../prompts/execute-analysis/step-summary.js";
|
|
31
|
+
import { composeSystemPrompt } from "../agents/system-prompt.js";
|
|
31
32
|
import { createReadFileTool } from "../tools/workspace/read-file.js";
|
|
32
33
|
import { StepSummarySchema } from "../schemas/step-summary.js";
|
|
33
34
|
import { incrementSummaryNullCount } from "./step-summary-metrics.js";
|
|
35
|
+
import { createNoopLogger } from "../lib/console-logger.js";
|
|
34
36
|
const SYSTEM_PROMPT = `You are a sandbox agent writing a post-step interpretive summary of work you just completed.
|
|
35
37
|
|
|
36
38
|
Your prior conversation — tool calls, code output, intermediate results — is in the message history above. Use it for narrative and intent.
|
|
@@ -68,11 +70,12 @@ function sanitizeTranscript(messages) {
|
|
|
68
70
|
* without `summary.md` in that case.
|
|
69
71
|
*/
|
|
70
72
|
export async function generateStepSummary(opts) {
|
|
73
|
+
const logger = (opts.logger ?? createNoopLogger()).named("step-summary").with({ runId: opts.runId, stepId: opts.stepId, agentId: opts.agentId });
|
|
71
74
|
const transcript = sanitizeTranscript(opts.messages);
|
|
72
75
|
const userPrompt = stepSummaryPrompt(opts.artifactPaths.join("\n"));
|
|
73
76
|
const writer = {
|
|
74
77
|
id: SUMMARY_AGENT_ID,
|
|
75
|
-
systemPrompt: SYSTEM_PROMPT,
|
|
78
|
+
systemPrompt: composeSystemPrompt(SYSTEM_PROMPT),
|
|
76
79
|
model: opts.modelId,
|
|
77
80
|
tools: [createReadFileTool(opts.workspaceFs, opts.workingDir)],
|
|
78
81
|
maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,
|
|
@@ -88,13 +91,13 @@ export async function generateStepSummary(opts) {
|
|
|
88
91
|
});
|
|
89
92
|
}
|
|
90
93
|
catch (err) {
|
|
91
|
-
|
|
94
|
+
logger.warn("summary loop failed", logger.errorFields(err));
|
|
92
95
|
incrementSummaryNullCount(opts.agentId, "throw");
|
|
93
96
|
return undefined;
|
|
94
97
|
}
|
|
95
98
|
const markdown = finalText(result.messages);
|
|
96
99
|
if (!markdown || markdown.trim().length === 0) {
|
|
97
|
-
|
|
100
|
+
logger.warn("empty markdown");
|
|
98
101
|
incrementSummaryNullCount(opts.agentId, "empty");
|
|
99
102
|
return undefined;
|
|
100
103
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,8 @@ export { createConfiguredAiSdkProvider } from "./providers/ai-sdk.js";
|
|
|
39
39
|
export type { AiSdkProviderConfig, ConfiguredAiSdkProviderDeps } from "./providers/ai-sdk.js";
|
|
40
40
|
export { createEmbeddingProvider } from "./providers/embedding.js";
|
|
41
41
|
export type { EmbeddingProviderDeps } from "./providers/embedding.js";
|
|
42
|
-
export type { AgentChat, ChatProvider, EmbeddingProvider, ChatRequest, ChatResponse, ChatStreamEvent, ModelMessage } from "./providers/types.js";
|
|
42
|
+
export type { AgentChat, ChatProvider, EmbeddingProvider, ChatRequest, ChatResponse, ChatStreamEvent, ChatUsage, ModelMessage, PromptCachePolicy, } from "./providers/types.js";
|
|
43
|
+
export { DEFAULT_PROMPT_CACHE, promptCacheProviderOptions } from "./providers/prompt-cache.js";
|
|
43
44
|
export { toProviderError, isProviderError } from "./providers/errors.js";
|
|
44
45
|
export type { ProviderError } from "./providers/errors.js";
|
|
45
46
|
export { createStreamingChat } from "./providers/streaming-chat.js";
|
|
@@ -94,7 +95,6 @@ export type { PlanStep } from "./workflows/execute-analysis-scheduler.js";
|
|
|
94
95
|
export { validatePlan } from "./schemas/validate-plan.js";
|
|
95
96
|
export type { ValidatePlanOptions } from "./schemas/validate-plan.js";
|
|
96
97
|
export type { ValidationResult } from "./schemas/validate-plan.js";
|
|
97
|
-
export { renderStepPrompt } from "./schemas/render-step-prompt.js";
|
|
98
98
|
export { upsertPlan, loadPlan } from "./state/plans.js";
|
|
99
99
|
export type { UpsertPlanInput } from "./state/plans.js";
|
|
100
100
|
export { insertRun, queryActiveRun, updateRunStatus, queryRun, queryRunsByAnalysis, RunDedupCollisionError } from "./state/runs.js";
|
|
@@ -102,8 +102,15 @@ export type { InsertRunInput } from "./state/runs.js";
|
|
|
102
102
|
export { queryStepsByRun } from "./state/step-executions.js";
|
|
103
103
|
export type { CortexRunRow, StepExecutionRow, RunStatus } from "./state/schema.js";
|
|
104
104
|
export type { DbError } from "./lib/db-result.js";
|
|
105
|
+
export { REFERENCE_DATA_CATALOG, REFERENCE_DATA_CATALOG_VERSION, ReferenceArtifactPathSchema, ReferenceArtifactSchema, ReferenceDataCatalogSchema, ReferenceDatasetSchema, ReferenceSha256Schema, UnknownReferenceDatasetError, referenceArtifactKey, resolveReferenceInstallPlan, } from "./reference-data/catalog.js";
|
|
106
|
+
export type { ReferenceArtifact, ReferenceDataCatalog, ReferenceDataset, ReferenceInstallPlan, ReferenceInstallPlanDataset, ReferenceIntegrity, } from "./reference-data/catalog.js";
|
|
107
|
+
export { REFERENCE_INSTALL_RECEIPT_VERSION, ReferenceInstallReceiptSchema, parseReferenceInstallReceipt } from "./reference-data/receipt.js";
|
|
108
|
+
export type { ReferenceInstallReceipt, ReferenceReceiptArtifact } from "./reference-data/receipt.js";
|
|
105
109
|
export { queryActiveSandboxes } from "./state/active-sandboxes.js";
|
|
106
110
|
export { runStepDir } from "./workspace/paths.js";
|
|
111
|
+
export type { LogFields, LogLevel, Logger } from "./lib/logger.js";
|
|
112
|
+
export { defaultErrorFields } from "./lib/logger.js";
|
|
113
|
+
export { createConsoleLogger, createNoopLogger } from "./lib/console-logger.js";
|
|
107
114
|
export { registerSandboxReaper } from "./sandbox/reaper.js";
|
|
108
115
|
export type { RegisterReaperDeps } from "./sandbox/reaper.js";
|
|
109
116
|
export { registerWatchdog } from "./sandbox/watchdog.js";
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,14 @@ export { createAnthropicProvider } from "./providers/anthropic.js";
|
|
|
43
43
|
// above is a convenience over this union's `anthropic` arm.
|
|
44
44
|
export { createConfiguredAiSdkProvider } from "./providers/ai-sdk.js";
|
|
45
45
|
export { createEmbeddingProvider } from "./providers/embedding.js";
|
|
46
|
+
// Prompt caching. `PromptCachePolicy` is the harness's vendor-neutral cache
|
|
47
|
+
// directive; a composition root sets it per run via `RunAgentOptions.promptCache`
|
|
48
|
+
// (defaulting to `DEFAULT_PROMPT_CACHE` — 5m — when omitted, since an agent loop
|
|
49
|
+
// re-sends its prefix every iteration and breaks even immediately). Hosts whose
|
|
50
|
+
// endpoint ignores cache directives — notably the Claude Max OAuth path — pass
|
|
51
|
+
// `"off"`; the `cortex.harness.agent.cache_*_tokens` metrics show which case a
|
|
52
|
+
// deployment is actually in.
|
|
53
|
+
export { DEFAULT_PROMPT_CACHE, promptCacheProviderOptions } from "./providers/prompt-cache.js";
|
|
46
54
|
// Provider error channel. `ProviderError` is the value `chat`/`embed` fail
|
|
47
55
|
// with; `toProviderError` is its sole constructor. Exposed so an embedder
|
|
48
56
|
// realizing its own `ChatProvider`/`EmbeddingProvider` fails with the exact
|
|
@@ -129,25 +137,36 @@ export { registerSandboxStep } from "./workflows/sandbox-step.js";
|
|
|
129
137
|
// `SandboxAgentDeps`, then selects the per-step agent by id from this record;
|
|
130
138
|
// `SANDBOX_AGENT_META` is the planner-facing meta the same ids key.
|
|
131
139
|
export { createSandboxAgents, SANDBOX_AGENT_META } from "./agents/sandbox/index.js";
|
|
132
|
-
// Plan schema
|
|
133
|
-
// a
|
|
134
|
-
// receives. `PlanStep` is the minimal `{ id, depends_on }` element type that
|
|
140
|
+
// Plan schema and structural validation — the gates a plan passes before it can
|
|
141
|
+
// trigger a run. `PlanStep` is the minimal `{ id, depends_on }` element type that
|
|
135
142
|
// `ExecuteAnalysisInput.steps` is typed against; a parsed `AnalysisPlan`'s
|
|
136
|
-
// richer `AnalysisStep[]` is assignable to it
|
|
143
|
+
// richer `AnalysisStep[]` is assignable to it, and is also what
|
|
144
|
+
// `ExecuteAnalysisInput.planStepById` carries. There is no prompt renderer here:
|
|
145
|
+
// an embedder supplies the plan's step DATA and the harness composes each step's
|
|
146
|
+
// seed at dispatch, when the step's dependencies have actually produced something.
|
|
137
147
|
export { AnalysisPlanSchema } from "./schemas/workflow-state.js";
|
|
138
148
|
export { validatePlan } from "./schemas/validate-plan.js";
|
|
139
|
-
export { renderStepPrompt } from "./schemas/render-step-prompt.js";
|
|
140
149
|
// Plan + run + step ledgers around a trigger. `upsertPlan` takes a
|
|
141
150
|
// caller-derived id and inserts-if-absent (the deterministic-id intake path);
|
|
142
151
|
// the run-state calls mirror the chat trigger's reserve → dedup → status flow.
|
|
143
152
|
export { upsertPlan, loadPlan } from "./state/plans.js";
|
|
144
153
|
export { insertRun, queryActiveRun, updateRunStatus, queryRun, queryRunsByAnalysis, RunDedupCollisionError } from "./state/runs.js";
|
|
145
154
|
export { queryStepsByRun } from "./state/step-executions.js";
|
|
155
|
+
// Host-neutral reference-data catalog and shared installation receipts. Each
|
|
156
|
+
// artifact names the third-party upstream it is fetched from; embedders own all
|
|
157
|
+
// transfer/storage behavior but never choose a different source.
|
|
158
|
+
export { REFERENCE_DATA_CATALOG, REFERENCE_DATA_CATALOG_VERSION, ReferenceArtifactPathSchema, ReferenceArtifactSchema, ReferenceDataCatalogSchema, ReferenceDatasetSchema, ReferenceSha256Schema, UnknownReferenceDatasetError, referenceArtifactKey, resolveReferenceInstallPlan, } from "./reference-data/catalog.js";
|
|
159
|
+
export { REFERENCE_INSTALL_RECEIPT_VERSION, ReferenceInstallReceiptSchema, parseReferenceInstallReceipt } from "./reference-data/receipt.js";
|
|
146
160
|
// Backs `WatchdogDeps.queryActiveSandboxes` when the embedder wires the watchdog.
|
|
147
161
|
export { queryActiveSandboxes } from "./state/active-sandboxes.js";
|
|
148
162
|
// Workspace-tree path convention — the root-relative step directory each
|
|
149
163
|
// sandbox step confines its artifact writes to (join onto the resolved root).
|
|
150
164
|
export { runStepDir } from "./workspace/paths.js";
|
|
165
|
+
// `Logger.errorFields` is on the interface so a realization can defer to its
|
|
166
|
+
// sink's native error handling (pino's `err` serializer, OTel's `exception.*`);
|
|
167
|
+
// `defaultErrorFields` is the shipped mapping for one with no opinion.
|
|
168
|
+
export { defaultErrorFields } from "./lib/logger.js";
|
|
169
|
+
export { createConsoleLogger, createNoopLogger } from "./lib/console-logger.js";
|
|
151
170
|
// Sandbox-hygiene scheduled workflows. Reaper reclaims a dead host's orphaned
|
|
152
171
|
// containers; watchdog converts a dead sandbox into a prompt step failure
|
|
153
172
|
// instead of a deadline-long `DBOS.recv` hang; the sweep prunes stale
|
package/dist/lib/chrome.d.ts
CHANGED
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
* semaphore so the sidecar isn't overwhelmed by concurrent reports.
|
|
8
8
|
*/
|
|
9
9
|
import type { Browser, BrowserContext, Page } from "puppeteer-core";
|
|
10
|
+
import type { Logger } from "./logger.js";
|
|
10
11
|
export interface ChromeConfig {
|
|
12
|
+
/** Operational logging seam; omitted falls back to no-op. */
|
|
13
|
+
readonly logger?: Logger;
|
|
11
14
|
readonly browserUrl?: string;
|
|
12
15
|
readonly maxPages?: number;
|
|
13
16
|
}
|
|
14
|
-
export declare function getBrowser(browserUrl?: string): Promise<Browser>;
|
|
17
|
+
export declare function getBrowser(browserUrl?: string, injected?: Logger): Promise<Browser>;
|
|
15
18
|
export declare function withPage<T>(cfg: ChromeConfig, fn: (page: Page, context: BrowserContext) => Promise<T>): Promise<T>;
|
package/dist/lib/chrome.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* semaphore so the sidecar isn't overwhelmed by concurrent reports.
|
|
8
8
|
*/
|
|
9
9
|
import puppeteer from "puppeteer-core";
|
|
10
|
+
import { createNoopLogger } from "./console-logger.js";
|
|
10
11
|
let browser;
|
|
11
12
|
let connecting;
|
|
12
13
|
let semaphore;
|
|
@@ -41,7 +42,8 @@ function getSemaphore(maxPages) {
|
|
|
41
42
|
}
|
|
42
43
|
return semaphore;
|
|
43
44
|
}
|
|
44
|
-
export async function getBrowser(browserUrl) {
|
|
45
|
+
export async function getBrowser(browserUrl, injected) {
|
|
46
|
+
const logger = (injected ?? createNoopLogger()).named("chrome");
|
|
45
47
|
if (browser && browser.connected)
|
|
46
48
|
return browser;
|
|
47
49
|
if (connecting)
|
|
@@ -50,21 +52,21 @@ export async function getBrowser(browserUrl) {
|
|
|
50
52
|
if (!browserURL) {
|
|
51
53
|
throw new Error("CHROME_BROWSER_URL is not set — Cortex requires the chrome sidecar to be reachable");
|
|
52
54
|
}
|
|
53
|
-
|
|
55
|
+
logger.info("connecting to browser", { browserURL });
|
|
54
56
|
connecting = puppeteer
|
|
55
57
|
.connect({ browserURL })
|
|
56
58
|
.then((b) => {
|
|
57
59
|
browser = b;
|
|
58
60
|
b.on("disconnected", () => {
|
|
59
|
-
|
|
61
|
+
logger.info("browser disconnected; will reconnect on next request");
|
|
60
62
|
if (browser === b)
|
|
61
63
|
browser = undefined;
|
|
62
64
|
});
|
|
63
|
-
|
|
65
|
+
logger.info("connected", { wsEndpoint: b.wsEndpoint() });
|
|
64
66
|
return b;
|
|
65
67
|
})
|
|
66
68
|
.catch((err) => {
|
|
67
|
-
|
|
69
|
+
logger.error("failed to connect to browser", logger.errorFields(err));
|
|
68
70
|
throw err;
|
|
69
71
|
})
|
|
70
72
|
.finally(() => {
|
|
@@ -76,7 +78,7 @@ export async function withPage(cfg, fn) {
|
|
|
76
78
|
const release = await getSemaphore(cfg.maxPages).acquire();
|
|
77
79
|
let context;
|
|
78
80
|
try {
|
|
79
|
-
const b = await getBrowser(cfg.browserUrl);
|
|
81
|
+
const b = await getBrowser(cfg.browserUrl, cfg.logger);
|
|
80
82
|
context = await b.createBrowserContext();
|
|
81
83
|
const page = await context.newPage();
|
|
82
84
|
return await fn(page, context);
|
|
@@ -87,7 +89,8 @@ export async function withPage(cfg, fn) {
|
|
|
87
89
|
await context.close();
|
|
88
90
|
}
|
|
89
91
|
catch (err) {
|
|
90
|
-
|
|
92
|
+
const logger = (cfg.logger ?? createNoopLogger()).named("chrome");
|
|
93
|
+
logger.error("error closing browser context", logger.errorFields(err));
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
release();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trivial `Logger` realizations: one that writes to `console`, and the
|
|
3
|
+
* silent fallback the harness substitutes when an embedder wires nothing.
|
|
4
|
+
*
|
|
5
|
+
* `createConsoleLogger` is offered, never defaulted. A host whose UI owns
|
|
6
|
+
* stdout (an alternate-screen TUI, for instance) discards console output, so
|
|
7
|
+
* defaulting to it would quietly reintroduce the invisible-diagnostics failure
|
|
8
|
+
* the seam exists to prevent — the default is `createNoopLogger`, which is at
|
|
9
|
+
* least honest about saying nothing.
|
|
10
|
+
*/
|
|
11
|
+
import { type Logger } from "./logger.js";
|
|
12
|
+
/** Build a `Logger` that writes each record to the matching `console` method. */
|
|
13
|
+
export declare function createConsoleLogger(): Logger;
|
|
14
|
+
/**
|
|
15
|
+
* Build a `Logger` that discards every record. This is what the harness falls
|
|
16
|
+
* back to when an embedder injects no logger, so internal call sites can log
|
|
17
|
+
* unconditionally instead of threading `?.` through every diagnostic.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createNoopLogger(): Logger;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trivial `Logger` realizations: one that writes to `console`, and the
|
|
3
|
+
* silent fallback the harness substitutes when an embedder wires nothing.
|
|
4
|
+
*
|
|
5
|
+
* `createConsoleLogger` is offered, never defaulted. A host whose UI owns
|
|
6
|
+
* stdout (an alternate-screen TUI, for instance) discards console output, so
|
|
7
|
+
* defaulting to it would quietly reintroduce the invisible-diagnostics failure
|
|
8
|
+
* the seam exists to prevent — the default is `createNoopLogger`, which is at
|
|
9
|
+
* least honest about saying nothing.
|
|
10
|
+
*/
|
|
11
|
+
import { defaultErrorFields } from "./logger.js";
|
|
12
|
+
/** Renders accumulated namespace segments as the message's `[a.b]` prefix. */
|
|
13
|
+
function prefixed(names, msg) {
|
|
14
|
+
return names.length > 0 ? `[${names.join(".")}] ${msg}` : msg;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `with()` accumulates into `bindings` and `named()` into `names`; each record
|
|
18
|
+
* merges call-site fields over the bindings, so a narrower call-site key
|
|
19
|
+
* deliberately wins over inherited context.
|
|
20
|
+
*/
|
|
21
|
+
function makeConsoleLogger(names, bindings) {
|
|
22
|
+
const emit = (level) => (msg, fields) => {
|
|
23
|
+
// The one sanctioned console site in the harness — writing to console is
|
|
24
|
+
// this function's entire contract. `no-console` exempts this file by path
|
|
25
|
+
// in eslint.config.js rather than by an inline disable here.
|
|
26
|
+
console[level](prefixed(names, msg), { ...bindings, ...fields });
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
debug: emit("debug"),
|
|
30
|
+
info: emit("info"),
|
|
31
|
+
warn: emit("warn"),
|
|
32
|
+
error: emit("error"),
|
|
33
|
+
with: (extra) => makeConsoleLogger(names, { ...bindings, ...extra }),
|
|
34
|
+
named: (name) => makeConsoleLogger([...names, name], bindings),
|
|
35
|
+
// console renders whatever it is handed; there is no native error
|
|
36
|
+
// serializer here to defer to, so the shipped default is the right shape.
|
|
37
|
+
errorFields: defaultErrorFields,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Build a `Logger` that writes each record to the matching `console` method. */
|
|
41
|
+
export function createConsoleLogger() {
|
|
42
|
+
return makeConsoleLogger([], {});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build a `Logger` that discards every record. This is what the harness falls
|
|
46
|
+
* back to when an embedder injects no logger, so internal call sites can log
|
|
47
|
+
* unconditionally instead of threading `?.` through every diagnostic.
|
|
48
|
+
*/
|
|
49
|
+
export function createNoopLogger() {
|
|
50
|
+
const noop = {
|
|
51
|
+
debug: () => { },
|
|
52
|
+
info: () => { },
|
|
53
|
+
warn: () => { },
|
|
54
|
+
error: () => { },
|
|
55
|
+
with: () => noop,
|
|
56
|
+
named: () => noop,
|
|
57
|
+
// Still the real mapping, not `{}`: callers spread the result into fields
|
|
58
|
+
// they may pass elsewhere, so it must stay honest even when nothing is emitted.
|
|
59
|
+
errorFields: defaultErrorFields,
|
|
60
|
+
};
|
|
61
|
+
return noop;
|
|
62
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The harness's operational logging seam.
|
|
3
|
+
*
|
|
4
|
+
* The harness ships as a published package embedded by hosts it does not
|
|
5
|
+
* control, so it declares the shape it logs through and lets the embedder bind
|
|
6
|
+
* a realization at its composition root — the same inversion the capability
|
|
7
|
+
* seams use. Naming a concrete logger here would push that library onto every
|
|
8
|
+
* consumer.
|
|
9
|
+
*
|
|
10
|
+
* The alternative that reads as obvious — take the embedder's logger type
|
|
11
|
+
* directly — was rejected for exactly that reason. `@opentelemetry/api-logs`
|
|
12
|
+
* was the other candidate, being the nearest thing to a neutral standard, but
|
|
13
|
+
* it is still pre-1.0 and would force consumers into an OTel SDK to read a log
|
|
14
|
+
* line. JS has no `log/slog` equivalent to conform to, so the harness defines
|
|
15
|
+
* its own minimum and adapts at the edges.
|
|
16
|
+
*
|
|
17
|
+
* Diagnostics MUST go through here, never `console`: an embedder whose UI owns
|
|
18
|
+
* stdout discards console output entirely, which is silent data loss precisely
|
|
19
|
+
* when something has gone wrong. `createConsoleLogger` (`./console-logger.ts`)
|
|
20
|
+
* is the one sanctioned console site.
|
|
21
|
+
*/
|
|
22
|
+
/** Severity of a log record, ascending. */
|
|
23
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
24
|
+
/**
|
|
25
|
+
* Structured key/value context attached to a record. Identifiers ride here
|
|
26
|
+
* rather than interpolated into the message so records stay queryable and any
|
|
27
|
+
* field-name redaction the host configures can actually match them.
|
|
28
|
+
*/
|
|
29
|
+
export type LogFields = Record<string, unknown>;
|
|
30
|
+
/**
|
|
31
|
+
* Operational logger. Message-first (`error(msg, fields?)`) — the convention
|
|
32
|
+
* `slog`, winston, and `console` share. Object-first loggers exist (pino,
|
|
33
|
+
* bunyan) and an embedder using one adapts at its composition root; shaping
|
|
34
|
+
* this contract to match one of them would model the published surface on a
|
|
35
|
+
* single consumer's choice.
|
|
36
|
+
*/
|
|
37
|
+
export interface Logger {
|
|
38
|
+
debug(msg: string, fields?: LogFields): void;
|
|
39
|
+
info(msg: string, fields?: LogFields): void;
|
|
40
|
+
warn(msg: string, fields?: LogFields): void;
|
|
41
|
+
error(msg: string, fields?: LogFields): void;
|
|
42
|
+
/**
|
|
43
|
+
* Bind `fields` onto every record the returned logger emits — `slog`'s
|
|
44
|
+
* `With`. Lets a workflow body fix `{ runId, stepId }` once instead of
|
|
45
|
+
* repeating it at each call site.
|
|
46
|
+
*/
|
|
47
|
+
with(fields: LogFields): Logger;
|
|
48
|
+
/**
|
|
49
|
+
* Bind a namespace onto every record the returned logger emits, rendered as
|
|
50
|
+
* a bracketed prefix on the message: `named("boot")` turns
|
|
51
|
+
* `info("harness booted")` into `[boot] harness booted`.
|
|
52
|
+
*
|
|
53
|
+
* The namespace is a first-class part of a record, so it is declared once at
|
|
54
|
+
* the seam rather than hand-typed into every message string — hand-typing is
|
|
55
|
+
* what lets one module drift to `[Boot]` or drop the tag entirely. Nesting
|
|
56
|
+
* composes with a dot (`named("post-step").named("reconcile")` →
|
|
57
|
+
* `[post-step.reconcile]`), matching the tag convention already in use.
|
|
58
|
+
*/
|
|
59
|
+
named(name: string): Logger;
|
|
60
|
+
/**
|
|
61
|
+
* Normalize a thrown value into fields to spread onto a record:
|
|
62
|
+
* `logger.error("step failure", { ...logger.errorFields(err), stepId })`.
|
|
63
|
+
*
|
|
64
|
+
* Every catch block would otherwise hand-roll
|
|
65
|
+
* `err instanceof Error ? err.message : String(err)` — repetition that
|
|
66
|
+
* reliably drifts, and that silently drops the stack from whichever site
|
|
67
|
+
* forgot it.
|
|
68
|
+
*
|
|
69
|
+
* It lives on the interface rather than as a free function because how an
|
|
70
|
+
* error is best represented is a property of the SINK, not of the harness: a
|
|
71
|
+
* pino-backed realization may defer to pino's `err` serializer, an
|
|
72
|
+
* OTel-backed one to the `exception.*` semantic conventions. Owning the
|
|
73
|
+
* mapping here would foreclose both. `defaultErrorFields` is the shipped
|
|
74
|
+
* implementation — a realization with no opinion just references it.
|
|
75
|
+
*/
|
|
76
|
+
errorFields(err: unknown): LogFields;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The default `Logger.errorFields`: `err` carries the message, `stack` rides as
|
|
80
|
+
* its own field when there is one.
|
|
81
|
+
*
|
|
82
|
+
* A raw `Error` is deliberately not passed through as a field value: it is
|
|
83
|
+
* assignable to `unknown` and so type-checks, but `JSON.stringify(new Error())`
|
|
84
|
+
* is `{}` — a sink that serializes to JSON would drop the message entirely,
|
|
85
|
+
* which is the silent-loss failure this seam exists to prevent. Normalizing to
|
|
86
|
+
* strings means any sink gets something printable regardless of its serializer.
|
|
87
|
+
*/
|
|
88
|
+
export declare function defaultErrorFields(err: unknown): LogFields;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The harness's operational logging seam.
|
|
3
|
+
*
|
|
4
|
+
* The harness ships as a published package embedded by hosts it does not
|
|
5
|
+
* control, so it declares the shape it logs through and lets the embedder bind
|
|
6
|
+
* a realization at its composition root — the same inversion the capability
|
|
7
|
+
* seams use. Naming a concrete logger here would push that library onto every
|
|
8
|
+
* consumer.
|
|
9
|
+
*
|
|
10
|
+
* The alternative that reads as obvious — take the embedder's logger type
|
|
11
|
+
* directly — was rejected for exactly that reason. `@opentelemetry/api-logs`
|
|
12
|
+
* was the other candidate, being the nearest thing to a neutral standard, but
|
|
13
|
+
* it is still pre-1.0 and would force consumers into an OTel SDK to read a log
|
|
14
|
+
* line. JS has no `log/slog` equivalent to conform to, so the harness defines
|
|
15
|
+
* its own minimum and adapts at the edges.
|
|
16
|
+
*
|
|
17
|
+
* Diagnostics MUST go through here, never `console`: an embedder whose UI owns
|
|
18
|
+
* stdout discards console output entirely, which is silent data loss precisely
|
|
19
|
+
* when something has gone wrong. `createConsoleLogger` (`./console-logger.ts`)
|
|
20
|
+
* is the one sanctioned console site.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The default `Logger.errorFields`: `err` carries the message, `stack` rides as
|
|
24
|
+
* its own field when there is one.
|
|
25
|
+
*
|
|
26
|
+
* A raw `Error` is deliberately not passed through as a field value: it is
|
|
27
|
+
* assignable to `unknown` and so type-checks, but `JSON.stringify(new Error())`
|
|
28
|
+
* is `{}` — a sink that serializes to JSON would drop the message entirely,
|
|
29
|
+
* which is the silent-loss failure this seam exists to prevent. Normalizing to
|
|
30
|
+
* strings means any sink gets something printable regardless of its serializer.
|
|
31
|
+
*/
|
|
32
|
+
export function defaultErrorFields(err) {
|
|
33
|
+
if (err instanceof Error) {
|
|
34
|
+
return err.stack ? { err: err.message, stack: err.stack } : { err: err.message };
|
|
35
|
+
}
|
|
36
|
+
return { err: String(err) };
|
|
37
|
+
}
|
package/dist/lib/otel.d.ts
CHANGED
|
@@ -15,13 +15,14 @@
|
|
|
15
15
|
* so inbound/outbound trace-context propagation across those paths is
|
|
16
16
|
* not currently wired.
|
|
17
17
|
*/
|
|
18
|
+
import type { Logger } from "./logger.js";
|
|
18
19
|
/**
|
|
19
20
|
* Initialize the OpenTelemetry SDK. Must be called before any code that
|
|
20
21
|
* calls trace.getTracer() or metrics.getMeter().
|
|
21
22
|
*
|
|
22
23
|
* Safe to call multiple times — only the first call has effect.
|
|
23
24
|
*/
|
|
24
|
-
export declare function initOtel(): void;
|
|
25
|
+
export declare function initOtel(injected?: Logger): void;
|
|
25
26
|
/**
|
|
26
27
|
* Flush and shut down the OTel exporters. Called by the graceful-shutdown
|
|
27
28
|
* sequence so in-flight batch spans/metrics make it to the collector
|
package/dist/lib/otel.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* not currently wired.
|
|
17
17
|
*/
|
|
18
18
|
import { propagation, metrics, trace } from "@opentelemetry/api";
|
|
19
|
+
import { createNoopLogger } from "./console-logger.js";
|
|
19
20
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
20
21
|
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
21
22
|
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
@@ -33,10 +34,11 @@ let registeredMeterProvider;
|
|
|
33
34
|
*
|
|
34
35
|
* Safe to call multiple times — only the first call has effect.
|
|
35
36
|
*/
|
|
36
|
-
export function initOtel() {
|
|
37
|
+
export function initOtel(injected) {
|
|
37
38
|
if (initialized)
|
|
38
39
|
return;
|
|
39
40
|
initialized = true;
|
|
41
|
+
const logger = (injected ?? createNoopLogger()).named("otel");
|
|
40
42
|
// ── W3C Trace Context propagation ──────────────────────────────────
|
|
41
43
|
propagation.setGlobalPropagator(new W3CTraceContextPropagator());
|
|
42
44
|
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
@@ -65,8 +67,11 @@ export function initOtel() {
|
|
|
65
67
|
const testSpan = testTracer.startSpan("init-check");
|
|
66
68
|
const ctx = testSpan.spanContext();
|
|
67
69
|
const isNoop = ctx.spanId === "0000000000000000";
|
|
68
|
-
console.log
|
|
69
|
-
|
|
70
|
+
// A `console.log` here is what forced the CLI embedder to pass
|
|
71
|
+
// `initTelemetry: () => {}` — its TUI owns stdout, so the banner corrupted
|
|
72
|
+
// the screen and the whole of the harness's traces + metrics were switched
|
|
73
|
+
// off to avoid it. At debug through the injected seam it costs nothing.
|
|
74
|
+
logger.debug("TracerProvider registered", { spanId: ctx.spanId, noop: isNoop, endpoint: endpoint ?? null, processors: spanProcessors.length });
|
|
70
75
|
testSpan.end();
|
|
71
76
|
}
|
|
72
77
|
// ── Metrics ────────────────────────────────────────────────────────
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatResponse, ChatProvider, ChatRequest } from "../../providers/types.js";
|
|
1
|
+
import type { ChatResponse, ChatProvider, ChatRequest, ChatUsage } from "../../providers/types.js";
|
|
2
2
|
import type { AgentSession as Session } from "../../auth/types.js";
|
|
3
3
|
export type TextBlock = {
|
|
4
4
|
type: "text";
|
|
@@ -20,7 +20,7 @@ export type ToolUseBlock = {
|
|
|
20
20
|
input: unknown;
|
|
21
21
|
};
|
|
22
22
|
export type ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock;
|
|
23
|
-
export declare function makeMessage(content: ContentBlock[], finishReason: ChatResponse["finishReason"] | "tool_use" | "end_turn" | "max_tokens" | "refusal"): ChatResponse;
|
|
23
|
+
export declare function makeMessage(content: ContentBlock[], finishReason: ChatResponse["finishReason"] | "tool_use" | "end_turn" | "max_tokens" | "refusal", usage?: ChatUsage): ChatResponse;
|
|
24
24
|
export declare function textBlock(text: string): TextBlock;
|
|
25
25
|
export declare function thinkingBlock(thinking: string, signature: string): ThinkingBlock;
|
|
26
26
|
export declare function toolUseBlock(id: string, name: string, input: unknown): ToolUseBlock;
|
|
@@ -13,10 +13,11 @@ function mapFinishReason(finishReason) {
|
|
|
13
13
|
return finishReason;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
export function makeMessage(content, finishReason) {
|
|
16
|
+
export function makeMessage(content, finishReason, usage) {
|
|
17
17
|
return {
|
|
18
18
|
message: { role: "assistant", content },
|
|
19
19
|
finishReason: mapFinishReason(finishReason),
|
|
20
|
+
usage,
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
export function textBlock(text) {
|