@robbeverhelst/do 1.274.0 → 1.275.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 +928 -843
  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()
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()
21394
21302
  });
21395
- var healthConditionViewSchema = createSelectSchema(healthConditions, {
21396
- bodyRegions: array(string2())
21397
- }).extend({
21398
- ...spine,
21399
- careTeam: array(healthCareTeamMemberSchema).default([])
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)
21400
21314
  });
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()
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"]
21410
21325
  });
21411
- var healthSymptomEntrySchema = createSelectSchema(healthSymptomEntries, {
21412
- occurredAt: exports_coerce.date(),
21413
- recordedAt: exports_coerce.date(),
21414
- qualifiers: record(string2(), unknown())
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()
21333
+ }).strict();
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"]
21415
21346
  });
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()
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()
21423
21379
  });
21424
- var healthMedicationViewSchema = createSelectSchema(healthMedications).extend({
21425
- ...spine,
21426
- lastTakenAt: exports_coerce.date().nullable()
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
21393
+ }).optional()
21427
21394
  });
21428
- var healthMedicationDoseSchema = createSelectSchema(healthMedicationDoses, {
21429
- takenAt: exports_coerce.date(),
21430
- createdAt: exports_coerce.date()
21431
- }).extend({
21432
- medicationTitle: string2()
21395
+ var agentChangesPageSchema = object({
21396
+ data: array(agentChangeSchema),
21397
+ nextCursor: string2()
21433
21398
  });
21434
- var healthEpisodeDetailSchema = healthEpisodeViewSchema.extend({
21435
- entries: array(healthSymptomEntrySchema),
21436
- doses: array(healthMedicationDoseSchema),
21437
- encounters: array(healthEncounterViewSchema),
21438
- condition: healthConditionViewSchema.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()
21439
21404
  });
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)
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()
21446
21418
  });
21447
- var healthConsentStateSchema = object({
21448
- granted: boolean3(),
21449
- version: string2().nullable(),
21450
- grantedAt: exports_coerce.date().nullable()
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()
21451
21430
  });
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
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")
21477
21434
  }).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
- }
21435
+ var agentUndoResultSchema = object({
21436
+ id: string2(),
21437
+ undone: _enum2(["removed", "restored"])
21494
21438
  });
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"
21439
+ var agentRedoResultSchema = object({
21440
+ id: string2(),
21441
+ redone: literal(true)
21512
21442
  });
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()
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()
21448
+ });
21449
+
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"
21466
+ });
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()
21553
21472
  }).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()
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([])
21566
21478
  }).strict();
21567
- var grantHealthConsentInputSchema = object({ version: literal(HEALTH_CONSENT_VERSION) }).strict();
21568
- var healthEpisodeListQuerySchema = object({
21569
- status: healthEpisodeStatusSchema.optional()
21479
+ var gatewayMemberSchema = object({
21480
+ id: string2().min(1),
21481
+ name: string2(),
21482
+ role: baseRoleSchema
21570
21483
  });
21571
- var upsertHealthEpisodeInputSchema = episodeFields;
21572
- var logDoseFields = logHealthDoseInputSchema.omit({ episodeId: true, source: true }).extend({
21573
- medicationId: ulidSchema.optional(),
21574
- medication: text2(200).optional()
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()
21575
21491
  });
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"
21582
- }).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)"
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),
21499
+ name: string2(),
21500
+ size: number2().int().nonnegative(),
21501
+ durationMs: number2().int().nonnegative().optional(),
21502
+ transcript: string2().optional()
21587
21503
  });
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
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()
21607
21517
  });
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()
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")
21613
21525
  });
21614
- var healthCourseDaySchema = object({
21615
- day: string2(),
21616
- severity: number2().int().nullable(),
21617
- entries: number2().int()
21526
+ var postRunSchema = object({
21527
+ status: runStatusSchema,
21528
+ steps: array(runStepSchema).max(12).optional()
21618
21529
  });
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)
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()
21626
21541
  });
21627
- var healthSummaryLabSchema = object({
21628
- 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
- }))
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()
21640
21558
  });
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() }))
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"
21647
21568
  });
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([])
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("")
21663
21574
  });
21664
- var healthSummaryQuerySchema = object({ episodeId: ulidSchema.optional() });
21665
-
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()
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()
21692
21585
  });
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()
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()
21600
+ });
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
21606
+ });
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([])
21622
+ });
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
21702
21632
  });
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")
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()
21718
21639
  });
21719
- var healthLabAnalyteViewSchema = object({
21720
- analyte: string2(),
21721
- 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()
21640
+ var interruptFrameSchema = frame("interrupt", {
21641
+ threadId: ulidSchema,
21642
+ memberId: string2().min(1)
21740
21643
  });
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)
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()
21747
21650
  });
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"
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()
21763
21660
  });
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
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
21784
21678
  });
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"
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()
21686
+ });
21687
+ var attachmentTranscriptFrameSchema = frame("attachment.transcript", {
21688
+ attachmentId: ulidSchema,
21689
+ text: string2().trim().min(1).max(AGENT_TRANSCRIPT_MAX)
21793
21690
  });
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
21702
+ ]);
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
+ }
21794
21710
 
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()
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(),
21803
+ createdAt: exports_coerce.date(),
21804
+ updatedAt: exports_coerce.date()
21805
+ };
21806
+ var healthCareTeamMemberSchema = object({
21807
+ contactId: string2(),
21808
+ name: string2(),
21809
+ phone: string2().nullable(),
21810
+ label: string2().nullable()
21803
21811
  });
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)
21812
+ var healthConditionViewSchema = createSelectSchema(healthConditions, {
21813
+ bodyRegions: array(string2())
21814
+ }).extend({
21815
+ ...spine,
21816
+ careTeam: array(healthCareTeamMemberSchema).default([])
21815
21817
  });
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"]
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()
21826
21827
  });
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"]
21828
+ var healthSymptomEntrySchema = createSelectSchema(healthSymptomEntries, {
21829
+ occurredAt: exports_coerce.date(),
21830
+ recordedAt: exports_coerce.date(),
21831
+ qualifiers: record(string2(), unknown())
21847
21832
  });
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()
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()
21880
21840
  });
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()
21841
+ var healthMedicationViewSchema = createSelectSchema(healthMedications).extend({
21842
+ ...spine,
21843
+ lastTakenAt: exports_coerce.date().nullable()
21895
21844
  });
21896
- var agentChangesPageSchema = object({
21897
- data: array(agentChangeSchema),
21898
- nextCursor: string2()
21845
+ var healthMedicationDoseSchema = createSelectSchema(healthMedicationDoses, {
21846
+ takenAt: exports_coerce.date(),
21847
+ createdAt: exports_coerce.date()
21848
+ }).extend({
21849
+ medicationTitle: string2()
21899
21850
  });
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()
21851
+ var healthEpisodeDetailSchema = healthEpisodeViewSchema.extend({
21852
+ entries: array(healthSymptomEntrySchema),
21853
+ doses: array(healthMedicationDoseSchema),
21854
+ encounters: array(healthEncounterViewSchema),
21855
+ condition: healthConditionViewSchema.nullable()
21905
21856
  });
21906
- var agentConfirmationKindSchema = _enum2(["delete", "cancel", "google", "orca", "bulk"]);
21907
- var agentConfirmationStatusSchema = _enum2([
21908
- "pending",
21909
- "confirmed",
21910
- "done",
21911
- "failed",
21912
- "declined"
21913
- ]);
21914
- var agentConfirmationItemSchema = object({
21915
- id: string2(),
21916
- title: string2().nullable(),
21917
- area: string2().nullable().optional(),
21918
- dueAt: exports_coerce.date().nullable().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)
21919
21863
  });
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() }),
21929
- createdAt: exports_coerce.date(),
21930
- decidedAt: exports_coerce.date().nullable()
21864
+ var healthConsentStateSchema = object({
21865
+ granted: boolean3(),
21866
+ version: string2().nullable(),
21867
+ grantedAt: exports_coerce.date().nullable()
21931
21868
  });
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")
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
21935
21881
  }).strict();
21936
- var agentUndoResultSchema = object({
21937
- id: string2(),
21938
- undone: _enum2(["removed", "restored"])
21939
- });
21940
- var agentRedoResultSchema = object({
21941
- id: string2(),
21942
- redone: literal(true)
21943
- });
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()
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
+ }
21949
21911
  });
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"
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"
21967
21929
  });
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()
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
21973
21944
  }).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([])
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
21979
21960
  }).strict();
21980
- var gatewayMemberSchema = object({
21981
- id: string2().min(1),
21982
- name: string2(),
21983
- role: baseRoleSchema
21984
- });
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()
21992
- });
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()
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()
22004
21987
  });
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()
21988
+ var upsertHealthEpisodeInputSchema = episodeFields;
21989
+ var logDoseFields = logHealthDoseInputSchema.omit({ episodeId: true, source: true }).extend({
21990
+ medicationId: ulidSchema.optional(),
21991
+ medication: text2(200).optional()
22018
21992
  });
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")
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)"
22026
22005
  });
22027
- var postRunSchema = object({
22028
- status: runStatusSchema,
22029
- steps: array(runStepSchema).max(12).optional()
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
22030
22025
  });
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()
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()
22049
22032
  });
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"
22033
+ var healthRedFlagsInputSchema = object({
22034
+ answers: redFlagsSchema.refine((a) => Object.keys(a).length > 0, {
22035
+ message: "answer at least one red flag"
22036
+ }),
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()
22059
22044
  });
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("")
22045
+ var healthCourseDaySchema = object({
22046
+ day: string2(),
22047
+ severity: number2().int().nullable(),
22048
+ entries: number2().int()
22065
22049
  });
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()
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)
22076
22057
  });
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()
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
+ }))
22091
22071
  });
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
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() }))
22097
22078
  });
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
22108
- }),
22109
- members: array(gatewayMemberSchema),
22110
- threads: array(gatewayThreadSchema),
22111
- heartbeatSec: number2().int().positive(),
22112
- hints: array(string2()).default([])
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([])
22113
22094
  });
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
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
22123
  });
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()
22124
+ var healthLabPanelViewSchema = createSelectSchema(healthLabPanels, {
22125
+ specimenAt: exports_coerce.date()
22126
+ }).extend({
22127
+ title: string2(),
22128
+ createdAt: exports_coerce.date(),
22129
+ updatedAt: exports_coerce.date(),
22130
+ orderedByName: string2().nullable(),
22131
+ results: array(healthLabResultSchema),
22132
+ unmatched: array(string2()).optional()
22130
22133
  });
22131
- var interruptFrameSchema = frame("interrupt", {
22132
- threadId: ulidSchema,
22133
- memberId: string2().min(1)
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")
22134
22149
  });
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()
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()
22141
22171
  });
22142
- var unseenPostSchema = object({
22143
- postId: ulidSchema,
22144
- threadId: ulidSchema,
22145
- memberId: string2().min(1),
22146
- title: string2(),
22147
- threadTitle: string2().nullable(),
22148
- path: string2().startsWith("/"),
22149
- url: string2().url().nullable(),
22150
- pushedAt: string2().datetime()
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)
22151
22178
  });
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
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"
22169
22194
  });
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()
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
22177
22215
  });
22178
- var attachmentTranscriptFrameSchema = frame("attachment.transcript", {
22179
- attachmentId: ulidSchema,
22180
- text: string2().trim().min(1).max(AGENT_TRANSCRIPT_MAX)
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;
@@ -22870,10 +22894,11 @@ var timeBlockStepSchema = object({
22870
22894
  at: exports_coerce.date().nullable()
22871
22895
  });
22872
22896
  var timeBlockEvidenceSchema = object({
22873
- source: _enum2(["habit", "check_in", "you", "agent", "plan"]),
22897
+ source: _enum2(["habit", "check_in", "you", "agent", "device", "github", "do", "plan"]),
22874
22898
  label: string2(),
22875
22899
  at: exports_coerce.date().nullable(),
22876
- agentName: string2().nullable()
22900
+ agentName: string2().nullable(),
22901
+ via: string2().nullable().optional()
22877
22902
  });
22878
22903
  var timeBlockReplacementSchema = object({
22879
22904
  id: string2(),
@@ -24470,6 +24495,12 @@ var moneyBudgetCopyResultSchema = object({
24470
24495
  copied: number2().int(),
24471
24496
  kept: number2().int()
24472
24497
  });
24498
+ var draftMoneyBudgetInputSchema = object({ month: moneyMonthSchema, months: number2().int().min(1).max(12).optional() }).strict();
24499
+ var moneyBudgetDraftResultSchema = object({
24500
+ lines: array(object({ id: ulidSchema, categoryId: ulidSchema, name: string2(), planned: amount3 })),
24501
+ kept: number2().int(),
24502
+ months: number2().int()
24503
+ });
24473
24504
  var moneyBudgetRowSchema = object({
24474
24505
  categoryId: ulidSchema,
24475
24506
  name: string2(),
@@ -28195,7 +28226,7 @@ function parseCapture2(input, now) {
28195
28226
 
28196
28227
  // src/meta.ts
28197
28228
  var CLI_NAME = "do";
28198
- var VERSION = "1.274.0";
28229
+ var VERSION = "1.275.0";
28199
28230
  var API_PREFIX = "/api/v1";
28200
28231
  var DEFAULT_API_URL = "http://localhost:3001";
28201
28232
 
@@ -29360,7 +29391,7 @@ var HEALTH_COMMAND_SPECS = [
29360
29391
  flags: [DATA_FLAG],
29361
29392
  scopes: WRITE2,
29362
29393
  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.'
29394
+ 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
29395
  },
29365
29396
  {
29366
29397
  path: ["health", "fix"],
@@ -29382,6 +29413,23 @@ var HEALTH_COMMAND_SPECS = [
29382
29413
  returns: "HealthReceipt",
29383
29414
  notes: "One a day: a second check-in the same day corrects the first. The receipt carries its undo."
29384
29415
  },
29416
+ {
29417
+ path: ["health", "red-flags"],
29418
+ summary: "Record the red-flag screen answered in chat: do health red-flags <episode> --no fever,vomiting.",
29419
+ args: [{ name: "episode", required: true, description: "The Episode's id." }],
29420
+ flags: [
29421
+ { name: "no", type: "string", description: "The flags said no to, comma-separated." },
29422
+ { name: "yes", type: "string", description: "The flags said yes to, comma-separated." },
29423
+ {
29424
+ name: "thread",
29425
+ type: "string",
29426
+ description: "Post the confirmation card in this thread (by slug); the agent's key only."
29427
+ }
29428
+ ],
29429
+ scopes: WRITE2,
29430
+ returns: "HealthRedFlagsResult",
29431
+ 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."
29432
+ },
29385
29433
  {
29386
29434
  path: ["health", "undo"],
29387
29435
  summary: "Take back what a receipt wrote: do health undo entry|dose|episode <id>.",
@@ -32833,6 +32881,18 @@ var COMMAND_SPECS = [
32833
32881
  returns: "{ ok, removed }",
32834
32882
  notes: "DELETE /api/v1/money/budget/lines/{id}."
32835
32883
  },
32884
+ {
32885
+ path: ["money", "budget-draft"],
32886
+ summary: "Draft a month's household plan from the months before it (the agent's lines).",
32887
+ args: [],
32888
+ flags: [
32889
+ { name: "month", type: "string", description: "The month to plan, YYYY-MM." },
32890
+ { name: "months", type: "string", description: "How many months back to read (default 3)." }
32891
+ ],
32892
+ scopes: ["finance:write"],
32893
+ returns: "{ lines, kept, months }",
32894
+ notes: "POST /api/v1/money/budget/draft. Undo by taking the lines out: `do money budget-remove <id>`."
32895
+ },
32836
32896
  {
32837
32897
  path: ["money", "budget-copy"],
32838
32898
  summary: "Copy a month's plan into another (lines already there are kept).",
@@ -37280,6 +37340,14 @@ var HANDLERS = {
37280
37340
  await requireClient().delete(`/money/budget/lines/${id}`);
37281
37341
  return { data: { ok: true, removed: id }, render: renderRecord };
37282
37342
  },
37343
+ "money budget-draft": async ({ flags, requireClient }) => {
37344
+ const months = flagString(flags, "months");
37345
+ const body = parseInput(draftMoneyBudgetInputSchema, {
37346
+ month: requireFlag(flags, "month", "money budget-draft needs --month <YYYY-MM>"),
37347
+ ...months ? { months: Number(months) } : {}
37348
+ });
37349
+ return { data: await requireClient().post("/money/budget/draft", body), render: renderRecord };
37350
+ },
37283
37351
  "money budget-copy": async ({ flags, requireClient }) => {
37284
37352
  const body = parseInput(copyMoneyBudgetInputSchema, {
37285
37353
  from: requireFlag(flags, "from", "money budget-copy needs --from <YYYY-MM>"),
@@ -37524,6 +37592,23 @@ var HANDLERS = {
37524
37592
  render: renderRecord
37525
37593
  };
37526
37594
  },
37595
+ "health red-flags": async ({ args, flags, requireClient }) => {
37596
+ const episodeId = requireArg(args, 0, "episode");
37597
+ const list = (name) => (flagString(flags, name) ?? "").split(",").map((f) => f.trim()).filter(Boolean);
37598
+ const answers = Object.fromEntries([
37599
+ ...list("no").map((f) => [f, false]),
37600
+ ...list("yes").map((f) => [f, true])
37601
+ ]);
37602
+ const thread = flagString(flags, "thread");
37603
+ const body = parseInput(healthRedFlagsInputSchema, {
37604
+ answers,
37605
+ ...thread ? { thread: { slug: thread } } : {}
37606
+ });
37607
+ return {
37608
+ data: await requireClient().post(`/health/episodes/${episodeId}/red-flags`, body),
37609
+ render: renderRecord
37610
+ };
37611
+ },
37527
37612
  "health undo": async ({ args, requireClient }) => {
37528
37613
  const body = parseInput(healthUndoInputSchema, {
37529
37614
  kind: requireArg(args, 0, "kind"),