openpond 0.0.30-bootstrap.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 (193) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/LICENSE +21 -0
  3. package/README.md +162 -0
  4. package/RELEASE.md +20 -0
  5. package/dist/api/core.d.ts +22 -0
  6. package/dist/api/deployments.d.ts +30 -0
  7. package/dist/api/types.d.ts +624 -0
  8. package/dist/api.d.ts +90 -0
  9. package/dist/cache.d.ts +22 -0
  10. package/dist/chunks/app-layer-YKXEQGOW.js +163 -0
  11. package/dist/chunks/apps-GGSIN2ZF.js +539 -0
  12. package/dist/chunks/chunk-3CC6MH35.js +1663 -0
  13. package/dist/chunks/chunk-3Y4EL3P6.js +1090 -0
  14. package/dist/chunks/chunk-4HYJG2JE.js +3875 -0
  15. package/dist/chunks/chunk-5G4E547X.js +294 -0
  16. package/dist/chunks/chunk-74O6FGVN.js +598 -0
  17. package/dist/chunks/chunk-AUJLPKGI.js +632 -0
  18. package/dist/chunks/chunk-BYAPLT37.js +744 -0
  19. package/dist/chunks/chunk-FUP7EGT7.js +1845 -0
  20. package/dist/chunks/chunk-I6HN3ZGW.js +88 -0
  21. package/dist/chunks/chunk-KRKGHVMQ.js +294 -0
  22. package/dist/chunks/chunk-LHYK6QO2.js +1300 -0
  23. package/dist/chunks/chunk-NLBKZZEK.js +224 -0
  24. package/dist/chunks/chunk-OG75GMVO.js +1 -0
  25. package/dist/chunks/chunk-Q57SVPEH.js +11663 -0
  26. package/dist/chunks/chunk-UACZUFIA.js +47 -0
  27. package/dist/chunks/chunk-VQX33YAG.js +5135 -0
  28. package/dist/chunks/chunk-W5GKHH77.js +168 -0
  29. package/dist/chunks/chunk-WYDVQOBL.js +17581 -0
  30. package/dist/chunks/chunk-XSAXENQD.js +4167 -0
  31. package/dist/chunks/chunk-Y6G6WRTG.js +210 -0
  32. package/dist/chunks/cli-NVKNE4AZ.js +11 -0
  33. package/dist/chunks/cli-X3HPLSOV.js +19 -0
  34. package/dist/chunks/core-commands-IM2UKLU4.js +41 -0
  35. package/dist/chunks/extend-YXCBULPO.js +84 -0
  36. package/dist/chunks/harness-GMK6IY2U.js +140 -0
  37. package/dist/chunks/help-LMH5FGT2.js +65 -0
  38. package/dist/chunks/opchat-BWXZ32GX.js +169 -0
  39. package/dist/chunks/organizations-4ISQRGMQ.js +738 -0
  40. package/dist/chunks/profile-NLDZDT3L.js +1110 -0
  41. package/dist/chunks/project-agent-ZPVO25HA.js +892 -0
  42. package/dist/chunks/sandbox-command-5GFJ2U3V.js +1652 -0
  43. package/dist/chunks/sandbox-template-LZN4F55Z.js +1646 -0
  44. package/dist/chunks/src-3RBI4DNN.js +3595 -0
  45. package/dist/chunks/src-EYXQS6XD.js +73427 -0
  46. package/dist/chunks/teams-bot-WP3FHKGA.js +137 -0
  47. package/dist/cli.js +77 -0
  48. package/dist/client-types.d.ts +222 -0
  49. package/dist/client.d.ts +19 -0
  50. package/dist/config.d.ts +184 -0
  51. package/dist/hosted-chat.d.ts +162 -0
  52. package/dist/index.d.ts +5 -0
  53. package/dist/index.js +25481 -0
  54. package/dist/indicators.d.ts +38 -0
  55. package/dist/opchat-smoke.d.ts +47 -0
  56. package/dist/private-json-file.d.ts +3 -0
  57. package/dist/profile/local-profile-types.d.ts +160 -0
  58. package/dist/profile/local-profile.d.ts +69 -0
  59. package/dist/profile/profile-catalog.d.ts +14 -0
  60. package/dist/profile/profile-git.d.ts +17 -0
  61. package/dist/profile/profile-promotion.d.ts +21 -0
  62. package/dist/profile/profile-setup-gate.d.ts +22 -0
  63. package/dist/profile/profile-skills.d.ts +30 -0
  64. package/dist/profile/profile-source-upload.d.ts +29 -0
  65. package/dist/profile/source-upload-cache.d.ts +29 -0
  66. package/dist/sandbox/async-request-options.d.ts +2 -0
  67. package/dist/sandbox/client-handles.d.ts +113 -0
  68. package/dist/sandbox/client.d.ts +348 -0
  69. package/dist/sandbox/runtime-handle.d.ts +36 -0
  70. package/dist/sandbox/sandbox-instance-client.d.ts +72 -0
  71. package/dist/sandbox/smoke.d.ts +3 -0
  72. package/dist/sandbox/stream.d.ts +7 -0
  73. package/dist/sandbox/types/billing.d.ts +176 -0
  74. package/dist/sandbox/types/client.d.ts +103 -0
  75. package/dist/sandbox/types/core.d.ts +140 -0
  76. package/dist/sandbox/types/index.d.ts +14 -0
  77. package/dist/sandbox/types/io.d.ts +240 -0
  78. package/dist/sandbox/types/microsoft-teams-bot.d.ts +51 -0
  79. package/dist/sandbox/types/org-project-agent.d.ts +610 -0
  80. package/dist/sandbox/types/record.d.ts +53 -0
  81. package/dist/sandbox/types/responses.d.ts +295 -0
  82. package/dist/sandbox/types/runtime-profiles.d.ts +15 -0
  83. package/dist/sandbox/types/runtime.d.ts +152 -0
  84. package/dist/sandbox/types/schedules.d.ts +141 -0
  85. package/dist/sandbox/types/snapshots.d.ts +205 -0
  86. package/dist/sandbox/types/workflow-modes.d.ts +1 -0
  87. package/dist/sandbox/types/workload-sources.d.ts +20 -0
  88. package/dist/sandbox/url.d.ts +2 -0
  89. package/dist/sandbox-template/manifest.d.ts +304 -0
  90. package/dist/sandbox-template/manifest.js +18381 -0
  91. package/dist/skills/openpond-cli/SKILL.md +49 -0
  92. package/dist/skills/openpond-desktop-harness/SKILL.md +113 -0
  93. package/dist/skills/openpond-desktop-harness/agents/openai.yaml +4 -0
  94. package/dist/skills/openpond-taskset-authoring/SKILL.md +38 -0
  95. package/dist/skills/openpond-taskset-authoring/references/graders-and-rewards.md +11 -0
  96. package/dist/skills/openpond-taskset-authoring/references/method-selection.md +12 -0
  97. package/dist/skills/openpond-taskset-authoring/references/privacy-and-provenance.md +8 -0
  98. package/dist/skills/openpond-taskset-authoring/references/task-design.md +13 -0
  99. package/dist/stream.d.ts +20 -0
  100. package/dist/types.d.ts +57 -0
  101. package/dist/urls.d.ts +4 -0
  102. package/dist/web/assets/AppsView-Bu-Nc3Ew.js +1 -0
  103. package/dist/web/assets/AppsView-DIhprTIC.css +1 -0
  104. package/dist/web/assets/BrowserSidebar-CCguQ-DR.js +1 -0
  105. package/dist/web/assets/BrowserSidebar-D9i7gQzw.css +1 -0
  106. package/dist/web/assets/CloudWorkView-DNoPIlMj.css +1 -0
  107. package/dist/web/assets/CloudWorkView-Dr3xqLE5.js +1 -0
  108. package/dist/web/assets/CommandMenu-CnodJFHD.js +1 -0
  109. package/dist/web/assets/CommandMenu-hNQCm8mw.css +1 -0
  110. package/dist/web/assets/CommunityView-CIbjNUZr.js +1 -0
  111. package/dist/web/assets/CommunityView-DSik4sd2.css +1 -0
  112. package/dist/web/assets/GetStartedView-C3ZrnEz5.css +1 -0
  113. package/dist/web/assets/GetStartedView-C8nyH_PT.js +1 -0
  114. package/dist/web/assets/LabsExtensions-GtJzxDnK.js +1 -0
  115. package/dist/web/assets/LabsProfile-DG7rWYur.js +1 -0
  116. package/dist/web/assets/LabsRoute-D6MDHBzq.js +2 -0
  117. package/dist/web/assets/LabsRoute-TEt9j1vB.css +1 -0
  118. package/dist/web/assets/LabsSignals-BfsDN86w.js +1 -0
  119. package/dist/web/assets/LabsSignals-D6iA6Ryl.css +1 -0
  120. package/dist/web/assets/NewProjectDialog-CaKiCoVS.js +1 -0
  121. package/dist/web/assets/ProfileSettingsSection-DTQS2DVL.css +1 -0
  122. package/dist/web/assets/ProfileSettingsSection-DxEzoF3K.js +1 -0
  123. package/dist/web/assets/ProfileView-CEscW7Ru.js +1 -0
  124. package/dist/web/assets/SettingsView-DwbGu8Kj.css +1 -0
  125. package/dist/web/assets/SettingsView-JIRR_FO4.js +63 -0
  126. package/dist/web/assets/TeamChatView-B5M1ThhJ.js +3 -0
  127. package/dist/web/assets/TeamChatView-Bx44q3WV.css +1 -0
  128. package/dist/web/assets/TerminalOverlay-C1iP4OS1.js +19 -0
  129. package/dist/web/assets/TerminalOverlay-DwBiZLwk.css +1 -0
  130. package/dist/web/assets/TrainingSettingsSection-BDYvI2te.js +1 -0
  131. package/dist/web/assets/TrainingView-CoCFK6W3.js +5 -0
  132. package/dist/web/assets/WorkspaceDiffPanel-CMxKQeo7.js +14 -0
  133. package/dist/web/assets/WorkspaceEnvironmentMenu-B8JJbwIz.js +32 -0
  134. package/dist/web/assets/WorkspaceEnvironmentMenu-DGIFdG3o.css +1 -0
  135. package/dist/web/assets/WorkspaceGitDialogs-B4sp9BGn.js +1 -0
  136. package/dist/web/assets/WorkspaceMonacoEditor-BBqimG5X.js +845 -0
  137. package/dist/web/assets/WorkspaceMonacoEditor-BwKcXIZw.css +1 -0
  138. package/dist/web/assets/boxes-DAaDUabq.js +1 -0
  139. package/dist/web/assets/codicon-ngg6Pgfi.ttf +0 -0
  140. package/dist/web/assets/css.worker-DBVD8oXr.js +93 -0
  141. package/dist/web/assets/cssMode-CBF1mieJ.js +1 -0
  142. package/dist/web/assets/dockerfile-BG73LgW2.js +1 -0
  143. package/dist/web/assets/editor.worker-CdQrwHl8.js +26 -0
  144. package/dist/web/assets/git-commit-horizontal-CAickXpN.js +1 -0
  145. package/dist/web/assets/git-dialogs-BZDqS1eT.css +1 -0
  146. package/dist/web/assets/html.worker-CwpTb9lJ.js +470 -0
  147. package/dist/web/assets/htmlMode-2u8OHtWO.js +1 -0
  148. package/dist/web/assets/index-BdY6A-YN.css +1 -0
  149. package/dist/web/assets/index-CU2qhUYV.js +195 -0
  150. package/dist/web/assets/index-Dz2B3-4C.js +1 -0
  151. package/dist/web/assets/info-CQNTh78o.js +1 -0
  152. package/dist/web/assets/json.worker-BoL8UZqY.js +58 -0
  153. package/dist/web/assets/jsonMode-C4CWXViX.js +7 -0
  154. package/dist/web/assets/lspLanguageFeatures-CBs_BOlB.js +4 -0
  155. package/dist/web/assets/markdown-BFxVWTOG.js +1 -0
  156. package/dist/web/assets/monaco.contribution-C1LUxAKf.js +2 -0
  157. package/dist/web/assets/monaco.contribution-Cpf6dWsh.js +2 -0
  158. package/dist/web/assets/monaco.contribution-lOXpG2xQ.js +2 -0
  159. package/dist/web/assets/monaco.contribution-sd3cFkcN.js +2 -0
  160. package/dist/web/assets/monitor-DsIswrMV.js +1 -0
  161. package/dist/web/assets/play-CeRw21NV.js +1 -0
  162. package/dist/web/assets/python-CXYq3BUl.js +1 -0
  163. package/dist/web/assets/refresh-cw-N5b_6AP5.js +1 -0
  164. package/dist/web/assets/reply-BSKjZrJg.js +1 -0
  165. package/dist/web/assets/save-D0oHH1a3.js +1 -0
  166. package/dist/web/assets/settings-lists-BEg6LMcy.css +1 -0
  167. package/dist/web/assets/shell-DiJ1NA_G.js +1 -0
  168. package/dist/web/assets/toggleHighContrast-B7NOMXDY.css +1 -0
  169. package/dist/web/assets/toggleHighContrast-DRjlcwes.js +62 -0
  170. package/dist/web/assets/training-model-data-BPrc68VG.js +1 -0
  171. package/dist/web/assets/ts.worker-BH9nVgjN.js +67718 -0
  172. package/dist/web/assets/tsMode-x-1A7ZcB.js +11 -0
  173. package/dist/web/assets/wifi-off-Dt52ofzh.js +1 -0
  174. package/dist/web/assets/workers-Ciff6Dzi.js +1 -0
  175. package/dist/web/assets/yaml-CB67Kxnz.js +1 -0
  176. package/dist/web/connected-apps/github.svg +3 -0
  177. package/dist/web/connected-apps/google.svg +6 -0
  178. package/dist/web/connected-apps/linear.svg +3 -0
  179. package/dist/web/connected-apps/microsoft.svg +6 -0
  180. package/dist/web/connected-apps/notion.svg +3 -0
  181. package/dist/web/connected-apps/openpond-mcp.svg +4 -0
  182. package/dist/web/connected-apps/slack.svg +6 -0
  183. package/dist/web/connected-apps/x.svg +3 -0
  184. package/dist/web/favicon-16x16.png +0 -0
  185. package/dist/web/favicon-32x32.png +0 -0
  186. package/dist/web/index.html +16 -0
  187. package/dist/web/openpond-icon.png +0 -0
  188. package/dist/web/openpond-wordlogo-white.png +0 -0
  189. package/dist/web/tokens/eth.svg +1 -0
  190. package/dist/web/tokens/usdc.svg +1 -0
  191. package/docs/agent-edit-check-status-json.md +132 -0
  192. package/docs/command-reference.md +695 -0
  193. package/package.json +84 -0
@@ -0,0 +1,88 @@
1
+ import { createRequire as __openpondCreateRequire } from "node:module"; var require = __openpondCreateRequire(import.meta.url);
2
+ import {
3
+ writePrivateJsonFile
4
+ } from "./chunk-XSAXENQD.js";
5
+
6
+ // ../../packages/cloud/src/profile/source-upload-cache.ts
7
+ import { createHash } from "node:crypto";
8
+ import { readFile } from "node:fs/promises";
9
+ import path from "node:path";
10
+ var SOURCE_UPLOAD_CACHE_PATH = ".openpond/source-upload-cache.json";
11
+ var SOURCE_UPLOAD_CACHE_SCHEMA = "openpond.source-upload-cache.v1";
12
+ async function readSourceUploadCache(rootPath) {
13
+ try {
14
+ const raw = await readFile(path.join(rootPath, SOURCE_UPLOAD_CACHE_PATH), "utf8");
15
+ const parsed = JSON.parse(raw);
16
+ if (parsed.schema !== SOURCE_UPLOAD_CACHE_SCHEMA || !parsed.entries) {
17
+ return /* @__PURE__ */ new Map();
18
+ }
19
+ const cache = /* @__PURE__ */ new Map();
20
+ for (const [cacheKey, value] of Object.entries(parsed.entries)) {
21
+ if (!isCacheEntry(value) || cacheKey !== cacheKeyForFile(value)) continue;
22
+ cache.set(cacheKey, value);
23
+ }
24
+ return cache;
25
+ } catch {
26
+ return /* @__PURE__ */ new Map();
27
+ }
28
+ }
29
+ async function materializeSourceUploadFile(file, cache) {
30
+ const cacheKey = cacheKeyForFile(file);
31
+ const cached = cache.get(cacheKey);
32
+ if (cached) {
33
+ return {
34
+ file,
35
+ entry: {
36
+ path: file.path,
37
+ type: "file",
38
+ contentsBase64: cached.contentsBase64
39
+ },
40
+ sha256: cached.sha256
41
+ };
42
+ }
43
+ const contents = await readFile(file.absolutePath);
44
+ return {
45
+ file,
46
+ entry: {
47
+ path: file.path,
48
+ type: "file",
49
+ contentsBase64: contents.toString("base64")
50
+ },
51
+ sha256: createHash("sha256").update(contents).digest("hex")
52
+ };
53
+ }
54
+ async function writeSourceUploadCache(rootPath, files) {
55
+ const entries = {};
56
+ for (const item of files) {
57
+ const cacheEntry = {
58
+ path: item.file.path,
59
+ size: item.file.size,
60
+ mtimeMs: item.file.mtimeMs,
61
+ ctimeMs: item.file.ctimeMs,
62
+ sha256: item.sha256,
63
+ contentsBase64: item.entry.contentsBase64
64
+ };
65
+ entries[cacheKeyForFile(cacheEntry)] = cacheEntry;
66
+ }
67
+ const cachePath = path.join(rootPath, SOURCE_UPLOAD_CACHE_PATH);
68
+ await writePrivateJsonFile(cachePath, {
69
+ schema: SOURCE_UPLOAD_CACHE_SCHEMA,
70
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
71
+ entries
72
+ });
73
+ }
74
+ function cacheKeyForFile(input) {
75
+ return `${input.path}\0${input.size}\0${input.mtimeMs}\0${input.ctimeMs}`;
76
+ }
77
+ function isCacheEntry(value) {
78
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
79
+ const record = value;
80
+ return typeof record.path === "string" && typeof record.size === "number" && typeof record.mtimeMs === "number" && typeof record.ctimeMs === "number" && typeof record.sha256 === "string" && typeof record.contentsBase64 === "string";
81
+ }
82
+
83
+ export {
84
+ SOURCE_UPLOAD_CACHE_PATH,
85
+ readSourceUploadCache,
86
+ materializeSourceUploadFile,
87
+ writeSourceUploadCache
88
+ };
@@ -0,0 +1,294 @@
1
+ import { createRequire as __openpondCreateRequire } from "node:module"; var require = __openpondCreateRequire(import.meta.url);
2
+ import {
3
+ getOpChatModel,
4
+ listOpChatModels,
5
+ sendHostedChatTurn,
6
+ streamHostedChatTurn
7
+ } from "./chunk-NLBKZZEK.js";
8
+
9
+ // ../../packages/cloud/src/opchat-smoke.ts
10
+ var DEFAULT_MODEL = "openpond-chat";
11
+ var COMPATIBILITY_MODEL = "deepseek-v4-flash";
12
+ var INVALID_MODEL = "not-a-real-opchat-model";
13
+ async function runOpChatSmoke(options) {
14
+ const defaultModel = options.defaultModel || DEFAULT_MODEL;
15
+ const compatibilityModel = options.compatibilityModel || COMPATIBILITY_MODEL;
16
+ const invalidModel = options.invalidModel || INVALID_MODEL;
17
+ const log = options.log || (() => void 0);
18
+ log(`opchat base: ${options.apiBaseUrl}`);
19
+ const models = await listOpChatModels({
20
+ apiBaseUrl: options.apiBaseUrl,
21
+ token: options.token
22
+ });
23
+ const listedModels = models.data.map((model) => model.id);
24
+ requireModel(listedModels, defaultModel);
25
+ requireModel(listedModels, compatibilityModel);
26
+ log(`models: ${listedModels.join(", ")}`);
27
+ const defaultLookup = await getOpChatModel({
28
+ apiBaseUrl: options.apiBaseUrl,
29
+ token: options.token,
30
+ model: defaultModel
31
+ });
32
+ const compatibilityLookup = await getOpChatModel({
33
+ apiBaseUrl: options.apiBaseUrl,
34
+ token: options.token,
35
+ model: compatibilityModel
36
+ });
37
+ const invalidModelError = await expectInvalidModel({
38
+ apiBaseUrl: options.apiBaseUrl,
39
+ token: options.token,
40
+ model: invalidModel
41
+ });
42
+ log(`invalid model error: ${invalidModelError}`);
43
+ const nonStreaming = summarizeCompletion(
44
+ defaultModel,
45
+ await sendHostedChatTurn({
46
+ apiBaseUrl: options.apiBaseUrl,
47
+ token: options.token,
48
+ model: defaultModel,
49
+ messages: [
50
+ {
51
+ role: "user",
52
+ content: "Reply with a short plain sentence confirming OpChat works."
53
+ }
54
+ ],
55
+ metadata: { source: "openpond-code-opchat-smoke", mode: "non_stream" }
56
+ })
57
+ );
58
+ requireText(nonStreaming, `${defaultModel} non-streaming response`);
59
+ log(
60
+ `${defaultModel} non-stream: id=${nonStreaming.id ?? "unknown"} usage=${formatUsage(
61
+ nonStreaming.usage
62
+ )}`
63
+ );
64
+ const streaming = options.skipStream ? void 0 : await runStreamSmoke({
65
+ apiBaseUrl: options.apiBaseUrl,
66
+ token: options.token,
67
+ model: defaultModel
68
+ });
69
+ if (streaming) {
70
+ log(
71
+ `${defaultModel} stream: chunks=${streaming.textDeltaCount} finish=${streaming.finishReason ?? "none"} usage=${formatUsage(streaming.usage)}`
72
+ );
73
+ }
74
+ const compatibilityNonStreaming = summarizeCompletion(
75
+ compatibilityModel,
76
+ await sendHostedChatTurn({
77
+ apiBaseUrl: options.apiBaseUrl,
78
+ token: options.token,
79
+ model: compatibilityModel,
80
+ messages: [
81
+ {
82
+ role: "user",
83
+ content: "Reply with one short sentence confirming compatibility."
84
+ }
85
+ ],
86
+ metadata: {
87
+ source: "openpond-code-opchat-smoke",
88
+ mode: "compatibility_non_stream"
89
+ }
90
+ })
91
+ );
92
+ requireText(
93
+ compatibilityNonStreaming,
94
+ `${compatibilityModel} non-streaming response`
95
+ );
96
+ log(
97
+ `${compatibilityModel} non-stream: id=${compatibilityNonStreaming.id ?? "unknown"} usage=${formatUsage(compatibilityNonStreaming.usage)}`
98
+ );
99
+ const toolCalling = options.skipTool ? void 0 : await runToolSmoke({
100
+ apiBaseUrl: options.apiBaseUrl,
101
+ token: options.token,
102
+ model: defaultModel
103
+ });
104
+ if (toolCalling) {
105
+ log(
106
+ `${defaultModel} tool: calls=${toolCalling.toolCallCount} names=${toolCalling.toolNames.join(
107
+ ","
108
+ )}`
109
+ );
110
+ }
111
+ return {
112
+ apiBaseUrl: options.apiBaseUrl,
113
+ listedModels,
114
+ defaultModel,
115
+ compatibilityModel,
116
+ modelLookups: [defaultLookup.id, compatibilityLookup.id],
117
+ invalidModelError,
118
+ nonStreaming,
119
+ compatibilityNonStreaming,
120
+ ...streaming ? { streaming } : {},
121
+ ...toolCalling ? { toolCalling } : {}
122
+ };
123
+ }
124
+ async function expectInvalidModel(options) {
125
+ try {
126
+ await getOpChatModel(options);
127
+ } catch (error) {
128
+ return error instanceof Error ? error.message : String(error);
129
+ }
130
+ throw new Error(`expected invalid model ${options.model} to fail`);
131
+ }
132
+ async function runStreamSmoke(options) {
133
+ const startedAt = Date.now();
134
+ let firstTextAt = null;
135
+ let text = "";
136
+ let textDeltaCount = 0;
137
+ let finishReason = null;
138
+ let usage = null;
139
+ for await (const chunk of streamHostedChatTurn({
140
+ apiBaseUrl: options.apiBaseUrl,
141
+ token: options.token,
142
+ model: options.model,
143
+ messages: [
144
+ {
145
+ role: "user",
146
+ content: "Reply with a short streamed sentence."
147
+ }
148
+ ],
149
+ metadata: { source: "openpond-code-opchat-smoke", mode: "stream" }
150
+ })) {
151
+ if (chunk.type === "text_delta") {
152
+ firstTextAt ??= Date.now();
153
+ text += chunk.text;
154
+ textDeltaCount += 1;
155
+ } else if (chunk.type === "finish") {
156
+ finishReason = chunk.finishReason;
157
+ } else if (chunk.type === "usage") {
158
+ usage = chunk.usage;
159
+ }
160
+ }
161
+ if (textDeltaCount === 0 || !text.trim()) {
162
+ throw new Error("streaming response did not emit text deltas");
163
+ }
164
+ if (!finishReason) {
165
+ throw new Error("streaming response did not emit a terminal finish marker");
166
+ }
167
+ return {
168
+ model: options.model,
169
+ textDeltaCount,
170
+ textPreview: previewText(text),
171
+ firstTextMs: firstTextAt === null ? null : firstTextAt - startedAt,
172
+ totalMs: Date.now() - startedAt,
173
+ finishReason,
174
+ usage
175
+ };
176
+ }
177
+ async function runToolSmoke(options) {
178
+ const tools = [
179
+ {
180
+ type: "function",
181
+ function: {
182
+ name: "get_current_weather",
183
+ description: "Get the current weather for a city.",
184
+ parameters: {
185
+ type: "object",
186
+ properties: {
187
+ location: {
188
+ type: "string",
189
+ description: "City and region, for example Boston, MA."
190
+ }
191
+ },
192
+ required: ["location"]
193
+ }
194
+ }
195
+ }
196
+ ];
197
+ const messages = [
198
+ {
199
+ role: "user",
200
+ content: "Use the get_current_weather tool for Boston, then wait for the result."
201
+ }
202
+ ];
203
+ const toolCompletion = await sendHostedChatTurn({
204
+ apiBaseUrl: options.apiBaseUrl,
205
+ token: options.token,
206
+ model: options.model,
207
+ messages,
208
+ tools,
209
+ toolChoice: "auto",
210
+ metadata: { source: "openpond-code-opchat-smoke", mode: "tool_call" }
211
+ });
212
+ const choice = toolCompletion.choices?.[0];
213
+ const toolCalls = choice?.message?.tool_calls ?? [];
214
+ if (toolCalls.length === 0) {
215
+ throw new Error("tool smoke did not receive an assistant tool call");
216
+ }
217
+ const toolResultMessages = buildToolResultMessages(toolCalls);
218
+ const followUp = summarizeCompletion(
219
+ options.model,
220
+ await sendHostedChatTurn({
221
+ apiBaseUrl: options.apiBaseUrl,
222
+ token: options.token,
223
+ model: options.model,
224
+ messages: [
225
+ ...messages,
226
+ {
227
+ role: "assistant",
228
+ content: choice?.message?.content ?? null,
229
+ tool_calls: toolCalls
230
+ },
231
+ ...toolResultMessages
232
+ ],
233
+ metadata: { source: "openpond-code-opchat-smoke", mode: "tool_result" }
234
+ })
235
+ );
236
+ requireText(followUp, "tool follow-up response");
237
+ return {
238
+ model: options.model,
239
+ toolCallCount: toolCalls.length,
240
+ toolNames: toolCalls.map((toolCall) => toolCall.function?.name).filter((name) => Boolean(name)),
241
+ finishReason: choice?.finish_reason ?? null,
242
+ followUp
243
+ };
244
+ }
245
+ function buildToolResultMessages(toolCalls) {
246
+ return toolCalls.map((toolCall, index) => {
247
+ if (!toolCall.id) {
248
+ throw new Error(`tool call ${index} is missing an id`);
249
+ }
250
+ return {
251
+ role: "tool",
252
+ tool_call_id: toolCall.id,
253
+ content: JSON.stringify({
254
+ location: "Boston, MA",
255
+ temperature: "58 F",
256
+ conditions: "clear"
257
+ })
258
+ };
259
+ });
260
+ }
261
+ function summarizeCompletion(model, completion) {
262
+ const choice = completion.choices?.[0];
263
+ return {
264
+ model,
265
+ id: completion.id ?? null,
266
+ finishReason: choice?.finish_reason ?? null,
267
+ textPreview: previewText(choice?.message?.content ?? ""),
268
+ usage: completion.usage ?? null
269
+ };
270
+ }
271
+ function requireModel(models, expected) {
272
+ if (!models.includes(expected)) {
273
+ throw new Error(`model list did not include ${expected}`);
274
+ }
275
+ }
276
+ function requireText(summary, label) {
277
+ if (!summary.textPreview.trim()) {
278
+ throw new Error(`${label} did not include assistant text`);
279
+ }
280
+ }
281
+ function previewText(value, maxLength = 120) {
282
+ const normalized = value.replace(/\s+/g, " ").trim();
283
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1)}...`;
284
+ }
285
+ function formatUsage(usage) {
286
+ if (!usage) return "none";
287
+ return String(
288
+ usage.total_tokens ?? usage.input_tokens ?? usage.output_tokens ?? "unknown"
289
+ );
290
+ }
291
+
292
+ export {
293
+ runOpChatSmoke
294
+ };