@robbeverhelst/do 1.274.0 → 1.276.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/do.js +940 -848
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -21291,913 +21291,937 @@ var houseUpkeepYearSchema = object({
21291
21291
  });
21292
21292
  var houseUpkeepYearQuerySchema = object({ year: exports_coerce.number().int().min(2000).max(2100).optional() }).strict();
21293
21293
 
21294
- // ../../packages/schema/src/contracts/health-records.ts
21295
- var BODY_REGION_VALUES = [
21296
- "head",
21297
- "face",
21298
- "eyes",
21299
- "ears",
21300
- "nose",
21301
- "mouth",
21302
- "throat",
21303
- "neck",
21304
- "chest",
21305
- "upper_back",
21306
- "lower_back",
21307
- "epigastric",
21308
- "ruq",
21309
- "luq",
21310
- "periumbilical",
21311
- "rlq",
21312
- "llq",
21313
- "lower_abdomen",
21314
- "pelvis",
21315
- "shoulder_l",
21316
- "shoulder_r",
21317
- "arm_l",
21318
- "arm_r",
21319
- "elbow_l",
21320
- "elbow_r",
21321
- "wrist_l",
21322
- "wrist_r",
21323
- "hand_l",
21324
- "hand_r",
21325
- "hip_l",
21326
- "hip_r",
21327
- "thigh_l",
21328
- "thigh_r",
21329
- "knee_l",
21330
- "knee_r",
21331
- "calf_l",
21332
- "calf_r",
21333
- "ankle_l",
21334
- "ankle_r",
21335
- "foot_l",
21336
- "foot_r",
21337
- "skin",
21338
- "whole_body"
21339
- ];
21340
- var bodyRegionSchema = _enum2(BODY_REGION_VALUES);
21341
- var RED_FLAG_VALUES = [
21342
- "fever",
21343
- "vomiting",
21344
- "black_stools",
21345
- "blood",
21346
- "weight_loss",
21347
- "night_pain",
21348
- "chest_pain",
21349
- "short_of_breath"
21350
- ];
21351
- var redFlagSchema = _enum2(RED_FLAG_VALUES);
21352
- var redFlagsSchema = partialRecord(redFlagSchema, boolean3());
21353
- var HEALTH_CONDITION_STATUS_VALUES = [
21354
- "active",
21355
- "managed",
21356
- "resolved",
21357
- "suspected"
21358
- ];
21359
- var healthConditionStatusSchema = _enum2(HEALTH_CONDITION_STATUS_VALUES);
21360
- var HEALTH_EPISODE_STATUS_VALUES = ["open", "watching", "resolved"];
21361
- var healthEpisodeStatusSchema = _enum2(HEALTH_EPISODE_STATUS_VALUES);
21362
- var HEALTH_ENCOUNTER_KIND_VALUES = [
21363
- "gp",
21364
- "specialist",
21365
- "physio",
21366
- "dentist",
21367
- "lab_draw",
21368
- "er",
21369
- "tele",
21370
- "other"
21371
- ];
21372
- var healthEncounterKindSchema = _enum2(HEALTH_ENCOUNTER_KIND_VALUES);
21373
- var healthMedicationKindSchema = _enum2(["drug", "supplement"]);
21374
- var healthMedicationScheduleSchema = _enum2(["scheduled", "as_needed"]);
21375
- var HEALTH_DOSE_EFFECT_VALUES = ["none", "a_little", "helped", "worse"];
21376
- var healthDoseEffectSchema = _enum2(HEALTH_DOSE_EFFECT_VALUES);
21377
- var healthEntrySourceSchema = _enum2(["chat", "manual", "import"]);
21378
- var severitySchema = number2().int().min(0).max(10);
21379
- var fuzzyDateSchema = string2().regex(/^\d{4}(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\d|3[01]))?)?$/, "must be YYYY, YYYY-MM or YYYY-MM-DD");
21380
- var civilDateSchema2 = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD");
21381
- var title = string2().trim().min(1).max(200);
21382
- var text2 = (max) => string2().trim().min(1).max(max);
21383
- var instant = exports_coerce.date();
21384
- var spine = {
21385
- title: string2(),
21386
- createdAt: exports_coerce.date(),
21387
- updatedAt: exports_coerce.date()
21388
- };
21389
- var healthCareTeamMemberSchema = object({
21390
- contactId: string2(),
21391
- name: string2(),
21392
- phone: string2().nullable(),
21393
- label: string2().nullable()
21394
- });
21395
- var healthConditionViewSchema = createSelectSchema(healthConditions, {
21396
- bodyRegions: array(string2())
21397
- }).extend({
21398
- ...spine,
21399
- careTeam: array(healthCareTeamMemberSchema).default([])
21400
- });
21401
- var healthEpisodeViewSchema = createSelectSchema(healthEpisodes, {
21402
- startedAt: exports_coerce.date(),
21403
- endedAt: exports_coerce.date().nullable(),
21404
- redFlags: redFlagsSchema,
21405
- redFlagsCheckedAt: exports_coerce.date().nullable()
21406
- }).extend({
21407
- ...spine,
21408
- latestSeverity: number2().int().nullable(),
21409
- lastEntryAt: exports_coerce.date().nullable()
21410
- });
21411
- var healthSymptomEntrySchema = createSelectSchema(healthSymptomEntries, {
21412
- occurredAt: exports_coerce.date(),
21413
- recordedAt: exports_coerce.date(),
21414
- qualifiers: record(string2(), unknown())
21415
- });
21416
- var healthEncounterViewSchema = createSelectSchema(healthEncounters, {
21417
- at: exports_coerce.date(),
21418
- followUpAt: exports_coerce.date().nullable(),
21419
- questions: array(string2())
21420
- }).extend({
21421
- ...spine,
21422
- providerName: string2().nullable()
21423
- });
21424
- var healthMedicationViewSchema = createSelectSchema(healthMedications).extend({
21425
- ...spine,
21426
- lastTakenAt: exports_coerce.date().nullable()
21427
- });
21428
- var healthMedicationDoseSchema = createSelectSchema(healthMedicationDoses, {
21429
- takenAt: exports_coerce.date(),
21430
- createdAt: exports_coerce.date()
21431
- }).extend({
21432
- medicationTitle: string2()
21433
- });
21434
- var healthEpisodeDetailSchema = healthEpisodeViewSchema.extend({
21435
- entries: array(healthSymptomEntrySchema),
21436
- doses: array(healthMedicationDoseSchema),
21437
- encounters: array(healthEncounterViewSchema),
21438
- condition: healthConditionViewSchema.nullable()
21439
- });
21440
- var healthProfileSchema = createSelectSchema(healthProfiles, {
21441
- allergies: array(string2()),
21442
- updatedAt: exports_coerce.date()
21443
- }).extend({
21444
- notes: string2().nullable().default(null),
21445
- sex: string2().nullable().default(null)
21446
- });
21447
- var healthConsentStateSchema = object({
21448
- granted: boolean3(),
21449
- version: string2().nullable(),
21450
- grantedAt: exports_coerce.date().nullable()
21294
+ // ../../packages/schema/src/contracts/agent-chat.ts
21295
+ var agentConnectionSourceSchema = _enum2(["space", "env"]);
21296
+ var agentGatewayStatusSchema = _enum2(["connected", "offline", "not_connected"]);
21297
+ var agentGatewayStateSchema = object({
21298
+ status: agentGatewayStatusSchema,
21299
+ connectedAt: exports_coerce.date().nullable(),
21300
+ seenAt: exports_coerce.date().nullable(),
21301
+ disconnectedAt: exports_coerce.date().nullable()
21451
21302
  });
21452
- var HEALTH_CONSENT_VERSION = "2026-10-18";
21453
- var subject = { subjectNodeId: ulidSchema.nullish() };
21454
- var createHealthConditionInputSchema = object({
21455
- id: ulidSchema.optional(),
21456
- title,
21457
- status: healthConditionStatusSchema.optional(),
21458
- onset: fuzzyDateSchema.nullish(),
21459
- resolvedOn: civilDateSchema2.nullish(),
21460
- bodyRegions: array(bodyRegionSchema).max(10).optional(),
21461
- code: text2(40).nullish(),
21462
- notes: text2(4000).nullish(),
21463
- ...subject
21464
- }).strict();
21465
- var addHealthCareTeamInputSchema = object({ contactId: ulidSchema, label: text2(60).nullish() }).strict();
21466
- var updateHealthConditionInputSchema = createHealthConditionInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21467
- var episodeFields = object({
21468
- id: ulidSchema.optional(),
21469
- title,
21470
- status: healthEpisodeStatusSchema.optional(),
21471
- startedAt: instant.optional(),
21472
- bodyRegion: bodyRegionSchema.nullish(),
21473
- triggerText: text2(500).nullish(),
21474
- summary: text2(500).nullish(),
21475
- conditionId: ulidSchema.nullish(),
21476
- ...subject
21477
- }).strict();
21478
- var createHealthEpisodeInputSchema = episodeFields.extend({ endedAt: instant.nullish() }).strict().superRefine((v, ctx) => {
21479
- if (!v.endedAt)
21480
- return;
21481
- if (v.status && v.status !== "resolved") {
21482
- ctx.addIssue({
21483
- code: "custom",
21484
- path: ["endedAt"],
21485
- message: "only a resolved episode has an end"
21486
- });
21487
- }
21488
- if (v.endedAt.getTime() > Date.now()) {
21489
- ctx.addIssue({ code: "custom", path: ["endedAt"], message: "can't end in the future" });
21490
- }
21491
- if (v.endedAt.getTime() < (v.startedAt ?? new Date).getTime()) {
21492
- ctx.addIssue({ code: "custom", path: ["endedAt"], message: "can't end before it started" });
21493
- }
21303
+ var agentConnectionSchema = object({
21304
+ connected: boolean3(),
21305
+ source: agentConnectionSourceSchema.nullable(),
21306
+ endpoint: string2().nullable(),
21307
+ model: string2().nullable(),
21308
+ hasKey: boolean3(),
21309
+ agentId: string2().nullable(),
21310
+ agentName: string2().nullable().default(null),
21311
+ autoFile: boolean3(),
21312
+ updatedAt: exports_coerce.date().nullable(),
21313
+ gateway: agentGatewayStateSchema.nullable().default(null)
21494
21314
  });
21495
- var updateHealthEpisodeInputSchema = episodeFields.omit({ id: true, subjectNodeId: true }).extend({
21496
- endedAt: instant.nullish(),
21497
- redFlags: redFlagsSchema.optional()
21498
- }).partial().strict();
21499
- var symptomFields = {
21500
- symptom: text2(200),
21501
- occurredAt: instant.optional(),
21502
- bodyRegion: bodyRegionSchema.nullish(),
21503
- severity: severitySchema.nullish(),
21504
- severityGuessed: boolean3().optional(),
21505
- qualifiers: record(string2(), unknown()).optional(),
21506
- note: text2(2000).nullish(),
21507
- source: healthEntrySourceSchema.optional()
21508
- };
21509
- var logHealthSymptomInputSchema = object({ id: ulidSchema.optional(), ...symptomFields }).strict();
21510
- var correctHealthSymptomInputSchema = object({ id: ulidSchema.optional(), ...symptomFields }).partial().strict().refine((v) => Object.keys(v).some((k) => k !== "id" && k !== "source"), {
21511
- message: "a correction must change something"
21315
+ var agentEndpointSchema = string2().trim().max(2000).url().refine((value) => /^https?:\/\//i.test(value), "endpoint must be an http(s) URL");
21316
+ var saveAgentConnectionInputSchema = object({
21317
+ endpoint: agentEndpointSchema.nullable(),
21318
+ apiKey: string2().trim().min(1).max(4000).nullable().optional(),
21319
+ model: string2().trim().min(1).max(200).nullable().optional(),
21320
+ agentId: string2().trim().min(1).max(64).nullable().optional(),
21321
+ autoFile: boolean3().optional()
21322
+ }).strict().refine((input) => input.endpoint !== null || Boolean(input.agentId), {
21323
+ message: "a connection without an endpoint names its agent",
21324
+ path: ["agentId"]
21512
21325
  });
21513
- var createHealthEncounterInputSchema = object({
21514
- id: ulidSchema.optional(),
21515
- title: title.optional(),
21516
- kind: healthEncounterKindSchema.optional(),
21517
- at: instant,
21518
- episodeId: ulidSchema.nullish(),
21519
- providerContactId: ulidSchema.nullish(),
21520
- placeId: ulidSchema.nullish(),
21521
- eventId: ulidSchema.nullish(),
21522
- reason: text2(500).nullish(),
21523
- questions: array(text2(300)).max(30).optional(),
21524
- outcome: text2(4000).nullish(),
21525
- followUpAt: instant.nullish(),
21526
- ...subject
21527
- }).strict();
21528
- var updateHealthEncounterInputSchema = createHealthEncounterInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21529
- var createHealthMedicationInputSchema = object({
21530
- id: ulidSchema.optional(),
21531
- title,
21532
- kind: healthMedicationKindSchema.optional(),
21533
- schedule: healthMedicationScheduleSchema.optional(),
21534
- ingredient: text2(200).nullish(),
21535
- dose: text2(100).nullish(),
21536
- form: text2(100).nullish(),
21537
- startedOn: civilDateSchema2.nullish(),
21538
- stoppedOn: civilDateSchema2.nullish(),
21539
- reason: text2(500).nullish(),
21540
- prescribedByContactId: ulidSchema.nullish(),
21541
- habitId: ulidSchema.nullish(),
21542
- ...subject
21543
- }).strict();
21544
- var updateHealthMedicationInputSchema = createHealthMedicationInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21545
- var logHealthDoseInputSchema = object({
21546
- id: ulidSchema.optional(),
21547
- takenAt: instant.optional(),
21548
- amount: text2(100).nullish(),
21549
- effect: healthDoseEffectSchema.nullish(),
21550
- note: text2(1000).nullish(),
21551
- episodeId: ulidSchema.nullish(),
21552
- source: healthEntrySourceSchema.optional()
21553
- }).strict();
21554
- var updateHealthDoseInputSchema = logHealthDoseInputSchema.omit({ id: true, source: true }).partial().strict();
21555
- var updateHealthProfileInputSchema = object({
21556
- bloodGroup: string2().regex(/^(A|B|AB|O)[+-]$/, "must be like A+ or O-").nullish(),
21557
- allergies: array(text2(100)).max(30).optional(),
21558
- heightCm: number2().min(30).max(260).nullish(),
21559
- sex: text2(40).nullish(),
21560
- alcohol: text2(200).nullish(),
21561
- smoking: text2(200).nullish(),
21562
- exercise: text2(200).nullish(),
21563
- notes: text2(2000).nullish(),
21564
- emergencyContactId: ulidSchema.nullish(),
21565
- primaryGpContactId: ulidSchema.nullish()
21326
+ var agentPageContextSchema = object({
21327
+ route: string2().trim().min(1).max(500).startsWith("/"),
21328
+ nodeId: string2().trim().min(1).max(64).nullable(),
21329
+ focusArea: object({
21330
+ id: string2().trim().min(1).max(64),
21331
+ title: string2().trim().min(1).max(200)
21332
+ }).nullish()
21566
21333
  }).strict();
21567
- var grantHealthConsentInputSchema = object({ version: literal(HEALTH_CONSENT_VERSION) }).strict();
21568
- var healthEpisodeListQuerySchema = object({
21569
- status: healthEpisodeStatusSchema.optional()
21334
+ var echoDeviceSchema = _enum2(["phone", "desktop"]);
21335
+ var agentChatInputSchema = object({
21336
+ message: string2().trim().max(8000),
21337
+ context: agentPageContextSchema,
21338
+ threadId: string2().trim().min(1).max(64).optional(),
21339
+ steer: boolean3().optional(),
21340
+ attachments: array(string2().trim().min(1).max(64)).max(20).optional(),
21341
+ replyTo: string2().trim().min(1).max(64).optional(),
21342
+ device: echoDeviceSchema.optional()
21343
+ }).strict().refine((input) => input.message.length > 0 || (input.attachments?.length ?? 0) > 0, {
21344
+ message: "write something or attach a file",
21345
+ path: ["message"]
21570
21346
  });
21571
- var upsertHealthEpisodeInputSchema = episodeFields;
21572
- var logDoseFields = logHealthDoseInputSchema.omit({ episodeId: true, source: true }).extend({
21573
- medicationId: ulidSchema.optional(),
21574
- medication: text2(200).optional()
21347
+ var agentChatStopInputSchema = object({ threadId: string2().trim().min(1).max(64) }).strict();
21348
+ var agentChatStopResultSchema = object({ stop: _enum2(["sent", "offline"]) });
21349
+ var agentChatEventSchema = discriminatedUnion("type", [
21350
+ object({
21351
+ type: literal("turn"),
21352
+ id: string2(),
21353
+ threadId: string2(),
21354
+ since: string2().nullable()
21355
+ }),
21356
+ object({ type: literal("delta"), text: string2() }),
21357
+ object({ type: literal("done") }),
21358
+ object({ type: literal("error"), message: string2() }),
21359
+ object({
21360
+ type: literal("posted"),
21361
+ threadId: string2(),
21362
+ postId: string2(),
21363
+ delivery: _enum2(["sent", "waiting"])
21364
+ })
21365
+ ]);
21366
+ var agentChangeValueSchema = union([
21367
+ string2(),
21368
+ number2(),
21369
+ boolean3(),
21370
+ _null3(),
21371
+ array(string2())
21372
+ ]);
21373
+ var agentChangeFieldSchema = object({
21374
+ field: string2(),
21375
+ before: agentChangeValueSchema,
21376
+ after: agentChangeValueSchema,
21377
+ beforeLabel: string2().nullable().optional(),
21378
+ afterLabel: string2().nullable().optional()
21575
21379
  });
21576
- var logHealthInputSchema = object({
21577
- episodeId: ulidSchema.optional(),
21578
- episode: upsertHealthEpisodeInputSchema.optional(),
21579
- symptom: logHealthSymptomInputSchema.omit({ source: true }).optional(),
21580
- dose: logDoseFields.refine((d) => !!d.medicationId !== !!d.medication, {
21581
- message: "name the medication by medicationId or by medication, not both"
21380
+ var agentChangeSchema = object({
21381
+ entity: changeEntitySchema,
21382
+ id: string2(),
21383
+ op: changeOpSchema,
21384
+ changedAt: exports_coerce.date(),
21385
+ title: string2().nullable(),
21386
+ actor: actorRefSchema,
21387
+ cursor: string2().optional(),
21388
+ fields: array(agentChangeFieldSchema).optional(),
21389
+ checkIn: object({
21390
+ value: number2(),
21391
+ unit: string2().nullable(),
21392
+ measurementType: habitMeasurementTypeSchema
21582
21393
  }).optional()
21583
- }).strict().refine((v) => !!v.symptom || !!v.dose, { message: "log a symptom, a dose, or both" }).refine((v) => !(v.episodeId && v.episode), {
21584
- message: "name the episode by episodeId or describe it in episode, not both"
21585
- }).refine((v) => !v.symptom || !!v.episodeId || !!v.episode, {
21586
- message: "a symptom needs an episode (episodeId, or episode to find or start one)"
21587
21394
  });
21588
- var correctHealthInputSchema = object({ entryId: ulidSchema, change: correctHealthSymptomInputSchema }).strict();
21589
- var HEALTH_CHECK_IN_TRENDS = ["better", "same", "worse"];
21590
- var healthCheckInTrendSchema = _enum2(HEALTH_CHECK_IN_TRENDS);
21591
- var healthCheckInInputSchema = object({ trend: healthCheckInTrendSchema }).strict();
21592
- var HEALTH_UNDO_KIND_VALUES = ["entry", "dose", "episode"];
21593
- var healthUndoInputSchema = object({ kind: _enum2(HEALTH_UNDO_KIND_VALUES), id: ulidSchema }).strict();
21594
- var HEALTH_RECEIPT_KIND_VALUES = [
21595
- "symptom",
21596
- "correction",
21597
- "dose",
21598
- "episode",
21599
- "encounter"
21600
- ];
21601
- var healthReceiptItemSchema = object({
21602
- kind: _enum2(HEALTH_RECEIPT_KIND_VALUES),
21603
- id: string2(),
21604
- line: string2(),
21605
- guessed: array(string2()),
21606
- undo: healthUndoInputSchema
21395
+ var agentChangesPageSchema = object({
21396
+ data: array(agentChangeSchema),
21397
+ nextCursor: string2()
21607
21398
  });
21608
- var healthReceiptSchema = object({
21609
- episode: object({ id: string2(), title: string2(), created: boolean3() }).nullable(),
21610
- items: array(healthReceiptItemSchema),
21611
- entry: healthSymptomEntrySchema.nullable(),
21612
- dose: healthMedicationDoseSchema.nullable()
21399
+ var agentChangesQuerySchema = object({
21400
+ since: string2().refine((s) => s === "now" || /^\d+-\d+$/.test(s), {
21401
+ message: "since must be a cursor from a prior page's nextCursor, or 'now'"
21402
+ }),
21403
+ node: string2().trim().min(1).max(64).optional()
21613
21404
  });
21614
- var healthCourseDaySchema = object({
21615
- day: string2(),
21616
- severity: number2().int().nullable(),
21617
- entries: number2().int()
21405
+ var agentConfirmationKindSchema = _enum2(["delete", "cancel", "google", "orca", "bulk"]);
21406
+ var agentConfirmationStatusSchema = _enum2([
21407
+ "pending",
21408
+ "confirmed",
21409
+ "done",
21410
+ "failed",
21411
+ "declined"
21412
+ ]);
21413
+ var agentConfirmationItemSchema = object({
21414
+ id: string2(),
21415
+ title: string2().nullable(),
21416
+ area: string2().nullable().optional(),
21417
+ dueAt: exports_coerce.date().nullable().optional()
21618
21418
  });
21619
- var healthTriedSchema = object({
21620
- medicationId: string2(),
21621
- title: string2(),
21622
- doses: number2().int(),
21623
- effects: array(healthDoseEffectSchema),
21624
- lastTakenAt: exports_coerce.date(),
21625
- amount: string2().nullable().default(null)
21419
+ var agentConfirmationSchema = object({
21420
+ id: string2(),
21421
+ kind: agentConfirmationKindSchema,
21422
+ summary: string2(),
21423
+ items: array(agentConfirmationItemSchema),
21424
+ method: string2(),
21425
+ path: string2(),
21426
+ status: agentConfirmationStatusSchema,
21427
+ agent: object({ id: string2(), name: string2().nullable() }),
21428
+ createdAt: exports_coerce.date(),
21429
+ decidedAt: exports_coerce.date().nullable()
21626
21430
  });
21627
- var healthSummaryLabSchema = object({
21431
+ var agentUndoInputSchema = object({
21432
+ id: string2().trim().min(1).max(64),
21433
+ since: string2().regex(/^\d+-\d+$/, "since must be a change-feed cursor")
21434
+ }).strict();
21435
+ var agentUndoResultSchema = object({
21628
21436
  id: string2(),
21629
- specimenAt: exports_coerce.date(),
21630
- labName: string2().nullable(),
21631
- results: array(object({
21632
- name: string2(),
21633
- valueNum: number2().nullable(),
21634
- valueText: string2().nullable(),
21635
- unit: string2().nullable(),
21636
- refLow: number2().nullable(),
21637
- refHigh: number2().nullable(),
21638
- flag: _enum2(["low", "normal", "high"]).nullable()
21639
- }))
21437
+ undone: _enum2(["removed", "restored"])
21640
21438
  });
21641
- var HEALTH_TREND_KEYS = ["sleep", "weight"];
21642
- var healthTrendSchema = object({
21643
- key: _enum2(HEALTH_TREND_KEYS),
21644
- label: string2(),
21645
- unit: string2(),
21646
- points: array(object({ day: string2(), value: number2() }))
21439
+ var agentRedoResultSchema = object({
21440
+ id: string2(),
21441
+ redone: literal(true)
21647
21442
  });
21648
- var healthSummarySchema = object({
21649
- generatedAt: exports_coerce.date(),
21650
- patient: object({ name: string2().nullable() }).default({ name: null }),
21651
- episode: healthEpisodeViewSchema.nullable(),
21652
- course: array(healthCourseDaySchema),
21653
- entries: array(healthSymptomEntrySchema),
21654
- tried: array(healthTriedSchema),
21655
- conditions: array(healthConditionViewSchema),
21656
- medications: array(healthMedicationViewSchema),
21657
- profile: healthProfileSchema,
21658
- gp: object({ id: string2(), name: string2(), phone: string2().nullable() }).nullable(),
21659
- nextVisit: healthEncounterViewSchema.nullable(),
21660
- questions: array(string2()),
21661
- labs: array(healthSummaryLabSchema).default([]),
21662
- trends: array(healthTrendSchema).default([])
21443
+ var agentFilingSchema = object({
21444
+ confident: boolean3().default(false),
21445
+ areaId: string2().nullable().optional(),
21446
+ owner: string2().nullable().optional(),
21447
+ date: string2().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
21663
21448
  });
21664
- var healthSummaryQuerySchema = object({ episodeId: ulidSchema.optional() });
21665
21449
 
21666
- // ../../packages/schema/src/contracts/health-labs.ts
21667
- var LAB_GROUP_VALUES = [
21668
- "vitamins_iron",
21669
- "blood_count",
21670
- "kidney",
21671
- "liver",
21672
- "thyroid",
21673
- "lipids",
21674
- "sugar",
21675
- "inflammation",
21676
- "hormones",
21677
- "other"
21678
- ];
21679
- var labGroupSchema = _enum2(LAB_GROUP_VALUES);
21680
- var HEALTH_LAB_FLAG_VALUES = ["low", "normal", "high"];
21681
- var healthLabFlagSchema = _enum2(HEALTH_LAB_FLAG_VALUES);
21682
- var healthLabPanelStatusSchema = _enum2(["draft", "confirmed"]);
21683
- var labAnalyteKeySchema = string2().regex(/^[a-z0-9]+(_[a-z0-9]+)*$/, "must be lowercase words joined by _").max(80);
21684
- var title2 = string2().trim().min(1).max(200);
21685
- var text3 = (max) => string2().trim().min(1).max(max);
21686
- var instant2 = exports_coerce.date();
21687
- var amount = number2().finite();
21688
- var healthLabResultSchema = createSelectSchema(healthLabResults, {
21689
- valueNum: number2().nullable(),
21690
- refLow: number2().nullable(),
21691
- refHigh: number2().nullable()
21450
+ // ../../packages/schema/src/contracts/agent-gateway.ts
21451
+ var AGENT_GATEWAY_VERSION = 1;
21452
+ var AGENT_GATEWAY_MAX_FRAME_BYTES = 1024 * 1024;
21453
+ var threadSlugSchema = string2().regex(/^[a-z0-9][a-z0-9-]{0,39}$/, "a thread slug is lower-case, like `build`");
21454
+ var postLevelSchema = _enum2(["needs_you", "told", "for_later", "silent"]);
21455
+ var postKindSchema = _enum2(["message", "brief", "card", "run"]);
21456
+ var runStatusSchema = _enum2(["running", "needs_you", "done", "failed", "stopped"]);
21457
+ var externalIdSchema = string2().min(1).max(200).regex(/^[\x21-\x7e]+$/, "printable ASCII without spaces");
21458
+ var AGENT_POST_TEXT_MAX = 64000;
21459
+ var postTextSchema = string2().max(AGENT_POST_TEXT_MAX);
21460
+ var briefVerbSchema = object({
21461
+ label: string2().trim().min(1).max(24),
21462
+ href: string2().max(2000).regex(/^(\/(?!\/)|https:\/\/)/, "a path in do (`/tasks`) or an https link").optional(),
21463
+ say: string2().trim().min(1).max(500).optional()
21464
+ }).strict().refine((v) => v.href === undefined !== (v.say === undefined), {
21465
+ message: "a verb has either href or say"
21692
21466
  });
21693
- var healthLabPanelViewSchema = createSelectSchema(healthLabPanels, {
21694
- specimenAt: exports_coerce.date()
21695
- }).extend({
21696
- title: string2(),
21697
- createdAt: exports_coerce.date(),
21698
- updatedAt: exports_coerce.date(),
21699
- orderedByName: string2().nullable(),
21700
- results: array(healthLabResultSchema),
21701
- unmatched: array(string2()).optional()
21467
+ var briefRowSchema = object({
21468
+ text: string2().trim().min(1).max(200),
21469
+ meta: string2().trim().max(200).optional(),
21470
+ icon: string2().max(24).optional(),
21471
+ verb: briefVerbSchema.optional()
21472
+ }).strict();
21473
+ var BRIEF_ROWS_MAX = 8;
21474
+ var briefSchema = object({
21475
+ label: string2().trim().min(1).max(40),
21476
+ title: string2().trim().min(1).max(200),
21477
+ rows: array(briefRowSchema).max(BRIEF_ROWS_MAX).default([])
21478
+ }).strict();
21479
+ var gatewayMemberSchema = object({
21480
+ id: string2().min(1),
21481
+ name: string2(),
21482
+ role: baseRoleSchema
21702
21483
  });
21703
- var healthLabPointSchema = object({
21704
- resultId: string2(),
21705
- panelId: string2(),
21706
- specimenAt: exports_coerce.date(),
21707
- labName: string2().nullable(),
21708
- status: healthLabPanelStatusSchema,
21709
- valueNum: number2().nullable(),
21710
- valueText: string2().nullable(),
21711
- unit: string2().nullable(),
21712
- refLow: number2().nullable(),
21713
- refHigh: number2().nullable(),
21714
- flag: healthLabFlagSchema.nullable(),
21715
- fileId: string2().nullable(),
21716
- fileMime: string2().nullable().default(null),
21717
- source: healthEntrySourceSchema.default("manual")
21484
+ var gatewayThreadSchema = object({
21485
+ id: ulidSchema,
21486
+ memberId: string2().min(1),
21487
+ slug: threadSlugSchema.nullable(),
21488
+ title: string2().nullable(),
21489
+ standing: boolean3(),
21490
+ deleted: boolean3().optional()
21718
21491
  });
21719
- var healthLabAnalyteViewSchema = object({
21720
- analyte: string2(),
21492
+ var AGENT_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
21493
+ var AGENT_ATTACHMENTS_MAX = 20;
21494
+ var attachmentKindSchema = _enum2(["image", "voice", "audio", "video", "file"]);
21495
+ var gatewayAttachmentSchema = object({
21496
+ id: ulidSchema,
21497
+ kind: attachmentKindSchema,
21498
+ mime: string2().min(1),
21721
21499
  name: string2(),
21722
- group: labGroupSchema,
21723
- loinc: string2().nullable(),
21724
- unit: string2().nullable(),
21725
- points: array(healthLabPointSchema),
21726
- target: object({
21727
- low: number2().nullable(),
21728
- high: number2().nullable(),
21729
- byContactId: string2().nullable(),
21730
- byName: string2().nullable(),
21731
- note: string2().nullable()
21732
- }).nullable(),
21733
- medication: object({
21734
- id: string2(),
21735
- title: string2(),
21736
- dose: string2().nullable(),
21737
- schedule: healthMedicationScheduleSchema,
21738
- habitId: string2().nullable()
21739
- }).nullable()
21500
+ size: number2().int().nonnegative(),
21501
+ durationMs: number2().int().nonnegative().optional(),
21502
+ transcript: string2().optional()
21740
21503
  });
21741
- var healthLabOverviewSchema = object({
21742
- draws: number2().int(),
21743
- firstAt: exports_coerce.date().nullable(),
21744
- lastAt: exports_coerce.date().nullable(),
21745
- lastLab: string2().nullable(),
21746
- analytes: array(healthLabAnalyteViewSchema)
21504
+ var AGENT_VOICE_MAX_MS = 5 * 60 * 1000;
21505
+ var AGENT_TRANSCRIPT_MAX = 20000;
21506
+ var inboundMessageSchema = object({
21507
+ id: ulidSchema,
21508
+ threadId: ulidSchema,
21509
+ member: object({ id: string2().min(1), name: string2() }),
21510
+ text: string2(),
21511
+ createdAt: string2().datetime(),
21512
+ attachments: array(gatewayAttachmentSchema).default([]),
21513
+ replyToPostId: ulidSchema.optional(),
21514
+ context: agentPageContextSchema.optional(),
21515
+ history: array(object({ role: _enum2(["member", "agent"]), text: string2() })).optional(),
21516
+ steer: boolean3().optional()
21517
+ });
21518
+ var threadTargetSchema = union([
21519
+ object({ id: ulidSchema }).strict(),
21520
+ object({ slug: threadSlugSchema, memberId: string2().min(1).optional() }).strict()
21521
+ ]);
21522
+ var runStepSchema = object({
21523
+ label: string2().min(1).max(60),
21524
+ state: _enum2(["pending", "active", "done"]).default("pending")
21525
+ });
21526
+ var postRunSchema = object({
21527
+ status: runStatusSchema,
21528
+ steps: array(runStepSchema).max(12).optional()
21529
+ });
21530
+ var POST_RECEIPT_ABOUT_VALUES = ["red_flags"];
21531
+ var postReceiptInputSchema = object({
21532
+ nodeId: ulidSchema,
21533
+ parts: array(ulidSchema).min(1).max(10).optional(),
21534
+ about: _enum2(POST_RECEIPT_ABOUT_VALUES).optional()
21535
+ }).strict();
21536
+ var postReceiptSchema = object({
21537
+ nodeId: string2(),
21538
+ nodeType: string2(),
21539
+ parts: array(string2()).optional(),
21540
+ about: _enum2(POST_RECEIPT_ABOUT_VALUES).optional()
21541
+ });
21542
+ var POST_TITLE_MAX = 200;
21543
+ var postTitleSchema = string2().trim().min(1).max(POST_TITLE_MAX);
21544
+ var agentPostInputSchema = object({
21545
+ externalId: externalIdSchema,
21546
+ thread: threadTargetSchema,
21547
+ text: postTextSchema,
21548
+ kind: postKindSchema.default("message"),
21549
+ title: postTitleSchema.optional(),
21550
+ level: postLevelSchema.nullish(),
21551
+ replyToMessageId: ulidSchema.optional(),
21552
+ attachments: array(ulidSchema).max(AGENT_ATTACHMENTS_MAX).default([]),
21553
+ final: boolean3().default(true),
21554
+ run: postRunSchema.optional(),
21555
+ recovered: boolean3().optional(),
21556
+ brief: briefSchema.optional(),
21557
+ receipt: postReceiptInputSchema.optional()
21558
+ });
21559
+ var agentPostEditSchema = object({
21560
+ text: postTextSchema.optional(),
21561
+ title: postTitleSchema.optional(),
21562
+ final: boolean3().optional(),
21563
+ level: postLevelSchema.optional(),
21564
+ run: postRunSchema.optional(),
21565
+ brief: briefSchema.optional()
21566
+ }).refine((e) => Object.values(e).some((v) => v !== undefined), {
21567
+ message: "send text, title, final, level, run or brief"
21568
+ });
21569
+ var agentPostResultSchema = object({ postId: ulidSchema, created: boolean3() });
21570
+ var promptOptionSchema = object({
21571
+ id: string2().min(1).max(40),
21572
+ label: string2().min(1).max(80),
21573
+ style: _enum2(["primary", "danger", ""]).default("")
21574
+ });
21575
+ var agentPromptSchema = object({
21576
+ promptId: string2().min(1).max(100),
21577
+ threadId: ulidSchema,
21578
+ kind: _enum2(["exec_approval", "clarify", "slash_confirm"]),
21579
+ text: postTextSchema,
21580
+ options: array(promptOptionSchema).min(1).max(12),
21581
+ allowText: boolean3().default(false),
21582
+ expiresAt: string2().datetime(),
21583
+ command: string2().optional(),
21584
+ description: string2().optional()
21747
21585
  });
21748
- var healthLabResultInputSchema = object({
21749
- id: ulidSchema.optional(),
21750
- analyte: labAnalyteKeySchema.optional(),
21751
- name: title2,
21752
- group: labGroupSchema.optional(),
21753
- loinc: text3(20).nullish(),
21754
- valueNum: amount.nullish(),
21755
- valueText: text3(200).nullish(),
21756
- unit: text3(40).nullish(),
21757
- refLow: amount.nullish(),
21758
- refHigh: amount.nullish(),
21759
- flag: healthLabFlagSchema.nullish(),
21760
- comment: text3(1000).nullish()
21761
- }).strict().refine((r) => r.valueNum != null || r.valueText != null, {
21762
- message: "a result needs valueNum or valueText"
21586
+ var agentGatewayErrorCodeSchema = _enum2([
21587
+ "bad_request",
21588
+ "not_found",
21589
+ "thread_not_found",
21590
+ "not_member",
21591
+ "too_large",
21592
+ "rate_limited",
21593
+ "unsupported",
21594
+ "internal"
21595
+ ]);
21596
+ var agentGatewayErrorSchema = object({
21597
+ code: agentGatewayErrorCodeSchema,
21598
+ message: string2(),
21599
+ retryable: boolean3()
21763
21600
  });
21764
- var createHealthLabPanelInputSchema = object({
21765
- id: ulidSchema.optional(),
21766
- title: title2.optional(),
21767
- specimenAt: instant2,
21768
- labName: text3(200).nullish(),
21769
- orderedByContactId: ulidSchema.nullish(),
21770
- encounterId: ulidSchema.nullish(),
21771
- fileId: ulidSchema.nullish(),
21772
- status: healthLabPanelStatusSchema.optional(),
21773
- source: healthEntrySourceSchema.optional(),
21774
- note: text3(2000).nullish(),
21775
- results: array(healthLabResultInputSchema).max(200).optional(),
21776
- subjectNodeId: ulidSchema.nullish()
21777
- }).strict();
21778
- var updateHealthLabPanelInputSchema = createHealthLabPanelInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21779
- var healthLabImportFieldsSchema = object({ text: string2().max(200000).optional() }).strict();
21780
- var healthLabImportResultSchema = object({
21781
- format: _enum2(["kmehr", "pdf"]),
21782
- found: number2().int(),
21783
- panel: healthLabPanelViewSchema
21601
+ var frame = (type, shape) => object({
21602
+ v: literal(AGENT_GATEWAY_VERSION),
21603
+ type: literal(type),
21604
+ id: string2().min(1).max(64),
21605
+ ...shape
21784
21606
  });
21785
- var setHealthLabAnalyteInputSchema = object({
21786
- targetLow: amount.nullish(),
21787
- targetHigh: amount.nullish(),
21788
- targetByContactId: ulidSchema.nullish(),
21789
- medicationId: ulidSchema.nullish(),
21790
- note: text3(1000).nullish()
21791
- }).strict().refine((t) => t.targetLow == null || t.targetHigh == null || t.targetLow <= t.targetHigh, {
21792
- message: "targetLow must not be above targetHigh"
21607
+ var readyFrameSchema = frame("ready", {
21608
+ space: object({
21609
+ id: string2().min(1),
21610
+ name: string2(),
21611
+ ownerMemberId: string2().min(1)
21612
+ }),
21613
+ agent: object({
21614
+ id: string2().min(1),
21615
+ name: string2(),
21616
+ homeSlug: threadSlugSchema
21617
+ }),
21618
+ members: array(gatewayMemberSchema),
21619
+ threads: array(gatewayThreadSchema),
21620
+ heartbeatSec: number2().int().positive(),
21621
+ hints: array(string2()).default([])
21793
21622
  });
21794
-
21795
- // ../../packages/schema/src/contracts/agent-chat.ts
21796
- var agentConnectionSourceSchema = _enum2(["space", "env"]);
21797
- var agentGatewayStatusSchema = _enum2(["connected", "offline", "not_connected"]);
21798
- var agentGatewayStateSchema = object({
21799
- status: agentGatewayStatusSchema,
21800
- connectedAt: exports_coerce.date().nullable(),
21801
- seenAt: exports_coerce.date().nullable(),
21802
- disconnectedAt: exports_coerce.date().nullable()
21623
+ var membersFrameSchema = frame("members", { members: array(gatewayMemberSchema) });
21624
+ var threadsFrameSchema = frame("threads", { threads: array(gatewayThreadSchema) });
21625
+ var messageFrameSchema = frame("message", { message: inboundMessageSchema });
21626
+ var promptAnswerFrameSchema = frame("prompt.answer", {
21627
+ promptId: string2().min(1),
21628
+ optionId: string2().min(1),
21629
+ text: string2().optional(),
21630
+ memberId: string2().min(1),
21631
+ threadId: ulidSchema
21803
21632
  });
21804
- var agentConnectionSchema = object({
21805
- connected: boolean3(),
21806
- source: agentConnectionSourceSchema.nullable(),
21807
- endpoint: string2().nullable(),
21808
- model: string2().nullable(),
21809
- hasKey: boolean3(),
21810
- agentId: string2().nullable(),
21811
- agentName: string2().nullable().default(null),
21812
- autoFile: boolean3(),
21813
- updatedAt: exports_coerce.date().nullable(),
21814
- gateway: agentGatewayStateSchema.nullable().default(null)
21633
+ var confirmationOutcomeFrameSchema = frame("confirmation.outcome", {
21634
+ confirmationId: string2().min(1),
21635
+ memberId: string2().min(1),
21636
+ threadId: ulidSchema.nullable(),
21637
+ outcome: _enum2(["done", "failed", "declined"]),
21638
+ text: string2()
21815
21639
  });
21816
- var agentEndpointSchema = string2().trim().max(2000).url().refine((value) => /^https?:\/\//i.test(value), "endpoint must be an http(s) URL");
21817
- var saveAgentConnectionInputSchema = object({
21818
- endpoint: agentEndpointSchema.nullable(),
21819
- apiKey: string2().trim().min(1).max(4000).nullable().optional(),
21820
- model: string2().trim().min(1).max(200).nullable().optional(),
21821
- agentId: string2().trim().min(1).max(64).nullable().optional(),
21822
- autoFile: boolean3().optional()
21823
- }).strict().refine((input) => input.endpoint !== null || Boolean(input.agentId), {
21824
- message: "a connection without an endpoint names its agent",
21825
- path: ["agentId"]
21640
+ var interruptFrameSchema = frame("interrupt", {
21641
+ threadId: ulidSchema,
21642
+ memberId: string2().min(1)
21826
21643
  });
21827
- var agentPageContextSchema = object({
21828
- route: string2().trim().min(1).max(500).startsWith("/"),
21829
- nodeId: string2().trim().min(1).max(64).nullable(),
21830
- focusArea: object({
21831
- id: string2().trim().min(1).max(64),
21832
- title: string2().trim().min(1).max(200)
21833
- }).nullish()
21834
- }).strict();
21835
- var echoDeviceSchema = _enum2(["phone", "desktop"]);
21836
- var agentChatInputSchema = object({
21837
- message: string2().trim().max(8000),
21838
- context: agentPageContextSchema,
21839
- threadId: string2().trim().min(1).max(64).optional(),
21840
- steer: boolean3().optional(),
21841
- attachments: array(string2().trim().min(1).max(64)).max(20).optional(),
21842
- replyTo: string2().trim().min(1).max(64).optional(),
21843
- device: echoDeviceSchema.optional()
21844
- }).strict().refine((input) => input.message.length > 0 || (input.attachments?.length ?? 0) > 0, {
21845
- message: "write something or attach a file",
21846
- path: ["message"]
21644
+ var ackFrameSchema = frame("ack", {
21645
+ ref: string2().min(1),
21646
+ ok: boolean3(),
21647
+ postId: ulidSchema.optional(),
21648
+ created: boolean3().optional(),
21649
+ error: agentGatewayErrorSchema.optional()
21847
21650
  });
21848
- var agentChatStopInputSchema = object({ threadId: string2().trim().min(1).max(64) }).strict();
21849
- var agentChatStopResultSchema = object({ stop: _enum2(["sent", "offline"]) });
21850
- var agentChatEventSchema = discriminatedUnion("type", [
21851
- object({
21852
- type: literal("turn"),
21853
- id: string2(),
21854
- threadId: string2(),
21855
- since: string2().nullable()
21856
- }),
21857
- object({ type: literal("delta"), text: string2() }),
21858
- object({ type: literal("done") }),
21859
- object({ type: literal("error"), message: string2() }),
21860
- object({
21861
- type: literal("posted"),
21862
- threadId: string2(),
21863
- postId: string2(),
21864
- delivery: _enum2(["sent", "waiting"])
21865
- })
21866
- ]);
21867
- var agentChangeValueSchema = union([
21868
- string2(),
21869
- number2(),
21870
- boolean3(),
21871
- _null3(),
21872
- array(string2())
21873
- ]);
21874
- var agentChangeFieldSchema = object({
21875
- field: string2(),
21876
- before: agentChangeValueSchema,
21877
- after: agentChangeValueSchema,
21878
- beforeLabel: string2().nullable().optional(),
21879
- afterLabel: string2().nullable().optional()
21651
+ var unseenPostSchema = object({
21652
+ postId: ulidSchema,
21653
+ threadId: ulidSchema,
21654
+ memberId: string2().min(1),
21655
+ title: string2(),
21656
+ threadTitle: string2().nullable(),
21657
+ path: string2().startsWith("/"),
21658
+ url: string2().url().nullable(),
21659
+ pushedAt: string2().datetime()
21880
21660
  });
21881
- var agentChangeSchema = object({
21882
- entity: changeEntitySchema,
21883
- id: string2(),
21884
- op: changeOpSchema,
21885
- changedAt: exports_coerce.date(),
21886
- title: string2().nullable(),
21887
- actor: actorRefSchema,
21888
- cursor: string2().optional(),
21889
- fields: array(agentChangeFieldSchema).optional(),
21890
- checkIn: object({
21891
- value: number2(),
21892
- unit: string2().nullable(),
21893
- measurementType: habitMeasurementTypeSchema
21894
- }).optional()
21661
+ var postUnseenFrameSchema = frame("post.unseen", { post: unseenPostSchema });
21662
+ var agentGatewayServerFrameSchema = discriminatedUnion("type", [
21663
+ readyFrameSchema,
21664
+ membersFrameSchema,
21665
+ threadsFrameSchema,
21666
+ messageFrameSchema,
21667
+ promptAnswerFrameSchema,
21668
+ interruptFrameSchema,
21669
+ confirmationOutcomeFrameSchema,
21670
+ ackFrameSchema,
21671
+ postUnseenFrameSchema
21672
+ ]);
21673
+ var messageAckFrameSchema = frame("message.ack", { messageId: ulidSchema });
21674
+ var postFrameSchema = frame("post", { post: agentPostInputSchema });
21675
+ var postEditFrameSchema = frame("post.edit", {
21676
+ postId: ulidSchema,
21677
+ edit: agentPostEditSchema
21895
21678
  });
21896
- var agentChangesPageSchema = object({
21897
- data: array(agentChangeSchema),
21898
- nextCursor: string2()
21679
+ var postDeleteFrameSchema = frame("post.delete", { postId: ulidSchema });
21680
+ var typingFrameSchema = frame("typing", { threadId: ulidSchema, on: boolean3() });
21681
+ var promptFrameSchema = frame("prompt", { prompt: agentPromptSchema });
21682
+ var promptCloseFrameSchema = frame("prompt.close", {
21683
+ promptId: string2().min(1),
21684
+ optionId: string2().optional(),
21685
+ expired: boolean3()
21899
21686
  });
21900
- var agentChangesQuerySchema = object({
21901
- since: string2().refine((s) => s === "now" || /^\d+-\d+$/.test(s), {
21902
- message: "since must be a cursor from a prior page's nextCursor, or 'now'"
21903
- }),
21904
- node: string2().trim().min(1).max(64).optional()
21687
+ var attachmentTranscriptFrameSchema = frame("attachment.transcript", {
21688
+ attachmentId: ulidSchema,
21689
+ text: string2().trim().min(1).max(AGENT_TRANSCRIPT_MAX)
21905
21690
  });
21906
- var agentConfirmationKindSchema = _enum2(["delete", "cancel", "google", "orca", "bulk"]);
21907
- var agentConfirmationStatusSchema = _enum2([
21908
- "pending",
21909
- "confirmed",
21910
- "done",
21911
- "failed",
21912
- "declined"
21691
+ var postUnseenAckFrameSchema = frame("post.unseen.ack", { postId: ulidSchema });
21692
+ var agentGatewayClientFrameSchema = discriminatedUnion("type", [
21693
+ messageAckFrameSchema,
21694
+ postUnseenAckFrameSchema,
21695
+ postFrameSchema,
21696
+ postEditFrameSchema,
21697
+ postDeleteFrameSchema,
21698
+ typingFrameSchema,
21699
+ promptFrameSchema,
21700
+ promptCloseFrameSchema,
21701
+ attachmentTranscriptFrameSchema
21913
21702
  ]);
21914
- var agentConfirmationItemSchema = object({
21915
- id: string2(),
21916
- title: string2().nullable(),
21917
- area: string2().nullable().optional(),
21918
- dueAt: exports_coerce.date().nullable().optional()
21919
- });
21920
- var agentConfirmationSchema = object({
21921
- id: string2(),
21922
- kind: agentConfirmationKindSchema,
21923
- summary: string2(),
21924
- items: array(agentConfirmationItemSchema),
21925
- method: string2(),
21926
- path: string2(),
21927
- status: agentConfirmationStatusSchema,
21928
- agent: object({ id: string2(), name: string2().nullable() }),
21703
+ var SERVER_FRAME_TYPES = new Set(agentGatewayServerFrameSchema.options.map((o) => o.shape.type.value));
21704
+ var CLIENT_FRAME_TYPES = new Set(agentGatewayClientFrameSchema.options.map((o) => o.shape.type.value));
21705
+ var agentThreadsResponseSchema = object({ threads: array(gatewayThreadSchema) });
21706
+ function homeSlugFor(agentName) {
21707
+ const slug = agentName.normalize("NFKD").replace(/[\u0300-\u036F]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
21708
+ return slug || "agent";
21709
+ }
21710
+
21711
+ // ../../packages/schema/src/contracts/health-records.ts
21712
+ var BODY_REGION_VALUES = [
21713
+ "head",
21714
+ "face",
21715
+ "eyes",
21716
+ "ears",
21717
+ "nose",
21718
+ "mouth",
21719
+ "throat",
21720
+ "neck",
21721
+ "chest",
21722
+ "upper_back",
21723
+ "lower_back",
21724
+ "epigastric",
21725
+ "ruq",
21726
+ "luq",
21727
+ "periumbilical",
21728
+ "rlq",
21729
+ "llq",
21730
+ "lower_abdomen",
21731
+ "pelvis",
21732
+ "shoulder_l",
21733
+ "shoulder_r",
21734
+ "arm_l",
21735
+ "arm_r",
21736
+ "elbow_l",
21737
+ "elbow_r",
21738
+ "wrist_l",
21739
+ "wrist_r",
21740
+ "hand_l",
21741
+ "hand_r",
21742
+ "hip_l",
21743
+ "hip_r",
21744
+ "thigh_l",
21745
+ "thigh_r",
21746
+ "knee_l",
21747
+ "knee_r",
21748
+ "calf_l",
21749
+ "calf_r",
21750
+ "ankle_l",
21751
+ "ankle_r",
21752
+ "foot_l",
21753
+ "foot_r",
21754
+ "skin",
21755
+ "whole_body"
21756
+ ];
21757
+ var bodyRegionSchema = _enum2(BODY_REGION_VALUES);
21758
+ var RED_FLAG_VALUES = [
21759
+ "fever",
21760
+ "vomiting",
21761
+ "black_stools",
21762
+ "blood",
21763
+ "weight_loss",
21764
+ "night_pain",
21765
+ "chest_pain",
21766
+ "short_of_breath"
21767
+ ];
21768
+ var redFlagSchema = _enum2(RED_FLAG_VALUES);
21769
+ var redFlagsSchema = partialRecord(redFlagSchema, boolean3());
21770
+ var HEALTH_CONDITION_STATUS_VALUES = [
21771
+ "active",
21772
+ "managed",
21773
+ "resolved",
21774
+ "suspected"
21775
+ ];
21776
+ var healthConditionStatusSchema = _enum2(HEALTH_CONDITION_STATUS_VALUES);
21777
+ var HEALTH_EPISODE_STATUS_VALUES = ["open", "watching", "resolved"];
21778
+ var healthEpisodeStatusSchema = _enum2(HEALTH_EPISODE_STATUS_VALUES);
21779
+ var HEALTH_ENCOUNTER_KIND_VALUES = [
21780
+ "gp",
21781
+ "specialist",
21782
+ "physio",
21783
+ "dentist",
21784
+ "lab_draw",
21785
+ "er",
21786
+ "tele",
21787
+ "other"
21788
+ ];
21789
+ var healthEncounterKindSchema = _enum2(HEALTH_ENCOUNTER_KIND_VALUES);
21790
+ var healthMedicationKindSchema = _enum2(["drug", "supplement"]);
21791
+ var healthMedicationScheduleSchema = _enum2(["scheduled", "as_needed"]);
21792
+ var HEALTH_DOSE_EFFECT_VALUES = ["none", "a_little", "helped", "worse"];
21793
+ var healthDoseEffectSchema = _enum2(HEALTH_DOSE_EFFECT_VALUES);
21794
+ var healthEntrySourceSchema = _enum2(["chat", "manual", "import"]);
21795
+ var severitySchema = number2().int().min(0).max(10);
21796
+ var fuzzyDateSchema = string2().regex(/^\d{4}(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\d|3[01]))?)?$/, "must be YYYY, YYYY-MM or YYYY-MM-DD");
21797
+ var civilDateSchema2 = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be YYYY-MM-DD");
21798
+ var title = string2().trim().min(1).max(200);
21799
+ var text2 = (max) => string2().trim().min(1).max(max);
21800
+ var instant = exports_coerce.date();
21801
+ var spine = {
21802
+ title: string2(),
21929
21803
  createdAt: exports_coerce.date(),
21930
- decidedAt: exports_coerce.date().nullable()
21804
+ updatedAt: exports_coerce.date()
21805
+ };
21806
+ var healthCareTeamMemberSchema = object({
21807
+ contactId: string2(),
21808
+ name: string2(),
21809
+ phone: string2().nullable(),
21810
+ label: string2().nullable()
21931
21811
  });
21932
- var agentUndoInputSchema = object({
21933
- id: string2().trim().min(1).max(64),
21934
- since: string2().regex(/^\d+-\d+$/, "since must be a change-feed cursor")
21935
- }).strict();
21936
- var agentUndoResultSchema = object({
21937
- id: string2(),
21938
- undone: _enum2(["removed", "restored"])
21812
+ var healthConditionViewSchema = createSelectSchema(healthConditions, {
21813
+ bodyRegions: array(string2())
21814
+ }).extend({
21815
+ ...spine,
21816
+ careTeam: array(healthCareTeamMemberSchema).default([])
21939
21817
  });
21940
- var agentRedoResultSchema = object({
21941
- id: string2(),
21942
- redone: literal(true)
21818
+ var healthEpisodeViewSchema = createSelectSchema(healthEpisodes, {
21819
+ startedAt: exports_coerce.date(),
21820
+ endedAt: exports_coerce.date().nullable(),
21821
+ redFlags: redFlagsSchema,
21822
+ redFlagsCheckedAt: exports_coerce.date().nullable()
21823
+ }).extend({
21824
+ ...spine,
21825
+ latestSeverity: number2().int().nullable(),
21826
+ lastEntryAt: exports_coerce.date().nullable()
21943
21827
  });
21944
- var agentFilingSchema = object({
21945
- confident: boolean3().default(false),
21946
- areaId: string2().nullable().optional(),
21947
- owner: string2().nullable().optional(),
21948
- date: string2().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional()
21828
+ var healthSymptomEntrySchema = createSelectSchema(healthSymptomEntries, {
21829
+ occurredAt: exports_coerce.date(),
21830
+ recordedAt: exports_coerce.date(),
21831
+ qualifiers: record(string2(), unknown())
21949
21832
  });
21950
-
21951
- // ../../packages/schema/src/contracts/agent-gateway.ts
21952
- var AGENT_GATEWAY_VERSION = 1;
21953
- var AGENT_GATEWAY_MAX_FRAME_BYTES = 1024 * 1024;
21954
- var threadSlugSchema = string2().regex(/^[a-z0-9][a-z0-9-]{0,39}$/, "a thread slug is lower-case, like `build`");
21955
- var postLevelSchema = _enum2(["needs_you", "told", "for_later", "silent"]);
21956
- var postKindSchema = _enum2(["message", "brief", "card", "run"]);
21957
- var runStatusSchema = _enum2(["running", "needs_you", "done", "failed", "stopped"]);
21958
- var externalIdSchema = string2().min(1).max(200).regex(/^[\x21-\x7e]+$/, "printable ASCII without spaces");
21959
- var AGENT_POST_TEXT_MAX = 64000;
21960
- var postTextSchema = string2().max(AGENT_POST_TEXT_MAX);
21961
- var briefVerbSchema = object({
21962
- label: string2().trim().min(1).max(24),
21963
- href: string2().max(2000).regex(/^(\/(?!\/)|https:\/\/)/, "a path in do (`/tasks`) or an https link").optional(),
21964
- say: string2().trim().min(1).max(500).optional()
21965
- }).strict().refine((v) => v.href === undefined !== (v.say === undefined), {
21966
- message: "a verb has either href or say"
21833
+ var healthEncounterViewSchema = createSelectSchema(healthEncounters, {
21834
+ at: exports_coerce.date(),
21835
+ followUpAt: exports_coerce.date().nullable(),
21836
+ questions: array(string2())
21837
+ }).extend({
21838
+ ...spine,
21839
+ providerName: string2().nullable()
21967
21840
  });
21968
- var briefRowSchema = object({
21969
- text: string2().trim().min(1).max(200),
21970
- meta: string2().trim().max(200).optional(),
21971
- icon: string2().max(24).optional(),
21972
- verb: briefVerbSchema.optional()
21973
- }).strict();
21974
- var BRIEF_ROWS_MAX = 8;
21975
- var briefSchema = object({
21976
- label: string2().trim().min(1).max(40),
21977
- title: string2().trim().min(1).max(200),
21978
- rows: array(briefRowSchema).max(BRIEF_ROWS_MAX).default([])
21979
- }).strict();
21980
- var gatewayMemberSchema = object({
21981
- id: string2().min(1),
21982
- name: string2(),
21983
- role: baseRoleSchema
21841
+ var healthMedicationViewSchema = createSelectSchema(healthMedications).extend({
21842
+ ...spine,
21843
+ lastTakenAt: exports_coerce.date().nullable()
21984
21844
  });
21985
- var gatewayThreadSchema = object({
21986
- id: ulidSchema,
21987
- memberId: string2().min(1),
21988
- slug: threadSlugSchema.nullable(),
21989
- title: string2().nullable(),
21990
- standing: boolean3(),
21991
- deleted: boolean3().optional()
21845
+ var healthMedicationDoseSchema = createSelectSchema(healthMedicationDoses, {
21846
+ takenAt: exports_coerce.date(),
21847
+ createdAt: exports_coerce.date()
21848
+ }).extend({
21849
+ medicationTitle: string2()
21992
21850
  });
21993
- var AGENT_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
21994
- var AGENT_ATTACHMENTS_MAX = 20;
21995
- var attachmentKindSchema = _enum2(["image", "voice", "audio", "video", "file"]);
21996
- var gatewayAttachmentSchema = object({
21997
- id: ulidSchema,
21998
- kind: attachmentKindSchema,
21999
- mime: string2().min(1),
22000
- name: string2(),
22001
- size: number2().int().nonnegative(),
22002
- durationMs: number2().int().nonnegative().optional(),
22003
- transcript: string2().optional()
21851
+ var healthEpisodeDetailSchema = healthEpisodeViewSchema.extend({
21852
+ entries: array(healthSymptomEntrySchema),
21853
+ doses: array(healthMedicationDoseSchema),
21854
+ encounters: array(healthEncounterViewSchema),
21855
+ condition: healthConditionViewSchema.nullable()
22004
21856
  });
22005
- var AGENT_VOICE_MAX_MS = 5 * 60 * 1000;
22006
- var AGENT_TRANSCRIPT_MAX = 20000;
22007
- var inboundMessageSchema = object({
22008
- id: ulidSchema,
22009
- threadId: ulidSchema,
22010
- member: object({ id: string2().min(1), name: string2() }),
22011
- text: string2(),
22012
- createdAt: string2().datetime(),
22013
- attachments: array(gatewayAttachmentSchema).default([]),
22014
- replyToPostId: ulidSchema.optional(),
22015
- context: agentPageContextSchema.optional(),
22016
- history: array(object({ role: _enum2(["member", "agent"]), text: string2() })).optional(),
22017
- steer: boolean3().optional()
21857
+ var healthProfileSchema = createSelectSchema(healthProfiles, {
21858
+ allergies: array(string2()),
21859
+ updatedAt: exports_coerce.date()
21860
+ }).extend({
21861
+ notes: string2().nullable().default(null),
21862
+ sex: string2().nullable().default(null)
22018
21863
  });
22019
- var threadTargetSchema = union([
22020
- object({ id: ulidSchema }).strict(),
22021
- object({ slug: threadSlugSchema, memberId: string2().min(1).optional() }).strict()
22022
- ]);
22023
- var runStepSchema = object({
22024
- label: string2().min(1).max(60),
22025
- state: _enum2(["pending", "active", "done"]).default("pending")
21864
+ var healthConsentStateSchema = object({
21865
+ granted: boolean3(),
21866
+ version: string2().nullable(),
21867
+ grantedAt: exports_coerce.date().nullable()
22026
21868
  });
22027
- var postRunSchema = object({
22028
- status: runStatusSchema,
22029
- steps: array(runStepSchema).max(12).optional()
21869
+ var HEALTH_CONSENT_VERSION = "2026-10-18";
21870
+ var subject = { subjectNodeId: ulidSchema.nullish() };
21871
+ var createHealthConditionInputSchema = object({
21872
+ id: ulidSchema.optional(),
21873
+ title,
21874
+ status: healthConditionStatusSchema.optional(),
21875
+ onset: fuzzyDateSchema.nullish(),
21876
+ resolvedOn: civilDateSchema2.nullish(),
21877
+ bodyRegions: array(bodyRegionSchema).max(10).optional(),
21878
+ code: text2(40).nullish(),
21879
+ notes: text2(4000).nullish(),
21880
+ ...subject
21881
+ }).strict();
21882
+ var addHealthCareTeamInputSchema = object({ contactId: ulidSchema, label: text2(60).nullish() }).strict();
21883
+ var updateHealthConditionInputSchema = createHealthConditionInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21884
+ var episodeFields = object({
21885
+ id: ulidSchema.optional(),
21886
+ title,
21887
+ status: healthEpisodeStatusSchema.optional(),
21888
+ startedAt: instant.optional(),
21889
+ bodyRegion: bodyRegionSchema.nullish(),
21890
+ triggerText: text2(500).nullish(),
21891
+ summary: text2(500).nullish(),
21892
+ conditionId: ulidSchema.nullish(),
21893
+ ...subject
21894
+ }).strict();
21895
+ var createHealthEpisodeInputSchema = episodeFields.extend({ endedAt: instant.nullish() }).strict().superRefine((v, ctx) => {
21896
+ if (!v.endedAt)
21897
+ return;
21898
+ if (v.status && v.status !== "resolved") {
21899
+ ctx.addIssue({
21900
+ code: "custom",
21901
+ path: ["endedAt"],
21902
+ message: "only a resolved episode has an end"
21903
+ });
21904
+ }
21905
+ if (v.endedAt.getTime() > Date.now()) {
21906
+ ctx.addIssue({ code: "custom", path: ["endedAt"], message: "can't end in the future" });
21907
+ }
21908
+ if (v.endedAt.getTime() < (v.startedAt ?? new Date).getTime()) {
21909
+ ctx.addIssue({ code: "custom", path: ["endedAt"], message: "can't end before it started" });
21910
+ }
22030
21911
  });
22031
- var postReceiptInputSchema = object({ nodeId: ulidSchema }).strict();
22032
- var postReceiptSchema = object({ nodeId: string2(), nodeType: string2() });
22033
- var POST_TITLE_MAX = 200;
22034
- var postTitleSchema = string2().trim().min(1).max(POST_TITLE_MAX);
22035
- var agentPostInputSchema = object({
22036
- externalId: externalIdSchema,
22037
- thread: threadTargetSchema,
22038
- text: postTextSchema,
22039
- kind: postKindSchema.default("message"),
22040
- title: postTitleSchema.optional(),
22041
- level: postLevelSchema.nullish(),
22042
- replyToMessageId: ulidSchema.optional(),
22043
- attachments: array(ulidSchema).max(AGENT_ATTACHMENTS_MAX).default([]),
22044
- final: boolean3().default(true),
22045
- run: postRunSchema.optional(),
22046
- recovered: boolean3().optional(),
22047
- brief: briefSchema.optional(),
22048
- receipt: postReceiptInputSchema.optional()
21912
+ var updateHealthEpisodeInputSchema = episodeFields.omit({ id: true, subjectNodeId: true }).extend({
21913
+ endedAt: instant.nullish(),
21914
+ redFlags: redFlagsSchema.optional()
21915
+ }).partial().strict();
21916
+ var symptomFields = {
21917
+ symptom: text2(200),
21918
+ occurredAt: instant.optional(),
21919
+ bodyRegion: bodyRegionSchema.nullish(),
21920
+ severity: severitySchema.nullish(),
21921
+ severityGuessed: boolean3().optional(),
21922
+ qualifiers: record(string2(), unknown()).optional(),
21923
+ note: text2(2000).nullish(),
21924
+ source: healthEntrySourceSchema.optional()
21925
+ };
21926
+ var logHealthSymptomInputSchema = object({ id: ulidSchema.optional(), ...symptomFields }).strict();
21927
+ var correctHealthSymptomInputSchema = object({ id: ulidSchema.optional(), ...symptomFields }).partial().strict().refine((v) => Object.keys(v).some((k) => k !== "id" && k !== "source"), {
21928
+ message: "a correction must change something"
22049
21929
  });
22050
- var agentPostEditSchema = object({
22051
- text: postTextSchema.optional(),
22052
- title: postTitleSchema.optional(),
22053
- final: boolean3().optional(),
22054
- level: postLevelSchema.optional(),
22055
- run: postRunSchema.optional(),
22056
- brief: briefSchema.optional()
22057
- }).refine((e) => Object.values(e).some((v) => v !== undefined), {
22058
- message: "send text, title, final, level, run or brief"
21930
+ var createHealthEncounterInputSchema = object({
21931
+ id: ulidSchema.optional(),
21932
+ title: title.optional(),
21933
+ kind: healthEncounterKindSchema.optional(),
21934
+ at: instant,
21935
+ episodeId: ulidSchema.nullish(),
21936
+ providerContactId: ulidSchema.nullish(),
21937
+ placeId: ulidSchema.nullish(),
21938
+ eventId: ulidSchema.nullish(),
21939
+ reason: text2(500).nullish(),
21940
+ questions: array(text2(300)).max(30).optional(),
21941
+ outcome: text2(4000).nullish(),
21942
+ followUpAt: instant.nullish(),
21943
+ ...subject
21944
+ }).strict();
21945
+ var updateHealthEncounterInputSchema = createHealthEncounterInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21946
+ var createHealthMedicationInputSchema = object({
21947
+ id: ulidSchema.optional(),
21948
+ title,
21949
+ kind: healthMedicationKindSchema.optional(),
21950
+ schedule: healthMedicationScheduleSchema.optional(),
21951
+ ingredient: text2(200).nullish(),
21952
+ dose: text2(100).nullish(),
21953
+ form: text2(100).nullish(),
21954
+ startedOn: civilDateSchema2.nullish(),
21955
+ stoppedOn: civilDateSchema2.nullish(),
21956
+ reason: text2(500).nullish(),
21957
+ prescribedByContactId: ulidSchema.nullish(),
21958
+ habitId: ulidSchema.nullish(),
21959
+ ...subject
21960
+ }).strict();
21961
+ var updateHealthMedicationInputSchema = createHealthMedicationInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
21962
+ var logHealthDoseInputSchema = object({
21963
+ id: ulidSchema.optional(),
21964
+ takenAt: instant.optional(),
21965
+ amount: text2(100).nullish(),
21966
+ effect: healthDoseEffectSchema.nullish(),
21967
+ note: text2(1000).nullish(),
21968
+ episodeId: ulidSchema.nullish(),
21969
+ source: healthEntrySourceSchema.optional()
21970
+ }).strict();
21971
+ var updateHealthDoseInputSchema = logHealthDoseInputSchema.omit({ id: true, source: true }).partial().strict();
21972
+ var updateHealthProfileInputSchema = object({
21973
+ bloodGroup: string2().regex(/^(A|B|AB|O)[+-]$/, "must be like A+ or O-").nullish(),
21974
+ allergies: array(text2(100)).max(30).optional(),
21975
+ heightCm: number2().min(30).max(260).nullish(),
21976
+ sex: text2(40).nullish(),
21977
+ alcohol: text2(200).nullish(),
21978
+ smoking: text2(200).nullish(),
21979
+ exercise: text2(200).nullish(),
21980
+ notes: text2(2000).nullish(),
21981
+ emergencyContactId: ulidSchema.nullish(),
21982
+ primaryGpContactId: ulidSchema.nullish()
21983
+ }).strict();
21984
+ var grantHealthConsentInputSchema = object({ version: literal(HEALTH_CONSENT_VERSION) }).strict();
21985
+ var healthEpisodeListQuerySchema = object({
21986
+ status: healthEpisodeStatusSchema.optional()
22059
21987
  });
22060
- var agentPostResultSchema = object({ postId: ulidSchema, created: boolean3() });
22061
- var promptOptionSchema = object({
22062
- id: string2().min(1).max(40),
22063
- label: string2().min(1).max(80),
22064
- style: _enum2(["primary", "danger", ""]).default("")
21988
+ var upsertHealthEpisodeInputSchema = episodeFields;
21989
+ var logDoseFields = logHealthDoseInputSchema.omit({ episodeId: true, source: true }).extend({
21990
+ medicationId: ulidSchema.optional(),
21991
+ medication: text2(200).optional()
22065
21992
  });
22066
- var agentPromptSchema = object({
22067
- promptId: string2().min(1).max(100),
22068
- threadId: ulidSchema,
22069
- kind: _enum2(["exec_approval", "clarify", "slash_confirm"]),
22070
- text: postTextSchema,
22071
- options: array(promptOptionSchema).min(1).max(12),
22072
- allowText: boolean3().default(false),
22073
- expiresAt: string2().datetime(),
22074
- command: string2().optional(),
22075
- description: string2().optional()
21993
+ var logHealthInputSchema = object({
21994
+ episodeId: ulidSchema.optional(),
21995
+ episode: upsertHealthEpisodeInputSchema.optional(),
21996
+ symptom: logHealthSymptomInputSchema.omit({ source: true }).optional(),
21997
+ dose: logDoseFields.refine((d) => !!d.medicationId !== !!d.medication, {
21998
+ message: "name the medication by medicationId or by medication, not both"
21999
+ }).optional(),
22000
+ thread: threadTargetSchema.optional()
22001
+ }).strict().refine((v) => !!v.symptom || !!v.dose, { message: "log a symptom, a dose, or both" }).refine((v) => !(v.episodeId && v.episode), {
22002
+ message: "name the episode by episodeId or describe it in episode, not both"
22003
+ }).refine((v) => !v.symptom || !!v.episodeId || !!v.episode, {
22004
+ message: "a symptom needs an episode (episodeId, or episode to find or start one)"
22076
22005
  });
22077
- var agentGatewayErrorCodeSchema = _enum2([
22078
- "bad_request",
22079
- "not_found",
22080
- "thread_not_found",
22081
- "not_member",
22082
- "too_large",
22083
- "rate_limited",
22084
- "unsupported",
22085
- "internal"
22086
- ]);
22087
- var agentGatewayErrorSchema = object({
22088
- code: agentGatewayErrorCodeSchema,
22089
- message: string2(),
22090
- retryable: boolean3()
22006
+ var correctHealthInputSchema = object({ entryId: ulidSchema, change: correctHealthSymptomInputSchema }).strict();
22007
+ var HEALTH_CHECK_IN_TRENDS = ["better", "same", "worse"];
22008
+ var healthCheckInTrendSchema = _enum2(HEALTH_CHECK_IN_TRENDS);
22009
+ var healthCheckInInputSchema = object({ trend: healthCheckInTrendSchema }).strict();
22010
+ var HEALTH_UNDO_KIND_VALUES = ["entry", "dose", "episode"];
22011
+ var healthUndoInputSchema = object({ kind: _enum2(HEALTH_UNDO_KIND_VALUES), id: ulidSchema }).strict();
22012
+ var HEALTH_RECEIPT_KIND_VALUES = [
22013
+ "symptom",
22014
+ "correction",
22015
+ "dose",
22016
+ "episode",
22017
+ "encounter"
22018
+ ];
22019
+ var healthReceiptItemSchema = object({
22020
+ kind: _enum2(HEALTH_RECEIPT_KIND_VALUES),
22021
+ id: string2(),
22022
+ line: string2(),
22023
+ guessed: array(string2()),
22024
+ undo: healthUndoInputSchema
22091
22025
  });
22092
- var frame = (type, shape) => object({
22093
- v: literal(AGENT_GATEWAY_VERSION),
22094
- type: literal(type),
22095
- id: string2().min(1).max(64),
22096
- ...shape
22026
+ var healthReceiptSchema = object({
22027
+ episode: object({ id: string2(), title: string2(), created: boolean3() }).nullable(),
22028
+ items: array(healthReceiptItemSchema),
22029
+ entry: healthSymptomEntrySchema.nullable(),
22030
+ dose: healthMedicationDoseSchema.nullable(),
22031
+ postId: string2().nullable().optional()
22097
22032
  });
22098
- var readyFrameSchema = frame("ready", {
22099
- space: object({
22100
- id: string2().min(1),
22101
- name: string2(),
22102
- ownerMemberId: string2().min(1)
22103
- }),
22104
- agent: object({
22105
- id: string2().min(1),
22106
- name: string2(),
22107
- homeSlug: threadSlugSchema
22033
+ var healthRedFlagsInputSchema = object({
22034
+ answers: redFlagsSchema.refine((a) => Object.keys(a).length > 0, {
22035
+ message: "answer at least one red flag"
22108
22036
  }),
22109
- members: array(gatewayMemberSchema),
22110
- threads: array(gatewayThreadSchema),
22111
- heartbeatSec: number2().int().positive(),
22112
- hints: array(string2()).default([])
22037
+ thread: threadTargetSchema.optional()
22038
+ }).strict();
22039
+ var healthRedFlagsResultSchema = object({
22040
+ episodeId: string2(),
22041
+ redFlags: redFlagsSchema,
22042
+ checkedAt: exports_coerce.date(),
22043
+ postId: string2().nullable()
22113
22044
  });
22114
- var membersFrameSchema = frame("members", { members: array(gatewayMemberSchema) });
22115
- var threadsFrameSchema = frame("threads", { threads: array(gatewayThreadSchema) });
22116
- var messageFrameSchema = frame("message", { message: inboundMessageSchema });
22117
- var promptAnswerFrameSchema = frame("prompt.answer", {
22118
- promptId: string2().min(1),
22119
- optionId: string2().min(1),
22120
- text: string2().optional(),
22121
- memberId: string2().min(1),
22122
- threadId: ulidSchema
22045
+ var healthCourseDaySchema = object({
22046
+ day: string2(),
22047
+ severity: number2().int().nullable(),
22048
+ entries: number2().int()
22049
+ });
22050
+ var healthTriedSchema = object({
22051
+ medicationId: string2(),
22052
+ title: string2(),
22053
+ doses: number2().int(),
22054
+ effects: array(healthDoseEffectSchema),
22055
+ lastTakenAt: exports_coerce.date(),
22056
+ amount: string2().nullable().default(null)
22123
22057
  });
22124
- var confirmationOutcomeFrameSchema = frame("confirmation.outcome", {
22125
- confirmationId: string2().min(1),
22126
- memberId: string2().min(1),
22127
- threadId: ulidSchema.nullable(),
22128
- outcome: _enum2(["done", "failed", "declined"]),
22129
- text: string2()
22058
+ var healthSummaryLabSchema = object({
22059
+ id: string2(),
22060
+ specimenAt: exports_coerce.date(),
22061
+ labName: string2().nullable(),
22062
+ results: array(object({
22063
+ name: string2(),
22064
+ valueNum: number2().nullable(),
22065
+ valueText: string2().nullable(),
22066
+ unit: string2().nullable(),
22067
+ refLow: number2().nullable(),
22068
+ refHigh: number2().nullable(),
22069
+ flag: _enum2(["low", "normal", "high"]).nullable()
22070
+ }))
22130
22071
  });
22131
- var interruptFrameSchema = frame("interrupt", {
22132
- threadId: ulidSchema,
22133
- memberId: string2().min(1)
22072
+ var HEALTH_TREND_KEYS = ["sleep", "weight"];
22073
+ var healthTrendSchema = object({
22074
+ key: _enum2(HEALTH_TREND_KEYS),
22075
+ label: string2(),
22076
+ unit: string2(),
22077
+ points: array(object({ day: string2(), value: number2() }))
22134
22078
  });
22135
- var ackFrameSchema = frame("ack", {
22136
- ref: string2().min(1),
22137
- ok: boolean3(),
22138
- postId: ulidSchema.optional(),
22139
- created: boolean3().optional(),
22140
- error: agentGatewayErrorSchema.optional()
22079
+ var healthSummarySchema = object({
22080
+ generatedAt: exports_coerce.date(),
22081
+ patient: object({ name: string2().nullable() }).default({ name: null }),
22082
+ episode: healthEpisodeViewSchema.nullable(),
22083
+ course: array(healthCourseDaySchema),
22084
+ entries: array(healthSymptomEntrySchema),
22085
+ tried: array(healthTriedSchema),
22086
+ conditions: array(healthConditionViewSchema),
22087
+ medications: array(healthMedicationViewSchema),
22088
+ profile: healthProfileSchema,
22089
+ gp: object({ id: string2(), name: string2(), phone: string2().nullable() }).nullable(),
22090
+ nextVisit: healthEncounterViewSchema.nullable(),
22091
+ questions: array(string2()),
22092
+ labs: array(healthSummaryLabSchema).default([]),
22093
+ trends: array(healthTrendSchema).default([])
22141
22094
  });
22142
- var unseenPostSchema = object({
22143
- postId: ulidSchema,
22144
- threadId: ulidSchema,
22145
- memberId: string2().min(1),
22095
+ var healthSummaryQuerySchema = object({ episodeId: ulidSchema.optional() });
22096
+
22097
+ // ../../packages/schema/src/contracts/health-labs.ts
22098
+ var LAB_GROUP_VALUES = [
22099
+ "vitamins_iron",
22100
+ "blood_count",
22101
+ "kidney",
22102
+ "liver",
22103
+ "thyroid",
22104
+ "lipids",
22105
+ "sugar",
22106
+ "inflammation",
22107
+ "hormones",
22108
+ "other"
22109
+ ];
22110
+ var labGroupSchema = _enum2(LAB_GROUP_VALUES);
22111
+ var HEALTH_LAB_FLAG_VALUES = ["low", "normal", "high"];
22112
+ var healthLabFlagSchema = _enum2(HEALTH_LAB_FLAG_VALUES);
22113
+ var healthLabPanelStatusSchema = _enum2(["draft", "confirmed"]);
22114
+ var labAnalyteKeySchema = string2().regex(/^[a-z0-9]+(_[a-z0-9]+)*$/, "must be lowercase words joined by _").max(80);
22115
+ var title2 = string2().trim().min(1).max(200);
22116
+ var text3 = (max) => string2().trim().min(1).max(max);
22117
+ var instant2 = exports_coerce.date();
22118
+ var amount = number2().finite();
22119
+ var healthLabResultSchema = createSelectSchema(healthLabResults, {
22120
+ valueNum: number2().nullable(),
22121
+ refLow: number2().nullable(),
22122
+ refHigh: number2().nullable()
22123
+ });
22124
+ var healthLabPanelViewSchema = createSelectSchema(healthLabPanels, {
22125
+ specimenAt: exports_coerce.date()
22126
+ }).extend({
22146
22127
  title: string2(),
22147
- threadTitle: string2().nullable(),
22148
- path: string2().startsWith("/"),
22149
- url: string2().url().nullable(),
22150
- pushedAt: string2().datetime()
22128
+ createdAt: exports_coerce.date(),
22129
+ updatedAt: exports_coerce.date(),
22130
+ orderedByName: string2().nullable(),
22131
+ results: array(healthLabResultSchema),
22132
+ unmatched: array(string2()).optional()
22151
22133
  });
22152
- var postUnseenFrameSchema = frame("post.unseen", { post: unseenPostSchema });
22153
- var agentGatewayServerFrameSchema = discriminatedUnion("type", [
22154
- readyFrameSchema,
22155
- membersFrameSchema,
22156
- threadsFrameSchema,
22157
- messageFrameSchema,
22158
- promptAnswerFrameSchema,
22159
- interruptFrameSchema,
22160
- confirmationOutcomeFrameSchema,
22161
- ackFrameSchema,
22162
- postUnseenFrameSchema
22163
- ]);
22164
- var messageAckFrameSchema = frame("message.ack", { messageId: ulidSchema });
22165
- var postFrameSchema = frame("post", { post: agentPostInputSchema });
22166
- var postEditFrameSchema = frame("post.edit", {
22167
- postId: ulidSchema,
22168
- edit: agentPostEditSchema
22134
+ var healthLabPointSchema = object({
22135
+ resultId: string2(),
22136
+ panelId: string2(),
22137
+ specimenAt: exports_coerce.date(),
22138
+ labName: string2().nullable(),
22139
+ status: healthLabPanelStatusSchema,
22140
+ valueNum: number2().nullable(),
22141
+ valueText: string2().nullable(),
22142
+ unit: string2().nullable(),
22143
+ refLow: number2().nullable(),
22144
+ refHigh: number2().nullable(),
22145
+ flag: healthLabFlagSchema.nullable(),
22146
+ fileId: string2().nullable(),
22147
+ fileMime: string2().nullable().default(null),
22148
+ source: healthEntrySourceSchema.default("manual")
22169
22149
  });
22170
- var postDeleteFrameSchema = frame("post.delete", { postId: ulidSchema });
22171
- var typingFrameSchema = frame("typing", { threadId: ulidSchema, on: boolean3() });
22172
- var promptFrameSchema = frame("prompt", { prompt: agentPromptSchema });
22173
- var promptCloseFrameSchema = frame("prompt.close", {
22174
- promptId: string2().min(1),
22175
- optionId: string2().optional(),
22176
- expired: boolean3()
22150
+ var healthLabAnalyteViewSchema = object({
22151
+ analyte: string2(),
22152
+ name: string2(),
22153
+ group: labGroupSchema,
22154
+ loinc: string2().nullable(),
22155
+ unit: string2().nullable(),
22156
+ points: array(healthLabPointSchema),
22157
+ target: object({
22158
+ low: number2().nullable(),
22159
+ high: number2().nullable(),
22160
+ byContactId: string2().nullable(),
22161
+ byName: string2().nullable(),
22162
+ note: string2().nullable()
22163
+ }).nullable(),
22164
+ medication: object({
22165
+ id: string2(),
22166
+ title: string2(),
22167
+ dose: string2().nullable(),
22168
+ schedule: healthMedicationScheduleSchema,
22169
+ habitId: string2().nullable()
22170
+ }).nullable()
22177
22171
  });
22178
- var attachmentTranscriptFrameSchema = frame("attachment.transcript", {
22179
- attachmentId: ulidSchema,
22180
- text: string2().trim().min(1).max(AGENT_TRANSCRIPT_MAX)
22172
+ var healthLabOverviewSchema = object({
22173
+ draws: number2().int(),
22174
+ firstAt: exports_coerce.date().nullable(),
22175
+ lastAt: exports_coerce.date().nullable(),
22176
+ lastLab: string2().nullable(),
22177
+ analytes: array(healthLabAnalyteViewSchema)
22178
+ });
22179
+ var healthLabResultInputSchema = object({
22180
+ id: ulidSchema.optional(),
22181
+ analyte: labAnalyteKeySchema.optional(),
22182
+ name: title2,
22183
+ group: labGroupSchema.optional(),
22184
+ loinc: text3(20).nullish(),
22185
+ valueNum: amount.nullish(),
22186
+ valueText: text3(200).nullish(),
22187
+ unit: text3(40).nullish(),
22188
+ refLow: amount.nullish(),
22189
+ refHigh: amount.nullish(),
22190
+ flag: healthLabFlagSchema.nullish(),
22191
+ comment: text3(1000).nullish()
22192
+ }).strict().refine((r) => r.valueNum != null || r.valueText != null, {
22193
+ message: "a result needs valueNum or valueText"
22194
+ });
22195
+ var createHealthLabPanelInputSchema = object({
22196
+ id: ulidSchema.optional(),
22197
+ title: title2.optional(),
22198
+ specimenAt: instant2,
22199
+ labName: text3(200).nullish(),
22200
+ orderedByContactId: ulidSchema.nullish(),
22201
+ encounterId: ulidSchema.nullish(),
22202
+ fileId: ulidSchema.nullish(),
22203
+ status: healthLabPanelStatusSchema.optional(),
22204
+ source: healthEntrySourceSchema.optional(),
22205
+ note: text3(2000).nullish(),
22206
+ results: array(healthLabResultInputSchema).max(200).optional(),
22207
+ subjectNodeId: ulidSchema.nullish()
22208
+ }).strict();
22209
+ var updateHealthLabPanelInputSchema = createHealthLabPanelInputSchema.omit({ id: true, subjectNodeId: true }).partial().strict();
22210
+ var healthLabImportFieldsSchema = object({ text: string2().max(200000).optional() }).strict();
22211
+ var healthLabImportResultSchema = object({
22212
+ format: _enum2(["kmehr", "pdf"]),
22213
+ found: number2().int(),
22214
+ panel: healthLabPanelViewSchema
22215
+ });
22216
+ var setHealthLabAnalyteInputSchema = object({
22217
+ targetLow: amount.nullish(),
22218
+ targetHigh: amount.nullish(),
22219
+ targetByContactId: ulidSchema.nullish(),
22220
+ medicationId: ulidSchema.nullish(),
22221
+ note: text3(1000).nullish()
22222
+ }).strict().refine((t) => t.targetLow == null || t.targetHigh == null || t.targetLow <= t.targetHigh, {
22223
+ message: "targetLow must not be above targetHigh"
22181
22224
  });
22182
- var postUnseenAckFrameSchema = frame("post.unseen.ack", { postId: ulidSchema });
22183
- var agentGatewayClientFrameSchema = discriminatedUnion("type", [
22184
- messageAckFrameSchema,
22185
- postUnseenAckFrameSchema,
22186
- postFrameSchema,
22187
- postEditFrameSchema,
22188
- postDeleteFrameSchema,
22189
- typingFrameSchema,
22190
- promptFrameSchema,
22191
- promptCloseFrameSchema,
22192
- attachmentTranscriptFrameSchema
22193
- ]);
22194
- var SERVER_FRAME_TYPES = new Set(agentGatewayServerFrameSchema.options.map((o) => o.shape.type.value));
22195
- var CLIENT_FRAME_TYPES = new Set(agentGatewayClientFrameSchema.options.map((o) => o.shape.type.value));
22196
- var agentThreadsResponseSchema = object({ threads: array(gatewayThreadSchema) });
22197
- function homeSlugFor(agentName) {
22198
- const slug = agentName.normalize("NFKD").replace(/[\u0300-\u036F]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
22199
- return slug || "agent";
22200
- }
22201
22225
 
22202
22226
  // ../../packages/schema/src/contracts/files.ts
22203
22227
  var FILE_TEXT_MAX = 1e6;
@@ -22867,13 +22891,21 @@ var timeBlockStepSchema = object({
22867
22891
  title: string2(),
22868
22892
  refKind: _enum2(["free", "habit", "task"]),
22869
22893
  status: _enum2(["done", "skipped", "open"]),
22870
- at: exports_coerce.date().nullable()
22894
+ at: exports_coerce.date().nullable(),
22895
+ habitId: string2().nullable().optional()
22871
22896
  });
22897
+ var timeBlockEvidenceOriginSchema = discriminatedUnion("kind", [
22898
+ object({ kind: literal("habit"), id: string2() }),
22899
+ object({ kind: literal("thread"), id: string2() }),
22900
+ object({ kind: literal("url"), url: url({ protocol: /^https?$/ }) })
22901
+ ]);
22872
22902
  var timeBlockEvidenceSchema = object({
22873
- source: _enum2(["habit", "check_in", "you", "agent", "plan"]),
22903
+ source: _enum2(["habit", "check_in", "you", "agent", "device", "github", "do", "plan"]),
22874
22904
  label: string2(),
22875
22905
  at: exports_coerce.date().nullable(),
22876
- agentName: string2().nullable()
22906
+ agentName: string2().nullable(),
22907
+ via: string2().nullable().optional(),
22908
+ origin: timeBlockEvidenceOriginSchema.nullable().optional()
22877
22909
  });
22878
22910
  var timeBlockReplacementSchema = object({
22879
22911
  id: string2(),
@@ -24470,6 +24502,12 @@ var moneyBudgetCopyResultSchema = object({
24470
24502
  copied: number2().int(),
24471
24503
  kept: number2().int()
24472
24504
  });
24505
+ var draftMoneyBudgetInputSchema = object({ month: moneyMonthSchema, months: number2().int().min(1).max(12).optional() }).strict();
24506
+ var moneyBudgetDraftResultSchema = object({
24507
+ lines: array(object({ id: ulidSchema, categoryId: ulidSchema, name: string2(), planned: amount3 })),
24508
+ kept: number2().int(),
24509
+ months: number2().int()
24510
+ });
24473
24511
  var moneyBudgetRowSchema = object({
24474
24512
  categoryId: ulidSchema,
24475
24513
  name: string2(),
@@ -28195,7 +28233,7 @@ function parseCapture2(input, now) {
28195
28233
 
28196
28234
  // src/meta.ts
28197
28235
  var CLI_NAME = "do";
28198
- var VERSION = "1.274.0";
28236
+ var VERSION = "1.276.0";
28199
28237
  var API_PREFIX = "/api/v1";
28200
28238
  var DEFAULT_API_URL = "http://localhost:3001";
28201
28239
 
@@ -29360,7 +29398,7 @@ var HEALTH_COMMAND_SPECS = [
29360
29398
  flags: [DATA_FLAG],
29361
29399
  scopes: WRITE2,
29362
29400
  returns: "HealthReceipt",
29363
- notes: 'Body: LogHealthInput, e.g. {"episode":{"title":"Sprained ankle","bodyRegion":"ankle_l"},"symptom":{"symptom":"worse on the stairs","severity":6,"severityGuessed":true},"dose":{"medication":"Ibuprofen"}}. The receipt lists each part with a line, what was guessed, and its undo.'
29401
+ notes: 'Body: LogHealthInput, e.g. {"episode":{"title":"Sprained ankle","bodyRegion":"ankle_l"},"symptom":{"symptom":"worse on the stairs","severity":6,"severityGuessed":true},"dose":{"medication":"Ibuprofen"}}. The receipt lists each part with a line, what was guessed, and its undo. With "thread":{"slug":"<agent>"} (only an agent key that converses) the receipt card is posted there too, and postId names it.'
29364
29402
  },
29365
29403
  {
29366
29404
  path: ["health", "fix"],
@@ -29382,6 +29420,23 @@ var HEALTH_COMMAND_SPECS = [
29382
29420
  returns: "HealthReceipt",
29383
29421
  notes: "One a day: a second check-in the same day corrects the first. The receipt carries its undo."
29384
29422
  },
29423
+ {
29424
+ path: ["health", "red-flags"],
29425
+ summary: "Record the red-flag screen answered in chat: do health red-flags <episode> --no fever,vomiting.",
29426
+ args: [{ name: "episode", required: true, description: "The Episode's id." }],
29427
+ flags: [
29428
+ { name: "no", type: "string", description: "The flags said no to, comma-separated." },
29429
+ { name: "yes", type: "string", description: "The flags said yes to, comma-separated." },
29430
+ {
29431
+ name: "thread",
29432
+ type: "string",
29433
+ description: "Post the confirmation card in this thread (by slug); the agent's key only."
29434
+ }
29435
+ ],
29436
+ scopes: WRITE2,
29437
+ returns: "HealthRedFlagsResult",
29438
+ notes: "Flags: fever, vomiting, black_stools, blood, weight_loss, night_pain, chest_pain, short_of_breath. Answers merge into those asked before; the Episode is marked checked today, and For the doctor shows it."
29439
+ },
29385
29440
  {
29386
29441
  path: ["health", "undo"],
29387
29442
  summary: "Take back what a receipt wrote: do health undo entry|dose|episode <id>.",
@@ -32833,6 +32888,18 @@ var COMMAND_SPECS = [
32833
32888
  returns: "{ ok, removed }",
32834
32889
  notes: "DELETE /api/v1/money/budget/lines/{id}."
32835
32890
  },
32891
+ {
32892
+ path: ["money", "budget-draft"],
32893
+ summary: "Draft a month's household plan from the months before it (the agent's lines).",
32894
+ args: [],
32895
+ flags: [
32896
+ { name: "month", type: "string", description: "The month to plan, YYYY-MM." },
32897
+ { name: "months", type: "string", description: "How many months back to read (default 3)." }
32898
+ ],
32899
+ scopes: ["finance:write"],
32900
+ returns: "{ lines, kept, months }",
32901
+ notes: "POST /api/v1/money/budget/draft. Undo by taking the lines out: `do money budget-remove <id>`."
32902
+ },
32836
32903
  {
32837
32904
  path: ["money", "budget-copy"],
32838
32905
  summary: "Copy a month's plan into another (lines already there are kept).",
@@ -37280,6 +37347,14 @@ var HANDLERS = {
37280
37347
  await requireClient().delete(`/money/budget/lines/${id}`);
37281
37348
  return { data: { ok: true, removed: id }, render: renderRecord };
37282
37349
  },
37350
+ "money budget-draft": async ({ flags, requireClient }) => {
37351
+ const months = flagString(flags, "months");
37352
+ const body = parseInput(draftMoneyBudgetInputSchema, {
37353
+ month: requireFlag(flags, "month", "money budget-draft needs --month <YYYY-MM>"),
37354
+ ...months ? { months: Number(months) } : {}
37355
+ });
37356
+ return { data: await requireClient().post("/money/budget/draft", body), render: renderRecord };
37357
+ },
37283
37358
  "money budget-copy": async ({ flags, requireClient }) => {
37284
37359
  const body = parseInput(copyMoneyBudgetInputSchema, {
37285
37360
  from: requireFlag(flags, "from", "money budget-copy needs --from <YYYY-MM>"),
@@ -37524,6 +37599,23 @@ var HANDLERS = {
37524
37599
  render: renderRecord
37525
37600
  };
37526
37601
  },
37602
+ "health red-flags": async ({ args, flags, requireClient }) => {
37603
+ const episodeId = requireArg(args, 0, "episode");
37604
+ const list = (name) => (flagString(flags, name) ?? "").split(",").map((f) => f.trim()).filter(Boolean);
37605
+ const answers = Object.fromEntries([
37606
+ ...list("no").map((f) => [f, false]),
37607
+ ...list("yes").map((f) => [f, true])
37608
+ ]);
37609
+ const thread = flagString(flags, "thread");
37610
+ const body = parseInput(healthRedFlagsInputSchema, {
37611
+ answers,
37612
+ ...thread ? { thread: { slug: thread } } : {}
37613
+ });
37614
+ return {
37615
+ data: await requireClient().post(`/health/episodes/${episodeId}/red-flags`, body),
37616
+ render: renderRecord
37617
+ };
37618
+ },
37527
37619
  "health undo": async ({ args, requireClient }) => {
37528
37620
  const body = parseInput(healthUndoInputSchema, {
37529
37621
  kind: requireArg(args, 0, "kind"),