experimental-a2 0.18.1 → 0.20.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 +44 -0
- package/dist/actor.js +1 -1
- package/dist/{ai-BMLlI2Ff.d.ts → ai-Cz3hqVhk.d.ts} +33 -16
- package/dist/ai-Cz3hqVhk.d.ts.map +1 -0
- package/dist/ai-client.d.ts +1 -1
- package/dist/ai-client.js +1 -1
- 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 +63 -13
- package/dist/ai-fx.js.map +1 -1
- package/dist/{ai-harness-B2suP2Qh.d.ts → ai-harness-CV6rXbB3.d.ts} +2 -2
- package/dist/ai-harness-CV6rXbB3.d.ts.map +1 -0
- package/dist/{ai-harness-BuLh_EYi.js → ai-harness-Clbg5ei7.js} +88 -15
- package/dist/ai-harness-Clbg5ei7.js.map +1 -0
- package/dist/{ai-D6mGlO8j.js → ai-mMiWul1T.js} +116 -77
- 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 +56 -11
- package/dist/ai-pi.js.map +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +1 -1
- package/dist/ai-server.d.ts +2 -2
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +123 -53
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +1 -1
- package/dist/internal-CscSY7K_.js.map +1 -1
- package/dist/scheduler-qstash.d.ts.map +1 -1
- package/dist/scheduler-qstash.js +5 -5
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +5 -7
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/server-DYAATFuT.d.ts.map +1 -1
- package/dist/{server-D-Y4pqwu.js → server-qyb5aJJG.js} +39 -25
- package/dist/server-qyb5aJJG.js.map +1 -0
- package/dist/server.js +1 -1
- package/dist/session-clear-DGI4jTQ5.js.map +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +38 -136
- package/dist/store-postgres.js.map +1 -1
- package/docs/01-quickstart.mdx +7 -4
- package/docs/actors/01-introduction.mdx +1 -1
- package/docs/actors/meta.ts +1 -1
- package/docs/agents/02-tools.mdx +1 -1
- package/docs/agents/03-conversations.mdx +26 -14
- package/docs/agents/04-harnesses.mdx +51 -5
- package/docs/agents/meta.ts +1 -1
- package/docs/client/meta.ts +1 -1
- package/docs/contract/03-sessions.mdx +2 -2
- package/docs/index.mdx +2 -2
- package/docs/reference/01-core.mdx +8 -8
- package/docs/reference/02-server.mdx +3 -3
- package/docs/reference/04-ai.mdx +36 -19
- package/docs/reference/05-telemetry.mdx +132 -0
- package/docs/reference/06-errors.mdx +1 -1
- package/docs/reference/meta.ts +1 -1
- package/docs/schedulers/01-overview.mdx +112 -0
- package/docs/schedulers/02-vercel-queues.mdx +87 -0
- package/docs/schedulers/03-qstash.mdx +123 -0
- package/docs/schedulers/meta.ts +1 -0
- package/docs/server/01-handlers.mdx +29 -2
- package/docs/server/02-timers.mdx +3 -3
- package/docs/server/06-guarantees.mdx +6 -3
- package/docs/stores/01-overview.mdx +37 -0
- package/docs/stores/02-redis.mdx +49 -0
- package/docs/stores/03-redis-http.mdx +56 -0
- package/docs/stores/04-postgres.mdx +121 -0
- package/docs/stores/05-sqlite.mdx +34 -0
- package/docs/stores/06-memory.mdx +22 -0
- package/docs/stores/meta.ts +1 -0
- package/examples/playground/DEPLOY.md +19 -5
- package/examples/playground/app/a0/a0.css +244 -5
- package/examples/playground/app/a0/app-view.tsx +2 -1
- package/examples/playground/app/a0/apps/[appId]/route.ts +6 -10
- package/examples/playground/app/a0/attachments.ts +133 -0
- package/examples/playground/app/a0/chat.test.tsx +595 -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/model.test.ts +28 -0
- package/examples/playground/app/a0/model.ts +30 -0
- package/examples/playground/app/a0/server.ts +5 -0
- package/examples/playground/app/a0/shell.tsx +1 -1
- package/examples/playground/app/a0/uploads/route.test.ts +59 -0
- 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 +116 -89
- package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +107 -76
- package/examples/playground/app/agent/ingress.test.ts +41 -17
- package/examples/playground/app/agent/model-input.test.tsx +92 -43
- 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/app/chat/[chatId]/agent-stream-drawer.test.tsx +2 -2
- package/examples/playground/app/chat/server.test.ts +38 -65
- package/examples/playground/app/components/activity-history.test.tsx +60 -18
- package/examples/playground/app/components/fast-link.test.tsx +3 -5
- package/examples/playground/app/initial-state.test.tsx +86 -45
- package/examples/playground/next.config.ts +7 -4
- package/examples/playground/package.json +4 -1
- package/examples/playground/test/agent.ts +35 -0
- package/examples/playground/test/model.ts +149 -0
- package/examples/playground/test/serve.ts +184 -0
- package/examples/playground/test/server-only.ts +1 -0
- package/examples/playground/vitest.config.ts +27 -0
- package/package.json +3 -1
- package/sql/postgres/notifications.sql +24 -0
- package/sql/postgres/schema.sql +137 -0
- package/src/ai-agent.ts +9 -4
- 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 +95 -23
- package/src/ai-harness.ts +171 -29
- package/src/ai-message-shape.ts +41 -0
- package/src/ai-pi.ts +88 -32
- package/src/ai-stored-state.ts +1 -3
- package/src/ai.ts +116 -77
- package/src/errors.ts +1 -1
- package/src/internal.ts +2 -1
- package/src/libfx.d.ts +8 -1
- package/src/postgres-notifications.ts +0 -22
- package/src/postgres-resources.ts +6 -9
- package/src/postgres-schema.ts +80 -0
- package/src/scheduler-qstash.ts +12 -5
- package/src/scheduler-vercel.ts +11 -16
- package/src/server.ts +66 -32
- package/src/store-postgres.ts +5 -123
- package/dist/ai-BMLlI2Ff.d.ts.map +0 -1
- package/dist/ai-D6mGlO8j.js.map +0 -1
- package/dist/ai-harness-B2suP2Qh.d.ts.map +0 -1
- package/dist/ai-harness-BuLh_EYi.js.map +0 -1
- package/dist/server-D-Y4pqwu.js.map +0 -1
- package/docs/reference/05-adapters.mdx +0 -351
- package/docs/server/05-production.mdx +0 -323
- package/examples/playground/app/a0/no-photon.cjs +0 -4
package/dist/ai-server.js
CHANGED
|
@@ -2,11 +2,11 @@ import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
|
|
|
2
2
|
import { a as reducer, s as validateSync } from "./reducer-BAXc8JyF.js";
|
|
3
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-qyb5aJJG.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 gatewaySessionAffinity, c as harnessLog, f as registerHarnessStates, l as harnessStates, o as harnessDriver } from "./ai-harness-Clbg5ei7.js";
|
|
8
9
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
10
|
import { asSchema, convertToModelMessages, isToolUIPart, stepCountIs, streamText, toUIMessageStream } from "ai";
|
|
11
11
|
import { Buffer } from "node:buffer";
|
|
12
12
|
//#region src/ai-coordinator.ts
|
|
@@ -43,12 +43,11 @@ const foldCoordinator = (state, event) => {
|
|
|
43
43
|
}
|
|
44
44
|
case "ai.message.created": {
|
|
45
45
|
const payload = event.payload;
|
|
46
|
-
|
|
47
|
-
if (message.role !== "user") return state;
|
|
46
|
+
if (payload.role !== "user") return state;
|
|
48
47
|
return {
|
|
49
48
|
...state,
|
|
50
|
-
queued: [...state.queued.filter((item) => item.messageId !==
|
|
51
|
-
messageId:
|
|
49
|
+
queued: [...state.queued.filter((item) => item.messageId !== payload.messageId), {
|
|
50
|
+
messageId: payload.messageId,
|
|
52
51
|
generate: payload.generate !== false
|
|
53
52
|
}]
|
|
54
53
|
};
|
|
@@ -244,7 +243,7 @@ const createControlRuntime = (options) => {
|
|
|
244
243
|
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY;
|
|
245
244
|
const reducer$2 = reducer({
|
|
246
245
|
contract: options.contract,
|
|
247
|
-
name: "a2.ai.control.
|
|
246
|
+
name: "a2.ai.control.v6",
|
|
248
247
|
initialState: initialControlState()
|
|
249
248
|
}).fold((state, event) => {
|
|
250
249
|
if (event.type === "ai.control.requested") {
|
|
@@ -309,15 +308,41 @@ const createControlRuntime = (options) => {
|
|
|
309
308
|
});
|
|
310
309
|
state.active = null;
|
|
311
310
|
};
|
|
312
|
-
const
|
|
311
|
+
const decide = async () => {
|
|
312
|
+
const receipt = {
|
|
313
|
+
commandId: ctx.event.id,
|
|
314
|
+
...ctx.event.type === "ai.work.reported" ? { work: true } : {},
|
|
315
|
+
outcome: reason === void 0 ? "applied" : "rejected",
|
|
316
|
+
...reason === void 0 ? {} : { reason }
|
|
317
|
+
};
|
|
318
|
+
return [
|
|
319
|
+
...facts,
|
|
320
|
+
{
|
|
321
|
+
type: "ai.control.committed",
|
|
322
|
+
id: await aiEventId("a2.ai.control.committed", ctx.event.id),
|
|
323
|
+
payload: controlCommit({
|
|
324
|
+
before,
|
|
325
|
+
after: state,
|
|
326
|
+
moves
|
|
327
|
+
})
|
|
328
|
+
},
|
|
329
|
+
...jobs,
|
|
330
|
+
{
|
|
331
|
+
type: "ai.control.decided",
|
|
332
|
+
id: await aiEventId("a2.ai.control.decided", ctx.event.id),
|
|
333
|
+
payload: receipt
|
|
334
|
+
}
|
|
335
|
+
];
|
|
336
|
+
};
|
|
337
|
+
const insert = ({ message, generate = true, afterStepOf }) => {
|
|
313
338
|
const candidate = {
|
|
314
339
|
id: message.id,
|
|
315
|
-
message,
|
|
340
|
+
role: message.role,
|
|
316
341
|
generate: generate && message.role === "user",
|
|
317
342
|
...afterStepOf === void 0 ? {} : { afterStepOf }
|
|
318
343
|
};
|
|
319
|
-
if (
|
|
320
|
-
else state.inbox.items.
|
|
344
|
+
if (afterStepOf === void 0) state.inbox.items.push(candidate);
|
|
345
|
+
else state.inbox.items.splice(steeringEnd(state.inbox.items, afterStepOf), 0, candidate);
|
|
321
346
|
};
|
|
322
347
|
const moveInput = ({ from, to }) => {
|
|
323
348
|
if (from === to) return;
|
|
@@ -380,9 +405,8 @@ const createControlRuntime = (options) => {
|
|
|
380
405
|
case "edit": {
|
|
381
406
|
const item = state.inbox.items.find((candidate) => candidate.id === command.message.id);
|
|
382
407
|
if (item === void 0) reason = "not-pending";
|
|
383
|
-
else if (item.
|
|
384
|
-
|
|
385
|
-
break;
|
|
408
|
+
else if (item.role !== command.message.role) reason = "role-mismatch";
|
|
409
|
+
return decide();
|
|
386
410
|
}
|
|
387
411
|
case "remove": {
|
|
388
412
|
const position = state.inbox.items.findIndex((item) => item.id === command.inputId);
|
|
@@ -408,14 +432,15 @@ const createControlRuntime = (options) => {
|
|
|
408
432
|
const selected = state.inbox.items[position];
|
|
409
433
|
if (!selected) reason = "not-pending";
|
|
410
434
|
else if ((state.active?.turnId ?? null) !== command.turnId) reason = "stale-turn";
|
|
411
|
-
else if (selected.
|
|
435
|
+
else if (selected.role !== "user") reason = "not-user-input";
|
|
412
436
|
else {
|
|
413
437
|
selected.generate = true;
|
|
414
438
|
if (state.active) selected.afterStepOf = state.active.turnId;
|
|
415
439
|
else delete selected.afterStepOf;
|
|
440
|
+
const others = state.inbox.items.filter((item) => item !== selected);
|
|
416
441
|
moveInput({
|
|
417
442
|
from: position,
|
|
418
|
-
to: 0
|
|
443
|
+
to: state.active ? steeringEnd(others, state.active.turnId) : 0
|
|
419
444
|
});
|
|
420
445
|
}
|
|
421
446
|
break;
|
|
@@ -431,7 +456,6 @@ const createControlRuntime = (options) => {
|
|
|
431
456
|
insert({
|
|
432
457
|
message: command.message,
|
|
433
458
|
generate: true,
|
|
434
|
-
first: true,
|
|
435
459
|
afterStepOf: command.turnId
|
|
436
460
|
});
|
|
437
461
|
break;
|
|
@@ -597,12 +621,12 @@ const createControlRuntime = (options) => {
|
|
|
597
621
|
const modelDone = active.model === null || active.model.settled;
|
|
598
622
|
const workSettled = modelDone && response.calls.every((call) => call.work === void 0 || call.work.settled);
|
|
599
623
|
const externalPending = response.calls.some((call) => call.call.providerExecuted && call.call.supportsDeferredResults && !call.terminal && !approvalBlocksExecution(call));
|
|
600
|
-
const handoffReady = handoff && workSettled && !externalPending && (active.suspended
|
|
624
|
+
const handoffReady = handoff && workSettled && !externalPending && (active.suspended ? !state.inbox.paused : response.failure !== void 0 || response.calls.every((call) => callReadyForModel(call) || approvalBlocksExecution(call)));
|
|
601
625
|
const readyForModel = !active.suspended && response.failure === void 0 && modelDone && callsDone && response.inputs.length === 0;
|
|
602
626
|
const naturalCompletion = readyForModel && response.completion !== void 0 && response.completion.finishReason !== "tool-calls";
|
|
603
627
|
if (handoffReady && !naturalCompletion) await end({
|
|
604
628
|
lastSeenIndex: void 0,
|
|
605
|
-
reason:
|
|
629
|
+
reason: STEERED_REASON
|
|
606
630
|
});
|
|
607
631
|
else if (readyForModel && (!handoff || handoffReady)) {
|
|
608
632
|
const resume = active.model !== null && active.model.version !== active.version;
|
|
@@ -632,12 +656,14 @@ const createControlRuntime = (options) => {
|
|
|
632
656
|
}
|
|
633
657
|
if (state.active === null && !state.inbox.paused && !state.coordinator.closed) while (state.inbox.items.length > 0) {
|
|
634
658
|
const item = state.inbox.items.shift();
|
|
659
|
+
if (steersOn(item, state.inbox.items)) item.generate = false;
|
|
635
660
|
delete item.afterStepOf;
|
|
636
661
|
await emit({
|
|
637
662
|
type: "ai.message.created",
|
|
638
663
|
payload: {
|
|
639
|
-
|
|
640
|
-
|
|
664
|
+
messageId: item.id,
|
|
665
|
+
role: item.role,
|
|
666
|
+
...item.generate ? {} : { generate: false }
|
|
641
667
|
},
|
|
642
668
|
id: await aiEventId("a2.ai.admitted", options.contract.name, ctx.event.sessionId, item.id)
|
|
643
669
|
});
|
|
@@ -661,30 +687,7 @@ const createControlRuntime = (options) => {
|
|
|
661
687
|
});
|
|
662
688
|
break;
|
|
663
689
|
}
|
|
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
|
-
];
|
|
690
|
+
return decide();
|
|
688
691
|
};
|
|
689
692
|
const report = async ({ ctx, events, settled, name }) => {
|
|
690
693
|
const payload = ctx.event.payload;
|
|
@@ -784,8 +787,12 @@ const index = (value) => typeof value === "number" && Number.isSafeInteger(value
|
|
|
784
787
|
const id = (value) => typeof value === "string" && value.length > 0;
|
|
785
788
|
const nullableId = (value) => value === null || id(value);
|
|
786
789
|
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
790
|
const indexes = (value, messages) => record(value) && Object.values(value).every(index) && messages.every((message) => Object.hasOwn(value, message.id));
|
|
791
|
+
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) => [
|
|
792
|
+
"commandId",
|
|
793
|
+
"inputId",
|
|
794
|
+
"message"
|
|
795
|
+
].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
796
|
const compaction = (value) => value === null || record(value) && Object.keys(value).every((key) => [
|
|
790
797
|
"status",
|
|
791
798
|
"generationId",
|
|
@@ -816,7 +823,7 @@ const progress = (value) => {
|
|
|
816
823
|
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
824
|
const restorableBase = (options) => {
|
|
818
825
|
assertMessageBase(options.base);
|
|
819
|
-
return
|
|
826
|
+
return isUIMessage(restoreMessageBase({
|
|
820
827
|
current: options.current,
|
|
821
828
|
base: options.base
|
|
822
829
|
}));
|
|
@@ -880,6 +887,7 @@ const contextSchema = (app) => ({ "~standard": {
|
|
|
880
887
|
"compaction",
|
|
881
888
|
"modelMetadata",
|
|
882
889
|
"closed",
|
|
890
|
+
"inputs",
|
|
883
891
|
"authority",
|
|
884
892
|
"generation",
|
|
885
893
|
"activeProjection",
|
|
@@ -892,7 +900,7 @@ const contextSchema = (app) => ({ "~standard": {
|
|
|
892
900
|
const metadata = value["modelMetadata"];
|
|
893
901
|
const generation = value["generation"];
|
|
894
902
|
const current = value["activeProjection"];
|
|
895
|
-
if (!Array.isArray(messages) || !messages.every(
|
|
903
|
+
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
904
|
modelId,
|
|
897
905
|
limits: entry["limits"]
|
|
898
906
|
}))) || !indexes(value["messageIndexes"], messages)) return invalid;
|
|
@@ -1002,6 +1010,10 @@ const createContextReducer = ({ contract }) => {
|
|
|
1002
1010
|
compaction: null,
|
|
1003
1011
|
modelMetadata: {},
|
|
1004
1012
|
closed: false,
|
|
1013
|
+
inputs: {
|
|
1014
|
+
commands: [],
|
|
1015
|
+
waiting: []
|
|
1016
|
+
},
|
|
1005
1017
|
authority: null,
|
|
1006
1018
|
generation: null,
|
|
1007
1019
|
activeProjection: null,
|
|
@@ -1010,7 +1022,7 @@ const createContextReducer = ({ contract }) => {
|
|
|
1010
1022
|
};
|
|
1011
1023
|
const reducer$1 = reducer({
|
|
1012
1024
|
contract,
|
|
1013
|
-
name: app === void 0 ? "a2.ai.context.
|
|
1025
|
+
name: app === void 0 ? "a2.ai.context.v7" : `${app.name}+a2.ai.context.v7`,
|
|
1014
1026
|
initialState,
|
|
1015
1027
|
stateSchema: contextSchema(app)
|
|
1016
1028
|
}).fold((state, event) => {
|
|
@@ -1046,15 +1058,69 @@ const reduceContext = (state, event) => {
|
|
|
1046
1058
|
};
|
|
1047
1059
|
return view.closed ? endGeneration(next) : next;
|
|
1048
1060
|
}
|
|
1061
|
+
case "ai.control.requested": {
|
|
1062
|
+
const command = event.payload;
|
|
1063
|
+
const held = command.action === "send" || command.action === "steer" || command.action === "edit" ? {
|
|
1064
|
+
commandId: event.id,
|
|
1065
|
+
inputId: command.message.id,
|
|
1066
|
+
message: command.message
|
|
1067
|
+
} : command.action === "remove" ? {
|
|
1068
|
+
commandId: event.id,
|
|
1069
|
+
inputId: command.inputId
|
|
1070
|
+
} : void 0;
|
|
1071
|
+
if (held === void 0) return state;
|
|
1072
|
+
return {
|
|
1073
|
+
...state,
|
|
1074
|
+
inputs: {
|
|
1075
|
+
...state.inputs,
|
|
1076
|
+
commands: [...state.inputs.commands, held]
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
case "ai.control.decided": {
|
|
1081
|
+
const receipt = event.payload;
|
|
1082
|
+
const held = receipt.work ? void 0 : state.inputs.commands.find((command) => command.commandId === receipt.commandId);
|
|
1083
|
+
if (held === void 0) return state;
|
|
1084
|
+
const commands = state.inputs.commands.filter((command) => command !== held);
|
|
1085
|
+
if (receipt.outcome !== "applied") return {
|
|
1086
|
+
...state,
|
|
1087
|
+
inputs: {
|
|
1088
|
+
...state.inputs,
|
|
1089
|
+
commands
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
const waiting = state.inputs.waiting.filter((input) => input.inputId !== held.inputId);
|
|
1093
|
+
if (held.message !== void 0) waiting.push({
|
|
1094
|
+
inputId: held.inputId,
|
|
1095
|
+
message: held.message
|
|
1096
|
+
});
|
|
1097
|
+
return {
|
|
1098
|
+
...state,
|
|
1099
|
+
inputs: {
|
|
1100
|
+
commands,
|
|
1101
|
+
waiting
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1049
1105
|
case "ai.session.closed": return endGeneration({
|
|
1050
1106
|
...state,
|
|
1051
1107
|
closed: true,
|
|
1108
|
+
inputs: {
|
|
1109
|
+
commands: [],
|
|
1110
|
+
waiting: []
|
|
1111
|
+
},
|
|
1052
1112
|
compaction: state.compaction?.status === "running" ? state.activeProjection?.baseCompaction ?? null : state.compaction
|
|
1053
1113
|
});
|
|
1054
1114
|
case "ai.message.created": {
|
|
1055
|
-
const {
|
|
1115
|
+
const { messageId } = event.payload;
|
|
1116
|
+
const message = state.inputs.waiting.find((input) => input.inputId === messageId)?.message ?? state.inputs.commands.find((command) => command.commandId === messageId)?.message;
|
|
1117
|
+
if (message === void 0) throw unexplainedAdmission(messageId);
|
|
1056
1118
|
return {
|
|
1057
1119
|
...state,
|
|
1120
|
+
inputs: {
|
|
1121
|
+
commands: state.inputs.commands.filter((command) => command.commandId !== messageId),
|
|
1122
|
+
waiting: state.inputs.waiting.filter((input) => input.inputId !== messageId)
|
|
1123
|
+
},
|
|
1058
1124
|
messages: upsertMessage(state.messages, message),
|
|
1059
1125
|
activeProjection: state.activeProjection?.responseMessageId === message.id ? {
|
|
1060
1126
|
...state.activeProjection,
|
|
@@ -1669,7 +1735,10 @@ async function generateWithAISDK(options) {
|
|
|
1669
1735
|
...context.generation,
|
|
1670
1736
|
headers: Object.keys(headers).some((key) => key.toLowerCase() === "x-session-affinity") ? headers : {
|
|
1671
1737
|
...headers,
|
|
1672
|
-
"x-session-affinity":
|
|
1738
|
+
"x-session-affinity": gatewaySessionAffinity({
|
|
1739
|
+
agentName,
|
|
1740
|
+
sessionId: context.event.sessionId
|
|
1741
|
+
})
|
|
1673
1742
|
},
|
|
1674
1743
|
providerOptions: {
|
|
1675
1744
|
...context.generation.providerOptions,
|
|
@@ -2062,6 +2131,7 @@ function createHandlers(options) {
|
|
|
2062
2131
|
if (harness !== void 0) for (const [name, tool] of Object.entries(options.tools ?? {})) {
|
|
2063
2132
|
const needsApproval = tool.needsApproval;
|
|
2064
2133
|
if (needsApproval !== void 0 && needsApproval !== false) throw new TypeError(`a harness runs tools without approval; '${name}' sets needsApproval`);
|
|
2134
|
+
if (tool.type === "provider") throw new TypeError(`a harness runs only tools A2 executes; '${name}' is provider-defined`);
|
|
2065
2135
|
}
|
|
2066
2136
|
const configuredCompaction = loop.compaction ?? (loop.generate === void 0 && harness === void 0 ? {} : false);
|
|
2067
2137
|
const staticCompaction = typeof configuredCompaction === "function" ? void 0 : validateCompaction({
|