@widgex/wgx 0.0.0-stage → 0.4.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 (130) hide show
  1. package/LICENSE.txt +49 -0
  2. package/README.md +33 -2
  3. package/ThirdPartyNotices.txt +4802 -0
  4. package/package.json +29 -4
  5. package/python/XACTOR.md +146 -0
  6. package/python/browser_actor_host.py +456 -0
  7. package/python/cdp_page.py +363 -0
  8. package/python/harness_check.py +77 -0
  9. package/python/requirements.txt +1 -0
  10. package/python/test_line_endings.py +185 -0
  11. package/python/xactor/__init__.py +18 -0
  12. package/python/xactor/__main__.py +226 -0
  13. package/python/xactor/api.py +882 -0
  14. package/python/xactor/bridge.py +784 -0
  15. package/python/xactor/dom.py +117 -0
  16. package/python/xactor/man/add_card.md +89 -0
  17. package/python/xactor/man/agent-vs-fork.md +108 -0
  18. package/python/xactor/man/agent.md +333 -0
  19. package/python/xactor/man/ask_model.md +110 -0
  20. package/python/xactor/man/ask_reference.md +56 -0
  21. package/python/xactor/man/ask_user.md +103 -0
  22. package/python/xactor/man/attach_app.md +595 -0
  23. package/python/xactor/man/attach_ide.md +65 -0
  24. package/python/xactor/man/attach_ide_surface.md +31 -0
  25. package/python/xactor/man/await_user.md +214 -0
  26. package/python/xactor/man/bash.md +142 -0
  27. package/python/xactor/man/browser-driver.md +137 -0
  28. package/python/xactor/man/browser_activity.md +53 -0
  29. package/python/xactor/man/browser_attach.md +84 -0
  30. package/python/xactor/man/browser_close_tab.md +50 -0
  31. package/python/xactor/man/browser_detach.md +50 -0
  32. package/python/xactor/man/browser_exec.md +66 -0
  33. package/python/xactor/man/browser_focus_tab.md +47 -0
  34. package/python/xactor/man/browser_hybrid.md +47 -0
  35. package/python/xactor/man/browser_open.md +50 -0
  36. package/python/xactor/man/browser_open_tab.md +58 -0
  37. package/python/xactor/man/browser_plumbing.md +107 -0
  38. package/python/xactor/man/browser_screenshot.md +56 -0
  39. package/python/xactor/man/browser_snapshot.md +52 -0
  40. package/python/xactor/man/browser_tabs.md +67 -0
  41. package/python/xactor/man/bulletin.md +88 -0
  42. package/python/xactor/man/capture_page.md +54 -0
  43. package/python/xactor/man/cd.md +64 -0
  44. package/python/xactor/man/chess_move.md +53 -0
  45. package/python/xactor/man/children.md +89 -0
  46. package/python/xactor/man/close_task.md +14 -0
  47. package/python/xactor/man/compact.md +75 -0
  48. package/python/xactor/man/drive.md +140 -0
  49. package/python/xactor/man/drive_space.md +72 -0
  50. package/python/xactor/man/driving.md +168 -0
  51. package/python/xactor/man/edit_file.md +112 -0
  52. package/python/xactor/man/finding.md +194 -0
  53. package/python/xactor/man/fork_agent.md +45 -0
  54. package/python/xactor/man/glob.md +83 -0
  55. package/python/xactor/man/grep.md +115 -0
  56. package/python/xactor/man/harness.md +165 -0
  57. package/python/xactor/man/harness_check.md +70 -0
  58. package/python/xactor/man/harness_format.md +257 -0
  59. package/python/xactor/man/highlight.md +66 -0
  60. package/python/xactor/man/instruct.md +111 -0
  61. package/python/xactor/man/ls.md +63 -0
  62. package/python/xactor/man/man.md +86 -0
  63. package/python/xactor/man/merge_wiz.md +40 -0
  64. package/python/xactor/man/notebook.md +98 -0
  65. package/python/xactor/man/overview.md +89 -0
  66. package/python/xactor/man/permissions.md +137 -0
  67. package/python/xactor/man/phase.md +150 -0
  68. package/python/xactor/man/powershell.md +74 -0
  69. package/python/xactor/man/profiles.md +60 -0
  70. package/python/xactor/man/project_drive.md +49 -0
  71. package/python/xactor/man/read_bulletin.md +89 -0
  72. package/python/xactor/man/read_file.md +90 -0
  73. package/python/xactor/man/relay.md +216 -0
  74. package/python/xactor/man/reply.md +72 -0
  75. package/python/xactor/man/reply_message.md +78 -0
  76. package/python/xactor/man/report_bug.md +118 -0
  77. package/python/xactor/man/request_answer.md +142 -0
  78. package/python/xactor/man/request_merge_decisions.md +121 -0
  79. package/python/xactor/man/request_operator_action.md +152 -0
  80. package/python/xactor/man/request_review.md +122 -0
  81. package/python/xactor/man/request_user_action.md +126 -0
  82. package/python/xactor/man/return_card.md +71 -0
  83. package/python/xactor/man/run.md +99 -0
  84. package/python/xactor/man/sandbox.md +144 -0
  85. package/python/xactor/man/session_fork.md +74 -0
  86. package/python/xactor/man/session_harness.md +109 -0
  87. package/python/xactor/man/session_join.md +102 -0
  88. package/python/xactor/man/session_land.md +73 -0
  89. package/python/xactor/man/session_nudge.md +73 -0
  90. package/python/xactor/man/session_rest.md +73 -0
  91. package/python/xactor/man/session_scope.md +84 -0
  92. package/python/xactor/man/session_terminate.md +58 -0
  93. package/python/xactor/man/session_token.md +78 -0
  94. package/python/xactor/man/sessions.md +93 -0
  95. package/python/xactor/man/set_harness.md +15 -0
  96. package/python/xactor/man/spawn_swarm.md +80 -0
  97. package/python/xactor/man/submit_evidence.md +54 -0
  98. package/python/xactor/man/swarm_brief.md +30 -0
  99. package/python/xactor/man/task_status.md +82 -0
  100. package/python/xactor/man/tasks.md +47 -0
  101. package/python/xactor/man/todo_write.md +104 -0
  102. package/python/xactor/man/update_card.md +70 -0
  103. package/python/xactor/man/use_profile.md +90 -0
  104. package/python/xactor/man/use_widget.md +82 -0
  105. package/python/xactor/man/wait_for_task.md +105 -0
  106. package/python/xactor/man/widget-model.md +284 -0
  107. package/python/xactor/man/widgets.md +59 -0
  108. package/python/xactor/man/write_file.md +76 -0
  109. package/python/xactor/man/writing-a-widget.md +142 -0
  110. package/python/xactor/man/xylon.md +120 -0
  111. package/python/xactor/man/xylon_blame.md +80 -0
  112. package/python/xactor/man/xylon_read.md +131 -0
  113. package/python/xactor/man/xylon_search.md +125 -0
  114. package/python/xactor/manual.py +195 -0
  115. package/python/xactor/parent_watch.py +115 -0
  116. package/python/xactor/plan_mode.py +350 -0
  117. package/python/xactor/sandbox.py +856 -0
  118. package/python/xactor/seals.py +438 -0
  119. package/python/xactor/shell_hints.py +210 -0
  120. package/python/xactor/states/__init__.py +13 -0
  121. package/python/xactor/states/base.py +523 -0
  122. package/python/xactor/states/registry.py +274 -0
  123. package/python/xactor/stdlib_api.py +6345 -0
  124. package/python/xactor/widgets/__init__.py +1 -0
  125. package/python/xactor/widgets/github_tokens.py +314 -0
  126. package/python/xactor/widgets/google_aistudio.py +365 -0
  127. package/settings-schema.json +403 -0
  128. package/viewer/index.css +160 -0
  129. package/viewer/index.js +15 -0
  130. package/wgx.mjs +273753 -0
@@ -0,0 +1,110 @@
1
+ # api.ask_model(model, prompt, system=None, temperature=None, max_tokens=None, stop=None, timeout_seconds=None) -> str
2
+
3
+ <!-- group: Sessions -->
4
+ <!-- also: complete, completion, generate, llm, sample, smiles, local-model -->
5
+
6
+ Ask one model one question. No tools, no subagent, no session. Never asks.
7
+
8
+ `api.agent` hands *work* over — the thing on the other end gets your shell, reads
9
+ files, runs code, and decides for itself when it is done. This hands over
10
+ nothing. It sends a prompt to a model and gives you back what it said, as a
11
+ string.
12
+
13
+ ## When you need it
14
+
15
+ Some models cannot call tools. Not "would rather not" — were never trained to,
16
+ and will never emit a tool call however you prompt them. A chemical language
17
+ model that answers in SMILES strings, a classifier, a fine-tune that returns one
18
+ line: these cannot participate in an agent loop, because an agent loop is made of
19
+ tool calls.
20
+
21
+ `api.agent` refuses them by name, and so does the session picker and the harness
22
+ config. This is the way in.
23
+
24
+ smiles = await api.ask_model(
25
+ 'ollama/smiley:latest',
26
+ 'Generate a drug-like molecule with logP below 5 containing a '
27
+ 'piperazine ring. Reply with the SMILES string only.',
28
+ )
29
+
30
+ You can ask any model this way, not only the tool-less ones — it is simply a
31
+ cheaper shape when all you want is an answer. But for a tool-less model it is the
32
+ only shape available.
33
+
34
+ ## What comes back is data, not work done
35
+
36
+ The string has been checked by nothing. The model that wrote it had no files, no
37
+ shell, and no way to verify its own answer — and it will answer confidently
38
+ whatever you ask it, including about things it has never seen. It does not refuse
39
+ out-of-scope questions; it makes something up.
40
+
41
+ So: parse it, validate it, run it past a real tool, throw away what does not hold
42
+ up. Do not hand one of these a coding task, a file path, or a question about this
43
+ repository.
44
+
45
+ ## Several answers at once
46
+
47
+ There is deliberately no `n`. The OpenAI parameter of that name is not
48
+ implemented by the local runtimes this call exists for, so passing it would
49
+ quietly return one sample while looking like it returned eight.
50
+
51
+ Ask several times instead. Every api call on this shell is a coroutine, and the
52
+ bridge multiplexes them, so this really is concurrent:
53
+
54
+ import asyncio
55
+
56
+ brief = 'Generate a drug-like molecule with a piperazine ring. SMILES only.'
57
+ candidates = await asyncio.gather(*[
58
+ api.ask_model('ollama/smiley:latest', brief, temperature=1.0)
59
+ for _ in range(8)
60
+ ])
61
+
62
+ Raise `temperature` when you do this. At the model's default you may get the same
63
+ answer eight times, which is not a bug and is not useful either.
64
+
65
+ ## Arguments
66
+
67
+ | | |
68
+ |---|---|
69
+ | `model` | `'provider/model'`, or a bare id when only one provider offers it. Unknown ids are refused with the list of what is available. |
70
+ | `prompt` | The whole question. It sees nothing of this conversation. |
71
+ | `system` | A system prompt, if the model expects one. Omitted sends **none at all**, not an empty one — for a fine-tune trained on one exact prompt shape those are different prompts. |
72
+ | `temperature` | 0 to 2. Omit for the model's own default. |
73
+ | `max_tokens` | Cap on the answer. See below. |
74
+ | `stop` | Up to four stop sequences. A bare string is fine. |
75
+ | `timeout_seconds` | Default 300. |
76
+
77
+ ## Hitting `max_tokens` raises
78
+
79
+ A completion that hit its cap does not come back as a short answer — it raises.
80
+
81
+ This is deliberate and it is about the models this call serves. A SMILES string
82
+ truncated mid-token still parses and still looks like a molecule. Returning it
83
+ would let you file something chemically meaningless as a result, and nothing
84
+ downstream would catch it. If you get `AskModelTruncated`, raise `max_tokens` and
85
+ ask again.
86
+
87
+ ## The first call is slow
88
+
89
+ A local model that is not already resident spends thirty seconds or more loading
90
+ before it says its first word. That is why the default timeout is 300 seconds and
91
+ not 30. Subsequent calls are fast until the server unloads it again.
92
+
93
+ `AskModelTimeout` says this in its message, so you can tell it apart from a model
94
+ that is genuinely stuck.
95
+
96
+ ## What it refuses
97
+
98
+ - **A model served by a CLI that runs its own agent loop** — Claude Code, Gemini,
99
+ Antigravity. They expose no completion endpoint. Refused by name rather than
100
+ quietly answered by a different model, because a fabricated answer attributed
101
+ to a model that never saw the prompt is worse than an error.
102
+ - **An unknown or disabled model** — with the list of what is available, and the
103
+ user's own notes on what each is for.
104
+
105
+ ## Related
106
+
107
+ - [[agent]] — hand over work, to a model that can act
108
+ - [[children]] — what you have already started
109
+
110
+ Never gated. It starts nothing, outlives nothing, and touches no file.
@@ -0,0 +1,56 @@
1
+ # api.ask_reference(ref, question, timeout=300) -> dict
2
+ <!-- group: Sessions -->
3
+
4
+ Ask an earlier conversation that the person attached to this chat.
5
+
6
+ A `<reference>` block at the top of a prompt is a summary and a changelog of
7
+ work done somewhere else. When that is not enough — you need to know why
8
+ something was decided, what was tried and dropped, or what a file looked like
9
+ at the time — ask it.
10
+
11
+ ```python
12
+ r = await api.ask_reference(
13
+ "Widgex/Widgex/Browser-Blocked",
14
+ "Did the fix change input coordinates, or only the screencast metadata?",
15
+ )
16
+ print(r["answer"])
17
+ ```
18
+
19
+ ## What happens
20
+
21
+ The first question starts a **fork** of that conversation: a new agent, filed
22
+ under your task, that begins with the summary and changelog and reads the old
23
+ transcript as it needs to. Every later question for the same reference goes to
24
+ that same fork, so it remembers what you already asked. The person can open it
25
+ and read the exchange.
26
+
27
+ ## Options
28
+
29
+ - **`ref`** — the `id` of the reference block. Only a reference attached to
30
+ this conversation can be asked; anything else is refused, and the error lists
31
+ what is attached.
32
+ - **`question`** — one question, specific. The fork quotes the passage an
33
+ answer rests on when you would need to check it; ask for that when it matters.
34
+ - **`timeout`** — seconds to wait. Raise the exec's own `timeout_seconds` past
35
+ it.
36
+
37
+ ## Returns
38
+
39
+ `{answer, session, node, status, error?}`
40
+
41
+ - `status: 'done'` — `answer` is the reply.
42
+ - `status: 'timeout'` — no reply yet, `answer` is empty, and the fork is still
43
+ working. It was not stopped: call again to wait for it.
44
+ - `status: 'error'` — the fork's turn failed; `error` says how.
45
+
46
+ Raises when the reference is not attached here, or when the conversation it
47
+ points at is no longer in the store.
48
+
49
+ ## Do not
50
+
51
+ - **Do not ask what the block already says.** A fork is a real agent and costs
52
+ like one; the summary and changelog are free.
53
+ - **Do not treat an answer as a fact about this working copy.** It describes
54
+ another one. Check any file, function or commit it names before acting on it.
55
+ - **Do not ask it to make changes.** It is told not to, and it is standing in
56
+ your working copy.
@@ -0,0 +1,103 @@
1
+ # api.ask_user(question, options, header=None, multi_select=False) -> str
2
+ <!-- group: Talking to the user -->
3
+
4
+ Ask a multiple-choice question and block for the answer. Not gated.
5
+
6
+ **The answer is arbitrary text.** The card always lets the user type something
7
+ of their own instead of picking, so an option label is a suggestion, not a
8
+ constraint on what comes back.
9
+
10
+ ## Options
11
+
12
+ - **`question`** — the question, as a full sentence. This string is also the
13
+ key the answer is looked up under, so it must be non-empty.
14
+ - **`options`** — 2 to 4 choices. Either plain strings, or dicts of
15
+ `{"label": str, "description": str}` where the description explains the
16
+ trade-off. **Put your recommendation first**, and say so in its label.
17
+ - **`header`** — a short category chip on the card, ~12 characters:
18
+ `"Auth method"`, `"Library"`. Defaults to `"Question"`.
19
+ - **`multi_select`** — allow more than one choice. The answer then comes back
20
+ as the chosen labels joined by `", "`.
21
+
22
+ At least two options are required; a one-option question is rejected with a
23
+ `ValueError` before anything reaches the user.
24
+
25
+ ## Returns
26
+
27
+ A `str`: the label the user chose, the labels they chose joined by `", "`, or
28
+ whatever they typed instead.
29
+
30
+ Raises `RuntimeError` if they dismissed the card without answering. That aborts
31
+ the exec, so do not put irreplaceable work after the call in the same block.
32
+
33
+ ## Examples
34
+
35
+ ```python
36
+ answer = await api.ask_user(
37
+ "Which database should the new service use?",
38
+ [
39
+ {"label": "Postgres (Recommended)",
40
+ "description": "Already used by the billing service; migrations exist."},
41
+ {"label": "SQLite",
42
+ "description": "No server to run, but no concurrent writers."},
43
+ ],
44
+ header="Database",
45
+ )
46
+ return answer
47
+ ```
48
+
49
+ Handling the answer as text, which is what it is:
50
+
51
+ ```python
52
+ answer = await api.ask_user("Ship it now, or wait for review?",
53
+ ["Ship now", "Wait for review"])
54
+ if "ship" in answer.lower():
55
+ ...
56
+ else:
57
+ # covers "Wait for review" *and* "wait until Thursday please"
58
+ ...
59
+ return answer
60
+ ```
61
+
62
+ Multi-select:
63
+
64
+ ```python
65
+ picks = await api.ask_user(
66
+ "Which checks should run in CI?",
67
+ ["Unit tests", "Type check", "Lint", "Bundle size"],
68
+ header="CI checks", multi_select=True,
69
+ )
70
+ return [p.strip() for p in picks.split(",")]
71
+ ```
72
+
73
+ ## Getting it wrong
74
+
75
+ **Comparing against your own labels with `==`.**
76
+
77
+ ```python
78
+ # Wrong — silently takes the else branch when the user typed anything.
79
+ if answer == "Postgres (Recommended)":
80
+ ...
81
+
82
+ # Right — the answer may be free text, so read it rather than match it.
83
+ if "postgres" in answer.lower():
84
+ ...
85
+ ```
86
+
87
+ **Asking for approval of a plan you are about to execute.** Permission prompts
88
+ already cover the gated calls. Use `ask_user` for a decision that changes
89
+ *what* you build, not to seek reassurance.
90
+
91
+ **Asking what you could find out.** If the answer is in the repo, read the
92
+ repo. A question the user has to answer costs them attention you can only spend
93
+ once.
94
+
95
+ **Options that are not mutually exclusive, without `multi_select=True`.** The
96
+ user then has to type, and you lose the structure you asked for.
97
+
98
+ **Losing work to a dismissal.** The `RuntimeError` kills the whole exec. Ask
99
+ first, act after — ideally in the next exec.
100
+
101
+ ## See also
102
+
103
+ `request_user_action`, `todo_write`, `permissions`