@pithy-sh/support 0.5.1 → 0.6.1
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/README.md +8 -0
- package/dist/audit/actions.d.ts +9 -0
- package/dist/audit/actions.d.ts.map +1 -1
- package/dist/audit/actions.js +9 -0
- package/dist/capability.d.ts +2 -1
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +30 -6
- package/dist/config/config.d.ts +63 -2
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +63 -5
- package/dist/data/assignment.d.ts +43 -0
- package/dist/data/assignment.d.ts.map +1 -0
- package/dist/data/assignment.js +38 -0
- package/dist/data/embedding.d.ts +21 -0
- package/dist/data/embedding.d.ts.map +1 -0
- package/dist/data/embedding.js +23 -0
- package/dist/data/tables.d.ts +28 -0
- package/dist/data/tables.d.ts.map +1 -1
- package/dist/data/tables.js +10 -2
- package/dist/data/thread.d.ts +9 -4
- package/dist/data/thread.d.ts.map +1 -1
- package/dist/data/thread.js +9 -4
- package/dist/http/guards.d.ts +32 -14
- package/dist/http/guards.d.ts.map +1 -1
- package/dist/http/guards.js +44 -16
- package/dist/http/handlers.d.ts +35 -2
- package/dist/http/handlers.d.ts.map +1 -1
- package/dist/http/handlers.js +81 -8
- package/dist/http/resolve.d.ts +8 -0
- package/dist/http/resolve.d.ts.map +1 -1
- package/dist/http/resolve.js +20 -1
- package/dist/http/responses.d.ts +355 -0
- package/dist/http/responses.d.ts.map +1 -1
- package/dist/http/responses.js +64 -2
- package/dist/http/routes.d.ts +25 -11
- package/dist/http/routes.d.ts.map +1 -1
- package/dist/http/routes.js +34 -5
- package/dist/http/schemas.d.ts +67 -3
- package/dist/http/schemas.d.ts.map +1 -1
- package/dist/http/schemas.js +44 -5
- package/dist/http/scopes.d.ts +10 -5
- package/dist/http/scopes.d.ts.map +1 -1
- package/dist/http/scopes.js +42 -6
- package/dist/http/views.d.ts +9 -1
- package/dist/http/views.d.ts.map +1 -1
- package/dist/http/views.js +40 -1
- package/dist/inbound/ingest.d.ts +1 -1
- package/dist/inbound/ingest.d.ts.map +1 -1
- package/dist/inbound/ingest.js +3 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/migrations/0002_assignment.d.ts +20 -0
- package/dist/migrations/0002_assignment.d.ts.map +1 -0
- package/dist/migrations/0002_assignment.js +45 -0
- package/dist/migrations/0003_embeddings.d.ts +15 -0
- package/dist/migrations/0003_embeddings.d.ts.map +1 -0
- package/dist/migrations/0003_embeddings.js +23 -0
- package/dist/migrations/set.d.ts +13 -0
- package/dist/migrations/set.d.ts.map +1 -0
- package/dist/migrations/set.js +21 -0
- package/dist/presence/room.d.ts +35 -0
- package/dist/presence/room.d.ts.map +1 -0
- package/dist/presence/room.js +66 -0
- package/dist/provision/provisionSupport.d.ts +32 -0
- package/dist/provision/provisionSupport.d.ts.map +1 -1
- package/dist/provision/provisionSupport.js +10 -2
- package/dist/provision/resolveSupportConfig.d.ts.map +1 -1
- package/dist/provision/resolveSupportConfig.js +13 -2
- package/dist/purge/contribution.d.ts +49 -0
- package/dist/purge/contribution.d.ts.map +1 -0
- package/dist/purge/contribution.js +164 -0
- package/dist/secret/registry.d.ts +26 -2
- package/dist/secret/registry.d.ts.map +1 -1
- package/dist/secret/registry.js +15 -3
- package/dist/semantic/documents.d.ts +21 -0
- package/dist/semantic/documents.d.ts.map +1 -0
- package/dist/semantic/documents.js +128 -0
- package/dist/semantic/embed.d.ts +59 -0
- package/dist/semantic/embed.d.ts.map +1 -0
- package/dist/semantic/embed.js +59 -0
- package/dist/semantic/messageIndex.d.ts +46 -0
- package/dist/semantic/messageIndex.d.ts.map +1 -0
- package/dist/semantic/messageIndex.js +67 -0
- package/dist/semantic/query.d.ts +37 -0
- package/dist/semantic/query.d.ts.map +1 -0
- package/dist/semantic/query.js +46 -0
- package/dist/staff/staff.d.ts +22 -0
- package/dist/staff/staff.d.ts.map +1 -0
- package/dist/staff/staff.js +64 -0
- package/dist/store/assignment.d.ts +63 -0
- package/dist/store/assignment.d.ts.map +1 -0
- package/dist/store/assignment.js +86 -0
- package/dist/store/hybrid.d.ts +134 -0
- package/dist/store/hybrid.d.ts.map +1 -0
- package/dist/store/hybrid.js +185 -0
- package/dist/store/paging.d.ts +10 -0
- package/dist/store/paging.d.ts.map +1 -1
- package/dist/store/paging.js +11 -1
- package/dist/store/provisionIndex.d.ts +21 -0
- package/dist/store/provisionIndex.d.ts.map +1 -0
- package/dist/store/provisionIndex.js +36 -0
- package/dist/store/search.d.ts +18 -9
- package/dist/store/search.d.ts.map +1 -1
- package/dist/store/search.js +36 -34
- package/dist/store/searchIndex.d.ts +4 -4
- package/dist/store/searchIndex.js +4 -4
- package/dist/store/threads.d.ts +174 -8
- package/dist/store/threads.d.ts.map +1 -1
- package/dist/store/threads.js +33 -40
- package/dist/submission/submit.d.ts +1 -1
- package/dist/submission/submit.d.ts.map +1 -1
- package/dist/submission/submit.js +2 -1
- package/dist/test-utils/seed.d.ts +33 -0
- package/dist/test-utils/seed.d.ts.map +1 -0
- package/dist/test-utils/seed.js +102 -0
- package/dist/test-utils/semantic.d.ts +21 -0
- package/dist/test-utils/semantic.d.ts.map +1 -0
- package/dist/test-utils/semantic.js +107 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/workflows/specs.d.ts +23 -0
- package/dist/workflows/specs.d.ts.map +1 -1
- package/dist/workflows/specs.js +27 -7
- package/dist/workflows/worker.d.ts +15 -2
- package/dist/workflows/worker.d.ts.map +1 -1
- package/dist/workflows/worker.js +48 -4
- package/package.json +9 -7
- package/pithy.manifest.json +21 -3
- package/src/audit/actions.ts +9 -0
- package/src/capability.ts +43 -4
- package/src/config/config.ts +104 -5
- package/src/data/assignment.ts +55 -0
- package/src/data/embedding.ts +27 -0
- package/src/data/tables.ts +8 -0
- package/src/data/thread.ts +26 -4
- package/src/http/guards.ts +52 -15
- package/src/http/handlers.ts +125 -4
- package/src/http/resolve.ts +19 -0
- package/src/http/responses.ts +154 -0
- package/src/http/routes.ts +98 -12
- package/src/http/schemas.ts +117 -28
- package/src/http/scopes.ts +43 -6
- package/src/http/views.ts +44 -0
- package/src/inbound/ingest.ts +5 -2
- package/src/index.ts +5 -0
- package/src/migrations/0002_assignment.ts +65 -0
- package/src/migrations/0003_embeddings.ts +29 -0
- package/src/migrations/set.ts +21 -0
- package/src/presence/room.ts +94 -0
- package/src/provision/provisionSupport.ts +33 -1
- package/src/provision/resolveSupportConfig.ts +24 -13
- package/src/purge/contribution.ts +294 -0
- package/src/secret/registry.ts +17 -2
- package/src/semantic/documents.ts +178 -0
- package/src/semantic/embed.ts +99 -0
- package/src/semantic/messageIndex.ts +74 -0
- package/src/semantic/query.ts +66 -0
- package/src/staff/staff.ts +128 -0
- package/src/store/assignment.ts +179 -0
- package/src/store/hybrid.ts +314 -0
- package/src/store/paging.ts +14 -0
- package/src/store/provisionIndex.ts +46 -0
- package/src/store/search.ts +58 -37
- package/src/store/searchIndex.ts +4 -4
- package/src/store/threads.ts +91 -91
- package/src/submission/submit.ts +3 -2
- package/src/test-utils/seed.ts +141 -0
- package/src/test-utils/semantic.ts +110 -0
- package/src/version.generated.ts +1 -1
- package/src/workflows/specs.ts +34 -0
- package/src/workflows/worker.ts +84 -8
- package/src/workflows/wrangler.jsonc +8 -3
package/src/workflows/worker.ts
CHANGED
|
@@ -4,15 +4,23 @@
|
|
|
4
4
|
import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from "cloudflare:workers";
|
|
5
5
|
import { NonRetryableError } from "cloudflare:workflows";
|
|
6
6
|
import type { D1Database } from "@cloudflare/workers-types";
|
|
7
|
+
import { pithyCommandOf } from "@pithy-sh/core/src/cli/command";
|
|
8
|
+
import { createWorkerLogger } from "@pithy-sh/core/src/logger/worker";
|
|
7
9
|
import { classifiedSteps } from "@pithy-sh/core/src/workflow/faults";
|
|
8
10
|
import { workflowHostEntry } from "@pithy-sh/core/src/workflow/hostEntry";
|
|
11
|
+
import type { VectorAi } from "@pithy-sh/vector/src/embed/embed";
|
|
12
|
+
import type { VectorStore } from "@pithy-sh/vector/src/index/index";
|
|
13
|
+
import { type ReprocessReport, reprocessIndex } from "@pithy-sh/vector/src/workflows/reprocess";
|
|
9
14
|
import type { SupportAi } from "../ai/classify";
|
|
10
15
|
import { SupportConfig } from "../config/config";
|
|
11
16
|
import { resolveCategories } from "../data/categories";
|
|
12
17
|
import { supportDatabase } from "../data/tables";
|
|
18
|
+
import { supportMessageDocuments } from "../semantic/documents";
|
|
19
|
+
import { runEmbedding } from "../semantic/embed";
|
|
20
|
+
import { supportMessageIndex } from "../semantic/messageIndex";
|
|
13
21
|
import { runClassification } from "./classify";
|
|
14
22
|
import { supportWorkflowRetry } from "./retryPolicy";
|
|
15
|
-
import { SUPPORT_CAPABILITY } from "./specs";
|
|
23
|
+
import { SUPPORT_CAPABILITY, SupportReprocessParams } from "./specs";
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
26
|
* The prebuilt support worker. `pithy support provision` deploys one per environment; the adopter
|
|
@@ -35,20 +43,27 @@ import { SUPPORT_CAPABILITY } from "./specs";
|
|
|
35
43
|
* `@pithy-sh/core/src/workflow/hostEntry`.
|
|
36
44
|
*/
|
|
37
45
|
|
|
38
|
-
/** The support worker's env: the app database, the AI binding, and the serialized config. */
|
|
46
|
+
/** The support worker's env: the app database, the AI binding, the message index, and the serialized config. */
|
|
39
47
|
export interface SupportWorkerEnv {
|
|
40
48
|
/** The app database the support tables live in. */
|
|
41
49
|
DB: D1Database;
|
|
42
|
-
/** The Workers AI binding. */
|
|
50
|
+
/** The Workers AI binding — classification and embedding both run on it. */
|
|
43
51
|
AI: SupportAi;
|
|
52
|
+
/** The semantic message index. Bound only when `search.semantic` is on. */
|
|
53
|
+
SUPPORT_VECTORIZE?: VectorStore;
|
|
44
54
|
/** The resolved support config as a JSON string, filled at provision. */
|
|
45
55
|
SUPPORT_CONFIG?: string;
|
|
46
56
|
}
|
|
47
57
|
|
|
58
|
+
/** Parse the config this worker was deployed with. Absent falls back to the defaults. */
|
|
59
|
+
function workerConfig(env: SupportWorkerEnv): SupportConfig {
|
|
60
|
+
return SupportConfig.parse(env.SUPPORT_CONFIG ? JSON.parse(env.SUPPORT_CONFIG) : {});
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
/** Classify one stored message and write the result. */
|
|
49
64
|
export class SupportClassifyWorkflow extends WorkflowEntrypoint<SupportWorkerEnv, { messageId: string }> {
|
|
50
65
|
override async run(event: WorkflowEvent<{ messageId: string }>, step: WorkflowStep): Promise<void> {
|
|
51
|
-
const config =
|
|
66
|
+
const config = workerConfig(this.env);
|
|
52
67
|
const deps = {
|
|
53
68
|
db: supportDatabase(this.env.DB),
|
|
54
69
|
ai: this.env.AI,
|
|
@@ -65,10 +80,71 @@ export class SupportClassifyWorkflow extends WorkflowEntrypoint<SupportWorkerEnv
|
|
|
65
80
|
// Under `supportWorkflowRetry`: a model that could not be reached re-drives, and everything else
|
|
66
81
|
// fails at once. `classifyMessage` already refuses to throw on a bad *answer*, so the only fault
|
|
67
82
|
// that reaches this classifier as retryable is the binding not answering. See `retryPolicy.ts`.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
if (config.ai.enabled) {
|
|
84
|
+
await classifiedSteps(step, supportWorkflowRetry, NonRetryableError).do(
|
|
85
|
+
`classify-${event.payload.messageId}`,
|
|
86
|
+
async () => {
|
|
87
|
+
await runClassification(deps, event.payload.messageId);
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Then the message index, when semantic search is on. Its own step, after the classification, and
|
|
93
|
+
// never fatal: `runEmbedding` reports a failure rather than throwing it, so the message stays stored and
|
|
94
|
+
// classified and is missing from semantic results only, until a reprocess picks it up.
|
|
95
|
+
const index = supportMessageIndex(config.search);
|
|
96
|
+
if (index) {
|
|
97
|
+
// Through the classifier like every step, though `runEmbedding` reports a failure rather than throwing one.
|
|
98
|
+
await classifiedSteps(step, supportWorkflowRetry, NonRetryableError).do(`embed-${event.payload.messageId}`, () =>
|
|
99
|
+
runEmbedding(
|
|
100
|
+
{
|
|
101
|
+
db: deps.db,
|
|
102
|
+
ai: this.env.AI as unknown as VectorAi,
|
|
103
|
+
store: this.env.SUPPORT_VECTORIZE,
|
|
104
|
+
index,
|
|
105
|
+
now: () => new Date(),
|
|
106
|
+
log: createWorkerLogger({ name: `${SUPPORT_CAPABILITY}:embed` }),
|
|
107
|
+
},
|
|
108
|
+
event.payload.messageId,
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Re-embed the semantic message index — `@pithy-sh/vector`'s own reprocess orchestration, over support's
|
|
117
|
+
* `DocumentStore`, one journalled page per step. `pithy vector reprocess --index support-messages` starts it,
|
|
118
|
+
* and so does `pithy support provision` once, to backfill an index it just created.
|
|
119
|
+
*/
|
|
120
|
+
export class SupportReprocessWorkflow extends WorkflowEntrypoint<SupportWorkerEnv, SupportReprocessParams> {
|
|
121
|
+
override async run(event: WorkflowEvent<SupportReprocessParams>, step: WorkflowStep): Promise<ReprocessReport> {
|
|
122
|
+
const params = SupportReprocessParams.parse(event.payload);
|
|
123
|
+
const index = supportMessageIndex(workerConfig(this.env).search);
|
|
124
|
+
if (!index) {
|
|
125
|
+
throw new NonRetryableError(
|
|
126
|
+
"support/reprocess: search.semantic is off in this worker's config, so there is no message index to re-embed",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const store = this.env.SUPPORT_VECTORIZE;
|
|
130
|
+
if (!store) {
|
|
131
|
+
throw new NonRetryableError(
|
|
132
|
+
`support/reprocess: the SUPPORT_VECTORIZE binding is absent; run \`${pithyCommandOf("support provision", {}, { runtime: true })}\` to bind the index`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return reprocessIndex(
|
|
136
|
+
{
|
|
137
|
+
documents: supportMessageDocuments(supportDatabase(this.env.DB), { store }),
|
|
138
|
+
store,
|
|
139
|
+
ai: this.env.AI as unknown as VectorAi,
|
|
140
|
+
index,
|
|
141
|
+
indexName: params.index,
|
|
142
|
+
now: () => new Date(),
|
|
143
|
+
},
|
|
144
|
+
classifiedSteps(step, supportWorkflowRetry, NonRetryableError),
|
|
145
|
+
{
|
|
146
|
+
...(params.all !== undefined ? { all: params.all } : {}),
|
|
147
|
+
...(params.pageSize !== undefined ? { pageSize: params.pageSize } : {}),
|
|
72
148
|
},
|
|
73
149
|
);
|
|
74
150
|
}
|
|
@@ -30,10 +30,15 @@
|
|
|
30
30
|
// and their customers' support mail never leaves their account.
|
|
31
31
|
"ai": { "binding": "AI" },
|
|
32
32
|
|
|
33
|
-
// The
|
|
34
|
-
//
|
|
33
|
+
// The Workflows this worker hosts. `class_name` matches the exported WorkflowEntrypoint subclass;
|
|
34
|
+
// `SUPPORT_CLASSIFY` is what the app worker dispatches to after storing a message, and `SUPPORT_REPROCESS`
|
|
35
|
+
// re-embeds the semantic message index when `pithy vector reprocess --index support-messages` starts it.
|
|
36
|
+
// When `search.semantic` is on, provisioning adds a `vectorize` entry binding `SUPPORT_VECTORIZE` to this
|
|
37
|
+
// environment's `<project>-<env>-support-messages` index; the template carries none, because most inboxes
|
|
38
|
+
// have no index.
|
|
35
39
|
"workflows": [
|
|
36
|
-
{ "binding": "SUPPORT_CLASSIFY", "name": "pithy-support-classify", "class_name": "SupportClassifyWorkflow" }
|
|
40
|
+
{ "binding": "SUPPORT_CLASSIFY", "name": "pithy-support-classify", "class_name": "SupportClassifyWorkflow" },
|
|
41
|
+
{ "binding": "SUPPORT_REPROCESS", "name": "pithy-support-reprocess", "class_name": "SupportReprocessWorkflow" }
|
|
37
42
|
],
|
|
38
43
|
|
|
39
44
|
"vars": {
|