@korallis/k-pi 0.1.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 (348) hide show
  1. package/CHANGELOG.md +5619 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +66 -0
  4. package/README.md +723 -0
  5. package/dist/bundle/chunks/anthropic-messages-IBCPCIJO.js +45 -0
  6. package/dist/bundle/chunks/anthropic.js +75 -0
  7. package/dist/bundle/chunks/azure-openai-responses-GUUG57CZ.js +2 -0
  8. package/dist/bundle/chunks/bedrock-converse-stream.js +74 -0
  9. package/dist/bundle/chunks/chunk-4L3WN2XY.js +2 -0
  10. package/dist/bundle/chunks/chunk-6CYCI3EJ.js +12 -0
  11. package/dist/bundle/chunks/chunk-6R7UI4IY.js +2 -0
  12. package/dist/bundle/chunks/chunk-AXIIZGTV.js +2 -0
  13. package/dist/bundle/chunks/chunk-CO7LIZG5.js +2 -0
  14. package/dist/bundle/chunks/chunk-DRQDKNXA.js +2 -0
  15. package/dist/bundle/chunks/chunk-GMWCTUPB.js +2 -0
  16. package/dist/bundle/chunks/chunk-HOFU6X66.js +50 -0
  17. package/dist/bundle/chunks/chunk-JUUC5AZY.js +2 -0
  18. package/dist/bundle/chunks/chunk-L2ZPNLYD.js +2 -0
  19. package/dist/bundle/chunks/chunk-MNAIPA3J.js +2 -0
  20. package/dist/bundle/chunks/chunk-NBBFIJUL.js +11 -0
  21. package/dist/bundle/chunks/chunk-NUHFSC37.js +25 -0
  22. package/dist/bundle/chunks/chunk-PGXDEOVV.js +2 -0
  23. package/dist/bundle/chunks/chunk-PJACZCIR.js +2 -0
  24. package/dist/bundle/chunks/chunk-PRRNXB7S.js +2 -0
  25. package/dist/bundle/chunks/chunk-TEPMHNKQ.js +2 -0
  26. package/dist/bundle/chunks/chunk-TRDNDS6A.js +4 -0
  27. package/dist/bundle/chunks/chunk-UAQELI3K.js +2 -0
  28. package/dist/bundle/chunks/chunk-X5QHCKY4.js +1653 -0
  29. package/dist/bundle/chunks/chunk-XDUWOHPL.js +6 -0
  30. package/dist/bundle/chunks/github-copilot.js +2 -0
  31. package/dist/bundle/chunks/google-generative-ai-YRXF7C4I.js +2 -0
  32. package/dist/bundle/chunks/google-vertex-BVZ6VBRQ.js +2 -0
  33. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
  34. package/dist/bundle/chunks/image-resize-worker.js +2 -0
  35. package/dist/bundle/chunks/kimi-coding.js +2 -0
  36. package/dist/bundle/chunks/lib-HGQMNYVT.js +9 -0
  37. package/dist/bundle/chunks/mistral-conversations-Q3AWZJAZ.js +5 -0
  38. package/dist/bundle/chunks/multipart-parser-SQ6GDJL7.js +3 -0
  39. package/dist/bundle/chunks/openai-codex-responses-GJVBJXLB.js +8 -0
  40. package/dist/bundle/chunks/openai-codex.js +75 -0
  41. package/dist/bundle/chunks/openai-completions-OICQQ5JB.js +7 -0
  42. package/dist/bundle/chunks/openai-responses-P5LIZTXX.js +2 -0
  43. package/dist/bundle/chunks/openrouter-images-XTKS2AS3.js +2 -0
  44. package/dist/bundle/chunks/openrouter.js +75 -0
  45. package/dist/bundle/chunks/pi-messages-TPFH44NP.js +8 -0
  46. package/dist/bundle/chunks/radius.js +75 -0
  47. package/dist/bundle/chunks/src-UK77SYZE.js +4 -0
  48. package/dist/bundle/chunks/xai.js +2 -0
  49. package/dist/bundle/cli.js +3 -0
  50. package/dist/bundle/client.js +2 -0
  51. package/dist/bundle/index.js +2 -0
  52. package/dist/bundle/rpc-entry.js +3 -0
  53. package/dist/core/export-html/template.css +1066 -0
  54. package/dist/core/export-html/template.html +55 -0
  55. package/dist/core/export-html/template.js +1864 -0
  56. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  57. package/dist/core/export-html/vendor/marked.min.js +78 -0
  58. package/dist/kpi/graphs/coding-loop.auto.json +377 -0
  59. package/dist/kpi/graphs/coding-loop.gated.json +417 -0
  60. package/dist/kpi/graphs/spec-first.json +40 -0
  61. package/dist/kpi/kstack/NOTICE +5 -0
  62. package/dist/kpi/kstack/UPSTREAM.md +23 -0
  63. package/dist/kpi/kstack/generated/LICENSE +21 -0
  64. package/dist/kpi/kstack/generated/skills/architect/SKILL.md +83 -0
  65. package/dist/kpi/kstack/generated/skills/architect/references/design-red-flags.md +33 -0
  66. package/dist/kpi/kstack/generated/skills/architect/references/rationale-template.md +35 -0
  67. package/dist/kpi/kstack/generated/skills/architect/references/runner-prompt.md +20 -0
  68. package/dist/kpi/kstack/generated/skills/arena/SKILL.md +29 -0
  69. package/dist/kpi/kstack/generated/skills/blast-radius/SKILL.md +50 -0
  70. package/dist/kpi/kstack/generated/skills/bro/SKILL.md +7 -0
  71. package/dist/kpi/kstack/generated/skills/create-verification-skill/SKILL.md +44 -0
  72. package/dist/kpi/kstack/generated/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  73. package/dist/kpi/kstack/generated/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  74. package/dist/kpi/kstack/generated/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  75. package/dist/kpi/kstack/generated/skills/figure-it-out/SKILL.md +55 -0
  76. package/dist/kpi/kstack/generated/skills/how/SKILL.md +135 -0
  77. package/dist/kpi/kstack/generated/skills/how/references/critic-prompt.md +59 -0
  78. package/dist/kpi/kstack/generated/skills/how/references/critique-rubric.md +58 -0
  79. package/dist/kpi/kstack/generated/skills/how/references/explainer-prompt.md +55 -0
  80. package/dist/kpi/kstack/generated/skills/how/references/explorer-prompt.md +52 -0
  81. package/dist/kpi/kstack/generated/skills/interrogate/SKILL.md +113 -0
  82. package/dist/kpi/kstack/generated/skills/interrogate/references/code-quality-review.md +47 -0
  83. package/dist/kpi/kstack/generated/skills/interrogate/references/lead-judgment.md +58 -0
  84. package/dist/kpi/kstack/generated/skills/interrogate/references/reviewer-prompt.md +72 -0
  85. package/dist/kpi/kstack/generated/skills/interrogate/references/rubric.md +77 -0
  86. package/dist/kpi/kstack/generated/skills/k-agent/SKILL.md +17 -0
  87. package/dist/kpi/kstack/generated/skills/k-mode/SKILL.md +64 -0
  88. package/dist/kpi/kstack/generated/skills/k-stack-principles/SKILL.md +24 -0
  89. package/dist/kpi/kstack/generated/skills/maintain-verification-skill/SKILL.md +39 -0
  90. package/dist/kpi/kstack/generated/skills/no-comments/SKILL.md +24 -0
  91. package/dist/kpi/kstack/generated/skills/playbook-arena/SKILL.md +20 -0
  92. package/dist/kpi/kstack/generated/skills/playbook-autonomous-run/SKILL.md +22 -0
  93. package/dist/kpi/kstack/generated/skills/playbook-autopilot-full/SKILL.md +20 -0
  94. package/dist/kpi/kstack/generated/skills/playbook-autopilot-stack/SKILL.md +20 -0
  95. package/dist/kpi/kstack/generated/skills/playbook-bug-fix/SKILL.md +21 -0
  96. package/dist/kpi/kstack/generated/skills/playbook-feature/SKILL.md +22 -0
  97. package/dist/kpi/kstack/generated/skills/playbook-investigation/SKILL.md +21 -0
  98. package/dist/kpi/kstack/generated/skills/playbook-shipping/SKILL.md +18 -0
  99. package/dist/kpi/kstack/generated/skills/playbook-swarm/SKILL.md +20 -0
  100. package/dist/kpi/kstack/generated/skills/principle-boundary-discipline/SKILL.md +34 -0
  101. package/dist/kpi/kstack/generated/skills/principle-build-the-lever/SKILL.md +23 -0
  102. package/dist/kpi/kstack/generated/skills/principle-encode-lessons-in-structure/SKILL.md +31 -0
  103. package/dist/kpi/kstack/generated/skills/principle-exhaust-the-design-space/SKILL.md +21 -0
  104. package/dist/kpi/kstack/generated/skills/principle-experience-first/SKILL.md +19 -0
  105. package/dist/kpi/kstack/generated/skills/principle-fix-root-causes/SKILL.md +23 -0
  106. package/dist/kpi/kstack/generated/skills/principle-foundational-thinking/SKILL.md +21 -0
  107. package/dist/kpi/kstack/generated/skills/principle-guard-the-context-window/SKILL.md +17 -0
  108. package/dist/kpi/kstack/generated/skills/principle-laziness-protocol/SKILL.md +18 -0
  109. package/dist/kpi/kstack/generated/skills/principle-make-operations-idempotent/SKILL.md +24 -0
  110. package/dist/kpi/kstack/generated/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +22 -0
  111. package/dist/kpi/kstack/generated/skills/principle-minimize-reader-load/SKILL.md +23 -0
  112. package/dist/kpi/kstack/generated/skills/principle-model-the-domain/SKILL.md +26 -0
  113. package/dist/kpi/kstack/generated/skills/principle-never-block-on-the-human/SKILL.md +23 -0
  114. package/dist/kpi/kstack/generated/skills/principle-outcome-oriented-execution/SKILL.md +22 -0
  115. package/dist/kpi/kstack/generated/skills/principle-prove-it-works/SKILL.md +33 -0
  116. package/dist/kpi/kstack/generated/skills/principle-redesign-from-first-principles/SKILL.md +16 -0
  117. package/dist/kpi/kstack/generated/skills/principle-separate-before-serializing-shared-state/SKILL.md +16 -0
  118. package/dist/kpi/kstack/generated/skills/principle-sequence-verifiable-units/SKILL.md +22 -0
  119. package/dist/kpi/kstack/generated/skills/principle-subtract-before-you-add/SKILL.md +22 -0
  120. package/dist/kpi/kstack/generated/skills/principle-type-system-discipline/SKILL.md +31 -0
  121. package/dist/kpi/kstack/generated/skills/recall/SKILL.md +35 -0
  122. package/dist/kpi/kstack/generated/skills/reflect/SKILL.md +77 -0
  123. package/dist/kpi/kstack/generated/skills/reflect/references/divergent-reviewer.md +43 -0
  124. package/dist/kpi/kstack/generated/skills/reflect/references/judgment-reviewer.md +42 -0
  125. package/dist/kpi/kstack/generated/skills/reflect/references/synthesizer.md +56 -0
  126. package/dist/kpi/kstack/generated/skills/reflect/references/tooling-reviewer.md +57 -0
  127. package/dist/kpi/kstack/generated/skills/setup-kstack/SKILL.md +48 -0
  128. package/dist/kpi/kstack/generated/skills/show-me-your-work/SKILL.md +82 -0
  129. package/dist/kpi/kstack/generated/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  130. package/dist/kpi/kstack/generated/skills/show-me-your-work/scripts/log.sh +40 -0
  131. package/dist/kpi/kstack/generated/skills/swarm/SKILL.md +27 -0
  132. package/dist/kpi/kstack/generated/skills/tdd/SKILL.md +44 -0
  133. package/dist/kpi/kstack/generated/skills/teach/SKILL.md +21 -0
  134. package/dist/kpi/kstack/generated/skills/technical-writing/SKILL.md +130 -0
  135. package/dist/kpi/kstack/generated/skills/typescript-best-practices/SKILL.md +30 -0
  136. package/dist/kpi/kstack/generated/skills/typescript-best-practices/references/patterns.md +313 -0
  137. package/dist/kpi/kstack/generated/skills/unslop/SKILL.md +81 -0
  138. package/dist/kpi/kstack/generated/skills/why/SKILL.md +230 -0
  139. package/dist/kpi/kstack/generated/skills/why/references/epistemics.md +144 -0
  140. package/dist/kpi/kstack/generated/skills/why/references/investigator-prompt.md +103 -0
  141. package/dist/kpi/kstack/generated/skills/why/references/source-playbook.md +17 -0
  142. package/dist/kpi/kstack/generated/skills/why/references/sources/code-archaeology.md +88 -0
  143. package/dist/kpi/kstack/generated/skills/why/references/sources/databricks.md +70 -0
  144. package/dist/kpi/kstack/generated/skills/why/references/sources/datadog.md +99 -0
  145. package/dist/kpi/kstack/generated/skills/why/references/sources/incident-postmortem.md +15 -0
  146. package/dist/kpi/kstack/generated/skills/why/references/sources/linear.md +48 -0
  147. package/dist/kpi/kstack/generated/skills/why/references/sources/notion.md +55 -0
  148. package/dist/kpi/kstack/generated/skills/why/references/sources/sentry.md +100 -0
  149. package/dist/kpi/kstack/generated/skills/why/references/sources/slack.md +54 -0
  150. package/dist/kpi/kstack/generated/skills/why/references/synthesizer-prompt.md +135 -0
  151. package/dist/kpi/kstack/model-ladder.md +50 -0
  152. package/dist/kpi/kstack/provenance.json +17 -0
  153. package/dist/kpi/prompts/implement.md +6 -0
  154. package/dist/kpi/prompts/plan.md +6 -0
  155. package/dist/kpi/prompts/review.md +6 -0
  156. package/dist/kpi/prompts/ship.md +6 -0
  157. package/dist/kpi/prompts/specify.md +6 -0
  158. package/dist/kpi/prompts/verify.md +6 -0
  159. package/dist/kpi/schemas/event.schema.json +1314 -0
  160. package/dist/kpi/schemas/evidence.schema.json +43 -0
  161. package/dist/kpi/schemas/stack.schema.json +102 -0
  162. package/dist/kpi/schemas/task.schema.json +165 -0
  163. package/dist/kpi/schemas/verdict.schema.json +44 -0
  164. package/dist/kpi/skills/concise-output/SKILL.md +10 -0
  165. package/dist/kpi/skills/context-pack/SKILL.md +10 -0
  166. package/dist/kpi/skills/conventional-commit/SKILL.md +12 -0
  167. package/dist/kpi/skills/isolated-review/SKILL.md +10 -0
  168. package/dist/kpi/skills/kg-claim/SKILL.md +26 -0
  169. package/dist/kpi/skills/minimalist/SKILL.md +24 -0
  170. package/dist/kpi/skills/quality-gates/SKILL.md +10 -0
  171. package/dist/kpi/skills/spec-first/SKILL.md +10 -0
  172. package/dist/kpi/skills/tdd-cycle/SKILL.md +10 -0
  173. package/dist/kpi/templates/AGENTS.md +31 -0
  174. package/dist/kpi/templates/APPEND_SYSTEM.md +13 -0
  175. package/dist/kpi/templates/context-pack/product.md +7 -0
  176. package/dist/kpi/templates/context-pack/structure.md +7 -0
  177. package/dist/kpi/templates/context-pack/tech.md +9 -0
  178. package/dist/kpi/templates/policy.json +17 -0
  179. package/dist/kpi/themes/loop-amber.json +82 -0
  180. package/dist/kpi/themes/protocol-blue.json +82 -0
  181. package/dist/modes/interactive/assets/clankolas.png +0 -0
  182. package/dist/modes/interactive/theme/dark.json +90 -0
  183. package/dist/modes/interactive/theme/light.json +89 -0
  184. package/dist/modes/interactive/theme/theme-schema.json +352 -0
  185. package/docs/compaction.md +418 -0
  186. package/docs/containerization.md +111 -0
  187. package/docs/custom-provider.md +777 -0
  188. package/docs/development.md +71 -0
  189. package/docs/docs.json +156 -0
  190. package/docs/environment-variables.md +97 -0
  191. package/docs/extensions.md +3020 -0
  192. package/docs/images/doom-extension.png +0 -0
  193. package/docs/images/exy.png +0 -0
  194. package/docs/images/interactive-mode.png +0 -0
  195. package/docs/images/tree-view.png +0 -0
  196. package/docs/index.md +84 -0
  197. package/docs/json.md +98 -0
  198. package/docs/keybindings.md +236 -0
  199. package/docs/llama-cpp.md +101 -0
  200. package/docs/models.md +571 -0
  201. package/docs/packages.md +228 -0
  202. package/docs/prompt-templates.md +96 -0
  203. package/docs/providers.md +317 -0
  204. package/docs/quickstart.md +167 -0
  205. package/docs/rpc.md +1618 -0
  206. package/docs/sdk.md +1219 -0
  207. package/docs/security.md +59 -0
  208. package/docs/session-format.md +438 -0
  209. package/docs/sessions.md +145 -0
  210. package/docs/settings.md +369 -0
  211. package/docs/shell-aliases.md +13 -0
  212. package/docs/skills.md +232 -0
  213. package/docs/terminal-setup.md +177 -0
  214. package/docs/termux.md +127 -0
  215. package/docs/themes.md +320 -0
  216. package/docs/tmux.md +63 -0
  217. package/docs/tui.md +942 -0
  218. package/docs/usage.md +311 -0
  219. package/docs/windows.md +39 -0
  220. package/examples/README.md +25 -0
  221. package/examples/extensions/README.md +213 -0
  222. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  223. package/examples/extensions/bash-spawn-hook.ts +30 -0
  224. package/examples/extensions/bookmark.ts +50 -0
  225. package/examples/extensions/border-status-editor.ts +150 -0
  226. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  227. package/examples/extensions/claude-rules.ts +86 -0
  228. package/examples/extensions/commands.ts +72 -0
  229. package/examples/extensions/confirm-destructive.ts +59 -0
  230. package/examples/extensions/custom-compaction.ts +117 -0
  231. package/examples/extensions/custom-footer.ts +64 -0
  232. package/examples/extensions/custom-header.ts +73 -0
  233. package/examples/extensions/custom-provider-anthropic/index.ts +611 -0
  234. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  235. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  236. package/examples/extensions/custom-provider-gitlab-duo/index.ts +405 -0
  237. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  238. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  239. package/examples/extensions/dirty-repo-guard.ts +56 -0
  240. package/examples/extensions/doom-overlay/README.md +46 -0
  241. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  242. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  243. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  244. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  245. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  246. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  247. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  248. package/examples/extensions/doom-overlay/index.ts +74 -0
  249. package/examples/extensions/doom-overlay/wad-finder.ts +55 -0
  250. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  251. package/examples/extensions/dynamic-resources/dynamic.json +79 -0
  252. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  253. package/examples/extensions/dynamic-resources/index.ts +15 -0
  254. package/examples/extensions/dynamic-tools.ts +74 -0
  255. package/examples/extensions/entry-renderer.ts +41 -0
  256. package/examples/extensions/event-bus.ts +43 -0
  257. package/examples/extensions/file-trigger.ts +41 -0
  258. package/examples/extensions/git-checkpoint.ts +53 -0
  259. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  260. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  261. package/examples/extensions/gondolin/index.ts +531 -0
  262. package/examples/extensions/gondolin/package-lock.json +185 -0
  263. package/examples/extensions/gondolin/package.json +19 -0
  264. package/examples/extensions/handoff.ts +190 -0
  265. package/examples/extensions/hello.ts +26 -0
  266. package/examples/extensions/hidden-thinking-label.ts +53 -0
  267. package/examples/extensions/inline-bash.ts +94 -0
  268. package/examples/extensions/input-transform-streaming.ts +39 -0
  269. package/examples/extensions/input-transform.ts +43 -0
  270. package/examples/extensions/interactive-shell.ts +196 -0
  271. package/examples/extensions/kimi-deferred-tools.ts +61 -0
  272. package/examples/extensions/mac-system-theme.ts +47 -0
  273. package/examples/extensions/message-renderer.ts +59 -0
  274. package/examples/extensions/minimal-mode.ts +426 -0
  275. package/examples/extensions/modal-editor.ts +85 -0
  276. package/examples/extensions/model-status.ts +31 -0
  277. package/examples/extensions/notify.ts +57 -0
  278. package/examples/extensions/overlay-qa-tests.ts +1450 -0
  279. package/examples/extensions/overlay-test.ts +153 -0
  280. package/examples/extensions/permission-gate.ts +34 -0
  281. package/examples/extensions/pirate.ts +47 -0
  282. package/examples/extensions/plan-mode/README.md +66 -0
  283. package/examples/extensions/plan-mode/index.ts +390 -0
  284. package/examples/extensions/plan-mode/utils.ts +168 -0
  285. package/examples/extensions/preset.ts +436 -0
  286. package/examples/extensions/project-trust.ts +64 -0
  287. package/examples/extensions/prompt-customizer.ts +97 -0
  288. package/examples/extensions/protected-paths.ts +30 -0
  289. package/examples/extensions/provider-payload.ts +18 -0
  290. package/examples/extensions/qna.ts +118 -0
  291. package/examples/extensions/question.ts +286 -0
  292. package/examples/extensions/questionnaire.ts +448 -0
  293. package/examples/extensions/rainbow-editor.ts +88 -0
  294. package/examples/extensions/reload-runtime.ts +37 -0
  295. package/examples/extensions/rpc-demo.ts +118 -0
  296. package/examples/extensions/sandbox/index.ts +321 -0
  297. package/examples/extensions/sandbox/package-lock.json +92 -0
  298. package/examples/extensions/sandbox/package.json +19 -0
  299. package/examples/extensions/send-user-message.ts +97 -0
  300. package/examples/extensions/session-name.ts +27 -0
  301. package/examples/extensions/shutdown-command.ts +63 -0
  302. package/examples/extensions/snake.ts +343 -0
  303. package/examples/extensions/space-invaders.ts +560 -0
  304. package/examples/extensions/ssh.ts +220 -0
  305. package/examples/extensions/status-line.ts +32 -0
  306. package/examples/extensions/structured-output.ts +65 -0
  307. package/examples/extensions/subagent/README.md +177 -0
  308. package/examples/extensions/subagent/agents/planner.md +37 -0
  309. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  310. package/examples/extensions/subagent/agents/scout.md +50 -0
  311. package/examples/extensions/subagent/agents/worker.md +24 -0
  312. package/examples/extensions/subagent/agents.ts +157 -0
  313. package/examples/extensions/subagent/index.ts +1038 -0
  314. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  315. package/examples/extensions/subagent/prompts/implement.md +10 -0
  316. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  317. package/examples/extensions/summarize.ts +199 -0
  318. package/examples/extensions/system-prompt-header.ts +17 -0
  319. package/examples/extensions/tic-tac-toe.ts +1008 -0
  320. package/examples/extensions/timed-confirm.ts +70 -0
  321. package/examples/extensions/titlebar-spinner.ts +58 -0
  322. package/examples/extensions/todo.ts +297 -0
  323. package/examples/extensions/tool-override.ts +144 -0
  324. package/examples/extensions/tools.ts +146 -0
  325. package/examples/extensions/trigger-compact.ts +50 -0
  326. package/examples/extensions/truncated-tool.ts +195 -0
  327. package/examples/extensions/widget-placement.ts +9 -0
  328. package/examples/extensions/with-deps/index.ts +32 -0
  329. package/examples/extensions/with-deps/package-lock.json +31 -0
  330. package/examples/extensions/with-deps/package.json +22 -0
  331. package/examples/extensions/working-indicator.ts +123 -0
  332. package/examples/extensions/working-message-test.ts +25 -0
  333. package/examples/rpc-extension-ui.ts +641 -0
  334. package/examples/sdk/01-minimal.ts +26 -0
  335. package/examples/sdk/02-custom-model.ts +49 -0
  336. package/examples/sdk/03-custom-prompt.ts +75 -0
  337. package/examples/sdk/04-skills.ts +55 -0
  338. package/examples/sdk/05-tools.ts +48 -0
  339. package/examples/sdk/06-extensions.ts +99 -0
  340. package/examples/sdk/07-context-files.ts +47 -0
  341. package/examples/sdk/08-prompt-templates.ts +51 -0
  342. package/examples/sdk/09-api-keys-and-oauth.ts +34 -0
  343. package/examples/sdk/10-settings.ts +53 -0
  344. package/examples/sdk/11-sessions.ts +52 -0
  345. package/examples/sdk/12-full-control.ts +74 -0
  346. package/examples/sdk/13-session-runtime.ts +67 -0
  347. package/examples/sdk/README.md +140 -0
  348. package/package.json +55 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * RPC Extension UI Example (TUI)
3
+ *
4
+ * A lightweight TUI chat client that spawns the agent in RPC mode.
5
+ * Demonstrates how to build a custom UI on top of the RPC protocol,
6
+ * including handling extension UI requests (select, confirm, input, editor).
7
+ *
8
+ * Usage: npx tsx examples/rpc-extension-ui.ts
9
+ *
10
+ * Slash commands:
11
+ * /select - demo select dialog
12
+ * /confirm - demo confirm dialog
13
+ * /input - demo input dialog
14
+ * /editor - demo editor dialog
15
+ */
16
+
17
+ import { spawn } from "node:child_process";
18
+ import { dirname, join } from "node:path";
19
+ import * as readline from "node:readline";
20
+ import { fileURLToPath } from "node:url";
21
+ import {
22
+ type Component,
23
+ Container,
24
+ Input,
25
+ matchesKey,
26
+ ProcessTerminal,
27
+ SelectList,
28
+ type TUI,
29
+ TuiMainScreen,
30
+ } from "@earendil-works/pi-tui";
31
+
32
+ const __dirname = dirname(fileURLToPath(import.meta.url));
33
+
34
+ // ============================================================================
35
+ // ANSI helpers
36
+ // ============================================================================
37
+
38
+ const GREEN = "\x1b[32m";
39
+ const YELLOW = "\x1b[33m";
40
+ const BLUE = "\x1b[34m";
41
+ const MAGENTA = "\x1b[35m";
42
+ const RED = "\x1b[31m";
43
+ const DIM = "\x1b[2m";
44
+ const BOLD = "\x1b[1m";
45
+ const RESET = "\x1b[0m";
46
+
47
+ // ============================================================================
48
+ // Extension UI request type (subset of rpc-types.ts)
49
+ // ============================================================================
50
+
51
+ interface ExtensionUIRequest {
52
+ type: "extension_ui_request";
53
+ id: string;
54
+ method: string;
55
+ title?: string;
56
+ options?: string[];
57
+ message?: string;
58
+ placeholder?: string;
59
+ prefill?: string;
60
+ notifyType?: "info" | "warning" | "error";
61
+ statusKey?: string;
62
+ statusText?: string;
63
+ widgetKey?: string;
64
+ widgetLines?: string[];
65
+ text?: string;
66
+ }
67
+
68
+ // ============================================================================
69
+ // Output log: accumulates styled lines, renders the tail that fits
70
+ // ============================================================================
71
+
72
+ class OutputLog implements Component {
73
+ private lines: string[] = [];
74
+ private maxLines = 1000;
75
+ private visibleLines = 0;
76
+
77
+ setVisibleLines(n: number): void {
78
+ this.visibleLines = n;
79
+ }
80
+
81
+ append(line: string): void {
82
+ this.lines.push(line);
83
+ if (this.lines.length > this.maxLines) {
84
+ this.lines = this.lines.slice(-this.maxLines);
85
+ }
86
+ }
87
+
88
+ appendRaw(text: string): void {
89
+ if (this.lines.length === 0) {
90
+ this.lines.push(text);
91
+ } else {
92
+ this.lines[this.lines.length - 1] += text;
93
+ }
94
+ }
95
+
96
+ invalidate(): void {}
97
+
98
+ render(width: number): string[] {
99
+ if (this.lines.length === 0) return [""];
100
+ const n = this.visibleLines > 0 ? this.visibleLines : this.lines.length;
101
+ return this.lines.slice(-n).map((l) => l.slice(0, width));
102
+ }
103
+ }
104
+
105
+ // ============================================================================
106
+ // Loading indicator: "Agent: Working." -> ".." -> "..." -> "."
107
+ // ============================================================================
108
+
109
+ class LoadingIndicator implements Component {
110
+ private dots = 1;
111
+ private intervalId: NodeJS.Timeout | null = null;
112
+ private tui: TUI | null = null;
113
+
114
+ start(tui: TUI): void {
115
+ this.tui = tui;
116
+ this.dots = 1;
117
+ this.intervalId = setInterval(() => {
118
+ this.dots = (this.dots % 3) + 1;
119
+ this.tui?.requestRender();
120
+ }, 400);
121
+ }
122
+
123
+ stop(): void {
124
+ if (this.intervalId) {
125
+ clearInterval(this.intervalId);
126
+ this.intervalId = null;
127
+ }
128
+ }
129
+
130
+ invalidate(): void {}
131
+
132
+ render(_width: number): string[] {
133
+ return [`${BLUE}${BOLD}Agent:${RESET} ${DIM}Working${".".repeat(this.dots)}${RESET}`];
134
+ }
135
+ }
136
+
137
+ // ============================================================================
138
+ // Prompt input: label + single-line input
139
+ // ============================================================================
140
+
141
+ class PromptInput implements Component {
142
+ readonly input: Input;
143
+ onCtrlD?: () => void;
144
+
145
+ constructor() {
146
+ this.input = new Input();
147
+ }
148
+
149
+ handleInput(data: string): void {
150
+ if (matchesKey(data, "ctrl+d")) {
151
+ this.onCtrlD?.();
152
+ return;
153
+ }
154
+ this.input.handleInput(data);
155
+ }
156
+
157
+ invalidate(): void {
158
+ this.input.invalidate();
159
+ }
160
+
161
+ render(width: number): string[] {
162
+ return [`${GREEN}${BOLD}You:${RESET}`, ...this.input.render(width)];
163
+ }
164
+ }
165
+
166
+ // ============================================================================
167
+ // Dialog components: replace the prompt input during interactive requests
168
+ // ============================================================================
169
+
170
+ class SelectDialog implements Component {
171
+ private list: SelectList;
172
+ private title: string;
173
+ onSelect?: (value: string) => void;
174
+ onCancel?: () => void;
175
+
176
+ constructor(title: string, options: string[]) {
177
+ this.title = title;
178
+ const items = options.map((o) => ({ value: o, label: o }));
179
+ this.list = new SelectList(items, Math.min(items.length, 8), {
180
+ selectedPrefix: (t) => `${MAGENTA}${t}${RESET}`,
181
+ selectedText: (t) => `${MAGENTA}${t}${RESET}`,
182
+ description: (t) => `${DIM}${t}${RESET}`,
183
+ scrollInfo: (t) => `${DIM}${t}${RESET}`,
184
+ noMatch: (t) => `${YELLOW}${t}${RESET}`,
185
+ });
186
+ this.list.onSelect = (item) => this.onSelect?.(item.value);
187
+ this.list.onCancel = () => this.onCancel?.();
188
+ }
189
+
190
+ handleInput(data: string): void {
191
+ this.list.handleInput(data);
192
+ }
193
+
194
+ invalidate(): void {
195
+ this.list.invalidate();
196
+ }
197
+
198
+ render(width: number): string[] {
199
+ return [
200
+ `${MAGENTA}${BOLD}${this.title}${RESET}`,
201
+ ...this.list.render(width),
202
+ `${DIM}Up/Down, Enter to select, Esc to cancel${RESET}`,
203
+ ];
204
+ }
205
+ }
206
+
207
+ class InputDialog implements Component {
208
+ private dialogInput: Input;
209
+ private title: string;
210
+ onCtrlD?: () => void;
211
+
212
+ constructor(title: string, prefill?: string) {
213
+ this.title = title;
214
+ this.dialogInput = new Input();
215
+ if (prefill) this.dialogInput.setValue(prefill);
216
+ }
217
+
218
+ set onSubmit(fn: ((value: string) => void) | undefined) {
219
+ this.dialogInput.onSubmit = fn;
220
+ }
221
+
222
+ set onEscape(fn: (() => void) | undefined) {
223
+ this.dialogInput.onEscape = fn;
224
+ }
225
+
226
+ get inputComponent(): Input {
227
+ return this.dialogInput;
228
+ }
229
+
230
+ handleInput(data: string): void {
231
+ if (matchesKey(data, "ctrl+d")) {
232
+ this.onCtrlD?.();
233
+ return;
234
+ }
235
+ this.dialogInput.handleInput(data);
236
+ }
237
+
238
+ invalidate(): void {
239
+ this.dialogInput.invalidate();
240
+ }
241
+
242
+ render(width: number): string[] {
243
+ return [
244
+ `${MAGENTA}${BOLD}${this.title}${RESET}`,
245
+ ...this.dialogInput.render(width),
246
+ `${DIM}Enter to submit, Esc to cancel${RESET}`,
247
+ ];
248
+ }
249
+ }
250
+
251
+ // ============================================================================
252
+ // Main
253
+ // ============================================================================
254
+
255
+ async function main() {
256
+ const extensionPath = join(__dirname, "extensions/rpc-demo.ts");
257
+ const cliPath = join(__dirname, "../dist/cli.js");
258
+
259
+ const agent = spawn(
260
+ "node",
261
+ [cliPath, "--mode", "rpc", "--no-session", "--no-extension", "--extension", extensionPath],
262
+ { stdio: ["pipe", "pipe", "pipe"] },
263
+ );
264
+
265
+ let stderr = "";
266
+ agent.stderr?.on("data", (data: Buffer) => {
267
+ stderr += data.toString();
268
+ });
269
+
270
+ await new Promise((resolve) => setTimeout(resolve, 500));
271
+ if (agent.exitCode !== null) {
272
+ console.error(`Agent exited immediately. Stderr:\n${stderr}`);
273
+ process.exit(1);
274
+ }
275
+
276
+ // -- TUI setup --
277
+
278
+ const terminal = new ProcessTerminal();
279
+ const tui: TUI = new TuiMainScreen(terminal);
280
+
281
+ const outputLog = new OutputLog();
282
+ const loadingIndicator = new LoadingIndicator();
283
+ const promptInput = new PromptInput();
284
+
285
+ const root = new Container();
286
+ root.addChild(outputLog);
287
+ root.addChild(promptInput);
288
+
289
+ tui.addChild(root);
290
+ tui.setFocus(promptInput.input);
291
+
292
+ // -- Agent communication --
293
+
294
+ function send(obj: Record<string, unknown>): void {
295
+ agent.stdin!.write(`${JSON.stringify(obj)}\n`);
296
+ }
297
+
298
+ let isStreaming = false;
299
+ let hasTextOutput = false;
300
+
301
+ function exit(): void {
302
+ tui.stop();
303
+ agent.kill("SIGTERM");
304
+ process.exit(0);
305
+ }
306
+
307
+ // -- Bottom area management --
308
+ // The bottom of the screen is either the prompt input or a dialog.
309
+ // These helpers swap between them.
310
+
311
+ let activeDialog: Component | null = null;
312
+
313
+ function setBottomComponent(component: Component): void {
314
+ root.clear();
315
+ root.addChild(outputLog);
316
+ if (isStreaming) root.addChild(loadingIndicator);
317
+ root.addChild(component);
318
+ tui.setFocus(component);
319
+ tui.requestRender();
320
+ }
321
+
322
+ function showPrompt(): void {
323
+ activeDialog = null;
324
+ setBottomComponent(promptInput);
325
+ tui.setFocus(promptInput.input);
326
+ }
327
+
328
+ function showDialog(dialog: Component): void {
329
+ activeDialog = dialog;
330
+ setBottomComponent(dialog);
331
+ }
332
+
333
+ function showLoading(): void {
334
+ if (!isStreaming) {
335
+ isStreaming = true;
336
+ hasTextOutput = false;
337
+ root.clear();
338
+ root.addChild(outputLog);
339
+ root.addChild(loadingIndicator);
340
+ root.addChild(activeDialog ?? promptInput);
341
+ if (!activeDialog) tui.setFocus(promptInput.input);
342
+ loadingIndicator.start(tui);
343
+ tui.requestRender();
344
+ }
345
+ }
346
+
347
+ function hideLoading(): void {
348
+ loadingIndicator.stop();
349
+ root.clear();
350
+ root.addChild(outputLog);
351
+ root.addChild(activeDialog ?? promptInput);
352
+ if (!activeDialog) tui.setFocus(promptInput.input);
353
+ tui.requestRender();
354
+ }
355
+
356
+ // -- Extension UI dialog handling --
357
+
358
+ function showSelectDialog(title: string, options: string[], onDone: (value: string | undefined) => void): void {
359
+ const dialog = new SelectDialog(title, options);
360
+ dialog.onSelect = (value) => {
361
+ showPrompt();
362
+ onDone(value);
363
+ };
364
+ dialog.onCancel = () => {
365
+ showPrompt();
366
+ onDone(undefined);
367
+ };
368
+ showDialog(dialog);
369
+ }
370
+
371
+ function showInputDialog(title: string, prefill?: string, onDone?: (value: string | undefined) => void): void {
372
+ const dialog = new InputDialog(title, prefill);
373
+ dialog.onSubmit = (value) => {
374
+ showPrompt();
375
+ onDone?.(value.trim() || undefined);
376
+ };
377
+ dialog.onEscape = () => {
378
+ showPrompt();
379
+ onDone?.(undefined);
380
+ };
381
+ dialog.onCtrlD = exit;
382
+ showDialog(dialog);
383
+ tui.setFocus(dialog.inputComponent);
384
+ }
385
+
386
+ function handleExtensionUI(req: ExtensionUIRequest): void {
387
+ const { id, method } = req;
388
+
389
+ switch (method) {
390
+ // Dialog methods: replace prompt with interactive component
391
+ case "select": {
392
+ showSelectDialog(req.title ?? "Select", req.options ?? [], (value) => {
393
+ if (value !== undefined) {
394
+ send({ type: "extension_ui_response", id, value });
395
+ } else {
396
+ send({ type: "extension_ui_response", id, cancelled: true });
397
+ }
398
+ });
399
+ break;
400
+ }
401
+
402
+ case "confirm": {
403
+ const title = req.message ? `${req.title}: ${req.message}` : (req.title ?? "Confirm");
404
+ showSelectDialog(title, ["Yes", "No"], (value) => {
405
+ send({ type: "extension_ui_response", id, confirmed: value === "Yes" });
406
+ });
407
+ break;
408
+ }
409
+
410
+ case "input": {
411
+ const title = req.placeholder ? `${req.title} (${req.placeholder})` : (req.title ?? "Input");
412
+ showInputDialog(title, undefined, (value) => {
413
+ if (value !== undefined) {
414
+ send({ type: "extension_ui_response", id, value });
415
+ } else {
416
+ send({ type: "extension_ui_response", id, cancelled: true });
417
+ }
418
+ });
419
+ break;
420
+ }
421
+
422
+ case "editor": {
423
+ const prefill = req.prefill?.replace(/\n/g, " ");
424
+ showInputDialog(req.title ?? "Editor", prefill, (value) => {
425
+ if (value !== undefined) {
426
+ send({ type: "extension_ui_response", id, value });
427
+ } else {
428
+ send({ type: "extension_ui_response", id, cancelled: true });
429
+ }
430
+ });
431
+ break;
432
+ }
433
+
434
+ // Fire-and-forget methods: display as notification
435
+ case "notify": {
436
+ const notifyType = (req.notifyType as string) ?? "info";
437
+ const color = notifyType === "error" ? RED : notifyType === "warning" ? YELLOW : MAGENTA;
438
+ outputLog.append(`${color}${BOLD}Notification:${RESET} ${req.message}`);
439
+ tui.requestRender();
440
+ break;
441
+ }
442
+
443
+ case "setStatus":
444
+ outputLog.append(
445
+ `${MAGENTA}${BOLD}Notification:${RESET} ${DIM}[status: ${req.statusKey}]${RESET} ${req.statusText ?? "(cleared)"}`,
446
+ );
447
+ tui.requestRender();
448
+ break;
449
+
450
+ case "setWidget": {
451
+ const lines = req.widgetLines;
452
+ if (lines && lines.length > 0) {
453
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} ${DIM}[widget: ${req.widgetKey}]${RESET}`);
454
+ for (const wl of lines) {
455
+ outputLog.append(` ${DIM}${wl}${RESET}`);
456
+ }
457
+ tui.requestRender();
458
+ }
459
+ break;
460
+ }
461
+
462
+ case "set_editor_text":
463
+ promptInput.input.setValue((req.text as string) ?? "");
464
+ tui.requestRender();
465
+ break;
466
+ }
467
+ }
468
+
469
+ // -- Slash commands (local, not sent to agent) --
470
+
471
+ function handleSlashCommand(cmd: string): boolean {
472
+ switch (cmd) {
473
+ case "/select":
474
+ showSelectDialog("Pick a color", ["Red", "Green", "Blue", "Yellow"], (value) => {
475
+ if (value) {
476
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} You picked: ${value}`);
477
+ } else {
478
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} Selection cancelled`);
479
+ }
480
+ tui.requestRender();
481
+ });
482
+ return true;
483
+
484
+ case "/confirm":
485
+ showSelectDialog("Are you sure?", ["Yes", "No"], (value) => {
486
+ const confirmed = value === "Yes";
487
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} Confirmed: ${confirmed}`);
488
+ tui.requestRender();
489
+ });
490
+ return true;
491
+
492
+ case "/input":
493
+ showInputDialog("Enter your name", undefined, (value) => {
494
+ if (value) {
495
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} You entered: ${value}`);
496
+ } else {
497
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} Input cancelled`);
498
+ }
499
+ tui.requestRender();
500
+ });
501
+ return true;
502
+
503
+ case "/editor":
504
+ showInputDialog("Edit text", "Hello, world!", (value) => {
505
+ if (value) {
506
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} Submitted: ${value}`);
507
+ } else {
508
+ outputLog.append(`${MAGENTA}${BOLD}Notification:${RESET} Editor cancelled`);
509
+ }
510
+ tui.requestRender();
511
+ });
512
+ return true;
513
+
514
+ default:
515
+ return false;
516
+ }
517
+ }
518
+
519
+ // -- Process agent stdout --
520
+
521
+ const stdoutRl = readline.createInterface({ input: agent.stdout!, terminal: false });
522
+
523
+ stdoutRl.on("line", (line) => {
524
+ let data: Record<string, unknown>;
525
+ try {
526
+ data = JSON.parse(line);
527
+ } catch {
528
+ return;
529
+ }
530
+
531
+ if (data.type === "response" && !data.success) {
532
+ outputLog.append(`${RED}[error]${RESET} ${data.command}: ${data.error}`);
533
+ tui.requestRender();
534
+ return;
535
+ }
536
+
537
+ if (data.type === "agent_start") {
538
+ showLoading();
539
+ return;
540
+ }
541
+
542
+ if (data.type === "extension_ui_request") {
543
+ handleExtensionUI(data as unknown as ExtensionUIRequest);
544
+ return;
545
+ }
546
+
547
+ if (data.type === "message_update") {
548
+ const evt = data.assistantMessageEvent as Record<string, unknown> | undefined;
549
+ if (evt?.type === "text_delta") {
550
+ if (!hasTextOutput) {
551
+ hasTextOutput = true;
552
+ outputLog.append("");
553
+ outputLog.append(`${BLUE}${BOLD}Agent:${RESET}`);
554
+ }
555
+ const delta = evt.delta as string;
556
+ const parts = delta.split("\n");
557
+ for (let i = 0; i < parts.length; i++) {
558
+ if (i > 0) outputLog.append("");
559
+ if (parts[i]) outputLog.appendRaw(parts[i]);
560
+ }
561
+ tui.requestRender();
562
+ }
563
+ return;
564
+ }
565
+
566
+ if (data.type === "tool_execution_start") {
567
+ outputLog.append(`${DIM}[tool: ${data.toolName}]${RESET}`);
568
+ tui.requestRender();
569
+ return;
570
+ }
571
+
572
+ if (data.type === "tool_execution_end") {
573
+ const result = JSON.stringify(data.result).slice(0, 120);
574
+ outputLog.append(`${DIM}[result: ${result}...]${RESET}`);
575
+ tui.requestRender();
576
+ return;
577
+ }
578
+
579
+ if (data.type === "agent_settled") {
580
+ isStreaming = false;
581
+ hideLoading();
582
+ outputLog.append("");
583
+ tui.requestRender();
584
+ return;
585
+ }
586
+ });
587
+
588
+ // -- User input --
589
+
590
+ promptInput.input.onSubmit = (value) => {
591
+ const trimmed = value.trim();
592
+ if (!trimmed) return;
593
+
594
+ promptInput.input.setValue("");
595
+
596
+ if (handleSlashCommand(trimmed)) {
597
+ outputLog.append(`${GREEN}${BOLD}You:${RESET} ${trimmed}`);
598
+ tui.requestRender();
599
+ return;
600
+ }
601
+
602
+ outputLog.append(`${GREEN}${BOLD}You:${RESET} ${trimmed}`);
603
+ send({ type: "prompt", message: trimmed });
604
+ tui.requestRender();
605
+ };
606
+
607
+ promptInput.onCtrlD = exit;
608
+
609
+ promptInput.input.onEscape = () => {
610
+ if (isStreaming) {
611
+ send({ type: "abort" });
612
+ outputLog.append(`${YELLOW}[aborted]${RESET}`);
613
+ tui.requestRender();
614
+ } else {
615
+ exit();
616
+ }
617
+ };
618
+
619
+ // -- Agent exit --
620
+
621
+ agent.on("exit", (code) => {
622
+ tui.stop();
623
+ if (stderr) console.error(stderr);
624
+ console.log(`Agent exited with code ${code}`);
625
+ process.exit(code ?? 0);
626
+ });
627
+
628
+ // -- Start --
629
+
630
+ outputLog.append(`${BOLD}RPC Chat${RESET}`);
631
+ outputLog.append(`${DIM}Type a message and press Enter. Esc to abort or exit. Ctrl+D to quit.${RESET}`);
632
+ outputLog.append(`${DIM}Slash commands: /select /confirm /input /editor${RESET}`);
633
+ outputLog.append("");
634
+
635
+ tui.start();
636
+ }
637
+
638
+ main().catch((err) => {
639
+ console.error(err);
640
+ process.exit(1);
641
+ });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Minimal SDK Usage
3
+ *
4
+ * Uses all defaults: discovers skills, extensions, tools, context files
5
+ * from cwd and ~/.pi/agent. Model chosen from settings or first available.
6
+ */
7
+
8
+ import { createAgentSession } from "@earendil-works/pi-coding-agent";
9
+
10
+ const { session } = await createAgentSession();
11
+
12
+ try {
13
+ session.subscribe((event) => {
14
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
15
+ process.stdout.write(event.assistantMessageEvent.delta);
16
+ }
17
+ });
18
+
19
+ await session.prompt("What files are in the current directory?");
20
+ session.state.messages.forEach((msg) => {
21
+ console.log(msg);
22
+ });
23
+ console.log();
24
+ } finally {
25
+ session.dispose();
26
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Custom Model Selection
3
+ *
4
+ * Shows how to select a specific model and thinking level.
5
+ */
6
+
7
+ import { createAgentSession, ModelRuntime } from "@earendil-works/pi-coding-agent";
8
+
9
+ const modelRuntime = await ModelRuntime.create();
10
+
11
+ // Option 1: Find a specific built-in model by provider/id
12
+ const opus = modelRuntime.getModel("anthropic", "claude-opus-4-5");
13
+ if (opus) {
14
+ console.log(`Found model: ${opus.provider}/${opus.id}`);
15
+ }
16
+
17
+ // Option 2: Find model via registry (includes custom models from models.json)
18
+ const customModel = modelRuntime.getModel("my-provider", "my-model");
19
+ if (customModel) {
20
+ console.log(`Found custom model: ${customModel.provider}/${customModel.id}`);
21
+ }
22
+
23
+ // Option 3: Pick from available models (have valid API keys)
24
+ const available = await modelRuntime.getAvailable();
25
+ console.log(
26
+ "Available models:",
27
+ available.map((m) => `${m.provider}/${m.id}`),
28
+ );
29
+
30
+ if (available.length > 0) {
31
+ const { session } = await createAgentSession({
32
+ model: available[0],
33
+ thinkingLevel: "medium", // off, low, medium, high
34
+ modelRuntime,
35
+ });
36
+
37
+ try {
38
+ session.subscribe((event) => {
39
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
40
+ process.stdout.write(event.assistantMessageEvent.delta);
41
+ }
42
+ });
43
+
44
+ await session.prompt("Say hello in one sentence.");
45
+ console.log();
46
+ } finally {
47
+ session.dispose();
48
+ }
49
+ }