@senpi/runtime 3.0.146 → 3.0.149

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 (88) hide show
  1. package/dist/cli/guide-commands.d.ts.map +1 -1
  2. package/dist/cli/guide-commands.js +55 -0
  3. package/dist/cli/guide-commands.js.map +1 -1
  4. package/dist/cli/quant-command.d.ts +128 -0
  5. package/dist/cli/quant-command.d.ts.map +1 -0
  6. package/dist/cli/quant-command.js +345 -0
  7. package/dist/cli/quant-command.js.map +1 -0
  8. package/dist/cli/senpi-commands.d.ts +11 -0
  9. package/dist/cli/senpi-commands.d.ts.map +1 -1
  10. package/dist/cli/senpi-commands.js +49 -4
  11. package/dist/cli/senpi-commands.js.map +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +40 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/quant/engine/quantdesk/__init__.py +19 -0
  16. package/dist/quant/engine/quantdesk/__main__.py +281 -0
  17. package/dist/quant/engine/quantdesk/_version.py +24 -0
  18. package/dist/quant/engine/quantdesk/benchmark.py +90 -0
  19. package/dist/quant/engine/quantdesk/book.py +197 -0
  20. package/dist/quant/engine/quantdesk/deep.py +197 -0
  21. package/dist/quant/engine/quantdesk/desk.py +878 -0
  22. package/dist/quant/engine/quantdesk/dsl.py +224 -0
  23. package/dist/quant/engine/quantdesk/followups.py +117 -0
  24. package/dist/quant/engine/quantdesk/hl_api.py +473 -0
  25. package/dist/quant/engine/quantdesk/market.py +290 -0
  26. package/dist/quant/engine/quantdesk/mcp_client.py +158 -0
  27. package/dist/quant/engine/quantdesk/metrics.py +409 -0
  28. package/dist/quant/engine/quantdesk/opportunities.py +88 -0
  29. package/dist/quant/engine/quantdesk/render.py +787 -0
  30. package/dist/quant/engine/quantdesk/roundtrips.py +124 -0
  31. package/dist/quant/engine/quantdesk/score.py +817 -0
  32. package/dist/quant/engine/quantdesk/senpi_history.py +160 -0
  33. package/dist/quant/engine/quantdesk/smart_money.py +354 -0
  34. package/dist/quant/engine/quantdesk/strategy_read.py +292 -0
  35. package/dist/quant/engine/quantdesk/taxonomy.py +55 -0
  36. package/dist/quant/engine/quantdesk/timing.py +164 -0
  37. package/dist/quant/engine/quantdesk/voice.py +42 -0
  38. package/dist/quant/engine-runner.d.ts +133 -0
  39. package/dist/quant/engine-runner.d.ts.map +1 -0
  40. package/dist/quant/engine-runner.js +306 -0
  41. package/dist/quant/engine-runner.js.map +1 -0
  42. package/dist/quant/job.d.ts +125 -0
  43. package/dist/quant/job.d.ts.map +1 -0
  44. package/dist/quant/job.js +184 -0
  45. package/dist/quant/job.js.map +1 -0
  46. package/dist/quant/register.d.ts +53 -0
  47. package/dist/quant/register.d.ts.map +1 -0
  48. package/dist/quant/register.js +253 -0
  49. package/dist/quant/register.js.map +1 -0
  50. package/dist/quant/registry.d.ts +105 -0
  51. package/dist/quant/registry.d.ts.map +1 -0
  52. package/dist/quant/registry.js +248 -0
  53. package/dist/quant/registry.js.map +1 -0
  54. package/dist/quant/types.d.ts +216 -0
  55. package/dist/quant/types.d.ts.map +1 -0
  56. package/dist/quant/types.js +121 -0
  57. package/dist/quant/types.js.map +1 -0
  58. package/dist/skills-manager/manifest.js +1 -1
  59. package/dist/skills-manager/skills-manifest.json +73 -16
  60. package/dist/widgets/index.d.ts +8 -1
  61. package/dist/widgets/index.d.ts.map +1 -1
  62. package/dist/widgets/index.js +1 -0
  63. package/dist/widgets/index.js.map +1 -1
  64. package/dist/widgets/registry.d.ts +8 -0
  65. package/dist/widgets/registry.d.ts.map +1 -1
  66. package/dist/widgets/registry.js +26 -1
  67. package/dist/widgets/registry.js.map +1 -1
  68. package/dist/widgets/tool.d.ts +14 -4
  69. package/dist/widgets/tool.d.ts.map +1 -1
  70. package/dist/widgets/tool.js +36 -23
  71. package/dist/widgets/tool.js.map +1 -1
  72. package/dist/widgets/turn-cap.d.ts +33 -0
  73. package/dist/widgets/turn-cap.d.ts.map +1 -0
  74. package/dist/widgets/turn-cap.js +119 -0
  75. package/dist/widgets/turn-cap.js.map +1 -0
  76. package/dist/widgets/types.d.ts +33 -5
  77. package/dist/widgets/types.d.ts.map +1 -1
  78. package/dist/widgets/types.js +4 -3
  79. package/dist/widgets/types.js.map +1 -1
  80. package/dist/widgets/widgets/fund-user-wallet.d.ts.map +1 -1
  81. package/dist/widgets/widgets/fund-user-wallet.js +1 -0
  82. package/dist/widgets/widgets/fund-user-wallet.js.map +1 -1
  83. package/dist/widgets/widgets/quant-desk-recommendations.d.ts +52 -0
  84. package/dist/widgets/widgets/quant-desk-recommendations.d.ts.map +1 -0
  85. package/dist/widgets/widgets/quant-desk-recommendations.js +278 -0
  86. package/dist/widgets/widgets/quant-desk-recommendations.js.map +1 -0
  87. package/openclaw.plugin.json +12 -2
  88. package/package.json +4 -3
@@ -2,23 +2,80 @@
2
2
  "schemaVersion": 1,
3
3
  "defaults": {
4
4
  "repo": "https://github.com/Senpi-ai/senpi-skills",
5
- "branch": "main"
5
+ "branch": "dev"
6
6
  },
7
7
  "skills": [
8
- { "name": "senpi-trading-runtime", "maxMajor": 4 },
9
- { "name": "senpi-strategy-author", "maxMajor": 3, "preserve": ["strategies", "scripts/strategies"] },
10
- { "name": "senpi-strategy-discover", "maxMajor": 2, "preserve": ["strategies", "scripts/strategies"] },
11
- { "name": "senpi-strategy-ops", "maxMajor": 3, "preserve": ["strategies", "scripts/strategies"] },
12
- { "name": "senpi-portfolio", "maxMajor": 1 },
13
- { "name": "senpi-improve-trades", "maxMajor": 1 },
14
- { "name": "senpi-market-pulse", "maxMajor": 1 },
15
- { "name": "senpi-smart-money", "maxMajor": 1 },
16
- { "name": "quant-desk", "maxMajor": 1 },
17
- { "name": "senpi-signals", "maxMajor": 2 },
18
- { "name": "senpi-trader-research", "maxMajor": 1 },
19
- { "name": "senpi-trade", "maxMajor": 1 },
20
- { "name": "senpi-account-status", "maxMajor": 1 },
21
- { "name": "senpi-why", "maxMajor": 1 },
22
- { "name": "senpi-deposit-withdraw-transfer", "maxMajor": 1 }
8
+ {
9
+ "name": "senpi-trading-runtime",
10
+ "maxMajor": 4
11
+ },
12
+ {
13
+ "name": "senpi-strategy-author",
14
+ "maxMajor": 3,
15
+ "preserve": [
16
+ "strategies",
17
+ "scripts/strategies"
18
+ ]
19
+ },
20
+ {
21
+ "name": "senpi-strategy-discover",
22
+ "maxMajor": 2,
23
+ "preserve": [
24
+ "strategies",
25
+ "scripts/strategies"
26
+ ]
27
+ },
28
+ {
29
+ "name": "senpi-strategy-ops",
30
+ "maxMajor": 3,
31
+ "preserve": [
32
+ "strategies",
33
+ "scripts/strategies"
34
+ ]
35
+ },
36
+ {
37
+ "name": "senpi-portfolio",
38
+ "maxMajor": 1
39
+ },
40
+ {
41
+ "name": "senpi-improve-trades",
42
+ "maxMajor": 1
43
+ },
44
+ {
45
+ "name": "senpi-market-pulse",
46
+ "maxMajor": 1
47
+ },
48
+ {
49
+ "name": "senpi-smart-money",
50
+ "maxMajor": 1
51
+ },
52
+ {
53
+ "name": "quant-desk",
54
+ "maxMajor": 2
55
+ },
56
+ {
57
+ "name": "senpi-signals",
58
+ "maxMajor": 2
59
+ },
60
+ {
61
+ "name": "senpi-trader-research",
62
+ "maxMajor": 1
63
+ },
64
+ {
65
+ "name": "senpi-trade",
66
+ "maxMajor": 1
67
+ },
68
+ {
69
+ "name": "senpi-account-status",
70
+ "maxMajor": 1
71
+ },
72
+ {
73
+ "name": "senpi-why",
74
+ "maxMajor": 1
75
+ },
76
+ {
77
+ "name": "senpi-deposit-withdraw-transfer",
78
+ "maxMajor": 1
79
+ }
23
80
  ]
24
81
  }
@@ -1,10 +1,11 @@
1
1
  import type { WidgetLogger } from "./types.js";
2
+ import type { QuantRunReader } from "../quant/types.js";
2
3
  export { WIDGET_SPECS, buildWidgetRegistry } from "./registry.js";
3
4
  export type { WidgetRegistry, WidgetsConfig } from "./registry.js";
4
5
  export { WidgetValidationError } from "./errors.js";
5
6
  export { SHOW_WIDGET_TOOL_NAME, buildShowWidgetDescription, buildShowWidgetParameters, createShowWidgetTool, } from "./tool.js";
6
7
  export type { ShowWidgetTool, ShowWidgetToolResult } from "./tool.js";
7
- export type { RegisteredWidget, WidgetPayload, WidgetResult, WidgetSpec } from "./types.js";
8
+ export type { RegisteredWidget, WidgetHandlerContext, WidgetPayload, WidgetResult, WidgetSpec } from "./types.js";
8
9
  /** The slice of the OpenClaw plugin API this module needs. */
9
10
  export interface WidgetToolPluginApi {
10
11
  registerTool(tool: (ctx: {
@@ -19,6 +20,12 @@ export interface RegisterShowWidgetToolOptions {
19
20
  /** The plugin config `widgets` block: `{ "<widget_type>": boolean }`. */
20
21
  widgetsConfig?: unknown;
21
22
  logger?: WidgetLogger;
23
+ /**
24
+ * The quant desk's run registry (read side), for `quant_desk_recommendations`. Absent when the
25
+ * desk failed to build: the tool still registers, and that type answers with a teaching error
26
+ * telling the model to relay the desk's next steps as text.
27
+ */
28
+ quantRuns?: QuantRunReader;
22
29
  }
23
30
  /**
24
31
  * Register `show_widget` as a plugin tool factory.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/widgets/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5F,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,YAAY,CACV,IAAI,EAAE,CAAC,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,EAC9C,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC9C,IAAI,CAAC;CACT;AAED,MAAM,WAAW,6BAA6B;IAC5C,GAAG,EAAE,mBAAmB,CAAC;IACzB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CA0BtF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/widgets/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAClE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAElH,8DAA8D;AAC9D,MAAM,WAAW,mBAAmB;IAClC,YAAY,CACV,IAAI,EAAE,CAAC,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,EAC9C,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAC9C,IAAI,CAAC;CACT;AAED,MAAM,WAAW,6BAA6B;IAC5C,GAAG,EAAE,mBAAmB,CAAC;IACzB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,6BAA6B,GAAG,OAAO,CA2BtF"}
@@ -26,6 +26,7 @@ export function registerShowWidgetTool(options) {
26
26
  registry,
27
27
  logger,
28
28
  sessionId: ctx?.sessionId,
29
+ handlerContext: options.quantRuns ? { quantRuns: options.quantRuns } : {},
29
30
  }), { names: [SHOW_WIDGET_TOOL_NAME] });
30
31
  logger?.info(`[senpi-widgets] ${SHOW_WIDGET_TOOL_NAME} registered | widget_types=${enabled.join(",")}`);
31
32
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/widgets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAmBnB;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAsC;IAC3E,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChC,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;IACxC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,CACV,6FAA6F,CAC9F,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACpC,GAAG,CAAC,YAAY,CACd,CAAC,GAA2B,EAAE,EAAE,CAC9B,oBAAoB,CAAC;QACnB,QAAQ;QACR,MAAM;QACN,SAAS,EAAE,GAAG,EAAE,SAAS;KAC1B,CAAC,EACJ,EAAE,KAAK,EAAE,CAAC,qBAAqB,CAAC,EAAE,CACnC,CAAC;IACF,MAAM,EAAE,IAAI,CACV,mBAAmB,qBAAqB,8BAA8B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC1F,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/widgets/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAInB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,WAAW,CAAC;AAyBnB;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAsC;IAC3E,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChC,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;IACxC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,EAAE,IAAI,CACV,6FAA6F,CAC9F,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IACD,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IACpC,GAAG,CAAC,YAAY,CACd,CAAC,GAA2B,EAAE,EAAE,CAC9B,oBAAoB,CAAC;QACnB,QAAQ;QACR,MAAM;QACN,SAAS,EAAE,GAAG,EAAE,SAAS;QACzB,cAAc,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE;KAC1E,CAAC,EACJ,EAAE,KAAK,EAAE,CAAC,qBAAqB,CAAC,EAAE,CACnC,CAAC;IACF,MAAM,EAAE,IAAI,CACV,mBAAmB,qBAAqB,8BAA8B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAC1F,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -20,5 +20,13 @@ export interface WidgetRegistry {
20
20
  get(widgetType: string): RegisteredWidget | undefined;
21
21
  enabledTypes(): string[];
22
22
  }
23
+ /**
24
+ * Resolve the spec list against plugin config.
25
+ *
26
+ * @param config The plugin config `widgets` block (see {@link WidgetsConfig}).
27
+ * @param specs The spec list; defaults to {@link WIDGET_SPECS}. Injected by tests.
28
+ * @throws Error when two specs share a `widget_type`, when two specs declare the same extra
29
+ * parameter name, or when a spec declares `widget_type` as an extra parameter.
30
+ */
23
31
  export declare function buildWidgetRegistry(config?: unknown, specs?: readonly WidgetSpec[]): WidgetRegistry;
24
32
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/widgets/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG/D;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAAyB,CAAC;AAExE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,GAAG,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACnC,yEAAyE;IACzE,OAAO,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACvC,+CAA+C;IAC/C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACtD,YAAY,IAAI,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CACjC,MAAM,CAAC,EAAE,OAAO,EAChB,KAAK,GAAE,SAAS,UAAU,EAAiB,GAC1C,cAAc,CAyBhB"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/widgets/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI/D;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAAuD,CAAC;AAEtG;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,GAAG,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACnC,yEAAyE;IACzE,OAAO,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACvC,+CAA+C;IAC/C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACtD,YAAY,IAAI,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,CAAC,EAAE,OAAO,EAChB,KAAK,GAAE,SAAS,UAAU,EAAiB,GAC1C,cAAc,CAyChB"}
@@ -1,11 +1,36 @@
1
1
  import { fundUserWalletSpec } from "./widgets/fund-user-wallet.js";
2
+ import { quantDeskRecommendationsSpec } from "./widgets/quant-desk-recommendations.js";
2
3
  /**
3
4
  * Every widget type this plugin can render. Adding one here adds it to the
4
5
  * `show_widget` enum, to the generated tool description, and to the config
5
6
  * gate — the tool name and the manifest are untouched.
6
7
  */
7
- export const WIDGET_SPECS = [fundUserWalletSpec];
8
+ export const WIDGET_SPECS = [fundUserWalletSpec, quantDeskRecommendationsSpec];
9
+ /**
10
+ * Resolve the spec list against plugin config.
11
+ *
12
+ * @param config The plugin config `widgets` block (see {@link WidgetsConfig}).
13
+ * @param specs The spec list; defaults to {@link WIDGET_SPECS}. Injected by tests.
14
+ * @throws Error when two specs share a `widget_type`, when two specs declare the same extra
15
+ * parameter name, or when a spec declares `widget_type` as an extra parameter.
16
+ */
8
17
  export function buildWidgetRegistry(config, specs = WIDGET_SPECS) {
18
+ // Parameters are one flat object shared by every type, so each extra name has exactly one owner.
19
+ // Checked over ALL specs, not just enabled ones: a clash hidden while one type is disabled would
20
+ // surface the day config flips it on.
21
+ const paramOwner = new Map();
22
+ for (const spec of specs) {
23
+ for (const key of Object.keys(spec.extraParameters ?? {})) {
24
+ if (key === "widget_type") {
25
+ throw new Error(`show_widget: ${spec.widgetType} declares "widget_type" as an extra parameter; it is the shared discriminator`);
26
+ }
27
+ const owner = paramOwner.get(key);
28
+ if (owner) {
29
+ throw new Error(`show_widget: parameter "${key}" is declared by both ${owner} and ${spec.widgetType}; each name has one owner`);
30
+ }
31
+ paramOwner.set(key, spec.widgetType);
32
+ }
33
+ }
9
34
  const gate = config && typeof config === "object" && !Array.isArray(config)
10
35
  ? config
11
36
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/widgets/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,kBAAkB,CAAC,CAAC;AAmBxE,MAAM,UAAU,mBAAmB,CACjC,MAAgB,EAChB,QAA+B,YAAY;IAE3C,MAAM,IAAI,GACR,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,OAAO,GAAuB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,GAAG,IAAI;QACP,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,KAAK;KAC3C,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,sDAAsD,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO;QACL,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO;QAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;QACtB,GAAG,EAAE,CAAC,UAAkB,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;QACnD,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;KACrD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/widgets/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AAEvF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,kBAAkB,EAAE,4BAA4B,CAAC,CAAC;AAmBtG;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAgB,EAChB,QAA+B,YAAY;IAE3C,iGAAiG;IACjG,iGAAiG;IACjG,sCAAsC;IACtC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1D,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,UAAU,+EAA+E,CAAC,CAAC;YAClI,CAAC;YACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,yBAAyB,KAAK,QAAQ,IAAI,CAAC,UAAU,2BAA2B,CAAC,CAAC;YAClI,CAAC;YACD,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GACR,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAC5D,CAAC,CAAE,MAAkC;QACrC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,OAAO,GAAuB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,GAAG,IAAI;QACP,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,KAAK;KAC3C,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,sDAAsD,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO;QACL,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO;QAClB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;QACtB,GAAG,EAAE,CAAC,UAAkB,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;QACnD,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;KACrD,CAAC;AACJ,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { WidgetRegistry } from "./registry.js";
2
- import type { WidgetLogger, WidgetPayload } from "./types.js";
2
+ import type { WidgetHandlerContext, WidgetLogger, WidgetPayload } from "./types.js";
3
3
  /**
4
4
  * The plugin's single agent tool. The name is static — new widget types are
5
5
  * new `widget_type` enum values, never new tools — so it is declared once in
@@ -24,25 +24,35 @@ export interface CreateShowWidgetToolOptions {
24
24
  logger?: WidgetLogger;
25
25
  /** Ephemeral session id from the plugin tool factory context; logged only. */
26
26
  sessionId?: string;
27
+ /** Collaborators handed to every handler (e.g. the quant run reader). Defaults to `{}`. */
28
+ handlerContext?: WidgetHandlerContext;
27
29
  }
28
30
  /**
29
31
  * Tool description, generated from the enabled specs. Nothing else teaches the
30
32
  * model about these cards, so this text carries the condition that should make
31
33
  * it call the tool, not just the shape of the call.
34
+ *
35
+ * The shared header claims nothing that is true of only one type: how a card is
36
+ * acted on (`card:`) and which fields it takes (`fields:`) are stated per type,
37
+ * because not every card has a button and not every type takes widget_type only.
32
38
  */
33
39
  export declare function buildShowWidgetDescription(registry: WidgetRegistry): string;
34
40
  /**
35
41
  * Declared JSON schema: one flat object, no unions at any depth.
36
42
  *
37
43
  * OpenClaw flattens top-level unions, Gemini flattens nested ones, and OpenAI
38
- * strict mode rejects a schema containing one anywhere. `widget_type` is the
39
- * only parameter, and it is required.
44
+ * strict mode rejects a schema containing one anywhere. So there is no per-type
45
+ * branch: `widget_type` is the one required property, and every enabled spec's
46
+ * `extraParameters` are merged in beside it as optional properties. Each such
47
+ * property belongs to one type (the registry refuses a shared name) and is
48
+ * validated by that type's handler; `rejectExtraFields` refuses one sent with
49
+ * any other type.
40
50
  */
41
51
  export declare function buildShowWidgetParameters(registry: WidgetRegistry): Record<string, unknown>;
42
52
  /**
43
53
  * Build the `show_widget` tool for one agent turn. `sessionId` comes from the
44
54
  * plugin tool factory context and is used for logging only — nothing about the
45
- * result depends on it.
55
+ * result depends on it. `handlerContext` is passed to every handler as-is.
46
56
  */
47
57
  export declare function createShowWidgetTool(options: CreateShowWidgetToolOptions): ShowWidgetTool;
48
58
  //# sourceMappingURL=tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/widgets/tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAoB,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAInD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAsB3E;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiB3F;AAmED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,cAAc,CAkCzF"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/widgets/tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAoB,oBAAoB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtG;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAInD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2FAA2F;IAC3F,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAwB3E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc3F;AAuED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,cAAc,CAmCzF"}
@@ -10,6 +10,10 @@ const WIDGET_TYPE_PARAM = "widget_type";
10
10
  * Tool description, generated from the enabled specs. Nothing else teaches the
11
11
  * model about these cards, so this text carries the condition that should make
12
12
  * it call the tool, not just the shape of the call.
13
+ *
14
+ * The shared header claims nothing that is true of only one type: how a card is
15
+ * acted on (`card:`) and which fields it takes (`fields:`) are stated per type,
16
+ * because not every card has a button and not every type takes widget_type only.
13
17
  */
14
18
  export function buildShowWidgetDescription(registry) {
15
19
  const widgets = registry.enabled();
@@ -17,16 +21,18 @@ export function buildShowWidgetDescription(registry) {
17
21
  return "Render a Senpi UI card in the user's chat.\n\nNo widget types are enabled on this deployment.";
18
22
  }
19
23
  const lines = [
20
- "Render a Senpi UI card in the user's chat. The card is live UI: its button runs the flow, so showing it is how the user acts.",
24
+ "Render a Senpi UI card in the user's chat.",
21
25
  "",
22
26
  "Call it yourself as part of your answer — the user does not have to ask for a card. Each type below states when to call it; the examples illustrate that rule, they are not a checklist to match.",
23
27
  "",
24
- `Pass ${WIDGET_TYPE_PARAM} and nothing else.`,
28
+ `Pass ${WIDGET_TYPE_PARAM} plus the fields listed for that type, and nothing else.`,
25
29
  "",
26
30
  "Widget types:",
27
31
  ];
28
32
  for (const widget of widgets) {
29
33
  lines.push(`- ${widget.widgetType}: ${widget.description}`);
34
+ lines.push(` card: ${widget.affordance}`);
35
+ lines.push(` fields: ${widget.fields ?? `none — ${WIDGET_TYPE_PARAM} only`}`);
30
36
  lines.push(` when: ${widget.callWhen}`);
31
37
  lines.push(` not this card: ${widget.notFor}`);
32
38
  lines.push(" for example:");
@@ -38,26 +44,28 @@ export function buildShowWidgetDescription(registry) {
38
44
  * Declared JSON schema: one flat object, no unions at any depth.
39
45
  *
40
46
  * OpenClaw flattens top-level unions, Gemini flattens nested ones, and OpenAI
41
- * strict mode rejects a schema containing one anywhere. `widget_type` is the
42
- * only parameter, and it is required.
47
+ * strict mode rejects a schema containing one anywhere. So there is no per-type
48
+ * branch: `widget_type` is the one required property, and every enabled spec's
49
+ * `extraParameters` are merged in beside it as optional properties. Each such
50
+ * property belongs to one type (the registry refuses a shared name) and is
51
+ * validated by that type's handler; `rejectExtraFields` refuses one sent with
52
+ * any other type.
43
53
  */
44
54
  export function buildShowWidgetParameters(registry) {
45
55
  const widgets = registry.enabled();
46
56
  if (widgets.length === 0) {
47
57
  throw new Error("show_widget has no enabled widget types; do not register the tool");
48
58
  }
49
- return {
50
- type: "object",
51
- properties: {
52
- [WIDGET_TYPE_PARAM]: {
53
- type: "string",
54
- enum: widgets.map((w) => w.widgetType),
55
- description: "Which card to render.",
56
- },
59
+ const properties = {
60
+ [WIDGET_TYPE_PARAM]: {
61
+ type: "string",
62
+ enum: widgets.map((w) => w.widgetType),
63
+ description: "Which card to render.",
57
64
  },
58
- required: [WIDGET_TYPE_PARAM],
59
- additionalProperties: false,
60
65
  };
66
+ for (const widget of widgets)
67
+ Object.assign(properties, widget.extraParameters ?? {});
68
+ return { type: "object", properties, required: [WIDGET_TYPE_PARAM], additionalProperties: false };
61
69
  }
62
70
  function availableTypesSentence(registry) {
63
71
  const types = registry.enabledTypes();
@@ -90,24 +98,28 @@ function resolveWidget(registry, args) {
90
98
  return widget;
91
99
  }
92
100
  /**
93
- * The tool takes one argument, so any other key is a field the model invented.
94
- * Every one is named in a single message: the correction is the same for all of
95
- * them, and the model can apply it in one retry.
101
+ * A type takes `widget_type` plus its own `extraParameters`, so any other key is
102
+ * a field the model invented — or one that belongs to another type, which the
103
+ * merged schema cannot refuse on its own. Every one is named in a single
104
+ * message, with the fields this type does take: the correction is the same for
105
+ * all of them, and the model can apply it in one retry.
96
106
  */
97
107
  function rejectExtraFields(widget, args) {
98
- const unexpected = Object.keys(args).filter((key) => key !== WIDGET_TYPE_PARAM);
108
+ const allowed = [WIDGET_TYPE_PARAM, ...Object.keys(widget.extraParameters ?? {})];
109
+ const unexpected = Object.keys(args).filter((key) => !allowed.includes(key));
99
110
  if (unexpected.length === 0)
100
111
  return;
112
+ const takes = allowed.length === 1 ? `${WIDGET_TYPE_PARAM} only` : `${allowed.join(", ")} for ${widget.widgetType}`;
101
113
  throw new WidgetValidationError(`show_widget failed for ${WIDGET_TYPE_PARAM} "${widget.widgetType}": unexpected fields: ` +
102
- `${unexpected.join(", ")}. show_widget takes ${WIDGET_TYPE_PARAM} only — drop them and call it again.`, widget.widgetType, unexpected);
114
+ `${unexpected.join(", ")}. show_widget takes ${takes} — drop them and call it again.`, widget.widgetType, unexpected);
103
115
  }
104
116
  /**
105
117
  * Build the `show_widget` tool for one agent turn. `sessionId` comes from the
106
118
  * plugin tool factory context and is used for logging only — nothing about the
107
- * result depends on it.
119
+ * result depends on it. `handlerContext` is passed to every handler as-is.
108
120
  */
109
121
  export function createShowWidgetTool(options) {
110
- const { registry, logger, sessionId } = options;
122
+ const { registry, logger, sessionId, handlerContext } = options;
111
123
  const session = sessionId ?? "(unknown)";
112
124
  return {
113
125
  name: SHOW_WIDGET_TOOL_NAME,
@@ -118,8 +130,9 @@ export function createShowWidgetTool(options) {
118
130
  const args = toArgs(params);
119
131
  const widget = resolveWidget(registry, args);
120
132
  rejectExtraFields(widget, args);
121
- const result = await widget.handler();
122
- logger?.info(`[senpi-widgets] widget shown | widget_type=${widget.widgetType} widget_version=${widget.widgetVersion} session=${session}`);
133
+ const result = await widget.handler(args, handlerContext ?? {});
134
+ logger?.info(`[senpi-widgets] widget shown | widget_type=${widget.widgetType} widget_version=${widget.widgetVersion}` +
135
+ `${typeof args.run_id === "string" ? ` run_id=${args.run_id}` : ""} session=${session}`);
123
136
  return {
124
137
  content: [{ type: "text", text: result.text }],
125
138
  details: result.payload,
@@ -1 +1 @@
1
- {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/widgets/tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/widgets/tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /** How long a run's entry is kept after its last touch. */
2
+ export declare const TURN_CAP_TTL_MS: number;
3
+ /** The reason the model reads on a blocked call. */
4
+ export declare const TURN_CAP_BLOCK_REASON = "[E_WIDGET_TURN_CAP] recommendation cards were already shown in this answer; fold anything else into text.";
5
+ /** The cap's two hook bodies, exposed for tests. */
6
+ export interface QuantWidgetTurnCap {
7
+ beforeToolCall(event: unknown, ctx?: unknown): {
8
+ block: true;
9
+ blockReason: string;
10
+ } | undefined;
11
+ afterToolCall(event: unknown, ctx?: unknown): void;
12
+ trackedRuns(): number;
13
+ }
14
+ /** Build the cap's state machine. `now` is injected so expiry is testable. */
15
+ export declare function createQuantWidgetTurnCap(opts: {
16
+ now(): number;
17
+ ttlMs?: number;
18
+ }): QuantWidgetTurnCap;
19
+ /** The slice of the plugin API the cap needs. */
20
+ export interface TurnCapPluginApi {
21
+ on(hookName: string, handler: (...args: unknown[]) => unknown, opts?: {
22
+ priority?: number;
23
+ }): void;
24
+ }
25
+ /** Register the cap on `before_tool_call` / `after_tool_call`. Fails open on any internal error. */
26
+ export declare function registerQuantWidgetTurnCap(api: TurnCapPluginApi, opts: {
27
+ now(): number;
28
+ logger?: {
29
+ info(...a: unknown[]): void;
30
+ warn(...a: unknown[]): void;
31
+ };
32
+ }): QuantWidgetTurnCap;
33
+ //# sourceMappingURL=turn-cap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-cap.d.ts","sourceRoot":"","sources":["../../src/widgets/turn-cap.ts"],"names":[],"mappings":"AA2BA,2DAA2D;AAC3D,eAAO,MAAM,eAAe,QAAc,CAAC;AAC3C,oDAAoD;AACpD,eAAO,MAAM,qBAAqB,8GAC2E,CAAC;AAe9G,oDAAoD;AACpD,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAChG,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnD,WAAW,IAAI,MAAM,CAAC;CACvB;AAmBD,8EAA8E;AAC9E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAAE,GAAG,IAAI,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,kBAAkB,CAwCpG;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpG;AAED,oGAAoG;AACpG,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE;IAAE,GAAG,IAAI,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,GAC7F,kBAAkB,CAoBpB"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Per-run cap on `quant_desk_recommendations` (spec D8).
3
+ *
4
+ * `maxItems` bounds one call; a model that wants seven cards parallelises instead (field finding
5
+ * 4). Tool factories carry no run id, hooks do, so the cap lives in `before_tool_call`: while a
6
+ * quant card call is in flight or has succeeded in an agent run, any further one in that run is
7
+ * blocked with a teaching reason. `after_tool_call` makes the cap exact rather than a counter: a
8
+ * FAILED call (a mistyped run id) frees the slot so the corrected retry renders, and the after-event
9
+ * of a call the cap itself blocked is ignored (matched by toolCallId). Entries expire after 10 min.
10
+ * No run id from the host → fail open. The hooks never throw into the tool pipeline.
11
+ *
12
+ * Host shapes (OpenClaw `PluginHookBeforeToolCallEvent` / `PluginHookAfterToolCallEvent` /
13
+ * `PluginHookToolContext`): both the event and the ctx carry optional `runId` and `toolCallId`, so
14
+ * the event is read first and the ctx is the fallback. The event carries `toolName` and `params`;
15
+ * the after-event adds `result` and `error` (a string, set when the tool threw or returned an error
16
+ * result — `show_widget` throws on every refusal). A `{ block, blockReason }` return from
17
+ * `before_tool_call` stops the call and hands `blockReason` to the model as the tool error.
18
+ *
19
+ * Parallel calls in one assistant message (the fleet model's way past `maxItems`) all reach
20
+ * `before_tool_call` before any `after_tool_call`; the in-flight `pendingCallId` is what blocks
21
+ * the second one in that window.
22
+ */
23
+ import { SHOW_WIDGET_TOOL_NAME } from "./tool.js";
24
+ const QUANT_WIDGET_TYPE = "quant_desk_recommendations";
25
+ /** The call id recorded when the host supplies none; it cannot identify a call on its own. */
26
+ const UNKNOWN_CALL_ID = "(unknown)";
27
+ /** How long a run's entry is kept after its last touch. */
28
+ export const TURN_CAP_TTL_MS = 10 * 60_000;
29
+ /** The reason the model reads on a blocked call. */
30
+ export const TURN_CAP_BLOCK_REASON = "[E_WIDGET_TURN_CAP] recommendation cards were already shown in this answer; fold anything else into text.";
31
+ function str(x) {
32
+ return typeof x === "string" && x.length > 0 ? x : undefined;
33
+ }
34
+ function read(event, ctx) {
35
+ const ev = (event && typeof event === "object" ? event : {});
36
+ const c = (ctx && typeof ctx === "object" ? ctx : {});
37
+ const params = ev.params && typeof ev.params === "object" ? ev.params : undefined;
38
+ const runId = str(ev.runId) ?? str(c.runId);
39
+ return {
40
+ ev,
41
+ ...(runId ? { runId } : {}),
42
+ callId: str(ev.toolCallId) ?? str(c.toolCallId) ?? UNKNOWN_CALL_ID,
43
+ isQuant: ev.toolName === SHOW_WIDGET_TOOL_NAME && params?.widget_type === QUANT_WIDGET_TYPE,
44
+ };
45
+ }
46
+ /** Build the cap's state machine. `now` is injected so expiry is testable. */
47
+ export function createQuantWidgetTurnCap(opts) {
48
+ const ttl = opts.ttlMs ?? TURN_CAP_TTL_MS;
49
+ const runs = new Map();
50
+ const sweep = () => {
51
+ const cutoff = opts.now() - ttl;
52
+ for (const [k, e] of runs)
53
+ if (e.touchedAt <= cutoff)
54
+ runs.delete(k);
55
+ };
56
+ return {
57
+ beforeToolCall(event, ctx) {
58
+ const { runId, callId, isQuant } = read(event, ctx);
59
+ if (!isQuant || !runId)
60
+ return undefined;
61
+ sweep();
62
+ const entry = runs.get(runId);
63
+ if (entry && (entry.shown || entry.pendingCallId !== undefined)) {
64
+ entry.touchedAt = opts.now();
65
+ return { block: true, blockReason: TURN_CAP_BLOCK_REASON };
66
+ }
67
+ runs.set(runId, { shown: false, pendingCallId: callId, touchedAt: opts.now() });
68
+ return undefined;
69
+ },
70
+ afterToolCall(event, ctx) {
71
+ // No `isQuant` gate here: only a quant call can have set `pendingCallId`, so the toolCallId
72
+ // match is the identity. Re-deriving it from `params` would leave the entry pending forever
73
+ // when a host's after-event omits or empties them. The one exception is a call the host gave
74
+ // no id: then "(unknown)" matches any id-less event, so the tool itself must be the quant one.
75
+ const { ev, runId, callId, isQuant } = read(event, ctx);
76
+ if (!runId)
77
+ return;
78
+ const entry = runs.get(runId);
79
+ if (!entry || entry.pendingCallId !== callId)
80
+ return;
81
+ if (callId === UNKNOWN_CALL_ID && !isQuant)
82
+ return;
83
+ if (ev.error !== undefined && ev.error !== null && ev.error !== "") {
84
+ runs.delete(runId);
85
+ return;
86
+ }
87
+ entry.shown = true;
88
+ entry.pendingCallId = undefined;
89
+ entry.touchedAt = opts.now();
90
+ },
91
+ trackedRuns: () => runs.size,
92
+ };
93
+ }
94
+ /** Register the cap on `before_tool_call` / `after_tool_call`. Fails open on any internal error. */
95
+ export function registerQuantWidgetTurnCap(api, opts) {
96
+ const cap = createQuantWidgetTurnCap(opts);
97
+ api.on("before_tool_call", (event, ctx) => {
98
+ try {
99
+ const verdict = cap.beforeToolCall(event, ctx);
100
+ if (verdict)
101
+ opts.logger?.info(`[senpi-widgets] turn cap blocked a second ${QUANT_WIDGET_TYPE} call`);
102
+ return verdict;
103
+ }
104
+ catch (err) {
105
+ opts.logger?.warn(`[senpi-widgets] turn cap failed open: ${err instanceof Error ? err.message : String(err)}`);
106
+ return undefined;
107
+ }
108
+ });
109
+ api.on("after_tool_call", (event, ctx) => {
110
+ try {
111
+ cap.afterToolCall(event, ctx);
112
+ }
113
+ catch {
114
+ // the cap never breaks the tool pipeline
115
+ }
116
+ });
117
+ return cap;
118
+ }
119
+ //# sourceMappingURL=turn-cap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-cap.js","sourceRoot":"","sources":["../../src/widgets/turn-cap.ts"],"names":[],"mappings":"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"}