@themoltnet/node-red-contrib-core 0.3.2 → 0.4.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/dist/nodes/src.js +423 -34
- package/dist/nodes/task-reader.js +2 -5
- package/package.json +2 -2
package/dist/nodes/src.js
CHANGED
|
@@ -1831,6 +1831,28 @@ var uploadRuntimeSession = (options) => (options.client ?? client).put({
|
|
|
1831
1831
|
}
|
|
1832
1832
|
});
|
|
1833
1833
|
/**
|
|
1834
|
+
* List recent team-scoped runtime slots for repair/sync.
|
|
1835
|
+
*/
|
|
1836
|
+
var listRuntimeSlots = (options) => (options.client ?? client).get({
|
|
1837
|
+
security: [
|
|
1838
|
+
{
|
|
1839
|
+
scheme: "bearer",
|
|
1840
|
+
type: "http"
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
name: "X-Moltnet-Session-Token",
|
|
1844
|
+
type: "apiKey"
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
in: "cookie",
|
|
1848
|
+
name: "ory_kratos_session",
|
|
1849
|
+
type: "apiKey"
|
|
1850
|
+
}
|
|
1851
|
+
],
|
|
1852
|
+
url: "/runtime-slots",
|
|
1853
|
+
...options
|
|
1854
|
+
});
|
|
1855
|
+
/**
|
|
1834
1856
|
* Upsert a team-scoped runtime slot for audit and continuation affinity lookup.
|
|
1835
1857
|
*/
|
|
1836
1858
|
var beginRuntimeSlot = (options) => (options.client ?? client).post({
|
|
@@ -2249,6 +2271,55 @@ var claimTask = (options) => (options.client ?? client).post({
|
|
|
2249
2271
|
}
|
|
2250
2272
|
});
|
|
2251
2273
|
/**
|
|
2274
|
+
* List task artifact metadata for the current team.
|
|
2275
|
+
*/
|
|
2276
|
+
var listTaskArtifacts = (options) => (options.client ?? client).get({
|
|
2277
|
+
security: [
|
|
2278
|
+
{
|
|
2279
|
+
scheme: "bearer",
|
|
2280
|
+
type: "http"
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
name: "X-Moltnet-Session-Token",
|
|
2284
|
+
type: "apiKey"
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
in: "cookie",
|
|
2288
|
+
name: "ory_kratos_session",
|
|
2289
|
+
type: "apiKey"
|
|
2290
|
+
}
|
|
2291
|
+
],
|
|
2292
|
+
url: "/tasks/{taskId}/artifacts",
|
|
2293
|
+
...options
|
|
2294
|
+
});
|
|
2295
|
+
/**
|
|
2296
|
+
* Upload immutable content-addressed artifact content for a task attempt.
|
|
2297
|
+
*/
|
|
2298
|
+
var uploadTaskArtifact = (options) => (options.client ?? client).put({
|
|
2299
|
+
bodySerializer: null,
|
|
2300
|
+
security: [
|
|
2301
|
+
{
|
|
2302
|
+
scheme: "bearer",
|
|
2303
|
+
type: "http"
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
name: "X-Moltnet-Session-Token",
|
|
2307
|
+
type: "apiKey"
|
|
2308
|
+
},
|
|
2309
|
+
{
|
|
2310
|
+
in: "cookie",
|
|
2311
|
+
name: "ory_kratos_session",
|
|
2312
|
+
type: "apiKey"
|
|
2313
|
+
}
|
|
2314
|
+
],
|
|
2315
|
+
url: "/tasks/{taskId}/attempts/{attemptN}/artifacts",
|
|
2316
|
+
...options,
|
|
2317
|
+
headers: {
|
|
2318
|
+
"Content-Type": "application/octet-stream",
|
|
2319
|
+
...options.headers
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
/**
|
|
2252
2323
|
* List teams the caller belongs to.
|
|
2253
2324
|
*/
|
|
2254
2325
|
var listTeams = (options) => (options?.client ?? client).get({
|
|
@@ -5134,6 +5205,15 @@ function createRuntimeSlotsNamespace(context) {
|
|
|
5134
5205
|
if (err instanceof MoltNetError && err.statusCode === 404) return null;
|
|
5135
5206
|
throw err;
|
|
5136
5207
|
}
|
|
5208
|
+
},
|
|
5209
|
+
async list(query, options) {
|
|
5210
|
+
const filteredQuery = Object.fromEntries(Object.entries(query).filter(([, value]) => value !== void 0));
|
|
5211
|
+
return unwrapResult(await listRuntimeSlots({
|
|
5212
|
+
auth,
|
|
5213
|
+
client,
|
|
5214
|
+
headers: requiredTeamHeaders(options),
|
|
5215
|
+
query: filteredQuery
|
|
5216
|
+
})).items;
|
|
5137
5217
|
}
|
|
5138
5218
|
};
|
|
5139
5219
|
}
|
|
@@ -9483,6 +9563,32 @@ var RuntimeProfileAllowedWorkspaceModes = _Array_(RuntimeProfileWorkspaceMode, {
|
|
|
9483
9563
|
maxItems: 3,
|
|
9484
9564
|
uniqueItems: true
|
|
9485
9565
|
});
|
|
9566
|
+
var RuntimeProfileThinkingLevelOptions = [
|
|
9567
|
+
Literal("off"),
|
|
9568
|
+
Literal("minimal"),
|
|
9569
|
+
Literal("low"),
|
|
9570
|
+
Literal("medium"),
|
|
9571
|
+
Literal("high"),
|
|
9572
|
+
Literal("xhigh")
|
|
9573
|
+
];
|
|
9574
|
+
Union([...RuntimeProfileThinkingLevelOptions]);
|
|
9575
|
+
var RuntimeProfileNullableThinkingLevel = Union([...RuntimeProfileThinkingLevelOptions, Null()]);
|
|
9576
|
+
var RuntimeProfileNullableTemperature = Union([Null(), Number$1({
|
|
9577
|
+
minimum: 0,
|
|
9578
|
+
maximum: 2
|
|
9579
|
+
})]);
|
|
9580
|
+
var RuntimeProfileNullableTopP = Union([Null(), Number$1({
|
|
9581
|
+
minimum: 0,
|
|
9582
|
+
maximum: 1
|
|
9583
|
+
})]);
|
|
9584
|
+
var RuntimeProfileNullableTopK = Union([Integer({
|
|
9585
|
+
minimum: 1,
|
|
9586
|
+
maximum: 1e4
|
|
9587
|
+
}), Null()]);
|
|
9588
|
+
var RuntimeProfileNullableMaxOutputTokens = Union([Integer({
|
|
9589
|
+
minimum: 1,
|
|
9590
|
+
maximum: 1e6
|
|
9591
|
+
}), Null()]);
|
|
9486
9592
|
var SandboxResumeCommandWhenSchema = _Object_({ workspaceMode: Optional(_Array_(Union([
|
|
9487
9593
|
Literal("shared_mount"),
|
|
9488
9594
|
Literal("dedicated_worktree"),
|
|
@@ -9607,6 +9713,11 @@ _Object_({
|
|
|
9607
9713
|
minLength: 1,
|
|
9608
9714
|
maxLength: 200
|
|
9609
9715
|
}),
|
|
9716
|
+
thinkingLevel: RuntimeProfileNullableThinkingLevel,
|
|
9717
|
+
temperature: RuntimeProfileNullableTemperature,
|
|
9718
|
+
topP: RuntimeProfileNullableTopP,
|
|
9719
|
+
topK: RuntimeProfileNullableTopK,
|
|
9720
|
+
maxOutputTokens: RuntimeProfileNullableMaxOutputTokens,
|
|
9610
9721
|
runtimeKind: Literal("gondolin_pi"),
|
|
9611
9722
|
sandbox: RuntimeProfileSandbox,
|
|
9612
9723
|
sessionStorageMode: Literal("local"),
|
|
@@ -9718,7 +9829,7 @@ var RuntimeWorkspace = _Object_({
|
|
|
9718
9829
|
createdAtMs: Integer({ minimum: 0 }),
|
|
9719
9830
|
lastUsedAtMs: Integer({ minimum: 0 })
|
|
9720
9831
|
}, { $id: "RuntimeWorkspace" });
|
|
9721
|
-
_Object_({
|
|
9832
|
+
_Object_({ items: _Array_(_Object_({
|
|
9722
9833
|
slot: _Object_({
|
|
9723
9834
|
id: String$1({ format: "uuid" }),
|
|
9724
9835
|
teamId: String$1({ format: "uuid" }),
|
|
@@ -9751,7 +9862,7 @@ _Object_({
|
|
|
9751
9862
|
expiresAtMs: Integer({ minimum: 0 })
|
|
9752
9863
|
}, { $id: "RuntimeSlot" }),
|
|
9753
9864
|
workspace: Union([RuntimeWorkspace, Null()])
|
|
9754
|
-
}, { $id: "ResolvedRuntimeSlot" });
|
|
9865
|
+
}, { $id: "ResolvedRuntimeSlot" })) }, { $id: "RuntimeSlotListResponse" });
|
|
9755
9866
|
_Object_({
|
|
9756
9867
|
agentName: String$1({
|
|
9757
9868
|
minLength: 1,
|
|
@@ -9812,6 +9923,21 @@ _Object_({
|
|
|
9812
9923
|
$id: "FindLatestRuntimeSlotForAttemptQuery",
|
|
9813
9924
|
additionalProperties: false
|
|
9814
9925
|
});
|
|
9926
|
+
_Object_({
|
|
9927
|
+
agentName: Optional(String$1({
|
|
9928
|
+
minLength: 1,
|
|
9929
|
+
maxLength: 100
|
|
9930
|
+
})),
|
|
9931
|
+
runtimeProfileId: Optional(String$1({ format: "uuid" })),
|
|
9932
|
+
state: Optional(RuntimeSlotState),
|
|
9933
|
+
limit: Optional(Integer({
|
|
9934
|
+
minimum: 1,
|
|
9935
|
+
maximum: 200
|
|
9936
|
+
}))
|
|
9937
|
+
}, {
|
|
9938
|
+
$id: "ListRuntimeSlotsQuery",
|
|
9939
|
+
additionalProperties: false
|
|
9940
|
+
});
|
|
9815
9941
|
//#endregion
|
|
9816
9942
|
//#region ../tasks/src/success-criteria.ts
|
|
9817
9943
|
/**
|
|
@@ -9959,6 +10085,97 @@ var VerificationRecord = _Object_({
|
|
|
9959
10085
|
$id: "VerificationRecord",
|
|
9960
10086
|
additionalProperties: false
|
|
9961
10087
|
});
|
|
10088
|
+
_Object_({
|
|
10089
|
+
artifacts: _Array_(_Object_({
|
|
10090
|
+
id: String$1({ format: "uuid" }),
|
|
10091
|
+
teamId: String$1({ format: "uuid" }),
|
|
10092
|
+
taskId: String$1({ format: "uuid" }),
|
|
10093
|
+
attemptN: Integer({ minimum: 1 }),
|
|
10094
|
+
kind: String$1({
|
|
10095
|
+
minLength: 1,
|
|
10096
|
+
maxLength: 100
|
|
10097
|
+
}),
|
|
10098
|
+
title: String$1({
|
|
10099
|
+
minLength: 1,
|
|
10100
|
+
maxLength: 255
|
|
10101
|
+
}),
|
|
10102
|
+
contentType: String$1({
|
|
10103
|
+
minLength: 1,
|
|
10104
|
+
maxLength: 200
|
|
10105
|
+
}),
|
|
10106
|
+
contentEncoding: Union([String$1({
|
|
10107
|
+
minLength: 1,
|
|
10108
|
+
maxLength: 100
|
|
10109
|
+
}), Null()]),
|
|
10110
|
+
sizeBytes: Integer({ minimum: 0 }),
|
|
10111
|
+
cid: String$1({
|
|
10112
|
+
minLength: 1,
|
|
10113
|
+
maxLength: 100
|
|
10114
|
+
}),
|
|
10115
|
+
createdByAgentId: String$1({ format: "uuid" }),
|
|
10116
|
+
expiresAt: Union([String$1({ format: "date-time" }), Null()]),
|
|
10117
|
+
createdAt: String$1({ format: "date-time" })
|
|
10118
|
+
}, { $id: "TaskArtifact" })),
|
|
10119
|
+
nextCursor: Union([String$1({ minLength: 1 }), Null()])
|
|
10120
|
+
}, { $id: "TaskArtifactList" });
|
|
10121
|
+
_Object_({
|
|
10122
|
+
limit: Optional(Integer({
|
|
10123
|
+
minimum: 1,
|
|
10124
|
+
maximum: 100
|
|
10125
|
+
})),
|
|
10126
|
+
cursor: Optional(String$1({ minLength: 1 }))
|
|
10127
|
+
}, {
|
|
10128
|
+
$id: "ListTaskArtifactsQuery",
|
|
10129
|
+
additionalProperties: false
|
|
10130
|
+
});
|
|
10131
|
+
_Object_({
|
|
10132
|
+
kind: String$1({
|
|
10133
|
+
minLength: 1,
|
|
10134
|
+
maxLength: 100
|
|
10135
|
+
}),
|
|
10136
|
+
title: String$1({
|
|
10137
|
+
minLength: 1,
|
|
10138
|
+
maxLength: 255
|
|
10139
|
+
}),
|
|
10140
|
+
contentType: Optional(String$1({
|
|
10141
|
+
minLength: 1,
|
|
10142
|
+
maxLength: 200
|
|
10143
|
+
})),
|
|
10144
|
+
contentEncoding: Optional(String$1({
|
|
10145
|
+
minLength: 1,
|
|
10146
|
+
maxLength: 100
|
|
10147
|
+
}))
|
|
10148
|
+
}, {
|
|
10149
|
+
$id: "UploadTaskArtifactQuery",
|
|
10150
|
+
additionalProperties: false
|
|
10151
|
+
});
|
|
10152
|
+
String$1({
|
|
10153
|
+
$id: "TaskArtifactContent",
|
|
10154
|
+
description: "Task artifact content stream.",
|
|
10155
|
+
format: "binary"
|
|
10156
|
+
});
|
|
10157
|
+
_Object_({ taskId: String$1({ format: "uuid" }) }, {
|
|
10158
|
+
$id: "TaskArtifactTaskParams",
|
|
10159
|
+
additionalProperties: false
|
|
10160
|
+
});
|
|
10161
|
+
_Object_({
|
|
10162
|
+
taskId: String$1({ format: "uuid" }),
|
|
10163
|
+
attemptN: Integer({ minimum: 1 })
|
|
10164
|
+
}, {
|
|
10165
|
+
$id: "TaskArtifactAttemptParams",
|
|
10166
|
+
additionalProperties: false
|
|
10167
|
+
});
|
|
10168
|
+
_Object_({
|
|
10169
|
+
taskId: String$1({ format: "uuid" }),
|
|
10170
|
+
attemptN: Integer({ minimum: 1 }),
|
|
10171
|
+
cid: String$1({
|
|
10172
|
+
minLength: 1,
|
|
10173
|
+
maxLength: 100
|
|
10174
|
+
})
|
|
10175
|
+
}, {
|
|
10176
|
+
$id: "TaskArtifactContentParams",
|
|
10177
|
+
additionalProperties: false
|
|
10178
|
+
});
|
|
9962
10179
|
new TextEncoder();
|
|
9963
10180
|
new TextDecoder();
|
|
9964
10181
|
//#endregion
|
|
@@ -10218,6 +10435,10 @@ var FreeformArtifact = _Object_({
|
|
|
10218
10435
|
description: Optional(String$1({ minLength: 1 })),
|
|
10219
10436
|
url: Optional(String$1({ minLength: 1 })),
|
|
10220
10437
|
path: Optional(String$1({ minLength: 1 })),
|
|
10438
|
+
cid: Optional(String$1({ minLength: 1 })),
|
|
10439
|
+
contentType: Optional(String$1({ minLength: 1 })),
|
|
10440
|
+
contentEncoding: Optional(String$1({ minLength: 1 })),
|
|
10441
|
+
sizeBytes: Optional(Integer({ minimum: 0 })),
|
|
10221
10442
|
body: Optional(String$1({ maxLength: 65536 }))
|
|
10222
10443
|
}, {
|
|
10223
10444
|
$id: "FreeformArtifact",
|
|
@@ -10225,6 +10446,7 @@ var FreeformArtifact = _Object_({
|
|
|
10225
10446
|
});
|
|
10226
10447
|
var FreeformOutput = _Object_({
|
|
10227
10448
|
summary: String$1({ minLength: 1 }),
|
|
10449
|
+
branch: Optional(String$1({ minLength: 1 })),
|
|
10228
10450
|
artifacts: Optional(_Array_(FreeformArtifact, { maxItems: 20 })),
|
|
10229
10451
|
proposedTaskType: Optional(FreeformTaskTypeProposal),
|
|
10230
10452
|
diaryEntryIds: Optional(_Array_(String$1({ format: "uuid" }))),
|
|
@@ -10237,7 +10459,7 @@ var FreeformOutput = _Object_({
|
|
|
10237
10459
|
* Server-side preflight for `freeform` task-create. Runs after the
|
|
10238
10460
|
* sync TypeBox check passes and only kicks in when
|
|
10239
10461
|
* `input.continueFrom` is set — i.e. the proposer is asking to
|
|
10240
|
-
*
|
|
10462
|
+
* continue from a prior freeform attempt (#1287).
|
|
10241
10463
|
*
|
|
10242
10464
|
* Failure modes, in evaluation order:
|
|
10243
10465
|
* 1. `freeform.sourceTaskNotFound` — source task id does not resolve
|
|
@@ -10245,23 +10467,17 @@ var FreeformOutput = _Object_({
|
|
|
10245
10467
|
* 2. `freeform.sourceTaskTypeNotSupported` — source isn't `freeform`.
|
|
10246
10468
|
* v1 only supports freeform → freeform continuation.
|
|
10247
10469
|
* 3. `freeform.sourceAttemptNotCompleted` — named attempt is missing
|
|
10248
|
-
* or not in `completed` state;
|
|
10470
|
+
* or not in `completed` state; continuation only makes sense
|
|
10249
10471
|
* once the parent has produced a terminal output.
|
|
10250
10472
|
* 4. `freeform.executionWorkspaceNotInheritable` — caller set
|
|
10251
10473
|
* `execution.workspace` together with `continueFrom`. Workspace
|
|
10252
|
-
* mode for a continuation is
|
|
10253
|
-
* (
|
|
10254
|
-
*
|
|
10255
|
-
*
|
|
10256
|
-
*
|
|
10257
|
-
* 5. `freeform.sourceNotResumeEligible` — `daemonState` is null or
|
|
10258
|
-
* `slotResumableUntil` is null. Older completions (pre-#1287) and
|
|
10259
|
-
* daemons that opt out fall here.
|
|
10260
|
-
* 6. `freeform.sourceResumeExpired` — `slotResumableUntil` is in the
|
|
10261
|
-
* past; the warm slot's TTL has elapsed and no daemon is
|
|
10262
|
-
* guaranteed to still hold it.
|
|
10474
|
+
* mode for a continuation is derived by the daemon from parent runtime
|
|
10475
|
+
* context (local slot first, durable session + source attempt branch
|
|
10476
|
+
* second), so any caller-supplied override is silently dropped at the
|
|
10477
|
+
* daemon plan stage. Reject explicitly so misconfiguration surfaces at
|
|
10478
|
+
* create time.
|
|
10263
10479
|
*
|
|
10264
|
-
* Returns on the first failure
|
|
10480
|
+
* Returns on the first failure — the checks
|
|
10265
10481
|
* are sequential preconditions, later ones presume earlier ones hold.
|
|
10266
10482
|
*/
|
|
10267
10483
|
async function validateFreeformInputAsync(input, ctx) {
|
|
@@ -10280,7 +10496,7 @@ async function validateFreeformInputAsync(input, ctx) {
|
|
|
10280
10496
|
}];
|
|
10281
10497
|
if (input.execution?.workspace) return [{
|
|
10282
10498
|
field: "input/execution/workspace",
|
|
10283
|
-
message: "execution.workspace is
|
|
10499
|
+
message: "execution.workspace is derived from parent runtime context when continueFrom is set; omit it",
|
|
10284
10500
|
code: "freeform.executionWorkspaceNotInheritable"
|
|
10285
10501
|
}];
|
|
10286
10502
|
if (ctx.deferReadinessChecks) return [];
|
|
@@ -10290,17 +10506,6 @@ async function validateFreeformInputAsync(input, ctx) {
|
|
|
10290
10506
|
message: `Source attempt ${cf.attemptN} on task ${cf.taskId} is not in 'completed' state`,
|
|
10291
10507
|
code: "freeform.sourceAttemptNotCompleted"
|
|
10292
10508
|
}];
|
|
10293
|
-
if (!attempt.daemonState || attempt.daemonState.slotResumableUntil === null) return [{
|
|
10294
|
-
field: "input/continueFrom",
|
|
10295
|
-
message: "Source attempt did not report continuation eligibility (older completion or daemon opted out)",
|
|
10296
|
-
code: "freeform.sourceNotResumeEligible"
|
|
10297
|
-
}];
|
|
10298
|
-
const expiresAt = new Date(attempt.daemonState.slotResumableUntil).getTime();
|
|
10299
|
-
if (Number.isNaN(expiresAt) || expiresAt <= Date.now()) return [{
|
|
10300
|
-
field: "input/continueFrom",
|
|
10301
|
-
message: `Source attempt's warm slot expired at ${attempt.daemonState.slotResumableUntil} (reported at ${attempt.daemonState.reportedAt})`,
|
|
10302
|
-
code: "freeform.sourceResumeExpired"
|
|
10303
|
-
}];
|
|
10304
10509
|
return [];
|
|
10305
10510
|
}
|
|
10306
10511
|
//#endregion
|
|
@@ -13635,11 +13840,12 @@ var MAX_CLAIM_CONDITION_STATUSES = 8;
|
|
|
13635
13840
|
/**
|
|
13636
13841
|
* Daemon-asserted runtime state stamped onto a `TaskAttemptSummary` at
|
|
13637
13842
|
* attempt-completion time. The server persists this block verbatim and
|
|
13638
|
-
*
|
|
13639
|
-
* eligibility
|
|
13640
|
-
*
|
|
13641
|
-
*
|
|
13642
|
-
*
|
|
13843
|
+
* exposes `slotResumableUntil` as a legacy/local warm-slot hint; task
|
|
13844
|
+
* continuation eligibility is based on the completed source attempt and
|
|
13845
|
+
* daemon-side claim-affinity/runtime-session recovery. The block carries
|
|
13846
|
+
* its own `reportedAt` so consumers can reason about staleness without
|
|
13847
|
+
* reading documentation. All daemon-asserted state lives here —
|
|
13848
|
+
* top-level attempt fields stay server-authoritative.
|
|
13643
13849
|
*
|
|
13644
13850
|
* Adding new fields requires explicit design review (intentional
|
|
13645
13851
|
* boundary; see docs/superpowers/specs/2026-06-04-tasks-continue-design.md).
|
|
@@ -13703,7 +13909,23 @@ var TaskRef = _Object_({
|
|
|
13703
13909
|
url: Optional(String$1()),
|
|
13704
13910
|
commit_sha: Optional(String$1()),
|
|
13705
13911
|
snapshot_cid: Optional(Cid)
|
|
13706
|
-
}))
|
|
13912
|
+
})),
|
|
13913
|
+
artifact: Optional(_Object_({
|
|
13914
|
+
cid: Cid,
|
|
13915
|
+
attemptN: Integer({ minimum: 1 }),
|
|
13916
|
+
kind: Optional(String$1({
|
|
13917
|
+
minLength: 1,
|
|
13918
|
+
maxLength: 100
|
|
13919
|
+
})),
|
|
13920
|
+
title: Optional(String$1({
|
|
13921
|
+
minLength: 1,
|
|
13922
|
+
maxLength: 255
|
|
13923
|
+
})),
|
|
13924
|
+
contentType: Optional(String$1({
|
|
13925
|
+
minLength: 1,
|
|
13926
|
+
maxLength: 200
|
|
13927
|
+
}))
|
|
13928
|
+
}, { additionalProperties: false }))
|
|
13707
13929
|
}, {
|
|
13708
13930
|
$id: "TaskRef",
|
|
13709
13931
|
additionalProperties: false
|
|
@@ -14048,6 +14270,7 @@ var TaskBuilder = class {
|
|
|
14048
14270
|
message: "reference is missing required outputCid"
|
|
14049
14271
|
}]);
|
|
14050
14272
|
ref = {
|
|
14273
|
+
...s,
|
|
14051
14274
|
taskId: s.taskId ?? null,
|
|
14052
14275
|
outputCid: s.outputCid,
|
|
14053
14276
|
role
|
|
@@ -14057,6 +14280,60 @@ var TaskBuilder = class {
|
|
|
14057
14280
|
return this;
|
|
14058
14281
|
}
|
|
14059
14282
|
/**
|
|
14283
|
+
* Add a reference to a persistent task artifact while retaining the accepted
|
|
14284
|
+
* output CID as the provenance anchor.
|
|
14285
|
+
*
|
|
14286
|
+
* @param source - A result reader, raw artifact reference, or `TaskRef`.
|
|
14287
|
+
* @param role - The role the referenced artifact plays.
|
|
14288
|
+
* @returns This builder, for chaining.
|
|
14289
|
+
* @throws {TaskBuildError} when output or artifact CID is missing.
|
|
14290
|
+
*/
|
|
14291
|
+
artifactReference(source, role) {
|
|
14292
|
+
let ref;
|
|
14293
|
+
if ("artifactRef" in source && typeof source.artifactRef === "function") ref = source.artifactRef(role);
|
|
14294
|
+
else if ("artifact" in source && source.artifact?.cid) {
|
|
14295
|
+
if (typeof source.artifact.attemptN !== "number" || !Number.isInteger(source.artifact.attemptN) || source.artifact.attemptN < 1) throw new TaskBuildError([{
|
|
14296
|
+
field: "references/artifact/attemptN",
|
|
14297
|
+
message: "artifact reference is missing required attemptN"
|
|
14298
|
+
}]);
|
|
14299
|
+
ref = {
|
|
14300
|
+
...source,
|
|
14301
|
+
role
|
|
14302
|
+
};
|
|
14303
|
+
} else {
|
|
14304
|
+
const s = source;
|
|
14305
|
+
const errors = [];
|
|
14306
|
+
if (!s.outputCid) errors.push({
|
|
14307
|
+
field: "references/outputCid",
|
|
14308
|
+
message: "reference is missing required outputCid"
|
|
14309
|
+
});
|
|
14310
|
+
if (!s.artifactCid) errors.push({
|
|
14311
|
+
field: "references/artifact/cid",
|
|
14312
|
+
message: "artifact reference is missing required cid"
|
|
14313
|
+
});
|
|
14314
|
+
if (typeof s.attemptN !== "number" || !Number.isInteger(s.attemptN) || s.attemptN < 1) errors.push({
|
|
14315
|
+
field: "references/artifact/attemptN",
|
|
14316
|
+
message: "artifact reference is missing required attemptN"
|
|
14317
|
+
});
|
|
14318
|
+
if (errors.length > 0) throw new TaskBuildError(errors);
|
|
14319
|
+
const attemptN = s.attemptN;
|
|
14320
|
+
ref = {
|
|
14321
|
+
taskId: s.taskId ?? null,
|
|
14322
|
+
outputCid: s.outputCid,
|
|
14323
|
+
role,
|
|
14324
|
+
artifact: {
|
|
14325
|
+
cid: s.artifactCid,
|
|
14326
|
+
attemptN,
|
|
14327
|
+
...s.kind ? { kind: s.kind } : {},
|
|
14328
|
+
...s.title ? { title: s.title } : {},
|
|
14329
|
+
...s.contentType ? { contentType: s.contentType } : {}
|
|
14330
|
+
}
|
|
14331
|
+
};
|
|
14332
|
+
}
|
|
14333
|
+
this.refs.push(ref);
|
|
14334
|
+
return this;
|
|
14335
|
+
}
|
|
14336
|
+
/**
|
|
14060
14337
|
* Set the owning team (required by the wire schema).
|
|
14061
14338
|
*
|
|
14062
14339
|
* @param teamId - Team UUID.
|
|
@@ -14434,6 +14711,34 @@ var TaskResultReader = class {
|
|
|
14434
14711
|
role
|
|
14435
14712
|
};
|
|
14436
14713
|
}
|
|
14714
|
+
/**
|
|
14715
|
+
* Build a `TaskRef` that anchors a downstream task to this accepted output
|
|
14716
|
+
* and points at one persistent task artifact by CID.
|
|
14717
|
+
*
|
|
14718
|
+
* @param filter - Artifact object or a filter resolved against output artifacts.
|
|
14719
|
+
* @param role - The role this artifact plays in the downstream task.
|
|
14720
|
+
* @returns A `TaskRef` with `artifact.cid` populated.
|
|
14721
|
+
* @throws {TaskResultError} if no matching artifact has a CID.
|
|
14722
|
+
*/
|
|
14723
|
+
artifactRef(filter, role) {
|
|
14724
|
+
const artifact = typeof filter === "object" && "cid" in filter && "kind" in filter ? filter : this.artifact(filter);
|
|
14725
|
+
if (!artifact?.cid) throw new TaskResultError([{
|
|
14726
|
+
field: "artifacts/cid",
|
|
14727
|
+
message: "no matching artifact with a cid"
|
|
14728
|
+
}]);
|
|
14729
|
+
return {
|
|
14730
|
+
taskId: this.taskId,
|
|
14731
|
+
outputCid: this.outputCid,
|
|
14732
|
+
role,
|
|
14733
|
+
artifact: {
|
|
14734
|
+
cid: artifact.cid,
|
|
14735
|
+
attemptN: this.accepted.attemptN,
|
|
14736
|
+
kind: artifact.kind,
|
|
14737
|
+
title: artifact.title,
|
|
14738
|
+
...artifact.contentType ? { contentType: artifact.contentType } : {}
|
|
14739
|
+
}
|
|
14740
|
+
};
|
|
14741
|
+
}
|
|
14437
14742
|
};
|
|
14438
14743
|
/**
|
|
14439
14744
|
* Validate and construct a {@link TaskResultReader} from a task and its
|
|
@@ -14458,6 +14763,63 @@ function createTasksNamespace(context) {
|
|
|
14458
14763
|
auth
|
|
14459
14764
|
}));
|
|
14460
14765
|
},
|
|
14766
|
+
artifacts: {
|
|
14767
|
+
async upload(path, body, query, options) {
|
|
14768
|
+
return unwrapResult(await uploadTaskArtifact({
|
|
14769
|
+
auth,
|
|
14770
|
+
body,
|
|
14771
|
+
client,
|
|
14772
|
+
duplex: "half",
|
|
14773
|
+
headers: {
|
|
14774
|
+
...requiredTeamHeaders(options),
|
|
14775
|
+
"content-type": "application/octet-stream"
|
|
14776
|
+
},
|
|
14777
|
+
path,
|
|
14778
|
+
query
|
|
14779
|
+
}));
|
|
14780
|
+
},
|
|
14781
|
+
async list(taskId, options, query) {
|
|
14782
|
+
return unwrapResult(await listTaskArtifacts({
|
|
14783
|
+
client,
|
|
14784
|
+
auth,
|
|
14785
|
+
headers: requiredTeamHeaders(options),
|
|
14786
|
+
path: { taskId },
|
|
14787
|
+
query
|
|
14788
|
+
})).artifacts;
|
|
14789
|
+
},
|
|
14790
|
+
async listPage(taskId, query, options) {
|
|
14791
|
+
return unwrapResult(await listTaskArtifacts({
|
|
14792
|
+
client,
|
|
14793
|
+
auth,
|
|
14794
|
+
headers: requiredTeamHeaders(options),
|
|
14795
|
+
path: { taskId },
|
|
14796
|
+
query
|
|
14797
|
+
}));
|
|
14798
|
+
},
|
|
14799
|
+
async download(path, options) {
|
|
14800
|
+
const result = await client.request({
|
|
14801
|
+
auth,
|
|
14802
|
+
headers: requiredTeamHeaders(options),
|
|
14803
|
+
method: "GET",
|
|
14804
|
+
parseAs: "stream",
|
|
14805
|
+
path,
|
|
14806
|
+
security: [{
|
|
14807
|
+
scheme: "bearer",
|
|
14808
|
+
type: "http"
|
|
14809
|
+
}],
|
|
14810
|
+
url: "/tasks/{taskId}/attempts/{attemptN}/artifacts/{cid}/content"
|
|
14811
|
+
});
|
|
14812
|
+
const normalizedStream = normalizeDownloadStream(unwrapResult(result));
|
|
14813
|
+
if (normalizedStream) return {
|
|
14814
|
+
artifactId: header(result.response, "x-moltnet-task-artifact-id"),
|
|
14815
|
+
cid: header(result.response, "x-moltnet-task-artifact-cid"),
|
|
14816
|
+
contentEncoding: header(result.response, "x-moltnet-task-artifact-content-encoding"),
|
|
14817
|
+
contentType: header(result.response, "x-moltnet-task-artifact-content-type"),
|
|
14818
|
+
stream: normalizedStream
|
|
14819
|
+
};
|
|
14820
|
+
throw new MoltNetError("Unexpected task artifact download response stream", { code: "INVALID_RESPONSE" });
|
|
14821
|
+
}
|
|
14822
|
+
},
|
|
14461
14823
|
async list(query, options) {
|
|
14462
14824
|
return unwrapResult(await listTasks({
|
|
14463
14825
|
client,
|
|
@@ -14626,6 +14988,33 @@ function createTasksNamespace(context) {
|
|
|
14626
14988
|
}
|
|
14627
14989
|
};
|
|
14628
14990
|
}
|
|
14991
|
+
function header(response, name) {
|
|
14992
|
+
const value = response?.headers.get(name) ?? null;
|
|
14993
|
+
return value === "" ? null : value;
|
|
14994
|
+
}
|
|
14995
|
+
function normalizeDownloadStream(stream) {
|
|
14996
|
+
if (isAsyncIterable(stream)) return stream;
|
|
14997
|
+
if (isReadableStream(stream)) return readableStreamToAsyncIterable(stream);
|
|
14998
|
+
return null;
|
|
14999
|
+
}
|
|
15000
|
+
function isAsyncIterable(value) {
|
|
15001
|
+
return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
|
|
15002
|
+
}
|
|
15003
|
+
function isReadableStream(value) {
|
|
15004
|
+
return typeof value === "object" && value !== null && "getReader" in value && typeof value.getReader === "function";
|
|
15005
|
+
}
|
|
15006
|
+
async function* readableStreamToAsyncIterable(stream) {
|
|
15007
|
+
const reader = stream.getReader();
|
|
15008
|
+
try {
|
|
15009
|
+
while (true) {
|
|
15010
|
+
const result = await reader.read();
|
|
15011
|
+
if (result.done) return;
|
|
15012
|
+
yield result.value;
|
|
15013
|
+
}
|
|
15014
|
+
} finally {
|
|
15015
|
+
reader.releaseLock();
|
|
15016
|
+
}
|
|
15017
|
+
}
|
|
14629
15018
|
//#endregion
|
|
14630
15019
|
//#region ../sdk/src/namespaces/teams.ts
|
|
14631
15020
|
function createTeamsNamespace(context) {
|
|
@@ -19,16 +19,13 @@ var init = (RED) => {
|
|
|
19
19
|
} : def.artifactKind : void 0;
|
|
20
20
|
let artifactBody;
|
|
21
21
|
const artifact = filter ? reader.artifact(filter) : void 0;
|
|
22
|
-
if (filter && artifact && typeof artifact.body === "string")
|
|
23
|
-
artifactBody = JSON.parse(artifact.body);
|
|
24
|
-
} catch {
|
|
25
|
-
artifactBody = void 0;
|
|
26
|
-
}
|
|
22
|
+
if (filter && artifact && typeof artifact.body === "string") artifactBody = reader.artifactBody(filter);
|
|
27
23
|
const out = RED.util.cloneMessage(msg);
|
|
28
24
|
out.payload = reader.output;
|
|
29
25
|
out.result = {
|
|
30
26
|
summary: reader.summary,
|
|
31
27
|
outputRef: reader.outputRef(role),
|
|
28
|
+
artifactRef: artifact?.cid !== void 0 ? reader.artifactRef(artifact, role) : void 0,
|
|
32
29
|
artifact,
|
|
33
30
|
artifactBody,
|
|
34
31
|
accepted: reader.accepted,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/node-red-contrib-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Node-RED nodes for the MoltNet API",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"main": "dist/nodes/agent.js",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@themoltnet/sdk": "0.
|
|
41
|
+
"@themoltnet/sdk": "0.115.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.19.0",
|