@senpi/runtime 3.0.81 → 3.0.83

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 (102) hide show
  1. package/dist/actions/decision-engine.d.ts +16 -0
  2. package/dist/actions/decision-engine.d.ts.map +1 -1
  3. package/dist/actions/decision-engine.js +137 -1
  4. package/dist/actions/decision-engine.js.map +1 -1
  5. package/dist/cli/guide-commands.d.ts.map +1 -1
  6. package/dist/cli/guide-commands.js +33 -0
  7. package/dist/cli/guide-commands.js.map +1 -1
  8. package/dist/cli/senpi-commands.d.ts.map +1 -1
  9. package/dist/cli/senpi-commands.js +12 -0
  10. package/dist/cli/senpi-commands.js.map +1 -1
  11. package/dist/cli/update-command.d.ts +70 -0
  12. package/dist/cli/update-command.d.ts.map +1 -0
  13. package/dist/cli/update-command.js +132 -0
  14. package/dist/cli/update-command.js.map +1 -0
  15. package/dist/dsl/plugin/index.d.ts +35 -1
  16. package/dist/dsl/plugin/index.d.ts.map +1 -1
  17. package/dist/dsl/plugin/index.js +62 -7
  18. package/dist/dsl/plugin/index.js.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +87 -6
  21. package/dist/index.js.map +1 -1
  22. package/dist/runtime/effective-config.d.ts +67 -0
  23. package/dist/runtime/effective-config.d.ts.map +1 -0
  24. package/dist/runtime/effective-config.js +324 -0
  25. package/dist/runtime/effective-config.js.map +1 -0
  26. package/dist/runtime/lifecycle-events.d.ts +19 -0
  27. package/dist/runtime/lifecycle-events.d.ts.map +1 -1
  28. package/dist/runtime/lifecycle-events.js +27 -0
  29. package/dist/runtime/lifecycle-events.js.map +1 -1
  30. package/dist/runtime/rebuild-errors.d.ts +26 -0
  31. package/dist/runtime/rebuild-errors.d.ts.map +1 -0
  32. package/dist/runtime/rebuild-errors.js +36 -0
  33. package/dist/runtime/rebuild-errors.js.map +1 -0
  34. package/dist/runtime/run.d.ts +10 -0
  35. package/dist/runtime/run.d.ts.map +1 -1
  36. package/dist/runtime/run.js +13 -1
  37. package/dist/runtime/run.js.map +1 -1
  38. package/dist/runtime/runtime.d.ts +99 -1
  39. package/dist/runtime/runtime.d.ts.map +1 -1
  40. package/dist/runtime/runtime.js +321 -127
  41. package/dist/runtime/runtime.js.map +1 -1
  42. package/dist/runtime/update-apply-deps.d.ts +43 -0
  43. package/dist/runtime/update-apply-deps.d.ts.map +1 -0
  44. package/dist/runtime/update-apply-deps.js +62 -0
  45. package/dist/runtime/update-apply-deps.js.map +1 -0
  46. package/dist/runtime/update-handler.d.ts +158 -0
  47. package/dist/runtime/update-handler.d.ts.map +1 -0
  48. package/dist/runtime/update-handler.js +252 -0
  49. package/dist/runtime/update-handler.js.map +1 -0
  50. package/dist/runtime/update-plan.d.ts +60 -0
  51. package/dist/runtime/update-plan.d.ts.map +1 -0
  52. package/dist/runtime/update-plan.js +164 -0
  53. package/dist/runtime/update-plan.js.map +1 -0
  54. package/dist/runtime/update-register.d.ts +72 -0
  55. package/dist/runtime/update-register.d.ts.map +1 -0
  56. package/dist/runtime/update-register.js +146 -0
  57. package/dist/runtime/update-register.js.map +1 -0
  58. package/dist/runtime/update-report.d.ts +93 -0
  59. package/dist/runtime/update-report.d.ts.map +1 -0
  60. package/dist/runtime/update-report.js +133 -0
  61. package/dist/runtime/update-report.js.map +1 -0
  62. package/dist/skills-manager/manifest.d.ts.map +1 -1
  63. package/dist/skills-manager/manifest.js +1 -0
  64. package/dist/skills-manager/manifest.js.map +1 -1
  65. package/dist/skills-manager/skills-manifest.json +1 -0
  66. package/dist/utils/event-catalog.d.ts +26 -0
  67. package/dist/utils/event-catalog.d.ts.map +1 -1
  68. package/dist/utils/event-catalog.js +1 -0
  69. package/dist/utils/event-catalog.js.map +1 -1
  70. package/dist/widgets/errors.d.ts +3 -15
  71. package/dist/widgets/errors.d.ts.map +1 -1
  72. package/dist/widgets/errors.js +3 -20
  73. package/dist/widgets/errors.js.map +1 -1
  74. package/dist/widgets/index.d.ts +3 -10
  75. package/dist/widgets/index.d.ts.map +1 -1
  76. package/dist/widgets/index.js +3 -6
  77. package/dist/widgets/index.js.map +1 -1
  78. package/dist/widgets/registry.d.ts.map +1 -1
  79. package/dist/widgets/registry.js +10 -3
  80. package/dist/widgets/registry.js.map +1 -1
  81. package/dist/widgets/tool.d.ts +6 -9
  82. package/dist/widgets/tool.d.ts.map +1 -1
  83. package/dist/widgets/tool.js +37 -147
  84. package/dist/widgets/tool.js.map +1 -1
  85. package/dist/widgets/types.d.ts +20 -58
  86. package/dist/widgets/types.d.ts.map +1 -1
  87. package/dist/widgets/types.js +4 -4
  88. package/dist/widgets/widgets/fund-user-wallet.d.ts +4 -5
  89. package/dist/widgets/widgets/fund-user-wallet.d.ts.map +1 -1
  90. package/dist/widgets/widgets/fund-user-wallet.js +27 -67
  91. package/dist/widgets/widgets/fund-user-wallet.js.map +1 -1
  92. package/openclaw.plugin.json +1 -4
  93. package/package.json +2 -3
  94. package/dist/widgets/strategy-lookup.d.ts +0 -39
  95. package/dist/widgets/strategy-lookup.d.ts.map +0 -1
  96. package/dist/widgets/strategy-lookup.js +0 -70
  97. package/dist/widgets/strategy-lookup.js.map +0 -1
  98. package/dist/widgets/widgets/fund-strategy-wallet.d.ts +0 -13
  99. package/dist/widgets/widgets/fund-strategy-wallet.d.ts.map +0 -1
  100. package/dist/widgets/widgets/fund-strategy-wallet.js +0 -139
  101. package/dist/widgets/widgets/fund-strategy-wallet.js.map +0 -1
  102. package/skills/senpi-widgets/SKILL.md +0 -167
@@ -1,23 +1,11 @@
1
1
  /**
2
2
  * Widget spec types.
3
3
  *
4
- * A widget spec is the single source for one `widget_type`: the fields it
5
- * accepts, the text that teaches the model about it, and the handler that
6
- * builds the result. The `show_widget` tool descriptor (enum + description) is
7
- * generated from the spec list, so the two cannot drift.
4
+ * A widget spec is the single source for one `widget_type`: the text that
5
+ * teaches the model when to reach for the card, and the handler that builds
6
+ * the result. The `show_widget` descriptor (enum + description) is generated
7
+ * from the spec list, so the two cannot drift.
8
8
  */
9
- /** Field value kinds a widget may declare. Extend as new widgets need them. */
10
- export type WidgetFieldType = "string";
11
- export interface WidgetFieldSpec {
12
- readonly name: string;
13
- readonly type: WidgetFieldType;
14
- /** Enforced in `execute()`; the declared JSON schema keeps every field optional. */
15
- readonly required: boolean;
16
- /** One line, shown to the model in the generated tool description. */
17
- readonly description: string;
18
- /** Upper bound for string fields. */
19
- readonly maxLength?: number;
20
- }
21
9
  /** Rendered by the client. Always carries the three shared keys. */
22
10
  export interface WidgetPayload {
23
11
  readonly widget_type: string;
@@ -30,53 +18,27 @@ export interface WidgetResult {
30
18
  /** Short line for the agent — what happened and what not to do next. */
31
19
  readonly text: string;
32
20
  }
33
- /** One of the caller's strategies, as the backend reported it. */
34
- export interface StrategyMatch {
35
- readonly id: string;
36
- /** The address exactly as the backend spells it, not as the model typed it. */
37
- readonly walletAddress: string;
38
- /** Lifecycle status, e.g. "ACTIVE", "PAUSED", "CLOSED". */
39
- readonly status: string;
40
- readonly name: string;
41
- }
42
- export interface StrategyLookup {
43
- /**
44
- * `null` means the backend answered and no strategy of the caller's holds that
45
- * address. A backend that did not answer usably **throws** — the two must never
46
- * collapse, or one timeout turns a good address into "not yours".
47
- */
48
- findByWallet(wallet: string): Promise<StrategyMatch | null>;
49
- }
50
- /** Everything a handler may reach for beyond its own args. */
51
- export interface WidgetContext {
52
- /** Absent when the plugin registered the tool without a backend. */
53
- readonly strategies?: StrategyLookup;
54
- }
55
- /**
56
- * A field a widget always refuses but wants to diagnose itself, because another
57
- * widget type declares it and the model can misroute it here.
58
- *
59
- * Matched by name only. No type or length check is applied, and the value
60
- * reaches the handler exactly as it arrived: the widget's answer is "drop this
61
- * field", which does not change with the value, and a type complaint would send
62
- * the model back to correct a field it should be removing.
63
- */
64
- export interface GuardedFieldSpec {
65
- readonly name: string;
66
- /** Why it is refused. For readers of the spec; the model sees the widget's own error. */
67
- readonly description: string;
68
- }
69
21
  export interface WidgetSpec {
70
22
  readonly widgetType: string;
71
23
  /** Bumped when the payload shape changes; the client falls back on unknown versions. */
72
24
  readonly widgetVersion: number;
73
- /** When to use this widget. Reproduced verbatim in the tool description. */
25
+ /** What the card does. Reproduced verbatim in the tool description. */
74
26
  readonly description: string;
75
- readonly fields: readonly WidgetFieldSpec[];
76
- /** Never advertised in the description or the declared schema. */
77
- readonly guardedFields?: readonly GuardedFieldSpec[];
78
- /** Receives args validated against `fields`, plus any guarded field verbatim. */
79
- readonly handler: (args: Readonly<Record<string, unknown>>, ctx: WidgetContext) => WidgetResult | Promise<WidgetResult>;
27
+ /**
28
+ * The condition that makes the model call the tool, stated as an intent it
29
+ * already has rather than a box to tick. Reproduced verbatim.
30
+ */
31
+ readonly callWhen: string;
32
+ /**
33
+ * The nearest thing this card is not, and the tool that owns it. One line,
34
+ * reproduced verbatim — a card can be mistaken for a neighbouring flow long
35
+ * before it is mistaken for an unrelated one.
36
+ */
37
+ readonly notFor: string;
38
+ /** Situations illustrating the condition. One line each, reproduced verbatim. */
39
+ readonly examples: readonly string[];
40
+ /** Takes no arguments: `show_widget` accepts `widget_type` and nothing else. */
41
+ readonly handler: () => WidgetResult | Promise<WidgetResult>;
80
42
  }
81
43
  /** A spec plus its resolved on/off state from plugin config. */
82
44
  export interface RegisteredWidget extends WidgetSpec {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/widgets/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qCAAqC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;CAC7D;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAC;IAC5C,kEAAkE;IAClE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrD,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,CAChB,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,GAAG,EAAE,aAAa,KACf,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC3C;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,mEAAmE;IACnE,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/widgets/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,uEAAuE;IACvE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9D;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,mEAAmE;IACnE,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClC"}
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Widget spec types.
3
3
  *
4
- * A widget spec is the single source for one `widget_type`: the fields it
5
- * accepts, the text that teaches the model about it, and the handler that
6
- * builds the result. The `show_widget` tool descriptor (enum + description) is
7
- * generated from the spec list, so the two cannot drift.
4
+ * A widget spec is the single source for one `widget_type`: the text that
5
+ * teaches the model when to reach for the card, and the handler that builds
6
+ * the result. The `show_widget` descriptor (enum + description) is generated
7
+ * from the spec list, so the two cannot drift.
8
8
  */
9
9
  export {};
10
10
  //# sourceMappingURL=types.js.map
@@ -3,11 +3,10 @@ import type { WidgetSpec } from "../types.js";
3
3
  * `fund_user_wallet` — a card that opens the client's existing deposit modal
4
4
  * for the user's own Senpi (Privy self-custody) wallet.
5
5
  *
6
- * The input surface is deliberately empty apart from a context sentence: the
7
- * modal resolves the wallet address and the networks from the user's own
8
- * session, so no amount, address or wallet id ever travels through the chat.
9
- * Nothing is authorized by showing the card, so there is no request id, no TTL
10
- * and no lifecycle.
6
+ * It takes no input: the modal resolves the wallet address and the networks
7
+ * from the user's own session, so no amount, address or wallet id travels
8
+ * through the chat. Showing the card authorizes nothing, so there is no
9
+ * request id, no TTL and no lifecycle.
11
10
  */
12
11
  export declare const fundUserWalletSpec: WidgetSpec;
13
12
  //# sourceMappingURL=fund-user-wallet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fund-user-wallet.d.ts","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-user-wallet.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,UAAU,EAAE,MAAM,aAAa,CAAC;AAoC7D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,UAqChC,CAAC"}
1
+ {"version":3,"file":"fund-user-wallet.d.ts","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-user-wallet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAK9C;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,UA6BhC,CAAC"}
@@ -1,78 +1,38 @@
1
- import { WidgetValidationError } from "../errors.js";
2
- import { isWalletAddress } from "../strategy-lookup.js";
3
1
  const WIDGET_TYPE = "fund_user_wallet";
4
- /**
5
- * An address never belongs on this widget: the deposit modal resolves the
6
- * user's own wallet from their session. The call is refused whatever the value
7
- * is — the lookup only decides which correction the model is given, and a
8
- * lookup that fails still leaves the refusal correct, so it is never a reason
9
- * to accept.
10
- */
11
- async function refuseValue(value, ctx) {
12
- // Only an actual address can name a strategy, so anything else is refused
13
- // without spending an MCP round trip on a value that cannot match.
14
- const wallet = typeof value === "string" ? value.trim() : "";
15
- let match = null;
16
- if (isWalletAddress(wallet)) {
17
- try {
18
- match = (await ctx.strategies?.findByWallet(wallet)) ?? null;
19
- }
20
- catch {
21
- // Unverified reads as unknown; the "remove the field" correction still holds.
22
- }
23
- }
24
- throw new WidgetValidationError(match
25
- ? `show_widget failed for widget_type "${WIDGET_TYPE}": ${wallet} is the wallet of your strategy ` +
26
- `"${match.name.trim() || match.id}", not the user's own wallet. Call show_widget again with ` +
27
- 'widget_type "fund_strategy_wallet" and that address.'
28
- : `show_widget failed for widget_type "${WIDGET_TYPE}": it takes no address — the card resolves the ` +
29
- "user's own wallet from their session. Remove strategy_wallet and call again. To fund a strategy " +
30
- 'instead, use widget_type "fund_strategy_wallet".', WIDGET_TYPE, ["strategy_wallet"]);
31
- }
2
+ const WIDGET_VERSION = 1;
32
3
  /**
33
4
  * `fund_user_wallet` — a card that opens the client's existing deposit modal
34
5
  * for the user's own Senpi (Privy self-custody) wallet.
35
6
  *
36
- * The input surface is deliberately empty apart from a context sentence: the
37
- * modal resolves the wallet address and the networks from the user's own
38
- * session, so no amount, address or wallet id ever travels through the chat.
39
- * Nothing is authorized by showing the card, so there is no request id, no TTL
40
- * and no lifecycle.
7
+ * It takes no input: the modal resolves the wallet address and the networks
8
+ * from the user's own session, so no amount, address or wallet id travels
9
+ * through the chat. Showing the card authorizes nothing, so there is no
10
+ * request id, no TTL and no lifecycle.
41
11
  */
42
12
  export const fundUserWalletSpec = {
43
- widgetType: "fund_user_wallet",
44
- widgetVersion: 1,
45
- description: "Show the user a card that opens Senpi's deposit flow for their own wallet. " +
46
- "Use it when the user has no funds, cannot trade for lack of balance, or asks how to add money. " +
47
- "The card owns the address, the networks and the deposit copy — never restate them yourself.",
48
- fields: [
49
- {
50
- name: "reason",
51
- type: "string",
52
- required: false,
53
- description: "One plain sentence on why you are showing the card, e.g. \"Your wallet has no balance yet.\" " +
54
- "Recorded with the call; the card renders its own copy, so this is not displayed to the user.",
55
- maxLength: 280,
56
- },
13
+ widgetType: WIDGET_TYPE,
14
+ widgetVersion: WIDGET_VERSION,
15
+ description: "Opens Senpi's deposit flow for the user's OWN Senpi wallet, the one they deposit into from outside. " +
16
+ "The card owns the address, the networks and the deposit copy — never write a deposit address, a QR code " +
17
+ "or a network list in chat.",
18
+ callWhen: "Call it whenever you want money to arrive in the user's own Senpi wallet, whether or not the user " +
19
+ "mentions a deposit or a card.",
20
+ notFor: "Funding, topping up or adding margin to a STRATEGY — a strategy is funded from the user's own wallet " +
21
+ "by the strategy_top_up tool, never by depositing to an address.",
22
+ examples: [
23
+ "the user asks how to deposit into Senpi, or how to add funds to their own wallet",
24
+ "the user's own Senpi wallet is empty",
25
+ "that wallet has some balance, but not enough for the trade or position the user asked for",
26
+ "you are about to tell the user they need more money in their own wallet before you can act",
57
27
  ],
58
- guardedFields: [
59
- {
60
- name: "strategy_wallet",
61
- description: "Always refused here; guarded so the misrouted call gets a targeted correction.",
28
+ handler: () => ({
29
+ payload: {
30
+ widget_type: WIDGET_TYPE,
31
+ widget_version: WIDGET_VERSION,
32
+ status: "shown",
62
33
  },
63
- ],
64
- handler: async (args, ctx) => {
65
- if (Object.hasOwn(args, "strategy_wallet"))
66
- await refuseValue(args.strategy_wallet, ctx);
67
- return {
68
- payload: {
69
- widget_type: WIDGET_TYPE,
70
- widget_version: 1,
71
- status: "shown",
72
- },
73
- text: "Funding card shown. The user can deposit from the card. " +
74
- "Do not show it again in this turn; answer follow-up questions in text.",
75
- };
76
- },
34
+ text: "Funding card shown. The user can deposit from the card. " +
35
+ "Do not show it again in this turn; answer follow-up questions in text.",
36
+ }),
77
37
  };
78
38
  //# sourceMappingURL=fund-user-wallet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fund-user-wallet.js","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-user-wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC;;;;;;GAMG;AACH,KAAK,UAAU,WAAW,CAAC,KAAc,EAAE,GAAkB;IAC3D,0EAA0E;IAC1E,mEAAmE;IACnE,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,IAAI,KAAK,GAAG,IAAI,CAAC;IACjB,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,8EAA8E;QAChF,CAAC;IACH,CAAC;IACD,MAAM,IAAI,qBAAqB,CAC7B,KAAK;QACH,CAAC,CAAC,uCAAuC,WAAW,MAAM,MAAM,kCAAkC;YAChG,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,4DAA4D;YAC7F,sDAAsD;QACxD,CAAC,CAAC,uCAAuC,WAAW,iDAAiD;YACnG,kGAAkG;YAClG,kDAAkD,EACtD,WAAW,EACX,CAAC,iBAAiB,CAAC,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC5C,UAAU,EAAE,kBAAkB;IAC9B,aAAa,EAAE,CAAC;IAChB,WAAW,EACT,6EAA6E;QAC7E,iGAAiG;QACjG,6FAA6F;IAC/F,MAAM,EAAE;QACN;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,KAAK;YACf,WAAW,EACT,+FAA+F;gBAC/F,8FAA8F;YAChG,SAAS,EAAE,GAAG;SACf;KACF;IACD,aAAa,EAAE;QACb;YACE,IAAI,EAAE,iBAAiB;YACvB,WAAW,EAAE,gFAAgF;SAC9F;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,CAAC;YAAE,MAAM,WAAW,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QACzF,OAAO;YACL,OAAO,EAAE;gBACP,WAAW,EAAE,WAAW;gBACxB,cAAc,EAAE,CAAC;gBACjB,MAAM,EAAE,OAAO;aAChB;YACD,IAAI,EACF,0DAA0D;gBAC1D,wEAAwE;SAC3E,CAAC;IACJ,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"fund-user-wallet.js","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-user-wallet.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC5C,UAAU,EAAE,WAAW;IACvB,aAAa,EAAE,cAAc;IAC7B,WAAW,EACT,sGAAsG;QACtG,0GAA0G;QAC1G,4BAA4B;IAC9B,QAAQ,EACN,oGAAoG;QACpG,+BAA+B;IACjC,MAAM,EACJ,uGAAuG;QACvG,iEAAiE;IACnE,QAAQ,EAAE;QACR,kFAAkF;QAClF,sCAAsC;QACtC,2FAA2F;QAC3F,4FAA4F;KAC7F;IACD,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACd,OAAO,EAAE;YACP,WAAW,EAAE,WAAW;YACxB,cAAc,EAAE,cAAc;YAC9B,MAAM,EAAE,OAAO;SAChB;QACD,IAAI,EACF,0DAA0D;YAC1D,wEAAwE;KAC3E,CAAC;CACH,CAAC"}
@@ -2,7 +2,7 @@
2
2
  "id": "runtime",
3
3
  "name": "Senpi Runtime",
4
4
  "description": "Senpi runtime plugin for OpenClaw. Orchestrates scanners, LLM-based trade decisions, and a DSL trailing stop-loss exit engine.",
5
- "version": "3.0.81",
5
+ "version": "3.0.83",
6
6
  "commandAliases": [
7
7
  {
8
8
  "name": "senpi"
@@ -19,9 +19,6 @@
19
19
  "show_widget"
20
20
  ]
21
21
  },
22
- "skills": [
23
- "skills/senpi-widgets"
24
- ],
25
22
  "configSchema": {
26
23
  "type": "object",
27
24
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senpi/runtime",
3
- "version": "3.0.81",
3
+ "version": "3.0.83",
4
4
  "description": "Senpi runtime plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,8 +8,7 @@
8
8
  "files": [
9
9
  "dist/",
10
10
  "openclaw.plugin.json",
11
- "examples/",
12
- "skills/senpi-widgets/"
11
+ "examples/"
13
12
  ],
14
13
  "scripts": {
15
14
  "setup:hooks": "sh -c 'git rev-parse --git-dir >/dev/null 2>&1 && git config core.hooksPath .githooks || true'",
@@ -1,39 +0,0 @@
1
- import type { StrategyLookup } from "./types.js";
2
- /**
3
- * Bounds one validation lookup. The user is waiting on a card, and the tool
4
- * result is what unblocks the turn, so a backend that never answers has to
5
- * become an error the model can retry rather than a hung turn.
6
- */
7
- export declare const STRATEGY_LOOKUP_TIMEOUT_MS = 10000;
8
- export declare function isWalletAddress(value: string): boolean;
9
- /** The `strategy_list` row fields this lookup reads. */
10
- interface StrategyRow {
11
- id: string;
12
- strategyWalletAddress: string;
13
- status: string;
14
- strategyName: string;
15
- }
16
- /** The slice of `SenpiClient` this lookup needs. */
17
- export interface StrategyLister {
18
- listStrategies(filters?: {
19
- strategyAddresses?: string[];
20
- }, opts?: {
21
- signal?: AbortSignal;
22
- }): Promise<StrategyRow[]>;
23
- }
24
- /**
25
- * Address → strategy, over `strategy_list` with an address filter.
26
- *
27
- * Deliberately not `SenpiClient.getStrategy`: that one falls back to the first
28
- * row when no row matches the requested address, and drops the address from its
29
- * result, so a backend that ignored the filter would resolve any address to
30
- * some strategy. Both are fine for a details read and fatal for a gate, so this
31
- * matches the address itself and never falls back.
32
- *
33
- * `listStrategies` already fails closed — an unrecognizable response throws
34
- * instead of reading as an empty list — so an empty result here is a real
35
- * "no strategy of yours holds that address" and is returned as `null`.
36
- */
37
- export declare function createSenpiStrategyLookup(withClient: <T>(fn: (client: StrategyLister) => Promise<T>) => Promise<T>): StrategyLookup;
38
- export {};
39
- //# sourceMappingURL=strategy-lookup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"strategy-lookup.d.ts","sourceRoot":"","sources":["../../src/widgets/strategy-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAiB,MAAM,YAAY,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAyBjD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,wDAAwD;AACxD,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB,EAAE,MAAM,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,cAAc,CACZ,OAAO,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,EAC1C,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GACxE,cAAc,CA+BhB"}
@@ -1,70 +0,0 @@
1
- /**
2
- * Bounds one validation lookup. The user is waiting on a card, and the tool
3
- * result is what unblocks the turn, so a backend that never answers has to
4
- * become an error the model can retry rather than a hung turn.
5
- */
6
- export const STRATEGY_LOOKUP_TIMEOUT_MS = 10_000;
7
- /**
8
- * Bounds the whole lookup, not just the MCP request.
9
- *
10
- * The signal passed to `listStrategies` covers the request only. Reaching it
11
- * means first connecting a client, and the MCP SDK gives `initialize` its own
12
- * 60s default — so an unreachable backend held the agent turn for over a minute
13
- * while this module advertised a ten-second bound. The race is what makes the
14
- * bound true; the signal stays so the in-flight request is really cancelled.
15
- */
16
- async function withDeadline(work, ms) {
17
- let timer;
18
- const deadline = new Promise((_resolve, reject) => {
19
- timer = setTimeout(() => reject(new Error(`strategy lookup timed out after ${ms}ms`)), ms);
20
- });
21
- try {
22
- return await Promise.race([work, deadline]);
23
- }
24
- finally {
25
- clearTimeout(timer);
26
- }
27
- }
28
- const WALLET_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
29
- export function isWalletAddress(value) {
30
- return WALLET_ADDRESS_RE.test(value);
31
- }
32
- /**
33
- * Address → strategy, over `strategy_list` with an address filter.
34
- *
35
- * Deliberately not `SenpiClient.getStrategy`: that one falls back to the first
36
- * row when no row matches the requested address, and drops the address from its
37
- * result, so a backend that ignored the filter would resolve any address to
38
- * some strategy. Both are fine for a details read and fatal for a gate, so this
39
- * matches the address itself and never falls back.
40
- *
41
- * `listStrategies` already fails closed — an unrecognizable response throws
42
- * instead of reading as an empty list — so an empty result here is a real
43
- * "no strategy of yours holds that address" and is returned as `null`.
44
- */
45
- export function createSenpiStrategyLookup(withClient) {
46
- return {
47
- async findByWallet(wallet) {
48
- // Lowercased for the backend, not just for the comparison below. The
49
- // `strategy_addresses` filter is an exact SQL `in` against a column
50
- // written lowercase, so a checksummed address matches nothing and comes
51
- // back as an ordinary empty list — a correct address reported as "not
52
- // yours", which is the one answer this gate must never invent.
53
- const wanted = wallet.toLowerCase();
54
- const rows = await withDeadline(withClient((client) => client.listStrategies({ strategyAddresses: [wanted] }, { signal: AbortSignal.timeout(STRATEGY_LOOKUP_TIMEOUT_MS) })), STRATEGY_LOOKUP_TIMEOUT_MS);
55
- const matches = rows.filter((row) => row.strategyWalletAddress.toLowerCase() === wanted);
56
- // An address may carry more than one row over its lifetime; a live
57
- // strategy on it is the answer, and its status is what the gate judges.
58
- const match = matches.find((row) => row.status.toUpperCase() === "ACTIVE") ?? matches[0];
59
- if (!match)
60
- return null;
61
- return {
62
- id: match.id,
63
- walletAddress: match.strategyWalletAddress,
64
- status: match.status,
65
- name: match.strategyName,
66
- };
67
- },
68
- };
69
- }
70
- //# sourceMappingURL=strategy-lookup.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"strategy-lookup.js","sourceRoot":"","sources":["../../src/widgets/strategy-lookup.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD;;;;;;;;GAQG;AACH,KAAK,UAAU,YAAY,CAAI,IAAgB,EAAE,EAAU;IACzD,IAAI,KAAgD,CAAC;IACrD,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QACvD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEhD,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAkBD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAyE;IAEzE,OAAO;QACL,KAAK,CAAC,YAAY,CAAC,MAAc;YAC/B,qEAAqE;YACrE,oEAAoE;YACpE,wEAAwE;YACxE,sEAAsE;YACtE,+DAA+D;YAC/D,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,YAAY,CAC7B,UAAU,CAAC,CAAC,MAAM,EAAE,EAAE,CACpB,MAAM,CAAC,cAAc,CACnB,EAAE,iBAAiB,EAAE,CAAC,MAAM,CAAC,EAAE,EAC/B,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,0BAA0B,CAAC,EAAE,CAC5D,CACF,EACD,0BAA0B,CAC3B,CAAC;YACF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,qBAAqB,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;YACzF,mEAAmE;YACnE,wEAAwE;YACxE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;YACzF,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxB,OAAO;gBACL,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,aAAa,EAAE,KAAK,CAAC,qBAAqB;gBAC1C,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,YAAY;aACzB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,13 +0,0 @@
1
- import type { WidgetSpec } from "../types.js";
2
- /**
3
- * `fund_strategy_wallet` — a card whose button tops the strategy up from the
4
- * user's own Senpi wallet. This is an internal transfer, not a deposit: a
5
- * strategy wallet has no deposit address anyone may be shown, because USDC sent
6
- * to it directly bypasses accounting and may be unrecoverable.
7
- *
8
- * The address is validated here rather than at the schema, because "is one of
9
- * this user's active strategies" is not something a JSON schema can state. The
10
- * payload carries the resolved strategy id: the top-up API keys on the id.
11
- */
12
- export declare const fundStrategyWalletSpec: WidgetSpec;
13
- //# sourceMappingURL=fund-strategy-wallet.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fund-strategy-wallet.d.ts","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-strategy-wallet.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgC,UAAU,EAAE,MAAM,aAAa,CAAC;AA4G5E;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,UA0DpC,CAAC"}
@@ -1,139 +0,0 @@
1
- import { WidgetLookupError, WidgetValidationError } from "../errors.js";
2
- import { isWalletAddress } from "../strategy-lookup.js";
3
- const WIDGET_TYPE = "fund_strategy_wallet";
4
- const WIDGET_VERSION = 1;
5
- /**
6
- * The tracking id becomes the top-up's `idempotencyKey`, so it has to be unique
7
- * per intent and safe to carry as a key. The charset excludes `:`, which would
8
- * otherwise let a digits-then-text id trip OpenClaw's value redaction and reach
9
- * the client masked; the length floor keeps a model from minting "1".
10
- */
11
- const TRACKING_ID_RE = /^[A-Za-z0-9._-]{8,128}$/;
12
- const TRACKING_ID_MAX = 128;
13
- /** Only a live strategy can take a top-up. */
14
- const ACTIVE = "ACTIVE";
15
- /** `strategyName` is nullable on the backend; the id is what always identifies a row. */
16
- function strategyLabel(match) {
17
- return match.name.trim() || match.id;
18
- }
19
- function requireFormat(args) {
20
- const wallet = String(args.strategy_wallet).trim();
21
- const trackingId = String(args.tracking_id).trim();
22
- const problems = [];
23
- const fields = [];
24
- if (!isWalletAddress(wallet)) {
25
- fields.push("strategy_wallet");
26
- problems.push(`strategy_wallet "${wallet}" is not a wallet address (expected 0x followed by 40 hex characters). ` +
27
- "Call strategy_list and pass the strategyWalletAddress of the strategy you mean");
28
- }
29
- if (!TRACKING_ID_RE.test(trackingId)) {
30
- fields.push("tracking_id");
31
- problems.push("tracking_id must be 8-128 characters of letters, digits, dot, underscore or hyphen — " +
32
- "generate a fresh UUID for this funding request");
33
- }
34
- if (problems.length > 0) {
35
- throw new WidgetValidationError(`show_widget failed for widget_type "${WIDGET_TYPE}": ${problems.join("; ")}.`, WIDGET_TYPE, fields);
36
- }
37
- return { wallet, trackingId };
38
- }
39
- async function resolveStrategy(ctx, wallet) {
40
- if (!ctx.strategies) {
41
- throw new WidgetLookupError(`show_widget failed for widget_type "${WIDGET_TYPE}": the strategy wallet could not be verified ` +
42
- "because this deployment has no Senpi backend configured. Do not retry; handle the request in text.", WIDGET_TYPE);
43
- }
44
- let match;
45
- try {
46
- match = await ctx.strategies.findByWallet(wallet);
47
- }
48
- catch (err) {
49
- // The address was never judged. Saying "not yours" here would make the model
50
- // swap a correct address for a wrong one.
51
- throw new WidgetLookupError(`show_widget failed for widget_type "${WIDGET_TYPE}": strategy wallet ${wallet} could not be verified — ` +
52
- "the Senpi backend did not answer. The address may well be correct. Try the same call again.", WIDGET_TYPE, err);
53
- }
54
- if (!match) {
55
- throw new WidgetValidationError(`show_widget failed for widget_type "${WIDGET_TYPE}": ${wallet} is not one of your strategy wallets. ` +
56
- "Call strategy_list and pass the strategyWalletAddress of the strategy you mean.", WIDGET_TYPE, ["strategy_wallet"]);
57
- }
58
- if (match.status.toUpperCase() !== ACTIVE) {
59
- // `strategyName` is nullable and the status covers the whole onboarding
60
- // lifecycle, not just PAUSED/CLOSED — so neither is quoted raw.
61
- throw new WidgetValidationError(`show_widget failed for widget_type "${WIDGET_TYPE}": that wallet belongs to strategy ` +
62
- `"${strategyLabel(match)}", whose status is ${match.status.trim() || "unknown"}, not ${ACTIVE}. ` +
63
- `Only an ${ACTIVE} strategy can be funded — tell the user to resume or finish setting it up, ` +
64
- "or pass a different strategy's wallet.", WIDGET_TYPE, ["strategy_wallet"]);
65
- }
66
- if (match.id.trim().length === 0) {
67
- // The funding API takes a strategy id, never the address, so an id-less row
68
- // is unusable even though the address checked out.
69
- throw new WidgetLookupError(`show_widget failed for widget_type "${WIDGET_TYPE}": the backend matched the wallet but returned no ` +
70
- "strategy id, so the card cannot be funded. Retrying is unlikely to help — tell the user this " +
71
- "strategy cannot be funded right now.", WIDGET_TYPE);
72
- }
73
- return match;
74
- }
75
- /**
76
- * `fund_strategy_wallet` — a card whose button tops the strategy up from the
77
- * user's own Senpi wallet. This is an internal transfer, not a deposit: a
78
- * strategy wallet has no deposit address anyone may be shown, because USDC sent
79
- * to it directly bypasses accounting and may be unrecoverable.
80
- *
81
- * The address is validated here rather than at the schema, because "is one of
82
- * this user's active strategies" is not something a JSON schema can state. The
83
- * payload carries the resolved strategy id: the top-up API keys on the id.
84
- */
85
- export const fundStrategyWalletSpec = {
86
- widgetType: WIDGET_TYPE,
87
- widgetVersion: WIDGET_VERSION,
88
- description: "Show the user a card that funds one of their own strategies from their Senpi wallet. " +
89
- "Use it when a strategy has too little balance to trade, or the user asks to fund, top up or add to a strategy. " +
90
- "Never state a deposit address for a strategy wallet — funding a strategy is an internal transfer and the card owns it.",
91
- fields: [
92
- {
93
- name: "strategy_wallet",
94
- type: "string",
95
- required: true,
96
- description: "The strategyWalletAddress of one of the user's ACTIVE strategies, from strategy_list. " +
97
- "Rejected if it is not one of theirs.",
98
- maxLength: 64,
99
- },
100
- {
101
- name: "tracking_id",
102
- type: "string",
103
- required: true,
104
- description: "A fresh UUID you generate for this funding request, 8-128 characters of letters, digits, dot, " +
105
- "underscore or hyphen. Never reuse one: it is the idempotency key, and a repeat replays the first top-up.",
106
- maxLength: TRACKING_ID_MAX,
107
- },
108
- {
109
- name: "reason",
110
- type: "string",
111
- required: false,
112
- description: 'One plain sentence on why you are showing the card, e.g. "This strategy has no margin left." ' +
113
- "Recorded with the call; the card renders its own copy, so this is not displayed to the user.",
114
- maxLength: 280,
115
- },
116
- ],
117
- handler: async (args, ctx) => {
118
- const { wallet, trackingId } = requireFormat(args);
119
- const match = await resolveStrategy(ctx, wallet);
120
- return {
121
- payload: {
122
- widget_type: WIDGET_TYPE,
123
- widget_version: WIDGET_VERSION,
124
- status: "shown",
125
- strategy_id: match.id,
126
- // The backend's spelling, not the model's. The web client re-resolves
127
- // the strategy from the args (the payload does not survive a reload),
128
- // so this is carried for clients that render from the payload.
129
- strategy_wallet: match.walletAddress,
130
- tracking_id: trackingId,
131
- },
132
- // No address in here: this text is the agent's to repeat, and a strategy
133
- // wallet address repeated in chat reads as a deposit address.
134
- text: `Funding card shown for strategy "${strategyLabel(match)}". The user funds it from the card. ` +
135
- "Do not show it again in this turn, and never give an address for funding a strategy.",
136
- };
137
- },
138
- };
139
- //# sourceMappingURL=fund-strategy-wallet.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fund-strategy-wallet.js","sourceRoot":"","sources":["../../../src/widgets/widgets/fund-strategy-wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAC3C,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,cAAc,GAAG,yBAAyB,CAAC;AACjD,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,8CAA8C;AAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC;AAExB,yFAAyF;AACzF,SAAS,aAAa,CAAC,KAAoB;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,aAAa,CAAC,IAAuC;IAI5D,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC/B,QAAQ,CAAC,IAAI,CACX,oBAAoB,MAAM,yEAAyE;YACjG,gFAAgF,CACnF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3B,QAAQ,CAAC,IAAI,CACX,uFAAuF;YACrF,gDAAgD,CACnD,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,qBAAqB,CAC7B,uCAAuC,WAAW,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAC9E,WAAW,EACX,MAAM,CACP,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,GAAkB,EAAE,MAAc;IAC/D,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QACpB,MAAM,IAAI,iBAAiB,CACzB,uCAAuC,WAAW,+CAA+C;YAC/F,oGAAoG,EACtG,WAAW,CACZ,CAAC;IACJ,CAAC;IACD,IAAI,KAA2B,CAAC;IAChC,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,6EAA6E;QAC7E,0CAA0C;QAC1C,MAAM,IAAI,iBAAiB,CACzB,uCAAuC,WAAW,sBAAsB,MAAM,2BAA2B;YACvG,6FAA6F,EAC/F,WAAW,EACX,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,qBAAqB,CAC7B,uCAAuC,WAAW,MAAM,MAAM,wCAAwC;YACpG,iFAAiF,EACnF,WAAW,EACX,CAAC,iBAAiB,CAAC,CACpB,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QAC1C,wEAAwE;QACxE,gEAAgE;QAChE,MAAM,IAAI,qBAAqB,CAC7B,uCAAuC,WAAW,qCAAqC;YACrF,IAAI,aAAa,CAAC,KAAK,CAAC,sBAAsB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,SAAS,MAAM,IAAI;YACjG,WAAW,MAAM,6EAA6E;YAC9F,wCAAwC,EAC1C,WAAW,EACX,CAAC,iBAAiB,CAAC,CACpB,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,4EAA4E;QAC5E,mDAAmD;QACnD,MAAM,IAAI,iBAAiB,CACzB,uCAAuC,WAAW,oDAAoD;YACpG,+FAA+F;YAC/F,sCAAsC,EACxC,WAAW,CACZ,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAe;IAChD,UAAU,EAAE,WAAW;IACvB,aAAa,EAAE,cAAc;IAC7B,WAAW,EACT,uFAAuF;QACvF,iHAAiH;QACjH,wHAAwH;IAC1H,MAAM,EAAE;QACN;YACE,IAAI,EAAE,iBAAiB;YACvB,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,IAAI;YACd,WAAW,EACT,wFAAwF;gBACxF,sCAAsC;YACxC,SAAS,EAAE,EAAE;SACd;QACD;YACE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,IAAI;YACd,WAAW,EACT,gGAAgG;gBAChG,0GAA0G;YAC5G,SAAS,EAAE,eAAe;SAC3B;QACD;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,KAAK;YACf,WAAW,EACT,+FAA+F;gBAC/F,8FAA8F;YAChG,SAAS,EAAE,GAAG;SACf;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO;YACL,OAAO,EAAE;gBACP,WAAW,EAAE,WAAW;gBACxB,cAAc,EAAE,cAAc;gBAC9B,MAAM,EAAE,OAAO;gBACf,WAAW,EAAE,KAAK,CAAC,EAAE;gBACrB,sEAAsE;gBACtE,sEAAsE;gBACtE,+DAA+D;gBAC/D,eAAe,EAAE,KAAK,CAAC,aAAa;gBACpC,WAAW,EAAE,UAAU;aACxB;YACD,yEAAyE;YACzE,8DAA8D;YAC9D,IAAI,EACF,oCAAoC,aAAa,CAAC,KAAK,CAAC,sCAAsC;gBAC9F,sFAAsF;SACzF,CAAC;IACJ,CAAC;CACF,CAAC"}