@yielded/agent 0.1.0-beta.174 → 0.1.0-beta.175
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/{Admin-BHmp2V9p.d.mts → Admin-Qa3I1oA5.d.mts} +38 -7
- package/dist/{AgentRuntime-BD3ZHAMq.d.mts → AgentRuntime-CHDyRbSf.d.mts} +3 -3
- package/dist/{AgentRuntime-B6qZlD3f.mjs → AgentRuntime-DaDKMasp.mjs} +123 -114
- package/dist/AgentRuntime-DaDKMasp.mjs.map +1 -0
- package/dist/{Digest-EpeqWEdv.mjs → Digest-C3EODOee.mjs} +2 -2
- package/dist/{Digest-EpeqWEdv.mjs.map → Digest-C3EODOee.mjs.map} +1 -1
- package/dist/{DurableAgentRuntime-CBBjRNJN.mjs → DurableAgentRuntime-CPlw5_7e.mjs} +161 -85
- package/dist/DurableAgentRuntime-CPlw5_7e.mjs.map +1 -0
- package/dist/{EventSource-C9aaJaXT.d.mts → EventSource-BTu68yDW.d.mts} +2 -2
- package/dist/InMemory.d.mts +2 -2
- package/dist/{MessageDelivery-BGDm-c46.d.mts → MessageDelivery-DjAZJ4Fd.d.mts} +4 -4
- package/dist/{MessagingHost-CRUK4JBi.mjs → MessagingHost-CZCyrnvJ.mjs} +27 -26
- package/dist/MessagingHost-CZCyrnvJ.mjs.map +1 -0
- package/dist/{PreparedInputAdmission-BvDqlgiP.d.mts → PreparedInputAdmission-wgY4JMZY.d.mts} +3 -3
- package/dist/{Records-BiuJDWNe.mjs → Records-DzL4Kbtw.mjs} +2 -2
- package/dist/{Records-BiuJDWNe.mjs.map → Records-DzL4Kbtw.mjs.map} +1 -1
- package/dist/{RunContinuation-CTJ1jGrO.d.mts → RunContinuation-3jB5pULC.d.mts} +10 -4
- package/dist/{RunContinuation-4ZATcVLB.mjs → RunContinuation-BiyKJK32.mjs} +74 -40
- package/dist/RunContinuation-BiyKJK32.mjs.map +1 -0
- package/dist/{RunJournal-CNZqA3Ge.mjs → RunJournal-CPMKcfd0.mjs} +84 -79
- package/dist/RunJournal-CPMKcfd0.mjs.map +1 -0
- package/dist/{RunStorage-BHjuuERI.mjs → RunStorage-CzutHJBE.mjs} +3 -2
- package/dist/RunStorage-CzutHJBE.mjs.map +1 -0
- package/dist/{Scheduling-NG8slKdI.mjs → Scheduling-07_dsGED.mjs} +3 -3
- package/dist/{Scheduling-NG8slKdI.mjs.map → Scheduling-07_dsGED.mjs.map} +1 -1
- package/dist/{Subagent-CTIpnzlB.mjs → Subagent-CexndZSp.mjs} +2 -2
- package/dist/{Subagent-CTIpnzlB.mjs.map → Subagent-CexndZSp.mjs.map} +1 -1
- package/dist/{Subagent-DKhZA72u.d.mts → Subagent-xhN_aD1r.d.mts} +3 -3
- package/dist/{Subscription-BNg9VCRl.d.mts → Subscription-DmIHlOJK.d.mts} +2 -2
- package/dist/{SubscriptionInput-BUoXv-_K.d.mts → SubscriptionInput-DgcQhvbe.d.mts} +2 -2
- package/dist/{Thread-dk-QiNml.d.mts → Thread-DzdJAY4J.d.mts} +4 -3
- package/dist/{ThreadHistory-ByxS8HU1.d.mts → ThreadHistory-KPPBJLJb.d.mts} +12 -2
- package/dist/{ThreadImport-CodYoJoa.mjs → ThreadImport-CjlG57vH.mjs} +8 -8
- package/dist/{ThreadImport-CodYoJoa.mjs.map → ThreadImport-CjlG57vH.mjs.map} +1 -1
- package/dist/{ThreadImport-CMgzttvr.d.mts → ThreadImport-DP-vOk2F.d.mts} +4 -4
- package/dist/{ThreadStore-59uDGXul.mjs → ThreadStore-EuUilthA.mjs} +5 -7
- package/dist/ThreadStore-EuUilthA.mjs.map +1 -0
- package/dist/{ThreadTransfer-3jigUl3g.mjs → ThreadTransfer-DB_zsrtJ.mjs} +4 -4
- package/dist/{ThreadTransfer-3jigUl3g.mjs.map → ThreadTransfer-DB_zsrtJ.mjs.map} +1 -1
- package/dist/{WorkerAdmission-DDYJdOsU.mjs → WorkerAdmission-eBeXt_mu.mjs} +5 -5
- package/dist/{WorkerAdmission-DDYJdOsU.mjs.map → WorkerAdmission-eBeXt_mu.mjs.map} +1 -1
- package/dist/{agent-registration-DRbyhAu-.mjs → agent-registration-a6QYaG3h.mjs} +4 -4
- package/dist/{agent-registration-DRbyhAu-.mjs.map → agent-registration-a6QYaG3h.mjs.map} +1 -1
- package/dist/capabilities/Messaging.mjs +1 -1
- package/dist/capabilities/ModelContext.d.mts +1 -1
- package/dist/capabilities/RunHooks.d.mts +1 -1
- package/dist/capabilities/Subagent.d.mts +1 -1
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/core/Thread.d.mts +2 -2
- package/dist/core/Thread.mjs +5 -3
- package/dist/core/Thread.mjs.map +1 -1
- package/dist/durable/ActivityStore.mjs +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/Admin.mjs +1 -1
- package/dist/durable/AgentRegistration.d.mts +1 -1
- package/dist/durable/AgentRegistration.mjs +1 -1
- package/dist/durable/Certification.d.mts +1 -1
- package/dist/durable/CommittedActivity.d.mts +1 -1
- package/dist/durable/CommittedActivity.mjs +3 -3
- package/dist/durable/Digest.mjs +1 -1
- package/dist/durable/DurableAgentRuntime.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.mjs +2 -2
- package/dist/durable/EventSource.d.mts +1 -1
- package/dist/durable/EventSource.mjs +1 -1
- package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
- package/dist/durable/LifecyclePublication.d.mts +1 -1
- package/dist/durable/LifecyclePublication.mjs +2 -2
- package/dist/durable/MessageDelivery.d.mts +1 -1
- package/dist/durable/MessageDelivery.mjs +2 -2
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +40 -40
- package/dist/durable/MessageDeliveryStoreConformance.mjs +2 -2
- package/dist/durable/PersistentHistory.d.mts +2 -2
- package/dist/durable/PersistentHistory.mjs +4 -4
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/RecordFormat.mjs +1 -1
- package/dist/durable/Records.mjs +1 -1
- package/dist/durable/Recovery.d.mts +1 -1
- package/dist/durable/Recovery.mjs +1 -1
- package/dist/durable/RunContinuation.d.mts +2 -2
- package/dist/durable/RunContinuation.mjs +3 -3
- package/dist/durable/RunJournal.d.mts +2 -2
- package/dist/durable/RunJournal.mjs +2 -2
- package/dist/durable/RunStorage.d.mts +1 -1
- package/dist/durable/RunStorage.mjs +1 -1
- package/dist/durable/Schedule.mjs +1 -1
- package/dist/durable/ScheduleStoreConformance.mjs +1 -1
- package/dist/durable/ScheduleTransition.mjs +1 -1
- package/dist/durable/Scheduling.d.mts +1 -1
- package/dist/durable/Scheduling.mjs +1 -1
- package/dist/durable/SettlementPublisher.d.mts +1 -1
- package/dist/durable/SettlementPublisher.mjs +3 -3
- package/dist/durable/SqlMemoryStore.mjs +5 -3
- package/dist/durable/SqlMemoryStore.mjs.map +1 -1
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedger.mjs +7 -3
- package/dist/durable/SubmissionLedger.mjs.map +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.mjs +6 -6
- package/dist/durable/SubmissionStatus.d.mts +1 -1
- package/dist/durable/Subscription.d.mts +1 -1
- package/dist/durable/Subscription.mjs +2 -2
- package/dist/durable/SubscriptionInput.d.mts +1 -1
- package/dist/durable/SubscriptionInput.mjs +2 -2
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
- package/dist/durable/SubscriptionTools.d.mts +2 -2
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/SubscriptionTransition.mjs +1 -1
- package/dist/durable/Subscriptions.d.mts +5 -5
- package/dist/durable/Subscriptions.mjs +2 -2
- package/dist/durable/ThreadArchiveRange.d.mts +1 -1
- package/dist/durable/ThreadArchiveRange.mjs +1 -1
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistory.mjs +2 -2
- package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
- package/dist/durable/ThreadImport.d.mts +1 -1
- package/dist/durable/ThreadImport.mjs +1 -1
- package/dist/durable/ThreadInvariants.d.mts +3 -3
- package/dist/durable/ThreadInvariants.mjs +4 -4
- package/dist/durable/ThreadProjection.mjs +1 -1
- package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
- package/dist/durable/ThreadReader.d.mts +1 -1
- package/dist/durable/ThreadReader.mjs +1 -1
- package/dist/durable/ThreadStore.d.mts +1 -1
- package/dist/durable/ThreadStore.mjs +2 -2
- package/dist/durable/ThreadStoreConformance.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.mjs +4 -4
- package/dist/durable/ThreadTransfer.d.mts +1 -1
- package/dist/durable/ThreadTransfer.mjs +1 -1
- package/dist/durable/ThreadWork.d.mts +2 -2
- package/dist/durable/ThreadWork.mjs +12 -6
- package/dist/durable/ThreadWork.mjs.map +1 -1
- package/dist/durable/ToolReconciler.mjs +1 -1
- package/dist/durable/WakeScheduler.mjs +23 -39
- package/dist/durable/WakeScheduler.mjs.map +1 -1
- package/dist/durable/WorkerAdmission.d.mts +1 -1
- package/dist/durable/WorkerAdmission.mjs +1 -1
- package/dist/durable/WorkerHost.d.mts +1 -1
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/MessagingHost.mjs +1 -1
- package/dist/engine/Output.mjs +1 -1
- package/dist/engine/ThreadHistory.d.mts +1 -1
- package/dist/engine/ThreadHistory.mjs +3 -2
- package/dist/engine/ThreadHistory.mjs.map +1 -1
- package/dist/index.d.mts +12 -12
- package/dist/index.mjs +13 -13
- package/dist/{output-contract-CMIhu4Cw.mjs → output-contract-DCnLYCdp.mjs} +12 -15
- package/dist/{output-contract-CMIhu4Cw.mjs.map → output-contract-DCnLYCdp.mjs.map} +1 -1
- package/dist/{run-context-reader-CC7ZD95F.d.mts → run-context-reader-DVhJZ1Qe.d.mts} +2 -2
- package/package.json +1 -1
- package/src/core/Thread.ts +143 -146
- package/src/durable/DurableAgentRuntime.ts +381 -206
- package/src/durable/RunContinuation.ts +113 -62
- package/src/durable/RunJournal.ts +99 -108
- package/src/durable/RunStorage.ts +7 -0
- package/src/durable/SqlMemoryStore.ts +8 -6
- package/src/durable/SubmissionLedger.ts +7 -0
- package/src/durable/ThreadStore.ts +9 -7
- package/src/durable/ThreadWork.ts +10 -0
- package/src/durable/WakeScheduler.ts +34 -66
- package/src/durable/internal/usage-totals.ts +28 -31
- package/src/engine/MessagingHost.ts +4 -2
- package/src/engine/ThreadHistory.ts +47 -48
- package/src/engine/internal/agent-runtime.ts +234 -202
- package/src/engine/internal/output-contract.ts +15 -15
- package/src/engine/internal/primitive-delta.ts +2 -3
- package/src/engine/internal/tool-telemetry.ts +3 -5
- package/dist/AgentRuntime-B6qZlD3f.mjs.map +0 -1
- package/dist/DurableAgentRuntime-CBBjRNJN.mjs.map +0 -1
- package/dist/MessagingHost-CRUK4JBi.mjs.map +0 -1
- package/dist/RunContinuation-4ZATcVLB.mjs.map +0 -1
- package/dist/RunJournal-CNZqA3Ge.mjs.map +0 -1
- package/dist/RunStorage-BHjuuERI.mjs.map +0 -1
- package/dist/ThreadStore-59uDGXul.mjs.map +0 -1
|
@@ -33,11 +33,13 @@ const EncodedMemoryChange = Schema.Struct({
|
|
|
33
33
|
resultJson: StoredJson,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
Schema.toEncoded(MemoryWrite.Wire.members[0].fields.content)
|
|
38
|
-
|
|
36
|
+
const makeEquivalentContent = () =>
|
|
37
|
+
Schema.toEquivalence(Schema.toEncoded(MemoryWrite.Wire.members[0].fields.content));
|
|
38
|
+
|
|
39
|
+
let equivalentContent: ReturnType<typeof makeEquivalentContent> | undefined;
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
+
const makeEquivalentScopes = () => Schema.toEquivalence(MemoryWrite.Wire.members[0].fields.scopes);
|
|
42
|
+
let equivalentScopes: ReturnType<typeof makeEquivalentScopes> | undefined;
|
|
41
43
|
|
|
42
44
|
/** Ordered commands committed atomically by the SQL memory adapter. */
|
|
43
45
|
export const SqlMemoryWriteBatch = Schema.Array(MemoryWrite.Wire).check(Schema.isMaxLength(128));
|
|
@@ -388,8 +390,8 @@ const validateReceiptResult = Effect.fnUntraced(function* (
|
|
|
388
390
|
return yield* storageError(operation, "corrupt");
|
|
389
391
|
}
|
|
390
392
|
if (
|
|
391
|
-
!equivalentContent(command.content, result.content) ||
|
|
392
|
-
!equivalentScopes(command.scopes, result.scopes)
|
|
393
|
+
!(equivalentContent ??= makeEquivalentContent())(command.content, result.content) ||
|
|
394
|
+
!(equivalentScopes ??= makeEquivalentScopes())(command.scopes, result.scopes)
|
|
393
395
|
) {
|
|
394
396
|
return yield* storageError(operation, "corrupt");
|
|
395
397
|
}
|
|
@@ -989,6 +989,10 @@ export type SubmissionLedgerFailure =
|
|
|
989
989
|
* An optional `parentLinkage` is recorded immutably at first admission (SUB-016); a replay
|
|
990
990
|
* whose linkage diverges (present vs. absent, or different identities) fails with
|
|
991
991
|
* `AdmissionConflict` even when the input digest matches.
|
|
992
|
+
* With `readyIfInitialized`, an adapter may insert a fresh ordinary Submission as ready
|
|
993
|
+
* when it proves Thread initialization under the admission's owner transaction. Readiness,
|
|
994
|
+
* its lifecycle fact and source progress commit with the receipt. Otherwise it returns
|
|
995
|
+
* admitted and the caller completes materialization and `markReady` as usual.
|
|
992
996
|
* - `resolveAdmission` — authoritative tri-state admission lookup by scoped idempotency key
|
|
993
997
|
* (SUB-031): `NotAdmitted` proves absence, `Admitted` carries the full snapshot, and
|
|
994
998
|
* `Indeterminate` states that the adapter cannot currently prove either. Only `NotAdmitted`
|
|
@@ -1093,6 +1097,7 @@ export class SubmissionLedger extends Context.Service<
|
|
|
1093
1097
|
readonly capabilities: Effect.Effect<LedgerCapabilities>;
|
|
1094
1098
|
readonly admit: (
|
|
1095
1099
|
request: AdmissionRequest,
|
|
1100
|
+
options?: { readonly readyIfInitialized?: boolean },
|
|
1096
1101
|
) => Effect.Effect<AdmissionResult, AdmissionConflict | AdmissionPolicyError | LedgerError>;
|
|
1097
1102
|
readonly markReady: (request: MarkReadyRequest) => Effect.Effect<void, LedgerError>;
|
|
1098
1103
|
readonly lookup: (
|
|
@@ -1168,6 +1173,8 @@ export class SubmissionLedger extends Context.Service<
|
|
|
1168
1173
|
request: ReleaseChildBudgetRequest,
|
|
1169
1174
|
) => Effect.Effect<ChildBudgetReservationSnapshot, ChildReservationConflict | LedgerError>;
|
|
1170
1175
|
readonly scanNonterminal: Stream.Stream<SubmissionWorkItem, LedgerError>;
|
|
1176
|
+
/** Optional native snapshot for hosts that need the complete control worklist. */
|
|
1177
|
+
readonly listNonterminal?: Effect.Effect<ReadonlyArray<SubmissionWorkItem>, LedgerError>;
|
|
1171
1178
|
readonly loadRecoverySnapshot: (
|
|
1172
1179
|
request: RecoverySnapshotRequest,
|
|
1173
1180
|
) => Effect.Effect<RecoverySnapshot, LedgerError>;
|
|
@@ -415,10 +415,6 @@ const captureExecution = (input: ExecutionUpdate) => {
|
|
|
415
415
|
facts.push(record.success);
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
// Keep the actual owned arrays within the persisted bounds as well.
|
|
419
|
-
validateExecutionRecordCount(operational);
|
|
420
|
-
validateExecutionRecordCount(facts);
|
|
421
|
-
|
|
422
418
|
const checkpoint = Object.freeze(
|
|
423
419
|
ExecutionCheckpoint.make(
|
|
424
420
|
{
|
|
@@ -446,7 +442,13 @@ const captureExecution = (input: ExecutionUpdate) => {
|
|
|
446
442
|
const json = `{"previousRevision":${update.previousRevision},"checkpoint":${checkpointJson},"facts":[${facts.map(({ json }) => json).join(",")}],"retire":${update.retire}}`;
|
|
447
443
|
|
|
448
444
|
return Result.succeed(
|
|
449
|
-
Object.freeze({
|
|
445
|
+
Object.freeze({
|
|
446
|
+
update,
|
|
447
|
+
json,
|
|
448
|
+
checkpointJson,
|
|
449
|
+
factsJson: JSON.stringify(facts.map(({ wire }) => wire)),
|
|
450
|
+
bytes: utf8ByteLength(json),
|
|
451
|
+
}),
|
|
450
452
|
);
|
|
451
453
|
};
|
|
452
454
|
|
|
@@ -497,6 +499,8 @@ export interface PreparedAppend extends AppendRequest {
|
|
|
497
499
|
readonly json: string;
|
|
498
500
|
/** Checkpoint wire from the same detached, validated execution capture. */
|
|
499
501
|
readonly checkpointJson: string;
|
|
502
|
+
/** Schema-encoded fact array from this same capture, for the stable retry digest. */
|
|
503
|
+
readonly factsJson: string;
|
|
500
504
|
readonly bytes: number;
|
|
501
505
|
}>;
|
|
502
506
|
readonly records: ReadonlyArray<{
|
|
@@ -542,8 +546,6 @@ export const PreparedAppend = {
|
|
|
542
546
|
executionWrites.push(yield* captureExecution(executions[index]!));
|
|
543
547
|
Object.freeze(executionWrites);
|
|
544
548
|
|
|
545
|
-
validateRecordCount(executionWrites);
|
|
546
|
-
|
|
547
549
|
if (input.batch.records.length === 0 && executionWrites.length === 0)
|
|
548
550
|
return yield* Result.fail(
|
|
549
551
|
ThreadStoreError.make({
|
|
@@ -144,6 +144,10 @@ export const ThreadWorkCursor = Schema.Struct({
|
|
|
144
144
|
|
|
145
145
|
export type ThreadWorkCursor = typeof ThreadWorkCursor.Type;
|
|
146
146
|
|
|
147
|
+
/** Local snapshot request; it grants no claim or dispatch authority. */
|
|
148
|
+
export const FreshAdmissionWork = Schema.Struct({ threadId: ThreadId, submissionId: SubmissionId });
|
|
149
|
+
export type FreshAdmissionWork = typeof FreshAdmissionWork.Type;
|
|
150
|
+
|
|
147
151
|
export const WorkThreadsRequest = Schema.Struct({
|
|
148
152
|
afterThreadId: Schema.optionalKey(ThreadId),
|
|
149
153
|
limit: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 32 })),
|
|
@@ -192,6 +196,12 @@ export class WorkDiscoveryUnavailable extends Schema.TaggedError<WorkDiscoveryUn
|
|
|
192
196
|
|
|
193
197
|
/** Native owner pages and canonical-index maintenance, implemented at the storage owner. */
|
|
194
198
|
export interface ThreadWorkStorage {
|
|
199
|
+
/** Native proof that this untouched root admission has no other recovery obligations.
|
|
200
|
+
* A caller must still claim and validate current controls before dispatch. */
|
|
201
|
+
readonly isOnlyFreshAdmission?: (
|
|
202
|
+
request: FreshAdmissionWork,
|
|
203
|
+
) => Effect.Effect<boolean, ThreadStoreError>;
|
|
204
|
+
|
|
195
205
|
readonly threads: (
|
|
196
206
|
request: WorkThreadsRequest,
|
|
197
207
|
) => Effect.Effect<WorkThreadsPage, ThreadStoreError>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Scope } from "effect";
|
|
2
|
-
import { Context, Deferred, Effect, Layer,
|
|
2
|
+
import { Context, Deferred, Effect, Layer, Stream } from "effect";
|
|
3
3
|
|
|
4
4
|
import { type ThreadId } from "../core/Identifiers.ts";
|
|
5
5
|
|
|
@@ -17,79 +17,47 @@ export interface WakeSubscriptionHub {
|
|
|
17
17
|
readonly notify: (threadId: ThreadId) => Effect.Effect<void>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
interface WakeRegistration {
|
|
21
|
-
readonly id: number;
|
|
22
|
-
readonly deferred: Deferred.Deferred<void>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
type WakeRegistrations = ReadonlyMap<ThreadId, ReadonlyMap<number, Deferred.Deferred<void>>>;
|
|
26
|
-
|
|
27
20
|
/**
|
|
28
21
|
* Build the shared per-incarnation registration primitive used by host WakeSchedulers. The hub
|
|
29
22
|
* contains hints only: eviction may discard it, while a reconnecting caller re-subscribes and
|
|
30
23
|
* rechecks canonical storage. Scope finalizers remove cancelled waiters, and notify broadcasts
|
|
31
24
|
* instead of consuming a signal that belongs to another waiter.
|
|
32
25
|
*/
|
|
33
|
-
export const makeWakeSubscriptionHub: Effect.Effect<WakeSubscriptionHub> = Effect.
|
|
34
|
-
const registrations =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
26
|
+
export const makeWakeSubscriptionHub: Effect.Effect<WakeSubscriptionHub> = Effect.sync(() => {
|
|
27
|
+
const registrations = new Map<ThreadId, Set<Deferred.Deferred<void>>>();
|
|
28
|
+
|
|
29
|
+
const subscribe = (threadId: ThreadId) =>
|
|
30
|
+
Effect.acquireRelease(
|
|
31
|
+
Effect.sync(() => {
|
|
32
|
+
const deferred = Deferred.makeUnsafe<void>();
|
|
33
|
+
let waiters = registrations.get(threadId);
|
|
34
|
+
|
|
35
|
+
if (waiters === undefined) {
|
|
36
|
+
waiters = new Set();
|
|
37
|
+
registrations.set(threadId, waiters);
|
|
38
|
+
}
|
|
39
|
+
waiters.add(deferred);
|
|
40
|
+
|
|
41
|
+
return deferred;
|
|
42
|
+
}),
|
|
43
|
+
(deferred) =>
|
|
44
|
+
Effect.sync(() => {
|
|
45
|
+
const waiters = registrations.get(threadId);
|
|
46
|
+
|
|
47
|
+
if (waiters?.delete(deferred) && waiters.size === 0) registrations.delete(threadId);
|
|
48
|
+
}),
|
|
49
|
+
).pipe(Effect.map(Deferred.await));
|
|
50
|
+
|
|
51
|
+
const notify = (threadId: ThreadId) =>
|
|
52
|
+
Effect.sync(() => {
|
|
53
|
+
const waiters = registrations.get(threadId);
|
|
54
|
+
|
|
55
|
+
if (waiters === undefined) return;
|
|
56
|
+
// Detach before resuming: a resumed waiter may register its next wait immediately.
|
|
57
|
+
registrations.delete(threadId);
|
|
58
|
+
for (const waiter of waiters) Deferred.doneUnsafe(waiter, Effect.void);
|
|
53
59
|
});
|
|
54
60
|
|
|
55
|
-
const subscribe = Effect.fnUntraced(function* (
|
|
56
|
-
threadId: ThreadId,
|
|
57
|
-
): Effect.fn.Return<Effect.Effect<void>, never, Scope.Scope> {
|
|
58
|
-
const deferred = yield* Deferred.make<void>();
|
|
59
|
-
const id = yield* Ref.getAndUpdate(nextId, (current) => current + 1);
|
|
60
|
-
const registration: WakeRegistration = { id, deferred };
|
|
61
|
-
|
|
62
|
-
yield* Effect.addFinalizer(() => remove(threadId, registration.id));
|
|
63
|
-
yield* Ref.update(registrations, (current) => {
|
|
64
|
-
const next = new Map(current);
|
|
65
|
-
const thread = new Map(current.get(threadId) ?? []);
|
|
66
|
-
|
|
67
|
-
thread.set(registration.id, registration.deferred);
|
|
68
|
-
next.set(threadId, thread);
|
|
69
|
-
|
|
70
|
-
return next;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
return Deferred.await(registration.deferred);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const notify = Effect.fnUntraced(function* (threadId: ThreadId) {
|
|
77
|
-
const waiters = yield* Ref.modify(registrations, (current) => {
|
|
78
|
-
const thread = current.get(threadId);
|
|
79
|
-
|
|
80
|
-
if (thread === undefined) return [[], current] as const;
|
|
81
|
-
const next = new Map(current);
|
|
82
|
-
|
|
83
|
-
next.delete(threadId);
|
|
84
|
-
|
|
85
|
-
return [[...thread.values()], next] as const;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
yield* Effect.forEach(waiters, (waiter) => Deferred.succeed(waiter, undefined), {
|
|
89
|
-
discard: true,
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
61
|
return { subscribe, notify };
|
|
94
62
|
});
|
|
95
63
|
|
|
@@ -3,36 +3,33 @@ import { Effect } from "effect";
|
|
|
3
3
|
import { summarizeModelUsage, type ModelCallUsage } from "../../core/Usage.ts";
|
|
4
4
|
|
|
5
5
|
/** Captured calls are additive and nonnegative; progress does not need attribution groups. */
|
|
6
|
-
export const continuationUsage =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
let knownWebSearchCalls = 0;
|
|
6
|
+
export const continuationUsage = (calls: ReadonlyArray<ModelCallUsage>) =>
|
|
7
|
+
Effect.suspend(() => {
|
|
8
|
+
let inputTokens = 0;
|
|
9
|
+
let outputTokens = 0;
|
|
10
|
+
let costMicrousd = 0;
|
|
11
|
+
let knownWebSearchCalls = 0;
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
for (const call of calls) {
|
|
14
|
+
inputTokens += call.inputTokens.total;
|
|
15
|
+
outputTokens += call.outputTokens.total;
|
|
16
|
+
costMicrousd += call.costMicrousd;
|
|
17
|
+
knownWebSearchCalls += call.webSearchCalls ?? 0;
|
|
18
|
+
}
|
|
19
|
+
if (
|
|
20
|
+
Number.isSafeInteger(inputTokens) &&
|
|
21
|
+
Number.isSafeInteger(outputTokens) &&
|
|
22
|
+
Number.isSafeInteger(costMicrousd) &&
|
|
23
|
+
Number.isSafeInteger(knownWebSearchCalls)
|
|
24
|
+
)
|
|
25
|
+
return Effect.succeed({ modelCalls: calls.length, inputTokens, outputTokens, costMicrousd });
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
});
|
|
27
|
+
// Safe global sums bound every component/group. On overflow retain the full validator,
|
|
28
|
+
// including groups whose hosted-search coverage differs from the aggregate's coverage.
|
|
29
|
+
return Effect.map(summarizeModelUsage(calls), (summary) => ({
|
|
30
|
+
modelCalls: summary.modelCalls,
|
|
31
|
+
inputTokens: summary.inputTokens.total,
|
|
32
|
+
outputTokens: summary.outputTokens.total,
|
|
33
|
+
costMicrousd: summary.costMicrousd,
|
|
34
|
+
}));
|
|
35
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Effect } from "effect";
|
|
2
2
|
import * as Context from "effect/Context";
|
|
3
3
|
|
|
4
4
|
import type { AnyDefinition } from "../core/Agent.ts";
|
|
@@ -47,7 +47,9 @@ export class MessagingHost extends Context.Service<
|
|
|
47
47
|
}
|
|
48
48
|
>()("@effect-agent/engine/MessagingHost") {
|
|
49
49
|
static readonly unavailable: MessagingHost["Service"] = {
|
|
50
|
-
context:
|
|
50
|
+
context: Effect.suspend(() =>
|
|
51
|
+
MessagingError.make({ operation: "context", reason: "unavailable" }),
|
|
52
|
+
),
|
|
51
53
|
send: () => MessagingError.make({ operation: "send", reason: "unavailable" }),
|
|
52
54
|
reply: () => MessagingError.make({ operation: "reply", reason: "unavailable" }),
|
|
53
55
|
inbox: () => MessagingError.make({ operation: "inbox", reason: "unavailable" }),
|
|
@@ -75,57 +75,56 @@ export class ThreadHistory extends Context.Service<
|
|
|
75
75
|
}
|
|
76
76
|
>()("@effect-agent/engine/ThreadHistory") {
|
|
77
77
|
/** Bind incremental history to the supplied Thread.Store, including scoped ownership views. */
|
|
78
|
-
static readonly
|
|
79
|
-
|
|
80
|
-
Effect.gen(function* () {
|
|
81
|
-
const threads = yield* ConversationStore;
|
|
78
|
+
static readonly makeFromStore = Effect.gen(function* () {
|
|
79
|
+
const threads = yield* ConversationStore;
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
81
|
+
const historyError = (cause: ThreadError): ThreadHistoryError =>
|
|
82
|
+
ThreadHistoryError.make({
|
|
83
|
+
threadId: cause.threadId,
|
|
84
|
+
reason:
|
|
85
|
+
cause._tag === "ThreadNotFound"
|
|
86
|
+
? "not-found"
|
|
87
|
+
: cause._tag === "ThreadLimitExceeded"
|
|
88
|
+
? "limit"
|
|
89
|
+
: cause._tag === "ThreadHistoryDiverged"
|
|
90
|
+
? "conflict"
|
|
91
|
+
: cause._tag === "ThreadOwnershipError"
|
|
92
|
+
? cause.reason === "closed"
|
|
93
|
+
? "fenced"
|
|
94
|
+
: "conflict"
|
|
95
|
+
: "encoding",
|
|
96
|
+
message:
|
|
97
|
+
cause._tag === "ThreadNotFound"
|
|
98
|
+
? "Thread history is not present in this application Scope"
|
|
99
|
+
: cause._tag === "ThreadLimitExceeded"
|
|
100
|
+
? `In-memory history exceeds the ${cause.limit} limit of ${cause.limitValue}`
|
|
101
|
+
: cause.message,
|
|
102
|
+
cause,
|
|
103
|
+
});
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
return ThreadHistory.of({
|
|
106
|
+
retention: "incremental",
|
|
107
|
+
memoryStore: threads,
|
|
108
|
+
load: (threadId) =>
|
|
109
|
+
threads.snapshot(threadId).pipe(Effect.map(toPrompt), Effect.mapError(historyError)),
|
|
110
|
+
open: Effect.fnUntraced(function* ({ threadId, runId }) {
|
|
111
|
+
const snapshot = yield* threads.create(threadId).pipe(Effect.mapError(historyError));
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
113
|
+
return {
|
|
114
|
+
prompt: toPrompt(snapshot),
|
|
115
|
+
stageInput: () => Effect.void,
|
|
116
|
+
stageHistory: ({ source }) =>
|
|
117
|
+
threads
|
|
118
|
+
.recordHistory(threadId, runId, source)
|
|
119
|
+
.pipe(Effect.asVoid, Effect.mapError(historyError)),
|
|
120
|
+
commit: () =>
|
|
121
|
+
threads.snapshot(threadId).pipe(Effect.asVoid, Effect.mapError(historyError)),
|
|
122
|
+
};
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
static readonly layerFromStore = Layer.effect(ThreadHistory, ThreadHistory.makeFromStore);
|
|
129
128
|
|
|
130
129
|
/** Retain history for the application Scope, within message and host capacity. Separate Layer builds own separate stores. */
|
|
131
130
|
static readonly layer = ThreadHistory.layerFromStore.pipe(Layer.provideMerge(layerMemory));
|