@lota-sdk/core 0.1.15 → 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/infrastructure/schema/00_identity.surql +0 -2
- package/infrastructure/schema/01_memory.surql +1 -1
- package/infrastructure/schema/02_execution_plan.surql +62 -1
- package/infrastructure/schema/03_learned_skill.surql +1 -1
- package/infrastructure/schema/06_playbook.surql +25 -0
- package/infrastructure/schema/07_institutional_memory.surql +13 -0
- package/infrastructure/schema/08_quality_metrics.surql +17 -0
- package/package.json +8 -7
- package/src/ai/definitions.ts +80 -2
- package/src/ai/index.ts +0 -2
- package/src/bifrost/bifrost.ts +2 -7
- package/src/config/agent-defaults.ts +31 -21
- package/src/config/agent-types.ts +11 -0
- package/src/config/constants.ts +2 -14
- package/src/config/debug-logger.ts +5 -1
- package/src/config/index.ts +3 -0
- package/src/config/model-constants.ts +16 -34
- package/src/config/search.ts +1 -15
- package/src/create-runtime.ts +244 -178
- package/src/db/cursor-pagination.ts +3 -6
- package/src/db/index.ts +2 -0
- package/src/db/memory-store.rows.ts +7 -7
- package/src/db/memory-store.ts +14 -18
- package/src/db/memory.ts +13 -13
- package/src/db/service.ts +153 -79
- package/src/db/startup.ts +6 -10
- package/src/db/surreal-mutation.ts +43 -0
- package/src/db/tables.ts +7 -0
- package/src/db/workstream-message-row.ts +15 -0
- package/src/embeddings/provider.ts +1 -1
- package/src/queues/context-compaction.queue.ts +15 -46
- package/src/queues/delayed-node-promotion.queue.ts +41 -0
- package/src/queues/index.ts +3 -0
- package/src/queues/memory-consolidation.queue.ts +16 -51
- package/src/queues/plan-scheduler.queue.ts +97 -0
- package/src/queues/post-chat-memory.queue.ts +15 -56
- package/src/queues/queue-factory.ts +100 -0
- package/src/queues/recent-activity-title-refinement.queue.ts +15 -50
- package/src/queues/regular-chat-memory-digest.queue.ts +16 -52
- package/src/queues/skill-extraction.queue.ts +15 -47
- package/src/queues/workstream-title-generation.queue.ts +15 -47
- package/src/redis/connection.ts +6 -0
- package/src/redis/index.ts +1 -1
- package/src/redis/stream-context.ts +11 -0
- package/src/runtime/agent-runtime-policy.ts +106 -21
- package/src/runtime/approval-continuation.ts +12 -6
- package/src/runtime/context-compaction-runtime.ts +1 -1
- package/src/runtime/context-compaction.ts +22 -60
- package/src/runtime/execution-plan.ts +22 -18
- package/src/runtime/graph-designer.ts +15 -0
- package/src/runtime/helper-model.ts +9 -197
- package/src/runtime/index.ts +2 -0
- package/src/runtime/llm-content.ts +1 -1
- package/src/runtime/memory-block.ts +9 -11
- package/src/runtime/memory-pipeline.ts +6 -9
- package/src/runtime/plugin-resolution.ts +35 -0
- package/src/runtime/plugin-types.ts +72 -0
- package/src/runtime/retrieval-adapters.ts +1 -1
- package/src/runtime/runtime-config.ts +25 -12
- package/src/runtime/runtime-extensions.ts +2 -2
- package/src/runtime/runtime-worker-registry.ts +6 -0
- package/src/runtime/team-consultation-orchestrator.ts +45 -28
- package/src/runtime/team-consultation-prompts.ts +11 -2
- package/src/runtime/title-helpers.ts +2 -4
- package/src/runtime/workstream-chat-helpers.ts +1 -1
- package/src/services/adaptive-playbook.service.ts +152 -0
- package/src/services/agent-executor.service.ts +293 -0
- package/src/services/artifact-provenance.service.ts +172 -0
- package/src/services/attachment.service.ts +6 -11
- package/src/services/context-compaction.service.ts +72 -55
- package/src/services/context-enrichment.service.ts +33 -0
- package/src/services/coordination-registry.service.ts +117 -0
- package/src/services/document-chunk.service.ts +1 -1
- package/src/services/domain-agent-executor.service.ts +71 -0
- package/src/services/execution-plan.service.ts +269 -50
- package/src/services/feedback-loop.service.ts +96 -0
- package/src/services/global-orchestrator.service.ts +148 -0
- package/src/services/index.ts +26 -0
- package/src/services/institutional-memory.service.ts +145 -0
- package/src/services/learned-skill.service.ts +24 -5
- package/src/services/memory-assessment.service.ts +3 -2
- package/src/services/memory-utils.ts +3 -8
- package/src/services/memory.service.ts +42 -59
- package/src/services/monitoring-window.service.ts +86 -0
- package/src/services/mutating-approval.service.ts +1 -1
- package/src/services/node-workspace.service.ts +155 -0
- package/src/services/notification.service.ts +39 -0
- package/src/services/organization-member.service.ts +11 -4
- package/src/services/organization.service.ts +5 -5
- package/src/services/ownership-dispatcher.service.ts +403 -0
- package/src/services/plan-approval.service.ts +1 -1
- package/src/services/plan-builder.service.ts +1 -0
- package/src/services/plan-checkpoint.service.ts +30 -2
- package/src/services/plan-compiler.service.ts +5 -0
- package/src/services/plan-coordination.service.ts +152 -0
- package/src/services/plan-cycle.service.ts +284 -0
- package/src/services/plan-deadline.service.ts +287 -0
- package/src/services/plan-executor.service.ts +384 -40
- package/src/services/plan-run.service.ts +41 -7
- package/src/services/plan-scheduler.service.ts +240 -0
- package/src/services/plan-template.service.ts +117 -0
- package/src/services/plan-validator.service.ts +84 -2
- package/src/services/plan-workspace.service.ts +83 -0
- package/src/services/playbook-registry.service.ts +67 -0
- package/src/services/plugin-executor.service.ts +103 -0
- package/src/services/quality-metrics.service.ts +132 -0
- package/src/services/recent-activity.service.ts +27 -31
- package/src/services/skill-resolver.service.ts +19 -0
- package/src/services/system-executor.service.ts +105 -0
- package/src/services/workstream-message.service.ts +12 -34
- package/src/services/workstream-plan-registry.service.ts +22 -0
- package/src/services/workstream-title.service.ts +3 -1
- package/src/services/workstream-turn-preparation.service.ts +34 -66
- package/src/services/workstream.service.ts +33 -55
- package/src/services/workstream.types.ts +9 -9
- package/src/services/write-intent-validator.service.ts +81 -0
- package/src/storage/attachment-parser.ts +1 -1
- package/src/storage/attachment-utils.ts +1 -1
- package/src/storage/generated-document-storage.service.ts +3 -2
- package/src/system-agents/delegated-agent-factory.ts +2 -0
- package/src/tools/execution-plan.tool.ts +17 -23
- package/src/tools/index.ts +0 -1
- package/src/tools/team-think.tool.ts +6 -4
- package/src/utils/async.ts +2 -1
- package/src/utils/date-time.ts +4 -32
- package/src/utils/env.ts +8 -0
- package/src/utils/errors.ts +42 -10
- package/src/utils/index.ts +9 -0
- package/src/utils/string.ts +114 -1
- package/src/workers/index.ts +1 -0
- package/src/workers/regular-chat-memory-digest.runner.ts +2 -2
- package/src/workers/skill-extraction.runner.ts +1 -1
- package/src/workers/utils/file-section-chunker.ts +2 -1
- package/src/workers/utils/repomix-file-sections.ts +2 -2
- package/src/workers/utils/sandbox-error.ts +11 -2
- package/src/workers/utils/workstream-message-query.ts +11 -20
- package/src/workers/worker-utils.ts +2 -2
- package/src/tools/log-hello-world.tool.ts +0 -17
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { MonitoringWindowConfig } from '@lota-sdk/shared'
|
|
2
|
+
|
|
3
|
+
import { planSchedulerService } from './plan-scheduler.service'
|
|
4
|
+
|
|
5
|
+
class MonitoringWindowService {
|
|
6
|
+
computeCheckTimes(config: MonitoringWindowConfig): { offsetMs: number; intervalMs: number }[] {
|
|
7
|
+
const times: { offsetMs: number; intervalMs: number }[] = []
|
|
8
|
+
let currentInterval = config.initialIntervalMs
|
|
9
|
+
let elapsed = 0
|
|
10
|
+
while (elapsed < config.durationMs) {
|
|
11
|
+
times.push({ offsetMs: elapsed, intervalMs: currentInterval })
|
|
12
|
+
elapsed += currentInterval
|
|
13
|
+
currentInterval = Math.min(currentInterval / config.decayFactor, config.maxIntervalMs)
|
|
14
|
+
}
|
|
15
|
+
return times
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async startMonitoringWindow(params: {
|
|
19
|
+
runId: string
|
|
20
|
+
nodeId: string
|
|
21
|
+
config: MonitoringWindowConfig
|
|
22
|
+
organizationId: string
|
|
23
|
+
workstreamId: string
|
|
24
|
+
}): Promise<void> {
|
|
25
|
+
await planSchedulerService.createSchedule({
|
|
26
|
+
organizationId: params.organizationId,
|
|
27
|
+
workstreamId: params.workstreamId,
|
|
28
|
+
runId: params.runId,
|
|
29
|
+
nodeId: params.nodeId,
|
|
30
|
+
scheduleSpec: {
|
|
31
|
+
type: 'monitoring',
|
|
32
|
+
intervalMs: params.config.initialIntervalMs,
|
|
33
|
+
maxFires: this.computeCheckTimes(params.config).length,
|
|
34
|
+
missedPolicy: 'skip',
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
evaluateTermination(params: { samples: unknown[]; config: MonitoringWindowConfig }): boolean {
|
|
40
|
+
if (!params.config.earlyTermination) return false
|
|
41
|
+
if (params.samples.length < params.config.earlyTermination.minSamples) return false
|
|
42
|
+
|
|
43
|
+
const { condition, minSamples } = params.config.earlyTermination
|
|
44
|
+
const numericSamples = params.samples
|
|
45
|
+
.map((s) =>
|
|
46
|
+
typeof s === 'number'
|
|
47
|
+
? s
|
|
48
|
+
: typeof s === 'object' && s !== null && 'value' in s
|
|
49
|
+
? Number((s as Record<string, unknown>).value)
|
|
50
|
+
: NaN,
|
|
51
|
+
)
|
|
52
|
+
.filter((n) => !isNaN(n))
|
|
53
|
+
|
|
54
|
+
// No numeric data to evaluate against — don't terminate
|
|
55
|
+
if (numericSamples.length === 0) return false
|
|
56
|
+
|
|
57
|
+
if (condition === 'stable') {
|
|
58
|
+
const recent = numericSamples.slice(-minSamples)
|
|
59
|
+
if (recent.length < 2) return false
|
|
60
|
+
const mean = recent.reduce((a, b) => a + b, 0) / recent.length
|
|
61
|
+
const variance = recent.reduce((a, b) => a + (b - mean) ** 2, 0) / recent.length
|
|
62
|
+
const cv = mean !== 0 ? Math.sqrt(variance) / Math.abs(mean) : 0
|
|
63
|
+
return cv < 0.1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const thresholdMatch = condition.match(/^threshold:(\d+(?:\.\d+)?)$/)
|
|
67
|
+
if (thresholdMatch?.[1]) {
|
|
68
|
+
const threshold = parseFloat(thresholdMatch[1])
|
|
69
|
+
return numericSamples.some((v) => v >= threshold)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (condition === 'trend:declining') {
|
|
73
|
+
const recent = numericSamples.slice(-minSamples)
|
|
74
|
+
return recent.length >= 2 && recent.every((v, i) => i === 0 || v <= (recent[i - 1] ?? v))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (condition === 'trend:increasing') {
|
|
78
|
+
const recent = numericSamples.slice(-minSamples)
|
|
79
|
+
return recent.length >= 2 && recent.every((v, i) => i === 0 || v >= (recent[i - 1] ?? v))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
throw new Error(`Unknown monitoring termination condition: ${condition}`)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const monitoringWindowService = new MonitoringWindowService()
|
|
@@ -106,5 +106,5 @@ async function verifyMutatingApprovalForWorkstream(
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export const verifyMutatingApproval: VerifyMutatingApproval = async (params) => {
|
|
109
|
-
return
|
|
109
|
+
return verifyMutatingApprovalForWorkstream(ensureRecordId(params.workstreamId, TABLES.WORKSTREAM), params)
|
|
110
110
|
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NodeResultQuality,
|
|
3
|
+
PlanArtifactSubmission,
|
|
4
|
+
PlanNodeResult,
|
|
5
|
+
PlanNodeSpec,
|
|
6
|
+
PlanSchemaRegistry,
|
|
7
|
+
WriteIntent,
|
|
8
|
+
WriteIntentAction,
|
|
9
|
+
} from '@lota-sdk/shared'
|
|
10
|
+
|
|
11
|
+
import { serverLogger } from '../config/logger'
|
|
12
|
+
|
|
13
|
+
export type WorkspaceEntryValidation = 'validated' | 'unvalidated'
|
|
14
|
+
|
|
15
|
+
export interface WorkspaceEntry {
|
|
16
|
+
targetPath: string
|
|
17
|
+
action: WriteIntentAction
|
|
18
|
+
payload: unknown
|
|
19
|
+
validation: WorkspaceEntryValidation
|
|
20
|
+
stagedAt: Date
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface NodeWorkspace {
|
|
24
|
+
nodeId: string
|
|
25
|
+
ctx: Readonly<{
|
|
26
|
+
resolvedInput: Record<string, unknown>
|
|
27
|
+
inputArtifacts: PlanArtifactSubmission[]
|
|
28
|
+
schemaRegistry: PlanSchemaRegistry
|
|
29
|
+
nodeSpec: PlanNodeSpec
|
|
30
|
+
}>
|
|
31
|
+
work: Map<string, unknown>
|
|
32
|
+
sys: {
|
|
33
|
+
startedAt: Date
|
|
34
|
+
correctionCounts: Map<string, number>
|
|
35
|
+
writeLog: Array<{ targetPath: string; action: WriteIntentAction; timestamp: Date; result: 'accepted' | 'rejected' }>
|
|
36
|
+
}
|
|
37
|
+
deliverables: Map<string, WorkspaceEntry>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class NodeWorkspaceService {
|
|
41
|
+
initialize(params: {
|
|
42
|
+
nodeSpec: PlanNodeSpec
|
|
43
|
+
resolvedInput: Record<string, unknown>
|
|
44
|
+
inputArtifacts: PlanArtifactSubmission[]
|
|
45
|
+
schemaRegistry: PlanSchemaRegistry
|
|
46
|
+
}): NodeWorkspace {
|
|
47
|
+
const ctx = Object.freeze({
|
|
48
|
+
resolvedInput: params.resolvedInput,
|
|
49
|
+
inputArtifacts: params.inputArtifacts,
|
|
50
|
+
schemaRegistry: params.schemaRegistry,
|
|
51
|
+
nodeSpec: params.nodeSpec,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
nodeId: params.nodeSpec.id,
|
|
56
|
+
ctx,
|
|
57
|
+
work: new Map(),
|
|
58
|
+
sys: { startedAt: new Date(), correctionCounts: new Map(), writeLog: [] },
|
|
59
|
+
deliverables: new Map(),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
stageWrite(workspace: NodeWorkspace, intent: WriteIntent, validation: WorkspaceEntryValidation): void {
|
|
64
|
+
const existing = workspace.deliverables.get(intent.targetPath)
|
|
65
|
+
|
|
66
|
+
if (intent.action === 'append' && existing && Array.isArray(existing.payload) && Array.isArray(intent.payload)) {
|
|
67
|
+
existing.payload = [...(existing.payload as unknown[]), ...intent.payload]
|
|
68
|
+
existing.action = intent.action
|
|
69
|
+
existing.validation = validation
|
|
70
|
+
existing.stagedAt = new Date()
|
|
71
|
+
} else {
|
|
72
|
+
workspace.deliverables.set(intent.targetPath, {
|
|
73
|
+
targetPath: intent.targetPath,
|
|
74
|
+
action: intent.action,
|
|
75
|
+
payload: intent.payload,
|
|
76
|
+
validation,
|
|
77
|
+
stagedAt: new Date(),
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
workspace.sys.writeLog.push({
|
|
82
|
+
targetPath: intent.targetPath,
|
|
83
|
+
action: intent.action,
|
|
84
|
+
timestamp: new Date(),
|
|
85
|
+
result: 'accepted',
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
finalize(workspace: NodeWorkspace): PlanNodeResult & { isComplete: boolean; quality: NodeResultQuality } {
|
|
90
|
+
const artifacts: PlanArtifactSubmission[] = []
|
|
91
|
+
let structuredOutput: Record<string, unknown> | undefined
|
|
92
|
+
let allValidated = true
|
|
93
|
+
const requiredNames = new Set(workspace.ctx.nodeSpec.deliverables.filter((d) => d.required).map((d) => d.name))
|
|
94
|
+
const presentRequired = new Set<string>()
|
|
95
|
+
|
|
96
|
+
for (const [targetPath, entry] of workspace.deliverables) {
|
|
97
|
+
if (entry.validation === 'unvalidated') {
|
|
98
|
+
allValidated = false
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (targetPath.startsWith('structuredOutput')) {
|
|
102
|
+
if (!structuredOutput) structuredOutput = {}
|
|
103
|
+
const subPath = targetPath.replace(/^structuredOutput\.?/, '')
|
|
104
|
+
if (subPath) {
|
|
105
|
+
structuredOutput[subPath] = entry.payload
|
|
106
|
+
} else {
|
|
107
|
+
structuredOutput =
|
|
108
|
+
typeof entry.payload === 'object' && entry.payload !== null && !Array.isArray(entry.payload)
|
|
109
|
+
? (entry.payload as Record<string, unknown>)
|
|
110
|
+
: structuredOutput
|
|
111
|
+
}
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const spec = workspace.ctx.nodeSpec.deliverables.find((d) => d.name === targetPath)
|
|
116
|
+
if (!spec) {
|
|
117
|
+
serverLogger.warn`Write to unknown deliverable path "${targetPath}" in node ${workspace.nodeId} — skipping`
|
|
118
|
+
continue
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (requiredNames.has(targetPath)) {
|
|
122
|
+
presentRequired.add(targetPath)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
artifacts.push({
|
|
126
|
+
name: spec.name,
|
|
127
|
+
kind: spec.kind,
|
|
128
|
+
pointer: `workspace://${workspace.nodeId}/${targetPath}`,
|
|
129
|
+
schemaRef: spec.schemaRef,
|
|
130
|
+
description: spec.description,
|
|
131
|
+
payload:
|
|
132
|
+
typeof entry.payload === 'string'
|
|
133
|
+
? { content: entry.payload }
|
|
134
|
+
: typeof entry.payload === 'object' && entry.payload !== null
|
|
135
|
+
? (entry.payload as Record<string, unknown> | unknown[])
|
|
136
|
+
: undefined,
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const allRequiredPresent = requiredNames.size === presentRequired.size
|
|
141
|
+
const quality: NodeResultQuality = allRequiredPresent && allValidated ? 'full' : 'partial'
|
|
142
|
+
const isComplete = quality === 'full'
|
|
143
|
+
|
|
144
|
+
return { structuredOutput, artifacts, quality, isComplete }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
cleanup(workspace: NodeWorkspace): void {
|
|
148
|
+
workspace.work.clear()
|
|
149
|
+
workspace.deliverables.clear()
|
|
150
|
+
workspace.sys.writeLog.length = 0
|
|
151
|
+
workspace.sys.correctionCounts.clear()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const nodeWorkspaceService = new NodeWorkspaceService()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { NotificationSeverity } from '@lota-sdk/shared'
|
|
2
|
+
|
|
3
|
+
export interface NotificationPayload {
|
|
4
|
+
organizationId: string
|
|
5
|
+
workstreamId: string
|
|
6
|
+
runId?: string
|
|
7
|
+
nodeId?: string
|
|
8
|
+
severity: NotificationSeverity
|
|
9
|
+
title: string
|
|
10
|
+
body: string
|
|
11
|
+
dedupeKey?: string
|
|
12
|
+
metadata?: Record<string, unknown>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface NotificationService {
|
|
16
|
+
notify(payload: NotificationPayload): Promise<void>
|
|
17
|
+
remind(payload: NotificationPayload): Promise<void>
|
|
18
|
+
escalate(payload: NotificationPayload): Promise<void>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class NoOpNotificationService implements NotificationService {
|
|
22
|
+
async notify(_payload: NotificationPayload): Promise<void> {}
|
|
23
|
+
async remind(_payload: NotificationPayload): Promise<void> {}
|
|
24
|
+
async escalate(_payload: NotificationPayload): Promise<void> {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let _notificationService: NotificationService | null = null
|
|
28
|
+
|
|
29
|
+
export function configureNotificationService(service: NotificationService | null): void {
|
|
30
|
+
_notificationService = service
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getNotificationService(): NotificationService {
|
|
34
|
+
if (_notificationService === null) {
|
|
35
|
+
throw new Error('Notification service is not configured.')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return _notificationService
|
|
39
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { recordIdStringSchema } from '@lota-sdk/shared'
|
|
1
|
+
import { recordIdSchema, recordIdStringSchema } from '@lota-sdk/shared'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
4
|
import { BaseService } from '../db/base.service'
|
|
@@ -8,9 +8,9 @@ import { TABLES } from '../db/tables'
|
|
|
8
8
|
import { toIsoDateTimeString } from '../utils/date-time'
|
|
9
9
|
|
|
10
10
|
const organizationMemberRecordSchema = z.object({
|
|
11
|
-
id:
|
|
12
|
-
in:
|
|
13
|
-
out:
|
|
11
|
+
id: recordIdSchema,
|
|
12
|
+
in: recordIdSchema,
|
|
13
|
+
out: recordIdSchema,
|
|
14
14
|
role: z.string(),
|
|
15
15
|
createdAt: z.coerce.date(),
|
|
16
16
|
})
|
|
@@ -91,6 +91,13 @@ class OrganizationMemberService extends BaseService<typeof organizationMemberRec
|
|
|
91
91
|
)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
async getMembership(userId: RecordIdInput, organizationId: RecordIdInput): Promise<SdkOrganizationMember | null> {
|
|
95
|
+
const userRef = ensureRecordId(userId, TABLES.USER)
|
|
96
|
+
const organizationRef = ensureRecordId(organizationId, TABLES.ORGANIZATION)
|
|
97
|
+
const record = (await this.findAll({ in: userRef, out: organizationRef }, { limit: 1 })).at(0)
|
|
98
|
+
return record ? this.toPublic(record) : null
|
|
99
|
+
}
|
|
100
|
+
|
|
94
101
|
async isMember(userId: RecordIdInput, organizationId: RecordIdInput): Promise<boolean> {
|
|
95
102
|
const userRef = ensureRecordId(userId, TABLES.USER)
|
|
96
103
|
const organizationRef = ensureRecordId(organizationId, TABLES.ORGANIZATION)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { recordIdStringSchema } from '@lota-sdk/shared'
|
|
1
|
+
import { recordIdSchema, recordIdStringSchema } from '@lota-sdk/shared'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
4
|
import { BaseService } from '../db/base.service'
|
|
@@ -9,12 +9,12 @@ import { TABLES } from '../db/tables'
|
|
|
9
9
|
import { toIsoDateTimeString, toOptionalIsoDateTimeString } from '../utils/date-time'
|
|
10
10
|
|
|
11
11
|
const organizationRecordSchema = z.object({
|
|
12
|
-
id:
|
|
12
|
+
id: recordIdSchema,
|
|
13
13
|
name: z.string(),
|
|
14
|
-
regularChatDigestLastWorkstreamCursorCreatedAt: z.
|
|
14
|
+
regularChatDigestLastWorkstreamCursorCreatedAt: z.coerce.date().optional(),
|
|
15
15
|
regularChatDigestLastWorkstreamCursorId: z.string().optional(),
|
|
16
16
|
skillExtractionLastCursorId: z.string().optional(),
|
|
17
|
-
skillExtractionLastCursorCreatedAt: z.
|
|
17
|
+
skillExtractionLastCursorCreatedAt: z.coerce.date().optional(),
|
|
18
18
|
createdAt: z.coerce.date(),
|
|
19
19
|
updatedAt: z.coerce.date(),
|
|
20
20
|
})
|
|
@@ -86,7 +86,7 @@ class OrganizationService extends BaseService<typeof organizationRecordSchema> {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
async getOrganizationRecord(organizationId: RecordIdRef): Promise<SdkOrganizationRecord> {
|
|
89
|
-
return
|
|
89
|
+
return this.getById(ensureRecordId(organizationId, TABLES.ORGANIZATION))
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
async updateOrganization(organizationId: RecordIdInput, params: { name: string }): Promise<SdkOrganization> {
|