types.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { z } from 'zod';
  2. export interface InterviewQuestion {
  3. id: string;
  4. question: string;
  5. options: string[];
  6. suggested?: string;
  7. }
  8. export interface InterviewAnswer {
  9. questionId: string;
  10. answer: string;
  11. }
  12. export interface InterviewAssistantState {
  13. summary: string;
  14. title?: string;
  15. questions: InterviewQuestion[];
  16. }
  17. // ─── Zod Schemas (for validating untrusted LLM output) ─────────────
  18. /** Raw question object from LLM output - loose, everything optional. */
  19. export const RawQuestionSchema = z.object({
  20. id: z.string().optional(),
  21. question: z.string().optional(),
  22. options: z.array(z.unknown()).optional(),
  23. suggested: z.unknown().optional(),
  24. });
  25. /** Raw interview_state block from LLM output. */
  26. export const RawInterviewStateSchema = z.object({
  27. summary: z.unknown().optional(),
  28. title: z.unknown().optional(),
  29. questions: z.array(z.unknown()).optional(),
  30. });
  31. // ─── Interfaces ─────────────────────────────────────────────────────
  32. export interface InterviewRecord {
  33. id: string;
  34. sessionID: string;
  35. idea: string;
  36. markdownPath: string;
  37. createdAt: string;
  38. abandonedAt?: string;
  39. abandonedOrder?: number;
  40. status: 'active' | 'abandoned';
  41. baseMessageCount: number;
  42. }
  43. export interface InterviewMessagePart {
  44. type?: string;
  45. text?: string;
  46. }
  47. export interface InterviewMessage {
  48. info?: {
  49. role?: string;
  50. [key: string]: unknown;
  51. };
  52. parts?: InterviewMessagePart[];
  53. }
  54. export interface InterviewListItem {
  55. id: string;
  56. idea: string;
  57. status: InterviewRecord['status'];
  58. createdAt: string;
  59. }
  60. export interface InterviewFileItem {
  61. fileName: string;
  62. resumeCommand: string;
  63. title: string;
  64. summary: string;
  65. sessionID?: string;
  66. directory?: string;
  67. }
  68. export interface SpecBlock {
  69. id: string;
  70. title: string;
  71. content: string;
  72. }
  73. export interface InterviewState {
  74. interview: InterviewRecord;
  75. url: string;
  76. markdownPath: string;
  77. mode:
  78. | 'awaiting-agent'
  79. | 'awaiting-user'
  80. | 'abandoned'
  81. | 'completed'
  82. | 'error'
  83. | 'session-disconnected';
  84. lastParseError?: string;
  85. isBusy: boolean;
  86. summary: string;
  87. questions: InterviewQuestion[];
  88. document: string;
  89. blocks: SpecBlock[];
  90. }
  91. /** Wire format for dashboard state cache entries. */
  92. export interface InterviewStateEntry {
  93. interviewId: string;
  94. sessionID: string;
  95. idea: string;
  96. mode:
  97. | 'awaiting-agent'
  98. | 'awaiting-user'
  99. | 'abandoned'
  100. | 'completed'
  101. | 'error'
  102. | 'session-disconnected';
  103. summary: string;
  104. title: string;
  105. questions: Array<{
  106. id: string;
  107. question: string;
  108. options?: string[];
  109. suggested?: string;
  110. }>;
  111. pendingAnswers: Array<{
  112. questionId: string;
  113. answer: string;
  114. }> | null;
  115. lastUpdatedAt: number;
  116. filePath: string;
  117. nudgeAction: 'more-questions' | 'confirm-complete' | null;
  118. pendingBlockComment: {
  119. section: string;
  120. comment: string;
  121. } | null;
  122. pendingChatMessage: string | null;
  123. document?: string;
  124. blocks?: SpecBlock[];
  125. }