slotlock 0.7.0 → 0.9.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.
- package/CHANGELOG.md +281 -0
- package/agent-server.d.ts +25 -5
- package/agent-server.js +152 -7
- package/agent-store-backend.d.ts +6 -1
- package/agent-store-backend.js +861 -55
- package/application-api.d.ts +19 -1
- package/application-api.js +578 -21
- package/approvals.d.ts +2 -0
- package/approvals.js +12 -5
- package/assistant.d.ts +64 -9
- package/assistant.js +450 -82
- package/availability-store.d.ts +193 -0
- package/availability-store.js +558 -0
- package/booking-rules.d.ts +92 -5
- package/booking-rules.js +243 -15
- package/dashboard-assistant-ui.d.ts +21 -0
- package/dashboard-assistant-ui.js +539 -0
- package/dashboard-markdown.d.ts +2 -0
- package/dashboard-markdown.js +157 -0
- package/dashboard-settings-ui.d.ts +1 -0
- package/dashboard-settings-ui.js +78 -0
- package/dashboard.d.ts +84 -11
- package/dashboard.js +1654 -384
- package/ddl.d.ts +5 -1
- package/ddl.js +760 -9
- package/event-feed.d.ts +1 -1
- package/event-feed.js +18 -0
- package/holiday-import.d.ts +38 -0
- package/holiday-import.js +57 -0
- package/holidays.d.ts +38 -0
- package/holidays.js +150 -0
- package/hours.d.ts +125 -0
- package/hours.js +224 -0
- package/index.d.ts +14 -3
- package/index.js +10 -2
- package/interop.d.ts +25 -7
- package/interop.js +145 -17
- package/lifecycle.d.ts +31 -0
- package/lifecycle.js +115 -0
- package/maintenance.d.ts +19 -0
- package/maintenance.js +55 -1
- package/metrics.js +3 -0
- package/openapi.json +16237 -7795
- package/package.json +1 -1
- package/ranges.d.ts +28 -0
- package/ranges.js +135 -0
- package/resource-search.d.ts +19 -0
- package/resource-search.js +153 -0
- package/rest-api.js +7 -0
- package/rules.d.ts +2 -0
- package/rules.js +2 -0
- package/self-host.d.ts +1 -1
- package/self-host.js +221 -21
- package/slotlock.manifest.json +1 -1
- package/store.d.ts +367 -24
- package/store.js +1567 -97
- package/types.d.ts +198 -0
package/approvals.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface PutApprovalPolicyParams {
|
|
|
23
23
|
outcome: SlotlockApprovalPolicy['outcome'];
|
|
24
24
|
approvalTtlMinutes?: number;
|
|
25
25
|
leadMinutes?: number;
|
|
26
|
+
/** It also holds the tenant's own bookings through the application API (default false). */
|
|
27
|
+
includeApplication?: boolean;
|
|
26
28
|
}
|
|
27
29
|
/** Create or replace a policy by its reference. Throws `invalid_approval_policy`; at most 50. */
|
|
28
30
|
export declare function putApprovalPolicy(sql: StoreSql, params: PutApprovalPolicyParams): Promise<SlotlockApprovalPolicy | null>;
|
package/approvals.js
CHANGED
|
@@ -18,7 +18,7 @@ export class SlotlockApprovalPolicyError extends Error {
|
|
|
18
18
|
super(`Slotlock approval policy: ${message}`);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
const POLICY_COLUMNS = 'ref, name, applies_to, conditions, outcome, approval_ttl_minutes, lead_minutes, created_at, updated_at';
|
|
21
|
+
const POLICY_COLUMNS = 'ref, name, applies_to, conditions, outcome, approval_ttl_minutes, lead_minutes, include_application, created_at, updated_at';
|
|
22
22
|
function toPolicy(row) {
|
|
23
23
|
const applies = row.applies_to;
|
|
24
24
|
const conditions = row.conditions;
|
|
@@ -39,6 +39,7 @@ function toPolicy(row) {
|
|
|
39
39
|
outcome: row.outcome,
|
|
40
40
|
approvalTtlMinutes: row.approval_ttl_minutes,
|
|
41
41
|
leadMinutes: row.lead_minutes,
|
|
42
|
+
includeApplication: row.include_application === true,
|
|
42
43
|
createdAt: row.created_at,
|
|
43
44
|
updatedAt: row.updated_at,
|
|
44
45
|
};
|
|
@@ -99,24 +100,30 @@ function storedPolicy(params) {
|
|
|
99
100
|
...(given.outsideHours !== undefined ? { outside_hours: given.outsideHours } : {}),
|
|
100
101
|
...(given.kinds !== undefined ? { kinds: [...new Set(given.kinds)].sort() } : {}),
|
|
101
102
|
};
|
|
102
|
-
|
|
103
|
+
if (params.includeApplication !== undefined && typeof params.includeApplication !== 'boolean') {
|
|
104
|
+
throw new SlotlockApprovalPolicyError('include_application must be true or false');
|
|
105
|
+
}
|
|
106
|
+
return { name, appliesTo, conditions, ttl, lead, includeApplication: params.includeApplication === true };
|
|
103
107
|
}
|
|
104
108
|
/** Create or replace a policy by its reference. Throws `invalid_approval_policy`; at most 50. */
|
|
105
109
|
export async function putApprovalPolicy(sql, params) {
|
|
106
110
|
const stored = storedPolicy(params);
|
|
107
111
|
const [row] = await sql `
|
|
108
112
|
INSERT INTO slotlock.approval_policies (
|
|
109
|
-
tenant_ref, ref, name, applies_to, conditions, outcome, approval_ttl_minutes, lead_minutes
|
|
113
|
+
tenant_ref, ref, name, applies_to, conditions, outcome, approval_ttl_minutes, lead_minutes,
|
|
114
|
+
include_application
|
|
110
115
|
)
|
|
111
116
|
SELECT ${params.tenantRef}, ${params.ref}, ${stored.name}, ${sql.json(stored.appliesTo)},
|
|
112
|
-
${sql.json(stored.conditions)}, ${params.outcome}, ${stored.ttl}, ${stored.lead}
|
|
117
|
+
${sql.json(stored.conditions)}, ${params.outcome}, ${stored.ttl}, ${stored.lead},
|
|
118
|
+
${stored.includeApplication}
|
|
113
119
|
WHERE EXISTS (SELECT 1 FROM slotlock.approval_policies WHERE tenant_ref = ${params.tenantRef} AND ref = ${params.ref})
|
|
114
120
|
OR (SELECT count(*) FROM slotlock.approval_policies WHERE tenant_ref = ${params.tenantRef})
|
|
115
121
|
< ${SLOTLOCK_MAX_APPROVAL_POLICIES}
|
|
116
122
|
ON CONFLICT (tenant_ref, ref) DO UPDATE
|
|
117
123
|
SET name = EXCLUDED.name, applies_to = EXCLUDED.applies_to, conditions = EXCLUDED.conditions,
|
|
118
124
|
outcome = EXCLUDED.outcome, approval_ttl_minutes = EXCLUDED.approval_ttl_minutes,
|
|
119
|
-
lead_minutes = EXCLUDED.lead_minutes,
|
|
125
|
+
lead_minutes = EXCLUDED.lead_minutes, include_application = EXCLUDED.include_application,
|
|
126
|
+
updated_at = statement_timestamp()
|
|
120
127
|
RETURNING ${sql.unsafe(POLICY_COLUMNS)}`;
|
|
121
128
|
return row ? toPolicy(row) : null;
|
|
122
129
|
}
|
package/assistant.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SlotlockAgentOperation } from './agent-server.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SlotlockAssistantChatRecord, SlotlockAssistantChatSummary, SlotlockAssistantSettingsRecord, SlotlockStore } from './store.js';
|
|
3
3
|
export type SlotlockAssistantProvider = 'anthropic' | 'openai';
|
|
4
4
|
/** What the assistant does with each agent operation: run it, propose it, or never offer it. */
|
|
5
5
|
export type SlotlockAssistantToolUse = 'read' | 'propose' | 'excluded';
|
|
@@ -95,18 +95,27 @@ export interface SlotlockAssistantStore {
|
|
|
95
95
|
* still opens, and is opened that way each time.
|
|
96
96
|
*/
|
|
97
97
|
resealKey?(tenantRef: string, from: string, to: string): Promise<boolean>;
|
|
98
|
-
|
|
98
|
+
/** A member's conversations, the most recent first: what the Chats list shows. */
|
|
99
|
+
listChats(tenantRef: string, memberRef: string, limit?: number): Promise<SlotlockAssistantChatSummary[]>;
|
|
100
|
+
/** One of a member's conversations, or null when there is none by that id. */
|
|
101
|
+
getChat(tenantRef: string, memberRef: string, chatId: string): Promise<SlotlockAssistantChatRecord | null>;
|
|
99
102
|
/**
|
|
100
|
-
*
|
|
101
|
-
* `added` ones not stored already
|
|
103
|
+
* Create one of a member's conversations (titled `title`), or replace its messages; keep the
|
|
104
|
+
* stored actions `keep` names, as they stand, and add the `added` ones not stored already
|
|
105
|
+
* (store.ts putAssistantChat). Kept until deleted, or for `ttlMs` when given. With `create`
|
|
106
|
+
* false, only one still there is changed (false when it was deleted meanwhile).
|
|
102
107
|
*/
|
|
103
|
-
|
|
108
|
+
putChat(tenantRef: string, memberRef: string, chatId: string, chat: {
|
|
109
|
+
title: string;
|
|
104
110
|
messages: unknown[];
|
|
105
111
|
added: Record<string, Record<string, unknown>>;
|
|
106
112
|
keep: readonly string[];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
create?: boolean;
|
|
114
|
+
}, ttlMs: number | null): Promise<boolean>;
|
|
115
|
+
/** Give a conversation a new title (1-120 characters). False when there is none. */
|
|
116
|
+
renameChat(tenantRef: string, memberRef: string, chatId: string, title: string): Promise<boolean>;
|
|
117
|
+
settleAction(tenantRef: string, memberRef: string, chatId: string, actionId: string, from: string, patch: Record<string, unknown>): Promise<Record<string, unknown> | null>;
|
|
118
|
+
deleteChat(tenantRef: string, memberRef: string, chatId: string): Promise<boolean>;
|
|
110
119
|
}
|
|
111
120
|
/** The assistant's records in the store, each in a transaction under the tenant's row-level security. */
|
|
112
121
|
export declare function createSlotlockAssistantStore(store: SlotlockStore): SlotlockAssistantStore;
|
|
@@ -191,6 +200,11 @@ interface ModelRequest {
|
|
|
191
200
|
force?: string;
|
|
192
201
|
fetch: typeof fetch;
|
|
193
202
|
signal: AbortSignal;
|
|
203
|
+
/**
|
|
204
|
+
* Stream the answer: called with each piece of its text as it arrives, in order; the pieces join
|
|
205
|
+
* to the answer's text. Without it the call asks for one JSON answer.
|
|
206
|
+
*/
|
|
207
|
+
onText?: (delta: string) => void;
|
|
194
208
|
}
|
|
195
209
|
/** One model call. Throws SlotlockAssistantProviderError, whose message never holds the key. */
|
|
196
210
|
export declare function callSlotlockAssistantModel(request: ModelRequest): Promise<SlotlockAssistantModelTurn>;
|
|
@@ -257,7 +271,30 @@ export interface SlotlockAssistantTurnOptions {
|
|
|
257
271
|
ok: false;
|
|
258
272
|
code: string;
|
|
259
273
|
}>;
|
|
274
|
+
/** Stream the turn: each model call's text as it arrives, and each tool call before and after it runs. */
|
|
275
|
+
onEvent?: (event: SlotlockAssistantTurnEvent) => void;
|
|
276
|
+
/** The member's Stop: the turn ends at once, keeping what it has, and says it stopped. */
|
|
277
|
+
signal?: AbortSignal;
|
|
260
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* What a streamed turn tells as it goes, in order: text as the model writes it; then each tool call
|
|
281
|
+
* (`read` runs, `write` is proposed, `unknown` is refused) before it runs, and its result after.
|
|
282
|
+
*/
|
|
283
|
+
export type SlotlockAssistantTurnEvent = {
|
|
284
|
+
type: 'text';
|
|
285
|
+
delta: string;
|
|
286
|
+
} | {
|
|
287
|
+
type: 'call';
|
|
288
|
+
id: string;
|
|
289
|
+
name: string;
|
|
290
|
+
use: 'read' | 'write' | 'unknown';
|
|
291
|
+
} | {
|
|
292
|
+
type: 'result';
|
|
293
|
+
id: string;
|
|
294
|
+
name: string;
|
|
295
|
+
ok: boolean;
|
|
296
|
+
actionId?: string;
|
|
297
|
+
};
|
|
261
298
|
export interface SlotlockAssistantTurnResult {
|
|
262
299
|
/** The entries this turn added. */
|
|
263
300
|
added: SlotlockAssistantEntry[];
|
|
@@ -267,7 +304,8 @@ export interface SlotlockAssistantTurnResult {
|
|
|
267
304
|
/**
|
|
268
305
|
* One member message: call the model, run what it reads, keep what it would write, and call it
|
|
269
306
|
* again with the results, up to `maxSteps` calls. Only the offered tools run, whatever the model
|
|
270
|
-
* names; everything else is answered `tool_not_available`.
|
|
307
|
+
* names; everything else is answered `tool_not_available`. With `onEvent` each model call streams;
|
|
308
|
+
* once `signal` aborts, no model call or tool goes on, and every call kept has its result.
|
|
271
309
|
*/
|
|
272
310
|
export declare function runSlotlockAssistantTurn(options: SlotlockAssistantTurnOptions): Promise<SlotlockAssistantTurnResult>;
|
|
273
311
|
/**
|
|
@@ -284,11 +322,28 @@ export declare function pruneSlotlockAssistantActions(entries: readonly Slotlock
|
|
|
284
322
|
export declare function pendingSlotlockAssistantActions(actions: Readonly<Record<string, Record<string, unknown>>>): number;
|
|
285
323
|
/** Read stored entries back, dropping anything malformed. */
|
|
286
324
|
export declare function readSlotlockAssistantEntries(value: unknown): SlotlockAssistantEntry[];
|
|
325
|
+
/** A resource as the assistant's system prompt lists it: its id, and what people call it. */
|
|
326
|
+
export interface SlotlockAssistantResourceEntry {
|
|
327
|
+
id: string;
|
|
328
|
+
name?: string;
|
|
329
|
+
ref?: string;
|
|
330
|
+
kind?: string;
|
|
331
|
+
location?: string;
|
|
332
|
+
timezone: string;
|
|
333
|
+
}
|
|
334
|
+
/** How many of the workspace's resources the system prompt lists; the rest are found by search. */
|
|
335
|
+
export declare const SLOTLOCK_ASSISTANT_DIRECTORY_SIZE = 50;
|
|
287
336
|
/** The system prompt: who the model works for, and that what it reads is data, not instructions. */
|
|
288
337
|
export declare function slotlockAssistantSystemPrompt(args: {
|
|
289
338
|
brand: string;
|
|
290
339
|
workspace: string;
|
|
291
340
|
login: string;
|
|
292
341
|
now: Date;
|
|
342
|
+
/**
|
|
343
|
+
* The workspace's resources agents may see, so a resource the member names is matched to its id
|
|
344
|
+
* without a lookup; `resourceCount` is how many there are when that is more than are listed.
|
|
345
|
+
*/
|
|
346
|
+
resources?: readonly SlotlockAssistantResourceEntry[];
|
|
347
|
+
resourceCount?: number;
|
|
293
348
|
}): string;
|
|
294
349
|
export {};
|