narraeon 0.1.1 → 0.2.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/node/protocol/modelConnections.js +49 -0
- package/dist/node/protocol/modelUsage.js +39 -0
- package/dist/node/protocol/v1.js +29 -0
- package/dist/node/runtime/V1Runtime.js +59 -23
- package/dist/node/runtime/model/FileNativeModelAdapters.js +691 -275
- package/dist/node/runtime/model/ModelConnectionStore.js +123 -2
- package/dist/node/runtime/model/ModelHost.js +74 -9
- package/dist/node/runtime/model/ModelHostStream.js +61 -1
- package/dist/node/runtime/model/SettingAuthorStream.js +16 -113
- package/dist/node/runtime/play/FileNativePlayAdvanceStore.js +269 -0
- package/dist/node/runtime/play/FileNativePlayTimelineStore.js +1039 -0
- package/dist/node/runtime/play/PlayCallChain.js +609 -330
- package/dist/node/runtime/play/PlayDocumentTools.js +35 -0
- package/dist/node/runtime/play/PlayFollowupRequests.js +1 -4
- package/dist/node/runtime/prompt/FileNativePromptCompiler.js +45 -30
- package/dist/node/runtime/prompt/FileNativeToolRegistry.js +55 -29
- package/dist/node/runtime/setting/DocumentCandidateSettingImprovement.js +9 -4
- package/dist/node/runtime/world/FileNativeWorldStorageMigrator.js +626 -0
- package/dist/node/runtime/world/FileNativeWorldStore.js +449 -191
- package/dist/web/assets/index-DHV_VWl3.js +1192 -0
- package/dist/web/assets/index-DjLCkP99.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-CRGTZ9Ak.css +0 -1
- package/dist/web/assets/index-DDx1itzT.js +0 -1192
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
/** CLIProxyAPI gives these model-name suffixes priority over body effort. */
|
|
2
|
+
export function hasCLIProxyThinkingSuffix(modelId) {
|
|
3
|
+
return /\((?:-1|none|auto|minimal|low|medium|high|xhigh|max|\d+)\)$/iu.test(modelId);
|
|
4
|
+
}
|
|
5
|
+
/** One validation authority shared by storage and the wire adapter boundary. */
|
|
6
|
+
export function modelReasoningPolicyIssue(input) {
|
|
7
|
+
const thinking = input.thinking ?? "provider_default";
|
|
8
|
+
const thinkingBudgetTokens = input.thinkingBudgetTokens ?? null;
|
|
9
|
+
const thinkingControlledByCLIProxySuffix = input.provider === "anthropic_messages" &&
|
|
10
|
+
input.dialect === "cliproxyapi" &&
|
|
11
|
+
hasCLIProxyThinkingSuffix(input.modelId);
|
|
12
|
+
if (input.provider === "anthropic_messages" &&
|
|
13
|
+
(input.effort === "none" || input.effort === "minimal"))
|
|
14
|
+
return "Anthropic Messages effort supports low, medium, high, xhigh, and max; use Thinking disabled instead of effort none";
|
|
15
|
+
if (input.provider !== "anthropic_messages" &&
|
|
16
|
+
thinking !== "provider_default")
|
|
17
|
+
return "Only Anthropic Messages defines a separate thinking mode; OpenAI-shaped protocols control reasoning through effort";
|
|
18
|
+
if (input.provider !== "anthropic_messages" && thinkingBudgetTokens !== null)
|
|
19
|
+
return "Only Anthropic Messages manual thinking accepts a thinking token budget";
|
|
20
|
+
if (thinking === "enabled") {
|
|
21
|
+
if (thinkingBudgetTokens === null ||
|
|
22
|
+
!Number.isSafeInteger(thinkingBudgetTokens) ||
|
|
23
|
+
thinkingBudgetTokens < 1_024)
|
|
24
|
+
return "Anthropic manual thinking requires an integer budget of at least 1024 tokens";
|
|
25
|
+
if (input.maxOutputTokens !== undefined &&
|
|
26
|
+
thinkingBudgetTokens >= input.maxOutputTokens)
|
|
27
|
+
return "Anthropic thinking budget must be lower than maximum output tokens";
|
|
28
|
+
}
|
|
29
|
+
else if (thinkingBudgetTokens !== null) {
|
|
30
|
+
return "A thinking token budget is valid only when Anthropic Thinking is set to manual enabled";
|
|
31
|
+
}
|
|
32
|
+
if (input.provider === "anthropic_messages" &&
|
|
33
|
+
(thinking === "provider_default" || thinking === "disabled") &&
|
|
34
|
+
input.summary !== "provider_default" &&
|
|
35
|
+
!(thinking === "provider_default" && thinkingControlledByCLIProxySuffix))
|
|
36
|
+
return "Anthropic returned thinking can be configured only when Thinking is adaptive or manual enabled, or when a CLIProxyAPI model suffix controls Thinking";
|
|
37
|
+
if (input.provider !== "openai_responses" &&
|
|
38
|
+
(input.summary === "concise" || input.summary === "detailed"))
|
|
39
|
+
return "Concise and detailed reasoning summaries are defined only by OpenAI Responses";
|
|
40
|
+
if (input.provider === "chat_completions" &&
|
|
41
|
+
input.dialect === "standard" &&
|
|
42
|
+
input.summary !== "provider_default")
|
|
43
|
+
return "Standard Chat Completions has no reasoning-summary parameter; use provider default or select the CLIProxyAPI dialect";
|
|
44
|
+
if (input.dialect === "cliproxyapi" &&
|
|
45
|
+
(input.effort !== "provider_default" || thinking !== "provider_default") &&
|
|
46
|
+
hasCLIProxyThinkingSuffix(input.modelId))
|
|
47
|
+
return "CLIProxyAPI model thinking suffixes override request effort and thinking; use either the model suffix with provider defaults or explicit request fields, not both";
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
1
50
|
export const modelProviderPresets = [
|
|
2
51
|
{
|
|
3
52
|
id: "custom",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const modelUsageKeys = [
|
|
2
|
+
"inputTokens",
|
|
3
|
+
"uncachedInputTokens",
|
|
4
|
+
"cacheReadTokens",
|
|
5
|
+
"cacheWriteTokens",
|
|
6
|
+
"reasoningTokens",
|
|
7
|
+
"outputTokens",
|
|
8
|
+
"totalTokens",
|
|
9
|
+
];
|
|
10
|
+
/** A zero baseline used only before any Provider exchange has completed. */
|
|
11
|
+
export function emptyAggregatedModelUsage() {
|
|
12
|
+
return usageWithValue(0, "derived_provider_fields");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Sum complete Provider usage records without treating an unreported field as
|
|
16
|
+
* zero. Once any exchange lacks a field, that aggregate remains unavailable.
|
|
17
|
+
*/
|
|
18
|
+
export function aggregateModelUsage(current, next) {
|
|
19
|
+
const result = {};
|
|
20
|
+
for (const key of modelUsageKeys) {
|
|
21
|
+
const right = next?.[key] ?? null;
|
|
22
|
+
result[key] =
|
|
23
|
+
current[key] === null || right === null ? null : current[key] + right;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...result,
|
|
27
|
+
provenance: Object.fromEntries(modelUsageKeys.map((key) => [
|
|
28
|
+
key,
|
|
29
|
+
result[key] === null ? "unavailable" : "derived_provider_fields",
|
|
30
|
+
])),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function usageWithValue(value, source) {
|
|
34
|
+
const values = Object.fromEntries(modelUsageKeys.map((key) => [key, value]));
|
|
35
|
+
return {
|
|
36
|
+
...values,
|
|
37
|
+
provenance: Object.fromEntries(modelUsageKeys.map((key) => [key, source])),
|
|
38
|
+
};
|
|
39
|
+
}
|
package/dist/node/protocol/v1.js
CHANGED
|
@@ -107,6 +107,14 @@ const requiredFields = {
|
|
|
107
107
|
playerText: "string",
|
|
108
108
|
},
|
|
109
109
|
"play.chain.inspect": { worldId: "string" },
|
|
110
|
+
"play.timeline.page": { worldId: "string", limit: "number" },
|
|
111
|
+
"play.timeline.detail": {
|
|
112
|
+
worldId: "string",
|
|
113
|
+
chainId: "string",
|
|
114
|
+
eventId: "number",
|
|
115
|
+
},
|
|
116
|
+
"world.surface.read": { worldId: "string", surface: "string" },
|
|
117
|
+
"world.play-decorations.read": { worldId: "string" },
|
|
110
118
|
"correction.begin": { worldId: "string", operationId: "string" },
|
|
111
119
|
"correction.read": { candidateId: "string", document: "string" },
|
|
112
120
|
"correction.patch": {
|
|
@@ -205,6 +213,23 @@ function validateRequestFields(request) {
|
|
|
205
213
|
request.operationId !== undefined &&
|
|
206
214
|
(typeof request.operationId !== "string" || request.operationId === ""))
|
|
207
215
|
throw new V1ProtocolError("invalid_request", "artifacts.debug.operationId is invalid");
|
|
216
|
+
if (request.type === "play.timeline.page") {
|
|
217
|
+
if (!Number.isSafeInteger(request.limit) ||
|
|
218
|
+
Number(request.limit) < 1 ||
|
|
219
|
+
Number(request.limit) > 100 ||
|
|
220
|
+
(request.cursor !== undefined &&
|
|
221
|
+
(typeof request.cursor !== "string" || request.cursor === "")))
|
|
222
|
+
throw new V1ProtocolError("invalid_request", "play.timeline.page pagination is invalid");
|
|
223
|
+
}
|
|
224
|
+
if (request.type === "play.timeline.detail" &&
|
|
225
|
+
(!Number.isSafeInteger(request.eventId) || Number(request.eventId) < 1))
|
|
226
|
+
throw new V1ProtocolError("invalid_request", "play.timeline.detail.eventId is invalid");
|
|
227
|
+
if (request.type === "world.surface.read" &&
|
|
228
|
+
request.surface !== "state" &&
|
|
229
|
+
request.surface !== "control" &&
|
|
230
|
+
request.surface !== "history" &&
|
|
231
|
+
request.surface !== "runtime")
|
|
232
|
+
throw new V1ProtocolError("invalid_request", "world.surface.read.surface is invalid");
|
|
208
233
|
if (request.type !== "setting-improvement.start")
|
|
209
234
|
return;
|
|
210
235
|
if (request.mode !== "plan_first" && request.mode !== "direct_candidate")
|
|
@@ -265,6 +290,10 @@ const requestTypes = new Set([
|
|
|
265
290
|
"play.chain.start",
|
|
266
291
|
"play.chain.append",
|
|
267
292
|
"play.chain.inspect",
|
|
293
|
+
"play.timeline.page",
|
|
294
|
+
"play.timeline.detail",
|
|
295
|
+
"world.surface.read",
|
|
296
|
+
"world.play-decorations.read",
|
|
268
297
|
"correction.begin",
|
|
269
298
|
"correction.read",
|
|
270
299
|
"correction.patch",
|
|
@@ -239,7 +239,8 @@ export class V1Runtime {
|
|
|
239
239
|
: this.#playPresets.bindRevision(request.playPresetId, request.playPresetRevision),
|
|
240
240
|
]);
|
|
241
241
|
const hostBinding = presetHostBinding(playPreset);
|
|
242
|
-
|
|
242
|
+
const modelHost = new FileNativeModelHost(connection);
|
|
243
|
+
const preview = this.#compiler.preview({
|
|
243
244
|
endpoint: {
|
|
244
245
|
id: `content:${request.packageId}`,
|
|
245
246
|
commit: "current",
|
|
@@ -251,8 +252,32 @@ export class V1Runtime {
|
|
|
251
252
|
}), `content:${request.packageId}.message.genesis.narrator`, "content-preview"),
|
|
252
253
|
playerInputPlacement: "append",
|
|
253
254
|
playerInput: request.playerInput,
|
|
254
|
-
modelBinding:
|
|
255
|
+
modelBinding: modelHost.binding(),
|
|
255
256
|
}, playPreset);
|
|
257
|
+
const tools = structuredClone(preview.compilation.toolUniverse ?? preview.compilation.tools);
|
|
258
|
+
return {
|
|
259
|
+
...preview,
|
|
260
|
+
wireRequest: modelHost.previewRequest({
|
|
261
|
+
bootstrap: structuredClone(preview.compilation),
|
|
262
|
+
tools: structuredClone(tools),
|
|
263
|
+
toolUniverse: structuredClone(tools),
|
|
264
|
+
allowedTools: tools.map(({ name }) => name),
|
|
265
|
+
toolStrategy: preview.compilation.toolStrategy,
|
|
266
|
+
appended: preview.initialAppend === undefined
|
|
267
|
+
? []
|
|
268
|
+
: [
|
|
269
|
+
{
|
|
270
|
+
kind: "player",
|
|
271
|
+
text: preview.initialAppend.logical.text,
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
requestId: "play_call_chain",
|
|
275
|
+
operationId: "prompt-preview",
|
|
276
|
+
requestAttempt: 1,
|
|
277
|
+
exchange: 1,
|
|
278
|
+
maxOutputTokens: modelHost.binding().maxOutputTokens,
|
|
279
|
+
}),
|
|
280
|
+
};
|
|
256
281
|
}
|
|
257
282
|
case "world.create": {
|
|
258
283
|
const [package_, connection, preset] = await Promise.all([
|
|
@@ -280,38 +305,42 @@ export class V1Runtime {
|
|
|
280
305
|
return this.#worlds.deleteWorld(request.worldId);
|
|
281
306
|
});
|
|
282
307
|
case "world.read": {
|
|
283
|
-
await this.#reconcileArtifacts(request.worldId);
|
|
284
308
|
const head = await this.#worlds.currentHead(request.worldId);
|
|
285
309
|
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
286
|
-
const [
|
|
287
|
-
this.#worlds.readSurface(request.worldId, "state"),
|
|
288
|
-
this.#worlds.readSurface(request.worldId, "control"),
|
|
289
|
-
this.#worlds.readSurface(request.worldId, "history"),
|
|
290
|
-
this.#worlds.readSurface(request.worldId, "runtime"),
|
|
291
|
-
this.#worlds.recoverEndpoint(request.worldId, head),
|
|
292
|
-
this.#worlds.readAuthorityHistory(request.worldId),
|
|
293
|
-
this.#frontendProjection(request.worldId),
|
|
294
|
-
this.#artifacts.readExtensionSummaries(request.worldId),
|
|
310
|
+
const [playerViewPanels, playTimeline] = await Promise.all([
|
|
295
311
|
this.#frontendPlayerViewPanels(request.worldId, head, playerViews),
|
|
312
|
+
this.#worlds.playTimeline.readPage(request.worldId, 40),
|
|
296
313
|
]);
|
|
297
314
|
return {
|
|
298
315
|
worldId: request.worldId,
|
|
299
316
|
head,
|
|
300
|
-
state,
|
|
301
|
-
control,
|
|
302
|
-
history,
|
|
303
|
-
runtime,
|
|
317
|
+
state: [],
|
|
318
|
+
control: [],
|
|
319
|
+
history: [],
|
|
320
|
+
runtime: { head, surfaces: "lazy" },
|
|
304
321
|
playerViews,
|
|
305
|
-
committedMessages:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
})),
|
|
309
|
-
artifacts,
|
|
310
|
-
extensions,
|
|
322
|
+
committedMessages: [],
|
|
323
|
+
artifacts: [],
|
|
324
|
+
extensions: [],
|
|
311
325
|
playerViewPanels,
|
|
312
|
-
|
|
326
|
+
artifactDebug: [],
|
|
327
|
+
playCallChain: null,
|
|
328
|
+
playTimeline,
|
|
313
329
|
};
|
|
314
330
|
}
|
|
331
|
+
case "world.surface.read":
|
|
332
|
+
return request.surface === "runtime"
|
|
333
|
+
? this.#worlds.readSurface(request.worldId, "runtime")
|
|
334
|
+
: this.#worlds.readSurface(request.worldId, request.surface);
|
|
335
|
+
case "world.play-decorations.read": {
|
|
336
|
+
const head = await this.#reconcileArtifacts(request.worldId);
|
|
337
|
+
const [artifacts, extensions, artifactDebug] = await Promise.all([
|
|
338
|
+
this.#frontendProjection(request.worldId),
|
|
339
|
+
this.#artifacts.readExtensionSummaries(request.worldId),
|
|
340
|
+
this.#frontendDebug(request.worldId),
|
|
341
|
+
]);
|
|
342
|
+
return { head, artifacts, extensions, artifactDebug };
|
|
343
|
+
}
|
|
315
344
|
case "artifacts.read":
|
|
316
345
|
await this.#reconcileArtifacts(request.worldId);
|
|
317
346
|
return this.#frontendProjection(request.worldId, request.channel);
|
|
@@ -400,6 +429,12 @@ export class V1Runtime {
|
|
|
400
429
|
}));
|
|
401
430
|
case "play.chain.inspect":
|
|
402
431
|
return this.#playCallChains.inspectWorld(request.worldId);
|
|
432
|
+
case "play.timeline.page":
|
|
433
|
+
await this.#worlds.ensureCurrentStorage(request.worldId);
|
|
434
|
+
return this.#worlds.playTimeline.readPage(request.worldId, request.limit, request.cursor);
|
|
435
|
+
case "play.timeline.detail":
|
|
436
|
+
await this.#worlds.ensureCurrentStorage(request.worldId);
|
|
437
|
+
return this.#worlds.playTimeline.readDetail(request.worldId, request.chainId, request.eventId);
|
|
403
438
|
case "correction.begin":
|
|
404
439
|
return this.#corrections.begin({
|
|
405
440
|
worldId: request.worldId,
|
|
@@ -437,6 +472,7 @@ export class V1Runtime {
|
|
|
437
472
|
this.#worlds.currentHeadOperationId(worldId),
|
|
438
473
|
]);
|
|
439
474
|
await this.#artifacts.reconcileHead(worldId, head, currentOperationId ?? undefined);
|
|
475
|
+
return head;
|
|
440
476
|
}
|
|
441
477
|
async #frontendProjection(worldId, channel) {
|
|
442
478
|
const artifacts = await this.#artifacts.readActiveProjection(worldId, channel);
|