@owlmeans/viable-common 0.0.24 → 0.0.26
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 +4 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/agent-presentation/SKILL.md +1 -1
- package/agent-meta/skills/viable-common/SKILL.md +115 -13
- package/build/blueprint/case.d.ts.map +1 -1
- package/build/blueprint/case.js +58 -16
- package/build/blueprint/case.js.map +1 -1
- package/build/blueprint/resolve.d.ts.map +1 -1
- package/build/blueprint/resolve.js +3 -0
- package/build/blueprint/resolve.js.map +1 -1
- package/build/blueprint/types.d.ts +44 -2
- package/build/blueprint/types.d.ts.map +1 -1
- package/build/blueprint/types.js +35 -1
- package/build/blueprint/types.js.map +1 -1
- package/build/branding.d.ts +5 -1
- package/build/branding.d.ts.map +1 -1
- package/build/branding.js +6 -0
- package/build/branding.js.map +1 -1
- package/build/connect/consts.d.ts +31 -43
- package/build/connect/consts.d.ts.map +1 -1
- package/build/connect/consts.js +34 -48
- package/build/connect/consts.js.map +1 -1
- package/build/connect/entrypoints.d.ts +36 -19
- package/build/connect/entrypoints.d.ts.map +1 -1
- package/build/connect/entrypoints.js +23 -4
- package/build/connect/entrypoints.js.map +1 -1
- package/build/connect/index.d.ts +0 -1
- package/build/connect/index.d.ts.map +1 -1
- package/build/connect/index.js +0 -1
- package/build/connect/index.js.map +1 -1
- package/build/connect/ops.d.ts +1 -4
- package/build/connect/ops.d.ts.map +1 -1
- package/build/connect/references.d.ts +33 -16
- package/build/connect/references.d.ts.map +1 -1
- package/build/connect/references.js +7 -1
- package/build/connect/references.js.map +1 -1
- package/build/connect/schemas.d.ts +17 -3
- package/build/connect/schemas.d.ts.map +1 -1
- package/build/connect/schemas.js +31 -5
- package/build/connect/schemas.js.map +1 -1
- package/build/connect/types.d.ts +63 -66
- package/build/connect/types.d.ts.map +1 -1
- package/build/consts.d.ts +1 -1
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +3 -0
- package/build/consts.js.map +1 -1
- package/build/design/runtime.d.ts +1 -1
- package/build/design/runtime.d.ts.map +1 -1
- package/build/metadata/types.d.ts +8 -0
- package/build/metadata/types.d.ts.map +1 -1
- package/build/metadata/types.js.map +1 -1
- package/build/planning/consts.d.ts +1 -1
- package/build/planning/consts.js +1 -1
- package/build/planning/helpers.d.ts +2 -1
- package/build/planning/helpers.d.ts.map +1 -1
- package/build/planning/helpers.js +5 -2
- package/build/planning/helpers.js.map +1 -1
- package/build/planning/index.d.ts +1 -0
- package/build/planning/index.d.ts.map +1 -1
- package/build/planning/index.js +1 -0
- package/build/planning/index.js.map +1 -1
- package/build/planning/landing.d.ts +25 -0
- package/build/planning/landing.d.ts.map +1 -0
- package/build/planning/landing.js +38 -0
- package/build/planning/landing.js.map +1 -0
- package/build/planning/schemas.d.ts.map +1 -1
- package/build/planning/schemas.js +13 -0
- package/build/planning/schemas.js.map +1 -1
- package/build/planning/types.d.ts +28 -3
- package/build/planning/types.d.ts.map +1 -1
- package/build/scaffold/consts.d.ts +8 -0
- package/build/scaffold/consts.d.ts.map +1 -1
- package/build/scaffold/consts.js +7 -0
- package/build/scaffold/consts.js.map +1 -1
- package/build/scaffold/schemas.d.ts.map +1 -1
- package/build/scaffold/schemas.js +257 -12
- package/build/scaffold/schemas.js.map +1 -1
- package/build/scaffold/types.d.ts +119 -4
- package/build/scaffold/types.d.ts.map +1 -1
- package/build/skills/catalogue.d.ts.map +1 -1
- package/build/skills/catalogue.js +150 -39
- package/build/skills/catalogue.js.map +1 -1
- package/build/skills/consts.d.ts +5 -0
- package/build/skills/consts.d.ts.map +1 -1
- package/build/skills/consts.js +8 -0
- package/build/skills/consts.js.map +1 -1
- package/build/skills/roles.d.ts.map +1 -1
- package/build/skills/roles.js +11 -5
- package/build/skills/roles.js.map +1 -1
- package/build/types.d.ts +30 -0
- package/build/types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/blueprint/case.ts +64 -16
- package/src/blueprint/resolve.ts +3 -0
- package/src/blueprint/types.ts +57 -1
- package/src/branding.ts +6 -0
- package/src/connect/consts.ts +32 -45
- package/src/connect/entrypoints.ts +51 -23
- package/src/connect/index.ts +0 -1
- package/src/connect/ops.ts +1 -4
- package/src/connect/references.ts +48 -29
- package/src/connect/schemas.ts +40 -11
- package/src/connect/types.ts +66 -69
- package/src/consts.ts +3 -0
- package/src/design/runtime.ts +1 -1
- package/src/metadata/types.ts +8 -0
- package/src/planning/consts.ts +1 -1
- package/src/planning/helpers.ts +5 -2
- package/src/planning/index.ts +1 -0
- package/src/planning/landing.ts +43 -0
- package/src/planning/schemas.ts +13 -0
- package/src/planning/types.ts +29 -3
- package/src/scaffold/consts.ts +10 -0
- package/src/scaffold/schemas.ts +262 -13
- package/src/scaffold/types.ts +105 -5
- package/src/skills/catalogue.ts +151 -39
- package/src/skills/consts.ts +8 -0
- package/src/skills/roles.ts +11 -5
- package/src/types.ts +30 -0
- package/tests/blueprint.spec.ts +98 -0
- package/tests/branding.spec.ts +21 -1
- package/tests/connect-convert.spec.ts +2 -8
- package/tests/connect-entrypoints.spec.ts +49 -28
- package/tests/planning.spec.ts +56 -1
- package/tests/scaffold.spec.ts +131 -0
- package/tests/skills.spec.ts +63 -2
- package/build/connect/jobs.d.ts +0 -25
- package/build/connect/jobs.d.ts.map +0 -1
- package/build/connect/jobs.js +0 -29
- package/build/connect/jobs.js.map +0 -1
- package/src/connect/jobs.ts +0 -40
package/src/blueprint/case.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { SubProject } from '../slot/consts.js'
|
|
|
2
2
|
import { ViableSkill } from '../skills/consts.js'
|
|
3
3
|
import { ViablePersona } from '../skills/roles.js'
|
|
4
4
|
import { aiLibraryList, gameLibraryList } from '../skills/catalogue.js'
|
|
5
|
+
import { LandingGatePreference } from './types.js'
|
|
5
6
|
import type { BlueprintPatch } from './types.js'
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -61,8 +62,8 @@ export interface BlueprintCaseDefinition {
|
|
|
61
62
|
/** What every AI case installs. The langchain peers are declared here, at ONE range. */
|
|
62
63
|
const AI_DEPS = {
|
|
63
64
|
[SubProject.Backend]: {
|
|
64
|
-
'@owlmeans/llm': '^0.1.18-rc.
|
|
65
|
-
'@owlmeans/agent': '^0.1.18-rc.
|
|
65
|
+
'@owlmeans/llm': '^0.1.18-rc.31',
|
|
66
|
+
'@owlmeans/agent': '^0.1.18-rc.32',
|
|
66
67
|
'@langchain/core': '^1.2.9',
|
|
67
68
|
'@langchain/anthropic': '^1.5.8',
|
|
68
69
|
'@langchain/openai': '^1.5.10',
|
|
@@ -85,12 +86,6 @@ const AI_SKILLS = [
|
|
|
85
86
|
ViableSkill.LibrariesAi,
|
|
86
87
|
]
|
|
87
88
|
|
|
88
|
-
/**
|
|
89
|
-
* What the analysis stage is told about a product whose value is a model.
|
|
90
|
-
*
|
|
91
|
-
* The pairing rule is the load-bearing one: an agent holds no permissions and owns no screen, so
|
|
92
|
-
* a story that is the AGENT's work is invisible unless a human story starts it and watches it.
|
|
93
|
-
*/
|
|
94
89
|
/**
|
|
95
90
|
* What the API side is told once a project may have a queue.
|
|
96
91
|
*
|
|
@@ -105,6 +100,12 @@ const PRODUCER_PERSONA_SKILLS = {
|
|
|
105
100
|
[ViablePersona.ApiCoder]: [ViableSkill.WorkerJobs],
|
|
106
101
|
}
|
|
107
102
|
|
|
103
|
+
/**
|
|
104
|
+
* What the analysis stage is told about a product whose value is a model.
|
|
105
|
+
*
|
|
106
|
+
* The pairing rule is the load-bearing one: an agent holds no permissions and owns no screen, so
|
|
107
|
+
* a story that is the AGENT's work is invisible unless a human story starts it and watches it.
|
|
108
|
+
*/
|
|
108
109
|
const AI_PERSONA_SKILLS = {
|
|
109
110
|
...PRODUCER_PERSONA_SKILLS,
|
|
110
111
|
[ViablePersona.BusinessAnalyst]: [ViableSkill.AgenticChoice],
|
|
@@ -115,6 +116,46 @@ const AI_PERSONA_SKILLS = {
|
|
|
115
116
|
],
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
type PersonaSkills = Partial<Record<ViablePersona, ViableSkill[]>>
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Join persona-skill maps, UNIONING a persona two maps both name.
|
|
123
|
+
*
|
|
124
|
+
* An object spread would keep only the last map's list for that persona — `BusinessAnalyst`
|
|
125
|
+
* carries `AgenticChoice` in an AI case and `LandingGate` from the gate map, and a spread would
|
|
126
|
+
* silently drop whichever came first.
|
|
127
|
+
*/
|
|
128
|
+
const joinPersonaSkills = (...maps: PersonaSkills[]): PersonaSkills => {
|
|
129
|
+
const out: PersonaSkills = {}
|
|
130
|
+
for (const map of maps) {
|
|
131
|
+
for (const [persona, skills] of Object.entries(map)) {
|
|
132
|
+
const key = persona as ViablePersona
|
|
133
|
+
out[key] = [...new Set([...(out[key] ?? []), ...(skills ?? [])])]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return out
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Who has to know the landing-gate pattern in a case that encourages one.
|
|
142
|
+
*
|
|
143
|
+
* The analyst decides whether a story is gate-worthy and plans the gate's copy; the UX designer
|
|
144
|
+
* shapes the full-scale screen that continues what the guest started; the frontend personas draw
|
|
145
|
+
* the gate, write the handoff and read it back. Nobody else touches it.
|
|
146
|
+
*/
|
|
147
|
+
const LANDING_GATE_PERSONA_SKILLS: PersonaSkills = {
|
|
148
|
+
[ViablePersona.BusinessAnalyst]: [ViableSkill.LandingGate],
|
|
149
|
+
[ViablePersona.UxDesigner]: [ViableSkill.LandingGate],
|
|
150
|
+
[ViablePersona.LayoutArchitect]: [ViableSkill.LandingGate],
|
|
151
|
+
[ViablePersona.ComponentArchitect]: [ViableSkill.LandingGate],
|
|
152
|
+
[ViablePersona.UiViewCoder]: [ViableSkill.LandingGate],
|
|
153
|
+
[ViablePersona.UiNavCoder]: [ViableSkill.LandingGate],
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The experience layer of a case whose product usually has a step a guest can begin. */
|
|
157
|
+
const ENCOURAGE_GATE = { landingGate: LandingGatePreference.Encourage }
|
|
158
|
+
|
|
118
159
|
const GAME_PERSONA_SKILLS = {
|
|
119
160
|
[ViablePersona.BusinessAnalyst]: [ViableSkill.GameDesign],
|
|
120
161
|
[ViablePersona.UxDesigner]: [ViableSkill.GameDesign, ViableSkill.GameUi],
|
|
@@ -151,7 +192,9 @@ party, nothing walks an unbounded set, nothing is scheduled. Most products are t
|
|
|
151
192
|
patch: {
|
|
152
193
|
packages: {
|
|
153
194
|
capabilities: { postgres: true, kv: false, queue: false, worker: false, agents: false, validation: true },
|
|
195
|
+
personaSkills: LANDING_GATE_PERSONA_SKILLS,
|
|
154
196
|
},
|
|
197
|
+
experience: ENCOURAGE_GATE,
|
|
155
198
|
},
|
|
156
199
|
},
|
|
157
200
|
|
|
@@ -173,6 +216,9 @@ to call a model at all.
|
|
|
173
216
|
capabilities: { postgres: true, kv: true, queue: true, worker: true, agents: false, validation: true },
|
|
174
217
|
personaSkills: PRODUCER_PERSONA_SKILLS,
|
|
175
218
|
},
|
|
219
|
+
// Neutral: the named off-request part is usually operator-side work, and whether a guest
|
|
220
|
+
// can begin anything is the specification's to say.
|
|
221
|
+
experience: { landingGate: LandingGatePreference.Allow },
|
|
176
222
|
},
|
|
177
223
|
},
|
|
178
224
|
|
|
@@ -194,8 +240,9 @@ application, and never merely a scalable one.
|
|
|
194
240
|
deps: AI_DEPS,
|
|
195
241
|
libraries: AI_LIBRARIES,
|
|
196
242
|
skills: AI_SKILLS,
|
|
197
|
-
personaSkills: AI_PERSONA_SKILLS,
|
|
243
|
+
personaSkills: joinPersonaSkills(AI_PERSONA_SKILLS, LANDING_GATE_PERSONA_SKILLS),
|
|
198
244
|
},
|
|
245
|
+
experience: ENCOURAGE_GATE,
|
|
199
246
|
},
|
|
200
247
|
},
|
|
201
248
|
|
|
@@ -214,18 +261,16 @@ in advance.
|
|
|
214
261
|
deps: {
|
|
215
262
|
[SubProject.Backend]: {
|
|
216
263
|
...AI_DEPS[SubProject.Backend],
|
|
217
|
-
'@owlmeans/agent-skills': '^0.1.18-rc.
|
|
264
|
+
'@owlmeans/agent-skills': '^0.1.18-rc.31',
|
|
218
265
|
},
|
|
219
266
|
},
|
|
220
267
|
libraries: AI_LIBRARIES,
|
|
221
268
|
skills: [...AI_SKILLS, ViableSkill.TargetAgentTools],
|
|
222
|
-
personaSkills: {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
...AI_PERSONA_SKILLS[ViablePersona.WorkerCoder], ViableSkill.TargetAgentTools,
|
|
226
|
-
],
|
|
227
|
-
},
|
|
269
|
+
personaSkills: joinPersonaSkills(AI_PERSONA_SKILLS, LANDING_GATE_PERSONA_SKILLS, {
|
|
270
|
+
[ViablePersona.WorkerCoder]: [ViableSkill.TargetAgentTools],
|
|
271
|
+
}),
|
|
228
272
|
},
|
|
273
|
+
experience: ENCOURAGE_GATE,
|
|
229
274
|
},
|
|
230
275
|
},
|
|
231
276
|
|
|
@@ -248,6 +293,9 @@ is not it.
|
|
|
248
293
|
skills: [ViableSkill.GameScene, ViableSkill.GameUi, ViableSkill.LibrariesGame],
|
|
249
294
|
personaSkills: { ...PRODUCER_PERSONA_SKILLS, ...GAME_PERSONA_SKILLS },
|
|
250
295
|
},
|
|
296
|
+
// A game's first value is PLAYING it, and the play screen is its own front door — a
|
|
297
|
+
// pick-and-preview card on a landing page is the wrong shape for it.
|
|
298
|
+
experience: { landingGate: LandingGatePreference.Discourage },
|
|
251
299
|
},
|
|
252
300
|
},
|
|
253
301
|
}
|
package/src/blueprint/resolve.ts
CHANGED
|
@@ -54,6 +54,9 @@ export const freezeBlueprint = (blueprint: Blueprint): Blueprint => Object.freez
|
|
|
54
54
|
...blueprint.packages,
|
|
55
55
|
capabilities: Object.freeze({ ...blueprint.packages.capabilities }),
|
|
56
56
|
}),
|
|
57
|
+
// The one optional layer: frozen when present, and never ADDED when absent, so a blueprint that
|
|
58
|
+
// has none still compares equal to what it was before the layer existed.
|
|
59
|
+
...(blueprint.experience != null ? { experience: Object.freeze({ ...blueprint.experience }) } : {}),
|
|
57
60
|
})
|
|
58
61
|
|
|
59
62
|
/** Every skill the blueprint asks for, stack first, deduped, order preserved. */
|
package/src/blueprint/types.ts
CHANGED
|
@@ -16,6 +16,12 @@ import type { TopologyDescriptor } from '../topology/types.js'
|
|
|
16
16
|
* Deliberately NOT called a preset: `presets/` in the agent library already means the LLM
|
|
17
17
|
* model/provider configurations, and the two are asked at different moments about different
|
|
18
18
|
* things.
|
|
19
|
+
*
|
|
20
|
+
* Five layers are REQUIRED and say what the project is built WITH; the sixth, `experience`, is
|
|
21
|
+
* OPTIONAL and says what its product should do for the people using it. Optional because a
|
|
22
|
+
* blueprint registered before the layer existed — or a patch serialized into a run row — must keep
|
|
23
|
+
* resolving: every reader asks through a helper that answers the default for an absent layer
|
|
24
|
+
* ({@link landingGatePreferenceOf}).
|
|
19
25
|
*/
|
|
20
26
|
export interface Blueprint {
|
|
21
27
|
id: string
|
|
@@ -25,6 +31,7 @@ export interface Blueprint {
|
|
|
25
31
|
template: TemplateLayer
|
|
26
32
|
createApp: CreateAppLayer
|
|
27
33
|
packages: PackagesLayer
|
|
34
|
+
experience?: ExperienceLayer
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
/**
|
|
@@ -32,7 +39,8 @@ export interface Blueprint {
|
|
|
32
39
|
*
|
|
33
40
|
* The ordering is the point: `technology` overrides everything, because a change of language
|
|
34
41
|
* invalidates every template, prompt and package below it. Nothing today has more than one
|
|
35
|
-
* technology — the ladder exists so that adding one is a data change.
|
|
42
|
+
* technology — the ladder exists so that adding one is a data change. `experience` is last and
|
|
43
|
+
* optional: it shares no key with the five build layers, so its place decides nothing today.
|
|
36
44
|
*/
|
|
37
45
|
export enum BlueprintLayer {
|
|
38
46
|
Technology = 'technology',
|
|
@@ -40,6 +48,7 @@ export enum BlueprintLayer {
|
|
|
40
48
|
Template = 'template',
|
|
41
49
|
CreateApp = 'create-app',
|
|
42
50
|
Packages = 'packages',
|
|
51
|
+
Experience = 'experience',
|
|
43
52
|
}
|
|
44
53
|
|
|
45
54
|
export const BLUEPRINT_LAYER_ORDER: BlueprintLayer[] = [
|
|
@@ -48,8 +57,55 @@ export const BLUEPRINT_LAYER_ORDER: BlueprintLayer[] = [
|
|
|
48
57
|
BlueprintLayer.Template,
|
|
49
58
|
BlueprintLayer.CreateApp,
|
|
50
59
|
BlueprintLayer.Packages,
|
|
60
|
+
BlueprintLayer.Experience,
|
|
51
61
|
]
|
|
52
62
|
|
|
63
|
+
/**
|
|
64
|
+
* How strongly a product of this kind wants a LANDING GATE — the working entry into the key
|
|
65
|
+
* end-user workflow drawn on the guest home, where a guest starts before signing in.
|
|
66
|
+
*
|
|
67
|
+
* A PRIOR handed to the model that decides, never the decision itself: `Encourage` still lets it
|
|
68
|
+
* answer "no gate" for a product with no end-user step a guest could begin, and `Discourage` still
|
|
69
|
+
* lets it choose one when the specification plainly describes such a step.
|
|
70
|
+
*/
|
|
71
|
+
export enum LandingGatePreference {
|
|
72
|
+
/** Most products of this kind have a first-value step a guest can begin — look for it. */
|
|
73
|
+
Encourage = 'encourage',
|
|
74
|
+
/** Neutral: decide from the specification alone. */
|
|
75
|
+
Allow = 'allow',
|
|
76
|
+
/** Products of this kind rarely have one — choose a gate only when the specification asks. */
|
|
77
|
+
Discourage = 'discourage',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* What the product should do for the people using it, independent of the stack it is built on.
|
|
82
|
+
*
|
|
83
|
+
* A layer of its own rather than a field of `packages`, because it changes no dependency, no
|
|
84
|
+
* capability and no prompt a coder reads — it is asked by the analysis stage about the PRODUCT.
|
|
85
|
+
*/
|
|
86
|
+
export interface ExperienceLayer {
|
|
87
|
+
landingGate: LandingGatePreference
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const LANDING_GATE_PREFERENCES = new Set<string>(Object.values(LandingGatePreference))
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The landing-gate preference of a resolved blueprint.
|
|
94
|
+
*
|
|
95
|
+
* Total: an absent layer, an absent key and a value this deploy does not know (a patch serialized
|
|
96
|
+
* by a newer one) all answer `Allow` — the neutral prior, which leaves the decision to the
|
|
97
|
+
* specification rather than tilting it either way on a value nobody set.
|
|
98
|
+
*/
|
|
99
|
+
export const landingGatePreferenceOf = (
|
|
100
|
+
blueprint?: Pick<Blueprint, 'experience'> | null
|
|
101
|
+
): LandingGatePreference => {
|
|
102
|
+
const value = blueprint?.experience?.landingGate
|
|
103
|
+
|
|
104
|
+
return value != null && LANDING_GATE_PREFERENCES.has(value)
|
|
105
|
+
? value
|
|
106
|
+
: LandingGatePreference.Allow
|
|
107
|
+
}
|
|
108
|
+
|
|
53
109
|
/** Language and toolchain. Overrides everything below it. */
|
|
54
110
|
export interface TechnologyLayer {
|
|
55
111
|
id: string
|
package/src/branding.ts
CHANGED
|
@@ -14,6 +14,7 @@ export const BRANDING_ENV_KEYS = [
|
|
|
14
14
|
'BRANDING_PRIVACY_URL',
|
|
15
15
|
'BRANDING_CREDIT',
|
|
16
16
|
'BRANDING_PRODUCT',
|
|
17
|
+
'BRANDING_GOOGLE_TAG',
|
|
17
18
|
] as const
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -23,6 +24,10 @@ export const BRANDING_ENV_KEYS = [
|
|
|
23
24
|
* hides the platform credit, so a metadata set that never carried the key keeps it. That is the
|
|
24
25
|
* safe direction — the opposite failure hands out a paid feature and nobody reports getting more
|
|
25
26
|
* than they paid for.
|
|
27
|
+
*
|
|
28
|
+
* `BRANDING_GOOGLE_TAG` is always EMITTED, empty when no tag is set, although its metadata key is
|
|
29
|
+
* omitted from a push while unset: the environment is read by the application's own build, which
|
|
30
|
+
* treats `''` as "load no tag", while the metadata key is read by a publisher that may predate it.
|
|
26
31
|
*/
|
|
27
32
|
export const brandingEnv = (meta: Partial<SlotMetadata>): Record<string, string> => ({
|
|
28
33
|
BRANDING_COPYRIGHT: meta.brandingCopyright ?? '',
|
|
@@ -31,4 +36,5 @@ export const brandingEnv = (meta: Partial<SlotMetadata>): Record<string, string>
|
|
|
31
36
|
BRANDING_PRIVACY_URL: meta.brandingPrivacyUrl ?? '',
|
|
32
37
|
BRANDING_CREDIT: meta.brandingCredit === '' ? '' : '1',
|
|
33
38
|
BRANDING_PRODUCT: meta.projectName ?? '',
|
|
39
|
+
BRANDING_GOOGLE_TAG: meta.brandingGoogleTag ?? '',
|
|
34
40
|
})
|
package/src/connect/consts.ts
CHANGED
|
@@ -209,47 +209,12 @@ export enum ModelTaskRole {
|
|
|
209
209
|
Tool = 'tool',
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
/**
|
|
213
|
-
export enum
|
|
214
|
-
|
|
215
|
-
ProjectInit = 'project-init',
|
|
216
|
-
ProjectReinit = 'project-reinit',
|
|
217
|
-
StoryDevelop = 'story-develop',
|
|
218
|
-
FreeFlight = 'free-flight',
|
|
219
|
-
PipelineResume = 'pipeline-resume',
|
|
220
|
-
/**
|
|
221
|
-
* The four stages of a conversion, plus the purge.
|
|
222
|
-
*
|
|
223
|
-
* One kind per stage rather than one for the whole conversion: each stage is its own platform
|
|
224
|
-
* pipeline run, ends at a decision the user makes, and is looked up by the pipeline alias its
|
|
225
|
-
* kind names. A single `convert` kind would match whichever run row happened to be newest.
|
|
226
|
-
*/
|
|
227
|
-
ConvertIntake = 'convert-intake',
|
|
228
|
-
ConvertAnalysis = 'convert-analysis',
|
|
229
|
-
ConvertExtraction = 'convert-extraction',
|
|
230
|
-
ConvertImplementation = 'convert-implementation',
|
|
231
|
-
ConvertPurge = 'convert-purge',
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export enum ConnectJobStatus {
|
|
235
|
-
Queued = 'queued',
|
|
236
|
-
Running = 'running',
|
|
237
|
-
/** Running, but waiting on the connector — see `ConnectJob.blockedOn`. */
|
|
238
|
-
Blocked = 'blocked',
|
|
239
|
-
Done = 'done',
|
|
240
|
-
Failed = 'failed',
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/** What a blocked job is waiting for. */
|
|
244
|
-
export enum ConnectJobBlock {
|
|
245
|
-
/** Model tasks are queued and nobody is answering them. */
|
|
212
|
+
/** Why a domain operation cannot currently advance. */
|
|
213
|
+
export enum ConnectWaitReason {
|
|
214
|
+
Person = 'person',
|
|
246
215
|
ModelTask = 'model-task',
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
/** The local target has no database configured and the run needs one. */
|
|
250
|
-
Env = 'env',
|
|
251
|
-
/** A question is waiting for a person and nobody has answered it. */
|
|
252
|
-
Question = 'question',
|
|
216
|
+
LocalConnector = 'local-connector',
|
|
217
|
+
Environment = 'environment',
|
|
253
218
|
}
|
|
254
219
|
|
|
255
220
|
/**
|
|
@@ -336,6 +301,19 @@ export const CONNECT_CONFIGURE_TIMEOUT_MS = 60_000
|
|
|
336
301
|
*/
|
|
337
302
|
export const CONNECT_CAP_LOCAL_LLM_KEY = 'connect--local-llm'
|
|
338
303
|
|
|
304
|
+
/**
|
|
305
|
+
* The ceilings of a project's branding strings on the connector wire.
|
|
306
|
+
*
|
|
307
|
+
* Each equals its twin in the platform's own branding contract (`BRANDING_COPYRIGHT_MAX`,
|
|
308
|
+
* `BRANDING_ORGANIZATION_MAX`, `BRANDING_URL_MAX`) and must stay equal: a connector refused below the
|
|
309
|
+
* web form's limit, or accepted above it and refused further in, is one value with two answers.
|
|
310
|
+
* The Google tag's is its own — the longest id any Google product issues is well under it.
|
|
311
|
+
*/
|
|
312
|
+
export const CONNECT_BRANDING_COPYRIGHT_MAX = 200
|
|
313
|
+
export const CONNECT_BRANDING_ORGANIZATION_MAX = 120
|
|
314
|
+
export const CONNECT_BRANDING_URL_MAX = 2048
|
|
315
|
+
export const CONNECT_BRANDING_GOOGLE_TAG_MAX = 32
|
|
316
|
+
|
|
339
317
|
/** The access-token prefix the platform issues. Every connector token starts with it. */
|
|
340
318
|
export const CONNECT_TOKEN_PREFIX = 'vib_'
|
|
341
319
|
|
|
@@ -398,10 +376,8 @@ export const RES_CONNECT_SESSION = 'connect-session'
|
|
|
398
376
|
* the tree would be a second place for a name to drift. The platform spreads the declarations
|
|
399
377
|
* these produce into its own entrypoint list and binds handlers onto them.
|
|
400
378
|
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* `@owlmeans/planning`) — one surface for the browser and a connector alike, so a story rule the
|
|
404
|
-
* platform enforces cannot be enforced on one of them only.
|
|
379
|
+
* Story mutations use the planning CARD surface. The connector story status route composes that
|
|
380
|
+
* card with its pipeline run and pending inquiry without creating a second mutation path.
|
|
405
381
|
*/
|
|
406
382
|
export const connect = Object.freeze({
|
|
407
383
|
base: 'viable:manager-api:connect:base',
|
|
@@ -430,7 +406,18 @@ export const connect = Object.freeze({
|
|
|
430
406
|
llm: 'viable:manager-api:connect:project:llm',
|
|
431
407
|
/** The per-project converter inference mode. Separate from `llm`: it is not a paid capability. */
|
|
432
408
|
converterLlm: 'viable:manager-api:connect:project:converter-llm',
|
|
433
|
-
|
|
409
|
+
/**
|
|
410
|
+
* The project's own branding — copyright, organization, the two legal links, the Google tag.
|
|
411
|
+
* The platform credit is deliberately NOT here: hiding it is a paid capability with its own
|
|
412
|
+
* gated route, and a connector setting the rest must never be able to touch it.
|
|
413
|
+
*/
|
|
414
|
+
branding: Object.freeze({
|
|
415
|
+
get: 'viable:manager-api:connect:project:branding:get',
|
|
416
|
+
save: 'viable:manager-api:connect:project:branding:save',
|
|
417
|
+
}),
|
|
418
|
+
}),
|
|
419
|
+
story: Object.freeze({
|
|
420
|
+
status: 'viable:manager-api:connect:story:status',
|
|
434
421
|
}),
|
|
435
422
|
convert: Object.freeze({
|
|
436
423
|
create: 'viable:manager-api:connect:convert:create',
|
|
@@ -6,16 +6,18 @@ import { connect } from './consts.js'
|
|
|
6
6
|
import {
|
|
7
7
|
ConnectAttachBodySchema, ConnectConfirmBodySchema, ConnectConvertCreateBodySchema,
|
|
8
8
|
ConnectConvertProceedBodySchema, ConnectCreateBodySchema, ConnectInquiryParamsSchema,
|
|
9
|
-
|
|
10
|
-
ConnectPipelineParamsSchema, ConnectPipelineResumeBodySchema,
|
|
11
|
-
ConnectProjectLlmBodySchema, ConnectSessionOpenSchema,
|
|
12
|
-
|
|
9
|
+
ConnectModifyBodySchema, ConnectOpParamsSchema, ConnectOpResultSchema,
|
|
10
|
+
ConnectPipelineParamsSchema, ConnectPipelineResumeBodySchema, ConnectProjectBrandingSaveSchema,
|
|
11
|
+
ConnectProjectIdSchema, ConnectProjectLlmBodySchema, ConnectSessionOpenSchema,
|
|
12
|
+
ConnectSessionParamsSchema, ConnectPullQuerySchema, ConnectStoryParamsSchema, InquiryAnswerSchema,
|
|
13
13
|
} from './schemas.js'
|
|
14
14
|
import type {
|
|
15
15
|
ConnectAttachBody, ConnectConfirmBody, ConnectConvertCreateBody, ConnectConvertProceedBody,
|
|
16
|
-
ConnectCreateBody, ConnectInquiryAnswerBody,
|
|
17
|
-
ConnectPipelineParams, ConnectPipelineResumeBody,
|
|
18
|
-
|
|
16
|
+
ConnectCreateBody, ConnectInquiryAnswerBody, ConnectModifyBody,
|
|
17
|
+
ConnectPipelineParams, ConnectPipelineResumeBody, ConnectProjectBranding,
|
|
18
|
+
ConnectProjectBrandingSave, ConnectProjectLlmBody, ConnectSessionOpen,
|
|
19
|
+
ConnectPipelineState, ConnectProjectStatus, ConnectPullQuery, ConnectSessionParams,
|
|
20
|
+
ConnectStoryStatus, ConversionStatusView, ConvertCheck,
|
|
19
21
|
} from './types.js'
|
|
20
22
|
import type { ConnectOpResult } from './ops.js'
|
|
21
23
|
import type { ConverterProjectLlmBody } from '../convert/types.js'
|
|
@@ -115,7 +117,7 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
115
117
|
route(connect.op.pull, '/session/:sessionId/ops', {
|
|
116
118
|
parent: base, method: RouteMethod.GET
|
|
117
119
|
}),
|
|
118
|
-
contract.request({ params: typed<ConnectSessionParams>(ConnectSessionParamsSchema), query: typed<
|
|
120
|
+
contract.request({ params: typed<ConnectSessionParams>(ConnectSessionParamsSchema), query: typed<ConnectPullQuery>(ConnectPullQuerySchema) }, typed())
|
|
119
121
|
),
|
|
120
122
|
submit: protocol(
|
|
121
123
|
route(connect.op.submit, '/session/:sessionId/ops/:opId', {
|
|
@@ -130,7 +132,7 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
130
132
|
project: {
|
|
131
133
|
create: protocol(
|
|
132
134
|
route(connect.project.create, '/project', { parent: base, method: RouteMethod.POST }),
|
|
133
|
-
contract.request({ body: typed<ConnectCreateBody>(ConnectCreateBodySchema) }, typed())
|
|
135
|
+
contract.request({ body: typed<ConnectCreateBody>(ConnectCreateBodySchema) }, typed<ConnectProjectStatus>())
|
|
134
136
|
),
|
|
135
137
|
list: protocol(
|
|
136
138
|
route(connect.project.list, '/project', { parent: base, method: RouteMethod.GET }),
|
|
@@ -146,25 +148,25 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
146
148
|
route(connect.project.confirm, '/project/:id/confirm', {
|
|
147
149
|
parent: base, method: RouteMethod.POST
|
|
148
150
|
}),
|
|
149
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema), body: typed<ConnectConfirmBody>(ConnectConfirmBodySchema) }, typed())
|
|
151
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema), body: typed<ConnectConfirmBody>(ConnectConfirmBodySchema) }, typed<ConnectProjectStatus>())
|
|
150
152
|
),
|
|
151
153
|
status: protocol(
|
|
152
154
|
route(connect.project.status, '/project/:id/status', {
|
|
153
155
|
parent: base, method: RouteMethod.GET
|
|
154
156
|
}),
|
|
155
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed())
|
|
157
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<ConnectProjectStatus>())
|
|
156
158
|
),
|
|
157
159
|
reinit: protocol(
|
|
158
160
|
route(connect.project.reinit, '/project/:id/reinit', {
|
|
159
161
|
parent: base, method: RouteMethod.POST
|
|
160
162
|
}),
|
|
161
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed())
|
|
163
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<ConnectProjectStatus>())
|
|
162
164
|
),
|
|
163
165
|
modify: protocol(
|
|
164
166
|
route(connect.project.modify, '/project/:id/modify', {
|
|
165
167
|
parent: base, method: RouteMethod.POST
|
|
166
168
|
}),
|
|
167
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema), body: typed<ConnectModifyBody>(ConnectModifyBodySchema) }, typed())
|
|
169
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema), body: typed<ConnectModifyBody>(ConnectModifyBodySchema) }, typed<ConnectProjectStatus>())
|
|
168
170
|
),
|
|
169
171
|
settings: protocol(
|
|
170
172
|
route(connect.project.settings, '/project/:id/settings', {
|
|
@@ -187,11 +189,37 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
187
189
|
body: typed<ConverterProjectLlmBody>(ConverterProjectLlmBodySchema),
|
|
188
190
|
}, typed()),
|
|
189
191
|
),
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
// Under `base` like every sibling — the guard and the ownership gate — and never under the
|
|
193
|
+
// paid gate: saving branding is free, and the paid credit switch is not reachable from here.
|
|
194
|
+
branding: {
|
|
195
|
+
get: protocol(
|
|
196
|
+
route(connect.project.branding.get, '/project/:id/branding', {
|
|
197
|
+
parent: base, method: RouteMethod.GET,
|
|
198
|
+
}),
|
|
199
|
+
contract.request({
|
|
200
|
+
params: typed<{ id: string }>(ConnectProjectIdSchema),
|
|
201
|
+
}, typed<ConnectProjectBranding>()),
|
|
202
|
+
),
|
|
203
|
+
save: protocol(
|
|
204
|
+
route(connect.project.branding.save, '/project/:id/branding', {
|
|
205
|
+
parent: base, method: RouteMethod.POST,
|
|
206
|
+
}),
|
|
207
|
+
contract.request({
|
|
208
|
+
params: typed<{ id: string }>(ConnectProjectIdSchema),
|
|
209
|
+
body: typed<ConnectProjectBrandingSave>(ConnectProjectBrandingSaveSchema),
|
|
210
|
+
}, typed<ConnectProjectBranding>()),
|
|
211
|
+
),
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
story: {
|
|
216
|
+
status: protocol(
|
|
217
|
+
route(connect.story.status, '/project/:id/story/:storyId/status', {
|
|
192
218
|
parent: base, method: RouteMethod.GET
|
|
193
219
|
}),
|
|
194
|
-
contract.request({
|
|
220
|
+
contract.request({
|
|
221
|
+
params: typed<{ id: string, storyId: string }>(ConnectStoryParamsSchema),
|
|
222
|
+
}, typed<ConnectStoryStatus>())
|
|
195
223
|
),
|
|
196
224
|
|
|
197
225
|
},
|
|
@@ -207,7 +235,7 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
207
235
|
convert: {
|
|
208
236
|
create: protocol(
|
|
209
237
|
route(connect.convert.create, '/convert', { parent: base, method: RouteMethod.POST }),
|
|
210
|
-
contract.request({ body: typed<ConnectConvertCreateBody>(ConnectConvertCreateBodySchema) }, typed<
|
|
238
|
+
contract.request({ body: typed<ConnectConvertCreateBody>(ConnectConvertCreateBodySchema) }, typed<ConversionStatusView>()),
|
|
211
239
|
),
|
|
212
240
|
check: protocol(
|
|
213
241
|
route(connect.convert.check, '/convert/:id/check', { parent: base, method: RouteMethod.GET }),
|
|
@@ -215,18 +243,18 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
215
243
|
),
|
|
216
244
|
start: protocol(
|
|
217
245
|
route(connect.convert.start, '/convert/:id/start', { parent: base, method: RouteMethod.POST }),
|
|
218
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<
|
|
246
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<ConversionStatusView>()),
|
|
219
247
|
),
|
|
220
248
|
proceed: protocol(
|
|
221
249
|
route(connect.convert.proceed, '/convert/:id/proceed', { parent: base, method: RouteMethod.POST }),
|
|
222
250
|
contract.request({
|
|
223
251
|
params: typed<{ id: string }>(ConnectProjectIdSchema),
|
|
224
252
|
body: typed<ConnectConvertProceedBody>(ConnectConvertProceedBodySchema),
|
|
225
|
-
}, typed<
|
|
253
|
+
}, typed<ConversionStatusView>()),
|
|
226
254
|
),
|
|
227
255
|
cancel: protocol(
|
|
228
256
|
route(connect.convert.cancel, '/convert/:id/cancel', { parent: base, method: RouteMethod.POST }),
|
|
229
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<
|
|
257
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<ConversionStatusView>()),
|
|
230
258
|
),
|
|
231
259
|
status: protocol(
|
|
232
260
|
route(connect.convert.status, '/convert/:id', { parent: base, method: RouteMethod.GET }),
|
|
@@ -234,7 +262,7 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
234
262
|
),
|
|
235
263
|
purge: protocol(
|
|
236
264
|
route(connect.convert.purge, '/convert/:id/purge', { parent: base, method: RouteMethod.POST }),
|
|
237
|
-
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<
|
|
265
|
+
contract.request({ params: typed<{ id: string }>(ConnectProjectIdSchema) }, typed<ConversionStatusView>()),
|
|
238
266
|
),
|
|
239
267
|
},
|
|
240
268
|
|
|
@@ -256,13 +284,13 @@ export const connectProtocols = (opts: ConnectEntrypointOptions) => {
|
|
|
256
284
|
route(connect.pipeline.state, '/pipeline/:id/:runId', {
|
|
257
285
|
parent: base, method: RouteMethod.GET
|
|
258
286
|
}),
|
|
259
|
-
contract.request({ params: typed<ConnectPipelineParams>(ConnectPipelineParamsSchema) }, typed())
|
|
287
|
+
contract.request({ params: typed<ConnectPipelineParams>(ConnectPipelineParamsSchema) }, typed<ConnectPipelineState>())
|
|
260
288
|
),
|
|
261
289
|
resume: protocol(
|
|
262
290
|
route(connect.pipeline.resume, '/pipeline/:id/:runId/resume', {
|
|
263
291
|
parent: base, method: RouteMethod.POST
|
|
264
292
|
}),
|
|
265
|
-
contract.request({ params: typed<ConnectPipelineParams>(ConnectPipelineParamsSchema), body: typed<ConnectPipelineResumeBody>(ConnectPipelineResumeBodySchema) }, typed())
|
|
293
|
+
contract.request({ params: typed<ConnectPipelineParams>(ConnectPipelineParamsSchema), body: typed<ConnectPipelineResumeBody>(ConnectPipelineResumeBodySchema) }, typed<ConnectPipelineState>())
|
|
266
294
|
),
|
|
267
295
|
},
|
|
268
296
|
}
|
package/src/connect/index.ts
CHANGED
package/src/connect/ops.ts
CHANGED
|
@@ -91,8 +91,6 @@ export interface ConfigureResult {
|
|
|
91
91
|
export interface ModelTask {
|
|
92
92
|
id: string
|
|
93
93
|
projectId: string
|
|
94
|
-
/** The job the call belongs to, so a parent can say what it is working on. */
|
|
95
|
-
jobId?: string
|
|
96
94
|
/** The platform role that asked. Informational; the tier is what decides the model. */
|
|
97
95
|
role: string
|
|
98
96
|
tier: ModelTier
|
|
@@ -170,14 +168,13 @@ export interface ConnectInquiryOption {
|
|
|
170
168
|
/**
|
|
171
169
|
* One question put to the person the connector is working for.
|
|
172
170
|
*
|
|
173
|
-
* It carries where it came from — the
|
|
171
|
+
* It carries where it came from — the run and the step — because an answer is recorded
|
|
174
172
|
* against the run that asked and re-read when that run resumes. `expiresAt` is what makes an
|
|
175
173
|
* unanswered question fail its step instead of parking a project lock forever.
|
|
176
174
|
*/
|
|
177
175
|
export interface InquiryPayload {
|
|
178
176
|
id: string
|
|
179
177
|
projectId: string
|
|
180
|
-
jobId?: string
|
|
181
178
|
runId?: string
|
|
182
179
|
/** The pipeline step that asked, so a resumed run can match the answer to the place it belongs. */
|
|
183
180
|
step?: string
|