@hexis-ai/engram-server 0.13.0 → 0.14.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/dist/adapters/memory-key-store.d.ts +9 -0
- package/dist/adapters/memory-key-store.js +15 -0
- package/dist/adapters/memory.js +6 -0
- package/dist/adapters/postgres-key-store.d.ts +1 -0
- package/dist/adapters/postgres-key-store.js +7 -2
- package/dist/adapters/postgres-org-store.d.ts +0 -1
- package/dist/adapters/postgres-org-store.js +2 -3
- package/dist/adapters/postgres.js +19 -3
- package/dist/admin.js +3 -3
- package/dist/key-store.d.ts +8 -0
- package/dist/migrations/0008-trigger-metadata.d.ts +2 -0
- package/dist/migrations/0008-trigger-metadata.js +15 -0
- package/dist/migrations/index.js +2 -0
- package/dist/org-store.d.ts +0 -6
- package/dist/schemas.d.ts +4 -0
- package/dist/schemas.js +4 -0
- package/dist/services/orgs.d.ts +10 -6
- package/dist/services/orgs.js +11 -7
- package/dist/storage.d.ts +2 -0
- package/dist/storage.js +6 -0
- package/openapi.json +40 -0
- package/package.json +3 -3
|
@@ -6,11 +6,20 @@ export declare class InMemoryKeyStore implements KeyStore {
|
|
|
6
6
|
private readonly workspaces;
|
|
7
7
|
private readonly keys;
|
|
8
8
|
private readonly byHash;
|
|
9
|
+
/** Mirror of engram_workspaces.org_id. Lookup-only — fakes / org-stores
|
|
10
|
+
* in tests read this to answer membership queries without re-tracking
|
|
11
|
+
* the binding themselves. */
|
|
12
|
+
private readonly orgIds;
|
|
9
13
|
createWorkspace(input: {
|
|
10
14
|
id?: string;
|
|
11
15
|
name?: string;
|
|
12
16
|
metadata?: Record<string, unknown>;
|
|
17
|
+
orgId?: string;
|
|
13
18
|
}): Promise<Workspace>;
|
|
19
|
+
/** Org id stamped on a workspace at creation, or undefined if not org-scoped. */
|
|
20
|
+
getWorkspaceOrgId(workspaceId: string): string | undefined;
|
|
21
|
+
/** All (workspaceId, orgId) pairs. Read-only view for fakes. */
|
|
22
|
+
workspaceOrgBindings(): ReadonlyMap<string, string>;
|
|
14
23
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
15
24
|
listWorkspaces(): Promise<Workspace[]>;
|
|
16
25
|
updateWorkspace(id: string, patch: {
|
|
@@ -6,6 +6,10 @@ export class InMemoryKeyStore {
|
|
|
6
6
|
workspaces = new Map();
|
|
7
7
|
keys = new Map();
|
|
8
8
|
byHash = new Map();
|
|
9
|
+
/** Mirror of engram_workspaces.org_id. Lookup-only — fakes / org-stores
|
|
10
|
+
* in tests read this to answer membership queries without re-tracking
|
|
11
|
+
* the binding themselves. */
|
|
12
|
+
orgIds = new Map();
|
|
9
13
|
async createWorkspace(input) {
|
|
10
14
|
const id = resolveWorkspaceId(input);
|
|
11
15
|
const existing = this.workspaces.get(id);
|
|
@@ -18,8 +22,18 @@ export class InMemoryKeyStore {
|
|
|
18
22
|
createdAt: new Date().toISOString(),
|
|
19
23
|
};
|
|
20
24
|
this.workspaces.set(id, ws);
|
|
25
|
+
if (input.orgId !== undefined)
|
|
26
|
+
this.orgIds.set(id, input.orgId);
|
|
21
27
|
return ws;
|
|
22
28
|
}
|
|
29
|
+
/** Org id stamped on a workspace at creation, or undefined if not org-scoped. */
|
|
30
|
+
getWorkspaceOrgId(workspaceId) {
|
|
31
|
+
return this.orgIds.get(workspaceId);
|
|
32
|
+
}
|
|
33
|
+
/** All (workspaceId, orgId) pairs. Read-only view for fakes. */
|
|
34
|
+
workspaceOrgBindings() {
|
|
35
|
+
return this.orgIds;
|
|
36
|
+
}
|
|
23
37
|
async getWorkspace(id) {
|
|
24
38
|
return this.workspaces.get(id) ?? null;
|
|
25
39
|
}
|
|
@@ -40,6 +54,7 @@ export class InMemoryKeyStore {
|
|
|
40
54
|
}
|
|
41
55
|
async deleteWorkspace(id) {
|
|
42
56
|
this.workspaces.delete(id);
|
|
57
|
+
this.orgIds.delete(id);
|
|
43
58
|
for (const [keyId, row] of this.keys) {
|
|
44
59
|
if (row.workspaceId === id) {
|
|
45
60
|
this.byHash.delete(row.keyHash);
|
package/dist/adapters/memory.js
CHANGED
|
@@ -42,6 +42,12 @@ export class InMemoryAdapter {
|
|
|
42
42
|
...(init.trigger_event_id != null
|
|
43
43
|
? { trigger_event_id: init.trigger_event_id }
|
|
44
44
|
: {}),
|
|
45
|
+
...(init.trigger_purpose != null
|
|
46
|
+
? { trigger_purpose: init.trigger_purpose }
|
|
47
|
+
: {}),
|
|
48
|
+
...(init.trigger_resume_hint != null
|
|
49
|
+
? { trigger_resume_hint: init.trigger_resume_hint }
|
|
50
|
+
: {}),
|
|
45
51
|
},
|
|
46
52
|
events: new Map(),
|
|
47
53
|
});
|
|
@@ -12,6 +12,7 @@ export declare class PostgresKeyStore implements KeyStore {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
name?: string;
|
|
14
14
|
metadata?: Record<string, unknown>;
|
|
15
|
+
orgId?: string;
|
|
15
16
|
}): Promise<Workspace>;
|
|
16
17
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
17
18
|
listWorkspaces(): Promise<Workspace[]>;
|
|
@@ -16,8 +16,13 @@ export class PostgresKeyStore {
|
|
|
16
16
|
async createWorkspace(input) {
|
|
17
17
|
const id = resolveWorkspaceId(input);
|
|
18
18
|
await this.sql `
|
|
19
|
-
INSERT INTO engram_workspaces (id, name, metadata)
|
|
20
|
-
VALUES (
|
|
19
|
+
INSERT INTO engram_workspaces (id, name, metadata, org_id)
|
|
20
|
+
VALUES (
|
|
21
|
+
${id},
|
|
22
|
+
${input.name ?? null},
|
|
23
|
+
${(input.metadata ?? {})},
|
|
24
|
+
${input.orgId ?? null}
|
|
25
|
+
)
|
|
21
26
|
ON CONFLICT (id) DO NOTHING
|
|
22
27
|
`;
|
|
23
28
|
const ws = await this.getWorkspace(id);
|
|
@@ -27,7 +27,6 @@ export declare class PostgresOrgStore implements OrgStore {
|
|
|
27
27
|
email: string;
|
|
28
28
|
} | null>;
|
|
29
29
|
listOrgsForUser(userId: string): Promise<OrgMembershipRow[]>;
|
|
30
|
-
setWorkspaceOrg(workspaceId: string, orgId: string): Promise<void>;
|
|
31
30
|
listWorkspacesForOrg(orgId: string): Promise<{
|
|
32
31
|
id: string;
|
|
33
32
|
name: string | null;
|
|
@@ -89,9 +89,8 @@ export class PostgresOrgStore {
|
|
|
89
89
|
return rows.map(toMember);
|
|
90
90
|
}
|
|
91
91
|
// ---------- workspace ↔ org link -----------------------------
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
92
|
+
// engram_workspaces.org_id is written by KeyStore.createWorkspace in
|
|
93
|
+
// the same INSERT as the workspace row. This store only reads.
|
|
95
94
|
async listWorkspacesForOrg(orgId) {
|
|
96
95
|
const { rows } = await this.pool.query(`SELECT id, name FROM engram_workspaces WHERE org_id = $1 ORDER BY created_at`, [orgId]);
|
|
97
96
|
return rows;
|
|
@@ -31,7 +31,8 @@ export class PostgresAdapter {
|
|
|
31
31
|
INSERT INTO engram_sessions (
|
|
32
32
|
workspace_id, id, title, channel, participants, viewable_by,
|
|
33
33
|
created_at, updated_at, status, summary, model,
|
|
34
|
-
trigger_conversation_id, trigger_event_id
|
|
34
|
+
trigger_conversation_id, trigger_event_id,
|
|
35
|
+
trigger_purpose, trigger_resume_hint
|
|
35
36
|
)
|
|
36
37
|
VALUES (
|
|
37
38
|
${this.workspaceId},
|
|
@@ -46,7 +47,9 @@ export class PostgresAdapter {
|
|
|
46
47
|
${init.summary ?? null},
|
|
47
48
|
${init.model ?? null},
|
|
48
49
|
${init.trigger_conversation_id ?? null},
|
|
49
|
-
${init.trigger_event_id ?? null}
|
|
50
|
+
${init.trigger_event_id ?? null},
|
|
51
|
+
${init.trigger_purpose ?? null},
|
|
52
|
+
${init.trigger_resume_hint ?? null}
|
|
50
53
|
)
|
|
51
54
|
ON CONFLICT (workspace_id, id) DO NOTHING
|
|
52
55
|
`;
|
|
@@ -97,7 +100,8 @@ export class PostgresAdapter {
|
|
|
97
100
|
const rows = await this.sql `
|
|
98
101
|
SELECT id, title, channel, participants, viewable_by, created_at,
|
|
99
102
|
updated_at, status, summary, model,
|
|
100
|
-
trigger_conversation_id, trigger_event_id
|
|
103
|
+
trigger_conversation_id, trigger_event_id,
|
|
104
|
+
trigger_purpose, trigger_resume_hint
|
|
101
105
|
FROM engram_sessions
|
|
102
106
|
WHERE workspace_id = ${this.workspaceId} AND id = ${sessionId}
|
|
103
107
|
LIMIT 1
|
|
@@ -122,6 +126,8 @@ export class PostgresAdapter {
|
|
|
122
126
|
const model = pickPatch(patch, "model");
|
|
123
127
|
const tcId = pickPatch(patch, "trigger_conversation_id");
|
|
124
128
|
const teId = pickPatch(patch, "trigger_event_id");
|
|
129
|
+
const tPurpose = pickPatch(patch, "trigger_purpose");
|
|
130
|
+
const tResume = pickPatch(patch, "trigger_resume_hint");
|
|
125
131
|
const rows = await this.sql `
|
|
126
132
|
UPDATE engram_sessions SET
|
|
127
133
|
title = CASE WHEN ${title.provided} THEN ${title.value} ELSE title END,
|
|
@@ -133,6 +139,10 @@ export class PostgresAdapter {
|
|
|
133
139
|
THEN ${tcId.value} ELSE trigger_conversation_id END,
|
|
134
140
|
trigger_event_id = CASE WHEN ${teId.provided}
|
|
135
141
|
THEN ${teId.value} ELSE trigger_event_id END,
|
|
142
|
+
trigger_purpose = CASE WHEN ${tPurpose.provided}
|
|
143
|
+
THEN ${tPurpose.value} ELSE trigger_purpose END,
|
|
144
|
+
trigger_resume_hint = CASE WHEN ${tResume.provided}
|
|
145
|
+
THEN ${tResume.value} ELSE trigger_resume_hint END,
|
|
136
146
|
updated_at = now()
|
|
137
147
|
WHERE workspace_id = ${this.workspaceId} AND id = ${sessionId}
|
|
138
148
|
RETURNING id
|
|
@@ -474,6 +484,12 @@ function toSessionRow(r) {
|
|
|
474
484
|
...(r.trigger_event_id !== null
|
|
475
485
|
? { trigger_event_id: r.trigger_event_id }
|
|
476
486
|
: {}),
|
|
487
|
+
...(r.trigger_purpose !== null
|
|
488
|
+
? { trigger_purpose: r.trigger_purpose }
|
|
489
|
+
: {}),
|
|
490
|
+
...(r.trigger_resume_hint !== null
|
|
491
|
+
? { trigger_resume_hint: r.trigger_resume_hint }
|
|
492
|
+
: {}),
|
|
477
493
|
};
|
|
478
494
|
}
|
|
479
495
|
function toAliasInfo(r) {
|
package/dist/admin.js
CHANGED
|
@@ -158,9 +158,9 @@ export function createAdminRouter(opts) {
|
|
|
158
158
|
return c.body(null, 204);
|
|
159
159
|
}));
|
|
160
160
|
// ----- org workspaces ---------------------------------------
|
|
161
|
-
// Stands up a tenant
|
|
162
|
-
//
|
|
163
|
-
//
|
|
161
|
+
// Stands up a tenant. createWorkspaceUnderOrg writes the workspace
|
|
162
|
+
// + org binding in a single INSERT (atomic) and then issues the
|
|
163
|
+
// initial API key (separate insert; retry-safe via ON CONFLICT).
|
|
164
164
|
app.post("/orgs/:id/workspaces", async (c) => runService(c, async () => {
|
|
165
165
|
const orgId = c.req.param("id");
|
|
166
166
|
await getOrgOrThrow(deps, orgId);
|
package/dist/key-store.d.ts
CHANGED
|
@@ -29,10 +29,18 @@ export interface KeyResolution {
|
|
|
29
29
|
keyId: string;
|
|
30
30
|
}
|
|
31
31
|
export interface KeyStore {
|
|
32
|
+
/**
|
|
33
|
+
* Persist a workspace row. `orgId`, when supplied, lands in the same
|
|
34
|
+
* INSERT so the workspace and its org binding are committed atomically
|
|
35
|
+
* (no orphaned workspace if a follow-up `setWorkspaceOrg` would have
|
|
36
|
+
* failed). Legacy callers without an org still work — `org_id` stays
|
|
37
|
+
* NULL.
|
|
38
|
+
*/
|
|
32
39
|
createWorkspace(input: {
|
|
33
40
|
id?: string;
|
|
34
41
|
name?: string;
|
|
35
42
|
metadata?: Record<string, unknown>;
|
|
43
|
+
orgId?: string;
|
|
36
44
|
}): Promise<Workspace>;
|
|
37
45
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
38
46
|
listWorkspaces(): Promise<Workspace[]>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const name = "0008-trigger-metadata";
|
|
2
|
+
export declare const sql = "\n-- Hosts that open a side-conversation with a stated goal (monet's\n-- start_conversation tool) need to thread two free-text fields through\n-- engram for the agent's resume flow:\n--\n-- trigger_purpose what this side-conv exists to accomplish\n-- trigger_resume_hint the condition that should resume the parent\n--\n-- Both are opaque to engram \u2014 we store and serve them verbatim. Nullable\n-- because most sessions aren't side-conversations.\n\nALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_purpose TEXT;\nALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_resume_hint TEXT;\n";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const name = "0008-trigger-metadata";
|
|
2
|
+
export const sql = `
|
|
3
|
+
-- Hosts that open a side-conversation with a stated goal (monet's
|
|
4
|
+
-- start_conversation tool) need to thread two free-text fields through
|
|
5
|
+
-- engram for the agent's resume flow:
|
|
6
|
+
--
|
|
7
|
+
-- trigger_purpose what this side-conv exists to accomplish
|
|
8
|
+
-- trigger_resume_hint the condition that should resume the parent
|
|
9
|
+
--
|
|
10
|
+
-- Both are opaque to engram — we store and serve them verbatim. Nullable
|
|
11
|
+
-- because most sessions aren't side-conversations.
|
|
12
|
+
|
|
13
|
+
ALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_purpose TEXT;
|
|
14
|
+
ALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_resume_hint TEXT;
|
|
15
|
+
`;
|
package/dist/migrations/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as m0004 from "./0004-schema-completion";
|
|
|
5
5
|
import * as m0005 from "./0005-session-updated-at";
|
|
6
6
|
import * as m0006 from "./0006-auth";
|
|
7
7
|
import * as m0007 from "./0007-orgs";
|
|
8
|
+
import * as m0008 from "./0008-trigger-metadata";
|
|
8
9
|
/**
|
|
9
10
|
* Schema migrations, applied in array order. Add a new file under
|
|
10
11
|
* `migrations/NNNN-<slug>.ts` exporting `name` and `sql`, then append it
|
|
@@ -20,4 +21,5 @@ export const MIGRATIONS = [
|
|
|
20
21
|
{ name: m0005.name, sql: m0005.sql },
|
|
21
22
|
{ name: m0006.name, sql: m0006.sql },
|
|
22
23
|
{ name: m0007.name, sql: m0007.sql },
|
|
24
|
+
{ name: m0008.name, sql: m0008.sql },
|
|
23
25
|
];
|
package/dist/org-store.d.ts
CHANGED
|
@@ -48,12 +48,6 @@ export interface OrgStore {
|
|
|
48
48
|
} | null>;
|
|
49
49
|
/** Orgs the given user is a member of. */
|
|
50
50
|
listOrgsForUser(userId: string): Promise<OrgMembershipRow[]>;
|
|
51
|
-
/**
|
|
52
|
-
* Set the org an already-existing workspace belongs to. Called
|
|
53
|
-
* by the admin endpoint that creates a workspace under an org
|
|
54
|
-
* (key issuance and engram_workspaces.org_id are written together).
|
|
55
|
-
*/
|
|
56
|
-
setWorkspaceOrg(workspaceId: string, orgId: string): Promise<void>;
|
|
57
51
|
/** Workspaces in the given org. */
|
|
58
52
|
listWorkspacesForOrg(orgId: string): Promise<{
|
|
59
53
|
id: string;
|
package/dist/schemas.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare const sessionInitSchema: z.ZodObject<{
|
|
|
24
24
|
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
25
|
trigger_conversation_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
26
26
|
trigger_event_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
|
+
trigger_purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
28
|
+
trigger_resume_hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
29
|
}, z.core.$strip>;
|
|
28
30
|
export declare const sessionUpdateSchema: z.ZodObject<{
|
|
29
31
|
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -37,6 +39,8 @@ export declare const sessionUpdateSchema: z.ZodObject<{
|
|
|
37
39
|
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
38
40
|
trigger_conversation_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
41
|
trigger_event_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
42
|
+
trigger_purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
43
|
+
trigger_resume_hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
44
|
}, z.core.$strip>;
|
|
41
45
|
export declare const sessionEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
42
46
|
type: z.ZodLiteral<"step">;
|
package/dist/schemas.js
CHANGED
|
@@ -20,6 +20,8 @@ export const sessionInitSchema = z.object({
|
|
|
20
20
|
model: z.string().nullable().optional(),
|
|
21
21
|
trigger_conversation_id: z.string().nullable().optional(),
|
|
22
22
|
trigger_event_id: z.string().nullable().optional(),
|
|
23
|
+
trigger_purpose: z.string().nullable().optional(),
|
|
24
|
+
trigger_resume_hint: z.string().nullable().optional(),
|
|
23
25
|
});
|
|
24
26
|
export const sessionUpdateSchema = z.object({
|
|
25
27
|
title: z.string().nullable().optional(),
|
|
@@ -29,6 +31,8 @@ export const sessionUpdateSchema = z.object({
|
|
|
29
31
|
model: z.string().nullable().optional(),
|
|
30
32
|
trigger_conversation_id: z.string().nullable().optional(),
|
|
31
33
|
trigger_event_id: z.string().nullable().optional(),
|
|
34
|
+
trigger_purpose: z.string().nullable().optional(),
|
|
35
|
+
trigger_resume_hint: z.string().nullable().optional(),
|
|
32
36
|
});
|
|
33
37
|
const stepEventSchema = z.object({
|
|
34
38
|
type: z.literal("step"),
|
package/dist/services/orgs.d.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* (`/admin/v1/*`) and the cookie-auth self-service surface (`/v1/orgs/*`).
|
|
4
4
|
*
|
|
5
5
|
* Auth and HTTP framing stay in the route modules. This file owns:
|
|
6
|
-
* - the multi-step orchestrations (
|
|
7
|
-
* +
|
|
6
|
+
* - the multi-step orchestrations (createWorkspaceUnderOrg writes
|
|
7
|
+
* the workspace + org binding atomically and then issues a key;
|
|
8
|
+
* email→userId lookup + upsertMember)
|
|
8
9
|
* - the safety invariants (workspace id validation, last-owner
|
|
9
10
|
* protection on member removal)
|
|
10
11
|
* - the canonical error → status mapping (OrgServiceError.status)
|
|
@@ -70,12 +71,15 @@ export interface CreateWorkspaceResult {
|
|
|
70
71
|
key?: IssuedKey;
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
|
-
* Stand up a new workspace under an org
|
|
74
|
-
*
|
|
74
|
+
* Stand up a new workspace under an org. The workspace + org binding
|
|
75
|
+
* commit atomically because the KeyStore writes `org_id` in the same
|
|
76
|
+
* INSERT as the workspace row. Issuing the initial API key remains a
|
|
77
|
+
* follow-up call (idempotent — a retry of the workspace POST returns
|
|
78
|
+
* the existing row via ON CONFLICT DO NOTHING).
|
|
75
79
|
*
|
|
76
80
|
* Validates the workspace id shape up front so a bad id fails before
|
|
77
|
-
* touching
|
|
78
|
-
*
|
|
81
|
+
* touching the store. Returns the workspace with `orgId` stamped on so
|
|
82
|
+
* callers don't need a second lookup.
|
|
79
83
|
*/
|
|
80
84
|
export declare function createWorkspaceUnderOrg(deps: OrgServiceDeps, orgId: string, body: CreateWorkspaceInput): Promise<CreateWorkspaceResult>;
|
|
81
85
|
export declare function updateOrgWorkspace(deps: OrgServiceDeps, orgId: string, wsId: string, body: {
|
package/dist/services/orgs.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* (`/admin/v1/*`) and the cookie-auth self-service surface (`/v1/orgs/*`).
|
|
4
4
|
*
|
|
5
5
|
* Auth and HTTP framing stay in the route modules. This file owns:
|
|
6
|
-
* - the multi-step orchestrations (
|
|
7
|
-
* +
|
|
6
|
+
* - the multi-step orchestrations (createWorkspaceUnderOrg writes
|
|
7
|
+
* the workspace + org binding atomically and then issues a key;
|
|
8
|
+
* email→userId lookup + upsertMember)
|
|
8
9
|
* - the safety invariants (workspace id validation, last-owner
|
|
9
10
|
* protection on member removal)
|
|
10
11
|
* - the canonical error → status mapping (OrgServiceError.status)
|
|
@@ -92,12 +93,15 @@ export async function removeMember(deps, orgId, userId) {
|
|
|
92
93
|
await deps.orgStore.removeMember(orgId, userId);
|
|
93
94
|
}
|
|
94
95
|
/**
|
|
95
|
-
* Stand up a new workspace under an org
|
|
96
|
-
*
|
|
96
|
+
* Stand up a new workspace under an org. The workspace + org binding
|
|
97
|
+
* commit atomically because the KeyStore writes `org_id` in the same
|
|
98
|
+
* INSERT as the workspace row. Issuing the initial API key remains a
|
|
99
|
+
* follow-up call (idempotent — a retry of the workspace POST returns
|
|
100
|
+
* the existing row via ON CONFLICT DO NOTHING).
|
|
97
101
|
*
|
|
98
102
|
* Validates the workspace id shape up front so a bad id fails before
|
|
99
|
-
* touching
|
|
100
|
-
*
|
|
103
|
+
* touching the store. Returns the workspace with `orgId` stamped on so
|
|
104
|
+
* callers don't need a second lookup.
|
|
101
105
|
*/
|
|
102
106
|
export async function createWorkspaceUnderOrg(deps, orgId, body) {
|
|
103
107
|
if (body.id !== undefined && !isValidWorkspaceId(body.id)) {
|
|
@@ -108,8 +112,8 @@ export async function createWorkspaceUnderOrg(deps, orgId, body) {
|
|
|
108
112
|
...(body.id !== undefined ? { id: body.id } : {}),
|
|
109
113
|
...(body.name !== undefined ? { name: body.name } : {}),
|
|
110
114
|
...(body.metadata !== undefined ? { metadata: body.metadata } : {}),
|
|
115
|
+
orgId,
|
|
111
116
|
});
|
|
112
|
-
await deps.orgStore.setWorkspaceOrg(ws.id, orgId);
|
|
113
117
|
if (body.issueKey === false) {
|
|
114
118
|
return { workspace: { ...ws, orgId } };
|
|
115
119
|
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -147,6 +147,8 @@ export interface SessionRow {
|
|
|
147
147
|
model?: string;
|
|
148
148
|
trigger_conversation_id?: string;
|
|
149
149
|
trigger_event_id?: string;
|
|
150
|
+
trigger_purpose?: string;
|
|
151
|
+
trigger_resume_hint?: string;
|
|
150
152
|
}
|
|
151
153
|
export declare function foldEvents(row: SessionRow, events: SessionEvent[], now: Date): Session;
|
|
152
154
|
/**
|
package/dist/storage.js
CHANGED
|
@@ -35,6 +35,12 @@ export function foldEvents(row, events, now) {
|
|
|
35
35
|
...(row.trigger_event_id !== undefined
|
|
36
36
|
? { trigger_event_id: row.trigger_event_id }
|
|
37
37
|
: {}),
|
|
38
|
+
...(row.trigger_purpose !== undefined
|
|
39
|
+
? { trigger_purpose: row.trigger_purpose }
|
|
40
|
+
: {}),
|
|
41
|
+
...(row.trigger_resume_hint !== undefined
|
|
42
|
+
? { trigger_resume_hint: row.trigger_resume_hint }
|
|
43
|
+
: {}),
|
|
38
44
|
updated_at: row.updatedAt,
|
|
39
45
|
};
|
|
40
46
|
}
|
package/openapi.json
CHANGED
|
@@ -145,6 +145,26 @@
|
|
|
145
145
|
"type": "null"
|
|
146
146
|
}
|
|
147
147
|
]
|
|
148
|
+
},
|
|
149
|
+
"trigger_purpose": {
|
|
150
|
+
"anyOf": [
|
|
151
|
+
{
|
|
152
|
+
"type": "string"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"type": "null"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
"trigger_resume_hint": {
|
|
160
|
+
"anyOf": [
|
|
161
|
+
{
|
|
162
|
+
"type": "string"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"type": "null"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
148
168
|
}
|
|
149
169
|
},
|
|
150
170
|
"additionalProperties": false
|
|
@@ -219,6 +239,26 @@
|
|
|
219
239
|
"type": "null"
|
|
220
240
|
}
|
|
221
241
|
]
|
|
242
|
+
},
|
|
243
|
+
"trigger_purpose": {
|
|
244
|
+
"anyOf": [
|
|
245
|
+
{
|
|
246
|
+
"type": "string"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"type": "null"
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
},
|
|
253
|
+
"trigger_resume_hint": {
|
|
254
|
+
"anyOf": [
|
|
255
|
+
{
|
|
256
|
+
"type": "string"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"type": "null"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
222
262
|
}
|
|
223
263
|
},
|
|
224
264
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexis-ai/engram-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Engram server: ingest agent session events, persist via a pluggable adapter, expose search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"engram",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"dev": "bun --hot src/dev.ts"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@hexis-ai/engram-core": "^0.
|
|
53
|
-
"@hexis-ai/engram-sdk": "^0.
|
|
52
|
+
"@hexis-ai/engram-core": "^0.3.0",
|
|
53
|
+
"@hexis-ai/engram-sdk": "^0.15.0",
|
|
54
54
|
"better-auth": "^1.6.11",
|
|
55
55
|
"hono": "^4.6.0",
|
|
56
56
|
"pg": "^8.13.0",
|