@relayfx/sdk 0.3.6 → 0.3.7

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.
@@ -16,7 +16,7 @@ import {
16
16
  exports_tool_executor,
17
17
  exports_tool_output,
18
18
  exports_turn_policy
19
- } from "./index-8fpd6kvj.js";
19
+ } from "./index-t5bbk8cp.js";
20
20
  import {
21
21
  ClientError,
22
22
  CommandReplyInvalid,
@@ -51,7 +51,7 @@ import {
51
51
  followExecutionFrom,
52
52
  inputSchemaRef,
53
53
  outputSchemaRef
54
- } from "./index-mtvz1bjn.js";
54
+ } from "./index-pw46cfne.js";
55
55
  import {
56
56
  __export
57
57
  } from "./index-nb39b5ae.js";
@@ -717,7 +717,7 @@ __export(exports_tool_runtime, {
717
717
  });
718
718
 
719
719
  // ../runtime/src/tool/tool-runtime-contract.ts
720
- import { Context as Context10, Layer as Layer10, Schema as Schema10 } from "effect";
720
+ import { Context as Context10, Effect as Effect10, Layer as Layer10, Schema as Schema10 } from "effect";
721
721
 
722
722
  class ToolNotRegistered extends Schema10.TaggedErrorClass()("ToolNotRegistered", {
723
723
  tool_name: exports_shared_schema.NonEmptyString
@@ -755,7 +755,7 @@ class ToolCallInfo extends Context10.Service()("@relayfx/runtime/tool/tool-runti
755
755
 
756
756
  class Service12 extends Context10.Service()("@relayfx/runtime/tool/tool-runtime-contract/Service") {
757
757
  }
758
- var testLayer8 = (implementation) => Layer10.succeed(Service12, Service12.of(implementation));
758
+ var testLayer8 = (implementation) => Layer10.succeed(Service12, Service12.of({ ...implementation, prepare: implementation.prepare ?? (() => Effect10.void) }));
759
759
  // ../store-sql/src/address/address-book-repository.ts
760
760
  var exports_address_book_repository = {};
761
761
  __export(exports_address_book_repository, {
@@ -3175,6 +3175,7 @@ __export(exports_execution_event_repository, {
3175
3175
  findByCursor: () => findByCursor,
3176
3176
  executionEventsChannel: () => executionEventsChannel,
3177
3177
  appendedSignals: () => appendedSignals,
3178
+ appendNext: () => appendNext,
3178
3179
  append: () => append,
3179
3180
  Service: () => Service25,
3180
3181
  ExecutionEventRow: () => ExecutionEventRow,
@@ -3183,7 +3184,7 @@ __export(exports_execution_event_repository, {
3183
3184
  ExecutionEventCursorNotFound: () => ExecutionEventCursorNotFound,
3184
3185
  DuplicateExecutionEvent: () => DuplicateExecutionEvent
3185
3186
  });
3186
- import { Context as Context23, Effect as Effect24, Filter, Layer as Layer23, Option as Option2, PubSub as PubSub2, Schema as Schema22, Stream as Stream2 } from "effect";
3187
+ import { Context as Context23, Effect as Effect24, Filter, Layer as Layer23, Option as Option2, PubSub as PubSub2, Schema as Schema22, Semaphore as Semaphore2, Stream as Stream2 } from "effect";
3187
3188
  import { SqlClient as SqlClient13 } from "effect/unstable/sql/SqlClient";
3188
3189
 
3189
3190
  // ../store-sql/src/database/notification-bus.ts
@@ -3319,6 +3320,7 @@ var duplicateError = (input) => DuplicateExecutionEvent.make({
3319
3320
  sequence: input.sequence,
3320
3321
  cursor: input.cursor
3321
3322
  });
3323
+ var hasSamePayload = (existing, input) => existing.id === input.id && existing.execution_id === input.execution_id && existing.child_execution_id === input.child_execution_id && existing.type === input.type && existing.cursor === input.cursor && exports_shared_schema.canonicalEquals(existing.content ?? null, input.content ?? null) && exports_shared_schema.canonicalEquals(existing.data ?? {}, input.data ?? {});
3322
3324
  var assertAppendable = (events, input) => {
3323
3325
  const duplicate = events.find((event) => event.sequence === input.sequence || event.cursor === input.cursor);
3324
3326
  if (duplicate !== undefined) {
@@ -3382,15 +3384,15 @@ var layer18 = Layer23.effect(Service25, Effect24.gen(function* () {
3382
3384
  ${timestampParam(sql, input.created_at)}
3383
3385
  )
3384
3386
  `;
3385
- const insertEvent = sql.onDialectOrElse({
3386
- mysql: () => (tenantId, input) => sql.withTransaction(Effect24.gen(function* () {
3387
- yield* insertStatement(tenantId, input);
3388
- return yield* selectByCursor(tenantId, input.cursor);
3389
- })),
3390
- orElse: () => (tenantId, input) => sql`
3391
- ${insertStatement(tenantId, input)}
3392
- RETURNING ${columns}
3393
- `
3387
+ const lockExecution = (tenantId, executionId) => sql.onDialectOrElse({
3388
+ mysql: () => sql`UPDATE relay_executions SET updated_at=updated_at WHERE tenant_id=${tenantId} AND id=${executionId}`.pipe(Effect24.andThen(sql`SELECT id FROM relay_executions WHERE tenant_id=${tenantId} AND id=${executionId}`)),
3389
+ orElse: () => sql`UPDATE relay_executions SET updated_at=updated_at WHERE tenant_id=${tenantId} AND id=${executionId} RETURNING id`
3390
+ });
3391
+ const lockExistingExecution = Effect24.fn("ExecutionEventRepository.lockExistingExecution")(function* (tenantId, executionId) {
3392
+ const rows = yield* lockExecution(tenantId, executionId);
3393
+ if (rows[0] === undefined) {
3394
+ return yield* ExecutionEventRepositoryError.make({ message: `Execution not found: ${executionId}` });
3395
+ }
3394
3396
  });
3395
3397
  const listConditions = (tenantId, input) => [
3396
3398
  sql`tenant_id = ${tenantId}`,
@@ -3407,28 +3409,68 @@ var layer18 = Layer23.effect(Service25, Effect24.gen(function* () {
3407
3409
  const decodeEvents = (rows) => Effect24.forEach(rows, decodeRow7).pipe(Effect24.map((decoded) => decoded.map(toEvent)));
3408
3410
  const append = Effect24.fn("ExecutionEventRepository.append")(function* (input) {
3409
3411
  const tenantId = yield* current();
3410
- const previousRows = yield* selectLatest(tenantId, input.execution_id).pipe(Effect24.mapError(toRepositoryError8));
3411
- const previous = previousRows[0] === undefined ? undefined : toEvent(yield* decodeRow7(previousRows[0]));
3412
- if (previous !== undefined && input.sequence === previous.sequence) {
3413
- return yield* duplicateError(input);
3414
- }
3415
- if (previous !== undefined && input.sequence < previous.sequence) {
3416
- return yield* ExecutionEventOrderViolation.make({
3417
- execution_id: input.execution_id,
3418
- sequence: input.sequence,
3419
- previous_sequence: previous.sequence
3420
- });
3421
- }
3422
- const duplicateCursorRows = yield* selectByCursor(tenantId, input.cursor).pipe(Effect24.mapError(toRepositoryError8));
3423
- if (duplicateCursorRows[0] !== undefined) {
3424
- return yield* duplicateError(input);
3425
- }
3426
- const rows = yield* insertEvent(tenantId, input).pipe(Effect24.mapError(toRepositoryError8));
3427
- const row = rows[0];
3428
- if (row === undefined) {
3429
- return yield* ExecutionEventRepositoryError.make({ message: "Execution event append returned no row" });
3430
- }
3431
- return toEvent(yield* decodeRow7(row));
3412
+ return yield* sql.withTransaction(Effect24.gen(function* () {
3413
+ yield* lockExistingExecution(tenantId, input.execution_id);
3414
+ const previousRows = yield* selectLatest(tenantId, input.execution_id);
3415
+ const previous = previousRows[0] === undefined ? undefined : toEvent(yield* decodeRow7(previousRows[0]));
3416
+ if (previous !== undefined && input.sequence === previous.sequence)
3417
+ return yield* duplicateError(input);
3418
+ if (previous !== undefined && input.sequence < previous.sequence) {
3419
+ return yield* ExecutionEventOrderViolation.make({
3420
+ execution_id: input.execution_id,
3421
+ sequence: input.sequence,
3422
+ previous_sequence: previous.sequence
3423
+ });
3424
+ }
3425
+ const duplicateCursorRows = yield* selectByCursor(tenantId, input.cursor);
3426
+ if (duplicateCursorRows[0] !== undefined)
3427
+ return yield* duplicateError(input);
3428
+ yield* insertStatement(tenantId, input);
3429
+ const rows = yield* selectByCursor(tenantId, input.cursor);
3430
+ const row = rows[0];
3431
+ if (row === undefined) {
3432
+ return yield* ExecutionEventRepositoryError.make({ message: "Execution event append returned no row" });
3433
+ }
3434
+ return toEvent(yield* decodeRow7(row));
3435
+ })).pipe(Effect24.mapError((error) => Schema22.is(DuplicateExecutionEvent)(error) || Schema22.is(ExecutionEventOrderViolation)(error) ? error : toRepositoryError8(error)));
3436
+ });
3437
+ const appendNext = Effect24.fn("ExecutionEventRepository.appendNext")(function* (input) {
3438
+ const tenantId = yield* current();
3439
+ return yield* sql.withTransaction(Effect24.gen(function* () {
3440
+ yield* lockExistingExecution(tenantId, input.execution_id);
3441
+ const existingRows = yield* selectByCursor(tenantId, input.cursor);
3442
+ const existingRow = existingRows[0];
3443
+ if (existingRow !== undefined) {
3444
+ const existing = toEvent(yield* decodeRow7(existingRow));
3445
+ if (hasSamePayload(existing, input))
3446
+ return { event: existing, inserted: false };
3447
+ return yield* duplicateError({ ...input, sequence: existing.sequence });
3448
+ }
3449
+ const sequenceRows = yield* sql`
3450
+ SELECT COALESCE(MAX(sequence), -1) + 1 AS value
3451
+ FROM relay_execution_events
3452
+ WHERE tenant_id = ${tenantId} AND execution_id = ${input.execution_id}
3453
+ `;
3454
+ const sequenceRow = sequenceRows[0];
3455
+ if (sequenceRow === undefined) {
3456
+ return yield* ExecutionEventRepositoryError.make({
3457
+ message: "Execution event sequence query returned no row"
3458
+ });
3459
+ }
3460
+ const decodedSequence = yield* decodeAggregate(sequenceRow);
3461
+ const { minimumSequence, ...eventInput } = input;
3462
+ const event = {
3463
+ ...eventInput,
3464
+ sequence: Math.max(Number(decodedSequence.value), minimumSequence ?? 0)
3465
+ };
3466
+ yield* insertStatement(tenantId, event);
3467
+ const rows = yield* selectByCursor(tenantId, input.cursor);
3468
+ const row = rows[0];
3469
+ if (row === undefined) {
3470
+ return yield* ExecutionEventRepositoryError.make({ message: "Execution event append returned no row" });
3471
+ }
3472
+ return { event: toEvent(yield* decodeRow7(row)), inserted: true };
3473
+ })).pipe(Effect24.mapError((error) => Schema22.is(DuplicateExecutionEvent)(error) ? error : toRepositoryError8(error)));
3432
3474
  });
3433
3475
  const list4 = Effect24.fn("ExecutionEventRepository.list")(function* (input) {
3434
3476
  const tenantId = yield* current();
@@ -3608,6 +3650,7 @@ var layer18 = Layer23.effect(Service25, Effect24.gen(function* () {
3608
3650
  return Service25.of({
3609
3651
  signalTransport: bus.transport,
3610
3652
  append,
3653
+ appendNext,
3611
3654
  list: list4,
3612
3655
  findBySequenceOrCursor,
3613
3656
  findByCursor,
@@ -3624,14 +3667,47 @@ var layer18 = Layer23.effect(Service25, Effect24.gen(function* () {
3624
3667
  var layerWithBus = layer18.pipe(Layer23.provide(layerFromDialect));
3625
3668
  var memoryLayer16 = Layer23.effect(Service25, Effect24.gen(function* () {
3626
3669
  const events = new Map;
3670
+ const locks = new Map;
3627
3671
  const signals = yield* PubSub2.unbounded();
3672
+ const lockFor = Effect24.fn("ExecutionEventRepository.memory.lockFor")(function* (executionId) {
3673
+ const candidate = yield* Semaphore2.make(1);
3674
+ return yield* Effect24.sync(() => {
3675
+ const existing = locks.get(executionId);
3676
+ if (existing !== undefined)
3677
+ return existing;
3678
+ locks.set(executionId, candidate);
3679
+ return candidate;
3680
+ });
3681
+ });
3628
3682
  return Service25.of({
3629
3683
  signalTransport: "in-process",
3630
3684
  append: Effect24.fn("ExecutionEventRepository.memory.append")(function* (input) {
3631
- const executionEvents = events.get(input.execution_id) ?? [];
3632
- yield* assertAppendable(executionEvents, input);
3633
- yield* Effect24.sync(() => events.set(input.execution_id, [...executionEvents, input]));
3634
- return input;
3685
+ const lock = yield* lockFor(input.execution_id);
3686
+ return yield* lock.withPermits(1)(Effect24.gen(function* () {
3687
+ const executionEvents = events.get(input.execution_id) ?? [];
3688
+ yield* assertAppendable(executionEvents, input);
3689
+ yield* Effect24.sync(() => events.set(input.execution_id, [...executionEvents, input]));
3690
+ return input;
3691
+ }));
3692
+ }),
3693
+ appendNext: Effect24.fn("ExecutionEventRepository.memory.appendNext")(function* (input) {
3694
+ const lock = yield* lockFor(input.execution_id);
3695
+ return yield* lock.withPermits(1)(Effect24.gen(function* () {
3696
+ const executionEvents = events.get(input.execution_id) ?? [];
3697
+ const existing = executionEvents.find((event2) => event2.cursor === input.cursor);
3698
+ if (existing !== undefined) {
3699
+ if (hasSamePayload(existing, input))
3700
+ return { event: existing, inserted: false };
3701
+ return yield* duplicateError({ ...input, sequence: existing.sequence });
3702
+ }
3703
+ const { minimumSequence, ...eventInput } = input;
3704
+ const event = {
3705
+ ...eventInput,
3706
+ sequence: Math.max(executionEvents.reduce((maximum, item) => Math.max(maximum, item.sequence), -1) + 1, minimumSequence ?? 0)
3707
+ };
3708
+ yield* Effect24.sync(() => events.set(input.execution_id, [...executionEvents, event]));
3709
+ return { event, inserted: true };
3710
+ }));
3635
3711
  }),
3636
3712
  list: Effect24.fn("ExecutionEventRepository.memory.list")(function* (input) {
3637
3713
  const executionEvents = events.get(input.executionId) ?? [];
@@ -3696,12 +3772,17 @@ var memoryLayer16 = Layer23.effect(Service25, Effect24.gen(function* () {
3696
3772
  }));
3697
3773
  var testLayer20 = (implementation) => Layer23.succeed(Service25, Service25.of({
3698
3774
  ...implementation,
3775
+ appendNext: implementation.appendNext ?? ((input) => implementation.append({ ...input, sequence: 0 }).pipe(Effect24.map((event) => ({ event, inserted: true })), Effect24.catchTag("ExecutionEventOrderViolation", (error) => ExecutionEventRepositoryError.make({ message: String(error) })))),
3699
3776
  page: implementation.page ?? (() => Effect24.succeed({ events: [], hasMore: false }))
3700
3777
  }));
3701
3778
  var append = Effect24.fn("ExecutionEventRepository.append.call")(function* (input) {
3702
3779
  const repository = yield* Service25;
3703
3780
  return yield* repository.append(input);
3704
3781
  });
3782
+ var appendNext = Effect24.fn("ExecutionEventRepository.appendNext.call")(function* (input) {
3783
+ const repository = yield* Service25;
3784
+ return yield* repository.appendNext(input);
3785
+ });
3705
3786
  var list4 = Effect24.fn("ExecutionEventRepository.list.call")(function* (input) {
3706
3787
  const repository = yield* Service25;
3707
3788
  return yield* repository.list(input);
@@ -4409,7 +4490,7 @@ var layer20 = Layer25.effect(Service27, Effect26.gen(function* () {
4409
4490
  }));
4410
4491
  var testLayer22 = (implementation) => Layer25.succeed(Service27, Service27.of(implementation));
4411
4492
  // ../store-sql/src/idempotency/idempotency-repository.ts
4412
- import { Context as Context26, Effect as Effect27, HashMap, Layer as Layer26, Option as Option5, Ref as Ref5, Schema as Schema25, Semaphore as Semaphore2 } from "effect";
4493
+ import { Context as Context26, Effect as Effect27, HashMap, Layer as Layer26, Option as Option5, Ref as Ref5, Schema as Schema25, Semaphore as Semaphore3 } from "effect";
4413
4494
  import { SqlClient as SqlClient16 } from "effect/unstable/sql/SqlClient";
4414
4495
  class IdempotencyRepositoryError extends Schema25.TaggedErrorClass()("IdempotencyRepositoryError", {
4415
4496
  message: Schema25.String
@@ -4528,7 +4609,7 @@ var layer21 = Layer26.effect(Service28, Effect27.gen(function* () {
4528
4609
  }));
4529
4610
  var memoryLayer19 = Layer26.effect(Service28, Effect27.gen(function* () {
4530
4611
  const records = yield* Ref5.make(HashMap.empty());
4531
- const semaphore = Semaphore2.makeUnsafe(1);
4612
+ const semaphore = Semaphore3.makeUnsafe(1);
4532
4613
  const runOnce = Effect27.fn("IdempotencyRepository.memory.runOnce")(function* (input, create4) {
4533
4614
  return yield* semaphore.withPermits(1)(Effect27.gen(function* () {
4534
4615
  const id = operationId(input);
@@ -4623,9 +4704,13 @@ var consumeMessage = (message, input) => Object.assign({}, message, { drain_id:
4623
4704
  var layer22 = Layer27.effect(Service29, Effect28.gen(function* () {
4624
4705
  const sql = yield* SqlClient17;
4625
4706
  const lockExecution = sql.onDialectOrElse({
4626
- pg: () => (tenant, executionId) => sql`SELECT pg_advisory_xact_lock(hashtext(${`${tenant}:${executionId}:inbox`}))`.pipe(Effect28.asVoid),
4627
- mysql: () => (tenant, executionId) => sql`SELECT id FROM relay_executions WHERE tenant_id=${tenant} AND id=${executionId} FOR UPDATE`.pipe(Effect28.asVoid),
4628
- orElse: () => () => Effect28.void
4707
+ mysql: () => (tenant, executionId) => sql`UPDATE relay_executions SET updated_at=updated_at WHERE tenant_id=${tenant} AND id=${executionId}`.pipe(Effect28.andThen(sql`SELECT id FROM relay_executions WHERE tenant_id=${tenant} AND id=${executionId}`)),
4708
+ orElse: () => (tenant, executionId) => sql`UPDATE relay_executions SET updated_at=updated_at WHERE tenant_id=${tenant} AND id=${executionId} RETURNING id`
4709
+ });
4710
+ const lockExistingExecution = Effect28.fn("InboxRepository.lockExistingExecution")(function* (tenant, executionId) {
4711
+ const rows = yield* lockExecution(tenant, executionId);
4712
+ if (rows[0] === undefined)
4713
+ return yield* InboxRepositoryError.make({ message: `Execution not found: ${executionId}` });
4629
4714
  });
4630
4715
  const appendEvent = (tenant, input, type, id, cursor, data) => Effect28.gen(function* () {
4631
4716
  const rows = yield* sql`SELECT COALESCE(MAX(sequence), -1) + 1 AS next_sequence FROM relay_execution_events WHERE tenant_id=${tenant} AND execution_id=${input.executionId}`;
@@ -4642,7 +4727,7 @@ var layer22 = Layer27.effect(Service29, Effect28.gen(function* () {
4642
4727
  const deliver = Effect28.fn("InboxRepository.deliver")(function* (input) {
4643
4728
  const tenant = yield* current();
4644
4729
  return yield* sql.withTransaction(Effect28.gen(function* () {
4645
- yield* lockExecution(tenant, input.executionId);
4730
+ yield* lockExistingExecution(tenant, input.executionId);
4646
4731
  if (input.idempotencyKey !== undefined) {
4647
4732
  const found = yield* sql`SELECT ${sql.literal(columns)} FROM relay_inbox_messages WHERE tenant_id=${tenant} AND execution_id=${input.executionId} AND idempotency_key=${input.idempotencyKey}`;
4648
4733
  if (found[0] !== undefined)
@@ -4671,7 +4756,7 @@ var layer22 = Layer27.effect(Service29, Effect28.gen(function* () {
4671
4756
  const drain = Effect28.fn("InboxRepository.drain")(function* (input) {
4672
4757
  const tenant = yield* current();
4673
4758
  return yield* sql.withTransaction(Effect28.gen(function* () {
4674
- yield* lockExecution(tenant, input.executionId);
4759
+ yield* lockExistingExecution(tenant, input.executionId);
4675
4760
  const old = yield* sql`SELECT message_sequences_json FROM relay_inbox_drains WHERE tenant_id=${tenant} AND execution_id=${input.executionId} AND drain_id=${input.drainId}`;
4676
4761
  let sequences;
4677
4762
  if (old[0] !== undefined)
@@ -6819,7 +6904,7 @@ __export(exports_skill_definition_repository, {
6819
6904
  Service: () => Service36,
6820
6905
  ExecutionSkillPinRow: () => ExecutionSkillPinRow
6821
6906
  });
6822
- import { Context as Context34, Effect as Effect35, HashSet, Layer as Layer34, Schema as Schema33, Semaphore as Semaphore3 } from "effect";
6907
+ import { Context as Context34, Effect as Effect35, HashSet, Layer as Layer34, Schema as Schema33, Semaphore as Semaphore4 } from "effect";
6823
6908
  import { SqlClient as SqlClient24 } from "effect/unstable/sql/SqlClient";
6824
6909
  class SkillDefinitionRepositoryError extends Schema33.TaggedErrorClass()("SkillDefinitionRepositoryError", {
6825
6910
  message: Schema33.String
@@ -7108,7 +7193,7 @@ var layer29 = Layer34.effect(Service36, Effect35.gen(function* () {
7108
7193
  return Service36.of({ put: put3, get: get10, getRevision: getRevision2, list: list11, listRevisions: listRevisions2, pinExecution, listPins, getPinned });
7109
7194
  }));
7110
7195
  var memoryLayer27 = Layer34.sync(Service36, () => {
7111
- const semaphore = Semaphore3.makeUnsafe(1);
7196
+ const semaphore = Semaphore4.makeUnsafe(1);
7112
7197
  const records = new Map;
7113
7198
  const revisions = new Map;
7114
7199
  const pins = new Map;
@@ -9622,7 +9707,8 @@ var afterSequence = (events, input) => {
9622
9707
  return Effect41.succeed(cursorEvent.sequence);
9623
9708
  };
9624
9709
  var replayAfter = (events, input, sequence) => events.filter((event) => event.execution_id === input.executionId).filter((event) => sequence === undefined || event.sequence > sequence).toSorted((left, right) => left.sequence - right.sequence).slice(0, limitOf(input));
9625
- var sameEvent = (left, right) => left.id === right.id && left.execution_id === right.execution_id && left.child_execution_id === right.child_execution_id && left.type === right.type && left.sequence === right.sequence && left.cursor === right.cursor && exports_shared_schema.canonicalEquals(left.content ?? null, right.content ?? null) && exports_shared_schema.canonicalEquals(left.data ?? {}, right.data ?? {});
9710
+ var sameEventPayload = (left, right) => left.id === right.id && left.execution_id === right.execution_id && left.child_execution_id === right.child_execution_id && left.type === right.type && left.cursor === right.cursor && exports_shared_schema.canonicalEquals(left.content ?? null, right.content ?? null) && exports_shared_schema.canonicalEquals(left.data ?? {}, right.data ?? {});
9711
+ var sameEvent = (left, right) => left.sequence === right.sequence && sameEventPayload(left, right);
9626
9712
  var findExisting = (events, input) => events.find((event) => event.cursor === input.cursor || event.sequence === input.sequence);
9627
9713
  var duplicateEventError = (input) => EventLogError.make({ message: `DuplicateExecutionEvent:${input.execution_id}:${input.sequence}` });
9628
9714
  var orderViolationError = (input, previous) => EventLogError.make({
@@ -9727,6 +9813,20 @@ var layerFromRepository = Layer39.effect(Service41, Effect41.gen(function* () {
9727
9813
  yield* recordEventAppended(event.type);
9728
9814
  return event;
9729
9815
  }),
9816
+ appendNext: Effect41.fn("EventLog.repository.appendNext")(function* (input) {
9817
+ yield* Effect41.annotateCurrentSpan({
9818
+ "relay.execution.id": input.execution_id,
9819
+ "relay.event.id": input.id,
9820
+ "relay.event.type": input.type
9821
+ });
9822
+ const result = yield* repository.appendNext(input).pipe(Effect41.mapError(mapRepositoryAppendError));
9823
+ if (result.inserted) {
9824
+ yield* PubSub5.publish(pubsub, result.event);
9825
+ yield* repository.notifyAppended(result.event).pipe(Effect41.catch((error5) => Effect41.logWarning("EventLog append notify failed", error5)));
9826
+ yield* recordEventAppended(result.event.type);
9827
+ }
9828
+ return result.event;
9829
+ }),
9730
9830
  replay: Effect41.fn("EventLog.repository.replay")(function* (input) {
9731
9831
  yield* Effect41.annotateCurrentSpan("relay.execution.id", input.executionId);
9732
9832
  const replay = yield* loadReplay(input);
@@ -9783,6 +9883,34 @@ var memoryLayer32 = Layer39.effect(Service41, Effect41.gen(function* () {
9783
9883
  yield* recordEventAppended(input.type);
9784
9884
  return input;
9785
9885
  }),
9886
+ appendNext: Effect41.fn("EventLog.memory.appendNext")(function* (input) {
9887
+ const result = yield* Ref10.modify((store) => {
9888
+ const existing = HashMap2.get(store, input.execution_id).pipe(Option6.getOrElse(() => []));
9889
+ const duplicate = existing.find((event2) => event2.cursor === input.cursor);
9890
+ if (duplicate !== undefined) {
9891
+ const candidate = { ...input, sequence: duplicate.sequence };
9892
+ if (!sameEvent(duplicate, candidate))
9893
+ return [{ _tag: "error", error: duplicateEventError(candidate) }, store];
9894
+ return [{ _tag: "event", event: duplicate, inserted: false }, store];
9895
+ }
9896
+ const { minimumSequence, ...eventInput } = input;
9897
+ const event = {
9898
+ ...eventInput,
9899
+ sequence: Math.max((existing.at(-1)?.sequence ?? -1) + 1, minimumSequence ?? 0)
9900
+ };
9901
+ return [
9902
+ { _tag: "event", event, inserted: true },
9903
+ HashMap2.set(store, input.execution_id, [...existing, event])
9904
+ ];
9905
+ })(events);
9906
+ if (result._tag === "error")
9907
+ return yield* result.error;
9908
+ if (result.inserted) {
9909
+ yield* PubSub5.publish(pubsub, result.event);
9910
+ yield* recordEventAppended(result.event.type);
9911
+ }
9912
+ return result.event;
9913
+ }),
9786
9914
  replay: Effect41.fn("EventLog.memory.replay")(function* (input) {
9787
9915
  yield* Effect41.annotateCurrentSpan("relay.execution.id", input.executionId);
9788
9916
  const replay = yield* loadReplay(input);
@@ -9827,18 +9955,28 @@ var memoryLayer32 = Layer39.effect(Service41, Effect41.gen(function* () {
9827
9955
  })
9828
9956
  });
9829
9957
  }));
9830
- var appendIdempotentTo = Function6.dual(2, (eventLog, input) => eventLog.append(input).pipe(Effect41.catchTag("EventLogError", (error5) => eventLog.findBySequenceOrCursor({
9831
- executionId: input.execution_id,
9832
- sequence: input.sequence,
9833
- cursor: input.cursor
9834
- }).pipe(Effect41.flatMap((existing) => Option6.match(existing, {
9958
+ var appendIdempotentTo = Function6.dual(2, (eventLog, input) => eventLog.appendNext({
9959
+ id: input.id,
9960
+ execution_id: input.execution_id,
9961
+ ...input.child_execution_id === undefined ? {} : { child_execution_id: input.child_execution_id },
9962
+ type: input.type,
9963
+ cursor: input.cursor,
9964
+ ...input.content === undefined ? {} : { content: input.content },
9965
+ ...input.data === undefined ? {} : { data: input.data },
9966
+ created_at: input.created_at,
9967
+ minimumSequence: input.sequence
9968
+ }).pipe(Effect41.catchTag("EventLogError", (error5) => eventLog.findByCursor({ executionId: input.execution_id, cursor: input.cursor }).pipe(Effect41.flatMap(Option6.match({
9835
9969
  onNone: () => Effect41.fail(error5),
9836
- onSome: (event) => sameEvent(event, input) ? Effect41.succeed(event) : Effect41.fail(error5)
9970
+ onSome: (event) => sameEventPayload(event, input) ? Effect41.succeed(event) : Effect41.fail(error5)
9837
9971
  })), Effect41.mapError(() => error5)))));
9838
9972
  var append3 = Effect41.fn("EventLog.append.call")(function* (input) {
9839
9973
  const service = yield* Service41;
9840
9974
  return yield* service.append(input);
9841
9975
  });
9976
+ var appendNext2 = Effect41.fn("EventLog.appendNext.call")(function* (input) {
9977
+ const service = yield* Service41;
9978
+ return yield* service.appendNext(input);
9979
+ });
9842
9980
  var appendIdempotent = Effect41.fn("EventLog.appendIdempotent.call")(function* (input) {
9843
9981
  const service = yield* Service41;
9844
9982
  return yield* appendIdempotentTo(service, input);
@@ -9978,7 +10116,7 @@ var createTimeoutSchedule = Effect42.fn("WaitService.createTimeoutSchedule")(fun
9978
10116
  var complete = Effect42.fn("WaitService.complete")(function* (repository, eventLog, input, event) {
9979
10117
  const result = yield* repository.completeWait(input).pipe(Effect42.mapError(mapRepositoryError2));
9980
10118
  if (result.transitioned) {
9981
- yield* eventLog.append(event(result.wait)).pipe(Effect42.mapError(mapEventLogError));
10119
+ yield* appendIdempotentTo(eventLog, event(result.wait)).pipe(Effect42.mapError(mapEventLogError));
9982
10120
  }
9983
10121
  return result;
9984
10122
  });
@@ -9998,7 +10136,7 @@ var layer34 = Layer40.effect(Service42, Effect42.gen(function* () {
9998
10136
  }
9999
10137
  yield* repository.acceptEnvelope({ envelope: input.envelope, waitId: input.waitId }).pipe(Effect42.mapError((error5) => WaitServiceError.make({ message: error5.message })));
10000
10138
  const wait = yield* repository.getWait(input.waitId).pipe(Effect42.mapError((error5) => WaitServiceError.make({ message: error5.message })), Effect42.flatMap((record2) => record2 === undefined ? Effect42.fail(WaitServiceError.make({ message: `Wait ${input.waitId} was not persisted` })) : Effect42.succeed(record2)));
10001
- yield* eventLog.append(waitCreatedEvent(input, wait)).pipe(Effect42.mapError(mapEventLogError));
10139
+ yield* appendIdempotentTo(eventLog, waitCreatedEvent(input, wait)).pipe(Effect42.mapError(mapEventLogError));
10002
10140
  if (input.envelope.wait.timeout !== undefined) {
10003
10141
  yield* createTimeoutSchedule(schedules, input.waitId, wait, input.envelope.wait.timeout);
10004
10142
  }
@@ -10018,7 +10156,7 @@ var layer34 = Layer40.effect(Service42, Effect42.gen(function* () {
10018
10156
  ...input.correlationKey === undefined ? {} : { correlationKey: input.correlationKey },
10019
10157
  ...input.metadata === undefined ? {} : { metadata: input.metadata }
10020
10158
  }).pipe(Effect42.mapError((error5) => WaitServiceError.make({ message: error5.message })));
10021
- yield* eventLog.append(waitCreatedEvent(input, wait)).pipe(Effect42.mapError(mapEventLogError));
10159
+ yield* appendIdempotentTo(eventLog, waitCreatedEvent(input, wait)).pipe(Effect42.mapError(mapEventLogError));
10022
10160
  if (input.timeout !== undefined) {
10023
10161
  yield* createTimeoutSchedule(schedules, input.waitId, wait, input.timeout);
10024
10162
  }
@@ -10136,11 +10274,17 @@ var requestedEvent = (input) => ({
10136
10274
  },
10137
10275
  created_at: input.createdAt
10138
10276
  });
10139
- var sameToolEventPayload = (left, right) => left.id === right.id && left.execution_id === right.execution_id && left.child_execution_id === right.child_execution_id && left.type === right.type && left.cursor === right.cursor && left.created_at === right.created_at && exports_shared_schema.canonicalEquals(left.data ?? {}, right.data ?? {});
10140
- var ensureToolEvent = (eventLog, event) => eventLog.findByCursor({ executionId: event.execution_id, cursor: event.cursor }).pipe(Effect43.mapError(mapEventLogError2), Effect43.flatMap(Option8.match({
10141
- onNone: () => appendIdempotentTo(eventLog, event).pipe(Effect43.mapError(mapEventLogError2), Effect43.asVoid),
10142
- onSome: (existing) => sameToolEventPayload(existing, event) ? Effect43.void : Effect43.fail(ToolRuntimeError.make({ message: "EventLogError" }))
10143
- })));
10277
+ var ensureToolEvent = (eventLog, event) => eventLog.appendNext({
10278
+ id: event.id,
10279
+ execution_id: event.execution_id,
10280
+ ...event.child_execution_id === undefined ? {} : { child_execution_id: event.child_execution_id },
10281
+ type: event.type,
10282
+ cursor: event.cursor,
10283
+ ...event.content === undefined ? {} : { content: event.content },
10284
+ ...event.data === undefined ? {} : { data: event.data },
10285
+ created_at: event.created_at,
10286
+ minimumSequence: event.sequence
10287
+ }).pipe(Effect43.mapError(mapEventLogError2), Effect43.asVoid);
10144
10288
  var resultEvent = (input, result, sequence) => ({
10145
10289
  id: Identifiers.eventId(input.executionId, input.call.id, "tool-result"),
10146
10290
  execution_id: input.executionId,
@@ -10268,6 +10412,7 @@ var resolveApproval = (waits, eventLog, input) => Effect43.gen(function* () {
10268
10412
  return yield* waitRequested(input, waitId2);
10269
10413
  }
10270
10414
  if (existing.state === "open") {
10415
+ yield* appendIdempotentTo(eventLog, approvalRequestedEvent({ ...input, createdAt: existing.createdAt }, waitId2)).pipe(Effect43.mapError(mapEventLogError2));
10271
10416
  return yield* waitRequested(input, waitId2);
10272
10417
  }
10273
10418
  const approved = existing.state === "resolved" && existing.metadata.approved === true;
@@ -10283,8 +10428,9 @@ var recordRequested = (repository, eventLog, input, tool) => repository.ensureCa
10283
10428
  placement: tool.placement ?? { kind: "local" },
10284
10429
  createdAt: input.createdAt
10285
10430
  }).pipe(Effect43.mapError(mapRepositoryError3), Effect43.tap((call) => ensureToolEvent(eventLog, requestedEvent({ ...input, createdAt: call.createdAt }))));
10286
- var repairResultEvent = (eventLog, input, record2) => eventLog.maxSequence(input.executionId).pipe(Effect43.mapError(mapEventLogError2), Effect43.flatMap((max) => ensureToolEvent(eventLog, resultEvent({ ...input, createdAt: record2.createdAt - 1 }, record2.result, (max ?? input.eventSequence) + 1))));
10287
- var recordReceived = (repository, eventLog, input, result) => repository.recordResult({ executionId: input.executionId, result, createdAt: input.createdAt + 1 }).pipe(Effect43.catchTag("DuplicateToolResult", () => repository.getResult(input.executionId, result.call_id).pipe(Effect43.mapError(mapRepositoryError3), Effect43.flatMap((existing) => existing === undefined ? Effect43.fail(ToolRuntimeError.make({ message: "DuplicateToolResult" })) : Effect43.succeed(existing)))), Effect43.mapError(preserveRecordResultError), Effect43.flatMap((record2) => eventLog.maxSequence(input.executionId).pipe(Effect43.mapError(mapEventLogError2), Effect43.flatMap((max) => appendIdempotentTo(eventLog, resultEvent(input, record2.result, (max ?? input.eventSequence) + 1)).pipe(Effect43.mapError(mapEventLogError2))), Effect43.as(record2.result))));
10431
+ var repairResultEvent = (eventLog, input, record2) => ensureToolEvent(eventLog, resultEvent({ ...input, createdAt: record2.createdAt - 1 }, record2.result, input.eventSequence + 1));
10432
+ var persistReceived = (repository, input, result) => repository.recordResult({ executionId: input.executionId, result, createdAt: input.createdAt + 1 }).pipe(Effect43.catchTag("DuplicateToolResult", () => repository.getResult(input.executionId, result.call_id).pipe(Effect43.mapError(mapRepositoryError3), Effect43.flatMap((existing) => existing === undefined ? Effect43.fail(ToolRuntimeError.make({ message: "DuplicateToolResult" })) : Effect43.succeed(existing)))), Effect43.mapError(preserveRecordResultError));
10433
+ var recordReceived = (eventLog, input, record2) => ensureToolEvent(eventLog, resultEvent({ ...input, createdAt: record2.createdAt - 1 }, record2.result, input.eventSequence + 1)).pipe(Effect43.as(record2.result));
10288
10434
  var nonEmptyName = (name) => Schema40.decodeUnknownSync(exports_shared_schema.NonEmptyString)(name);
10289
10435
  var needsApprovalFromEffectTool = (tool) => tool.needsApproval === undefined ? undefined : typeof tool.needsApproval === "boolean" ? tool.needsApproval : true;
10290
10436
  var definitionFromEffectTool = (modelTool, options) => ({
@@ -10431,7 +10577,25 @@ var makeService = (initialTools) => Effect43.gen(function* () {
10431
10577
  register: Effect43.fn("ToolRuntime.register")((registeredTool) => registerTool(tools, registeredTool)),
10432
10578
  definitions: Ref11.get(tools).pipe(Effect43.map((registry) => Chunk.toReadonlyArray(Chunk.map(registry, (registeredTool) => registeredTool.definition)))),
10433
10579
  registeredTools: Ref11.get(tools).pipe(Effect43.map(Chunk.toReadonlyArray)),
10580
+ prepare: Effect43.fn("ToolRuntime.prepare")(function* (input) {
10581
+ const stored = yield* Ref11.get(tools);
10582
+ const registry = (input.extraTools ?? []).reduce(upsertTool, stored);
10583
+ const registeredTool = Chunk.findFirst(registry, sameToolName(input.call.name)).pipe(Option8.getOrUndefined);
10584
+ if (registeredTool === undefined)
10585
+ return yield* ToolNotRegistered.make({ tool_name: input.call.name });
10586
+ yield* ensureAllowed(registeredTool, input);
10587
+ yield* validateInput(registeredTool, input);
10588
+ yield* recordRequested(repository, eventLog, input, registeredTool);
10589
+ if (input.onRequested !== undefined)
10590
+ yield* input.onRequested;
10591
+ }),
10434
10592
  run: Effect43.fn("ToolRuntime.run")(function* (input) {
10593
+ let settlementSequence;
10594
+ const beginSettlement = Effect43.suspend(() => {
10595
+ if (settlementSequence !== undefined)
10596
+ return Effect43.succeed(settlementSequence);
10597
+ return (input.beforeSettlement ?? Effect43.succeed(input.eventSequence)).pipe(Effect43.tap((sequence) => Effect43.sync(() => settlementSequence = sequence)));
10598
+ });
10435
10599
  const stored = yield* Ref11.get(tools);
10436
10600
  const registry = (input.extraTools ?? []).reduce(upsertTool, stored);
10437
10601
  const registeredTool = Chunk.findFirst(registry, sameToolName(input.call.name)).pipe(Option8.getOrUndefined);
@@ -10442,8 +10606,11 @@ var makeService = (initialTools) => Effect43.gen(function* () {
10442
10606
  yield* ensureAllowed(registeredTool, input);
10443
10607
  yield* validateInput(registeredTool, input);
10444
10608
  const call = yield* recordRequested(repository, eventLog, input, registeredTool);
10609
+ if (input.onRequested !== undefined)
10610
+ yield* input.onRequested;
10445
10611
  const existingResult = yield* repository.getResult(input.executionId, input.call.id).pipe(Effect43.mapError(mapRepositoryError3));
10446
10612
  if (existingResult !== undefined) {
10613
+ yield* beginSettlement;
10447
10614
  yield* repairResultEvent(eventLog, input, existingResult);
10448
10615
  return existingResult.result;
10449
10616
  }
@@ -10451,26 +10618,46 @@ var makeService = (initialTools) => Effect43.gen(function* () {
10451
10618
  if (registeredTool.definition.needs_approval === true) {
10452
10619
  const bypass = yield* hasPermissionApprovalBypass(waits, input);
10453
10620
  if (!bypass) {
10454
- const decision = yield* resolveApproval(waits, eventLog, input);
10455
- effectiveInput = { ...input, eventSequence: input.eventSequence + 2, createdAt: input.createdAt + 2 };
10621
+ const sequence = yield* beginSettlement;
10622
+ effectiveInput = {
10623
+ ...input,
10624
+ eventSequence: sequence,
10625
+ createdAt: input.createdAt + sequence - input.eventSequence
10626
+ };
10627
+ const decision = yield* resolveApproval(waits, eventLog, effectiveInput);
10628
+ effectiveInput = {
10629
+ ...effectiveInput,
10630
+ eventSequence: effectiveInput.eventSequence + 1,
10631
+ createdAt: effectiveInput.createdAt + 1
10632
+ };
10456
10633
  if (decision._tag === "denied") {
10457
- const denied = yield* recordReceived(repository, eventLog, effectiveInput, {
10634
+ const deniedRecord = yield* persistReceived(repository, effectiveInput, {
10458
10635
  call_id: input.call.id,
10459
10636
  output: null,
10460
10637
  error: decision.reason
10461
10638
  });
10639
+ const denied = yield* recordReceived(eventLog, effectiveInput, deniedRecord);
10462
10640
  yield* recordToolCall(input.call.name, "denied");
10463
10641
  return denied;
10464
10642
  }
10465
10643
  }
10466
10644
  }
10467
- const rawResult = call.placement.kind === "client" || call.placement.kind === "remote" ? yield* runExternalTool(repository, waits, call, effectiveInput) : yield* repository.beginAttempt({
10645
+ const executeHandler = call.placement.kind === "client" || call.placement.kind === "remote" ? runExternalTool(repository, waits, call, effectiveInput) : repository.beginAttempt({
10468
10646
  executionId: input.executionId,
10469
10647
  callId: input.call.id,
10470
10648
  startedAt: effectiveInput.createdAt
10471
10649
  }).pipe(Effect43.mapError(mapRepositoryError3), Effect43.flatMap(() => finalToolResult(registeredTool, effectiveInput, call.idempotencyKey)), Effect43.catchTag("ToolExecutionFailed", (error5) => Effect43.succeed(placementFailureResult(input, error5.message))));
10472
- const result = input.transformResult === undefined || rawResult.error !== undefined ? rawResult : yield* input.transformResult(rawResult);
10473
- const received = yield* recordReceived(repository, eventLog, effectiveInput, result);
10650
+ const record2 = yield* Effect43.uninterruptibleMask((restore) => restore(executeHandler).pipe(Effect43.flatMap((rawResult) => input.transformResult === undefined || rawResult.error !== undefined ? Effect43.succeed(rawResult) : input.transformResult(rawResult)), Effect43.flatMap((result2) => persistReceived(repository, effectiveInput, result2))));
10651
+ const result = record2.result;
10652
+ if (effectiveInput === input) {
10653
+ const sequence = yield* beginSettlement;
10654
+ effectiveInput = {
10655
+ ...input,
10656
+ eventSequence: sequence,
10657
+ createdAt: input.createdAt + sequence - input.eventSequence
10658
+ };
10659
+ }
10660
+ const received = yield* recordReceived(eventLog, effectiveInput, record2);
10474
10661
  yield* recordToolCall(input.call.name, result.error === undefined ? "success" : "failure");
10475
10662
  return received;
10476
10663
  }).pipe(Effect43.tapError((error5) => recordToolCall(input.call.name, error5._tag === "ToolExecutionWaitRequested" ? "wait" : error5._tag === "ToolPermissionDenied" ? "denied" : "failure")));
@@ -11911,7 +12098,7 @@ var registeredTools2 = (state) => [
11911
12098
  ];
11912
12099
 
11913
12100
  // ../runtime/src/session/session-store-service.ts
11914
- import { Clock as Clock9, Context as Context51, Effect as Effect57, Function as Function12, Layer as Layer52, Ref as Ref13, Semaphore as Semaphore4 } from "effect";
12101
+ import { Clock as Clock9, Context as Context51, Effect as Effect57, Function as Function12, Layer as Layer52, Ref as Ref13, Semaphore as Semaphore5 } from "effect";
11915
12102
 
11916
12103
  class Service51 extends Context51.Service()("@relayfx/runtime/session/session-store-service/Service") {
11917
12104
  }
@@ -12053,7 +12240,7 @@ var toAppendInput = (input) => {
12053
12240
  var make4 = Effect57.fn("RelaySessionStore.make")(function* (sessionId, entryScope = "default", makeOptions) {
12054
12241
  const repository = yield* exports_session_repository.Service;
12055
12242
  const state = yield* Ref13.make(undefined);
12056
- const lock = yield* Semaphore4.make(1);
12243
+ const lock = yield* Semaphore5.make(1);
12057
12244
  const entryPrefix = `${sessionId}:entry:${entryScope}:`;
12058
12245
  const initialState = Effect57.fn("RelaySessionStore.initialState")(function* (input) {
12059
12246
  const current2 = yield* Ref13.get(state);
@@ -13029,13 +13216,13 @@ var layer47 = Layer58.effect(Service57, Effect63.gen(function* () {
13029
13216
  }));
13030
13217
 
13031
13218
  // ../runtime/src/tool/tool-transition-coordinator.ts
13032
- import { Context as Context58, Effect as Effect64, Layer as Layer59, Semaphore as Semaphore5 } from "effect";
13219
+ import { Context as Context58, Effect as Effect64, Layer as Layer59, Semaphore as Semaphore6 } from "effect";
13033
13220
  import { SqlClient as SqlClient29 } from "effect/unstable/sql/SqlClient";
13034
13221
 
13035
13222
  class Service58 extends Context58.Service()("@relayfx/runtime/tool/tool-transition-coordinator/Service") {
13036
13223
  }
13037
13224
  var make6 = Effect64.gen(function* () {
13038
- const semaphore = yield* Semaphore5.make(1);
13225
+ const semaphore = yield* Semaphore6.make(1);
13039
13226
  return Service58.of({
13040
13227
  coordinate: (effect) => semaphore.withPermit(effect)
13041
13228
  });
@@ -13043,7 +13230,7 @@ var make6 = Effect64.gen(function* () {
13043
13230
  var memoryLayer41 = Layer59.effect(Service58, make6);
13044
13231
  var sqlLayer = Layer59.effect(Service58, Effect64.gen(function* () {
13045
13232
  const sql = yield* SqlClient29;
13046
- const semaphore = yield* Semaphore5.make(1);
13233
+ const semaphore = yield* Semaphore6.make(1);
13047
13234
  return Service58.of({
13048
13235
  coordinate: (effect) => semaphore.withPermit(sql.withTransaction(effect))
13049
13236
  });
@@ -15063,7 +15250,7 @@ var layer55 = (config) => Layer68.succeed(exports_steering.Steering, exports_ste
15063
15250
  }));
15064
15251
 
15065
15252
  // ../runtime/src/agent/relay-tool-executor.ts
15066
- import { Effect as Effect78, Layer as Layer69, Option as Option17, Schema as Schema71 } from "effect";
15253
+ import { Deferred as Deferred3, Effect as Effect78, Layer as Layer69, Option as Option17, Schema as Schema71 } from "effect";
15067
15254
  var jsonValue5 = (value) => Schema71.decodeUnknownSync(exports_shared_schema.JsonValue)(value);
15068
15255
  var errorDetail = (error5) => {
15069
15256
  switch (error5._tag) {
@@ -15091,47 +15278,103 @@ var boundResult = (config, result) => {
15091
15278
  return Effect78.succeed(result);
15092
15279
  return exports_tool_output.bound({ _tag: "Success", result: result.output, encodedResult: result.output }, { toolCallId: result.call_id, maxBytes: config.toolOutputMaxBytes }).pipe(Effect78.map((bounded) => ({ ...result, output: jsonValue5(bounded.encodedResult) })));
15093
15280
  };
15094
- var make8 = (config) => ({
15095
- execute: (request) => Effect78.gen(function* () {
15096
- const first = yield* config.allocator.current;
15097
- const call = {
15098
- id: exports_ids_schema.ToolCallId.make(request.call.id),
15099
- name: request.call.name,
15100
- input: jsonValue5(request.call.params)
15101
- };
15102
- const resumed = config.resumedToolCallId === call.id;
15103
- const existingRequest = resumed ? yield* hasRequestedEvent(config, call.id) : false;
15104
- const eventSequence = existingRequest ? first - 1 : first;
15105
- return yield* config.toolRuntime.run({
15106
- executionId: config.executionId,
15107
- call,
15108
- permissions: config.permissions,
15109
- eventSequence,
15110
- createdAt: config.startedAt + eventSequence - config.eventSequence,
15111
- ...config.extraTools === undefined ? {} : { extraTools: config.extraTools },
15112
- transformResult: (result) => boundResult(config, result)
15113
- }).pipe(Effect78.flatMap((result) => nextLoggedSequence2(config.eventLog, config.executionId, existingRequest ? first + 1 : first + 2).pipe(Effect78.flatMap(config.allocator.resetTo), Effect78.as(result.error === undefined ? { _tag: "Success", result: result.output, encodedResult: result.output } : {
15114
- _tag: "DomainFailure",
15115
- failure: result.error,
15116
- encodedFailure: result.error
15117
- }))), Effect78.catch((error5) => nextLoggedSequence2(config.eventLog, config.executionId, first).pipe(Effect78.flatMap(config.allocator.resetTo), Effect78.flatMap(() => {
15118
- if (error5._tag === "ToolExecutionWaitRequested") {
15119
- return Effect78.succeed({ _tag: "Suspend", token: error5.wait_id });
15120
- }
15121
- if (error5._tag === "ToolExecutionFailed") {
15122
- const failure2 = `${error5._tag}: ${errorDetail(error5)}`;
15123
- return Effect78.succeed({ _tag: "DomainFailure", failure: failure2, encodedFailure: failure2 });
15124
- }
15125
- const stage = error5._tag === "ToolPermissionDenied" ? "authorization" : error5._tag === "ToolInputInvalid" ? "decode-input" : error5._tag === "ToolNotRegistered" ? "missing-handler" : "handler";
15126
- return Effect78.fail(exports_tool_executor.FrameworkFailure.make({
15127
- stage,
15128
- tool: call.name,
15129
- message: `${error5._tag}: ${errorDetail(error5)}`
15130
- }));
15131
- }))));
15132
- })
15281
+ var batchKey = (request) => `${request.turn}:${request.toolCallBatch.calls.map((call) => call.id).join(":")}`;
15282
+ var gateKey = (turn, toolCallIndex) => `${turn}:${toolCallIndex}`;
15283
+ var gateFor = (gates, key4) => {
15284
+ const existing = gates.get(key4);
15285
+ if (existing !== undefined)
15286
+ return existing;
15287
+ const created = Deferred3.makeUnsafe();
15288
+ gates.set(key4, created);
15289
+ return created;
15290
+ };
15291
+ var callFrom = (call) => ({
15292
+ id: exports_ids_schema.ToolCallId.make(call.id),
15293
+ name: call.name,
15294
+ input: jsonValue5(call.params)
15295
+ });
15296
+ var frameworkFailure = (call, error5) => {
15297
+ const stage = error5._tag === "ToolPermissionDenied" ? "authorization" : error5._tag === "ToolInputInvalid" ? "decode-input" : error5._tag === "ToolNotRegistered" ? "missing-handler" : "handler";
15298
+ return exports_tool_executor.FrameworkFailure.make({
15299
+ stage,
15300
+ tool: call.name,
15301
+ message: `${error5._tag}: ${errorDetail(error5)}`
15302
+ });
15303
+ };
15304
+ var make8 = (config) => Effect78.sync(() => {
15305
+ const prepared = new Map;
15306
+ const settled = new Map;
15307
+ const awaitPrevious = (gates, request) => {
15308
+ if (request.toolCallIndex === 0 || config.resumedToolCallId === request.call.id)
15309
+ return Effect78.void;
15310
+ return Deferred3.await(gateFor(gates, gateKey(request.turn, request.toolCallIndex - 1)));
15311
+ };
15312
+ const completeSettlement = (request) => Deferred3.succeed(gateFor(settled, gateKey(request.turn, request.toolCallIndex)), undefined).pipe(Effect78.asVoid);
15313
+ return exports_tool_executor.ToolExecutor.of({
15314
+ execute: (request) => {
15315
+ const key4 = batchKey(request);
15316
+ const existingPreparation = prepared.get(key4);
15317
+ const preparation = existingPreparation ?? Deferred3.makeUnsafe();
15318
+ if (existingPreparation === undefined)
15319
+ prepared.set(key4, preparation);
15320
+ const prepareBatch = existingPreparation === undefined ? Effect78.gen(function* () {
15321
+ const first = yield* config.allocator.current;
15322
+ yield* Effect78.forEach(request.toolCallBatch.calls.entries(), ([toolCallIndex, batchCall]) => {
15323
+ const call = callFrom(batchCall);
15324
+ const eventSequence = first + toolCallIndex;
15325
+ return config.toolRuntime.prepare({
15326
+ executionId: config.executionId,
15327
+ call,
15328
+ permissions: config.permissions,
15329
+ eventSequence,
15330
+ createdAt: config.startedAt + eventSequence - config.eventSequence,
15331
+ ...config.extraTools === undefined ? {} : { extraTools: config.extraTools }
15332
+ }).pipe(Effect78.mapError((error5) => frameworkFailure(call, error5)));
15333
+ });
15334
+ const next = yield* nextLoggedSequence2(config.eventLog, config.executionId, first);
15335
+ yield* config.allocator.advanceTo(next);
15336
+ return next;
15337
+ }).pipe(Effect78.exit, Effect78.flatMap((exit) => Deferred3.done(preparation, exit)), Effect78.andThen(Deferred3.await(preparation)), Effect78.uninterruptible) : Deferred3.await(preparation);
15338
+ return Effect78.gen(function* () {
15339
+ yield* prepareBatch;
15340
+ let settlementSequence;
15341
+ const beginSettlement = Effect78.suspend(() => {
15342
+ if (settlementSequence !== undefined)
15343
+ return Effect78.succeed(settlementSequence);
15344
+ return awaitPrevious(settled, request).pipe(Effect78.andThen(config.allocator.current), Effect78.map((sequence) => sequence - 1), Effect78.tap((sequence) => Effect78.sync(() => settlementSequence = sequence)));
15345
+ });
15346
+ const first = yield* config.allocator.current;
15347
+ const call = callFrom(request.call);
15348
+ const existingRequest = yield* hasRequestedEvent(config, call.id);
15349
+ const eventSequence = existingRequest ? first - 1 : first;
15350
+ return yield* config.toolRuntime.run({
15351
+ executionId: config.executionId,
15352
+ call,
15353
+ permissions: config.permissions,
15354
+ eventSequence,
15355
+ createdAt: config.startedAt + eventSequence - config.eventSequence,
15356
+ ...config.extraTools === undefined ? {} : { extraTools: config.extraTools },
15357
+ beforeSettlement: beginSettlement,
15358
+ transformResult: (result) => boundResult(config, result)
15359
+ }).pipe(Effect78.flatMap((result) => nextLoggedSequence2(config.eventLog, config.executionId, existingRequest ? first + 1 : first + 2).pipe(Effect78.flatMap(config.allocator.advanceTo), Effect78.as(result.error === undefined ? { _tag: "Success", result: result.output, encodedResult: result.output } : {
15360
+ _tag: "DomainFailure",
15361
+ failure: result.error,
15362
+ encodedFailure: result.error
15363
+ }))), Effect78.catch((error5) => beginSettlement.pipe(Effect78.asVoid, Effect78.andThen(nextLoggedSequence2(config.eventLog, config.executionId, first)), Effect78.flatMap(config.allocator.advanceTo), Effect78.flatMap(() => {
15364
+ if (error5._tag === "ToolExecutionWaitRequested") {
15365
+ return Effect78.succeed({ _tag: "Suspend", token: error5.wait_id });
15366
+ }
15367
+ if (error5._tag === "ToolExecutionFailed") {
15368
+ const failure2 = `${error5._tag}: ${errorDetail(error5)}`;
15369
+ return Effect78.succeed({ _tag: "DomainFailure", failure: failure2, encodedFailure: failure2 });
15370
+ }
15371
+ return Effect78.fail(frameworkFailure(call, error5));
15372
+ }))), Effect78.tap((outcome) => outcome._tag === "Suspend" ? Effect78.void : completeSettlement(request)), Effect78.onInterrupt(() => completeSettlement(request)));
15373
+ });
15374
+ }
15375
+ });
15133
15376
  });
15134
- var layer56 = (config) => Layer69.succeed(exports_tool_executor.ToolExecutor, exports_tool_executor.ToolExecutor.of(make8(config)));
15377
+ var layer56 = (config) => Layer69.effect(exports_tool_executor.ToolExecutor, make8(config));
15135
15378
 
15136
15379
  // ../runtime/src/agent/relay-tool-output.ts
15137
15380
  import { Effect as Effect79, Function as Function14, Layer as Layer70, Option as Option18 } from "effect";
@@ -15182,6 +15425,7 @@ import { Effect as Effect80, Ref as Ref17 } from "effect";
15182
15425
  var make10 = (first) => Ref17.make(first).pipe(Effect80.map((ref) => ({
15183
15426
  allocate: (count) => Ref17.getAndUpdate(ref, (value) => value + count),
15184
15427
  current: Ref17.get(ref),
15428
+ advanceTo: (sequence) => Ref17.update(ref, (current2) => Math.max(current2, sequence)),
15185
15429
  resetTo: (sequence) => Ref17.set(ref, sequence)
15186
15430
  })));
15187
15431
 
@@ -15418,7 +15662,7 @@ var loopError = (error5, nextEventSequence5) => AgentLoopError.make({
15418
15662
  message: error5 instanceof Error ? `${error5.name}: ${error5.message}` : String(error5),
15419
15663
  next_event_sequence: nextEventSequence5
15420
15664
  });
15421
- var appendEvent = (eventLog, event, nextEventSequence5) => appendIdempotentTo(eventLog, event).pipe(Effect81.mapError((error5) => loopError(error5, nextEventSequence5)));
15665
+ var appendEvent = (eventLog, allocator, event, nextEventSequence5) => appendIdempotentTo(eventLog, event).pipe(Effect81.tap((appended) => allocator.advanceTo(appended.sequence + 1)), Effect81.mapError((error5) => loopError(error5, nextEventSequence5)));
15422
15666
  var compactionCommittedCursor = (executionId, checkpointId2) => `execution:${executionId}:agent-compaction:${checkpointId2}:committed`;
15423
15667
  var appendCompactionCommittedEvent = Effect81.fn("AgentLoop.appendCompactionCommittedEvent")(function* (eventLog, allocator, input, checkpoint) {
15424
15668
  if (input.sessionId === undefined)
@@ -15433,7 +15677,7 @@ var appendCompactionCommittedEvent = Effect81.fn("AgentLoop.appendCompactionComm
15433
15677
  session_id: input.sessionId,
15434
15678
  summary_present: checkpoint.summary !== undefined
15435
15679
  };
15436
- yield* appendEvent(eventLog, {
15680
+ yield* appendEvent(eventLog, allocator, {
15437
15681
  id: exports_ids_schema.EventId.make(`event:${input.executionId}:agent-compaction:${checkpoint.id}:committed`),
15438
15682
  execution_id: input.executionId,
15439
15683
  type: "agent.compaction.committed",
@@ -15719,7 +15963,10 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15719
15963
  const definitions2 = registered.map((tool3) => tool3.definition);
15720
15964
  yield* validateToolInputSchemaDigests(input, definitions2);
15721
15965
  const toolCallDecodeMaxRetries = yield* toolCallDecodeMaxRetriesConfig.pipe(Effect81.mapError((error5) => loopError(error5, input.eventSequence + 1)));
15722
- yield* appendEvent(eventLog, inputPreparedEvent(input, definitions2), input.eventSequence + 1);
15966
+ const durableMaxSequence = yield* eventLog.maxSequence(input.executionId).pipe(Effect81.mapError((error5) => loopError(error5, input.eventSequence + 1)));
15967
+ const nextEventSequence5 = Math.max(input.eventSequence + 1, (durableMaxSequence ?? -1) + 1);
15968
+ const allocator = yield* make10(nextEventSequence5);
15969
+ yield* appendEvent(eventLog, allocator, inputPreparedEvent(input, definitions2), input.eventSequence + 1);
15723
15970
  const toolOutputMaxBytes = yield* effectiveToolOutputMaxBytes(input);
15724
15971
  const compactionPolicy = input.agent.compaction_policy;
15725
15972
  const configuredCompactionOptions = compactionOptions(input.agent);
@@ -15743,9 +15990,6 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15743
15990
  input: jsonValue6(resumeSuspension.tool_params)
15744
15991
  };
15745
15992
  const storedHistory = resumeToolCall === undefined ? yield* loadStoredHistory(chats, input) : yield* restoreHistory(chats, input);
15746
- const durableMaxSequence = yield* eventLog.maxSequence(input.executionId).pipe(Effect81.mapError((error5) => loopError(error5, input.eventSequence + 1)));
15747
- const nextEventSequence5 = Math.max(input.eventSequence + 1, (durableMaxSequence ?? -1) + 1);
15748
- const allocator = yield* make10(nextEventSequence5);
15749
15993
  const onCheckpointCommitted = (result) => appendCompactionCommittedEvent(eventLog, allocator, input, result.checkpoint).pipe(Effect81.andThen(layerOptions?.onCheckpointCommitted?.(result) ?? Effect81.void));
15750
15994
  const durableHistory = Option19.isNone(sessionRepository) ? storedHistory : yield* reconcileCompactionCheckpoint(sessionRepository.value, chats, input, storedHistory, onCheckpointCommitted, resumeSuspension === undefined);
15751
15995
  const continuingDurableHistory = durableHistory !== undefined;
@@ -15805,7 +16049,8 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15805
16049
  const agent = exports_agent.make({
15806
16050
  name: input.agent.name,
15807
16051
  toolkit,
15808
- policy: turnPolicyFromDefinition(input.agent)
16052
+ policy: turnPolicyFromDefinition(input.agent),
16053
+ ...input.agent.tool_execution === undefined ? {} : { toolExecution: input.agent.tool_execution }
15809
16054
  });
15810
16055
  if (toolOutputMaxBytes !== undefined && Option19.isNone(blobStore)) {
15811
16056
  return yield* AgentLoopError.make({
@@ -15867,7 +16112,7 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15867
16112
  const tokenBudget = input.agent.token_budget;
15868
16113
  const enforceBudget = (state) => tokenBudget === undefined || state.tokensUsed < tokenBudget ? Effect81.void : Effect81.gen(function* () {
15869
16114
  const budgetSequence = yield* allocator.allocate(1);
15870
- yield* appendEvent(eventLog, budgetExceededEvent(input, state.tokensUsed, tokenBudget, budgetSequence), budgetSequence + 1);
16115
+ yield* appendEvent(eventLog, allocator, budgetExceededEvent(input, state.tokensUsed, tokenBudget, budgetSequence), budgetSequence + 1);
15871
16116
  return yield* AgentLoopBudgetExceeded.make({
15872
16117
  tokens_used: state.tokensUsed,
15873
16118
  token_budget: tokenBudget,
@@ -15881,13 +16126,13 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15881
16126
  if (part.type === "text-delta") {
15882
16127
  const sequence = yield* allocator.allocate(1);
15883
16128
  const deltaIndex = sequence - input.eventSequence - 1;
15884
- yield* appendEvent(eventLog, outputDeltaEvent(input, part, deltaIndex), sequence + 1);
16129
+ yield* appendEvent(eventLog, allocator, outputDeltaEvent(input, part, deltaIndex), sequence + 1);
15885
16130
  return { ...state, text: `${state.text}${part.delta}` };
15886
16131
  }
15887
16132
  if (part.type === "reasoning" || part.type === "reasoning-delta") {
15888
16133
  const sequence = yield* allocator.allocate(1);
15889
16134
  const deltaIndex = sequence - input.eventSequence - 1;
15890
- yield* appendEvent(eventLog, reasoningDeltaEvent(input, part, deltaIndex), sequence + 1);
16135
+ yield* appendEvent(eventLog, allocator, reasoningDeltaEvent(input, part, deltaIndex), sequence + 1);
15891
16136
  return state;
15892
16137
  }
15893
16138
  if (part.type === "tool-params-start") {
@@ -15896,7 +16141,7 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15896
16141
  if (part.type === "tool-params-delta") {
15897
16142
  const sequence = yield* allocator.allocate(1);
15898
16143
  const deltaIndex = state.toolCallDeltaIndexes[part.id] ?? 0;
15899
- yield* appendEvent(eventLog, toolCallDeltaEvent(input, part, state.toolCallNames[part.id], sequence, deltaIndex), sequence + 1);
16144
+ yield* appendEvent(eventLog, allocator, toolCallDeltaEvent(input, part, state.toolCallNames[part.id], sequence, deltaIndex), sequence + 1);
15900
16145
  return {
15901
16146
  ...state,
15902
16147
  toolCallDeltaIndexes: { ...state.toolCallDeltaIndexes, [part.id]: deltaIndex + 1 }
@@ -15905,7 +16150,7 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15905
16150
  if (part.type === "finish") {
15906
16151
  const finish = part;
15907
16152
  const sequence = yield* allocator.allocate(1);
15908
- yield* appendEvent(eventLog, usageReportedEvent(input, finish, sequence), sequence + 1);
16153
+ yield* appendEvent(eventLog, allocator, usageReportedEvent(input, finish, sequence), sequence + 1);
15909
16154
  yield* recordModelUsage({
15910
16155
  provider: input.agent.model.provider,
15911
16156
  model: input.agent.model.model,
@@ -15973,7 +16218,7 @@ var make11 = (layerOptions) => Effect81.gen(function* () {
15973
16218
  const schemaRef = input.agent.output_schema_ref;
15974
16219
  const structuredOutput = schemaRef === undefined || finalState.transcript === undefined ? undefined : yield* Chat.fromPrompt(finalState.transcript).pipe(Effect81.flatMap((chat) => runStructuredTurn(languageModels, schemas, chat, input, schemaRef, completedSequence + 1)));
15975
16220
  const structuredPart = structuredOutput === undefined || schemaRef === undefined ? [] : [{ type: "structured", value: structuredOutput, schema_ref: schemaRef }];
15976
- yield* appendEvent(eventLog, outputCompletedEvent(input, [...completedContent(finalState.text), ...structuredPart], finalState.text, completedSequence, structuredOutput), completedSequence + 1);
16221
+ yield* appendEvent(eventLog, allocator, outputCompletedEvent(input, [...completedContent(finalState.text), ...structuredPart], finalState.text, completedSequence, structuredOutput), completedSequence + 1);
15977
16222
  return {
15978
16223
  metadata: {
15979
16224
  model_output: finalState.text,
@@ -17537,6 +17782,7 @@ var registerAgentPayload = Effect90.fn("Client.registerAgentPayload")(function*
17537
17782
  ...input.permission_rules === undefined ? {} : { permission_rules: input.permission_rules },
17538
17783
  ...input.compaction_policy === undefined ? {} : { compaction_policy: input.compaction_policy },
17539
17784
  ...turnPolicy,
17785
+ ...input.agent.toolExecution === undefined ? {} : { tool_execution: input.agent.toolExecution },
17540
17786
  ...input.max_wait_turns === undefined ? {} : { max_wait_turns: input.max_wait_turns },
17541
17787
  ...input.token_budget === undefined ? {} : { token_budget: input.token_budget },
17542
17788
  ...input.child_run_presets === undefined ? {} : { child_run_presets: input.child_run_presets },
@@ -17911,6 +18157,16 @@ var layerFromRuntime3 = Layer80.effect(Service, Effect90.gen(function* () {
17911
18157
  const executionId = exports_ids_schema.ExecutionId.make(input.correlation_key ?? `execution:send:${identity2}`);
17912
18158
  const envelopeId = exports_ids_schema.EnvelopeId.make(`${executionId}:envelope:${identity2}`);
17913
18159
  const createdAt = yield* Clock19.currentTimeMillis;
18160
+ const execution = yield* executionRepository.get(executionId).pipe(Effect90.mapError(toClientError));
18161
+ if (execution === undefined) {
18162
+ yield* executionRepository.create({
18163
+ id: executionId,
18164
+ rootAddressId: input.from,
18165
+ status: "queued",
18166
+ metadata: { operation: "envelope-send" },
18167
+ createdAt
18168
+ }).pipe(Effect90.catchIf(Schema83.is(exports_execution_repository.DuplicateExecution), () => Effect90.void), Effect90.mapError(toClientError));
18169
+ }
17914
18170
  const maxSequence3 = yield* eventLog.maxSequence(executionId).pipe(Effect90.mapError(toClientError));
17915
18171
  return yield* envelopes.send({
17916
18172
  envelopeId,