experimental-a2 0.18.0 → 0.19.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/CHANGELOG.md +39 -0
- package/dist/{actor-Bjce9_5U.d.ts → actor-C7b-1arn.d.ts} +3 -3
- package/dist/{actor-Bjce9_5U.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
- package/dist/actor-client.d.ts +1 -1
- package/dist/actor-react.d.ts +1 -1
- package/dist/actor-react.js +1 -1
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +2 -2
- package/dist/{ai-DrUaMyRt.d.ts → ai-Cz3hqVhk.d.ts} +34 -17
- package/dist/ai-Cz3hqVhk.d.ts.map +1 -0
- package/dist/ai-client.d.ts +1 -1
- package/dist/ai-client.js +2 -2
- package/dist/ai-control-CvLbW10B.js +46 -0
- package/dist/ai-control-CvLbW10B.js.map +1 -0
- package/dist/ai-fx.d.ts +1 -1
- package/dist/ai-fx.d.ts.map +1 -1
- package/dist/ai-fx.js +122 -44
- package/dist/ai-fx.js.map +1 -1
- package/dist/{ai-harness-BuLh_EYi.js → ai-harness-BuuC-gJ3.js} +79 -15
- package/dist/ai-harness-BuuC-gJ3.js.map +1 -0
- package/dist/{ai-harness-DvsPeJeB.d.ts → ai-harness-CV6rXbB3.d.ts} +2 -2
- package/dist/ai-harness-CV6rXbB3.d.ts.map +1 -0
- package/dist/{ai-BpOGm-zB.js → ai-mMiWul1T.js} +117 -78
- package/dist/ai-mMiWul1T.js.map +1 -0
- package/dist/ai-pi.d.ts +1 -1
- package/dist/ai-pi.d.ts.map +1 -1
- package/dist/ai-pi.js +114 -23
- package/dist/ai-pi.js.map +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +2 -2
- package/dist/ai-server.d.ts +3 -3
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +127 -55
- package/dist/ai-server.js.map +1 -1
- package/dist/ai-tool-input-DmSqMUQi.js +40 -0
- package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +1 -1
- package/dist/{client-BReKqwZC.js → client-BhHLoNKF.js} +3 -3
- package/dist/{client-BReKqwZC.js.map → client-BhHLoNKF.js.map} +1 -1
- package/dist/client.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/{internal-B2T3U4Rq.js → internal-CscSY7K_.js} +4 -2
- package/dist/{internal-B2T3U4Rq.js.map → internal-CscSY7K_.js.map} +1 -1
- package/dist/react.js +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +3 -3
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts +7 -7
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +10 -14
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/{server-Dw_k_7kO.js → server-D-Y4pqwu.js} +37 -11
- package/dist/server-D-Y4pqwu.js.map +1 -0
- package/dist/{server-En7cbi3v.d.ts → server-DYAATFuT.d.ts} +11 -5
- package/dist/server-DYAATFuT.d.ts.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/{session-clear-Bo-XTFEy.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
- package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
- package/dist/{store-Djdv0bnZ.d.ts → store-CyLUy86v.d.ts} +23 -4
- package/dist/store-CyLUy86v.d.ts.map +1 -0
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.js +25 -6
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-B5FcwJfo.js → store-polling-7WJV0YWP.js} +2 -2
- package/dist/{store-polling-B5FcwJfo.js.map → store-polling-7WJV0YWP.js.map} +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +55 -25
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-BAwS8RWn.js → store-presence-polling-B1ixeqIS.js} +3 -3
- package/dist/{store-presence-polling-BAwS8RWn.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +3 -3
- package/dist/{store-redis-notify-BRITti_o.js → store-redis-notify-CM0AfLY0.js} +88 -37
- package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.js +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.js +35 -20
- package/dist/store-sqlite.js.map +1 -1
- package/dist/{wire-rSUglYo8.js → wire-BKxH1vbP.js} +2 -2
- package/dist/{wire-rSUglYo8.js.map → wire-BKxH1vbP.js.map} +1 -1
- package/docs/agents/03-conversations.mdx +27 -15
- package/docs/agents/04-harnesses.mdx +51 -5
- package/docs/contract/03-sessions.mdx +1 -1
- package/docs/index.mdx +3 -3
- package/docs/reference/02-server.mdx +12 -7
- package/docs/reference/04-ai.mdx +41 -23
- package/docs/reference/05-adapters.mdx +6 -6
- package/docs/server/01-handlers.mdx +1 -1
- package/docs/server/02-timers.mdx +1 -1
- package/docs/server/03-cancellation.mdx +3 -2
- package/docs/server/05-production.mdx +4 -3
- package/docs/server/06-guarantees.mdx +20 -11
- package/examples/playground/DEPLOY.md +11 -4
- package/examples/playground/app/a0/[appId]/page.tsx +2 -8
- package/examples/playground/app/a0/a0.css +244 -5
- package/examples/playground/app/a0/app-view.tsx +2 -1
- package/examples/playground/app/a0/attachments.ts +133 -0
- package/examples/playground/app/a0/chat.test.tsx +504 -0
- package/examples/playground/app/a0/chat.tsx +623 -63
- package/examples/playground/app/a0/context-menu.tsx +38 -11
- package/examples/playground/app/a0/devtools.tsx +2 -8
- package/examples/playground/app/a0/model.test.ts +28 -0
- package/examples/playground/app/a0/model.ts +30 -0
- package/examples/playground/app/a0/server.ts +13 -19
- package/examples/playground/app/a0/uploads/route.ts +29 -0
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +2 -1
- package/examples/playground/app/agent/[agentId]/agent-queue.test.tsx +1 -0
- package/examples/playground/app/agent/model.test.ts +12 -3
- package/examples/playground/app/chat/[chatId]/agent-state.test.ts +1 -5
- package/examples/playground/next.config.ts +7 -4
- package/examples/playground/package.json +3 -1
- package/package.json +1 -1
- package/src/ai-agent.ts +14 -3
- package/src/ai-client-state.ts +21 -9
- package/src/ai-context-schema.ts +28 -4
- package/src/ai-context.ts +83 -3
- package/src/ai-control-server.ts +70 -43
- package/src/ai-control-state.ts +3 -4
- package/src/ai-control.ts +59 -10
- package/src/ai-coordinator.ts +7 -6
- package/src/ai-fx.ts +184 -67
- package/src/ai-harness.ts +153 -29
- package/src/ai-message-shape.ts +41 -0
- package/src/ai-pi.ts +161 -46
- package/src/ai-stored-state.ts +1 -3
- package/src/ai-tool-input.ts +45 -0
- package/src/ai.ts +116 -77
- package/src/internal.ts +6 -0
- package/src/libfx.d.ts +8 -1
- package/src/scheduler-qstash.ts +5 -5
- package/src/scheduler-vercel.ts +15 -27
- package/src/server.ts +58 -12
- package/src/store-memory.ts +50 -9
- package/src/store-postgres.ts +79 -28
- package/src/store-redis-core.ts +112 -31
- package/src/store-sqlite.ts +61 -28
- package/src/store.ts +22 -3
- package/dist/ai-BpOGm-zB.js.map +0 -1
- package/dist/ai-DrUaMyRt.d.ts.map +0 -1
- package/dist/ai-harness-BuLh_EYi.js.map +0 -1
- package/dist/ai-harness-DvsPeJeB.d.ts.map +0 -1
- package/dist/server-Dw_k_7kO.js.map +0 -1
- package/dist/server-En7cbi3v.d.ts.map +0 -1
- package/dist/session-clear-Bo-XTFEy.d.ts.map +0 -1
- package/dist/store-Djdv0bnZ.d.ts.map +0 -1
- package/dist/store-redis-notify-BRITti_o.js.map +0 -1
- package/examples/playground/app/a0/no-photon.cjs +0 -4
package/dist/ai-server.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
|
|
2
2
|
import { a as reducer, s as validateSync } from "./reducer-BAXc8JyF.js";
|
|
3
|
-
import { h as installAmbientToolScopeStorage, m as failedPreviousAttempt, p as consumeSchedulerSendFailure } from "./internal-
|
|
3
|
+
import { h as installAmbientToolScopeStorage, m as failedPreviousAttempt, p as consumeSchedulerSendFailure } from "./internal-CscSY7K_.js";
|
|
4
4
|
import { t as boundedCache } from "./bounded-cache-CPHWF-8h.js";
|
|
5
|
-
import { a as CONSOLE_TELEMETRY, o as setServerFetchHooks, t as createServer } from "./server-
|
|
6
|
-
import {
|
|
7
|
-
import { a as
|
|
5
|
+
import { a as CONSOLE_TELEMETRY, o as setServerFetchHooks, t as createServer } from "./server-D-Y4pqwu.js";
|
|
6
|
+
import { a as unexplainedAdmission, i as steersOn, n as initialControlState, r as steeringEnd, t as STEERED_REASON } from "./ai-control-CvLbW10B.js";
|
|
7
|
+
import { A as interruptUIMessage, C as reduceToolActivity, D as flattenProgressBatches, E as upsertResponse, M as assertMessageBase, N as restoreMessageBase, O as progressBatches, S as projectedMessage, T as upsertMessage, _ as applyControlChanges, a as events, b as findMessage, d as appSlice, f as isAgentContract, g as isUIMessage, h as aiEventId, j as pauseUIMessage, k as progressOwnedBy, m as AI_EVENT_ID_PREFIX, n as agentContract, p as withAIStorage, u as appReducerOf, v as controlCommit, w as retainMessageBase, y as advanceProjection } from "./ai-mMiWul1T.js";
|
|
8
|
+
import { a as harnessDriver, c as harnessStates, d as registerHarnessStates, s as harnessLog } from "./ai-harness-BuuC-gJ3.js";
|
|
8
9
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
10
|
import { createHash } from "node:crypto";
|
|
10
11
|
import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
|
|
@@ -43,12 +44,11 @@ const foldCoordinator = (state, event) => {
|
|
|
43
44
|
}
|
|
44
45
|
case "ai.message.created": {
|
|
45
46
|
const payload = event.payload;
|
|
46
|
-
|
|
47
|
-
if (message.role !== "user") return state;
|
|
47
|
+
if (payload.role !== "user") return state;
|
|
48
48
|
return {
|
|
49
49
|
...state,
|
|
50
|
-
queued: [...state.queued.filter((item) => item.messageId !==
|
|
51
|
-
messageId:
|
|
50
|
+
queued: [...state.queued.filter((item) => item.messageId !== payload.messageId), {
|
|
51
|
+
messageId: payload.messageId,
|
|
52
52
|
generate: payload.generate !== false
|
|
53
53
|
}]
|
|
54
54
|
};
|
|
@@ -244,7 +244,7 @@ const createControlRuntime = (options) => {
|
|
|
244
244
|
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
245
245
|
const reducer$2 = reducer({
|
|
246
246
|
contract: options.contract,
|
|
247
|
-
name: "a2.ai.control.
|
|
247
|
+
name: "a2.ai.control.v6",
|
|
248
248
|
initialState: initialControlState()
|
|
249
249
|
}).fold((state, event) => {
|
|
250
250
|
if (event.type === "ai.control.requested") {
|
|
@@ -309,15 +309,41 @@ const createControlRuntime = (options) => {
|
|
|
309
309
|
});
|
|
310
310
|
state.active = null;
|
|
311
311
|
};
|
|
312
|
-
const
|
|
312
|
+
const decide = async () => {
|
|
313
|
+
const receipt = {
|
|
314
|
+
commandId: ctx.event.id,
|
|
315
|
+
...ctx.event.type === "ai.work.reported" ? { work: true } : {},
|
|
316
|
+
outcome: reason === void 0 ? "applied" : "rejected",
|
|
317
|
+
...reason === void 0 ? {} : { reason }
|
|
318
|
+
};
|
|
319
|
+
return [
|
|
320
|
+
...facts,
|
|
321
|
+
{
|
|
322
|
+
type: "ai.control.committed",
|
|
323
|
+
id: await aiEventId("a2.ai.control.committed", ctx.event.id),
|
|
324
|
+
payload: controlCommit({
|
|
325
|
+
before,
|
|
326
|
+
after: state,
|
|
327
|
+
moves
|
|
328
|
+
})
|
|
329
|
+
},
|
|
330
|
+
...jobs,
|
|
331
|
+
{
|
|
332
|
+
type: "ai.control.decided",
|
|
333
|
+
id: await aiEventId("a2.ai.control.decided", ctx.event.id),
|
|
334
|
+
payload: receipt
|
|
335
|
+
}
|
|
336
|
+
];
|
|
337
|
+
};
|
|
338
|
+
const insert = ({ message, generate = true, afterStepOf }) => {
|
|
313
339
|
const candidate = {
|
|
314
340
|
id: message.id,
|
|
315
|
-
message,
|
|
341
|
+
role: message.role,
|
|
316
342
|
generate: generate && message.role === "user",
|
|
317
343
|
...afterStepOf === void 0 ? {} : { afterStepOf }
|
|
318
344
|
};
|
|
319
|
-
if (
|
|
320
|
-
else state.inbox.items.
|
|
345
|
+
if (afterStepOf === void 0) state.inbox.items.push(candidate);
|
|
346
|
+
else state.inbox.items.splice(steeringEnd(state.inbox.items, afterStepOf), 0, candidate);
|
|
321
347
|
};
|
|
322
348
|
const moveInput = ({ from, to }) => {
|
|
323
349
|
if (from === to) return;
|
|
@@ -380,9 +406,8 @@ const createControlRuntime = (options) => {
|
|
|
380
406
|
case "edit": {
|
|
381
407
|
const item = state.inbox.items.find((candidate) => candidate.id === command.message.id);
|
|
382
408
|
if (item === void 0) reason = "not-pending";
|
|
383
|
-
else if (item.
|
|
384
|
-
|
|
385
|
-
break;
|
|
409
|
+
else if (item.role !== command.message.role) reason = "role-mismatch";
|
|
410
|
+
return decide();
|
|
386
411
|
}
|
|
387
412
|
case "remove": {
|
|
388
413
|
const position = state.inbox.items.findIndex((item) => item.id === command.inputId);
|
|
@@ -408,14 +433,15 @@ const createControlRuntime = (options) => {
|
|
|
408
433
|
const selected = state.inbox.items[position];
|
|
409
434
|
if (!selected) reason = "not-pending";
|
|
410
435
|
else if ((state.active?.turnId ?? null) !== command.turnId) reason = "stale-turn";
|
|
411
|
-
else if (selected.
|
|
436
|
+
else if (selected.role !== "user") reason = "not-user-input";
|
|
412
437
|
else {
|
|
413
438
|
selected.generate = true;
|
|
414
439
|
if (state.active) selected.afterStepOf = state.active.turnId;
|
|
415
440
|
else delete selected.afterStepOf;
|
|
441
|
+
const others = state.inbox.items.filter((item) => item !== selected);
|
|
416
442
|
moveInput({
|
|
417
443
|
from: position,
|
|
418
|
-
to: 0
|
|
444
|
+
to: state.active ? steeringEnd(others, state.active.turnId) : 0
|
|
419
445
|
});
|
|
420
446
|
}
|
|
421
447
|
break;
|
|
@@ -431,7 +457,6 @@ const createControlRuntime = (options) => {
|
|
|
431
457
|
insert({
|
|
432
458
|
message: command.message,
|
|
433
459
|
generate: true,
|
|
434
|
-
first: true,
|
|
435
460
|
afterStepOf: command.turnId
|
|
436
461
|
});
|
|
437
462
|
break;
|
|
@@ -597,12 +622,12 @@ const createControlRuntime = (options) => {
|
|
|
597
622
|
const modelDone = active.model === null || active.model.settled;
|
|
598
623
|
const workSettled = modelDone && response.calls.every((call) => call.work === void 0 || call.work.settled);
|
|
599
624
|
const externalPending = response.calls.some((call) => call.call.providerExecuted && call.call.supportsDeferredResults && !call.terminal && !approvalBlocksExecution(call));
|
|
600
|
-
const handoffReady = handoff && workSettled && !externalPending && (active.suspended
|
|
625
|
+
const handoffReady = handoff && workSettled && !externalPending && (active.suspended ? !state.inbox.paused : response.failure !== void 0 || response.calls.every((call) => callReadyForModel(call) || approvalBlocksExecution(call)));
|
|
601
626
|
const readyForModel = !active.suspended && response.failure === void 0 && modelDone && callsDone && response.inputs.length === 0;
|
|
602
627
|
const naturalCompletion = readyForModel && response.completion !== void 0 && response.completion.finishReason !== "tool-calls";
|
|
603
628
|
if (handoffReady && !naturalCompletion) await end({
|
|
604
629
|
lastSeenIndex: void 0,
|
|
605
|
-
reason:
|
|
630
|
+
reason: STEERED_REASON
|
|
606
631
|
});
|
|
607
632
|
else if (readyForModel && (!handoff || handoffReady)) {
|
|
608
633
|
const resume = active.model !== null && active.model.version !== active.version;
|
|
@@ -632,12 +657,14 @@ const createControlRuntime = (options) => {
|
|
|
632
657
|
}
|
|
633
658
|
if (state.active === null && !state.inbox.paused && !state.coordinator.closed) while (state.inbox.items.length > 0) {
|
|
634
659
|
const item = state.inbox.items.shift();
|
|
660
|
+
if (steersOn(item, state.inbox.items)) item.generate = false;
|
|
635
661
|
delete item.afterStepOf;
|
|
636
662
|
await emit({
|
|
637
663
|
type: "ai.message.created",
|
|
638
664
|
payload: {
|
|
639
|
-
|
|
640
|
-
|
|
665
|
+
messageId: item.id,
|
|
666
|
+
role: item.role,
|
|
667
|
+
...item.generate ? {} : { generate: false }
|
|
641
668
|
},
|
|
642
669
|
id: await aiEventId("a2.ai.admitted", options.contract.name, ctx.event.sessionId, item.id)
|
|
643
670
|
});
|
|
@@ -661,30 +688,7 @@ const createControlRuntime = (options) => {
|
|
|
661
688
|
});
|
|
662
689
|
break;
|
|
663
690
|
}
|
|
664
|
-
|
|
665
|
-
commandId: ctx.event.id,
|
|
666
|
-
...ctx.event.type === "ai.work.reported" ? { work: true } : {},
|
|
667
|
-
outcome: reason === void 0 ? "applied" : "rejected",
|
|
668
|
-
...reason === void 0 ? {} : { reason }
|
|
669
|
-
};
|
|
670
|
-
return [
|
|
671
|
-
...facts,
|
|
672
|
-
{
|
|
673
|
-
type: "ai.control.committed",
|
|
674
|
-
id: await aiEventId("a2.ai.control.committed", ctx.event.id),
|
|
675
|
-
payload: controlCommit({
|
|
676
|
-
before,
|
|
677
|
-
after: state,
|
|
678
|
-
moves
|
|
679
|
-
})
|
|
680
|
-
},
|
|
681
|
-
...jobs,
|
|
682
|
-
{
|
|
683
|
-
type: "ai.control.decided",
|
|
684
|
-
id: await aiEventId("a2.ai.control.decided", ctx.event.id),
|
|
685
|
-
payload: receipt
|
|
686
|
-
}
|
|
687
|
-
];
|
|
691
|
+
return decide();
|
|
688
692
|
};
|
|
689
693
|
const report = async ({ ctx, events, settled, name }) => {
|
|
690
694
|
const payload = ctx.event.payload;
|
|
@@ -784,8 +788,12 @@ const index = (value) => typeof value === "number" && Number.isSafeInteger(value
|
|
|
784
788
|
const id = (value) => typeof value === "string" && value.length > 0;
|
|
785
789
|
const nullableId = (value) => value === null || id(value);
|
|
786
790
|
const matches = (schema, value) => validateSync(schema, value, "AI context checkpoint").issues === void 0;
|
|
787
|
-
const isMessage = (value) => matches(events["ai.message.created"], { message: value });
|
|
788
791
|
const indexes = (value, messages) => record(value) && Object.values(value).every(index) && messages.every((message) => Object.hasOwn(value, message.id));
|
|
792
|
+
const inputs = (value) => record(value) && Object.keys(value).length === 2 && Array.isArray(value["commands"]) && value["commands"].every((held) => record(held) && Object.keys(held).every((key) => [
|
|
793
|
+
"commandId",
|
|
794
|
+
"inputId",
|
|
795
|
+
"message"
|
|
796
|
+
].includes(key)) && id(held["commandId"]) && id(held["inputId"]) && (held["message"] === void 0 || isUIMessage(held["message"]))) && Array.isArray(value["waiting"]) && value["waiting"].every((input) => record(input) && Object.keys(input).length === 2 && id(input["inputId"]) && isUIMessage(input["message"]));
|
|
789
797
|
const compaction = (value) => value === null || record(value) && Object.keys(value).every((key) => [
|
|
790
798
|
"status",
|
|
791
799
|
"generationId",
|
|
@@ -816,7 +824,7 @@ const progress = (value) => {
|
|
|
816
824
|
const indexedEvents = (value, types) => Array.isArray(value) && value.every((event) => record(event) && index(event["index"]) && types.includes(event["type"]) && matches(events[event["type"]], event["payload"]));
|
|
817
825
|
const restorableBase = (options) => {
|
|
818
826
|
assertMessageBase(options.base);
|
|
819
|
-
return
|
|
827
|
+
return isUIMessage(restoreMessageBase({
|
|
820
828
|
current: options.current,
|
|
821
829
|
base: options.base
|
|
822
830
|
}));
|
|
@@ -880,6 +888,7 @@ const contextSchema = (app) => ({ "~standard": {
|
|
|
880
888
|
"compaction",
|
|
881
889
|
"modelMetadata",
|
|
882
890
|
"closed",
|
|
891
|
+
"inputs",
|
|
883
892
|
"authority",
|
|
884
893
|
"generation",
|
|
885
894
|
"activeProjection",
|
|
@@ -892,7 +901,7 @@ const contextSchema = (app) => ({ "~standard": {
|
|
|
892
901
|
const metadata = value["modelMetadata"];
|
|
893
902
|
const generation = value["generation"];
|
|
894
903
|
const current = value["activeProjection"];
|
|
895
|
-
if (!Array.isArray(messages) || !messages.every(
|
|
904
|
+
if (!Array.isArray(messages) || !messages.every(isUIMessage) || !compaction(value["compaction"]) || typeof value["closed"] !== "boolean" || !inputs(value["inputs"]) || !authority(value["authority"]) || !record(metadata) || !Object.entries(metadata).every(([modelId, entry]) => record(entry) && (entry["status"] === "pending" || entry["status"] === "unavailable" || entry["status"] === "resolved" && matches(events["ai.model.metadata.resolved"], {
|
|
896
905
|
modelId,
|
|
897
906
|
limits: entry["limits"]
|
|
898
907
|
}))) || !indexes(value["messageIndexes"], messages)) return invalid;
|
|
@@ -1002,6 +1011,10 @@ const createContextReducer = ({ contract }) => {
|
|
|
1002
1011
|
compaction: null,
|
|
1003
1012
|
modelMetadata: {},
|
|
1004
1013
|
closed: false,
|
|
1014
|
+
inputs: {
|
|
1015
|
+
commands: [],
|
|
1016
|
+
waiting: []
|
|
1017
|
+
},
|
|
1005
1018
|
authority: null,
|
|
1006
1019
|
generation: null,
|
|
1007
1020
|
activeProjection: null,
|
|
@@ -1010,7 +1023,7 @@ const createContextReducer = ({ contract }) => {
|
|
|
1010
1023
|
};
|
|
1011
1024
|
const reducer$1 = reducer({
|
|
1012
1025
|
contract,
|
|
1013
|
-
name: app === void 0 ? "a2.ai.context.
|
|
1026
|
+
name: app === void 0 ? "a2.ai.context.v7" : `${app.name}+a2.ai.context.v7`,
|
|
1014
1027
|
initialState,
|
|
1015
1028
|
stateSchema: contextSchema(app)
|
|
1016
1029
|
}).fold((state, event) => {
|
|
@@ -1046,15 +1059,69 @@ const reduceContext = (state, event) => {
|
|
|
1046
1059
|
};
|
|
1047
1060
|
return view.closed ? endGeneration(next) : next;
|
|
1048
1061
|
}
|
|
1062
|
+
case "ai.control.requested": {
|
|
1063
|
+
const command = event.payload;
|
|
1064
|
+
const held = command.action === "send" || command.action === "steer" || command.action === "edit" ? {
|
|
1065
|
+
commandId: event.id,
|
|
1066
|
+
inputId: command.message.id,
|
|
1067
|
+
message: command.message
|
|
1068
|
+
} : command.action === "remove" ? {
|
|
1069
|
+
commandId: event.id,
|
|
1070
|
+
inputId: command.inputId
|
|
1071
|
+
} : void 0;
|
|
1072
|
+
if (held === void 0) return state;
|
|
1073
|
+
return {
|
|
1074
|
+
...state,
|
|
1075
|
+
inputs: {
|
|
1076
|
+
...state.inputs,
|
|
1077
|
+
commands: [...state.inputs.commands, held]
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
case "ai.control.decided": {
|
|
1082
|
+
const receipt = event.payload;
|
|
1083
|
+
const held = receipt.work ? void 0 : state.inputs.commands.find((command) => command.commandId === receipt.commandId);
|
|
1084
|
+
if (held === void 0) return state;
|
|
1085
|
+
const commands = state.inputs.commands.filter((command) => command !== held);
|
|
1086
|
+
if (receipt.outcome !== "applied") return {
|
|
1087
|
+
...state,
|
|
1088
|
+
inputs: {
|
|
1089
|
+
...state.inputs,
|
|
1090
|
+
commands
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
const waiting = state.inputs.waiting.filter((input) => input.inputId !== held.inputId);
|
|
1094
|
+
if (held.message !== void 0) waiting.push({
|
|
1095
|
+
inputId: held.inputId,
|
|
1096
|
+
message: held.message
|
|
1097
|
+
});
|
|
1098
|
+
return {
|
|
1099
|
+
...state,
|
|
1100
|
+
inputs: {
|
|
1101
|
+
commands,
|
|
1102
|
+
waiting
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1049
1106
|
case "ai.session.closed": return endGeneration({
|
|
1050
1107
|
...state,
|
|
1051
1108
|
closed: true,
|
|
1109
|
+
inputs: {
|
|
1110
|
+
commands: [],
|
|
1111
|
+
waiting: []
|
|
1112
|
+
},
|
|
1052
1113
|
compaction: state.compaction?.status === "running" ? state.activeProjection?.baseCompaction ?? null : state.compaction
|
|
1053
1114
|
});
|
|
1054
1115
|
case "ai.message.created": {
|
|
1055
|
-
const {
|
|
1116
|
+
const { messageId } = event.payload;
|
|
1117
|
+
const message = state.inputs.waiting.find((input) => input.inputId === messageId)?.message ?? state.inputs.commands.find((command) => command.commandId === messageId)?.message;
|
|
1118
|
+
if (message === void 0) throw unexplainedAdmission(messageId);
|
|
1056
1119
|
return {
|
|
1057
1120
|
...state,
|
|
1121
|
+
inputs: {
|
|
1122
|
+
commands: state.inputs.commands.filter((command) => command.commandId !== messageId),
|
|
1123
|
+
waiting: state.inputs.waiting.filter((input) => input.inputId !== messageId)
|
|
1124
|
+
},
|
|
1058
1125
|
messages: upsertMessage(state.messages, message),
|
|
1059
1126
|
activeProjection: state.activeProjection?.responseMessageId === message.id ? {
|
|
1060
1127
|
...state.activeProjection,
|
|
@@ -1711,7 +1778,12 @@ async function* consumeGeneration(options) {
|
|
|
1711
1778
|
chunks: mergeDeltas(pending.splice(0))
|
|
1712
1779
|
});
|
|
1713
1780
|
const reader = options.source.stream.getReader();
|
|
1714
|
-
|
|
1781
|
+
const readAhead = () => {
|
|
1782
|
+
const read = reader.read();
|
|
1783
|
+
read.catch(() => {});
|
|
1784
|
+
return read;
|
|
1785
|
+
};
|
|
1786
|
+
let pendingChunk = readAhead();
|
|
1715
1787
|
try {
|
|
1716
1788
|
for (;;) {
|
|
1717
1789
|
let result;
|
|
@@ -1730,7 +1802,7 @@ async function* consumeGeneration(options) {
|
|
|
1730
1802
|
pending.push(chunk);
|
|
1731
1803
|
if (chunk.type === "finish") streamedFinishReason = chunk.finishReason;
|
|
1732
1804
|
if (chunk.type === "error") streamedError = chunk.errorText;
|
|
1733
|
-
pendingChunk =
|
|
1805
|
+
pendingChunk = readAhead();
|
|
1734
1806
|
if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
|
|
1735
1807
|
yield batch();
|
|
1736
1808
|
lastFlush = Date.now();
|
|
@@ -1740,7 +1812,6 @@ async function* consumeGeneration(options) {
|
|
|
1740
1812
|
if (pending.length > 0) yield batch();
|
|
1741
1813
|
throw error;
|
|
1742
1814
|
} finally {
|
|
1743
|
-
pendingChunk.catch(() => {});
|
|
1744
1815
|
try {
|
|
1745
1816
|
await reader.cancel();
|
|
1746
1817
|
} catch {} finally {
|
|
@@ -2058,6 +2129,7 @@ function createHandlers(options) {
|
|
|
2058
2129
|
if (harness !== void 0) for (const [name, tool] of Object.entries(options.tools ?? {})) {
|
|
2059
2130
|
const needsApproval = tool.needsApproval;
|
|
2060
2131
|
if (needsApproval !== void 0 && needsApproval !== false) throw new TypeError(`a harness runs tools without approval; '${name}' sets needsApproval`);
|
|
2132
|
+
if (tool.type === "provider") throw new TypeError(`a harness runs only tools A2 executes; '${name}' is provider-defined`);
|
|
2061
2133
|
}
|
|
2062
2134
|
const configuredCompaction = loop.compaction ?? (loop.generate === void 0 && harness === void 0 ? {} : false);
|
|
2063
2135
|
const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
|