@plumbus/core 0.8.0-beta.5 → 0.8.0-beta.7

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +6 -1
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/ai/ai/cost-tracker.d.ts +5 -1
  5. package/dist/ai/ai/model-pricing.d.ts +3 -2
  6. package/dist/ai/ai-service.d.ts +3 -0
  7. package/dist/ai/ai-service.d.ts.map +1 -1
  8. package/dist/ai/ai-service.js +146 -24
  9. package/dist/ai/ai-service.js.map +1 -1
  10. package/dist/ai/cost-tracker.d.ts +5 -1
  11. package/dist/ai/cost-tracker.d.ts.map +1 -1
  12. package/dist/ai/cost-tracker.js +7 -2
  13. package/dist/ai/cost-tracker.js.map +1 -1
  14. package/dist/ai/explainability.d.ts +2 -1
  15. package/dist/ai/explainability.d.ts.map +1 -1
  16. package/dist/ai/explainability.js +1 -0
  17. package/dist/ai/explainability.js.map +1 -1
  18. package/dist/ai/model-pricing.d.ts +3 -2
  19. package/dist/ai/model-pricing.d.ts.map +1 -1
  20. package/dist/ai/model-pricing.js +23 -2
  21. package/dist/ai/model-pricing.js.map +1 -1
  22. package/dist/ai/provider.d.ts.map +1 -1
  23. package/dist/ai/provider.js +35 -15
  24. package/dist/ai/provider.js.map +1 -1
  25. package/dist/cli/commands/dev.d.ts.map +1 -1
  26. package/dist/cli/commands/dev.js +2 -1
  27. package/dist/cli/commands/dev.js.map +1 -1
  28. package/dist/cli/commands/generate-openapi-from-zod.d.ts.map +1 -1
  29. package/dist/cli/commands/generate-openapi-from-zod.js +9 -1
  30. package/dist/cli/commands/generate-openapi-from-zod.js.map +1 -1
  31. package/dist/cli/commands/init.d.ts +1 -1
  32. package/dist/cli/commands/init.d.ts.map +1 -1
  33. package/dist/cli/commands/init.js +3 -1
  34. package/dist/cli/commands/init.js.map +1 -1
  35. package/dist/cli/commands/start.d.ts.map +1 -1
  36. package/dist/cli/commands/start.js +2 -1
  37. package/dist/cli/commands/start.js.map +1 -1
  38. package/dist/cli/commands/worker.js +1 -1
  39. package/dist/cli/commands/worker.js.map +1 -1
  40. package/dist/cli/discover.d.ts +2 -0
  41. package/dist/cli/discover.d.ts.map +1 -1
  42. package/dist/cli/discover.js +19 -2
  43. package/dist/cli/discover.js.map +1 -1
  44. package/dist/events/dispatcher.d.ts +9 -0
  45. package/dist/events/dispatcher.d.ts.map +1 -1
  46. package/dist/events/dispatcher.js +36 -17
  47. package/dist/events/dispatcher.js.map +1 -1
  48. package/dist/events/pipeline-audit.d.ts +14 -0
  49. package/dist/events/pipeline-audit.d.ts.map +1 -0
  50. package/dist/events/pipeline-audit.js +29 -0
  51. package/dist/events/pipeline-audit.js.map +1 -0
  52. package/dist/events/worker.d.ts +3 -0
  53. package/dist/events/worker.d.ts.map +1 -1
  54. package/dist/events/worker.js +13 -11
  55. package/dist/events/worker.js.map +1 -1
  56. package/dist/execution/context-factory.d.ts.map +1 -1
  57. package/dist/execution/context-factory.js +3 -0
  58. package/dist/execution/context-factory.js.map +1 -1
  59. package/dist/flows/engine.d.ts.map +1 -1
  60. package/dist/flows/engine.js +2 -0
  61. package/dist/flows/engine.js.map +1 -1
  62. package/dist/runtime/bootstrap.d.ts +3 -1
  63. package/dist/runtime/bootstrap.d.ts.map +1 -1
  64. package/dist/runtime/bootstrap.js +19 -4
  65. package/dist/runtime/bootstrap.js.map +1 -1
  66. package/dist/runtime/load-extensions.d.ts +2 -1
  67. package/dist/runtime/load-extensions.d.ts.map +1 -1
  68. package/dist/runtime/load-extensions.js +8 -1
  69. package/dist/runtime/load-extensions.js.map +1 -1
  70. package/dist/runtime/start-worker-pool.d.ts.map +1 -1
  71. package/dist/runtime/start-worker-pool.js +1 -0
  72. package/dist/runtime/start-worker-pool.js.map +1 -1
  73. package/dist/server/bootstrap.d.ts +3 -0
  74. package/dist/server/bootstrap.d.ts.map +1 -1
  75. package/dist/server/bootstrap.js +20 -1
  76. package/dist/server/bootstrap.js.map +1 -1
  77. package/dist/testing/context.d.ts +2 -0
  78. package/dist/testing/context.d.ts.map +1 -1
  79. package/dist/testing/context.js +7 -3
  80. package/dist/testing/context.js.map +1 -1
  81. package/dist/types/context.d.ts +15 -1
  82. package/dist/types/context.d.ts.map +1 -1
  83. package/dist/types/index.d.ts +1 -1
  84. package/dist/types/index.d.ts.map +1 -1
  85. package/dist/types/index.js.map +1 -1
  86. package/dist/worker/bootstrap.d.ts.map +1 -1
  87. package/dist/worker/bootstrap.js +3 -0
  88. package/dist/worker/bootstrap.js.map +1 -1
  89. package/instructions/README.md +2 -1
  90. package/instructions/ai-classification.md +114 -0
  91. package/instructions/ai.md +28 -1
  92. package/instructions/peer-dependencies.md +1 -1
  93. package/package.json +6 -5
  94. package/dist/ai/__typecheck-fixtures__/legacy-cost-api.d.ts +0 -5
  95. package/dist/ai/__typecheck-fixtures__/legacy-cost-api.d.ts.map +0 -1
  96. package/dist/ai/__typecheck-fixtures__/legacy-cost-api.js +0 -15
  97. package/dist/ai/__typecheck-fixtures__/legacy-cost-api.js.map +0 -1
@@ -0,0 +1,114 @@
1
+ # AI classification: provider and model selection
2
+
3
+ Read this when implementing classification, categorization, label selection, or
4
+ TypeSafe/Jev and Laya integration. Requires **@plumbus/core 0.7.4+** (0.8 family: **0.8.0-beta.6+**) for the
5
+ `classify()` provider/model options. Use this recipe inside Plumbus capabilities
6
+ and flows; preserve their access policies and declare `effects.ai: true`.
7
+
8
+ ## Choose the operation
9
+
10
+ | Need | Operation |
11
+ | --- | --- |
12
+ | Matching labels from a known list, using a generative or decision model | `ctx.ai.classify()` → `string[]` |
13
+ | Typed choices, ordinal scores, probabilities, or mixed questions | `ctx.ai.decide()` → typed answers |
14
+ | Generated text or structured output from a prompt | `ctx.ai.generate()` |
15
+
16
+ Do not call vendor adapters directly for application business logic. Both native
17
+ classification and decisions use core validation, security, budgets, identity,
18
+ cancellation, and accounting. Predictions never replace authorization.
19
+
20
+ ## Register the provider
21
+
22
+ Install only the decision provider needed by the app:
23
+
24
+ ```bash
25
+ pnpm add @plumbus/core@~0.7.4 @plumbus/ai-decision-typesafe@~0.2.2
26
+ # For self-hosted Laya, use @plumbus/ai-decision-laya@~0.2.2 instead.
27
+ # 0.8 beta family: pnpm add @plumbus/core@plumbus-next @plumbus/ai-decision-typesafe@plumbus-next
28
+ ```
29
+
30
+ Export registration at the server boundary so API and workers share it:
31
+
32
+ ```ts
33
+ // app/server.ts
34
+ import { createTypeSafeDecisionAdapter } from '@plumbus/ai-decision-typesafe';
35
+
36
+ export const decisions = {
37
+ providers: {
38
+ typesafe: createTypeSafeDecisionAdapter({
39
+ apiKey: process.env.TYPESAFE_API_KEY ?? '',
40
+ model: 'jev-1.13.0',
41
+ }),
42
+ },
43
+ defaultProvider: 'typesafe',
44
+ };
45
+ ```
46
+
47
+ For Laya, register `laya: createLayaDecisionAdapter({ baseUrl, apiKey })` using the
48
+ factory from `@plumbus/ai-decision-laya`. Keep credentials and adapter construction
49
+ on the server. Laya requires a separately running service. For programmatic
50
+ bootstrap, pass `decisions` to `createServer()` / `buildWorkerAiService()` or
51
+ `createAIService()`. Decision adapters belong under `decisions.providers`, not the
52
+ text-completion `providers` map. Use distinct names across those two maps.
53
+
54
+ ## Select a provider and model per call
55
+
56
+ ```ts
57
+ // Inside a capability handler or flow step:
58
+ const labels = await ctx.ai.classify({
59
+ text: input.ticketText,
60
+ labels: ['billing', 'technical', 'refund'],
61
+ provider: 'typesafe',
62
+ model: 'jev-1.13.0',
63
+ threshold: 0.5,
64
+ signal: ctx.signal,
65
+ costContext: { projectId: input.projectId },
66
+ });
67
+ ```
68
+
69
+ `provider` is the registered map key; `model` is a model ID supported by that
70
+ endpoint. For Laya automatic language routing use `provider: 'laya', model: 'auto'`;
71
+ an explicit checkpoint must be configured on your Laya service.
72
+
73
+ | Setting | Resolution |
74
+ | --- | --- |
75
+ | Omitted `provider` | Existing default text provider, even when `decisions.defaultProvider` is set |
76
+ | Decision `model` | Per-call `model` → `decisions.defaultModel` → adapter default |
77
+ | Text `model` | Per-call `model` → AI service `defaultModel` → adapter default |
78
+ | Decision `threshold` | Inclusive probability cutoff in [0, 1], default 0.5 |
79
+
80
+ For a generative provider, pass its registered name and model and omit `threshold`:
81
+
82
+ ```ts
83
+ const labels = await ctx.ai.classify({
84
+ text: input.ticketText,
85
+ labels: ['billing', 'technical'],
86
+ provider: 'openai',
87
+ model: 'gpt-6-sol',
88
+ });
89
+ ```
90
+
91
+ Native classification accepts 1–256 nonempty labels, batches one independent
92
+ probability question per label, and returns matching labels in input order. Zero
93
+ or multiple matches are valid. `threshold` is rejected for text providers. Use
94
+ `decide()` with a choice question when exactly one choice and its distribution
95
+ are required; generative models are not a `decide()` backend.
96
+
97
+ ## Cost recording and tests
98
+
99
+ Persist the existing `onAICostRecorded` hook. Native classification records one
100
+ `operation: 'classify'` row per dispatched logical call, including failures, with
101
+ actual model, usage, cost, tenant/actor, and `costContext`. It does not create an
102
+ extra `decide` row. Unknown cost remains `null`; never invent zero to bypass a
103
+ budget. TypeSafe uses adapter pricing; Laya uses optional `costPerRequestUsd`.
104
+
105
+ Use `mockAI({ classify: ['billing'] })` through `createTestContext` and
106
+ `runCapability` / `simulateFlow` for application tests. Read the installed provider's
107
+ `instructions/README.md` for adapter tests. Live Laya inference is opt-in; keep it
108
+ out of routine tests.
109
+
110
+ After upgrading core, run `plumbus init --patch --agent all` and `plumbus doctor`
111
+ to refresh agent wiring to **v17**, preserving app-owned text outside managed blocks.
112
+
113
+ See [AI operations](ai.md), [instruction index](README.md), and the
114
+ [decision provider guide](https://github.com/plumbus-framework/plumbus/blob/main/docs/ai/decision-providers.md).
@@ -70,6 +70,11 @@ const invoice = await ctx.ai.extract({
70
70
 
71
71
  ### Classify
72
72
 
73
+ **Start with [the classification recipe](ai-classification.md)** for provider/model
74
+ selection, TypeSafe/Jev and Laya registration, defaults, thresholds, and cost hooks
75
+ (core **0.7.4+** / **0.8.0-beta.6+**). Use `classify()` for matching labels and `decide()` for richer
76
+ typed questions. Keep calls inside capabilities/flows.
77
+
73
78
  Classify text into provided categories:
74
79
 
75
80
  ```ts
@@ -115,7 +120,7 @@ await ctx.ai.generateWithUsage({
115
120
  });
116
121
  ```
117
122
 
118
- Omit `reasoning` to inherit prompt/config; use `null` to restore the provider/model default for one call, clearing both inherited `reasoning` and inherited legacy `reasoningEffort`. Explicit modes are `{ mode:'disabled' }`, `{ mode:'effort', effort:'minimal'|'low'|'medium'|'high'|'xhigh'|'max' }`, and `{ mode:'budget', maxTokens }`. Built-in core adapters translate the intent: OpenAI uses Chat Completions normally and switches caller-tool requests that need active/default GPT-5.6 reasoning to the Responses API; Anthropic uses `thinking` + `output_config.effort`. Responses tool continuations are stateless (`store:false`) and preserve encrypted reasoning items through server-owned `providerState`. Custom providers translate the contract in their own `AIProviderAdapter`. Unsupported modes fail with `AIInvalidRequestError` before provider I/O when the adapter can identify the incompatibility. Deprecated `reasoningEffort` remains the unchanged OpenAI-only `'low' | 'medium' | 'high'` shorthand.
123
+ Omit `reasoning` to inherit prompt/config; use `null` to restore the provider/model default for one call, clearing both inherited `reasoning` and inherited legacy `reasoningEffort`. Explicit modes are `{ mode:'disabled' }`, `{ mode:'effort', effort:'minimal'|'low'|'medium'|'high'|'xhigh'|'max' }`, and `{ mode:'budget', maxTokens }`. Built-in core adapters translate the intent: OpenAI uses Chat Completions normally and switches caller-tool requests that need active/default GPT-5.6 or GPT-6 reasoning to the Responses API; Anthropic uses `thinking` + `output_config.effort`. GPT-6 Chat Completions use `max_completion_tokens`; GPT-6 requests omit sampling temperature unless reasoning is explicitly disabled. Responses tool continuations are stateless (`store:false`) and preserve encrypted reasoning items through server-owned `providerState`. Custom providers translate the contract in their own `AIProviderAdapter`. Unsupported modes fail with `AIInvalidRequestError` before provider I/O when the adapter can identify the incompatibility. Deprecated `reasoningEffort` remains the unchanged OpenAI-only `'low' | 'medium' | 'high'` shorthand.
119
124
 
120
125
  ### Tool calling (provider-native)
121
126
 
@@ -382,3 +387,25 @@ See `docs/ai/ai-integration.md` and `docs/upgrading-contract-alignment.md` §12.
382
387
  - With security configured, generate/stream/extract/classify apply the field-classification policy. Extract/classify use the `text` field; arbitrary free-text PII is not automatically detected. Explainability stores redacted input.
383
388
  - Unknown prior spend rejects further requests when a dollar cap is configured. Local/unpriced providers still work without dollar caps; explicit free prices stay supported. Never supply fake zero costs to bypass budgets.
384
389
  - Read [the security release checklist](./upgrading-security-release.md) before upgrading custom cost hooks or AI wrappers.
390
+
391
+
392
+ ## Typed decisions (core 0.7.4+ / 0.8.0-beta.6+)
393
+
394
+ For choices, scores, and probabilities, use `ctx.ai.decide()` inside capabilities
395
+ and flows. Define reusable contracts with `defineDecision` from
396
+ `@plumbus/ai-decision`; CLI startup discovers `app/decisions/`. The shared contract
397
+ package is provided by core; install only the TypeSafe/Laya provider required by
398
+ the app. Export `decisions = { providers, defaultProvider }` from `app/server.ts`
399
+ for both API and workers, using `createTypeSafeDecisionAdapter` or
400
+ `createLayaDecisionAdapter` at that server-owned boundary. Do not register these
401
+ adapters as text-completion providers or call them directly for app business logic.
402
+
403
+ Core records `operation: 'decide'` with actual model, usage, cost, tenant/actor,
404
+ optional `decisionName`, and the caller's `costContext`. Existing
405
+ `onAICostRecorded(record, costContext, db)` hooks persist these rows; include the
406
+ new operation in any app-owned ledger enum/schema. Failed responses and cancelled
407
+ calls also produce rows. Unknown USD cost is null, never a free zero. Security
408
+ scans state and structured questions; budgets are checked before provider work.
409
+ Use `mockAI({ decide: result })` and test through `runCapability`/`simulateFlow`.
410
+
411
+ Guide: https://github.com/plumbus-framework/plumbus/blob/main/docs/ai/decision-providers.md
@@ -43,4 +43,4 @@ Run lint, format checking, typechecking, tests, and packed npm install checks be
43
43
 
44
44
  ## Consumer upgrade
45
45
 
46
- Read [upgrading-security-release.md](./upgrading-security-release.md) and the 0.8 notes in the root docs, explicitly select the new package versions for every installed Plumbus add-on, and run `plumbus init --patch` for agent wiring **v16**. Keep application business logic in Plumbus primitives and `ctx.*`; do not bypass security checks to make a migration pass.
46
+ Read [upgrading-security-release.md](./upgrading-security-release.md) and the 0.8 notes in the root docs, explicitly select the new package versions for every installed Plumbus add-on, and run `plumbus init --patch --agent all` for current agent wiring (**v17** with core 0.7.4+ / 0.8.0-beta.6+). For classification/provider/model selection, read [ai-classification.md](./ai-classification.md). Keep application business logic in Plumbus primitives and `ctx.*`; do not bypass security checks to make a migration pass.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumbus/core",
3
- "version": "0.8.0-beta.5",
3
+ "version": "0.8.0-beta.7",
4
4
  "description": "Plumbus framework core — types, SDK, runtime, CLI, test utilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -89,7 +89,8 @@
89
89
  "xml-crypto": "^6.1.2",
90
90
  "xpath": "^0.0.34",
91
91
  "zod": "^3.24.0",
92
- "zod-to-json-schema": "^3.25.2"
92
+ "zod-to-json-schema": "^3.25.2",
93
+ "@plumbus/ai-decision": "~0.3.0-beta.0"
93
94
  },
94
95
  "peerDependencies": {
95
96
  "@plumbus/api": ">=0.3.0-beta.0 <0.4.0",
@@ -121,10 +122,10 @@
121
122
  "@vitest/browser": "^3.0.0",
122
123
  "esbuild": "^0.25.12",
123
124
  "typescript": "^5.7.0",
124
- "@plumbus/api": "0.3.0-beta.0",
125
125
  "@plumbus/ai-bedrock": "0.3.0-beta.0",
126
- "@plumbus/voice": "0.6.0-beta.0",
127
- "@plumbus/mcp": "0.7.0-beta.0"
126
+ "@plumbus/api": "0.3.0-beta.0",
127
+ "@plumbus/mcp": "0.7.0-beta.0",
128
+ "@plumbus/voice": "0.6.0-beta.1"
128
129
  },
129
130
  "scripts": {
130
131
  "build": "tsc -b",
@@ -1,5 +0,0 @@
1
- import { type AIService, type RAGPipelineConfig, type RunToolLoopParams } from '@plumbus/core';
2
- export declare function legacyConsumer(ai: AIService, params: RunToolLoopParams): Promise<number>;
3
- export declare const legacyEmbeddingCallback: RAGPipelineConfig['onEmbeddingCost'];
4
- export declare const uncheckedEstimate: number;
5
- //# sourceMappingURL=legacy-cost-api.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"legacy-cost-api.d.ts","sourceRoot":"","sources":["../../../src/ai/__typecheck-fixtures__/legacy-cost-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAC;AAEvB,wBAAsB,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9F;AAED,eAAO,MAAM,uBAAuB,EAAE,iBAAiB,CAAC,iBAAiB,CAGxE,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,MAAyC,CAAC"}
@@ -1,15 +0,0 @@
1
- import { calculateModelCost, estimateModelCost, runToolLoop, } from '@plumbus/core';
2
- export async function legacyConsumer(ai, params) {
3
- const result = await ai.generateWithUsage({ prompt: 'p', input: {} });
4
- const cost = result.cost;
5
- const loop = await runToolLoop(ai, params);
6
- const total = loop.aggregatedCost;
7
- return cost + total + calculateModelCost(1, 1, 'local');
8
- }
9
- export const legacyEmbeddingCallback = (info) => {
10
- const numericCost = info.cost;
11
- void numericCost;
12
- };
13
- // @ts-expect-error Unknown-aware estimates cannot be treated as definitely priced.
14
- export const uncheckedEstimate = estimateModelCost(1, 1, 'local');
15
- //# sourceMappingURL=legacy-cost-api.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"legacy-cost-api.js","sourceRoot":"","sources":["../../../src/ai/__typecheck-fixtures__/legacy-cost-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,GAIZ,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAa,EAAE,MAAyB;IAC3E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,IAAI,GAAW,MAAM,CAAC,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAW,IAAI,CAAC,cAAc,CAAC;IAC1C,OAAO,IAAI,GAAG,KAAK,GAAG,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAyC,CAAC,IAAI,EAAE,EAAE;IACpF,MAAM,WAAW,GAAW,IAAI,CAAC,IAAI,CAAC;IACtC,KAAK,WAAW,CAAC;AACnB,CAAC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC"}