@clone-ai/prompt-prediction 0.7.0-bootstrap.0 → 0.7.0

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 (57) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/CONTRIBUTING.md +52 -0
  3. package/LICENSE +21 -0
  4. package/README.md +119 -1
  5. package/SECURITY.md +9 -0
  6. package/dist/assistant-ui.d.ts +5 -0
  7. package/dist/assistant-ui.js +26 -0
  8. package/dist/clone-mode.d.ts +64 -0
  9. package/dist/clone-mode.js +156 -0
  10. package/dist/controller.d.ts +61 -0
  11. package/dist/controller.js +155 -0
  12. package/dist/deadline.d.ts +2 -0
  13. package/dist/deadline.js +25 -0
  14. package/dist/feedback.d.ts +50 -0
  15. package/dist/feedback.js +118 -0
  16. package/dist/generated/api-types.d.ts +1663 -0
  17. package/dist/generated/api-types.js +5 -0
  18. package/dist/http.d.ts +8 -0
  19. package/dist/http.js +35 -0
  20. package/dist/index.d.ts +9 -0
  21. package/dist/index.js +4 -0
  22. package/dist/react.d.ts +50 -0
  23. package/dist/react.js +147 -0
  24. package/dist/server.d.ts +33 -0
  25. package/dist/server.js +93 -0
  26. package/dist/transport.d.ts +15 -0
  27. package/dist/transport.js +42 -0
  28. package/dist/types.d.ts +8 -0
  29. package/dist/types.js +1 -0
  30. package/docs/agent-integration.md +122 -0
  31. package/docs/api.md +69 -0
  32. package/docs/billing.md +53 -0
  33. package/docs/browser-onboarding.md +69 -0
  34. package/docs/clone-mode.md +40 -0
  35. package/docs/context-mapping.md +28 -0
  36. package/docs/data-and-service.md +25 -0
  37. package/docs/developer-apps.md +87 -0
  38. package/docs/feedback.md +70 -0
  39. package/docs/pilot-validation.md +35 -0
  40. package/docs/releases.md +88 -0
  41. package/docs/reliability.md +33 -0
  42. package/docs/start.md +91 -0
  43. package/examples/react/composer-events.ts +3 -0
  44. package/examples/react/demo.tsx +195 -0
  45. package/examples/react/index.html +12 -0
  46. package/examples/react/mode-demo.tsx +95 -0
  47. package/examples/react/pilot-observations.ts +57 -0
  48. package/examples/react/vite.config.ts +123 -0
  49. package/openapi.json +2268 -0
  50. package/package.json +99 -4
  51. package/playwright.config.ts +13 -0
  52. package/release-manifest.json +63 -0
  53. package/scripts/create-example.mjs +31 -0
  54. package/scripts/pilot-metrics.mjs +91 -0
  55. package/tests/browser/clone-mode-options.tsx +38 -0
  56. package/tests/browser/clone-mode.spec.ts +68 -0
  57. package/tests/browser/composer.spec.ts +238 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,120 @@
1
+ # 0.7.0
2
+
3
+ - Publish the JavaScript SDK as `@clone-ai/prompt-prediction`. Update imports, generated integration examples, archive names, npm verification and installation guides. Runtime exports and prediction behavior remain unchanged.
4
+
5
+ # 0.6.4
6
+
7
+ - Include public npm installation instructions in the distributed README and integration guides. Keep exact package versions and checksum-verified archive alternatives aligned, and point billing guidance to the API pricing page.
8
+ - Allow a verified npm release to be published directly as `latest` or `next` through the configured trusted publisher. Preview publication remains the default.
9
+
10
+ # 0.6.3
11
+
12
+ - Keep pilot metrics and feedback events attributed to the originating prediction source. Fault tests remain separate from live and fixture usage after delayed responses, retries or source changes.
13
+ - Include request attribution in example transport metrics and omit unrecognized observations instead of counting them as live usage. Attribution memory is bounded to the latest 1,000 predictions per example server.
14
+
15
+ # 0.6.2
16
+
17
+ - Keep successful submission events when an opted-in edited text exceeds the API content limit; omit the optional text instead of losing the event.
18
+ - Clarify feedback integration: observe SDK insertions, human edits and Undo through the same value callback; keep the tracker stable between renders. The generated example already uses this wiring.
19
+
20
+ # 0.6.1
21
+
22
+ - Fix the example host proxy for an empty feedback-clear POST. Add an HTTP regression check for clearing and origin isolation.
23
+
24
+ # 0.6.0
25
+
26
+ - Packaged feedback tracker and bounded idempotent delivery.
27
+ - Explicit evaluations, rejection and host-observed outcomes. Edited sent text remains opt-in and attributed.
28
+ - Feedback revision and server-side memory clearing in JS and Python (0.2.0).
29
+ - API contract for app/user/grant-scoped feedback memory; requires the matching server rollout.
30
+
31
+ # Changelog
32
+
33
+ ## 0.5.0
34
+
35
+ - Add optional content-free transport timing and outcome observations; broken observers do not affect predictions or submission.
36
+ - Validate isolated customer proxies with opt-in latency and outage injection and private pilot observations. See [pilot validation](docs/pilot-validation.md).
37
+ - Add a typed synchronous and asynchronous [Python client](https://github.com/cloneisyou/clone-sdk/blob/main/python/README.md) for all seven app-key operations, with bounded requests, safe errors and server-owned user identity.
38
+ - Build and verify Python wheels on Python 3.11 and 3.14. Prepare separate, explicit npm and PyPI publication jobs tied to verified release distributions.
39
+
40
+ ## 0.4.0
41
+
42
+ - Choose optional grapheme-safe typewriter presentation with `presentation: "typewriter"`; instant remains the default and Tab waits for the complete candidate.
43
+ - Bound stalled SDK requests with prediction deadlines and server-side concurrency protection; cancellation also covers response-body reads. See [reliability](docs/reliability.md).
44
+ - Offer explicitly started [Clone mode](docs/clone-mode.md) with preview, Stop, scope isolation, turn/time limits, agent attribution, and host completion acknowledgments.
45
+ - Follow the [API guide](docs/api.md) and [agent installation guide](docs/start.md) for API Platform, installation choices, outage handling and personalization.
46
+ - Try the local interaction example at `?clone-mode=1` to inspect preview, Stop and host completion behavior.
47
+
48
+ ## 0.3.1
49
+
50
+ - Clarify installation, entry points and repository layout for public distribution.
51
+ - Group generated types and the executable React demo by responsibility.
52
+ - Clean build outputs and verify the actual package contents before packing.
53
+ - Preserve HTTP body cancellation and reject malformed success envelopes without exposing response text.
54
+ - Expand server authentication, PKCE, transport and packaging regression coverage.
55
+ - Describe the hosted service through its public contract and document the publication review boundary.
56
+
57
+ ## 0.3.0
58
+
59
+ - Align the one-prompt installation guide and billing documentation with the verified 0.3.0 package.
60
+ - Allow an isolated browser-test port through `CLONE_SDK_TEST_PORT`.
61
+
62
+ - Describe company-level PAYG, shared monthly invoices, alert budgets and opt-in hard limits.
63
+ - Represent an unlimited PAYG usage cap as `null` and expose the billing model and cap scope in generated usage types.
64
+ - Preserve prediction behavior and the existing runtime exports.
65
+
66
+ ## 0.2.1
67
+
68
+ - Document app-key authentication and typed success/error responses in the SDK API contract.
69
+ - Limit the contract to the seven app-key operations used by the server client.
70
+ - Derive server client result types from the generated contract.
71
+ - Exclude repository maintenance scripts from the installable package while retaining runnable examples.
72
+ - Provide a public security contact and remove unnecessary internal testing details.
73
+
74
+ ## 0.2.0
75
+
76
+ - Predict from product context without a Clone end-user account or connection.
77
+ - Accept optional app-scoped user preferences; keep Clone profile/Goal personalization opt-in.
78
+ - Invalidate candidates on changes between product context and Clone connections.
79
+ - Update examples and agent onboarding so basic integrations need no callback.
80
+ - `connection_id` is optional/nullable in requests and nullable in responses. App-only responses use an empty profile revision and grant revision zero. Existing connected requests retain their behavior.
81
+ - Hosts must explicitly disable prediction on logout; absence of a Clone connection no longer disables it.
82
+
83
+
84
+ ## 0.1.6
85
+
86
+ - Fix the README integration example to pass the required language field, so the copied TypeScript snippet compiles against the released package.
87
+ - Use the public package type import in the host observation helper so it can be copied into a consumer without rewriting an internal source path.
88
+ - Runtime exports and API schema are unchanged.
89
+
90
+ ## 0.1.5
91
+
92
+ - Fix the examples losing the first typed character after accepting a suggestion when observation state updates during input capture.
93
+ - Include submitted messages, their origins and updated conversation revisions in subsequent predictions for React and assistant-ui examples.
94
+ - Verify exact edited text, manual corrections and history propagation in packaged consumer tests.
95
+ - SDK runtime exports and API schema are unchanged. Live suggestion quality and customer-app acceptance remain separate checks.
96
+
97
+ ## 0.1.4
98
+
99
+ - Executable React and assistant-ui examples now deliver presentation, acceptance, edit, dismissal and explicit-submission observations through the authenticated backend.
100
+ - Preserve each observation ID across delivery retries; do not attribute manual submission after Undo or clearing removes a completion.
101
+ - Include the host attribution helper in generated clean-consumer projects and extend browser acceptance tests.
102
+ - SDK runtime exports and API schema are unchanged. Fixture observations do not prove suggestion quality or customer adoption.
103
+
104
+ ## 0.1.3
105
+
106
+ - Private beta delivery through authenticated GitHub release downloads, checksum verification, and local archive dependencies.
107
+ - Customer-agent prerequisites and CI instructions now describe repository access explicitly.
108
+ - Release CI verifies authenticated download and installation; public npm publication is blocked while the repository is private.
109
+ - Runtime behavior, API schema and the MIT license are unchanged.
110
+
111
+ ## 0.1.2
112
+
113
+ First standalone open-source preview, following private package versions 0.1.0 and 0.1.1.
114
+
115
+ - MIT-licensed headless controller, React input/hook, optional assistant-ui adapter, and server client.
116
+ - Public API schema, agent integration guide, and synthetic video/slide examples.
117
+ - Independent build, unit tests, Chromium interaction tests, and packaged React 18/19 consumer checks.
118
+ - Separate public Git history, versioned release archives, and publication checks.
119
+
120
+ Hosted service access is provisioned separately. This release does not establish live suggestion quality, native OS IME support, or acceptance in third-party applications.
@@ -0,0 +1,52 @@
1
+ # Contributing
2
+
3
+ Use Node 22.13+ and pnpm 11.19.0. Run `pnpm install --frozen-lockfile` from this repository. The default demo and all CI tests use synthetic data and need no API credentials.
4
+
5
+ Before proposing a change, run:
6
+
7
+ ```sh
8
+ pnpm generate:types
9
+ git diff --exit-code -- src/generated/api-types.ts
10
+ pnpm check
11
+ pnpm exec playwright install chromium
12
+ pnpm test:browser
13
+ pnpm test:package
14
+ pnpm check:public
15
+ ```
16
+
17
+ For API contract changes, update `openapi.json` and regenerate the public types. Coordinate deployed service compatibility separately. Never copy an entire private service schema or implementation into this repository.
18
+
19
+ Keep existing composer submission behavior intact. Test candidate insertion, Undo, dismissal, focus traversal, stale results, account/context changes, and composition handling when relevant. Browser composition events do not substitute for testing a native input method.
20
+
21
+ Use synthetic examples. Do not submit credentials, private prompts, user conversations, customer names, internal links, screenshots of real accounts, or private repository history. Review your staged diff and author identity before pushing; public pull requests and workflow logs are public artifacts too. The automated checks are aids, not a complete disclosure review.
22
+
23
+ Contributions are provided under this repository's MIT license. Declare any imported third-party code and preserve its license notices. Runtime dependencies retain their own licenses; no third-party runtime source is vendored here.
24
+
25
+ This is the canonical SDK repository. Consume versioned npm packages or verified GitHub release archives in downstream applications. For local changes, build and pack this repository, then install the tarball in a consumer; do not maintain a second SDK source copy or add a Git submodule just to use the package.
26
+
27
+ ## Repository layout
28
+
29
+ ```text
30
+ src/ SDK implementation and stable entry points
31
+ generated/ Types generated from openapi.json
32
+ examples/react/ Runnable React and assistant-ui demo, loopback backend
33
+ scripts/ Build, package verification and example generator
34
+ lib/ Shared publication checks
35
+ tests/ Unit tests for controller, HTTP and server boundaries
36
+ browser/ Composer interaction tests
37
+ scripts/ Build and publication regression tests
38
+ docs/ Integration, account, data and release guides
39
+ .github/workflows/ Validation and opt-in release workflows
40
+ ```
41
+
42
+ Keep the four package entry points stable. The controller owns prediction state; React owns native input interaction; HTTP decoding is shared by browser and server transports. Generated API types have one source of truth: `openapi.json`.
43
+
44
+ The demo's loopback backend belongs under `examples/react`; it is not part of the runtime library. Build output is disposable and is cleaned before every build. The release manifest follows npm's actual file selection and checks each included file. `pnpm typecheck` also checks examples and test code. `pnpm test:scripts` checks cleanup and rejection of unintended package contents. Keep audit reports outside the repository.
45
+
46
+ After moving source modules, regenerate and test the packed consumer. Update example-generator import mappings whenever example imports change. Never edit generated types directly.
47
+
48
+ ## Public documentation boundary
49
+
50
+ Document the SDK, public request/response contract, customer-visible behavior and data-use commitments. Keep the hosted service implementation out of this repository, including model choices, internal prompts, algorithms, storage design, infrastructure and operational procedures. Treat service-issued identifiers and revisions as opaque values. A required payment or consent disclosure must remain accurate.
51
+
52
+ Secret scanning does not establish that content is suitable for publication. Review prose, comments, generated files and the packed archive as well as code. Before making an existing repository public, review every branch and tag, Git history, pull requests, releases, Actions artifacts and logs. A clean latest commit does not sanitize those earlier records. Keep detailed audit findings in the private review location, not in public commits or release notes.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Clone contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,121 @@
1
1
  # Clone SDK
2
2
 
3
- This registration version configures verified CI publishing. Use the documented SDK version from https://clone.is/docs/sdk-quickstart.
3
+ Add next-prompt prediction and Tab completion to your existing composer. Suggestions appear as ghost text. **Tab inserts; your application decides when to send.**
4
+
5
+ **SDK 0.7.0:** instant display remains the default. Set `presentation="typewriter"` for a cancellable display animation after the complete JSON response arrives; the API does not stream. These options and Clone mode are absent from the 0.3.1 package. Keep ordinary typing and sending available when predictions are loading, fail, or never return. See the [rendering contract](docs/agent-integration.md#suggestion-rendering-contract) before building a custom editor adapter.
6
+
7
+ Use your product's conversation, selected artifact and user preferences as context. Your end users do not need a Clone account. Connecting a user's Clone context is optional.
8
+
9
+ - **Headless controller** for custom editors.
10
+ - **React hook and textarea**, plus an optional assistant-ui adapter.
11
+ - **Server client** for prediction, usage and optional account connection.
12
+ - **Python server client**, with sync and async interfaces. See [Python installation and usage](https://github.com/cloneisyou/clone-sdk/blob/main/python/README.md).
13
+ - **Optional Clone mode**, explicitly started by the end user, with preview, Stop and bounded automatic sends. See [Clone mode](docs/clone-mode.md).
14
+ - **Direct HTTPS API** for any backend or custom interface. See [API integration](docs/api.md).
15
+ - **MIT licensed SDK.** The hosted prediction API is a separate service that requires a server-side app key. See [service boundaries](docs/data-and-service.md) and [billing](docs/billing.md).
16
+
17
+ ## Quick start
18
+
19
+ Open your product repository in your coding agent and paste:
20
+
21
+ ```text
22
+ Read https://clone.is/docs/sdk-quickstart and integrate Clone SDK into this product using the documented npm version and a lockfile. Discover our composer, backend and authentication; reuse existing setup and keep app keys server-side. Wire prediction, acceptance, edits, explicit evaluations and rejection, successful submission and observed task outcomes through the authenticated backend. Preserve typing, IME, Undo and manual sending during delays and outages. Ask only about unresolved product choices; keep personalization, automatic sending, feedback text collection and paid usage opt-in. Verify the actual integration and report installation, feedback delivery, outage results and pending live/customer checks separately.
23
+ ```
24
+
25
+ Your agent will handle setup, integration and verification. Production onboarding includes company account, app registration, pricing and card setup before SDK installation. You personally complete login, billing consent and card entry; no fee is charged at card registration. Choose **Try the free sandbox** for a separate card-free evaluation.
26
+
27
+ <details>
28
+ <summary>Manual setup</summary>
29
+
30
+ First complete [production app and card setup](https://clone.is/developer/apps?setup=production), or explicitly choose the [free sandbox](https://clone.is/developer/apps?setup=sandbox). Save the one-time app key on your backend before leaving the console. Then install the package below.
31
+
32
+ Node **22.13+**, ESM. React integrations support **18 and 19**. The headless controller and server client do not require React.
33
+
34
+ Install the public npm package. Existing integrations can keep their pinned version while validating an upgrade:
35
+
36
+ ```sh
37
+ npm install --save-exact @clone-ai/prompt-prediction@0.7.0
38
+ ```
39
+
40
+ Use your project's package manager and commit its lockfile. Verified [GitHub release archives](docs/releases.md#download-and-install) remain available. Hosted API access requires a separate app key.
41
+
42
+ ```tsx
43
+ 'use client';
44
+ import { useState } from 'react';
45
+ import { createPredictionTransport } from '@clone-ai/prompt-prediction';
46
+ import { TabCompletionInput } from '@clone-ai/prompt-prediction/react';
47
+
48
+ const transport = createPredictionTransport('/api/clone/predict');
49
+
50
+ export function Composer({ threadId, contextRevision }: {
51
+ threadId: string;
52
+ contextRevision: string;
53
+ }) {
54
+ const [value, setValue] = useState('');
55
+
56
+ return (
57
+ <TabCompletionInput
58
+ aria-label="Instruction"
59
+ value={value}
60
+ onValueChange={setValue}
61
+ transport={transport}
62
+ context={{
63
+ session_id: threadId,
64
+ context_revision: contextRevision,
65
+ language: 'auto',
66
+ messages: [],
67
+ }}
68
+ />
69
+ );
70
+ }
71
+ ```
72
+
73
+ Implement `/api/clone/predict` in your authenticated backend using `CloneClient` from `@clone-ai/prompt-prediction/server`. Derive the user ID from the server session. Keep the app key on the server, never in browser code or `VITE_*` / `NEXT_PUBLIC_*` variables. Pass your real conversation and advance `context_revision` when it changes.
74
+
75
+ For complete setup and verification, follow the [integration guide](docs/start.md).
76
+
77
+ </details>
78
+
79
+ ## Try the demo
80
+
81
+ ```sh
82
+ git clone https://github.com/cloneisyou/clone-sdk.git
83
+ cd clone-sdk
84
+ corepack enable
85
+ pnpm install --frozen-lockfile
86
+ pnpm dev
87
+ ```
88
+
89
+ Open [localhost:4317](http://127.0.0.1:4317). Type, accept with Tab, then send explicitly. Add `?assistant=1` to try assistant-ui. The default demo uses synthetic suggestions and sends nothing to Clone.
90
+
91
+ For a connected proxy, outage testing and private measurements, follow [pilot validation](docs/pilot-validation.md). Synthetic checks, real model calls and customer acceptance are separate evidence.
92
+
93
+ ## Choose an entry point
94
+
95
+ | Import | Use it for |
96
+ | --- | --- |
97
+ | `@clone-ai/prompt-prediction` | Controller, browser transport, errors and public types |
98
+ | `@clone-ai/prompt-prediction/react` | `useTabCompletion` or `TabCompletionInput` |
99
+ | `@clone-ai/prompt-prediction/assistant-ui` | `CloneComposerInput` inside an existing assistant-ui composer |
100
+ | `@clone-ai/prompt-prediction/server` | `CloneClient` and optional PKCE connection flow |
101
+
102
+ The React input uses a native textarea. Rich-text editors need an insertion and Undo adapter around the controller. The assistant-ui adapter targets `@assistant-ui/react@0.15.21` and uses its `unstable_useComposerInput` hook; verify compatibility before upgrading it.
103
+
104
+ ## Develop
105
+
106
+ ```sh
107
+ pnpm check
108
+ pnpm exec playwright install chromium
109
+ pnpm test:browser
110
+ pnpm test:package
111
+ ```
112
+
113
+ Package tests install the actual archive into React 18 and 19 consumers and verify build, Tab insertion, Undo, explicit send and context changes. These checks do not establish suggestion quality, native OS IME behavior or acceptance in your application.
114
+
115
+ See [Contributing](CONTRIBUTING.md) for the repository layout and validation commands, [context mapping](docs/context-mapping.md) for request design, [reliability](docs/reliability.md) for outage handling and limits, and [Releases](docs/releases.md) for distribution.
116
+
117
+ [Security](SECURITY.md) · [Changelog](CHANGELOG.md) · [MIT license](LICENSE)
118
+
119
+ ## Feedback loop
120
+
121
+ SDK 0.7.0 can return explicit rejection, evaluations, edited successful submissions and host-observed outcomes to the API. Wire the packaged tracker to your host send and authenticated proxy. Text collection is off by default. See [feedback integration](docs/feedback.md) for scoped memory, delivery, expiry and clearing. These features require the API feedback deployment; event collection alone is not model learning.
package/SECURITY.md ADDED
@@ -0,0 +1,9 @@
1
+ # Security
2
+
3
+ Report suspected vulnerabilities privately to [contact@clone.is](mailto:contact@clone.is) with the subject **Clone SDK security report**. This is Clone's published [security and privacy contact](https://clone.is/privacy). It is available to all reporters, including people without repository access or an existing integration contact. Do not use public issues for security reports or include live keys, personal data, or account screenshots. Include the affected SDK version, impact and a synthetic reproduction.
4
+
5
+ When this repository becomes public and private vulnerability reporting is enabled, GitHub's Security tab can also provide a private reporting form. Until that form is confirmed available, use the email address above.
6
+
7
+ App keys and PKCE flow state belong on your authenticated server. This SDK does not replace your session authentication, CSRF checks, origin policy, or per-user connection storage. The included loopback backend uses one synthetic identity and in-memory state; it is not a production authentication example.
8
+
9
+ The current preview is maintained on the latest 0.x version. There is no promised security-response SLA. Hosted service security and data-processing terms are separate from the SDK license.
@@ -0,0 +1,5 @@
1
+ import type { TabCompletionInputProps } from './react.js';
2
+ /** Place inside your existing assistant-ui ComposerPrimitive.Root/runtime.
3
+ * Only reads/writes composer text; submission stays with the existing host form.
4
+ */
5
+ export declare function CloneComposerInput(props: Omit<TabCompletionInputProps, 'value' | 'onValueChange'>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { unstable_useComposerInput } from '@assistant-ui/react';
4
+ import { useState } from 'react';
5
+ import { TabCompletionInput } from './react.js';
6
+ /** Place inside your existing assistant-ui ComposerPrimitive.Root/runtime.
7
+ * Only reads/writes composer text; submission stays with the existing host form.
8
+ */
9
+ export function CloneComposerInput(props) {
10
+ // This version-pinned public hook flushes external-store input updates before
11
+ // React restores the DOM, preserving native Undo and composition behavior.
12
+ const composer = unstable_useComposerInput({ disabled: props.disabled });
13
+ // Native edits also need immediate local state: an external store can render
14
+ // after React has already restored the old controlled value during execCommand.
15
+ const [local, setLocal] = useState({ value: composer.value, external: composer.value });
16
+ if (local.external !== composer.value)
17
+ setLocal({ value: composer.value, external: composer.value });
18
+ return _jsx(TabCompletionInput, { ...props, value: local.external === composer.value ? local.value : composer.value, onValueChange: value => { setLocal({ value, external: composer.value }); composer.setText(value); }, disabled: composer.isDisabled, onKeyDown: event => {
19
+ props.onKeyDown?.(event);
20
+ if (!event.defaultPrevented && event.key === 'Enter' && !event.shiftKey
21
+ && !event.nativeEvent.isComposing && event.keyCode !== 229 && composer.canSend) {
22
+ event.preventDefault();
23
+ composer.send();
24
+ }
25
+ } });
26
+ }
@@ -0,0 +1,64 @@
1
+ import type { CompletionRequest, PredictionOutput, PredictionTransport } from './types.js';
2
+ export interface CloneModeInput {
3
+ /** Bind to the authenticated host user and thread. Never reuse across users. */
4
+ scopeId: string;
5
+ context: Omit<CompletionRequest, 'draft' | 'mode' | 'request_id'>;
6
+ draft: string;
7
+ enabled: boolean;
8
+ busy: boolean;
9
+ composing?: boolean;
10
+ visible?: boolean;
11
+ }
12
+ export interface CloneModeState {
13
+ status: 'off' | 'predicting' | 'reviewing' | 'submitting' | 'waiting' | 'stopped';
14
+ sent: number;
15
+ maxTurns: number;
16
+ candidate: PredictionOutput | null;
17
+ sendAt: number | null;
18
+ reason: string | null;
19
+ }
20
+ export interface CloneModeOptions {
21
+ transport: PredictionTransport;
22
+ /** Return true only after the host accepted the send. Unknown outcomes must not be retried. */
23
+ onSubmit: (text: string, metadata: {
24
+ requestId: string;
25
+ origin: 'agent';
26
+ signal: AbortSignal;
27
+ }) => Promise<boolean>;
28
+ reviewMs?: number;
29
+ requestTimeoutMs?: number;
30
+ }
31
+ /** Explicit, bounded delegation. Normal Tab completion never starts this controller. */
32
+ export declare class CloneModeController {
33
+ private readonly options;
34
+ private input;
35
+ private disposed;
36
+ private scope;
37
+ private epoch;
38
+ private abort;
39
+ private timer;
40
+ private sessionTimer;
41
+ private pendingSubmission;
42
+ private submittedRevision;
43
+ private usedRequests;
44
+ private listeners;
45
+ private state;
46
+ constructor(options: CloneModeOptions);
47
+ getSnapshot: () => CloneModeState;
48
+ subscribe: (listener: () => void) => () => void;
49
+ private emit;
50
+ private identity;
51
+ private eligible;
52
+ update(input: CloneModeInput): void;
53
+ /** Call only from the end user's explicit Start action, never on mount or restore. */
54
+ start({ maxTurns, maxDurationMs }?: {
55
+ maxTurns?: number;
56
+ maxDurationMs?: number;
57
+ }): boolean;
58
+ stop(reason?: string): void;
59
+ /** Call after a real host turn finishes and its new context has been supplied via update(). */
60
+ turnCompleted(): boolean;
61
+ private predict;
62
+ private submit;
63
+ dispose(): void;
64
+ }
@@ -0,0 +1,156 @@
1
+ import { withDeadline } from './deadline.js';
2
+ /** Explicit, bounded delegation. Normal Tab completion never starts this controller. */
3
+ export class CloneModeController {
4
+ options;
5
+ input = null;
6
+ disposed = false;
7
+ scope = '';
8
+ epoch = 0;
9
+ abort = new AbortController();
10
+ timer;
11
+ sessionTimer;
12
+ pendingSubmission = false;
13
+ submittedRevision = '';
14
+ usedRequests = new Set();
15
+ listeners = new Set();
16
+ state = { status: 'off', sent: 0, maxTurns: 3, candidate: null, sendAt: null, reason: null };
17
+ constructor(options) {
18
+ this.options = options;
19
+ }
20
+ getSnapshot = () => this.state;
21
+ subscribe = (listener) => { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; };
22
+ emit(change) {
23
+ this.state = { ...this.state, ...change };
24
+ for (const listener of this.listeners)
25
+ listener();
26
+ }
27
+ identity(input) {
28
+ return JSON.stringify([input.scopeId, input.context.session_id, input.context.connection_id ?? null]);
29
+ }
30
+ eligible() {
31
+ return this.input?.enabled && this.input.visible !== false && !this.input.draft && !this.input.composing;
32
+ }
33
+ update(input) {
34
+ if (this.disposed)
35
+ return;
36
+ // Detach from host objects that may be mutated while a request is in flight.
37
+ const next = structuredClone(input);
38
+ const active = !['off', 'stopped'].includes(this.state.status);
39
+ const contextChanged = this.input && JSON.stringify(this.input.context) !== JSON.stringify(next.context);
40
+ this.input = next;
41
+ if (!active)
42
+ return;
43
+ if (this.identity(next) !== this.scope)
44
+ this.stop('scope_changed');
45
+ else if (!this.eligible())
46
+ this.stop(next.draft || next.composing ? 'user_input' : 'unavailable');
47
+ else if (['predicting', 'reviewing'].includes(this.state.status) && (contextChanged || next.busy))
48
+ this.stop('context_changed');
49
+ }
50
+ /** Call only from the end user's explicit Start action, never on mount or restore. */
51
+ start({ maxTurns = 3, maxDurationMs = 300_000 } = {}) {
52
+ if (this.disposed || !this.input || !this.eligible() || this.input.busy || this.pendingSubmission
53
+ || !['off', 'stopped'].includes(this.state.status))
54
+ return false;
55
+ if (!Number.isInteger(maxTurns) || maxTurns < 1 || maxTurns > 100
56
+ || !Number.isFinite(maxDurationMs) || maxDurationMs < 1000 || maxDurationMs > 3_600_000)
57
+ throw new Error('Invalid Clone mode limits');
58
+ this.stop('restarted');
59
+ this.abort = new AbortController();
60
+ this.scope = this.identity(this.input);
61
+ this.usedRequests.clear();
62
+ const epoch = this.epoch;
63
+ this.emit({ status: 'predicting', sent: 0, maxTurns, candidate: null, sendAt: null, reason: null });
64
+ if (epoch !== this.epoch)
65
+ return false;
66
+ this.sessionTimer = setTimeout(() => this.stop('time_limit'), maxDurationMs);
67
+ void this.predict();
68
+ return true;
69
+ }
70
+ stop(reason = 'user_stopped') {
71
+ this.epoch++;
72
+ this.abort.abort();
73
+ clearTimeout(this.timer);
74
+ clearTimeout(this.sessionTimer);
75
+ this.emit({ status: 'stopped', candidate: null, sendAt: null, reason });
76
+ }
77
+ /** Call after a real host turn finishes and its new context has been supplied via update(). */
78
+ turnCompleted() {
79
+ if (this.state.status !== 'waiting' || !this.input || this.input.busy || !this.eligible()
80
+ || this.input.context.context_revision === this.submittedRevision)
81
+ return false;
82
+ if (this.state.sent >= this.state.maxTurns) {
83
+ this.stop('turn_limit');
84
+ return false;
85
+ }
86
+ void this.predict();
87
+ return true;
88
+ }
89
+ async predict() {
90
+ const input = this.input;
91
+ const epoch = this.epoch;
92
+ const request = { ...input.context, connection_id: input.context.connection_id ?? null,
93
+ request_id: crypto.randomUUID(), mode: 'next_prompt', draft: { text: '', revision: 0 } };
94
+ this.emit({ status: 'predicting', candidate: null, sendAt: null });
95
+ if (epoch !== this.epoch)
96
+ return;
97
+ try {
98
+ const timeout = this.options.requestTimeoutMs ?? 15_000;
99
+ const candidate = await withDeadline(signal => this.options.transport(request, { signal }), Number.isFinite(timeout) ? Math.max(1, Math.min(timeout, 30_000)) : 15_000, this.abort.signal);
100
+ if (epoch !== this.epoch)
101
+ return;
102
+ if (!candidate || candidate.request_id !== request.request_id || candidate.session_id !== request.session_id
103
+ || candidate.context_revision !== request.context_revision || candidate.connection_id !== request.connection_id
104
+ || candidate.draft_revision !== 0 || !Number.isFinite(candidate.expires_at))
105
+ return this.stop('invalid_prediction');
106
+ if (candidate.status === 'abstained')
107
+ return this.stop('abstained');
108
+ if (candidate.status !== 'suggested' || typeof candidate.completion !== 'string' || !candidate.completion.trim())
109
+ return this.stop('invalid_prediction');
110
+ const delay = this.options.reviewMs ?? 2000;
111
+ const reviewMs = Number.isFinite(delay) ? Math.max(1000, Math.min(delay, 10_000)) : 2000;
112
+ const sendAt = Date.now() + reviewMs;
113
+ if (candidate.expires_at * 1000 <= sendAt)
114
+ return this.stop('expired');
115
+ this.emit({ status: 'reviewing', candidate, sendAt });
116
+ if (epoch === this.epoch)
117
+ this.timer = setTimeout(() => void this.submit(candidate, epoch), reviewMs);
118
+ }
119
+ catch {
120
+ if (epoch === this.epoch)
121
+ this.stop('prediction_failed');
122
+ }
123
+ }
124
+ async submit(candidate, epoch) {
125
+ if (epoch !== this.epoch)
126
+ return;
127
+ if (!this.input || !this.eligible() || this.input.busy
128
+ || candidate.expires_at * 1000 <= Date.now() || this.usedRequests.has(candidate.request_id))
129
+ return this.stop('not_ready');
130
+ this.usedRequests.add(candidate.request_id);
131
+ this.submittedRevision = this.input.context.context_revision;
132
+ this.pendingSubmission = true;
133
+ this.emit({ status: 'submitting', sendAt: null });
134
+ try {
135
+ if (epoch !== this.epoch)
136
+ return;
137
+ const accepted = await this.options.onSubmit(candidate.completion, { requestId: candidate.request_id, origin: 'agent', signal: this.abort.signal });
138
+ if (epoch !== this.epoch)
139
+ return;
140
+ if (!accepted)
141
+ return this.stop('send_rejected');
142
+ const sent = this.state.sent + 1;
143
+ this.emit({ status: 'waiting', sent, candidate: null });
144
+ if (sent >= this.state.maxTurns)
145
+ this.stop('turn_limit');
146
+ }
147
+ catch {
148
+ if (epoch === this.epoch)
149
+ this.stop('send_failed');
150
+ }
151
+ finally {
152
+ this.pendingSubmission = false;
153
+ }
154
+ }
155
+ dispose() { this.disposed = true; this.stop('disposed'); this.listeners.clear(); }
156
+ }
@@ -0,0 +1,61 @@
1
+ import type { CompletionRequest, PredictionOutput, PredictionTransport } from './types.js';
2
+ export interface CompletionInput {
3
+ value: string;
4
+ revision: number;
5
+ context: Omit<CompletionRequest, 'draft' | 'mode' | 'request_id'>;
6
+ focused: boolean;
7
+ composing: boolean;
8
+ selectionStart: number;
9
+ selectionEnd: number;
10
+ enabled?: boolean;
11
+ }
12
+ export interface CompletionState {
13
+ status: 'idle' | 'loading' | 'suggested' | 'unavailable';
14
+ candidate: PredictionOutput | null;
15
+ error: string | null;
16
+ /** Full in instant mode; a grapheme-safe prefix during optional animation. */
17
+ visibleCompletion: string;
18
+ }
19
+ export interface AcceptedCompletion {
20
+ value: string;
21
+ suffix: string;
22
+ requestId: string;
23
+ }
24
+ export interface CompletionOptions {
25
+ transport: PredictionTransport;
26
+ debounceMs?: number;
27
+ maxRequestsPerMinute?: number;
28
+ requestTimeoutMs?: number;
29
+ presentation?: 'instant' | 'typewriter';
30
+ onEvent?: (event: {
31
+ request_id: string;
32
+ kind: 'presented' | 'accepted' | 'dismissed';
33
+ }) => void;
34
+ }
35
+ /** Prediction lifecycle only. It has no submit, agent, or execution API. */
36
+ export declare class CompletionController {
37
+ private readonly options;
38
+ private input;
39
+ private key;
40
+ private generation;
41
+ private timer;
42
+ private expiry;
43
+ private animation;
44
+ private deadline;
45
+ private abort;
46
+ private listeners;
47
+ private requestTimes;
48
+ private disposed;
49
+ private state;
50
+ constructor(options: CompletionOptions);
51
+ getSnapshot: () => CompletionState;
52
+ subscribe: (listener: () => void) => (() => void);
53
+ private emit;
54
+ private event;
55
+ private invalidate;
56
+ update(input: CompletionInput): void;
57
+ private predict;
58
+ accept(): AcceptedCompletion | null;
59
+ dismiss(report?: boolean): void;
60
+ dispose(): void;
61
+ }