@inflexa-ai/harness 0.37.0 → 0.39.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 +1 -2
- package/dist/auth/local-run-authorizer.js +5 -4
- package/dist/auth/types.d.ts +28 -9
- package/dist/auth/types.js +5 -3
- package/dist/billing/cached-resolver.d.ts +11 -7
- package/dist/billing/cached-resolver.js +17 -11
- package/dist/billing/noop-run-charge.js +3 -2
- package/dist/billing/noop-usage-recorder.js +2 -1
- package/dist/billing/run-charge.d.ts +18 -5
- package/dist/billing/run-charge.js +5 -1
- package/dist/billing/usage-recorder.d.ts +11 -9
- package/dist/billing/usage-recorder.js +2 -3
- package/dist/contracts/chat-events.d.ts +4 -1
- package/dist/contracts/chat-parts.d.ts +1 -1
- package/dist/contracts/schemas/chat-parts.d.ts +4 -4
- package/dist/execution/artifact-registration.d.ts +6 -1
- package/dist/execution/artifact-registration.js +12 -4
- package/dist/execution/artifact-registry.d.ts +10 -3
- package/dist/execution/noop-artifact-registry.js +3 -4
- package/dist/execution/post-step-pipeline.d.ts +14 -3
- package/dist/execution/post-step-pipeline.js +21 -8
- package/dist/execution/run-authorizer.d.ts +5 -3
- package/dist/execution/run-canceler.js +4 -20
- package/dist/index.d.ts +14 -8
- package/dist/index.js +12 -6
- package/dist/lib/hooks.d.ts +49 -0
- package/dist/lib/hooks.js +39 -0
- package/dist/lib/result.d.ts +22 -11
- package/dist/lib/result.js +24 -14
- package/dist/loop/run-agent.d.ts +2 -2
- package/dist/loop/run-agent.js +5 -4
- package/dist/provenance/seam.d.ts +1 -1
- package/dist/providers/ai-sdk.d.ts +43 -5
- package/dist/providers/ai-sdk.js +55 -52
- package/dist/providers/anthropic.d.ts +2 -3
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/embedding.d.ts +13 -7
- package/dist/providers/embedding.js +26 -6
- package/dist/providers/errors.d.ts +67 -37
- package/dist/providers/errors.js +57 -58
- package/dist/providers/request-headers.d.ts +18 -0
- package/dist/providers/request-headers.js +22 -0
- package/dist/report-model/production-resolver.d.ts +5 -2
- package/dist/report-model/production-resolver.js +12 -2
- package/dist/runtime/assemble.d.ts +3 -2
- package/dist/runtime/dbos.d.ts +4 -3
- package/dist/runtime/dbos.js +18 -3
- package/dist/runtime/result-serialization.d.ts +29 -0
- package/dist/runtime/result-serialization.js +45 -0
- package/dist/sandbox/client.d.ts +11 -3
- package/dist/sandbox/create-sandbox.d.ts +5 -2
- package/dist/sandbox/create-sandbox.js +51 -25
- package/dist/sandbox/docker-client.d.ts +4 -3
- package/dist/sandbox/docker-client.js +23 -31
- package/dist/sandbox/k8s-client.d.ts +4 -13
- package/dist/sandbox/k8s-client.js +28 -61
- package/dist/sandbox/labels.d.ts +34 -0
- package/dist/sandbox/labels.js +47 -0
- package/dist/sandbox/mount-plan.d.ts +3 -1
- package/dist/sandbox/mount-plan.js +9 -0
- package/dist/sandbox/sandbox-error.d.ts +36 -13
- package/dist/sandbox/sandbox-error.js +32 -17
- package/dist/sandbox/types.d.ts +18 -10
- package/dist/schemas/validate-plan.js +13 -0
- package/dist/schemas/workflow-state.d.ts +4 -4
- package/dist/state/analyses.d.ts +4 -4
- package/dist/state/analyses.js +4 -4
- package/dist/state/schema.d.ts +5 -5
- package/dist/tasks/data-profile.d.ts +5 -8
- package/dist/tasks/data-profile.js +88 -43
- package/dist/tasks/derive-table-exec.d.ts +10 -6
- package/dist/tasks/derive-table-exec.js +17 -12
- package/dist/tasks/extract-values.d.ts +16 -10
- package/dist/tasks/extract-values.js +34 -18
- package/dist/tools/execute-analysis.js +29 -24
- package/dist/tools/report-session/derive-table.d.ts +9 -1
- package/dist/tools/report-session/derive-table.js +25 -22
- package/dist/tools/report-session/examine-page.d.ts +6 -3
- package/dist/tools/report-session/examine-page.js +16 -8
- package/dist/tools/report-session/index.d.ts +1 -1
- package/dist/tools/report-session/preview-report.js +11 -9
- package/dist/tools/report-session/session-page-publisher.d.ts +17 -21
- package/dist/tools/report-session/session-page-publisher.js +5 -7
- package/dist/tools/research/inspect-run.d.ts +1 -1
- package/dist/tools/sandbox/link-packages.d.ts +8 -0
- package/dist/tools/sandbox/link-packages.js +19 -9
- package/dist/workflows/execute-analysis.d.ts +25 -16
- package/dist/workflows/execute-analysis.js +223 -216
- package/dist/workflows/metrics.d.ts +4 -3
- package/dist/workflows/metrics.js +4 -3
- package/dist/workflows/sandbox-step.d.ts +20 -29
- package/dist/workflows/sandbox-step.js +71 -127
- package/dist/workflows/suspension.d.ts +32 -0
- package/dist/workflows/suspension.js +38 -0
- package/package.json +1 -1
- package/dist/billing/noop-resolver.d.ts +0 -6
- package/dist/billing/noop-resolver.js +0 -7
- package/dist/billing/resolver.d.ts +0 -64
- package/dist/billing/resolver.js +0 -24
- package/dist/loop/budget-exceeded.d.ts +0 -38
- package/dist/loop/budget-exceeded.js +0 -88
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* fail-fast vs. best-effort. This module owns only the stage bodies.
|
|
12
12
|
*/
|
|
13
13
|
import { join } from "node:path";
|
|
14
|
+
import { err, ok } from "neverthrow";
|
|
14
15
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
15
16
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
16
17
|
import { writeFileWithinRoot } from "../lib/fs-helpers.js";
|
|
@@ -92,14 +93,18 @@ export async function generateStepSummaryAndWrite(deps, postCtx, manifest) {
|
|
|
92
93
|
}
|
|
93
94
|
return summary;
|
|
94
95
|
}
|
|
96
|
+
export function describeStepRegistrationFailure(failure) {
|
|
97
|
+
return failure.kind === "refused" ? `the artifact registry refused the registration: ${failure.refusal.reason}` : failure.message;
|
|
98
|
+
}
|
|
95
99
|
/**
|
|
96
100
|
* Reconcile the manifest against disk (drop phantoms, rehash) and register the
|
|
97
101
|
* survivors with the local ledger + the injected `ArtifactRegistry`. Fail-fast
|
|
98
102
|
* (see the artifact-manifest spec): `externalFailed` counts only the terminal
|
|
99
103
|
* rejections — a rejected output whose bytes exist nowhere but the step tree,
|
|
100
104
|
* plus anything rejected as a consequence of one — so a non-zero count means
|
|
101
|
-
* real outputs went unregistered, and
|
|
102
|
-
* OSS filesystem registry returns `externalFailed: 0`, so it never trips).
|
|
105
|
+
* real outputs went unregistered, and the `err` carries the per-file detail (the
|
|
106
|
+
* OSS filesystem registry returns `externalFailed: 0`, so it never trips). A
|
|
107
|
+
* refusal of the `register` gate is the other `err`.
|
|
103
108
|
* Returns the reconciled manifest.
|
|
104
109
|
*/
|
|
105
110
|
export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest) {
|
|
@@ -115,14 +120,17 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
|
|
|
115
120
|
...(deps.logger ? { logger: deps.logger } : {}),
|
|
116
121
|
});
|
|
117
122
|
if (reconciled.manifest.length === 0)
|
|
118
|
-
return reconciled.manifest;
|
|
119
|
-
const
|
|
123
|
+
return ok(reconciled.manifest);
|
|
124
|
+
const registered = await registerStepArtifacts(deps.pool, deps.artifactRegistry, {
|
|
120
125
|
resourceId: input.analysisId,
|
|
121
126
|
runId: input.runId,
|
|
122
127
|
stepId: input.stepId,
|
|
123
128
|
artifacts: reconciled.manifest,
|
|
124
129
|
collector: lineageCollector,
|
|
125
130
|
}, session, deps.logger);
|
|
131
|
+
if (registered.isErr())
|
|
132
|
+
return err({ kind: "refused", refusal: registered.error });
|
|
133
|
+
const reg = registered.value;
|
|
126
134
|
if (reg.externalFailed > 0) {
|
|
127
135
|
// The registry commits per leaf and per activity, so accepted and rejected
|
|
128
136
|
// rows arriving together is ordinary and `externalRegistered` is what
|
|
@@ -137,7 +145,7 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
|
|
|
137
145
|
`${reg.externalFailed} terminal rejection(s), ${reg.externalRegistered}/${reg.localCount} local artifact(s) registered` +
|
|
138
146
|
(noneRegistered ? " (nothing in this batch registered)" : "") +
|
|
139
147
|
(detail ? `\n ${detail}` : "");
|
|
140
|
-
// Logged as fields as well as
|
|
148
|
+
// Logged as fields as well as returned: the failure reaches `failStep` as one
|
|
141
149
|
// opaque string, so the per-path rejections are only queryable from here.
|
|
142
150
|
// This is what distinguishes a registry rejection from the attestation
|
|
143
151
|
// throws in `reconcileManifestWithDisk` when a step dies.
|
|
@@ -150,9 +158,9 @@ export async function reconcileAndRegisterStepArtifacts(deps, postCtx, manifest)
|
|
|
150
158
|
noneRegistered,
|
|
151
159
|
failures: reg.failureDetails,
|
|
152
160
|
});
|
|
153
|
-
|
|
161
|
+
return err({ kind: "rejected", message: msg });
|
|
154
162
|
}
|
|
155
|
-
return reconciled.manifest;
|
|
163
|
+
return ok(reconciled.manifest);
|
|
156
164
|
}
|
|
157
165
|
/**
|
|
158
166
|
* Vector-index the threaded file descriptions + the step summary into the
|
|
@@ -212,7 +220,12 @@ export async function vectorIndexStepOutputs(deps, postCtx, artifacts) {
|
|
|
212
220
|
let indexed = 0;
|
|
213
221
|
let failed = 0;
|
|
214
222
|
for (const entry of liveMetadata) {
|
|
215
|
-
const ok = await indexOne(`/${input.analysisId}/${entry.dbPath}`, entry.description, {
|
|
223
|
+
const ok = await indexOne(`/${input.analysisId}/${entry.dbPath}`, entry.description, {
|
|
224
|
+
text: entry.description,
|
|
225
|
+
type: "output",
|
|
226
|
+
...entry.metadata,
|
|
227
|
+
path: entry.dbPath,
|
|
228
|
+
});
|
|
216
229
|
if (ok)
|
|
217
230
|
indexed++;
|
|
218
231
|
else
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* Mirrors the `SessionPagePublisher` seam: a narrow interface in the harness, the managed
|
|
15
15
|
* realization injected at the composition root.
|
|
16
16
|
*/
|
|
17
|
+
import type { ResultAsync } from "neverthrow";
|
|
17
18
|
import type { AuthContext, Provenance, RunFrame, RunSession, Scope } from "../auth/types.js";
|
|
19
|
+
import type { GateFailure, NoticeFailure } from "../lib/hooks.js";
|
|
18
20
|
/**
|
|
19
21
|
* Locates a run credential when no `RunAuthorization` exists: the persisted
|
|
20
22
|
* jti from `cortex_runs` plus the revoking caller's opaque `auth` — the sole
|
|
@@ -48,8 +50,8 @@ export interface RunAuthorization {
|
|
|
48
50
|
* path (a no-op for reused or local authorizations).
|
|
49
51
|
*/
|
|
50
52
|
export interface RunAuthorizer {
|
|
51
|
-
authorize(input: AuthorizeRunInput):
|
|
52
|
-
revoke(authorization: RunAuthorization, reason: string):
|
|
53
|
+
authorize(input: AuthorizeRunInput): ResultAsync<RunAuthorization, GateFailure>;
|
|
54
|
+
revoke(authorization: RunAuthorization, reason: string): ResultAsync<void, NoticeFailure>;
|
|
53
55
|
/**
|
|
54
56
|
* Out-of-band revocation for paths holding no `RunAuthorization`. Normal
|
|
55
57
|
* terminal paths use `revoke(authorization, reason)` under the run
|
|
@@ -57,5 +59,5 @@ export interface RunAuthorizer {
|
|
|
57
59
|
* credential's JWT was never persisted and only its jti survives on
|
|
58
60
|
* `cortex_runs`. Local/OSS authorizers no-op — they mint no jti.
|
|
59
61
|
*/
|
|
60
|
-
revokeByJti(ref: RevokeByJtiRef, reason: string):
|
|
62
|
+
revokeByJti(ref: RevokeByJtiRef, reason: string): ResultAsync<void, NoticeFailure>;
|
|
61
63
|
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* terminal frame read-side.
|
|
19
19
|
*/
|
|
20
20
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
21
|
+
import { deliverNotice } from "../lib/hooks.js";
|
|
21
22
|
import { elapsedSinceIso, recordRunCompleted, recordStepCompleted } from "../lib/metrics.js";
|
|
22
23
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
23
24
|
import { markRunCanceledIfActive, queryRun } from "../state/runs.js";
|
|
@@ -113,26 +114,9 @@ export function createRunCanceler(deps) {
|
|
|
113
114
|
catch (err) {
|
|
114
115
|
logger.error("pending-step sweep failed", { runId, ...logger.errorFields(err) });
|
|
115
116
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
await runCharge.close({ analysisId: row.analysisId, runId, reason: "canceled", session });
|
|
121
|
-
charge = true;
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
logger.error("running-charge close failed", { runId, ...logger.errorFields(err) });
|
|
125
|
-
}
|
|
126
|
-
let mandate = row.mandateJti === null;
|
|
127
|
-
if (row.mandateJti !== null) {
|
|
128
|
-
try {
|
|
129
|
-
await runAuthorizer.revokeByJti({ jti: row.mandateJti, auth: session.auth }, EXTERNAL_CANCEL_REASON);
|
|
130
|
-
mandate = true;
|
|
131
|
-
}
|
|
132
|
-
catch (err) {
|
|
133
|
-
logger.error("mandate revoke failed", { runId, jti: row.mandateJti, ...logger.errorFields(err) });
|
|
134
|
-
}
|
|
135
|
-
}
|
|
117
|
+
const charge = await deliverNotice(logger.with({ runId }), "RunCharge.close", runCharge.close({ analysisId: row.analysisId, runId, outcome: { kind: "canceled" }, session }));
|
|
118
|
+
const mandate = row.mandateJti === null ||
|
|
119
|
+
(await deliverNotice(logger.with({ runId, jti: row.mandateJti }), "RunAuthorizer.revokeByJti", runAuthorizer.revokeByJti({ jti: row.mandateJti, auth: session.auth }, EXTERNAL_CANCEL_REASON)));
|
|
136
120
|
// No transition means the run reached a terminal state on its own (or the
|
|
137
121
|
// write failed) — report the row as it stands rather than claiming `canceled`.
|
|
138
122
|
let finalStatus = "canceled";
|
package/dist/index.d.ts
CHANGED
|
@@ -24,10 +24,10 @@ export type { ConversationAgentDeps } from "./agents/conversation-agent.js";
|
|
|
24
24
|
export type { BioToolKeys } from "./tools/bio/keys.js";
|
|
25
25
|
export { createLocalRunAuthorizer } from "./auth/local-run-authorizer.js";
|
|
26
26
|
export type { RunAuthorizer, AuthorizeRunInput, RunAuthorization, RevokeByJtiRef } from "./execution/run-authorizer.js";
|
|
27
|
-
export {
|
|
28
|
-
export type {
|
|
27
|
+
export type { GateFailure, NoticeFailure } from "./lib/hooks.js";
|
|
28
|
+
export type { RequestHeaders, ResolveRequestHeaders } from "./providers/request-headers.js";
|
|
29
29
|
export { createNoopRunCharge } from "./billing/noop-run-charge.js";
|
|
30
|
-
export type { RunCharge } from "./billing/run-charge.js";
|
|
30
|
+
export type { RunCharge, RunChargeOutcome } from "./billing/run-charge.js";
|
|
31
31
|
export { createNoopUsageRecorder } from "./billing/noop-usage-recorder.js";
|
|
32
32
|
export type { UsageRecorder, LlmUsageRecord } from "./billing/usage-recorder.js";
|
|
33
33
|
export { createNoopArtifactRegistry } from "./execution/noop-artifact-registry.js";
|
|
@@ -35,7 +35,7 @@ export type { ArtifactRegistry, ArtifactRegistrationInput, ArtifactSyncInput, Ex
|
|
|
35
35
|
export type { ArtifactManifestEntry } from "./schemas/artifact-manifest.js";
|
|
36
36
|
export type { ProvenanceCollector } from "./provenance/collector.js";
|
|
37
37
|
export { UnavailableSessionPagePublisher } from "./tools/report-session/session-page-publisher.js";
|
|
38
|
-
export type { MakeSessionPagePublisher, SessionPagePublisher,
|
|
38
|
+
export type { MakeSessionPagePublisher, SessionPageGrant, SessionPageMintFailure, SessionPagePublisher, } from "./tools/report-session/session-page-publisher.js";
|
|
39
39
|
export type { ResolvePageUrl, SessionPageAccess } from "./tools/report-session/index.js";
|
|
40
40
|
export { bindReadExport, bindSessionEmit } from "./provenance/seam.js";
|
|
41
41
|
export type { ProvenanceExport, ProvenanceSeam, RunProvenanceEvent, SessionProvenanceEvent } from "./provenance/seam.js";
|
|
@@ -63,12 +63,12 @@ export type { RunAgentOptions, RunAgentResult, AgentFinish } from "./loop/run-ag
|
|
|
63
63
|
export type { AgentDefinition, RunStep, EmitFn, EmitEvent, EventSource } from "./loop/types.js";
|
|
64
64
|
export { passthroughStep } from "./loop/run-step.js";
|
|
65
65
|
export { forStep, forSubAgent, scopeResource, scopeWorkloadId } from "./auth/types.js";
|
|
66
|
-
export type { AgentSession, RequestSession, RunSession, Identity, Scope, Credential, Provenance, RunFrame, AuthContext, ResourceCoordinates, } from "./auth/types.js";
|
|
66
|
+
export type { AgentSession, RequestSession, RunSession, Identity, Scope, Credential, Provenance, RunFrame, AuthContext, ResourceCoordinates, HookSessionView, ResolvableSession, } from "./auth/types.js";
|
|
67
67
|
export { makeLocalAuth } from "./auth/local-auth-context.js";
|
|
68
68
|
export { createAnthropicProvider } from "./providers/anthropic.js";
|
|
69
69
|
export type { AnthropicProviderDeps } from "./providers/anthropic.js";
|
|
70
70
|
export { createConfiguredAiSdkProvider, DEFAULT_MAX_OUTPUT_TOKENS } from "./providers/ai-sdk.js";
|
|
71
|
-
export type { AiSdkProviderConfig, ConfiguredAiSdkProviderDeps } from "./providers/ai-sdk.js";
|
|
71
|
+
export type { AiSdkProviderConfig, ConfiguredAiSdkProviderDeps, ProviderHostPolicy } from "./providers/ai-sdk.js";
|
|
72
72
|
export { createEmbeddingProvider } from "./providers/embedding.js";
|
|
73
73
|
export type { EmbeddingProviderDeps } from "./providers/embedding.js";
|
|
74
74
|
export type { AgentChat, ChatProvider, EmbeddingProvider, ChatRequest, ChatResponse, ChatStreamEvent, ChatUsage, ModelMessage, PromptCachePolicy, ReasoningPolicy, } from "./providers/types.js";
|
|
@@ -76,6 +76,10 @@ export { DEFAULT_PROMPT_CACHE, promptCacheProviderOptions, withPromptCacheBreakp
|
|
|
76
76
|
export { DEFAULT_REASONING } from "./providers/reasoning.js";
|
|
77
77
|
export { toProviderError, isProviderError } from "./providers/errors.js";
|
|
78
78
|
export type { ProviderError } from "./providers/errors.js";
|
|
79
|
+
export { DEFAULT_SUSPEND_ON } from "./providers/errors.js";
|
|
80
|
+
export type { SuspendOn } from "./providers/errors.js";
|
|
81
|
+
export { suspensionOfFailure } from "./workflows/suspension.js";
|
|
82
|
+
export type { Suspension } from "./workflows/suspension.js";
|
|
79
83
|
export { createStreamingChat } from "./providers/streaming-chat.js";
|
|
80
84
|
export { prepareChatTurn } from "./app/chat-turn.js";
|
|
81
85
|
export type { PrepareChatTurnDeps, PrepareChatTurnParams, PrepareChatTurnResult } from "./app/chat-turn.js";
|
|
@@ -137,8 +141,10 @@ export type { ResolveWorkspaceRoot } from "./workspace/paths.js";
|
|
|
137
141
|
export { createSandboxClient } from "./sandbox/create-sandbox.js";
|
|
138
142
|
export type { CreateSandboxClientConfig, SandboxBackendConfig } from "./sandbox/create-sandbox.js";
|
|
139
143
|
export type { SandboxClient } from "./sandbox/client.js";
|
|
140
|
-
export {
|
|
141
|
-
export type {
|
|
144
|
+
export type { ResolveSandboxLabels, SandboxLabels, SandboxSpec } from "./sandbox/types.js";
|
|
145
|
+
export type { SpawnSession } from "./auth/types.js";
|
|
146
|
+
export { describeSandboxError, keepSuspendingRefusal, SandboxFailure } from "./sandbox/sandbox-error.js";
|
|
147
|
+
export type { SandboxError, SuspendingRefusal } from "./sandbox/sandbox-error.js";
|
|
142
148
|
export type { ExtendAnalysisFarm, FarmLocation, FarmResolution, FarmSource, PackageRequestOutcome, ResolveAnalysisFarm, ToolchainSource, } from "./sandbox/types.js";
|
|
143
149
|
export { formatQuery, identityAddress, identityKey, identityOf, parseIdentityKey, parseQuery, pythonIdentity, resolveQuery, rIdentity, } from "./sandbox/package-identity.js";
|
|
144
150
|
export type { PackageIdentity, PackageQuery, ParseQueryError, PoolIndex, QueryResolution, Track } from "./sandbox/package-identity.js";
|
package/dist/index.js
CHANGED
|
@@ -29,13 +29,11 @@ export { bootHarness } from "./runtime/boot.js";
|
|
|
29
29
|
export { createConversationAgent } from "./agents/conversation-agent.js";
|
|
30
30
|
// Seam: run authorization.
|
|
31
31
|
export { createLocalRunAuthorizer } from "./auth/local-run-authorizer.js";
|
|
32
|
-
// Seam: billing resolution.
|
|
33
|
-
export { createNoopBillingResolver } from "./billing/noop-resolver.js";
|
|
34
32
|
// Seam: run-level billing bracket.
|
|
35
33
|
export { createNoopRunCharge } from "./billing/noop-run-charge.js";
|
|
36
|
-
// Seam: per-call LLM usage accounting. `record` is
|
|
37
|
-
//
|
|
38
|
-
//
|
|
34
|
+
// Seam: per-call LLM usage accounting. `record` is a notice: the loop does not
|
|
35
|
+
// wait for its result, and it logs the reason of an err when the result
|
|
36
|
+
// arrives. Wired as the optional `usageRecorder` of `assembleCoreRuntime`;
|
|
39
37
|
// unwired, every call is dropped by `createNoopUsageRecorder`.
|
|
40
38
|
export { createNoopUsageRecorder } from "./billing/noop-usage-recorder.js";
|
|
41
39
|
// Seam: artifact registration.
|
|
@@ -135,6 +133,12 @@ export { DEFAULT_REASONING } from "./providers/reasoning.js";
|
|
|
135
133
|
// directly needs: `chatStream` throws a `ProviderError` value (a plain object,
|
|
136
134
|
// not an `Error`), so a `catch` recognizes it by shape, not `instanceof`.
|
|
137
135
|
export { toProviderError, isProviderError } from "./providers/errors.js";
|
|
136
|
+
// The suspend map of a provider: an HTTP status to the suspend reason of the
|
|
137
|
+
// host. A map from the host replaces `DEFAULT_SUSPEND_ON`, which holds `402`.
|
|
138
|
+
export { DEFAULT_SUSPEND_ON } from "./providers/errors.js";
|
|
139
|
+
// The suspension of work. A host reads the suspend reason of a failed chat turn
|
|
140
|
+
// with `suspensionOfFailure`, by the kind of the error, never by its text.
|
|
141
|
+
export { suspensionOfFailure } from "./workflows/suspension.js";
|
|
138
142
|
// `createStreamingChat` wraps a `ChatProvider` as a streaming `AgentChat` (the
|
|
139
143
|
// type `runAgent`'s `provider` option takes): its `chat` drives the provider's
|
|
140
144
|
// `chatStream` and forwards each text delta to `onText`, so a same-process host
|
|
@@ -248,7 +252,9 @@ export { computeInputSignature } from "./execution/input-signature.js";
|
|
|
248
252
|
export { createSandboxClient } from "./sandbox/create-sandbox.js";
|
|
249
253
|
// The throw of the client seam. An embedder matches the class and reads the
|
|
250
254
|
// typed variant on `error`, instead of a string match on the message.
|
|
251
|
-
|
|
255
|
+
// `createSandbox` gives each failure as an `err`, and `keepSuspendingRefusal`
|
|
256
|
+
// keeps a refusal of the label hook with the suspend flag as a value and throws each other failure.
|
|
257
|
+
export { describeSandboxError, keepSuspendingRefusal, SandboxFailure } from "./sandbox/sandbox-error.js";
|
|
252
258
|
// The identity of a package, the query that asks for one, and the resolution
|
|
253
259
|
// between the two. An embedder reads `by_name` of the dependency graph with
|
|
254
260
|
// these, thus the host lookup, the census, and the graph key never disagree on
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two kinds of host hook: a gate and a notice.
|
|
3
|
+
*
|
|
4
|
+
* A gate gives a value or a permission that the harness must have before it
|
|
5
|
+
* can continue an operation. A notice reports a fact after the operation. The
|
|
6
|
+
* type of each hook shows its kind:
|
|
7
|
+
*
|
|
8
|
+
* gate: (input) => ResultAsync<T, GateFailure>
|
|
9
|
+
* notice: (input) => ResultAsync<void, NoticeFailure>
|
|
10
|
+
*
|
|
11
|
+
* The harness calls each hook through `passGate` or `deliverNotice`, thus no
|
|
12
|
+
* call site selects its own failure policy, and no call site puts a `try` or a
|
|
13
|
+
* `catch` around a hook. A hook gives a failure as an `err`. A hook whose
|
|
14
|
+
* promise rejects has a defect, and the rejection passes through the helpers
|
|
15
|
+
* with no change.
|
|
16
|
+
*
|
|
17
|
+
* The reason of a failure is the text of the host. The harness carries it and
|
|
18
|
+
* never reads it. The flag `suspend` is part of the contract, thus the harness
|
|
19
|
+
* branches on it.
|
|
20
|
+
*/
|
|
21
|
+
import { ResultAsync } from "neverthrow";
|
|
22
|
+
import type { Logger } from "./logger.js";
|
|
23
|
+
export interface GateFailure {
|
|
24
|
+
readonly reason: string;
|
|
25
|
+
/** True when the host asks the harness to suspend the work in place of a failure. */
|
|
26
|
+
readonly suspend: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface NoticeFailure {
|
|
29
|
+
readonly reason: string;
|
|
30
|
+
}
|
|
31
|
+
export type GateName = "RunAuthorizer.authorize" | "RunCharge.open" | "ArtifactRegistry.register" | "resolveRequestHeaders" | "resolveSandboxLabels";
|
|
32
|
+
export type NoticeName = "RunAuthorizer.revoke" | "RunAuthorizer.revokeByJti" | "RunCharge.close" | "ArtifactRegistry.sync" | "UsageRecorder.record";
|
|
33
|
+
export type GateRefusal = {
|
|
34
|
+
readonly kind: "failed";
|
|
35
|
+
readonly gate: GateName;
|
|
36
|
+
readonly reason: string;
|
|
37
|
+
} | {
|
|
38
|
+
readonly kind: "suspended";
|
|
39
|
+
readonly gate: GateName;
|
|
40
|
+
readonly reason: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The host can build its `Result` with its own copy of neverthrow. The helper
|
|
44
|
+
* gives the outcome again as a `Result` of the copy of the harness. Thus the
|
|
45
|
+
* checkpoint recipes (`runtime/result-serialization.ts`) recognize the class,
|
|
46
|
+
* and a replay reads the same outcome.
|
|
47
|
+
*/
|
|
48
|
+
export declare function passGate<T>(gate: GateName, result: ResultAsync<T, GateFailure>): ResultAsync<T, GateRefusal>;
|
|
49
|
+
export declare function deliverNotice(log: Logger, notice: NoticeName, result: ResultAsync<void, NoticeFailure>): Promise<boolean>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two kinds of host hook: a gate and a notice.
|
|
3
|
+
*
|
|
4
|
+
* A gate gives a value or a permission that the harness must have before it
|
|
5
|
+
* can continue an operation. A notice reports a fact after the operation. The
|
|
6
|
+
* type of each hook shows its kind:
|
|
7
|
+
*
|
|
8
|
+
* gate: (input) => ResultAsync<T, GateFailure>
|
|
9
|
+
* notice: (input) => ResultAsync<void, NoticeFailure>
|
|
10
|
+
*
|
|
11
|
+
* The harness calls each hook through `passGate` or `deliverNotice`, thus no
|
|
12
|
+
* call site selects its own failure policy, and no call site puts a `try` or a
|
|
13
|
+
* `catch` around a hook. A hook gives a failure as an `err`. A hook whose
|
|
14
|
+
* promise rejects has a defect, and the rejection passes through the helpers
|
|
15
|
+
* with no change.
|
|
16
|
+
*
|
|
17
|
+
* The reason of a failure is the text of the host. The harness carries it and
|
|
18
|
+
* never reads it. The flag `suspend` is part of the contract, thus the harness
|
|
19
|
+
* branches on it.
|
|
20
|
+
*/
|
|
21
|
+
import { err, ok, ResultAsync } from "neverthrow";
|
|
22
|
+
/**
|
|
23
|
+
* The host can build its `Result` with its own copy of neverthrow. The helper
|
|
24
|
+
* gives the outcome again as a `Result` of the copy of the harness. Thus the
|
|
25
|
+
* checkpoint recipes (`runtime/result-serialization.ts`) recognize the class,
|
|
26
|
+
* and a replay reads the same outcome.
|
|
27
|
+
*/
|
|
28
|
+
export function passGate(gate, result) {
|
|
29
|
+
return new ResultAsync(Promise.resolve(result).then((settled) => settled.isOk()
|
|
30
|
+
? ok(settled.value)
|
|
31
|
+
: err({ kind: settled.error.suspend ? "suspended" : "failed", gate, reason: settled.error.reason })));
|
|
32
|
+
}
|
|
33
|
+
export async function deliverNotice(log, notice, result) {
|
|
34
|
+
const delivered = await result;
|
|
35
|
+
if (delivered.isOk())
|
|
36
|
+
return true;
|
|
37
|
+
log.error("a notice of the host failed", { notice, reason: delivered.error.reason });
|
|
38
|
+
return false;
|
|
39
|
+
}
|
package/dist/lib/result.d.ts
CHANGED
|
@@ -4,20 +4,31 @@
|
|
|
4
4
|
* The agent loop and execution boundary model failure as values, not throws.
|
|
5
5
|
* The house rules:
|
|
6
6
|
*
|
|
7
|
-
* 1. `try/catch` lives ONLY
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* 1. `try/catch` lives ONLY at a boundary:
|
|
8
|
+
* - the thin wrappers at calls to code external to ours — a third-party
|
|
9
|
+
* SDK, the `pg` driver, `fs`, the DBOS runtime. Those wrappers turn a
|
|
10
|
+
* throw into an `err(DomainError)`.
|
|
11
|
+
* - an API entry point, where a caller outside the harness gets the
|
|
12
|
+
* outcome.
|
|
13
|
+
* - a workflow body that gets the throw of a failed step or a failed
|
|
14
|
+
* child workflow, and runs its failure path.
|
|
15
|
+
* - the dispatch catch of the loop.
|
|
16
|
+
* Everything else flows `Result` / `ResultAsync`. A host hook has no
|
|
17
|
+
* `try/catch` around it: `passGate` / `deliverNotice` (`lib/hooks.ts`)
|
|
18
|
+
* consume its `Result`.
|
|
11
19
|
* 2. Absence is NOT an error. A "not found" stays in the ok channel as a
|
|
12
20
|
* data variant (`ok({ found: false })`), never an `err`. `err` is
|
|
13
21
|
* reserved for what used to be `throw`n — an unexpected upstream failure.
|
|
14
22
|
* 3. A `Result` is unwrapped at exactly three edges, each speaking its own
|
|
15
23
|
* dialect of failure:
|
|
16
24
|
* - HTTP routes `.match(...)` a `Result` into a response.
|
|
17
|
-
* - The DBOS step boundary throws on `err`
|
|
18
|
-
* `resultStep` in `loop/run-step.ts`):
|
|
19
|
-
* failed — and retries / fails fast —
|
|
20
|
-
*
|
|
25
|
+
* - The DBOS step boundary throws on an `err` that must fail or retry
|
|
26
|
+
* the step (`unwrapOrThrow` / `resultStep` in `loop/run-step.ts`):
|
|
27
|
+
* durability records a step as failed — and retries / fails fast —
|
|
28
|
+
* ONLY on a thrown exception. A step can also return a `Result` as
|
|
29
|
+
* its value: `runtime/result-serialization.ts` keeps the `Ok` / `Err`
|
|
30
|
+
* class across the checkpoint, DBOS records the step as a success,
|
|
31
|
+
* and the body MUST use the `err`.
|
|
21
32
|
* - Tool dispatch maps `err` into an `is_error` `tool_result`
|
|
22
33
|
* (`loop/run-agent.ts`).
|
|
23
34
|
*
|
|
@@ -43,9 +54,9 @@ export interface DomainError {
|
|
|
43
54
|
/**
|
|
44
55
|
* A thrown wrapper for a structured error value that is not already an
|
|
45
56
|
* `Error`. The original value rides on `.cause`, so the cause-walking
|
|
46
|
-
* classifiers (`classifyProviderError`, `
|
|
47
|
-
* `status` / `code` signals they look for after a `Result` is
|
|
48
|
-
* boundary.
|
|
57
|
+
* classifiers (`classifyProviderError`, `findSuspendError`) still reach the
|
|
58
|
+
* `status` / `code` / `type` signals they look for after a `Result` is
|
|
59
|
+
* rethrown at a boundary.
|
|
49
60
|
*/
|
|
50
61
|
export declare class ResultError extends Error {
|
|
51
62
|
readonly value: unknown;
|
package/dist/lib/result.js
CHANGED
|
@@ -4,20 +4,31 @@
|
|
|
4
4
|
* The agent loop and execution boundary model failure as values, not throws.
|
|
5
5
|
* The house rules:
|
|
6
6
|
*
|
|
7
|
-
* 1. `try/catch` lives ONLY
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* 1. `try/catch` lives ONLY at a boundary:
|
|
8
|
+
* - the thin wrappers at calls to code external to ours — a third-party
|
|
9
|
+
* SDK, the `pg` driver, `fs`, the DBOS runtime. Those wrappers turn a
|
|
10
|
+
* throw into an `err(DomainError)`.
|
|
11
|
+
* - an API entry point, where a caller outside the harness gets the
|
|
12
|
+
* outcome.
|
|
13
|
+
* - a workflow body that gets the throw of a failed step or a failed
|
|
14
|
+
* child workflow, and runs its failure path.
|
|
15
|
+
* - the dispatch catch of the loop.
|
|
16
|
+
* Everything else flows `Result` / `ResultAsync`. A host hook has no
|
|
17
|
+
* `try/catch` around it: `passGate` / `deliverNotice` (`lib/hooks.ts`)
|
|
18
|
+
* consume its `Result`.
|
|
11
19
|
* 2. Absence is NOT an error. A "not found" stays in the ok channel as a
|
|
12
20
|
* data variant (`ok({ found: false })`), never an `err`. `err` is
|
|
13
21
|
* reserved for what used to be `throw`n — an unexpected upstream failure.
|
|
14
22
|
* 3. A `Result` is unwrapped at exactly three edges, each speaking its own
|
|
15
23
|
* dialect of failure:
|
|
16
24
|
* - HTTP routes `.match(...)` a `Result` into a response.
|
|
17
|
-
* - The DBOS step boundary throws on `err`
|
|
18
|
-
* `resultStep` in `loop/run-step.ts`):
|
|
19
|
-
* failed — and retries / fails fast —
|
|
20
|
-
*
|
|
25
|
+
* - The DBOS step boundary throws on an `err` that must fail or retry
|
|
26
|
+
* the step (`unwrapOrThrow` / `resultStep` in `loop/run-step.ts`):
|
|
27
|
+
* durability records a step as failed — and retries / fails fast —
|
|
28
|
+
* ONLY on a thrown exception. A step can also return a `Result` as
|
|
29
|
+
* its value: `runtime/result-serialization.ts` keeps the `Ok` / `Err`
|
|
30
|
+
* class across the checkpoint, DBOS records the step as a success,
|
|
31
|
+
* and the body MUST use the `err`.
|
|
21
32
|
* - Tool dispatch maps `err` into an `is_error` `tool_result`
|
|
22
33
|
* (`loop/run-agent.ts`).
|
|
23
34
|
*
|
|
@@ -32,9 +43,9 @@ import { Err, Ok } from "neverthrow";
|
|
|
32
43
|
/**
|
|
33
44
|
* A thrown wrapper for a structured error value that is not already an
|
|
34
45
|
* `Error`. The original value rides on `.cause`, so the cause-walking
|
|
35
|
-
* classifiers (`classifyProviderError`, `
|
|
36
|
-
* `status` / `code` signals they look for after a `Result` is
|
|
37
|
-
* boundary.
|
|
46
|
+
* classifiers (`classifyProviderError`, `findSuspendError`) still reach the
|
|
47
|
+
* `status` / `code` / `type` signals they look for after a `Result` is
|
|
48
|
+
* rethrown at a boundary.
|
|
38
49
|
*/
|
|
39
50
|
export class ResultError extends Error {
|
|
40
51
|
value;
|
|
@@ -49,9 +60,8 @@ function describe(value) {
|
|
|
49
60
|
return value.message;
|
|
50
61
|
if (value && typeof value === "object" && "type" in value) {
|
|
51
62
|
// Prefer a human `message` field when the structured error carries one
|
|
52
|
-
// (e.g. a `ProviderError`) so the wrapped `Error.message`
|
|
53
|
-
//
|
|
54
|
-
// to the `type` discriminant otherwise.
|
|
63
|
+
// (e.g. a `ProviderError`) so the wrapped `Error.message` names the
|
|
64
|
+
// failure; fall back to the `type` discriminant otherwise.
|
|
55
65
|
const message = value.message;
|
|
56
66
|
if (typeof message === "string" && message.length > 0)
|
|
57
67
|
return message;
|
package/dist/loop/run-agent.d.ts
CHANGED
|
@@ -100,8 +100,8 @@ export interface RunAgentOptions {
|
|
|
100
100
|
readonly logger?: Logger;
|
|
101
101
|
/**
|
|
102
102
|
* Per-call LLM usage-accounting seam. Omitted falls back to the no-op
|
|
103
|
-
* recorder.
|
|
104
|
-
*
|
|
103
|
+
* recorder. `record` is a notice: the loop does not wait for its result,
|
|
104
|
+
* and it logs the reason of an `err` when the result arrives.
|
|
105
105
|
*/
|
|
106
106
|
readonly usageRecorder?: UsageRecorder;
|
|
107
107
|
/**
|
package/dist/loop/run-agent.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsonSchema, tool as aiTool, } from "ai";
|
|
|
3
3
|
import { createNoopUsageRecorder } from "../billing/noop-usage-recorder.js";
|
|
4
4
|
import { stripNulCharacters } from "../input-sanitization.js";
|
|
5
5
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
6
|
+
import { deliverNotice } from "../lib/hooks.js";
|
|
6
7
|
import { ATTR_INFLEXA_TOOL_USE_ID, passThroughSpan, stableSpan } from "../lib/otel-spans.js";
|
|
7
8
|
import { ResultError } from "../lib/result.js";
|
|
8
9
|
import { describeZodIssueShapes } from "../lib/zod-issue-shape.js";
|
|
@@ -150,8 +151,8 @@ async function runAgentLoop(agent, initial, session, opts) {
|
|
|
150
151
|
* reported nothing to account for, so it is folded (to no effect) and left
|
|
151
152
|
* out of the ledger rather than entered as an all-absent record.
|
|
152
153
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
154
|
+
* `record` is a notice. The loop does not wait for its result, thus a
|
|
155
|
+
* recorder that blocks does not make the run slower.
|
|
155
156
|
*/
|
|
156
157
|
const accountForCall = (reply, stepName) => {
|
|
157
158
|
addChatUsage(usage, reply.usage);
|
|
@@ -159,7 +160,7 @@ async function runAgentLoop(agent, initial, session, opts) {
|
|
|
159
160
|
const reported = reply.usage;
|
|
160
161
|
if (reported === undefined || !hasReportedUsage(reported))
|
|
161
162
|
return;
|
|
162
|
-
usageRecorder.record({
|
|
163
|
+
void deliverNotice(log, "UsageRecorder.record", usageRecorder.record({
|
|
163
164
|
recordKey: recordKeyFor(session, opts.invocationId, stepName),
|
|
164
165
|
agentId: source.agentId,
|
|
165
166
|
callPath: source.callPath,
|
|
@@ -169,7 +170,7 @@ async function runAgentLoop(agent, initial, session, opts) {
|
|
|
169
170
|
...(reply.requestedModelId === undefined ? {} : { requestedModelId: reply.requestedModelId }),
|
|
170
171
|
...(reply.servedModelId === undefined ? {} : { servedModelId: reply.servedModelId }),
|
|
171
172
|
usage: reported,
|
|
172
|
-
});
|
|
173
|
+
}));
|
|
173
174
|
};
|
|
174
175
|
/** The rollups this loop stamps on its finish — each absent when nothing reported. */
|
|
175
176
|
const finishUsage = () => ({
|
|
@@ -69,7 +69,7 @@ export type RunProvenanceEvent = {
|
|
|
69
69
|
runId: string;
|
|
70
70
|
/**
|
|
71
71
|
* The body's terminal status. Both boundary sites resolve it through `deriveFinalStatus`,
|
|
72
|
-
* which records a
|
|
72
|
+
* which records a suspension as `"canceled"` — so `"suspended_insufficient_funds"` (a
|
|
73
73
|
* `RunStatus` member) is never emitted here and is deliberately absent from this narrower
|
|
74
74
|
* `ExecuteAnalysisFinalStatus`-minus-`"running"` set.
|
|
75
75
|
*/
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type LanguageModel } from "ai";
|
|
2
|
-
import type
|
|
2
|
+
import { type AgentSession } from "../auth/types.js";
|
|
3
3
|
import type { Logger } from "../lib/logger.js";
|
|
4
|
+
import { type ProviderError, type SuspendOn } from "./errors.js";
|
|
5
|
+
import { type ResolveRequestHeaders } from "./request-headers.js";
|
|
4
6
|
import type { ChatProvider, FetchLike, ProviderCapabilities } from "./types.js";
|
|
5
7
|
/**
|
|
6
8
|
* The harness-owned retry envelope. The AI SDK's built-in retry exposes only a
|
|
@@ -30,9 +32,13 @@ export declare const RETRY_MAX_DELAY_MS = 30000;
|
|
|
30
32
|
* and the server then enforces the true cap of the model.
|
|
31
33
|
*/
|
|
32
34
|
export declare const DEFAULT_MAX_OUTPUT_TOKENS = 64000;
|
|
33
|
-
|
|
35
|
+
/** With no `suspendOn`, a provider uses {@link DEFAULT_SUSPEND_ON}. */
|
|
36
|
+
export interface ProviderHostPolicy {
|
|
37
|
+
readonly resolveRequestHeaders?: ResolveRequestHeaders;
|
|
38
|
+
readonly suspendOn?: SuspendOn;
|
|
39
|
+
}
|
|
40
|
+
export interface AiSdkProviderDeps extends ProviderHostPolicy {
|
|
34
41
|
readonly model: LanguageModel;
|
|
35
|
-
readonly resolveBilling: ResolveBilling;
|
|
36
42
|
readonly capabilities?: Partial<ProviderCapabilities>;
|
|
37
43
|
readonly logger?: Logger;
|
|
38
44
|
/**
|
|
@@ -193,9 +199,8 @@ export type AiSdkProviderConfig = {
|
|
|
193
199
|
*/
|
|
194
200
|
readonly maxRetries?: number;
|
|
195
201
|
};
|
|
196
|
-
export interface ConfiguredAiSdkProviderDeps {
|
|
202
|
+
export interface ConfiguredAiSdkProviderDeps extends ProviderHostPolicy {
|
|
197
203
|
readonly config: AiSdkProviderConfig;
|
|
198
|
-
readonly resolveBilling: ResolveBilling;
|
|
199
204
|
readonly logger?: Logger;
|
|
200
205
|
}
|
|
201
206
|
/**
|
|
@@ -207,6 +212,38 @@ export interface ConfiguredAiSdkProviderDeps {
|
|
|
207
212
|
* the same retry tick. `random` is injectable so the delay is testable.
|
|
208
213
|
*/
|
|
209
214
|
export declare function computeRetryDelayMs(error: unknown, exponentialBackoffDelay: number, random?: () => number): number;
|
|
215
|
+
/**
|
|
216
|
+
* A rejection of the request headers hook is a defect of the host, and the
|
|
217
|
+
* harness does not catch it (host-hooks spec): the envelope never retries it,
|
|
218
|
+
* and the outer catch rethrows it unchanged. The hook call has no `catch`, thus
|
|
219
|
+
* this flag marks the rejection: it stays set when the hook call of the attempt
|
|
220
|
+
* did not settle as a value.
|
|
221
|
+
*/
|
|
222
|
+
export interface HookCall {
|
|
223
|
+
unsettled: boolean;
|
|
224
|
+
}
|
|
225
|
+
/** A refusal of the hook throws `HeadersRefused`. */
|
|
226
|
+
export declare function headersForAttempt(hook: ResolveRequestHeaders | undefined, session: AgentSession, call: HookCall): Promise<Record<string, string>>;
|
|
227
|
+
export declare function failureOf(e: unknown, workload: string, suspendOn: SuspendOn): ProviderError;
|
|
228
|
+
/**
|
|
229
|
+
* Wrap a single wire attempt in the harness retry envelope. Built per call so
|
|
230
|
+
* the caller's `AbortSignal` reaches the primitive: it rethrows abort errors
|
|
231
|
+
* without retrying and cancels its own backoff sleep when the signal fires, so
|
|
232
|
+
* the retried closure adds no abort handling of its own. `shouldRetry` defers to
|
|
233
|
+
* the harness retryability taxonomy under the `suspendOn` map of the provider —
|
|
234
|
+
* thus a mapped status is never retried — and it never retries a refusal or a
|
|
235
|
+
* rejection of the request headers hook. A non-retried first failure is rethrown untouched,
|
|
236
|
+
* preserving the exact throwable the outer catch classifies. `createRetryError` carries the last real failure on `cause` so
|
|
237
|
+
* that, once retries are exhausted, `toProviderError`'s status walk reaches the
|
|
238
|
+
* true HTTP status instead of stopping at a synthetic wrapper. The attempt
|
|
239
|
+
* counter is per-instance because each call builds its own retry.
|
|
240
|
+
*
|
|
241
|
+
* An aborted caller signal also stops the retry. A wall-clock guard of a caller
|
|
242
|
+
* aborts with a `TimeoutError` reason, which the taxonomy marks as a retryable
|
|
243
|
+
* timeout. Without this guard the envelope would loop an expiry that the caller
|
|
244
|
+
* itself declared.
|
|
245
|
+
*/
|
|
246
|
+
export declare function createRetry(signal: AbortSignal | undefined, logger: Logger, maxRetries: number, suspendOn: SuspendOn, hookCall: HookCall): import("@ai-sdk/provider-utils").RetryFunction;
|
|
210
247
|
export declare function createAiSdkProvider(deps: AiSdkProviderDeps): ChatProvider;
|
|
211
248
|
/**
|
|
212
249
|
* Wrap a fetch so that the wait until the response starts does not exceed
|
|
@@ -227,6 +264,7 @@ export declare function createAiSdkProvider(deps: AiSdkProviderDeps): ChatProvid
|
|
|
227
264
|
* and the behavior stays byte-identical.
|
|
228
265
|
*/
|
|
229
266
|
export declare function wrapFetchWithRequestTimeout(fetchImpl: FetchLike, requestTimeoutMs: number): FetchLike;
|
|
267
|
+
export declare function hostPolicyOf(deps: ProviderHostPolicy): ProviderHostPolicy;
|
|
230
268
|
/**
|
|
231
269
|
* Realize an `AiSdkProviderConfig` into a `ChatProvider` bound to that config's
|
|
232
270
|
* connection and model. The model is closed into the returned provider here (it
|