@ggui-ai/negotiator 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +49 -0
  3. package/dist/contract-hash.d.ts +54 -0
  4. package/dist/contract-hash.d.ts.map +1 -0
  5. package/dist/contract-hash.js +96 -0
  6. package/dist/contract-validators.d.ts +171 -0
  7. package/dist/contract-validators.d.ts.map +1 -0
  8. package/dist/contract-validators.js +478 -0
  9. package/dist/decision-input.d.ts +48 -0
  10. package/dist/decision-input.d.ts.map +1 -0
  11. package/dist/decision-input.js +14 -0
  12. package/dist/decision.d.ts +54 -0
  13. package/dist/decision.d.ts.map +1 -0
  14. package/dist/decision.js +500 -0
  15. package/dist/index.d.ts +36 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +25 -0
  18. package/dist/intent.d.ts +22 -0
  19. package/dist/intent.d.ts.map +1 -0
  20. package/dist/intent.js +28 -0
  21. package/dist/llm-caller.d.ts +70 -0
  22. package/dist/llm-caller.d.ts.map +1 -0
  23. package/dist/llm-caller.js +38 -0
  24. package/dist/llm-rerank.d.ts +101 -0
  25. package/dist/llm-rerank.d.ts.map +1 -0
  26. package/dist/llm-rerank.js +178 -0
  27. package/dist/negotiate.d.ts +141 -0
  28. package/dist/negotiate.d.ts.map +1 -0
  29. package/dist/negotiate.js +161 -0
  30. package/dist/normalize-schema.d.ts +22 -0
  31. package/dist/normalize-schema.d.ts.map +1 -0
  32. package/dist/normalize-schema.js +191 -0
  33. package/dist/pure.d.ts +30 -0
  34. package/dist/pure.d.ts.map +1 -0
  35. package/dist/pure.js +43 -0
  36. package/dist/rag-search.d.ts +73 -0
  37. package/dist/rag-search.d.ts.map +1 -0
  38. package/dist/rag-search.js +192 -0
  39. package/dist/rerank-eval/pairs.d.ts +28 -0
  40. package/dist/rerank-eval/pairs.d.ts.map +1 -0
  41. package/dist/rerank-eval/pairs.js +531 -0
  42. package/dist/rerank-eval/run-probe-cli.d.ts +3 -0
  43. package/dist/rerank-eval/run-probe-cli.d.ts.map +1 -0
  44. package/dist/rerank-eval/run-probe-cli.js +146 -0
  45. package/dist/rerank-eval/run-probe.d.ts +68 -0
  46. package/dist/rerank-eval/run-probe.d.ts.map +1 -0
  47. package/dist/rerank-eval/run-probe.js +113 -0
  48. package/dist/session.d.ts +42 -0
  49. package/dist/session.d.ts.map +1 -0
  50. package/dist/session.js +21 -0
  51. package/dist/suggestion.d.ts +38 -0
  52. package/dist/suggestion.d.ts.map +1 -0
  53. package/dist/suggestion.js +47 -0
  54. package/dist/synth-bench/corpus.d.ts +106 -0
  55. package/dist/synth-bench/corpus.d.ts.map +1 -0
  56. package/dist/synth-bench/corpus.js +994 -0
  57. package/dist/synth-bench/run-bench-cli.d.ts +3 -0
  58. package/dist/synth-bench/run-bench-cli.d.ts.map +1 -0
  59. package/dist/synth-bench/run-bench-cli.js +181 -0
  60. package/dist/synth-bench/run-bench.d.ts +101 -0
  61. package/dist/synth-bench/run-bench.d.ts.map +1 -0
  62. package/dist/synth-bench/run-bench.js +374 -0
  63. package/dist/synthesize-contract.d.ts +131 -0
  64. package/dist/synthesize-contract.d.ts.map +1 -0
  65. package/dist/synthesize-contract.js +948 -0
  66. package/dist/types.d.ts +30 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +13 -0
  69. package/package.json +74 -0
  70. package/src/contract-hash.ts +102 -0
  71. package/src/contract-validators.ts +604 -0
  72. package/src/decision-input.ts +49 -0
  73. package/src/decision.ts +581 -0
  74. package/src/index.ts +63 -0
  75. package/src/intent.ts +37 -0
  76. package/src/llm-caller.ts +82 -0
  77. package/src/llm-rerank.ts +280 -0
  78. package/src/negotiate.ts +312 -0
  79. package/src/normalize-schema.ts +193 -0
  80. package/src/pure.ts +46 -0
  81. package/src/rag-search.ts +274 -0
  82. package/src/rerank-eval/pairs.ts +624 -0
  83. package/src/rerank-eval/run-probe-cli.ts +197 -0
  84. package/src/rerank-eval/run-probe.ts +198 -0
  85. package/src/session.ts +41 -0
  86. package/src/suggestion.ts +73 -0
  87. package/src/synth-bench/corpus.ts +1126 -0
  88. package/src/synth-bench/run-bench-cli.ts +237 -0
  89. package/src/synth-bench/run-bench.ts +525 -0
  90. package/src/synthesize-contract.ts +1161 -0
  91. package/src/types.ts +31 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Contract synthesis.
3
+ *
4
+ * When an agent calls `ggui_handshake({story: {intent}})` without
5
+ * authoring a `contract`, the negotiator's cold path used to stamp an
6
+ * empty stub on `plan.contract`. The stub survived the handshake →
7
+ * push hop but failed downstream: the generator emitted
8
+ * `useAction(...)` / `useGguiContext(...)` calls that didn't match
9
+ * any declared `actionSpec` / `contextSpec`, and the validator
10
+ * stripped them, leaving dead buttons on the rendered UI.
11
+ *
12
+ * `synthesizeContract` closes that gap. Given an LLM caller and an
13
+ * intent string, it asks the model to infer a plausible
14
+ * `DataContract` from the natural-language ask: which actions a user
15
+ * might fire, which context slots the agent would observe, which
16
+ * stream channels would carry live updates. The resulting contract
17
+ * feeds the negotiator's `plan.contract`, rides through to the
18
+ * paired push, and arrives at the generator with a real wire surface
19
+ * that the validator accepts.
20
+ *
21
+ * **Conservative by design.** The synthesized contract emits only
22
+ * what the LLM is confident about — better to under-declare than to
23
+ * fabricate actions the UI doesn't actually need. Operators who want
24
+ * a richer surface should author the contract themselves on the
25
+ * handshake input; synthesis is a fallback, not a replacement.
26
+ *
27
+ * **Failure modes collapse to null.** LLM throws, parse fails,
28
+ * provider doesn't support `callStructured` → return `null`. Caller
29
+ * falls back to an empty stub; behavior regresses to pre-synth but
30
+ * doesn't crash.
31
+ *
32
+ * **Cost.** ~$0.0005-0.001 per call (Haiku 4.5, ~500 input + ~300
33
+ * output tokens). Latency ~1.5s. Fires only on cold-path Tier 3
34
+ * AND when the agent omitted the contract — most pushes from
35
+ * contract-aware agents skip synthesis entirely.
36
+ */
37
+ import { type DataContract, type GadgetDescriptor } from '@ggui-ai/protocol';
38
+ import type { LLMCaller, ToolSchema } from './llm-caller.js';
39
+ import { type ContractValidationFinding } from './contract-validators.js';
40
+ /** Result of one synthesis attempt. */
41
+ export interface SynthesizeContractResult {
42
+ /** Synthesized contract, or `null` when synthesis declined / failed. */
43
+ readonly contract: DataContract | null;
44
+ /** Human-readable reason for the synthesis decision. */
45
+ readonly reason: string;
46
+ /** Wall-clock latency across every attempt. */
47
+ readonly latencyMs: number;
48
+ /**
49
+ * Number of LLM attempts the synthesizer made — `1` on the common
50
+ * already-valid path, up to {@link MAX_SYNTH_ATTEMPTS} when the
51
+ * validate-and-repair loop had to retry. `0` for the early-skip
52
+ * paths (empty intent, provider lacks structured output).
53
+ */
54
+ readonly attempts: number;
55
+ /**
56
+ * Structural-validator findings produced when the synthesizer ran the
57
+ * `validateContractStructure` gate against its assembled contract.
58
+ * Empty when validator didn't run (early skip / decline). Surfaced
59
+ * so callers (cache-trace emit site, ops dashboards) can render
60
+ * findings without re-running the detector.
61
+ */
62
+ readonly findings: readonly ContractValidationFinding[];
63
+ }
64
+ /**
65
+ * Tool schema the synthesizer's structured-output call uses. The
66
+ * shape mirrors `DataContract` but stays loose at the ToolSchema
67
+ * layer — Anthropic's tool-use adapter doesn't enforce nested
68
+ * required-field rules deeply, and we re-validate on the return path.
69
+ */
70
+ export declare const SYNTHESIZE_TOOL: ToolSchema;
71
+ /**
72
+ * Run the synthesizer for a contract-less cold-path handshake.
73
+ *
74
+ * Empty / whitespace intent short-circuits to null with a reason —
75
+ * no contract can be inferred from nothing.
76
+ *
77
+ * Provider lacking `callStructured` (test stubs, providers without
78
+ * tool-use) collapses to null.
79
+ *
80
+ * Each attempt is self-checked against the validation gate; a failure
81
+ * feeds the precise error back for up to {@link MAX_SYNTH_ATTEMPTS}
82
+ * attempts (a transient `callStructured` throw re-runs the same
83
+ * prompt). Only when the budget is exhausted does it collapse to null
84
+ * — the caller then falls back to an empty contract stub.
85
+ */
86
+ export declare function synthesizeContract(deps: {
87
+ readonly llm: LLMCaller;
88
+ }, intent: string, options?: {
89
+ /**
90
+ * Per-app gadget catalog (`App.gadgets`) — when bound, synth
91
+ * emits an "AVAILABLE GADGETS" section on the user prompt (NOT
92
+ * the system prompt, so the system-prompt cache stays warm)
93
+ * listing each registered package's exports — hook AND component
94
+ * — with description + usage. The LLM uses this to decide which
95
+ * (if any) `clientCapabilities.gadgets[<package>][<export>]`
96
+ * entries to declare on the synthesized contract. Per-export
97
+ * budget ~300 chars; total budget ~3 KB.
98
+ *
99
+ * When omitted, synth still uses the static stdlib hint baked
100
+ * into SYNTHESIZE_SYSTEM_PROMPT (preserves behavior on the OSS
101
+ * no-app-registry path).
102
+ */
103
+ readonly appGadgets?: readonly GadgetDescriptor[];
104
+ }): Promise<SynthesizeContractResult>;
105
+ /**
106
+ * Compose the "AVAILABLE GADGETS" section appended to synth's user
107
+ * prompt (and the decision-engine user message — both paths share
108
+ * this one composer). Flattens the package-keyed
109
+ * {@link GadgetDescriptor} catalog into one line per export:
110
+ *
111
+ * - hook `useGeolocation` (package `@ggui-ai/gadgets`) — <desc> (usage: <usage>)
112
+ * - component `Chart` (package `@acme/charts`) — <desc> (usage: <usage>)
113
+ *
114
+ * The leading `hook` / `component` tag teaches the LLM the two render
115
+ * idioms (a hook is CALLED, a component is RENDERED as JSX); the
116
+ * `(package …)` tag carries the npm package name the LLM needs to
117
+ * author the package-keyed
118
+ * `clientCapabilities.gadgets[<package>][<export>]` wire entry.
119
+ *
120
+ * Budget enforcement: per-export text capped at
121
+ * {@link SYNTH_PER_LIBRARY_BUDGET}, total section capped at
122
+ * {@link SYNTH_TOTAL_BUDGET}.
123
+ *
124
+ * Returns `undefined` when the catalog is empty / every export lacks
125
+ * teaching text — the caller then omits the section entirely
126
+ * (preserves the no-registry prompt verbatim for cache hit).
127
+ *
128
+ * Pure helper; exported for the prompt-builder unit test.
129
+ */
130
+ export declare function composeAvailableGadgetsSection(gadgets: readonly GadgetDescriptor[] | undefined): string | undefined;
131
+ //# sourceMappingURL=synthesize-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesize-contract.d.ts","sourceRoot":"","sources":["../src/synthesize-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,0BAA0B,CAAC;AAsBlC,uCAAuC;AACvC,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACzD;AA+ND;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,UA+I7B,CAAC;AAsGF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;CAAE,EACjC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD,GACA,OAAO,CAAC,wBAAwB,CAAC,CAiKnC;AAgUD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,GAC/C,MAAM,GAAG,SAAS,CA+CpB"}