@lota-sdk/shared 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lota-sdk/shared",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -25,7 +25,7 @@
25
25
  "registry": "https://registry.npmjs.org/"
26
26
  },
27
27
  "dependencies": {
28
- "ai": "^6.0.116",
28
+ "ai": "^6.0.137",
29
29
  "zod": "^4.3.6"
30
30
  }
31
31
  }
@@ -0,0 +1,34 @@
1
+ export const OPENAI_REASONING_MODEL_ID = 'openai/gpt-5.4' as const
2
+
3
+ export const OPENROUTER_TEAM_AGENT_MODEL_ID = 'openrouter/google/gemini-3.1-pro-preview' as const
4
+ export const OPENROUTER_STRUCTURED_HELPER_MODEL_ID = 'openrouter/google/gemini-3-flash-preview:exacto' as const
5
+ export const OPENROUTER_DELEGATED_REASONING_MODEL_ID = 'openrouter/google/gemini-3-flash-preview:exacto' as const
6
+ export const OPENROUTER_WEB_RESEARCH_MODEL_ID = 'openrouter/stepfun/step-3.5-flash' as const
7
+ export const OPENROUTER_FAST_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:nitro' as const
8
+ export const OPENROUTER_STRUCTURED_REASONING_MODEL_ID = 'openrouter/openai/gpt-oss-120b:exacto' as const
9
+
10
+ export const BIFROST_REASONING_SUMMARY_LEVEL = 'detailed' as const
11
+
12
+ export const OPENAI_HIGH_REASONING_PROVIDER_OPTIONS = {
13
+ openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
14
+ } as const
15
+
16
+ export const OPENROUTER_HIGH_REASONING_PROVIDER_OPTIONS = {
17
+ openai: { forceReasoning: true, reasoningEffort: 'high', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
18
+ } as const
19
+
20
+ export const OPENROUTER_XHIGH_REASONING_PROVIDER_OPTIONS = {
21
+ openai: { forceReasoning: true, reasoningEffort: 'xhigh', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
22
+ } as const
23
+
24
+ export const OPENROUTER_MEDIUM_REASONING_PROVIDER_OPTIONS = {
25
+ openai: { forceReasoning: true, reasoningEffort: 'medium', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
26
+ } as const
27
+
28
+ export const OPENROUTER_LOW_REASONING_PROVIDER_OPTIONS = {
29
+ openai: { forceReasoning: true, reasoningEffort: 'low', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
30
+ } as const
31
+
32
+ export const OPENROUTER_MINIMAL_REASONING_PROVIDER_OPTIONS = {
33
+ openai: { forceReasoning: true, reasoningEffort: 'minimal', reasoningSummary: BIFROST_REASONING_SUMMARY_LEVEL },
34
+ } as const
@@ -0,0 +1 @@
1
+ export const VECTOR_SEARCH_OVERFETCH_MULTIPLIER = 2
package/src/index.ts CHANGED
@@ -2,14 +2,19 @@ export * from './constants/attachments'
2
2
  export * from './constants/workstream'
3
3
  export * from './runtime/agent-types'
4
4
  export * from './runtime/chat-message-metadata'
5
+ export * from './runtime/execution-plan-result'
5
6
  export * from './schemas/chat-api'
6
7
  export * from './schemas/chat-message'
7
8
  export * from './schemas/common'
9
+ export * from './schemas/confidence'
8
10
  export * from './schemas/document'
9
11
  export * from './schemas/error'
10
12
  export * from './schemas/execution-plan'
13
+ export * from './schemas/graph-designer'
11
14
  export * from './schemas/organization'
12
15
  export * from './schemas/organization-api'
16
+ export * from './schemas/playbook'
17
+ export * from './schemas/plugin-coordination'
13
18
  export * from './schemas/recent-activity'
14
19
  export * from './schemas/repository-structure'
15
20
  export * from './schemas/tools'
@@ -17,6 +22,11 @@ export * from './schemas/user'
17
22
  export * from './schemas/user-api'
18
23
  export * from './schemas/workstream'
19
24
  export * from './schemas/workstream-api'
25
+ export * from './constants/model'
26
+ export * from './constants/search'
20
27
  export * from './utils/assistant-text'
28
+ export * from './utils/confidence'
29
+ export * from './utils/date-time'
30
+ export * from './utils/errors'
21
31
  export * from './utils/markdown-normalization'
22
32
  export * from './utils/string'
@@ -9,6 +9,7 @@ export interface CreateRoutedAgentOptions<TTools extends ToolSet = ToolSet> {
9
9
  stopWhen?: StopCondition<TTools> | Array<StopCondition<TTools>>
10
10
  prepareStep?: PrepareStepFunction<TTools>
11
11
  maxRetries?: number
12
+ output?: Output.Output
12
13
  modelOverride?: { model: unknown; providerOptions?: Record<string, unknown> }
13
14
  onFinish?: ToolLoopAgentOnFinishCallback<TTools>
14
15
  }
@@ -1,16 +1,23 @@
1
+ /** Open-ended metadata bag -- index signature required for AI SDK compatibility */
1
2
  export interface MessageMetadataLike {
2
3
  createdAt?: unknown
3
4
  [key: string]: unknown
4
5
  }
5
6
 
6
- export function toTimestamp(value: unknown): number {
7
+ export function toTimestamp(value: unknown): number | undefined {
7
8
  if (typeof value === 'number' && Number.isFinite(value)) return value
8
9
  if (typeof value === 'string') {
9
10
  const parsed = Date.parse(value)
10
11
  if (Number.isFinite(parsed)) return parsed
11
12
  }
12
13
  if (value instanceof Date) return value.getTime()
13
- return Date.now()
14
+ return undefined
15
+ }
16
+
17
+ export function requireTimestamp(value: unknown): number {
18
+ const ts = toTimestamp(value)
19
+ if (ts === undefined) throw new Error(`Expected a valid timestamp, got ${String(value)}`)
20
+ return ts
14
21
  }
15
22
 
16
23
  export function getMessageCreatedAt(
@@ -18,21 +25,25 @@ export function getMessageCreatedAt(
18
25
  options?: { fallback?: number },
19
26
  ): number {
20
27
  const createdAt = toTimestamp(message.metadata?.createdAt)
21
- if (Number.isFinite(createdAt)) return createdAt
22
- return options?.fallback ?? Date.now()
28
+ if (createdAt !== undefined) return createdAt
29
+ if (options?.fallback !== undefined) return options.fallback
30
+ throw new Error('Message metadata is missing createdAt timestamp')
23
31
  }
24
32
 
25
33
  export function withCreatedAtMetadata<TMetadata extends MessageMetadataLike | undefined>(
26
34
  metadata: TMetadata,
27
- fallback = Date.now(),
35
+ createdAt?: number,
28
36
  ): NonNullable<TMetadata> & { createdAt: number } {
29
- const next =
30
- metadata && typeof metadata === 'object'
31
- ? ({ ...(metadata as Record<string, unknown>) } as NonNullable<TMetadata>)
32
- : ({} as NonNullable<TMetadata>)
37
+ const next = (
38
+ metadata && typeof metadata === 'object' ? { ...(metadata as Record<string, unknown>) } : {}
39
+ ) as NonNullable<TMetadata>
40
+
41
+ if (typeof createdAt === 'number' && Number.isFinite(createdAt)) {
42
+ next.createdAt = createdAt
43
+ }
33
44
 
34
45
  if (typeof next.createdAt !== 'number' || !Number.isFinite(next.createdAt)) {
35
- next.createdAt = fallback
46
+ throw new Error('withCreatedAtMetadata: createdAt is required but was not provided or present in metadata')
36
47
  }
37
48
 
38
49
  return next as NonNullable<TMetadata> & { createdAt: number }
@@ -40,8 +51,8 @@ export function withCreatedAtMetadata<TMetadata extends MessageMetadataLike | un
40
51
 
41
52
  export function withMessageCreatedAt<TMessage extends { metadata?: MessageMetadataLike }>(
42
53
  message: TMessage,
43
- fallback = Date.now(),
54
+ createdAt?: number,
44
55
  ): TMessage {
45
- const metadata = withCreatedAtMetadata(message.metadata, fallback)
56
+ const metadata = withCreatedAtMetadata(message.metadata, createdAt)
46
57
  return { ...message, metadata }
47
58
  }
@@ -0,0 +1,20 @@
1
+ import type { ExecutionPlanToolResultData } from '../schemas/tools'
2
+
3
+ export function isExecutionPlanResult(value: unknown): value is ExecutionPlanToolResultData {
4
+ return value !== null && value !== undefined && typeof value === 'object' && 'hasPlan' in value
5
+ }
6
+
7
+ export function getLatestExecutionPlanResult(output: unknown): ExecutionPlanToolResultData | null {
8
+ if (isExecutionPlanResult(output)) {
9
+ return output
10
+ }
11
+
12
+ if (Array.isArray(output)) {
13
+ for (let index = output.length - 1; index >= 0; index -= 1) {
14
+ const candidate = getLatestExecutionPlanResult(output[index])
15
+ if (candidate) return candidate
16
+ }
17
+ }
18
+
19
+ return null
20
+ }
@@ -30,7 +30,7 @@ export function parseRowMetadata(raw: unknown): MessageMetadata {
30
30
  return result.success ? result.data : undefined
31
31
  }
32
32
 
33
- export const dataPartsSchema = {}
33
+ export const dataPartsSchemas = {}
34
34
 
35
35
  export type CustomDataParts = {}
36
36
 
@@ -2,10 +2,10 @@ import { z } from 'zod'
2
2
 
3
3
  import { WORKSTREAM } from '../constants/workstream'
4
4
 
5
- export const unixTimestampSchema = z.coerce.date()
6
-
7
5
  const SURREALDB_RECORD_ID_CLASSES = new Set(['RecordId', 'StringRecordId'])
8
6
 
7
+ export const unixTimestampSchema = z.coerce.date()
8
+
9
9
  function coerceRecordIdToString(val: unknown): unknown {
10
10
  if (val === null || val === undefined) return val
11
11
  if (typeof val === 'string') return val
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod'
2
+
3
+ export const ConfidenceDimensionSchema = z.enum([
4
+ 'data-quality',
5
+ 'source-reliability',
6
+ 'temporal-relevance',
7
+ 'consensus',
8
+ 'completeness',
9
+ ])
10
+ export type ConfidenceDimension = z.infer<typeof ConfidenceDimensionSchema>
11
+
12
+ export const ConfidenceMethodSchema = z.enum(['weighted-average', 'min', 'bayesian'])
13
+ export type ConfidenceMethod = z.infer<typeof ConfidenceMethodSchema>
14
+
15
+ export const ConfidenceScoreSchema = z.object({
16
+ overall: z.number().min(0).max(1),
17
+ dimensions: z.record(z.string(), z.number().min(0).max(1)).default({}),
18
+ method: ConfidenceMethodSchema.default('weighted-average'),
19
+ })
20
+ export type ConfidenceScore = z.infer<typeof ConfidenceScoreSchema>
@@ -1,15 +1,24 @@
1
1
  import { z } from 'zod'
2
2
 
3
- import { recordIdSchema, unixTimestampSchema } from './common'
3
+ import { recordIdSchema } from './common'
4
+
5
+ /** For DB record schemas — accepts Date objects from SurrealDB and coerces strings */
6
+ const dbDateTimeSchema = z.coerce.date()
7
+
8
+ /** For tool/API schemas that need JSON Schema representation — accepts ISO strings only */
9
+ const apiDateTimeSchema = z.string().datetime({ offset: true })
4
10
 
5
11
  const planSchemaLiteralSchema = z.union([z.string(), z.number(), z.boolean(), z.null()])
6
12
 
13
+ /** JSON Schema enum literal type */
14
+ export type PlanSchemaLiteral = string | number | boolean | null
15
+
7
16
  export type PlanDataSchemaDefinition = {
8
17
  type: 'string' | 'number' | 'boolean' | 'object' | 'array'
9
18
  description?: string
10
19
  nullable?: boolean
11
20
  required?: boolean
12
- enum?: Array<string | number | boolean | null>
21
+ enum?: Array<PlanSchemaLiteral>
13
22
  properties?: Record<string, PlanDataSchemaDefinition>
14
23
  items?: PlanDataSchemaDefinition
15
24
  minItems?: number
@@ -46,17 +55,28 @@ export const PlanNodeTypeSchema = z
46
55
  'switch',
47
56
  'join',
48
57
  'subgraph',
58
+ 'monitoring',
59
+ 'deliberation-fork',
49
60
  ])
50
61
  .meta({ id: 'PlanNodeTypeSchema' })
51
62
  export type PlanNodeType = z.infer<typeof PlanNodeTypeSchema>
52
63
 
53
64
  export const PlanNodeExecutorTypeSchema = z
54
- .enum(['agent', 'plugin', 'user', 'system'])
65
+ .enum(['agent', 'plugin', 'user', 'system', 'skill'])
55
66
  .meta({ id: 'PlanNodeExecutorTypeSchema' })
56
67
  export type PlanNodeExecutorType = z.infer<typeof PlanNodeExecutorTypeSchema>
57
68
 
58
69
  export const PlanArtifactKindSchema = z
59
- .enum(['json', 'markdown', 'file', 'external-ref', 'record'])
70
+ .enum([
71
+ 'json',
72
+ 'markdown',
73
+ 'file',
74
+ 'external-ref',
75
+ 'record',
76
+ 'time-series',
77
+ 'deliberation-evidence',
78
+ 'recommendation',
79
+ ])
60
80
  .meta({ id: 'PlanArtifactKindSchema' })
61
81
  export type PlanArtifactKind = z.infer<typeof PlanArtifactKindSchema>
62
82
 
@@ -92,12 +112,24 @@ export const PlanSpecStatusSchema = z.enum(['compiled', 'superseded']).meta({ id
92
112
  export type PlanSpecStatus = z.infer<typeof PlanSpecStatusSchema>
93
113
 
94
114
  export const PlanRunStatusSchema = z
95
- .enum(['running', 'awaiting-human', 'blocked', 'completed', 'failed', 'aborted'])
115
+ .enum(['running', 'awaiting-human', 'blocked', 'completed', 'failed', 'aborted', 'scheduled'])
96
116
  .meta({ id: 'PlanRunStatusSchema' })
97
117
  export type PlanRunStatus = z.infer<typeof PlanRunStatusSchema>
98
118
 
99
119
  export const PlanNodeRunStatusSchema = z
100
- .enum(['pending', 'ready', 'running', 'awaiting-human', 'completed', 'partial', 'blocked', 'failed', 'skipped'])
120
+ .enum([
121
+ 'pending',
122
+ 'ready',
123
+ 'running',
124
+ 'awaiting-human',
125
+ 'completed',
126
+ 'partial',
127
+ 'blocked',
128
+ 'failed',
129
+ 'skipped',
130
+ 'scheduled',
131
+ 'monitoring',
132
+ ])
101
133
  .meta({ id: 'PlanNodeRunStatusSchema' })
102
134
  export type PlanNodeRunStatus = z.infer<typeof PlanNodeRunStatusSchema>
103
135
 
@@ -135,13 +167,49 @@ export const PlanEventTypeSchema = z
135
167
  'checkpoint-saved',
136
168
  'run-resumed',
137
169
  'validation-reported',
170
+ 'schedule-created',
171
+ 'schedule-fired',
172
+ 'schedule-missed',
173
+ 'deadline-warning',
174
+ 'deadline-missed',
175
+ 'node-scheduled',
176
+ 'node-monitoring',
177
+ 'cycle-started',
178
+ 'cycle-completed',
179
+ 'feedback-analyzed',
138
180
  ])
139
181
  .meta({ id: 'PlanEventTypeSchema' })
140
182
  export type PlanEventType = z.infer<typeof PlanEventTypeSchema>
141
183
 
142
- export const PlanNodeOwnerSchema = z
143
- .object({ executorType: PlanNodeExecutorTypeSchema, ref: z.string().trim().min(1).max(200) })
184
+ const planOwnerRefSchema = z.string().trim().min(1).max(200)
185
+ const planOwnerOperationSchema = z.string().trim().min(1).max(200)
186
+
187
+ export const AgentPlanNodeOwnerSchema = z.object({ executorType: z.literal('agent'), ref: planOwnerRefSchema }).strict()
188
+ export type AgentPlanNodeOwner = z.infer<typeof AgentPlanNodeOwnerSchema>
189
+
190
+ export const PluginPlanNodeOwnerSchema = z
191
+ .object({ executorType: z.literal('plugin'), ref: planOwnerRefSchema, operation: planOwnerOperationSchema })
192
+ .strict()
193
+ export type PluginPlanNodeOwner = z.infer<typeof PluginPlanNodeOwnerSchema>
194
+
195
+ export const UserPlanNodeOwnerSchema = z.object({ executorType: z.literal('user'), ref: planOwnerRefSchema }).strict()
196
+ export type UserPlanNodeOwner = z.infer<typeof UserPlanNodeOwnerSchema>
197
+
198
+ export const SystemPlanNodeOwnerSchema = z
199
+ .object({ executorType: z.literal('system'), ref: planOwnerRefSchema, operation: planOwnerOperationSchema })
144
200
  .strict()
201
+ export type SystemPlanNodeOwner = z.infer<typeof SystemPlanNodeOwnerSchema>
202
+
203
+ export const SkillPlanNodeOwnerSchema = z.object({ executorType: z.literal('skill'), ref: planOwnerRefSchema }).strict()
204
+ export type SkillPlanNodeOwner = z.infer<typeof SkillPlanNodeOwnerSchema>
205
+
206
+ export const PlanNodeOwnerSchema = z.discriminatedUnion('executorType', [
207
+ AgentPlanNodeOwnerSchema,
208
+ PluginPlanNodeOwnerSchema,
209
+ UserPlanNodeOwnerSchema,
210
+ SystemPlanNodeOwnerSchema,
211
+ SkillPlanNodeOwnerSchema,
212
+ ])
145
213
  export type PlanNodeOwner = z.infer<typeof PlanNodeOwnerSchema>
146
214
 
147
215
  export const PlanArtifactSpecSchema = z
@@ -192,7 +260,241 @@ export const PlanContextPolicySchema = z
192
260
  .strict()
193
261
  export type PlanContextPolicy = z.infer<typeof PlanContextPolicySchema>
194
262
 
195
- const planStructuredPayloadSchema = z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())])
263
+ export const ScheduleTypeSchema = z.enum(['immediate', 'absolute', 'relative', 'cron', 'monitoring'])
264
+ export type ScheduleType = z.infer<typeof ScheduleTypeSchema>
265
+
266
+ export const MissedSchedulePolicySchema = z.enum(['skip', 'run-immediately', 'run-next-window'])
267
+ export type MissedSchedulePolicy = z.infer<typeof MissedSchedulePolicySchema>
268
+
269
+ export const PlanScheduleSpecSchema = z
270
+ .object({
271
+ type: ScheduleTypeSchema,
272
+ at: apiDateTimeSchema.optional(),
273
+ delayMs: z.number().int().positive().optional(),
274
+ cron: z.string().trim().min(1).max(200).optional(),
275
+ intervalMs: z.number().int().positive().optional(),
276
+ maxFires: z.number().int().positive().optional(),
277
+ missedPolicy: MissedSchedulePolicySchema.default('run-immediately'),
278
+ })
279
+ .strict()
280
+ export type PlanScheduleSpec = z.infer<typeof PlanScheduleSpecSchema>
281
+
282
+ export const DeadlineActionSchema = z.enum(['notify', 'escalate', 'block', 'fail'])
283
+ export type DeadlineAction = z.infer<typeof DeadlineActionSchema>
284
+
285
+ export const DeadlineReminderSchema = z
286
+ .object({
287
+ beforeMs: z.number().int().positive(),
288
+ action: DeadlineActionSchema.default('notify'),
289
+ message: z.string().trim().min(1).max(500).optional(),
290
+ })
291
+ .strict()
292
+ export type DeadlineReminder = z.infer<typeof DeadlineReminderSchema>
293
+
294
+ export const DeadlineSpecSchema = z
295
+ .object({
296
+ dueAt: apiDateTimeSchema.optional(),
297
+ durationMs: z.number().int().positive().optional(),
298
+ reminders: z.array(DeadlineReminderSchema).default([]),
299
+ missAction: DeadlineActionSchema.default('fail'),
300
+ })
301
+ .strict()
302
+ export type DeadlineSpec = z.infer<typeof DeadlineSpecSchema>
303
+
304
+ export const NotificationSeveritySchema = z.enum(['info', 'warning', 'urgent', 'critical'])
305
+ export type NotificationSeverity = z.infer<typeof NotificationSeveritySchema>
306
+
307
+ export const PlanScheduleStatusSchema = z.enum(['active', 'paused', 'completed', 'cancelled'])
308
+ export type PlanScheduleStatus = z.infer<typeof PlanScheduleStatusSchema>
309
+
310
+ export const PlanScheduleRecordSchema = z.object({
311
+ id: recordIdSchema,
312
+ organizationId: recordIdSchema,
313
+ workstreamId: recordIdSchema,
314
+ planSpecId: recordIdSchema.optional(),
315
+ runId: recordIdSchema.optional(),
316
+ nodeId: z.string().optional(),
317
+ scheduleSpec: PlanScheduleSpecSchema,
318
+ status: PlanScheduleStatusSchema,
319
+ fireCount: z.number().int().nonnegative().default(0),
320
+ nextFireAt: dbDateTimeSchema.optional(),
321
+ lastFiredAt: dbDateTimeSchema.optional(),
322
+ createdAt: dbDateTimeSchema,
323
+ updatedAt: dbDateTimeSchema.optional(),
324
+ })
325
+ export type PlanScheduleRecord = z.infer<typeof PlanScheduleRecordSchema>
326
+
327
+ export const PlanTemplateSourceSchema = z.enum(['user', 'playbook', 'system']).default('user')
328
+ export type PlanTemplateSource = z.infer<typeof PlanTemplateSourceSchema>
329
+
330
+ export const CycleFrequencySchema = z.enum(['daily', 'weekly', 'biweekly', 'monthly', 'quarterly', 'custom'])
331
+ export type CycleFrequency = z.infer<typeof CycleFrequencySchema>
332
+
333
+ export const CarryForwardPolicySchema = z.enum(['none', 'incomplete-only', 'all-pending'])
334
+ export type CarryForwardPolicy = z.infer<typeof CarryForwardPolicySchema>
335
+
336
+ export const CycleScheduleSchema = z
337
+ .object({
338
+ frequency: CycleFrequencySchema,
339
+ customIntervalMs: z.number().int().positive().optional(),
340
+ startAt: apiDateTimeSchema,
341
+ endAt: apiDateTimeSchema.optional(),
342
+ })
343
+ .strict()
344
+ export type CycleSchedule = z.infer<typeof CycleScheduleSchema>
345
+
346
+ export const PlanCycleStatusSchema = z.enum(['active', 'paused', 'completed', 'cancelled'])
347
+ export type PlanCycleStatus = z.infer<typeof PlanCycleStatusSchema>
348
+
349
+ export const ExecutionModeSchema = z.enum(['linear', 'graph-lite', 'graph-full']).default('linear')
350
+ export type ExecutionMode = z.infer<typeof ExecutionModeSchema>
351
+
352
+ export const WriteIntentActionSchema = z.enum(['create', 'append', 'update'])
353
+ export type WriteIntentAction = z.infer<typeof WriteIntentActionSchema>
354
+
355
+ export const WriteIntentSchema = z
356
+ .object({
357
+ targetPath: z.string().trim().min(1).max(500),
358
+ action: WriteIntentActionSchema,
359
+ payload: z.union([z.record(z.string(), z.unknown()), z.array(z.unknown()), z.string()]),
360
+ })
361
+ .strict()
362
+ export type WriteIntent = z.infer<typeof WriteIntentSchema>
363
+
364
+ export const WriteValidationErrorSchema = z
365
+ .object({
366
+ targetPath: z.string(),
367
+ action: WriteIntentActionSchema,
368
+ status: z.enum(['pass', 'fail']),
369
+ issues: z.array(
370
+ z.object({
371
+ code: z.string(),
372
+ message: z.string(),
373
+ path: z.string().optional(),
374
+ suggestion: z.string().optional(),
375
+ }),
376
+ ),
377
+ })
378
+ .strict()
379
+ export type WriteValidationError = z.infer<typeof WriteValidationErrorSchema>
380
+
381
+ export const NodeWorkspaceEntrySchema = z
382
+ .object({
383
+ targetPath: z.string(),
384
+ action: WriteIntentActionSchema,
385
+ payload: z.unknown(),
386
+ validatedAt: apiDateTimeSchema,
387
+ })
388
+ .strict()
389
+ export type NodeWorkspaceEntry = z.infer<typeof NodeWorkspaceEntrySchema>
390
+
391
+ export const NodeResultQualitySchema = z.enum(['full', 'partial']).default('full')
392
+ export type NodeResultQuality = z.infer<typeof NodeResultQualitySchema>
393
+
394
+ const planJsonValueSchema: z.ZodType<unknown> = z.lazy(() =>
395
+ z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(planJsonValueSchema), planStructuredObjectSchema]),
396
+ )
397
+ const planStructuredObjectSchema: z.ZodType<Record<string, unknown>> = z.lazy(() =>
398
+ z.object({}).catchall(planJsonValueSchema),
399
+ )
400
+ const planStructuredPayloadSchema: z.ZodType<Record<string, unknown> | unknown[]> = z.union([
401
+ planStructuredObjectSchema,
402
+ z.array(planJsonValueSchema),
403
+ ])
404
+ export type PlanStructuredPayload = z.infer<typeof planStructuredPayloadSchema>
405
+
406
+ export const PlanArtifactSubmissionSchema = z
407
+ .object({
408
+ name: z.string().trim().min(1).max(200),
409
+ kind: PlanArtifactKindSchema,
410
+ pointer: z.string().trim().min(1).max(500),
411
+ schemaRef: z.string().trim().min(1).max(200).optional(),
412
+ description: z.string().trim().min(1).max(1000).optional(),
413
+ payload: planStructuredPayloadSchema.optional(),
414
+ })
415
+ .strict()
416
+ export type PlanArtifactSubmission = z.infer<typeof PlanArtifactSubmissionSchema>
417
+
418
+ export const PlanNodeResultSubmissionSchema = z
419
+ .object({
420
+ structuredOutput: planStructuredObjectSchema.optional(),
421
+ artifacts: z.array(PlanArtifactSubmissionSchema).default([]),
422
+ notes: z.string().trim().min(1).max(2000).optional(),
423
+ quality: NodeResultQualitySchema.optional(),
424
+ })
425
+ .strict()
426
+ export type PlanNodeResultSubmission = z.infer<typeof PlanNodeResultSubmissionSchema>
427
+ export type PlanNodeResult = PlanNodeResultSubmission
428
+
429
+ export interface OwnershipDispatchContext {
430
+ organizationId: string
431
+ workstreamId: string
432
+ planId: string
433
+ nodeId: string
434
+ leadAgentId: string
435
+ userId?: string
436
+ userName?: string
437
+ }
438
+
439
+ export const MonitoringWindowConfigSchema = z.object({
440
+ durationMs: z.number().int().positive(),
441
+ initialIntervalMs: z.number().int().positive(),
442
+ decayFactor: z.number().min(0.1).max(1.0).default(0.8),
443
+ maxIntervalMs: z.number().int().positive(),
444
+ earlyTermination: z
445
+ .object({ condition: z.string().trim().min(1).max(500), minSamples: z.number().int().positive().default(3) })
446
+ .optional(),
447
+ })
448
+ export type MonitoringWindowConfig = z.infer<typeof MonitoringWindowConfigSchema>
449
+
450
+ export const PlanDependencyTriggerModeSchema = z.enum(['block', 'notify', 'best-effort'])
451
+ export type PlanDependencyTriggerMode = z.infer<typeof PlanDependencyTriggerModeSchema>
452
+
453
+ export const PlanDependencySchema = z.object({
454
+ sourcePlanTitle: z.string().trim().min(1).max(200),
455
+ sourceNodeId: z.string().trim().min(1).max(200),
456
+ artifactName: z.string().trim().min(1).max(200),
457
+ triggerMode: PlanDependencyTriggerModeSchema.default('block'),
458
+ maxStalenessMs: z.number().int().positive().optional(),
459
+ })
460
+ export type PlanDependency = z.infer<typeof PlanDependencySchema>
461
+
462
+ export const DeliberationBranchSchema = z.object({
463
+ branchId: z.string().trim().min(1).max(200),
464
+ label: z.string().trim().min(1).max(300),
465
+ entryNodeId: z.string().trim().min(1).max(200),
466
+ })
467
+ export type DeliberationBranch = z.infer<typeof DeliberationBranchSchema>
468
+
469
+ export const DeliberationForkConfigSchema = z.object({
470
+ branches: z.array(DeliberationBranchSchema).min(2).max(8),
471
+ resolutionGateNodeId: z.string().trim().min(1).max(200),
472
+ })
473
+ export type DeliberationForkConfig = z.infer<typeof DeliberationForkConfigSchema>
474
+
475
+ export const ProvenanceNodeSchema = z.object({
476
+ nodeId: z.string(),
477
+ label: z.string(),
478
+ artifacts: z.array(z.object({ name: z.string(), kind: PlanArtifactKindSchema, id: z.string() })),
479
+ })
480
+ export type ProvenanceNode = z.infer<typeof ProvenanceNodeSchema>
481
+
482
+ export const ProvenanceChainSchema = z.object({
483
+ root: z.object({ nodeId: z.string() }),
484
+ chain: z.array(ProvenanceNodeSchema),
485
+ depth: z.number().int().nonnegative(),
486
+ })
487
+ export type ProvenanceChain = z.infer<typeof ProvenanceChainSchema>
488
+
489
+ export const ImpactAnalysisSchema = z.object({
490
+ sourceNodeId: z.string(),
491
+ affectedNodes: z.array(z.object({ nodeId: z.string(), label: z.string(), status: PlanNodeRunStatusSchema })),
492
+ affectedArtifacts: z.array(z.object({ name: z.string(), nodeId: z.string() })),
493
+ })
494
+ export type ImpactAnalysis = z.infer<typeof ImpactAnalysisSchema>
495
+
496
+ export const ConvergenceStateSchema = z.enum(['progressing', 'stalled', 'diverging', 'converging'])
497
+ export type ConvergenceState = z.infer<typeof ConvergenceStateSchema>
196
498
 
197
499
  export const PlanNodeSpecSchema = z
198
500
  .object({
@@ -216,6 +518,11 @@ export const PlanNodeSpecSchema = z
216
518
  attachmentPolicy: 'referenced-only',
217
519
  webPolicy: 'allowed',
218
520
  }),
521
+ schedule: PlanScheduleSpecSchema.optional(),
522
+ deadline: DeadlineSpecSchema.optional(),
523
+ monitoringConfig: MonitoringWindowConfigSchema.optional(),
524
+ delayAfterPredecessorMs: z.number().int().positive().optional(),
525
+ deliberationConfig: DeliberationForkConfigSchema.optional(),
219
526
  })
220
527
  .strict()
221
528
  export type PlanNodeSpec = z.infer<typeof PlanNodeSpecSchema>
@@ -239,10 +546,16 @@ export const PlanDraftSchema = z
239
546
  nodes: z.array(PlanNodeSpecSchema).min(1).max(32),
240
547
  edges: z.array(PlanEdgeSpecSchema).default([]),
241
548
  entryNodeIds: z.array(z.string().trim().min(1).max(200)).min(1).optional(),
549
+ executionMode: ExecutionModeSchema.optional(),
550
+ schedule: PlanScheduleSpecSchema.optional(),
551
+ dependencies: z.array(PlanDependencySchema).optional(),
242
552
  })
243
553
  .strict()
244
554
  export type PlanDraft = z.infer<typeof PlanDraftSchema>
245
555
 
556
+ export const ContextEnrichmentEntrySchema = z.object({ type: z.string(), content: z.string() })
557
+ export type ContextEnrichmentEntry = z.infer<typeof ContextEnrichmentEntrySchema>
558
+
246
559
  export const PlanSpecSchema = z.object({
247
560
  id: recordIdSchema,
248
561
  organizationId: recordIdSchema,
@@ -255,10 +568,14 @@ export const PlanSpecSchema = z.object({
255
568
  schemaRegistry: PlanSchemaRegistrySchema,
256
569
  edges: z.array(PlanEdgeSpecSchema),
257
570
  entryNodeIds: z.array(z.string()),
571
+ executionMode: ExecutionModeSchema,
572
+ schedule: PlanScheduleSpecSchema.optional(),
573
+ dependencies: z.array(PlanDependencySchema).optional(),
574
+ contextEnrichments: z.array(ContextEnrichmentEntrySchema).optional(),
258
575
  replacedSpecId: recordIdSchema.optional(),
259
- createdAt: unixTimestampSchema,
260
- updatedAt: unixTimestampSchema.optional(),
261
- compiledAt: unixTimestampSchema.optional(),
576
+ createdAt: dbDateTimeSchema,
577
+ updatedAt: dbDateTimeSchema.optional(),
578
+ compiledAt: dbDateTimeSchema.optional(),
262
579
  })
263
580
  export type PlanSpecRecord = z.infer<typeof PlanSpecSchema>
264
581
 
@@ -282,10 +599,15 @@ export const PlanNodeSpecRecordSchema = z.object({
282
599
  timeoutMs: z.number().int().positive().optional(),
283
600
  toolPolicy: PlanToolPolicySchema,
284
601
  contextPolicy: PlanContextPolicySchema,
602
+ schedule: PlanScheduleSpecSchema.optional(),
603
+ deadline: DeadlineSpecSchema.optional(),
604
+ monitoringConfig: MonitoringWindowConfigSchema.optional(),
605
+ delayAfterPredecessorMs: z.number().int().positive().optional(),
606
+ deliberationConfig: DeliberationForkConfigSchema.optional(),
285
607
  upstreamNodeIds: z.array(z.string()).default([]),
286
608
  downstreamNodeIds: z.array(z.string()).default([]),
287
- createdAt: unixTimestampSchema,
288
- updatedAt: unixTimestampSchema.optional(),
609
+ createdAt: dbDateTimeSchema,
610
+ updatedAt: dbDateTimeSchema.optional(),
289
611
  })
290
612
  export type PlanNodeSpecRecord = z.infer<typeof PlanNodeSpecRecordSchema>
291
613
 
@@ -302,10 +624,12 @@ export const PlanRunSchema = z.object({
302
624
  failureCount: z.number().int().nonnegative(),
303
625
  replacedRunId: recordIdSchema.optional(),
304
626
  lastCheckpointId: recordIdSchema.optional(),
305
- createdAt: unixTimestampSchema,
306
- updatedAt: unixTimestampSchema.optional(),
307
- startedAt: unixTimestampSchema.optional(),
308
- completedAt: unixTimestampSchema.optional(),
627
+ scheduledAt: dbDateTimeSchema.optional(),
628
+ scheduleId: recordIdSchema.optional(),
629
+ createdAt: dbDateTimeSchema,
630
+ updatedAt: dbDateTimeSchema.optional(),
631
+ startedAt: dbDateTimeSchema.optional(),
632
+ completedAt: dbDateTimeSchema.optional(),
309
633
  })
310
634
  export type PlanRunRecord = z.infer<typeof PlanRunSchema>
311
635
 
@@ -323,11 +647,12 @@ export const PlanNodeRunSchema = z.object({
323
647
  latestAttemptId: recordIdSchema.optional(),
324
648
  blockedReason: z.string().optional(),
325
649
  failureClass: PlanFailureClassSchema.optional(),
326
- readyAt: unixTimestampSchema.optional(),
327
- startedAt: unixTimestampSchema.optional(),
328
- completedAt: unixTimestampSchema.optional(),
329
- createdAt: unixTimestampSchema,
330
- updatedAt: unixTimestampSchema.optional(),
650
+ scheduledAt: dbDateTimeSchema.optional(),
651
+ readyAt: dbDateTimeSchema.optional(),
652
+ startedAt: dbDateTimeSchema.optional(),
653
+ completedAt: dbDateTimeSchema.optional(),
654
+ createdAt: dbDateTimeSchema,
655
+ updatedAt: dbDateTimeSchema.optional(),
331
656
  })
332
657
  export type PlanNodeRunRecord = z.infer<typeof PlanNodeRunSchema>
333
658
 
@@ -338,11 +663,11 @@ export const PlanNodeAttemptSchema = z.object({
338
663
  nodeId: z.string(),
339
664
  emittedBy: z.string(),
340
665
  status: PlanAttemptStatusSchema,
341
- structuredOutput: z.record(z.string(), z.unknown()).optional(),
666
+ structuredOutput: planStructuredObjectSchema.optional(),
342
667
  notes: z.string().optional(),
343
668
  validationIssueIds: z.array(recordIdSchema).default([]),
344
669
  failureClass: PlanFailureClassSchema.optional(),
345
- createdAt: unixTimestampSchema,
670
+ createdAt: dbDateTimeSchema,
346
671
  })
347
672
  export type PlanNodeAttemptRecord = z.infer<typeof PlanNodeAttemptSchema>
348
673
 
@@ -357,7 +682,7 @@ export const PlanArtifactSchema = z.object({
357
682
  schemaRef: z.string().optional(),
358
683
  description: z.string().optional(),
359
684
  payload: planStructuredPayloadSchema.optional(),
360
- createdAt: unixTimestampSchema,
685
+ createdAt: dbDateTimeSchema,
361
686
  })
362
687
  export type PlanArtifactRecord = z.infer<typeof PlanArtifactSchema>
363
688
 
@@ -371,7 +696,7 @@ export const PlanValidationIssueSchema = z.object({
371
696
  code: z.string(),
372
697
  message: z.string(),
373
698
  detail: z.record(z.string(), z.unknown()).optional(),
374
- createdAt: unixTimestampSchema,
699
+ createdAt: dbDateTimeSchema,
375
700
  })
376
701
  export type PlanValidationIssueRecord = z.infer<typeof PlanValidationIssueSchema>
377
702
 
@@ -385,7 +710,7 @@ export const PlanCheckpointSchema = z.object({
385
710
  artifactIds: z.array(recordIdSchema).default([]),
386
711
  lastCompletedNodeIds: z.array(z.string()).default([]),
387
712
  snapshot: z.record(z.string(), z.unknown()),
388
- createdAt: unixTimestampSchema,
713
+ createdAt: dbDateTimeSchema,
389
714
  })
390
715
  export type PlanCheckpointRecord = z.infer<typeof PlanCheckpointSchema>
391
716
 
@@ -402,9 +727,9 @@ export const PlanApprovalSchema = z.object({
402
727
  approvalMessageId: z.string().optional(),
403
728
  comments: z.string().optional(),
404
729
  requiredEdits: z.array(z.string()).default([]),
405
- createdAt: unixTimestampSchema,
406
- updatedAt: unixTimestampSchema.optional(),
407
- respondedAt: unixTimestampSchema.optional(),
730
+ createdAt: dbDateTimeSchema,
731
+ updatedAt: dbDateTimeSchema.optional(),
732
+ respondedAt: dbDateTimeSchema.optional(),
408
733
  })
409
734
  export type PlanApprovalRecord = z.infer<typeof PlanApprovalSchema>
410
735
 
@@ -421,7 +746,7 @@ export const PlanEventSchema = z.object({
421
746
  message: z.string(),
422
747
  detail: z.record(z.string(), z.unknown()).optional(),
423
748
  emittedBy: z.string(),
424
- createdAt: unixTimestampSchema,
749
+ createdAt: dbDateTimeSchema,
425
750
  })
426
751
  export type PlanEventRecord = z.infer<typeof PlanEventSchema>
427
752
 
@@ -442,6 +767,11 @@ export const SerializablePlanNodeSchema = z.object({
442
767
  timeoutMs: z.number().int().positive().nullish(),
443
768
  toolPolicy: PlanToolPolicySchema,
444
769
  contextPolicy: PlanContextPolicySchema,
770
+ schedule: PlanScheduleSpecSchema.nullish(),
771
+ deadline: DeadlineSpecSchema.nullish(),
772
+ monitoringConfig: MonitoringWindowConfigSchema.nullish(),
773
+ delayAfterPredecessorMs: z.number().int().positive().nullish(),
774
+ deliberationConfig: DeliberationForkConfigSchema.nullish(),
445
775
  status: PlanNodeRunStatusSchema,
446
776
  attemptCount: z.number().int().nonnegative(),
447
777
  retryCount: z.number().int().nonnegative(),
@@ -539,6 +869,8 @@ export const SerializableExecutionPlanProgressSchema = z.object({
539
869
  blocked: z.number().int().nonnegative(),
540
870
  failed: z.number().int().nonnegative(),
541
871
  skipped: z.number().int().nonnegative(),
872
+ scheduled: z.number().int().nonnegative(),
873
+ monitoring: z.number().int().nonnegative(),
542
874
  completionRatio: z.number().min(0).max(1).nullish(),
543
875
  })
544
876
  export type SerializableExecutionPlanProgress = z.infer<typeof SerializableExecutionPlanProgressSchema>
@@ -553,9 +885,11 @@ export const SerializableExecutionPlanSchema = z.object({
553
885
  version: z.number().int().positive(),
554
886
  status: PlanRunStatusSchema,
555
887
  leadAgentId: z.string(),
888
+ executionMode: ExecutionModeSchema,
556
889
  schemaRegistry: PlanSchemaRegistrySchema,
557
890
  entryNodeIds: z.array(z.string()),
558
891
  edges: z.array(PlanEdgeSpecSchema),
892
+ schedule: PlanScheduleSpecSchema.nullish(),
559
893
  activeNodeIds: z.array(z.string()),
560
894
  readyNodeIds: z.array(z.string()),
561
895
  waitingNodeId: z.string().nullish(),
@@ -573,3 +907,97 @@ export const SerializableExecutionPlanSchema = z.object({
573
907
  recentEvents: z.array(SerializablePlanEventSchema),
574
908
  })
575
909
  export type SerializableExecutionPlan = z.infer<typeof SerializableExecutionPlanSchema>
910
+
911
+ export const PlanTemplateRecordSchema = z.object({
912
+ id: recordIdSchema,
913
+ organizationId: recordIdSchema,
914
+ name: z.string(),
915
+ description: z.string().optional(),
916
+ draft: PlanDraftSchema,
917
+ tags: z.array(z.string()).default([]),
918
+ source: PlanTemplateSourceSchema,
919
+ sourceRef: z.string().optional(),
920
+ createdAt: dbDateTimeSchema,
921
+ updatedAt: dbDateTimeSchema.optional(),
922
+ })
923
+ export type PlanTemplateRecord = z.infer<typeof PlanTemplateRecordSchema>
924
+
925
+ export const PlanCycleRecordSchema = z.object({
926
+ id: recordIdSchema,
927
+ organizationId: recordIdSchema,
928
+ workstreamId: recordIdSchema,
929
+ templateId: recordIdSchema,
930
+ name: z.string(),
931
+ schedule: CycleScheduleSchema,
932
+ carryForwardPolicy: CarryForwardPolicySchema.default('incomplete-only'),
933
+ status: PlanCycleStatusSchema,
934
+ currentIteration: z.number().int().nonnegative().default(0),
935
+ currentRunId: recordIdSchema.optional(),
936
+ scheduleId: recordIdSchema.optional(),
937
+ createdAt: dbDateTimeSchema,
938
+ updatedAt: dbDateTimeSchema.optional(),
939
+ })
940
+ export type PlanCycleRecord = z.infer<typeof PlanCycleRecordSchema>
941
+
942
+ export const ContextEnrichmentSchema = z.object({
943
+ domain: z.string().trim().min(1).max(200),
944
+ data: z.record(z.string(), z.unknown()),
945
+ confidence: z.number().min(0).max(1),
946
+ })
947
+ export type ContextEnrichment = z.infer<typeof ContextEnrichmentSchema>
948
+
949
+ export const EvidenceRecordSchema = z.object({
950
+ sourceType: z.enum(['artifact', 'metric', 'pattern', 'external']),
951
+ sourceId: z.string().trim().min(1).max(200),
952
+ summary: z.string().trim().min(1).max(1000),
953
+ confidence: z.number().min(0).max(1),
954
+ })
955
+ export type EvidenceRecord = z.infer<typeof EvidenceRecordSchema>
956
+
957
+ export const RecommendationTypeSchema = z.enum(['optimization', 'warning', 'pattern'])
958
+ export type RecommendationType = z.infer<typeof RecommendationTypeSchema>
959
+
960
+ export const RecommendationTargetSchema = z.enum(['node', 'edge', 'plan', 'playbook'])
961
+ export type RecommendationTarget = z.infer<typeof RecommendationTargetSchema>
962
+
963
+ export const RecommendationSchema = z.object({
964
+ type: RecommendationTypeSchema,
965
+ target: RecommendationTargetSchema,
966
+ targetId: z.string().optional(),
967
+ description: z.string().trim().min(1).max(2000),
968
+ evidence: z.array(EvidenceRecordSchema),
969
+ confidence: z.number().min(0).max(1),
970
+ })
971
+ export type Recommendation = z.infer<typeof RecommendationSchema>
972
+
973
+ export const NodeQualityMetricsSchema = z.object({
974
+ executionTimeMs: z.number().int().nonnegative(),
975
+ attemptCount: z.number().int().nonnegative(),
976
+ artifactCount: z.number().int().nonnegative(),
977
+ validationIssueCount: z.number().int().nonnegative(),
978
+ ownerRef: z.string(),
979
+ ownerType: PlanNodeExecutorTypeSchema,
980
+ nodeType: PlanNodeTypeSchema,
981
+ })
982
+ export type NodeQualityMetrics = z.infer<typeof NodeQualityMetricsSchema>
983
+
984
+ export const InstitutionalMemoryTypeSchema = z.enum([
985
+ 'execution-pattern',
986
+ 'failure-pattern',
987
+ 'agent-affinity',
988
+ 'timing-pattern',
989
+ 'quality-pattern',
990
+ ])
991
+ export type InstitutionalMemoryType = z.infer<typeof InstitutionalMemoryTypeSchema>
992
+
993
+ export const InstitutionalMemorySchema = z.object({
994
+ id: recordIdSchema,
995
+ organizationId: recordIdSchema,
996
+ type: InstitutionalMemoryTypeSchema,
997
+ pattern: z.record(z.string(), z.unknown()),
998
+ confidence: z.number().min(0).max(1),
999
+ sampleCount: z.number().int().positive(),
1000
+ createdAt: dbDateTimeSchema,
1001
+ updatedAt: dbDateTimeSchema.optional(),
1002
+ })
1003
+ export type InstitutionalMemory = z.infer<typeof InstitutionalMemorySchema>
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod'
2
+
3
+ import { PlanArtifactKindSchema, PlanDraftSchema } from './execution-plan'
4
+
5
+ export const GraphDesignRequestSchema = z.object({
6
+ objective: z.string().trim().min(1).max(4000),
7
+ constraints: z.array(z.string().trim().min(1).max(1000)).default([]),
8
+ availableAgents: z.array(z.object({ agentId: z.string(), capabilities: z.array(z.string()) })),
9
+ availablePlugins: z.array(z.object({ pluginRef: z.string(), operations: z.array(z.string()) })),
10
+ contextArtifacts: z
11
+ .array(z.object({ name: z.string(), kind: PlanArtifactKindSchema, summary: z.string().optional() }))
12
+ .default([]),
13
+ })
14
+ export type GraphDesignRequest = z.infer<typeof GraphDesignRequestSchema>
15
+
16
+ export const GraphDesignResponseSchema = z.object({
17
+ draft: PlanDraftSchema,
18
+ reasoning: z.string().trim().min(1).max(4000),
19
+ confidence: z.number().min(0).max(1),
20
+ })
21
+ export type GraphDesignResponse = z.infer<typeof GraphDesignResponseSchema>
@@ -0,0 +1,33 @@
1
+ import { z } from 'zod'
2
+
3
+ import { recordIdSchema } from './common'
4
+
5
+ const unixTimestampSchema = z.coerce.date()
6
+
7
+ export const PlaybookVersionStatusSchema = z.enum(['active', 'testing', 'rolled-back', 'archived'])
8
+ export type PlaybookVersionStatus = z.infer<typeof PlaybookVersionStatusSchema>
9
+
10
+ export const PlaybookVersionSchema = z.object({
11
+ id: recordIdSchema,
12
+ playbookId: recordIdSchema,
13
+ version: z.number().int().positive(),
14
+ parentVersionId: recordIdSchema.optional(),
15
+ appliedRecommendations: z.array(z.string()).default([]),
16
+ qualityScore: z.number().min(0).max(1).optional(),
17
+ status: PlaybookVersionStatusSchema,
18
+ createdAt: unixTimestampSchema,
19
+ })
20
+ export type PlaybookVersion = z.infer<typeof PlaybookVersionSchema>
21
+
22
+ export const PlaybookSchema = z.object({
23
+ id: recordIdSchema,
24
+ organizationId: recordIdSchema,
25
+ name: z.string().trim().min(1).max(200),
26
+ objective: z.string().trim().min(1).max(2000),
27
+ currentVersionId: recordIdSchema,
28
+ previousVersionId: recordIdSchema.optional(),
29
+ cycleCount: z.number().int().nonnegative().default(0),
30
+ createdAt: unixTimestampSchema,
31
+ updatedAt: unixTimestampSchema.optional(),
32
+ })
33
+ export type Playbook = z.infer<typeof PlaybookSchema>
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod'
2
+
3
+ export const SignalDirectionSchema = z.enum(['produces', 'consumes'])
4
+ export type SignalDirection = z.infer<typeof SignalDirectionSchema>
5
+
6
+ export const SignalDeclarationSchema = z.object({
7
+ signalName: z.string().trim().min(1).max(200),
8
+ direction: SignalDirectionSchema,
9
+ description: z.string().trim().min(1).max(500).optional(),
10
+ })
11
+ export type SignalDeclaration = z.infer<typeof SignalDeclarationSchema>
@@ -3,8 +3,8 @@ import { z } from 'zod'
3
3
  import { baseChatMessageSchema } from './chat-api'
4
4
  import type { AnyChatMessage } from './chat-message'
5
5
  import {
6
- PlanArtifactKindSchema,
7
6
  PlanDraftSchema,
7
+ PlanNodeResultSubmissionSchema,
8
8
  PlanRunStatusSchema,
9
9
  SerializableExecutionPlanSchema,
10
10
  } from './execution-plan'
@@ -15,6 +15,8 @@ export const CONSULT_TEAM_TOOL_NAME = 'consultTeam' as const
15
15
  export const CREATE_EXECUTION_PLAN_TOOL_NAME = 'createExecutionPlan' as const
16
16
  export const REPLACE_EXECUTION_PLAN_TOOL_NAME = 'replaceExecutionPlan' as const
17
17
  export const SUBMIT_EXECUTION_NODE_RESULT_TOOL_NAME = 'submitExecutionNodeResult' as const
18
+ export const LIST_EXECUTION_PLANS_TOOL_NAME = 'listExecutionPlans' as const
19
+ export const GET_EXECUTION_PLAN_DETAILS_TOOL_NAME = 'getExecutionPlanDetails' as const
18
20
  export const GET_ACTIVE_EXECUTION_PLAN_TOOL_NAME = 'getActiveExecutionPlan' as const
19
21
  export const RESUME_EXECUTION_PLAN_RUN_TOOL_NAME = 'resumeExecutionPlanRun' as const
20
22
 
@@ -48,29 +50,6 @@ export const ConsultTeamResponseSchema = z
48
50
 
49
51
  export const ConsultTeamArgsSchema = z.object({ task: z.string().trim().min(1).max(6000) }).strict()
50
52
 
51
- const planStructuredPayloadSchema = z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())])
52
-
53
- export const PlanArtifactSubmissionSchema = z
54
- .object({
55
- name: z.string().trim().min(1).max(200),
56
- kind: PlanArtifactKindSchema,
57
- pointer: z.string().trim().min(1).max(500),
58
- schemaRef: z.string().trim().min(1).max(200).optional(),
59
- description: z.string().trim().min(1).max(1000).optional(),
60
- payload: planStructuredPayloadSchema.optional(),
61
- })
62
- .strict()
63
- export type PlanArtifactSubmission = z.infer<typeof PlanArtifactSubmissionSchema>
64
-
65
- export const PlanNodeResultSubmissionSchema = z
66
- .object({
67
- structuredOutput: z.record(z.string(), z.unknown()).optional(),
68
- artifacts: z.array(PlanArtifactSubmissionSchema).default([]),
69
- notes: z.string().trim().min(1).max(2000).optional(),
70
- })
71
- .strict()
72
- export type PlanNodeResultSubmission = z.infer<typeof PlanNodeResultSubmissionSchema>
73
-
74
53
  const ExecutionPlanToolActionSchema = z.enum([
75
54
  'created',
76
55
  'replaced',
@@ -91,18 +70,41 @@ export const SubmitExecutionNodeResultArgsSchema = z
91
70
  .object({ runId: z.string().trim().min(1), nodeId: z.string().trim().min(1), result: PlanNodeResultSubmissionSchema })
92
71
  .strict()
93
72
 
73
+ export const ListExecutionPlansArgsSchema = z.object({}).strict()
74
+
94
75
  export const GetActiveExecutionPlanArgsSchema = z
95
76
  .object({
96
- includeEvents: z.boolean().optional().default(true),
97
- includeArtifacts: z.boolean().optional().default(true),
98
- includeApprovals: z.boolean().optional().default(true),
99
- includeCheckpoints: z.boolean().optional().default(false),
100
- includeValidationIssues: z.boolean().optional().default(true),
77
+ runId: z.string().trim().min(1).optional(),
78
+ includeEvents: z.boolean().default(true),
79
+ includeArtifacts: z.boolean().default(true),
80
+ includeApprovals: z.boolean().default(true),
81
+ includeCheckpoints: z.boolean().default(false),
82
+ includeValidationIssues: z.boolean().default(true),
101
83
  })
102
84
  .strict()
103
85
 
104
86
  export const ResumeExecutionPlanRunArgsSchema = z.object({ runId: z.string().trim().min(1) }).strict()
105
87
 
88
+ export const PlanSummarySchema = z
89
+ .object({ runId: z.string(), title: z.string(), status: PlanRunStatusSchema })
90
+ .strict()
91
+
92
+ export const ListExecutionPlansSummarySchema = z
93
+ .object({
94
+ runId: z.string(),
95
+ title: z.string(),
96
+ status: PlanRunStatusSchema,
97
+ objective: z.string(),
98
+ nodeCount: z.number().int().nonnegative(),
99
+ completedCount: z.number().int().nonnegative(),
100
+ failedCount: z.number().int().nonnegative(),
101
+ })
102
+ .strict()
103
+
104
+ export const ListExecutionPlansToolResultDataSchema = z
105
+ .object({ plans: z.array(ListExecutionPlansSummarySchema), totalCount: z.number().int().nonnegative() })
106
+ .strict()
107
+
106
108
  export const ExecutionPlanToolResultDataSchema = z
107
109
  .object({
108
110
  action: ExecutionPlanToolActionSchema,
@@ -111,6 +113,8 @@ export const ExecutionPlanToolResultDataSchema = z
111
113
  plan: SerializableExecutionPlanSchema.nullish(),
112
114
  hasPlan: z.boolean(),
113
115
  status: PlanRunStatusSchema.nullish(),
116
+ planCount: z.number().int().nonnegative().optional(),
117
+ planSummaries: z.array(PlanSummarySchema).optional(),
114
118
  })
115
119
  .strict()
116
120
 
@@ -128,6 +132,9 @@ export type ConsultTeamResultData = { responses: ConsultTeamResponseData[] }
128
132
  export type CreateExecutionPlanArgs = z.infer<typeof CreateExecutionPlanArgsSchema>
129
133
  export type ReplaceExecutionPlanArgs = z.infer<typeof ReplaceExecutionPlanArgsSchema>
130
134
  export type SubmitExecutionNodeResultArgs = z.infer<typeof SubmitExecutionNodeResultArgsSchema>
135
+ export type ListExecutionPlansArgs = z.infer<typeof ListExecutionPlansArgsSchema>
136
+ export type ListExecutionPlansSummary = z.infer<typeof ListExecutionPlansSummarySchema>
137
+ export type ListExecutionPlansToolResultData = z.infer<typeof ListExecutionPlansToolResultDataSchema>
131
138
  export type GetActiveExecutionPlanArgs = z.infer<typeof GetActiveExecutionPlanArgsSchema>
132
139
  export type ResumeExecutionPlanRunArgs = z.infer<typeof ResumeExecutionPlanRunArgsSchema>
133
140
  export type ExecutionPlanToolResultData = z.infer<typeof ExecutionPlanToolResultDataSchema>
@@ -138,6 +145,7 @@ export type CoreChatTools = {
138
145
  createExecutionPlan: { input: CreateExecutionPlanArgs; output: ExecutionPlanToolResultData }
139
146
  replaceExecutionPlan: { input: ReplaceExecutionPlanArgs; output: ExecutionPlanToolResultData }
140
147
  submitExecutionNodeResult: { input: SubmitExecutionNodeResultArgs; output: ExecutionPlanToolResultData }
141
- getActiveExecutionPlan: { input: GetActiveExecutionPlanArgs; output: ExecutionPlanToolResultData }
148
+ listExecutionPlans: { input: ListExecutionPlansArgs; output: ListExecutionPlansToolResultData }
149
+ getExecutionPlanDetails: { input: GetActiveExecutionPlanArgs; output: ExecutionPlanToolResultData }
142
150
  resumeExecutionPlanRun: { input: ResumeExecutionPlanRunArgs; output: ExecutionPlanToolResultData }
143
151
  }
@@ -15,7 +15,7 @@ export const sdkWorkstreamSchema = z.object({
15
15
  coreType: z.string().nullable().optional(),
16
16
  title: z.string(),
17
17
  status: sdkWorkstreamStatusSchema,
18
- nameGenerated: z.boolean(),
18
+ nameGenerated: z.boolean(), // Ideally `isNameGenerated`, but maps directly to SurrealDB column `nameGenerated`
19
19
  isRunning: z.boolean(),
20
20
  isCompacting: z.boolean(),
21
21
  memoryBlock: z.string().optional(),
@@ -28,17 +28,17 @@ export const sdkWorkstreamRecordSchema = z.object({
28
28
  organizationId: recordIdSchema,
29
29
  userId: recordIdSchema,
30
30
  agentId: z.string().nullish(),
31
- mode: sdkWorkstreamModeSchema.optional(),
32
- core: z.boolean().optional(),
31
+ mode: sdkWorkstreamModeSchema,
32
+ core: z.boolean(),
33
33
  coreType: z.string().nullish(),
34
34
  title: z.string().nullish(),
35
- status: sdkWorkstreamStatusSchema.nullish(),
35
+ status: sdkWorkstreamStatusSchema,
36
36
  memoryBlock: z.string().nullish(),
37
37
  memoryBlockSummary: z.string().nullish(),
38
38
  activeRunId: z.string().nullish(),
39
39
  compactionSummary: z.string().nullish(),
40
40
  lastCompactedMessageId: z.string().nullish(),
41
- nameGenerated: z.boolean().optional(),
41
+ nameGenerated: z.boolean(), // Ideally `isNameGenerated`, but maps directly to SurrealDB column `nameGenerated`
42
42
  isCompacting: z.boolean().optional(),
43
43
  state: z.unknown().optional(),
44
44
  createdAt: z.coerce.date(),
@@ -0,0 +1,18 @@
1
+ import type { ConfidenceScore } from '../schemas/confidence'
2
+
3
+ export function aggregateConfidence(
4
+ scores: ConfidenceScore[],
5
+ method?: 'weighted-average' | 'min' | 'bayesian',
6
+ ): number {
7
+ if (scores.length === 0) return 0
8
+ const resolvedMethod = method ?? 'weighted-average'
9
+ const overalls = scores.map((s) => s.overall)
10
+ switch (resolvedMethod) {
11
+ case 'weighted-average':
12
+ return overalls.reduce((a, b) => a + b, 0) / overalls.length
13
+ case 'min':
14
+ return Math.min(...overalls)
15
+ case 'bayesian':
16
+ return overalls.reduce((a, b) => a * b, 1)
17
+ }
18
+ }
@@ -0,0 +1,34 @@
1
+ export function toIsoDateTimeString(value: unknown): string {
2
+ if (value instanceof Date) {
3
+ return value.toISOString()
4
+ }
5
+
6
+ // Assume API boundaries already use ISO strings.
7
+ if (typeof value === 'string') {
8
+ return value
9
+ }
10
+
11
+ // Support unix timestamps (seconds or milliseconds).
12
+ if (typeof value === 'number') {
13
+ const millis = value < 1_000_000_000_000 ? value * 1000 : value
14
+ return new Date(millis).toISOString()
15
+ }
16
+
17
+ // Support objects that expose toISOString (e.g., SurrealDB temporal types).
18
+ if (value && typeof value === 'object') {
19
+ const maybeToIso = (value as { toISOString?: unknown }).toISOString
20
+ if (typeof maybeToIso === 'function') {
21
+ return (value as { toISOString: () => string }).toISOString()
22
+ }
23
+ }
24
+
25
+ return String(value)
26
+ }
27
+
28
+ export function toOptionalIsoDateTimeString(value: unknown): string | undefined {
29
+ if (value === null || value === undefined || value === '') {
30
+ return undefined
31
+ }
32
+
33
+ return toIsoDateTimeString(value)
34
+ }
@@ -0,0 +1,10 @@
1
+ export function getErrorMessage(error: unknown): string {
2
+ if (error instanceof Error) return error.message
3
+ if (typeof error === 'string') return error
4
+
5
+ try {
6
+ return JSON.stringify(error)
7
+ } catch {
8
+ return String(error)
9
+ }
10
+ }