@coffer-org/server 7.3.0 → 7.4.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.
@@ -2,9 +2,11 @@ import type { ImageTarget } from '../media/index.ts';
2
2
  import type { AuthRole } from '../plugin-hooks.ts';
3
3
  import type { ContextFact } from './context-facts.ts';
4
4
  import type { SystemAreas } from './system-areas.ts';
5
+ import type { StoredAttachment } from '../conversation-store.ts';
5
6
  export type { ImageTarget };
6
7
  export type { ContextFact };
7
8
  export type { SystemAreas };
9
+ export type { StoredAttachment };
8
10
  export interface AttachmentRef {
9
11
  name: string;
10
12
  mime?: string;
@@ -85,7 +87,7 @@ export interface AgentTurn {
85
87
  body: {
86
88
  system: string[];
87
89
  messages: ConvMessage[];
88
- userTurns: number;
90
+ userMessageCount: number;
89
91
  };
90
92
  toolProvider?: AgentToolProvider;
91
93
  presetId?: string;
@@ -112,7 +114,6 @@ export interface AgentRuntime {
112
114
  }
113
115
  export interface ConnectorRegistration {
114
116
  id: string;
115
- linkUrl?(code: string): string | undefined;
116
117
  }
117
118
  export interface AttachmentMaterializer {
118
119
  store(bytes: Uint8Array, opts?: {
@@ -120,10 +121,9 @@ export interface AttachmentMaterializer {
120
121
  mime?: string;
121
122
  }): Promise<AttachmentRef>;
122
123
  }
123
- export type SenderIdKind = 'coffer-user' | 'transport';
124
124
  export interface TurnEnvelope {
125
125
  connectorId: string;
126
- chatId: string;
126
+ conversationId: string;
127
127
  turnId: string;
128
128
  }
129
129
  export interface ConnectorCapabilities {
@@ -132,23 +132,26 @@ export interface ConnectorCapabilities {
132
132
  }
133
133
  export interface TurnBody {
134
134
  systemPrompt: SystemAreas;
135
- messages: ConvMessage[];
136
135
  capabilities: ConnectorCapabilities;
137
- userTurns: number;
138
136
  }
139
137
  export interface TurnRequest {
140
138
  envelope: TurnEnvelope;
141
- body: TurnBody;
142
- agentId?: string;
143
- presetId?: string;
144
139
  sender: {
145
- id: string;
140
+ userId: number;
146
141
  displayName?: string;
147
- idKind?: SenderIdKind;
148
142
  };
143
+ message?: {
144
+ text: string;
145
+ attachments?: StoredAttachment[];
146
+ replyToMsgId?: string | null;
147
+ };
148
+ capabilities?: ConnectorCapabilities;
149
+ systemPrompt?: SystemAreas;
149
150
  turnContext?: ContextFact[];
150
- prepareAttachments?: (materializer: AttachmentMaterializer) => Promise<ConvMessage[]>;
151
+ agentId?: string;
152
+ presetId?: string;
151
153
  signal?: AbortSignal;
154
+ prepareAttachments?(m: AttachmentMaterializer): Promise<StoredAttachment[] | ConvMessage[]>;
152
155
  }
153
156
  export type TurnEvent = {
154
157
  kind: 'delta';
@@ -177,9 +180,6 @@ export type TurnEvent = {
177
180
  } | {
178
181
  kind: 'title';
179
182
  text: string;
180
- } | {
181
- kind: 'notice';
182
- text: string;
183
183
  };
184
184
  export interface TurnSink {
185
185
  emit(event: TurnEvent): void;
@@ -187,14 +187,8 @@ export interface TurnSink {
187
187
  }
188
188
  export interface Connector {
189
189
  id: string;
190
- enrolmentNotice: string;
191
- open(envelope: TurnEnvelope): TurnSink;
192
- recordContext(m: {
193
- chatId: string;
194
- userMsgId: string;
195
- facts: ContextFact[];
196
- ts: number;
197
- }): Promise<void>;
190
+ open(envelope: TurnEnvelope, msgId: string): TurnSink;
191
+ bindMessage?(envelope: TurnEnvelope, msgId: string, externalId: string): Promise<void>;
198
192
  }
199
193
  export interface GatePolicy {
200
194
  agentId?: string;
@@ -1,6 +1,7 @@
1
1
  import type { EntityManager } from '@mikro-orm/core';
2
2
  import type { z } from 'zod';
3
- import type { ColumnType, ColumnConversion } from '@coffer-org/sdk/fields';
3
+ import type { ColumnType, ColumnConversion, LayoutEl } from '@coffer-org/sdk/fields';
4
+ import type { LayoutInput } from '@coffer-org/sdk/materialize/decl';
4
5
  import { type Logger } from '@coffer-org/sdk/logger';
5
6
  export type { BackgroundTask } from './background-scheduler.ts';
6
7
  export interface TableOps {
@@ -60,6 +61,15 @@ export type PluginStreamAction = (body: Record<string, unknown>, ctx: {
60
61
  emit: (event: string, data: unknown) => void;
61
62
  signal: AbortSignal;
62
63
  }) => Promise<void>;
64
+ export interface PrivateTableDef {
65
+ name: string;
66
+ fields: LayoutEl[];
67
+ unique?: string[][];
68
+ }
69
+ export type PrivateTableDefInput = Omit<PrivateTableDef, 'fields'> & {
70
+ fields: LayoutInput;
71
+ };
72
+ export declare function definePrivateTable(t: PrivateTableDefInput): PrivateTableDef;
63
73
  export interface PluginHooks {
64
74
  migrations?: Migration[];
65
75
  seed?: Seed[];
@@ -71,6 +81,7 @@ export interface PluginHooks {
71
81
  userActions?: Record<string, PluginUserAction>;
72
82
  streamActions?: Record<string, PluginStreamAction>;
73
83
  http?: PluginHttpMount[];
84
+ tables?: PrivateTableDef[];
74
85
  }
75
86
  export declare const pluginHooks: Record<string, PluginHooks>;
76
87
  export interface PluginHttpRequest {
@@ -1,3 +1,4 @@
1
+ import { materializeDef } from '@coffer-org/sdk/materialize/pipeline';
1
2
  import { getLogger } from '@coffer-org/sdk/logger';
2
3
  export function pluginCtx(id, em, signal) {
3
4
  return { em, log: getLogger(id), ...(signal ? { signal } : {}) };
@@ -10,4 +11,7 @@ export class HttpError extends Error {
10
11
  this.name = 'HttpError';
11
12
  }
12
13
  }
14
+ export function definePrivateTable(t) {
15
+ return materializeDef(t);
16
+ }
13
17
  export const pluginHooks = {};
@@ -1,14 +1,18 @@
1
+ import type { EntitySchema } from '@mikro-orm/core';
1
2
  import { type Registry } from '@coffer-org/sdk/compose';
2
3
  import type { PluginManifest } from '@coffer-org/sdk/plugin';
4
+ import { type PluginHooks } from './plugin-hooks.ts';
3
5
  export declare function getPlugins(): Promise<PluginManifest[]>;
4
6
  export declare function readDisabled(): Promise<Set<string>>;
5
7
  export declare function getDisabled(): Promise<Set<string>>;
6
8
  export declare function getPluginSettings(groupId: string): Promise<Record<string, unknown>>;
7
9
  export declare function requireSettings<K extends string>(pluginId: string, keys: readonly K[]): Promise<Record<K, string>>;
10
+ export declare function privateTableEntities(plugins: PluginManifest[], hooks: Record<string, PluginHooks>): EntitySchema[];
8
11
  export declare function initStorage(): Promise<Set<string>>;
9
12
  export declare function initPlugins(): Promise<Registry>;
10
13
  export declare function teardownPlugins(): Promise<void>;
11
14
  export declare function teardownPlugin(id: string): Promise<void>;
15
+ export declare function pluginTables(p: PluginManifest, hooks?: Record<string, PluginHooks>): string[];
12
16
  export declare function purgePluginData(p: PluginManifest, actor: string): Promise<void>;
13
17
  export declare function filterEnabled<T extends {
14
18
  id: string;
@@ -2,7 +2,7 @@ import { composeRegistry } from '@coffer-org/sdk/compose';
2
2
  import { getLogger } from '@coffer-org/sdk/logger';
3
3
  import { initDb, getOrm, getEm } from "./db.js";
4
4
  import { syncSchema } from "./schema-sync.js";
5
- import { systemEntities, buildPluginEntities, shelfTableName } from "./entity-schema.js";
5
+ import { systemEntities, buildPluginEntities, buildPrivateTableEntity, shelfTableName, privateTableName, } from "./entity-schema.js";
6
6
  import { pluginHooks, pluginCtx, HttpError } from "./plugin-hooks.js";
7
7
  import { discoverPlugins, loadServerHooks } from "./plugin-discovery.js";
8
8
  import { selectRows } from "./read-rows.js";
@@ -13,7 +13,7 @@ import { migrateEmbeddingVectorsToBlob } from "./embeddings.js";
13
13
  import { ensureSearchTable } from "./search-index.js";
14
14
  import { startScheduler, stopScheduler } from "./background-scheduler.js";
15
15
  import { startSearchIndexer, indexSearchOnce } from "./search-indexer.js";
16
- import { startOrchestrator, stopOrchestrator, orchestratorStartersTask, linkCodePruneTask, } from "./orchestrator/index.js";
16
+ import { startOrchestrator, stopOrchestrator, orchestratorStartersTask } from "./orchestrator/index.js";
17
17
  import { SYSTEM_SETTINGS_ID, SYSTEM_SETTINGS } from "./system-settings.js";
18
18
  const log = getLogger('plugins');
19
19
  let stopSearchIndexer;
@@ -78,6 +78,9 @@ async function seedPluginRows() {
78
78
  }
79
79
  await fork.flush();
80
80
  }
81
+ export function privateTableEntities(plugins, hooks) {
82
+ return plugins.flatMap((p) => (hooks[p.id]?.tables ?? []).map((t) => buildPrivateTableEntity(p.id, t)));
83
+ }
81
84
  export async function initStorage() {
82
85
  await initDb(systemEntities);
83
86
  await runSystemMigrations(getEm().fork());
@@ -92,10 +95,10 @@ export async function initStorage() {
92
95
  const hooks = await loadServerHooks();
93
96
  await runMigrations({
94
97
  em: getEm().fork(),
95
- plugins: active.map((p) => ({ id: p.id, tables: pluginTables(p) })),
98
+ plugins: active.map((p) => ({ id: p.id, tables: pluginTables(p, hooks) })),
96
99
  hooks,
97
100
  });
98
- const pluginEntities = buildPluginEntities(active);
101
+ const pluginEntities = [...buildPluginEntities(active), ...privateTableEntities(active, hooks)];
99
102
  await assertSafeRequired(getEm().fork(), pluginEntities);
100
103
  if (pluginEntities.length)
101
104
  getOrm().discoverEntity(pluginEntities);
@@ -110,7 +113,7 @@ export async function initPlugins() {
110
113
  Object.assign(pluginHooks, await loadServerHooks());
111
114
  await runSeeds({ em: getEm().fork(), plugins: reg.order, hooks: pluginHooks });
112
115
  startOrchestrator();
113
- const bgTasks = [orchestratorStartersTask, linkCodePruneTask];
116
+ const bgTasks = [orchestratorStartersTask];
114
117
  for (const p of reg.order) {
115
118
  const h = pluginHooks[p.id];
116
119
  try {
@@ -175,16 +178,17 @@ function pluginShelves(p) {
175
178
  ...(p.libraryShelves ?? []).map((m) => ({ library: m.library, shelf: m.shelf })),
176
179
  ];
177
180
  }
178
- function pluginTables(p) {
181
+ export function pluginTables(p, hooks) {
179
182
  return [
180
183
  ...pluginShelves(p).map(({ library, shelf }) => shelfTableName(library, shelf)),
181
184
  ...(p.extends_ ?? []).map((e) => `extend__${e.id}`),
182
185
  ...(p.settings && p.settings.fields.length > 0 ? [`_settings__${p.id}`] : []),
186
+ ...(hooks?.[p.id]?.tables ?? []).map((t) => privateTableName(p.id, t.name)),
183
187
  ];
184
188
  }
185
189
  export async function purgePluginData(p, actor) {
186
190
  await teardownPlugin(p.id);
187
- const tables = pluginTables(p);
191
+ const tables = pluginTables(p, pluginHooks);
188
192
  const conn = getEm().fork().getConnection();
189
193
  for (const t of tables) {
190
194
  await conn.execute(`DROP TABLE IF EXISTS "${t}"`);
@@ -1,15 +1,21 @@
1
1
  import type { FastifyInstance } from 'fastify';
2
2
  import type { PluginManifest } from '@coffer-org/sdk/plugin';
3
3
  import type { PluginAssetRecord } from './plugin-discovery.ts';
4
+ export interface PluginLabelEntry {
5
+ id: string;
6
+ label: string;
7
+ }
4
8
  export interface PluginListEntry {
5
9
  id: string;
10
+ label: string;
11
+ description: string;
6
12
  installedVersion: string;
7
13
  latestVersion: string | null;
8
14
  packageName: string | null;
9
15
  dependsOn: string[];
10
16
  enabled: boolean;
11
- libraries: string[];
12
- extends: string[];
17
+ libraries: PluginLabelEntry[];
18
+ extends: PluginLabelEntry[];
13
19
  hasSettings: boolean;
14
20
  schema?: string;
15
21
  web?: string;
@@ -11,13 +11,15 @@ export async function buildPluginListResponse(plugins, assets, disabled, withUpd
11
11
  const a = assetById.get(p.id);
12
12
  return {
13
13
  id: p.id,
14
+ label: p.label,
15
+ description: p.description,
14
16
  installedVersion: a?.version ?? p.version,
15
17
  latestVersion: withUpdates && a && !a.local ? await checkLatestVersion(a.packageName, { force: forceUpdates }) : null,
16
18
  packageName: a?.packageName ?? null,
17
19
  dependsOn: p.dependsOn,
18
20
  enabled: !disabled.has(p.id),
19
- libraries: (p.libraries ?? []).map((v) => v.meta.id),
20
- extends: (p.extends_ ?? []).map((e) => e.id),
21
+ libraries: (p.libraries ?? []).map((v) => ({ id: v.meta.id, label: v.meta.label })),
22
+ extends: (p.extends_ ?? []).map((e) => ({ id: e.id, label: e.label })),
21
23
  hasSettings: Boolean(p.settings && p.settings.fields.length > 0),
22
24
  schema: a?.schema,
23
25
  web: a?.web,
@@ -5,11 +5,10 @@ export interface SettingsFieldInfo {
5
5
  key: string;
6
6
  kind: string;
7
7
  label?: string;
8
- required: boolean;
9
8
  options?: string[];
10
9
  }
11
10
  export declare function describeSettingsFields(fields: LayoutEl[]): SettingsFieldInfo[];
12
- export declare function buildSettingsBody(groupId: string, fields: LayoutEl[], incoming: Record<string, unknown>, existing: Record<string, unknown>, label?: string): Record<string, unknown>;
11
+ export declare function buildSettingsBody(groupId: string, fields: LayoutEl[], incoming: Record<string, unknown>, existing: Record<string, unknown>, label: string): Record<string, unknown>;
13
12
  export declare function writePluginSettings(em: EntityManager, groupId: string, incoming: Record<string, unknown>, actor: string, pluginsOverride?: PluginManifest[]): Promise<Record<string, unknown>>;
14
13
  export declare function listSettings(pluginsOverride?: PluginManifest[]): Promise<{
15
14
  group: string;
@@ -9,11 +9,10 @@ export function describeSettingsFields(fields) {
9
9
  key,
10
10
  kind: f.kind,
11
11
  label: f.label,
12
- required: f.required === true,
13
12
  ...(f.options ? { options: f.options.map((o) => o.value) } : {}),
14
13
  }));
15
14
  }
16
- function settingsShelf(groupId, fields, label = `${groupId}.plugin.label`) {
15
+ function settingsShelf(groupId, fields, label) {
17
16
  return { library: '_settings', shelf: groupId, label, fields };
18
17
  }
19
18
  export function buildSettingsBody(groupId, fields, incoming, existing, label) {
package/dist/temporal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { fieldMap } from '@coffer-org/sdk/shelf';
1
+ import { fieldEntries, storageColumns } from '@coffer-org/sdk/shelf';
2
2
  export function dtStringToDate(s) {
3
3
  return new Date(`${s}:00Z`);
4
4
  }
@@ -8,8 +8,13 @@ export function dateToDtString(d) {
8
8
  `T${p(d.getUTCHours())}:${p(d.getUTCMinutes())}`);
9
9
  }
10
10
  function datetimeKeysAt(fields) {
11
- const fm = fieldMap(fields);
12
- return Object.keys(fm).filter((k) => fm[k]?.column === 'datetime');
11
+ const out = [];
12
+ for (const [key, fm] of fieldEntries(fields)) {
13
+ for (const [col, type] of storageColumns(key, fm))
14
+ if (type === 'datetime')
15
+ out.push(col);
16
+ }
17
+ return out;
13
18
  }
14
19
  export function encodeTemporalAt(fields, row) {
15
20
  const out = { ...row };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffer-org/server",
3
- "version": "7.3.0",
3
+ "version": "7.4.0",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=24"
@@ -40,7 +40,7 @@
40
40
  "postpack": "node ../../scripts/swap-exports.mjs src"
41
41
  },
42
42
  "dependencies": {
43
- "@coffer-org/sdk": "^7.3.0",
43
+ "@coffer-org/sdk": "^7.4.0",
44
44
  "@extractus/oembed-extractor": "^4.1.0",
45
45
  "@fastify/cors": "^11.2.0",
46
46
  "@fastify/multipart": "^10.0.0",