openpond-sdk 0.12.20 → 0.12.22
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/OPENTELEMETRY.md +85 -0
- package/README.md +4 -0
- package/TASK_INGESTION.md +135 -0
- package/TRAINING_WORKFLOWS.md +14 -0
- package/dist/advanced-refiner-evaluations.js +2 -2
- package/dist/{chunk-RN5MK7NH.js → chunk-6EZAGTZG.js} +4 -4
- package/dist/{chunk-3MDNVNBM.js → chunk-BNBPKCIR.js} +6 -6
- package/dist/chunk-NZRGRUYG.js +140 -0
- package/dist/chunk-NZRGRUYG.js.map +1 -0
- package/dist/{chunk-RT7SQHO4.js → chunk-SP7DQEQM.js} +2 -2
- package/dist/connected-evidence.js +3 -3
- package/dist/dataset-workspaces.js +125 -36
- package/dist/dataset-workspaces.js.map +1 -1
- package/dist/experiment-evaluation-schedules.js +5 -5
- package/dist/experiments.js +5 -5
- package/dist/index.js +51 -36
- package/dist/index.js.map +1 -1
- package/dist/opentelemetry.js +92 -0
- package/dist/opentelemetry.js.map +1 -0
- package/dist/taskset-drafts.js +1 -1
- package/dist/taskset-packages.js +13 -13
- package/dist/training-bundle.js +10 -10
- package/dist/training.js +31 -8
- package/dist/training.js.map +1 -1
- package/dist/types/packages/sdk/src/dataset-task-ingestion.d.ts +86 -0
- package/dist/types/packages/sdk/src/dataset-task-ingestion.d.ts.map +1 -0
- package/dist/types/packages/sdk/src/dataset-workspace-client.d.ts +152 -140
- package/dist/types/packages/sdk/src/dataset-workspace-client.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/dataset-workspaces.d.ts +1 -0
- package/dist/types/packages/sdk/src/dataset-workspaces.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/experiment-client.d.ts +77 -77
- package/dist/types/packages/sdk/src/experiment-draft-storage.d.ts +112 -0
- package/dist/types/packages/sdk/src/experiment-draft-storage.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/experiment-evaluation-schedules.d.ts +216 -216
- package/dist/types/packages/sdk/src/index.d.ts +4 -0
- package/dist/types/packages/sdk/src/index.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/managed-decision-executions.d.ts +339 -339
- package/dist/types/packages/sdk/src/model-taskset-runs.d.ts +216 -216
- package/dist/types/packages/sdk/src/opentelemetry.d.ts +39 -0
- package/dist/types/packages/sdk/src/opentelemetry.d.ts.map +1 -0
- package/dist/types/packages/sdk/src/taskset-draft-client.d.ts +120 -120
- package/dist/types/packages/sdk/src/taskset-draft-source.d.ts +20 -20
- package/dist/types/packages/sdk/src/training-experiment-setup.d.ts +77 -0
- package/dist/types/packages/sdk/src/training-experiment-setup.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/training-qualification-preparation.d.ts +25 -25
- package/dist/types/packages/sdk/src/training.d.ts +4466 -4466
- package/dist/types/packages/sdk/src/training.d.ts.map +1 -1
- package/dist/types/packages/sdk/src/types.d.ts +2 -0
- package/dist/types/packages/sdk/src/types.d.ts.map +1 -1
- package/fixtures/python-foundation/operation-matrix.json +17 -0
- package/fixtures/python-foundation/schemas.json +5941 -5001
- package/package.json +18 -3
- /package/dist/{chunk-RN5MK7NH.js.map → chunk-6EZAGTZG.js.map} +0 -0
- /package/dist/{chunk-3MDNVNBM.js.map → chunk-BNBPKCIR.js.map} +0 -0
- /package/dist/{chunk-RT7SQHO4.js.map → chunk-SP7DQEQM.js.map} +0 -0
package/OPENTELEMETRY.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Optional OpenTelemetry integration
|
|
2
|
+
|
|
3
|
+
`openpond-sdk/opentelemetry` implements the standard JavaScript
|
|
4
|
+
[`SpanExporter`](https://open-telemetry.github.io/opentelemetry-js/modules/_opentelemetry_sdk-trace.html)
|
|
5
|
+
interface. Install the current tracing SDK alongside OpenPond:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install openpond-sdk @opentelemetry/api @opentelemetry/sdk-trace@^3.1.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This is an adapter into the structured [addTask API](./TASK_INGESTION.md), not an
|
|
12
|
+
OTLP receiver. Existing automatic instrumentation can produce the spans. Register
|
|
13
|
+
this exporter in your existing OTel configuration, alongside your observability
|
|
14
|
+
exporter if desired. It does not replace the global provider, install framework
|
|
15
|
+
instrumentation, or automatically create training tasks from every log line.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { OpenPondClient } from "openpond-sdk";
|
|
19
|
+
import { OpenPondSpanExporter } from "openpond-sdk/opentelemetry";
|
|
20
|
+
import { BatchSpanProcessor, TracerProvider } from "@opentelemetry/sdk-trace";
|
|
21
|
+
|
|
22
|
+
const client = new OpenPondClient({ baseUrl: apiBaseUrl, apiKey, teamId });
|
|
23
|
+
const exporter = new OpenPondSpanExporter({
|
|
24
|
+
client,
|
|
25
|
+
datasetId,
|
|
26
|
+
maxExportBatchSize: 32,
|
|
27
|
+
projectSpan(span) {
|
|
28
|
+
// These are application-owned attributes: explicitly mark selected agent runs.
|
|
29
|
+
if (span.attributes["app.learning_task"] !== true) return null;
|
|
30
|
+
const input = span.attributes["app.sanitized_task_input"];
|
|
31
|
+
if (typeof input !== "string" || !input.trim()) return null;
|
|
32
|
+
return {
|
|
33
|
+
name: span.name,
|
|
34
|
+
input: { prompt: input },
|
|
35
|
+
// Preserve for review; upload does not authorize training.
|
|
36
|
+
split: "validation",
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const processor = new BatchSpanProcessor({
|
|
41
|
+
exporter,
|
|
42
|
+
maxExportBatchSize: 32,
|
|
43
|
+
maxQueueSize: 256,
|
|
44
|
+
exportTimeoutMillis: 30_000,
|
|
45
|
+
});
|
|
46
|
+
// If your application already has a provider, configure its processor list there.
|
|
47
|
+
const provider = new TracerProvider({ spanProcessors: [processor] });
|
|
48
|
+
const tracer = provider.getTracer("production-agent");
|
|
49
|
+
// Use tracer in your agent, or your existing framework instrumentation.
|
|
50
|
+
// At graceful application shutdown:
|
|
51
|
+
await provider.shutdown();
|
|
52
|
+
// exporter.lastExportError exposes the latest batch failure, if any.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Only the returned task and trace/span source IDs are uploaded. Prompts, outputs,
|
|
56
|
+
attributes, exceptions and events are not copied implicitly. Redact secrets before
|
|
57
|
+
returning content. A selected span should contain the context needed to reproduce
|
|
58
|
+
a useful task; logs and exceptions can supply that context through span events in
|
|
59
|
+
your projection. Standalone log, metrics and OTLP ingestion are not implemented.
|
|
60
|
+
These examples use application attributes, not unsettled GenAI convention names.
|
|
61
|
+
|
|
62
|
+
The exporter derives a dataset-scoped idempotency key from trace ID and span ID.
|
|
63
|
+
Duplicate spans in a successful batch are skipped. Replaying a span after a lost
|
|
64
|
+
reply uses the same key. Keep projections deterministic for a span: a changed
|
|
65
|
+
payload with an existing key is a conflict, not a second task. Saved tasks still
|
|
66
|
+
require the application's separate review and training authorization.
|
|
67
|
+
|
|
68
|
+
Use `BatchSpanProcessor` for its bounded background queue; ending a span must not
|
|
69
|
+
wait for an HTTP write. Queues can drop spans when full. The adapter sends selected
|
|
70
|
+
tasks sequentially, rejects oversized/concurrent export batches, and has a 10s
|
|
71
|
+
per-request and 25s overall batch deadline by default. Configure small batches for
|
|
72
|
+
your network latency. HTTP failures, invalid projections and receipt mismatches
|
|
73
|
+
produce OTel export failure with bounded trace/span failure details in
|
|
74
|
+
`OpenPondSpanExportError.failures`. No retry worker or persistent outbox is created;
|
|
75
|
+
OTel's processor does not guarantee retries or durable delivery. Use direct
|
|
76
|
+
`addTask` with your own durable queue when loss is unacceptable.
|
|
77
|
+
|
|
78
|
+
`forceFlush()` waits for the exporter's current HTTP work; flush the **provider**
|
|
79
|
+
to drain its processor queue. `shutdown()` rejects new exports and waits for
|
|
80
|
+
accepted work. A successful flush means the queue was drained, not that every
|
|
81
|
+
write succeeded: inspect exporter errors/OTel diagnostics. Keep credentials on the
|
|
82
|
+
server and do not change providers or close dependencies while exports are active.
|
|
83
|
+
|
|
84
|
+
Python has the matching optional exporter in `ponder_sdk.opentelemetry`; see the
|
|
85
|
+
[Python SDK README](../../python/openpond-sdk/README.md).
|
package/README.md
CHANGED
|
@@ -389,3 +389,7 @@ is immutable and owner-scoped. `comparisonBudget(id)` returns each operation's
|
|
|
389
389
|
run ID, known settled spend, pending reservations and remaining allowance.
|
|
390
390
|
Registering a comparison does not start any work. Independent experiments do
|
|
391
391
|
not implicitly share a spending cap.
|
|
392
|
+
|
|
393
|
+
## Add production tasks
|
|
394
|
+
|
|
395
|
+
Use the flat `client.addTask(datasetId, task)` operation, or bind one destination with `createTaskAdder` and call `addTask(task)`. See [task ingestion](TASK_INGESTION.md) for TypeScript/Python examples, receipt semantics and duplicate-safe retries. Task uploads do not enable training.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Add tasks to a Dataset
|
|
2
|
+
|
|
3
|
+
Task submission uses an authenticated OpenPond API, separate from OpenTelemetry.
|
|
4
|
+
A successful receipt means a structured task was durably saved and is available
|
|
5
|
+
through the ordinary Dataset Tasks reader. It does not start training, publish
|
|
6
|
+
a release, create a Model or enable a collection schedule.
|
|
7
|
+
|
|
8
|
+
Create or choose an editable Dataset in Console and copy its ID. Configure the
|
|
9
|
+
server-side SDK with the workspace that owns it:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { createOpenPondClient } from "openpond-sdk";
|
|
13
|
+
|
|
14
|
+
const client = createOpenPondClient({
|
|
15
|
+
apiKey: process.env.OPENPOND_API_KEY!,
|
|
16
|
+
teamId: process.env.OPENPOND_TEAM_ID!,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const receipt = await client.addTask(process.env.OPENPOND_DATASET_ID!, {
|
|
20
|
+
name: "Handle an expired API token",
|
|
21
|
+
input: { request: "Fetch the report", observedError: "Token expired" },
|
|
22
|
+
source: { kind: "production_agent", eventId: "run-123" },
|
|
23
|
+
}, { idempotencyKey: "run-123" });
|
|
24
|
+
|
|
25
|
+
console.log(receipt.taskId, receipt.receivedAt);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use a configured `baseUrl` when targeting a different OpenPond API origin.
|
|
29
|
+
Never expose the API key in browser code or logged task content.
|
|
30
|
+
|
|
31
|
+
## Bind the destination once
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { createTaskAdder } from "openpond-sdk";
|
|
35
|
+
|
|
36
|
+
const addTask = createTaskAdder({
|
|
37
|
+
apiKey: process.env.OPENPOND_API_KEY!,
|
|
38
|
+
teamId: process.env.OPENPOND_TEAM_ID!,
|
|
39
|
+
datasetId: process.env.OPENPOND_DATASET_ID!,
|
|
40
|
+
baseUrl: "https://api.openpond.ai",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await addTask({
|
|
44
|
+
name: "Explain a failed agent run",
|
|
45
|
+
input: { request: "Summarize the report", outcome: "incomplete" },
|
|
46
|
+
}, { idempotencyKey: "agent-run-456" });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The Dataset ID is still included in every request. The helper binds it locally;
|
|
50
|
+
it never uses a global account, last-selected Dataset or implicit Fix-it Model.
|
|
51
|
+
|
|
52
|
+
## Input and receipt
|
|
53
|
+
|
|
54
|
+
Every task has a readable `name` and structured `input`. Optional fields are
|
|
55
|
+
`expectedOutput`, `split`, `tags` and `source` (`kind`, `eventId`, `label`,
|
|
56
|
+
`occurredAt`). The default split is `validation`. A `train` split alone does
|
|
57
|
+
not authorize training. Keep a missing correct answer absent rather than
|
|
58
|
+
replacing it with an error message.
|
|
59
|
+
|
|
60
|
+
The complete request is bounded to 128 KiB. The receipt includes workspace,
|
|
61
|
+
Dataset, task and operation identities, server `receivedAt`, saved revision,
|
|
62
|
+
`state: "saved"` and `trainingUseAuthorized: false`. Source occurrence time is
|
|
63
|
+
different from server upload time.
|
|
64
|
+
|
|
65
|
+
## Delivery and retries
|
|
66
|
+
|
|
67
|
+
Retain an explicit stable idempotency key for each source event. Repeating the
|
|
68
|
+
same key and task in the same authorized destination returns the original
|
|
69
|
+
receipt without inserting a duplicate. Reusing a key with different content is
|
|
70
|
+
a conflict. Separate keys add separate tasks, including simultaneous writers.
|
|
71
|
+
|
|
72
|
+
The SDK makes one request; it does not silently replay arbitrary mutations.
|
|
73
|
+
When a response is lost, `DatasetTaskIngestionError.operationId` retains the
|
|
74
|
+
operation identity and `outcomeUnknown` indicates that persistence could not be
|
|
75
|
+
confirmed. Retry the original task with that same key. Do not generate a new
|
|
76
|
+
key merely because the response was interrupted. A supplied abort signal is
|
|
77
|
+
forwarded to the request; an interrupted response can still have been saved.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { DatasetTaskIngestionError } from "openpond-sdk";
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await addTask(task, { idempotencyKey: sourceEventId });
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error instanceof DatasetTaskIngestionError && error.outcomeUnknown) {
|
|
86
|
+
// Retain task + error.operationId privately for a later exact retry.
|
|
87
|
+
}
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The underlying route is `POST /v1/dataset-workspaces/{datasetId}/tasks`, with
|
|
93
|
+
`Authorization: Bearer …`, `X-OpenPond-Team-Id` and JSON:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"schemaVersion": "openpond.datasetTaskAppend.v1",
|
|
98
|
+
"operationId": "stable-source-event",
|
|
99
|
+
"task": {
|
|
100
|
+
"name": "Handle an expired API token",
|
|
101
|
+
"input": { "observedError": "Token expired" }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The server owns authorization, atomic append and revision history. Appending
|
|
107
|
+
does not rewrite fixed Experiment Dataset versions or previously published
|
|
108
|
+
releases. Full authoring still uses the revisioned Dataset workspace API.
|
|
109
|
+
|
|
110
|
+
## Python
|
|
111
|
+
|
|
112
|
+
The maintained `ponder-sdk` package exposes the same operation on `Client`
|
|
113
|
+
and `AsyncClient`:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from ponder_sdk import Client
|
|
117
|
+
|
|
118
|
+
with Client(base_url=api_origin, api_key=api_key, team_id=team_id) as client:
|
|
119
|
+
receipt = client.add_task(
|
|
120
|
+
dataset_id,
|
|
121
|
+
{"name": "Handle an expired API token", "input": {"error": "Token expired"}},
|
|
122
|
+
idempotency_key=source_event_id,
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Use `async with AsyncClient(...)` and `await client.add_task(...)` for async
|
|
127
|
+
applications. Both use the existing client connection pool and typed wire
|
|
128
|
+
validation. Retain the caller's key/task across an unknown mutation outcome.
|
|
129
|
+
|
|
130
|
+
## OpenTelemetry
|
|
131
|
+
|
|
132
|
+
OpenTelemetry is an optional source adapter, not this HTTP request format.
|
|
133
|
+
Its span exporter can project explicitly selected spans into structured tasks
|
|
134
|
+
using the same destination and receipts. It does not make this endpoint an
|
|
135
|
+
OTLP receiver, automatically capture arbitrary logs, or authorize training.
|
package/TRAINING_WORKFLOWS.md
CHANGED
|
@@ -54,6 +54,20 @@ execution location. Training authoring uses `trainingForm`. Cleared evaluation
|
|
|
54
54
|
numeric controls remain `null`; blank training spend fields remain strings.
|
|
55
55
|
These incomplete values can be retained without becoming executable requests.
|
|
56
56
|
|
|
57
|
+
Model setup authoring may also retain optional `modelSetup` metadata, exported
|
|
58
|
+
as `ModelSetupDraftSchema` and `ModelSetupDraft` from `openpond-sdk/training`.
|
|
59
|
+
It stores the selected workflow (`sft`, `rl`, `decision`), adapter (`lora`,
|
|
60
|
+
`engram`, `neuron-training`), `continualLearning` choice, current setup section
|
|
61
|
+
and an optional editable Dataset `{ id, revision }`. That Dataset reference is
|
|
62
|
+
an authoring destination, not an admitted training batch or immutable release.
|
|
63
|
+
These choices survive the same revisioned draft save/read lifecycle. They do
|
|
64
|
+
not publish a learning policy or establish executor compatibility. Call
|
|
65
|
+
`assertModelSetupExecutionIntent(draft, requestedOperation)` when converting a
|
|
66
|
+
retained setup draft into a preparation request. It rejects a different or
|
|
67
|
+
unsupported workflow/adapter operation; executor admission still owns runtime,
|
|
68
|
+
permissions and resource checks. Direct explicit-method APIs remain independent
|
|
69
|
+
of this authoring metadata.
|
|
70
|
+
|
|
57
71
|
Use `training.saveExperimentDraft(request)` with
|
|
58
72
|
`schemaVersion: "openpond.experimentDraftSave.v1"`, `teamId`, a stable
|
|
59
73
|
`operationId`, `expectedRevision`, optional `projectId`, and an
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
sealAdvancedRefinerEvaluationPin,
|
|
13
13
|
sealAdvancedRefinerReviewReceipt,
|
|
14
14
|
verifyAdvancedRefinerEvaluationPin
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-QNOCM5JX.js";
|
|
15
|
+
} from "./chunk-6EZAGTZG.js";
|
|
17
16
|
import "./chunk-3B5KSH3V.js";
|
|
18
17
|
import "./chunk-H3367ISL.js";
|
|
18
|
+
import "./chunk-QNOCM5JX.js";
|
|
19
19
|
import "./chunk-626JLH4D.js";
|
|
20
20
|
import "./chunk-O6FKHAWN.js";
|
|
21
21
|
import "./chunk-GS5HEE4M.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ExperimentImprovementOptionsSchema
|
|
3
|
-
} from "./chunk-QNOCM5JX.js";
|
|
4
1
|
import {
|
|
5
2
|
EvaluationCoordinationTransport
|
|
6
3
|
} from "./chunk-3B5KSH3V.js";
|
|
7
4
|
import {
|
|
8
5
|
ChatModelRefSchema
|
|
9
6
|
} from "./chunk-H3367ISL.js";
|
|
7
|
+
import {
|
|
8
|
+
ExperimentImprovementOptionsSchema
|
|
9
|
+
} from "./chunk-QNOCM5JX.js";
|
|
10
10
|
import {
|
|
11
11
|
ImmutableReleaseRefSchema,
|
|
12
12
|
contentHash
|
|
@@ -264,4 +264,4 @@ export {
|
|
|
264
264
|
AdvancedRefinerEvaluationAccountingSchema,
|
|
265
265
|
OpenPondAdvancedRefinerEvaluationClient
|
|
266
266
|
};
|
|
267
|
-
//# sourceMappingURL=chunk-
|
|
267
|
+
//# sourceMappingURL=chunk-6EZAGTZG.js.map
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
materializePortableTasksetRelease,
|
|
3
|
-
portableTasksetEnvironment,
|
|
4
|
-
projectPortableTaskRecord
|
|
5
|
-
} from "./chunk-GWXJSBWR.js";
|
|
6
1
|
import {
|
|
7
2
|
decodeTasksetDraftWorkspaceFile,
|
|
8
3
|
isManagedTasksetDraftFilePath,
|
|
@@ -10,6 +5,11 @@ import {
|
|
|
10
5
|
renderTasksetDraftManifests,
|
|
11
6
|
validateTasksetDraftWorkspace
|
|
12
7
|
} from "./chunk-Q4RGCEOI.js";
|
|
8
|
+
import {
|
|
9
|
+
materializePortableTasksetRelease,
|
|
10
|
+
portableTasksetEnvironment,
|
|
11
|
+
projectPortableTaskRecord
|
|
12
|
+
} from "./chunk-GWXJSBWR.js";
|
|
13
13
|
import {
|
|
14
14
|
TasksetSchema,
|
|
15
15
|
computeTasksetHash
|
|
@@ -471,4 +471,4 @@ export {
|
|
|
471
471
|
compileTasksetDraftWorkspace,
|
|
472
472
|
compileModelTasksetDraftWorkspace
|
|
473
473
|
};
|
|
474
|
-
//# sourceMappingURL=chunk-
|
|
474
|
+
//# sourceMappingURL=chunk-BNBPKCIR.js.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readBoundedJsonResponse
|
|
3
|
+
} from "./chunk-B3ZHJ2KK.js";
|
|
4
|
+
|
|
5
|
+
// src/dataset-task-ingestion.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { assertBoundedTaskJson } from "@openpond/evals/task-schema";
|
|
8
|
+
var Id = z.string().trim().min(1).max(240);
|
|
9
|
+
var DatasetTaskInputSchema = z.object({
|
|
10
|
+
name: z.string().trim().min(1).max(300),
|
|
11
|
+
input: z.record(z.string(), z.unknown()),
|
|
12
|
+
expectedOutput: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
13
|
+
split: z.enum(["train", "validation", "frozen_eval"]).default("validation"),
|
|
14
|
+
source: z.object({
|
|
15
|
+
kind: z.string().trim().min(1).max(100),
|
|
16
|
+
eventId: Id.optional(),
|
|
17
|
+
label: z.string().trim().min(1).max(300).optional(),
|
|
18
|
+
occurredAt: z.iso.datetime().optional()
|
|
19
|
+
}).strict().optional(),
|
|
20
|
+
tags: z.array(Id).max(100).default([])
|
|
21
|
+
}).strict();
|
|
22
|
+
var DatasetTaskAppendRequestSchema = z.object({
|
|
23
|
+
schemaVersion: z.literal("openpond.datasetTaskAppend.v1"),
|
|
24
|
+
operationId: Id,
|
|
25
|
+
task: DatasetTaskInputSchema
|
|
26
|
+
}).strict();
|
|
27
|
+
var DatasetTaskAppendReceiptSchema = z.object({
|
|
28
|
+
schemaVersion: z.literal("openpond.datasetTaskReceipt.v1"),
|
|
29
|
+
teamId: Id,
|
|
30
|
+
datasetId: z.string().trim().min(1).max(240),
|
|
31
|
+
taskId: Id,
|
|
32
|
+
operationId: Id,
|
|
33
|
+
receivedAt: z.iso.datetime(),
|
|
34
|
+
revision: z.number().int().positive(),
|
|
35
|
+
state: z.literal("saved"),
|
|
36
|
+
trainingUseAuthorized: z.literal(false)
|
|
37
|
+
}).strict();
|
|
38
|
+
var DatasetTaskIngestionError = class extends Error {
|
|
39
|
+
constructor(message, status, code, operationId) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.status = status;
|
|
42
|
+
this.code = code;
|
|
43
|
+
this.operationId = operationId;
|
|
44
|
+
this.name = "DatasetTaskIngestionError";
|
|
45
|
+
this.outcomeUnknown = status === 0 || status >= 500 || code === "dataset_task_receipt_invalid";
|
|
46
|
+
}
|
|
47
|
+
status;
|
|
48
|
+
code;
|
|
49
|
+
operationId;
|
|
50
|
+
outcomeUnknown;
|
|
51
|
+
};
|
|
52
|
+
async function addDatasetTask(config, datasetId, task, options = {}) {
|
|
53
|
+
const url = new URL(config.baseUrl);
|
|
54
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash || url.pathname !== "/")
|
|
55
|
+
throw new Error("A clean API origin is required.");
|
|
56
|
+
const teamId = Id.parse(config.teamId);
|
|
57
|
+
if (!config.apiKey.trim()) throw new Error("An OpenPond API key is required.");
|
|
58
|
+
const id = z.string().trim().min(1).max(240).parse(datasetId);
|
|
59
|
+
const request = DatasetTaskAppendRequestSchema.parse({
|
|
60
|
+
schemaVersion: "openpond.datasetTaskAppend.v1",
|
|
61
|
+
operationId: options.idempotencyKey ?? crypto.randomUUID(),
|
|
62
|
+
task
|
|
63
|
+
});
|
|
64
|
+
assertBoundedTaskJson(request, 128 * 1024);
|
|
65
|
+
let response;
|
|
66
|
+
try {
|
|
67
|
+
response = await (config.fetch ?? fetch)(
|
|
68
|
+
`${url.origin}/v1/dataset-workspaces/${encodeURIComponent(id)}/tasks`,
|
|
69
|
+
{
|
|
70
|
+
method: "POST",
|
|
71
|
+
redirect: "error",
|
|
72
|
+
signal: options.signal,
|
|
73
|
+
headers: {
|
|
74
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
75
|
+
"X-OpenPond-Team-Id": teamId,
|
|
76
|
+
"Content-Type": "application/json"
|
|
77
|
+
},
|
|
78
|
+
body: JSON.stringify(request)
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
} catch {
|
|
82
|
+
throw new DatasetTaskIngestionError(
|
|
83
|
+
"Task delivery could not be confirmed. Retry with the same operation ID.",
|
|
84
|
+
0,
|
|
85
|
+
"dataset_task_outcome_unknown",
|
|
86
|
+
request.operationId
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
let raw;
|
|
90
|
+
try {
|
|
91
|
+
raw = await readBoundedJsonResponse(response, 64 * 1024, "Dataset task receipt");
|
|
92
|
+
} catch {
|
|
93
|
+
throw new DatasetTaskIngestionError(
|
|
94
|
+
"Task delivery returned an invalid receipt. Retain the same operation ID before retrying.",
|
|
95
|
+
response.status,
|
|
96
|
+
"dataset_task_receipt_invalid",
|
|
97
|
+
request.operationId
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
const error = z.object({ message: z.string().optional(), code: z.string().optional() }).passthrough().safeParse(raw);
|
|
102
|
+
throw new DatasetTaskIngestionError(
|
|
103
|
+
error.success ? error.data.message ?? "Task submission failed." : "Task submission failed.",
|
|
104
|
+
response.status,
|
|
105
|
+
error.success ? error.data.code ?? "dataset_task_request_failed" : "dataset_task_request_failed",
|
|
106
|
+
request.operationId
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const parsed = DatasetTaskAppendReceiptSchema.safeParse(raw);
|
|
110
|
+
if (!parsed.success)
|
|
111
|
+
throw new DatasetTaskIngestionError(
|
|
112
|
+
"Task delivery returned an invalid receipt.",
|
|
113
|
+
response.status,
|
|
114
|
+
"dataset_task_receipt_invalid",
|
|
115
|
+
request.operationId
|
|
116
|
+
);
|
|
117
|
+
const receipt = parsed.data;
|
|
118
|
+
if (receipt.teamId !== teamId || receipt.datasetId !== id || receipt.operationId !== request.operationId)
|
|
119
|
+
throw new DatasetTaskIngestionError(
|
|
120
|
+
"Dataset task receipt identity mismatch.",
|
|
121
|
+
response.status,
|
|
122
|
+
"dataset_task_receipt_invalid",
|
|
123
|
+
request.operationId
|
|
124
|
+
);
|
|
125
|
+
return receipt;
|
|
126
|
+
}
|
|
127
|
+
function createTaskAdder(config) {
|
|
128
|
+
const { datasetId, ...connection } = config;
|
|
129
|
+
return (task, options) => addDatasetTask(connection, datasetId, task, options);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
DatasetTaskInputSchema,
|
|
134
|
+
DatasetTaskAppendRequestSchema,
|
|
135
|
+
DatasetTaskAppendReceiptSchema,
|
|
136
|
+
DatasetTaskIngestionError,
|
|
137
|
+
addDatasetTask,
|
|
138
|
+
createTaskAdder
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=chunk-NZRGRUYG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dataset-task-ingestion.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { assertBoundedTaskJson } from \"@openpond/evals/task-schema\";\nimport { readBoundedJsonResponse } from \"./protocol.js\";\n\nconst Id = z.string().trim().min(1).max(240);\nexport const DatasetTaskInputSchema = z\n .object({\n name: z.string().trim().min(1).max(300),\n input: z.record(z.string(), z.unknown()),\n expectedOutput: z.record(z.string(), z.unknown()).nullable().default(null),\n split: z.enum([\"train\", \"validation\", \"frozen_eval\"]).default(\"validation\"),\n source: z\n .object({\n kind: z.string().trim().min(1).max(100),\n eventId: Id.optional(),\n label: z.string().trim().min(1).max(300).optional(),\n occurredAt: z.iso.datetime().optional(),\n })\n .strict()\n .optional(),\n tags: z.array(Id).max(100).default([]),\n })\n .strict();\nexport const DatasetTaskAppendRequestSchema = z\n .object({\n schemaVersion: z.literal(\"openpond.datasetTaskAppend.v1\"),\n operationId: Id,\n task: DatasetTaskInputSchema,\n })\n .strict();\nexport const DatasetTaskAppendReceiptSchema = z\n .object({\n schemaVersion: z.literal(\"openpond.datasetTaskReceipt.v1\"),\n teamId: Id,\n datasetId: z.string().trim().min(1).max(240),\n taskId: Id,\n operationId: Id,\n receivedAt: z.iso.datetime(),\n revision: z.number().int().positive(),\n state: z.literal(\"saved\"),\n trainingUseAuthorized: z.literal(false),\n })\n .strict();\nexport type DatasetTaskInput = z.input<typeof DatasetTaskInputSchema>;\nexport type DatasetTaskAppendReceipt = z.infer<typeof DatasetTaskAppendReceiptSchema>;\nexport type AddTaskOptions = { idempotencyKey?: string; signal?: AbortSignal };\nexport type DatasetTaskClientOptions = {\n apiKey: string;\n baseUrl: string;\n teamId: string;\n fetch?: typeof fetch;\n};\n\nexport class DatasetTaskIngestionError extends Error {\n readonly outcomeUnknown: boolean;\n constructor(\n message: string,\n readonly status: number,\n readonly code: string,\n readonly operationId: string,\n ) {\n super(message);\n this.name = \"DatasetTaskIngestionError\";\n this.outcomeUnknown = status === 0 || status >= 500 || code === \"dataset_task_receipt_invalid\";\n }\n}\n\n/** A bounded append, independent of complete workspace downloads or replacement. */\nexport async function addDatasetTask(\n config: DatasetTaskClientOptions,\n datasetId: string,\n task: DatasetTaskInput,\n options: AddTaskOptions = {},\n): Promise<DatasetTaskAppendReceipt> {\n const url = new URL(config.baseUrl);\n if (\n ![\"http:\", \"https:\"].includes(url.protocol) ||\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n url.pathname !== \"/\"\n )\n throw new Error(\"A clean API origin is required.\");\n const teamId = Id.parse(config.teamId);\n if (!config.apiKey.trim()) throw new Error(\"An OpenPond API key is required.\");\n const id = z.string().trim().min(1).max(240).parse(datasetId);\n const request = DatasetTaskAppendRequestSchema.parse({\n schemaVersion: \"openpond.datasetTaskAppend.v1\",\n operationId: options.idempotencyKey ?? crypto.randomUUID(),\n task,\n });\n assertBoundedTaskJson(request, 128 * 1024);\n let response: Response;\n try {\n response = await (config.fetch ?? fetch)(\n `${url.origin}/v1/dataset-workspaces/${encodeURIComponent(id)}/tasks`,\n {\n method: \"POST\",\n redirect: \"error\",\n signal: options.signal,\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n \"X-OpenPond-Team-Id\": teamId,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n },\n );\n } catch {\n throw new DatasetTaskIngestionError(\n \"Task delivery could not be confirmed. Retry with the same operation ID.\",\n 0,\n \"dataset_task_outcome_unknown\",\n request.operationId,\n );\n }\n let raw: unknown;\n try {\n raw = await readBoundedJsonResponse(response, 64 * 1024, \"Dataset task receipt\");\n } catch {\n throw new DatasetTaskIngestionError(\n \"Task delivery returned an invalid receipt. Retain the same operation ID before retrying.\",\n response.status,\n \"dataset_task_receipt_invalid\",\n request.operationId,\n );\n }\n if (!response.ok) {\n const error = z\n .object({ message: z.string().optional(), code: z.string().optional() })\n .passthrough()\n .safeParse(raw);\n throw new DatasetTaskIngestionError(\n error.success ? (error.data.message ?? \"Task submission failed.\") : \"Task submission failed.\",\n response.status,\n error.success\n ? (error.data.code ?? \"dataset_task_request_failed\")\n : \"dataset_task_request_failed\",\n request.operationId,\n );\n }\n const parsed = DatasetTaskAppendReceiptSchema.safeParse(raw);\n if (!parsed.success)\n throw new DatasetTaskIngestionError(\n \"Task delivery returned an invalid receipt.\",\n response.status,\n \"dataset_task_receipt_invalid\",\n request.operationId,\n );\n const receipt = parsed.data;\n if (\n receipt.teamId !== teamId ||\n receipt.datasetId !== id ||\n receipt.operationId !== request.operationId\n )\n throw new DatasetTaskIngestionError(\n \"Dataset task receipt identity mismatch.\",\n response.status,\n \"dataset_task_receipt_invalid\",\n request.operationId,\n );\n return receipt;\n}\n\n/** Bind credentials and destination once; the returned addTask has no global state. */\nexport function createTaskAdder(config: DatasetTaskClientOptions & { datasetId: string }) {\n const { datasetId, ...connection } = config;\n return (task: DatasetTaskInput, options?: AddTaskOptions) =>\n addDatasetTask(connection, datasetId, task, options);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-GPQLBVQC.js";
|
|
10
10
|
import {
|
|
11
11
|
AuthoredTasksetFileInventorySchema
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BNBPKCIR.js";
|
|
13
13
|
import {
|
|
14
14
|
configuredTasksetDraftFiles,
|
|
15
15
|
createTasksetDraftWorkspace,
|
|
@@ -698,4 +698,4 @@ export {
|
|
|
698
698
|
prepareTasksetDraftSource,
|
|
699
699
|
materializeTasksetDraftWorkspace
|
|
700
700
|
};
|
|
701
|
-
//# sourceMappingURL=chunk-
|
|
701
|
+
//# sourceMappingURL=chunk-SP7DQEQM.js.map
|
|
@@ -49,15 +49,15 @@ import {
|
|
|
49
49
|
ConnectedStartingAssetsRequestSchema,
|
|
50
50
|
verifyConnectedStartingAssetsReceipt
|
|
51
51
|
} from "./chunk-AG6UJ3DI.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
-
import "./chunk-GWXJSBWR.js";
|
|
52
|
+
import "./chunk-BNBPKCIR.js";
|
|
54
53
|
import "./chunk-Q4RGCEOI.js";
|
|
54
|
+
import "./chunk-GWXJSBWR.js";
|
|
55
55
|
import "./chunk-GCUWJUUM.js";
|
|
56
56
|
import {
|
|
57
57
|
ConnectedDatasetSourceRefSchema
|
|
58
58
|
} from "./chunk-ZQ6QTYRE.js";
|
|
59
|
-
import "./chunk-Z252BNAZ.js";
|
|
60
59
|
import "./chunk-TK3DXH7A.js";
|
|
60
|
+
import "./chunk-Z252BNAZ.js";
|
|
61
61
|
import "./chunk-H3367ISL.js";
|
|
62
62
|
import "./chunk-O6FKHAWN.js";
|
|
63
63
|
import "./chunk-QTNYXOJW.js";
|